1
2
3
4
5
6
7
8
9
10#include <linux/bitfield.h>
11#include <linux/bitops.h>
12#include <linux/clk.h>
13#include <linux/delay.h>
14#include <linux/io.h>
15#include <linux/module.h>
16#include <linux/of_device.h>
17#include <linux/regmap.h>
18#include <linux/reset.h>
19#include <linux/phy/phy.h>
20#include <linux/platform_device.h>
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49#define MIPI_DSI_PHY_CTRL 0x0
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94#define MIPI_DSI_CHAN_CTRL 0x4
95
96
97
98
99
100
101
102
103
104
105
106#define MIPI_DSI_CHAN_STS 0x8
107
108
109
110
111
112
113#define MIPI_DSI_CLK_TIM 0xc
114
115
116
117
118
119
120#define MIPI_DSI_HS_TIM 0x10
121
122
123
124
125
126
127#define MIPI_DSI_LP_TIM 0x14
128
129
130#define MIPI_DSI_ANA_UP_TIM 0x18
131
132
133#define MIPI_DSI_INIT_TIM 0x1c
134
135
136#define MIPI_DSI_WAKEUP_TIM 0x20
137
138
139
140
141#define MIPI_DSI_LPOK_TIM 0x24
142
143
144#define MIPI_DSI_LP_WCHDOG 0x28
145
146
147
148
149#define MIPI_DSI_ANA_CTRL 0x2c
150
151
152
153
154#define MIPI_DSI_CLK_TIM1 0x30
155
156
157#define MIPI_DSI_TURN_WCHDOG 0x34
158
159
160
161
162#define MIPI_DSI_ULPS_CHECK 0x38
163#define MIPI_DSI_TEST_CTRL0 0x3c
164#define MIPI_DSI_TEST_CTRL1 0x40
165
166struct phy_meson_axg_mipi_dphy_priv {
167 struct device *dev;
168 struct regmap *regmap;
169 struct clk *clk;
170 struct reset_control *reset;
171 struct phy *analog;
172 struct phy_configure_opts_mipi_dphy config;
173};
174
175static const struct regmap_config phy_meson_axg_mipi_dphy_regmap_conf = {
176 .reg_bits = 8,
177 .val_bits = 32,
178 .reg_stride = 4,
179 .max_register = MIPI_DSI_TEST_CTRL1,
180};
181
182static int phy_meson_axg_mipi_dphy_init(struct phy *phy)
183{
184 struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
185 int ret;
186
187 ret = phy_init(priv->analog);
188 if (ret)
189 return ret;
190
191 ret = reset_control_reset(priv->reset);
192 if (ret)
193 return ret;
194
195 return 0;
196}
197
198static int phy_meson_axg_mipi_dphy_configure(struct phy *phy,
199 union phy_configure_opts *opts)
200{
201 struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
202 int ret;
203
204 ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
205 if (ret)
206 return ret;
207
208 ret = phy_configure(priv->analog, opts);
209 if (ret)
210 return ret;
211
212 memcpy(&priv->config, opts, sizeof(priv->config));
213
214 return 0;
215}
216
217static int phy_meson_axg_mipi_dphy_power_on(struct phy *phy)
218{
219 struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
220 int ret;
221 unsigned long temp;
222
223 ret = phy_power_on(priv->analog);
224 if (ret)
225 return ret;
226
227
228 regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL, 0x1);
229 regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL,
230 BIT(0) |
231 BIT(7) |
232 BIT(8));
233
234
235 regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(9), BIT(9));
236
237
238 regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(12), BIT(12));
239 regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31), BIT(31));
240 regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31), 0);
241
242
243 temp = (1000000 * 100) / (priv->config.hs_clk_rate / 1000);
244 temp = temp * 8 * 10;
245
246 regmap_write(priv->regmap, MIPI_DSI_CLK_TIM,
247 DIV_ROUND_UP(priv->config.clk_trail, temp) |
248 (DIV_ROUND_UP(priv->config.clk_post +
249 priv->config.hs_trail, temp) << 8) |
250 (DIV_ROUND_UP(priv->config.clk_zero, temp) << 16) |
251 (DIV_ROUND_UP(priv->config.clk_prepare, temp) << 24));
252 regmap_write(priv->regmap, MIPI_DSI_CLK_TIM1,
253 DIV_ROUND_UP(priv->config.clk_pre, temp));
254
255 regmap_write(priv->regmap, MIPI_DSI_HS_TIM,
256 DIV_ROUND_UP(priv->config.hs_exit, temp) |
257 (DIV_ROUND_UP(priv->config.hs_trail, temp) << 8) |
258 (DIV_ROUND_UP(priv->config.hs_zero, temp) << 16) |
259 (DIV_ROUND_UP(priv->config.hs_prepare, temp) << 24));
260
261 regmap_write(priv->regmap, MIPI_DSI_LP_TIM,
262 DIV_ROUND_UP(priv->config.lpx, temp) |
263 (DIV_ROUND_UP(priv->config.ta_sure, temp) << 8) |
264 (DIV_ROUND_UP(priv->config.ta_go, temp) << 16) |
265 (DIV_ROUND_UP(priv->config.ta_get, temp) << 24));
266
267 regmap_write(priv->regmap, MIPI_DSI_ANA_UP_TIM, 0x0100);
268 regmap_write(priv->regmap, MIPI_DSI_INIT_TIM,
269 DIV_ROUND_UP(priv->config.init * NSEC_PER_MSEC, temp));
270 regmap_write(priv->regmap, MIPI_DSI_WAKEUP_TIM,
271 DIV_ROUND_UP(priv->config.wakeup * NSEC_PER_MSEC, temp));
272 regmap_write(priv->regmap, MIPI_DSI_LPOK_TIM, 0x7C);
273 regmap_write(priv->regmap, MIPI_DSI_ULPS_CHECK, 0x927C);
274 regmap_write(priv->regmap, MIPI_DSI_LP_WCHDOG, 0x1000);
275 regmap_write(priv->regmap, MIPI_DSI_TURN_WCHDOG, 0x1000);
276
277
278 switch (priv->config.lanes) {
279 case 1:
280 regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xe);
281 break;
282 case 2:
283 regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xc);
284 break;
285 case 3:
286 regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0x8);
287 break;
288 case 4:
289 default:
290 regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0);
291 break;
292 }
293
294
295 regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(1), BIT(1));
296
297 return 0;
298}
299
300static int phy_meson_axg_mipi_dphy_power_off(struct phy *phy)
301{
302 struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
303
304 regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xf);
305 regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31));
306
307 phy_power_off(priv->analog);
308
309 return 0;
310}
311
312static int phy_meson_axg_mipi_dphy_exit(struct phy *phy)
313{
314 struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
315 int ret;
316
317 ret = phy_exit(priv->analog);
318 if (ret)
319 return ret;
320
321 return reset_control_reset(priv->reset);
322}
323
324static const struct phy_ops phy_meson_axg_mipi_dphy_ops = {
325 .configure = phy_meson_axg_mipi_dphy_configure,
326 .init = phy_meson_axg_mipi_dphy_init,
327 .exit = phy_meson_axg_mipi_dphy_exit,
328 .power_on = phy_meson_axg_mipi_dphy_power_on,
329 .power_off = phy_meson_axg_mipi_dphy_power_off,
330 .owner = THIS_MODULE,
331};
332
333static int phy_meson_axg_mipi_dphy_probe(struct platform_device *pdev)
334{
335 struct device *dev = &pdev->dev;
336 struct phy_provider *phy_provider;
337 struct resource *res;
338 struct phy_meson_axg_mipi_dphy_priv *priv;
339 struct phy *phy;
340 void __iomem *base;
341 int ret;
342
343 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
344 if (!priv)
345 return -ENOMEM;
346
347 priv->dev = dev;
348 platform_set_drvdata(pdev, priv);
349
350 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
351 base = devm_ioremap_resource(dev, res);
352 if (IS_ERR(base))
353 return PTR_ERR(base);
354
355 priv->regmap = devm_regmap_init_mmio(dev, base,
356 &phy_meson_axg_mipi_dphy_regmap_conf);
357 if (IS_ERR(priv->regmap))
358 return PTR_ERR(priv->regmap);
359
360 priv->clk = devm_clk_get(dev, "pclk");
361 if (IS_ERR(priv->clk))
362 return PTR_ERR(priv->clk);
363
364 priv->reset = devm_reset_control_get(dev, "phy");
365 if (IS_ERR(priv->reset))
366 return PTR_ERR(priv->reset);
367
368 priv->analog = devm_phy_get(dev, "analog");
369 if (IS_ERR(priv->analog))
370 return PTR_ERR(priv->analog);
371
372 ret = clk_prepare_enable(priv->clk);
373 if (ret)
374 return ret;
375
376 ret = reset_control_deassert(priv->reset);
377 if (ret)
378 return ret;
379
380 phy = devm_phy_create(dev, NULL, &phy_meson_axg_mipi_dphy_ops);
381 if (IS_ERR(phy)) {
382 ret = PTR_ERR(phy);
383 if (ret != -EPROBE_DEFER)
384 dev_err(dev, "failed to create PHY\n");
385
386 return ret;
387 }
388
389 phy_set_drvdata(phy, priv);
390
391 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
392
393 return PTR_ERR_OR_ZERO(phy_provider);
394}
395
396static const struct of_device_id phy_meson_axg_mipi_dphy_of_match[] = {
397 { .compatible = "amlogic,axg-mipi-dphy", },
398 { },
399};
400MODULE_DEVICE_TABLE(of, phy_meson_axg_mipi_dphy_of_match);
401
402static struct platform_driver phy_meson_axg_mipi_dphy_driver = {
403 .probe = phy_meson_axg_mipi_dphy_probe,
404 .driver = {
405 .name = "phy-meson-axg-mipi-dphy",
406 .of_match_table = phy_meson_axg_mipi_dphy_of_match,
407 },
408};
409module_platform_driver(phy_meson_axg_mipi_dphy_driver);
410
411MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
412MODULE_DESCRIPTION("Meson AXG MIPI DPHY driver");
413MODULE_LICENSE("GPL v2");
414