1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/platform_device.h>
15
16#include "dsi_phy.h"
17
18#define S_DIV_ROUND_UP(n, d) \
19 (((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
20
21static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
22 s32 min_result, bool even)
23{
24 s32 v;
25
26 v = (tmax - tmin) * percent;
27 v = S_DIV_ROUND_UP(v, 100) + tmin;
28 if (even && (v & 0x1))
29 return max_t(s32, min_result, v - 1);
30 else
31 return max_t(s32, min_result, v);
32}
33
34static void dsi_dphy_timing_calc_clk_zero(struct msm_dsi_dphy_timing *timing,
35 s32 ui, s32 coeff, s32 pcnt)
36{
37 s32 tmax, tmin, clk_z;
38 s32 temp;
39
40
41 temp = 300 * coeff - ((timing->clk_prepare >> 1) + 1) * 2 * ui;
42 tmin = S_DIV_ROUND_UP(temp, ui) - 2;
43 if (tmin > 255) {
44 tmax = 511;
45 clk_z = linear_inter(2 * tmin, tmin, pcnt, 0, true);
46 } else {
47 tmax = 255;
48 clk_z = linear_inter(tmax, tmin, pcnt, 0, true);
49 }
50
51
52 temp = (timing->hs_rqst + timing->clk_prepare + clk_z) & 0x7;
53 timing->clk_zero = clk_z + 8 - temp;
54}
55
56int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
57 struct msm_dsi_phy_clk_request *clk_req)
58{
59 const unsigned long bit_rate = clk_req->bitclk_rate;
60 const unsigned long esc_rate = clk_req->escclk_rate;
61 s32 ui, lpx;
62 s32 tmax, tmin;
63 s32 pcnt0 = 10;
64 s32 pcnt1 = (bit_rate > 1200000000) ? 15 : 10;
65 s32 pcnt2 = 10;
66 s32 pcnt3 = (bit_rate > 180000000) ? 10 : 40;
67 s32 coeff = 1000;
68 s32 temp;
69
70 if (!bit_rate || !esc_rate)
71 return -EINVAL;
72
73 ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
74 lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
75
76 tmax = S_DIV_ROUND_UP(95 * coeff, ui) - 2;
77 tmin = S_DIV_ROUND_UP(38 * coeff, ui) - 2;
78 timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, true);
79
80 temp = lpx / ui;
81 if (temp & 0x1)
82 timing->hs_rqst = temp;
83 else
84 timing->hs_rqst = max_t(s32, 0, temp - 2);
85
86
87 dsi_dphy_timing_calc_clk_zero(timing, ui, coeff, pcnt2);
88
89 temp = 105 * coeff + 12 * ui - 20 * coeff;
90 tmax = S_DIV_ROUND_UP(temp, ui) - 2;
91 tmin = S_DIV_ROUND_UP(60 * coeff, ui) - 2;
92 timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
93
94 temp = 85 * coeff + 6 * ui;
95 tmax = S_DIV_ROUND_UP(temp, ui) - 2;
96 temp = 40 * coeff + 4 * ui;
97 tmin = S_DIV_ROUND_UP(temp, ui) - 2;
98 timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, true);
99
100 tmax = 255;
101 temp = ((timing->hs_prepare >> 1) + 1) * 2 * ui + 2 * ui;
102 temp = 145 * coeff + 10 * ui - temp;
103 tmin = S_DIV_ROUND_UP(temp, ui) - 2;
104 timing->hs_zero = linear_inter(tmax, tmin, pcnt2, 24, true);
105
106 temp = 105 * coeff + 12 * ui - 20 * coeff;
107 tmax = S_DIV_ROUND_UP(temp, ui) - 2;
108 temp = 60 * coeff + 4 * ui;
109 tmin = DIV_ROUND_UP(temp, ui) - 2;
110 timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
111
112 tmax = 255;
113 tmin = S_DIV_ROUND_UP(100 * coeff, ui) - 2;
114 timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, true);
115
116 tmax = 63;
117 temp = ((timing->hs_exit >> 1) + 1) * 2 * ui;
118 temp = 60 * coeff + 52 * ui - 24 * ui - temp;
119 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
120 timing->shared_timings.clk_post = linear_inter(tmax, tmin, pcnt2, 0,
121 false);
122 tmax = 63;
123 temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui;
124 temp += ((timing->clk_zero >> 1) + 1) * 2 * ui;
125 temp += 8 * ui + lpx;
126 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
127 if (tmin > tmax) {
128 temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false);
129 timing->shared_timings.clk_pre = temp >> 1;
130 timing->shared_timings.clk_pre_inc_by_2 = true;
131 } else {
132 timing->shared_timings.clk_pre =
133 linear_inter(tmax, tmin, pcnt2, 0, false);
134 timing->shared_timings.clk_pre_inc_by_2 = false;
135 }
136
137 timing->ta_go = 3;
138 timing->ta_sure = 0;
139 timing->ta_get = 4;
140
141 DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
142 timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
143 timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
144 timing->clk_trail, timing->clk_prepare, timing->hs_exit,
145 timing->hs_zero, timing->hs_prepare, timing->hs_trail,
146 timing->hs_rqst);
147
148 return 0;
149}
150
151int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing,
152 struct msm_dsi_phy_clk_request *clk_req)
153{
154 const unsigned long bit_rate = clk_req->bitclk_rate;
155 const unsigned long esc_rate = clk_req->escclk_rate;
156 s32 ui, ui_x8, lpx;
157 s32 tmax, tmin;
158 s32 pcnt0 = 50;
159 s32 pcnt1 = 50;
160 s32 pcnt2 = 10;
161 s32 pcnt3 = 30;
162 s32 pcnt4 = 10;
163 s32 pcnt5 = 2;
164 s32 coeff = 1000;
165 s32 hb_en, hb_en_ckln, pd_ckln, pd;
166 s32 val, val_ckln;
167 s32 temp;
168
169 if (!bit_rate || !esc_rate)
170 return -EINVAL;
171
172 timing->hs_halfbyte_en = 0;
173 hb_en = 0;
174 timing->hs_halfbyte_en_ckln = 0;
175 hb_en_ckln = 0;
176 timing->hs_prep_dly_ckln = (bit_rate > 100000000) ? 0 : 3;
177 pd_ckln = timing->hs_prep_dly_ckln;
178 timing->hs_prep_dly = (bit_rate > 120000000) ? 0 : 1;
179 pd = timing->hs_prep_dly;
180
181 val = (hb_en << 2) + (pd << 1);
182 val_ckln = (hb_en_ckln << 2) + (pd_ckln << 1);
183
184 ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
185 ui_x8 = ui << 3;
186 lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
187
188 temp = S_DIV_ROUND_UP(38 * coeff - val_ckln * ui, ui_x8);
189 tmin = max_t(s32, temp, 0);
190 temp = (95 * coeff - val_ckln * ui) / ui_x8;
191 tmax = max_t(s32, temp, 0);
192 timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
193
194 temp = 300 * coeff - ((timing->clk_prepare << 3) + val_ckln) * ui;
195 tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3;
196 tmax = (tmin > 255) ? 511 : 255;
197 timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
198
199 tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
200 temp = 105 * coeff + 12 * ui - 20 * coeff;
201 tmax = (temp + 3 * ui) / ui_x8;
202 timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
203
204 temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui - val * ui, ui_x8);
205 tmin = max_t(s32, temp, 0);
206 temp = (85 * coeff + 6 * ui - val * ui) / ui_x8;
207 tmax = max_t(s32, temp, 0);
208 timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
209
210 temp = 145 * coeff + 10 * ui - ((timing->hs_prepare << 3) + val) * ui;
211 tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3;
212 tmax = 255;
213 timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
214
215 tmin = DIV_ROUND_UP(60 * coeff + 4 * ui + 3 * ui, ui_x8);
216 temp = 105 * coeff + 12 * ui - 20 * coeff;
217 tmax = (temp + 3 * ui) / ui_x8;
218 timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
219
220 temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
221 timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
222
223 tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
224 tmax = 255;
225 timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
226
227 temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
228 timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
229
230 temp = 60 * coeff + 52 * ui - 43 * ui;
231 tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
232 tmax = 63;
233 timing->shared_timings.clk_post =
234 linear_inter(tmax, tmin, pcnt2, 0, false);
235
236 temp = 8 * ui + ((timing->clk_prepare << 3) + val_ckln) * ui;
237 temp += (((timing->clk_zero + 3) << 3) + 11 - (pd_ckln << 1)) * ui;
238 temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
239 (((timing->hs_rqst_ckln << 3) + 8) * ui);
240 tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
241 tmax = 63;
242 if (tmin > tmax) {
243 temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
244 timing->shared_timings.clk_pre = temp >> 1;
245 timing->shared_timings.clk_pre_inc_by_2 = 1;
246 } else {
247 timing->shared_timings.clk_pre =
248 linear_inter(tmax, tmin, pcnt2, 0, false);
249 timing->shared_timings.clk_pre_inc_by_2 = 0;
250 }
251
252 timing->ta_go = 3;
253 timing->ta_sure = 0;
254 timing->ta_get = 4;
255
256 DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
257 timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
258 timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
259 timing->clk_trail, timing->clk_prepare, timing->hs_exit,
260 timing->hs_zero, timing->hs_prepare, timing->hs_trail,
261 timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en,
262 timing->hs_halfbyte_en_ckln, timing->hs_prep_dly,
263 timing->hs_prep_dly_ckln);
264
265 return 0;
266}
267
268int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
269 struct msm_dsi_phy_clk_request *clk_req)
270{
271 const unsigned long bit_rate = clk_req->bitclk_rate;
272 const unsigned long esc_rate = clk_req->escclk_rate;
273 s32 ui, ui_x8, lpx;
274 s32 tmax, tmin;
275 s32 pcnt0 = 50;
276 s32 pcnt1 = 50;
277 s32 pcnt2 = 10;
278 s32 pcnt3 = 30;
279 s32 pcnt4 = 10;
280 s32 pcnt5 = 2;
281 s32 coeff = 1000;
282 s32 hb_en, hb_en_ckln;
283 s32 temp;
284
285 if (!bit_rate || !esc_rate)
286 return -EINVAL;
287
288 timing->hs_halfbyte_en = 0;
289 hb_en = 0;
290 timing->hs_halfbyte_en_ckln = 0;
291 hb_en_ckln = 0;
292
293 ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
294 ui_x8 = ui << 3;
295 lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
296
297 temp = S_DIV_ROUND_UP(38 * coeff, ui_x8);
298 tmin = max_t(s32, temp, 0);
299 temp = (95 * coeff) / ui_x8;
300 tmax = max_t(s32, temp, 0);
301 timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
302
303 temp = 300 * coeff - (timing->clk_prepare << 3) * ui;
304 tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
305 tmax = (tmin > 255) ? 511 : 255;
306 timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
307
308 tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
309 temp = 105 * coeff + 12 * ui - 20 * coeff;
310 tmax = (temp + 3 * ui) / ui_x8;
311 timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
312
313 temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui, ui_x8);
314 tmin = max_t(s32, temp, 0);
315 temp = (85 * coeff + 6 * ui) / ui_x8;
316 tmax = max_t(s32, temp, 0);
317 timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
318
319 temp = 145 * coeff + 10 * ui - (timing->hs_prepare << 3) * ui;
320 tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
321 tmax = 255;
322 timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
323
324 tmin = DIV_ROUND_UP(60 * coeff + 4 * ui, ui_x8) - 1;
325 temp = 105 * coeff + 12 * ui - 20 * coeff;
326 tmax = (temp / ui_x8) - 1;
327 timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
328
329 temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
330 timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
331
332 tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
333 tmax = 255;
334 timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
335
336 temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
337 timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
338
339 temp = 60 * coeff + 52 * ui - 43 * ui;
340 tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
341 tmax = 63;
342 timing->shared_timings.clk_post =
343 linear_inter(tmax, tmin, pcnt2, 0, false);
344
345 temp = 8 * ui + (timing->clk_prepare << 3) * ui;
346 temp += (((timing->clk_zero + 3) << 3) + 11) * ui;
347 temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
348 (((timing->hs_rqst_ckln << 3) + 8) * ui);
349 tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
350 tmax = 63;
351 if (tmin > tmax) {
352 temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
353 timing->shared_timings.clk_pre = temp >> 1;
354 timing->shared_timings.clk_pre_inc_by_2 = 1;
355 } else {
356 timing->shared_timings.clk_pre =
357 linear_inter(tmax, tmin, pcnt2, 0, false);
358 timing->shared_timings.clk_pre_inc_by_2 = 0;
359 }
360
361 timing->ta_go = 3;
362 timing->ta_sure = 0;
363 timing->ta_get = 4;
364
365 DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
366 timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
367 timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
368 timing->clk_trail, timing->clk_prepare, timing->hs_exit,
369 timing->hs_zero, timing->hs_prepare, timing->hs_trail,
370 timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en,
371 timing->hs_halfbyte_en_ckln, timing->hs_prep_dly,
372 timing->hs_prep_dly_ckln);
373
374 return 0;
375}
376
377void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
378 u32 bit_mask)
379{
380 int phy_id = phy->id;
381 u32 val;
382
383 if ((phy_id >= DSI_MAX) || (pll_id >= DSI_MAX))
384 return;
385
386 val = dsi_phy_read(phy->base + reg);
387
388 if (phy->cfg->src_pll_truthtable[phy_id][pll_id])
389 dsi_phy_write(phy->base + reg, val | bit_mask);
390 else
391 dsi_phy_write(phy->base + reg, val & (~bit_mask));
392}
393
394static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
395{
396 struct regulator_bulk_data *s = phy->supplies;
397 const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
398 struct device *dev = &phy->pdev->dev;
399 int num = phy->cfg->reg_cfg.num;
400 int i, ret;
401
402 for (i = 0; i < num; i++)
403 s[i].supply = regs[i].name;
404
405 ret = devm_regulator_bulk_get(dev, num, s);
406 if (ret < 0) {
407 dev_err(dev, "%s: failed to init regulator, ret=%d\n",
408 __func__, ret);
409 return ret;
410 }
411
412 return 0;
413}
414
415static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
416{
417 struct regulator_bulk_data *s = phy->supplies;
418 const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
419 int num = phy->cfg->reg_cfg.num;
420 int i;
421
422 DBG("");
423 for (i = num - 1; i >= 0; i--)
424 if (regs[i].disable_load >= 0)
425 regulator_set_load(s[i].consumer, regs[i].disable_load);
426
427 regulator_bulk_disable(num, s);
428}
429
430static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
431{
432 struct regulator_bulk_data *s = phy->supplies;
433 const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
434 struct device *dev = &phy->pdev->dev;
435 int num = phy->cfg->reg_cfg.num;
436 int ret, i;
437
438 DBG("");
439 for (i = 0; i < num; i++) {
440 if (regs[i].enable_load >= 0) {
441 ret = regulator_set_load(s[i].consumer,
442 regs[i].enable_load);
443 if (ret < 0) {
444 dev_err(dev,
445 "regulator %d set op mode failed, %d\n",
446 i, ret);
447 goto fail;
448 }
449 }
450 }
451
452 ret = regulator_bulk_enable(num, s);
453 if (ret < 0) {
454 dev_err(dev, "regulator enable failed, %d\n", ret);
455 goto fail;
456 }
457
458 return 0;
459
460fail:
461 for (i--; i >= 0; i--)
462 regulator_set_load(s[i].consumer, regs[i].disable_load);
463 return ret;
464}
465
466static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
467{
468 struct device *dev = &phy->pdev->dev;
469 int ret;
470
471 pm_runtime_get_sync(dev);
472
473 ret = clk_prepare_enable(phy->ahb_clk);
474 if (ret) {
475 dev_err(dev, "%s: can't enable ahb clk, %d\n", __func__, ret);
476 pm_runtime_put_sync(dev);
477 }
478
479 return ret;
480}
481
482static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
483{
484 clk_disable_unprepare(phy->ahb_clk);
485 pm_runtime_put_autosuspend(&phy->pdev->dev);
486}
487
488static const struct of_device_id dsi_phy_dt_match[] = {
489#ifdef CONFIG_DRM_MSM_DSI_28NM_PHY
490 { .compatible = "qcom,dsi-phy-28nm-hpm",
491 .data = &dsi_phy_28nm_hpm_cfgs },
492 { .compatible = "qcom,dsi-phy-28nm-lp",
493 .data = &dsi_phy_28nm_lp_cfgs },
494#endif
495#ifdef CONFIG_DRM_MSM_DSI_20NM_PHY
496 { .compatible = "qcom,dsi-phy-20nm",
497 .data = &dsi_phy_20nm_cfgs },
498#endif
499#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY
500 { .compatible = "qcom,dsi-phy-28nm-8960",
501 .data = &dsi_phy_28nm_8960_cfgs },
502#endif
503#ifdef CONFIG_DRM_MSM_DSI_14NM_PHY
504 { .compatible = "qcom,dsi-phy-14nm",
505 .data = &dsi_phy_14nm_cfgs },
506#endif
507#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY
508 { .compatible = "qcom,dsi-phy-10nm",
509 .data = &dsi_phy_10nm_cfgs },
510#endif
511 {}
512};
513
514
515
516
517
518
519static int dsi_phy_get_id(struct msm_dsi_phy *phy)
520{
521 struct platform_device *pdev = phy->pdev;
522 const struct msm_dsi_phy_cfg *cfg = phy->cfg;
523 struct resource *res;
524 int i;
525
526 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dsi_phy");
527 if (!res)
528 return -EINVAL;
529
530 for (i = 0; i < cfg->num_dsi_phy; i++) {
531 if (cfg->io_start[i] == res->start)
532 return i;
533 }
534
535 return -EINVAL;
536}
537
538int msm_dsi_phy_init_common(struct msm_dsi_phy *phy)
539{
540 struct platform_device *pdev = phy->pdev;
541 int ret = 0;
542
543 phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
544 "DSI_PHY_REG");
545 if (IS_ERR(phy->reg_base)) {
546 dev_err(&pdev->dev, "%s: failed to map phy regulator base\n",
547 __func__);
548 ret = -ENOMEM;
549 goto fail;
550 }
551
552fail:
553 return ret;
554}
555
556static int dsi_phy_driver_probe(struct platform_device *pdev)
557{
558 struct msm_dsi_phy *phy;
559 struct device *dev = &pdev->dev;
560 const struct of_device_id *match;
561 int ret;
562
563 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
564 if (!phy)
565 return -ENOMEM;
566
567 match = of_match_node(dsi_phy_dt_match, dev->of_node);
568 if (!match)
569 return -ENODEV;
570
571 phy->cfg = match->data;
572 phy->pdev = pdev;
573
574 phy->id = dsi_phy_get_id(phy);
575 if (phy->id < 0) {
576 ret = phy->id;
577 dev_err(dev, "%s: couldn't identify PHY index, %d\n",
578 __func__, ret);
579 goto fail;
580 }
581
582 phy->regulator_ldo_mode = of_property_read_bool(dev->of_node,
583 "qcom,dsi-phy-regulator-ldo-mode");
584
585 phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
586 if (IS_ERR(phy->base)) {
587 dev_err(dev, "%s: failed to map phy base\n", __func__);
588 ret = -ENOMEM;
589 goto fail;
590 }
591
592 ret = dsi_phy_regulator_init(phy);
593 if (ret) {
594 dev_err(dev, "%s: failed to init regulator\n", __func__);
595 goto fail;
596 }
597
598 phy->ahb_clk = msm_clk_get(pdev, "iface");
599 if (IS_ERR(phy->ahb_clk)) {
600 dev_err(dev, "%s: Unable to get ahb clk\n", __func__);
601 ret = PTR_ERR(phy->ahb_clk);
602 goto fail;
603 }
604
605 if (phy->cfg->ops.init) {
606 ret = phy->cfg->ops.init(phy);
607 if (ret)
608 goto fail;
609 }
610
611
612
613
614 ret = dsi_phy_enable_resource(phy);
615 if (ret)
616 goto fail;
617
618 phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
619 if (IS_ERR_OR_NULL(phy->pll))
620 dev_info(dev,
621 "%s: pll init failed: %ld, need separate pll clk driver\n",
622 __func__, PTR_ERR(phy->pll));
623
624 dsi_phy_disable_resource(phy);
625
626 platform_set_drvdata(pdev, phy);
627
628 return 0;
629
630fail:
631 return ret;
632}
633
634static int dsi_phy_driver_remove(struct platform_device *pdev)
635{
636 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
637
638 if (phy && phy->pll) {
639 msm_dsi_pll_destroy(phy->pll);
640 phy->pll = NULL;
641 }
642
643 platform_set_drvdata(pdev, NULL);
644
645 return 0;
646}
647
648static struct platform_driver dsi_phy_platform_driver = {
649 .probe = dsi_phy_driver_probe,
650 .remove = dsi_phy_driver_remove,
651 .driver = {
652 .name = "msm_dsi_phy",
653 .of_match_table = dsi_phy_dt_match,
654 },
655};
656
657void __init msm_dsi_phy_driver_register(void)
658{
659 platform_driver_register(&dsi_phy_platform_driver);
660}
661
662void __exit msm_dsi_phy_driver_unregister(void)
663{
664 platform_driver_unregister(&dsi_phy_platform_driver);
665}
666
667int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
668 struct msm_dsi_phy_clk_request *clk_req)
669{
670 struct device *dev = &phy->pdev->dev;
671 int ret;
672
673 if (!phy || !phy->cfg->ops.enable)
674 return -EINVAL;
675
676 ret = dsi_phy_enable_resource(phy);
677 if (ret) {
678 dev_err(dev, "%s: resource enable failed, %d\n",
679 __func__, ret);
680 goto res_en_fail;
681 }
682
683 ret = dsi_phy_regulator_enable(phy);
684 if (ret) {
685 dev_err(dev, "%s: regulator enable failed, %d\n",
686 __func__, ret);
687 goto reg_en_fail;
688 }
689
690 ret = phy->cfg->ops.enable(phy, src_pll_id, clk_req);
691 if (ret) {
692 dev_err(dev, "%s: phy enable failed, %d\n", __func__, ret);
693 goto phy_en_fail;
694 }
695
696
697
698
699
700
701
702 if (phy->usecase != MSM_DSI_PHY_SLAVE) {
703 ret = msm_dsi_pll_restore_state(phy->pll);
704 if (ret) {
705 dev_err(dev, "%s: failed to restore pll state, %d\n",
706 __func__, ret);
707 goto pll_restor_fail;
708 }
709 }
710
711 return 0;
712
713pll_restor_fail:
714 if (phy->cfg->ops.disable)
715 phy->cfg->ops.disable(phy);
716phy_en_fail:
717 dsi_phy_regulator_disable(phy);
718reg_en_fail:
719 dsi_phy_disable_resource(phy);
720res_en_fail:
721 return ret;
722}
723
724void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
725{
726 if (!phy || !phy->cfg->ops.disable)
727 return;
728
729
730 if (phy->usecase != MSM_DSI_PHY_SLAVE)
731 msm_dsi_pll_save_state(phy->pll);
732
733 phy->cfg->ops.disable(phy);
734
735 dsi_phy_regulator_disable(phy);
736 dsi_phy_disable_resource(phy);
737}
738
739void msm_dsi_phy_get_shared_timings(struct msm_dsi_phy *phy,
740 struct msm_dsi_phy_shared_timings *shared_timings)
741{
742 memcpy(shared_timings, &phy->timing.shared_timings,
743 sizeof(*shared_timings));
744}
745
746struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
747{
748 if (!phy)
749 return NULL;
750
751 return phy->pll;
752}
753
754void msm_dsi_phy_set_usecase(struct msm_dsi_phy *phy,
755 enum msm_dsi_phy_usecase uc)
756{
757 if (phy)
758 phy->usecase = uc;
759}
760