blob: cdc1ff63f3e2a12f4ef055d1995ebd40936ec0c2 [file] [log] [blame]
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07001/*
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Ajay Singh Parmar67f31322016-06-22 17:37:56 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "msm-dsi-phy:[%s] " fmt, __func__
15
16#include <linux/of_device.h>
17#include <linux/err.h>
18#include <linux/regulator/consumer.h>
19#include <linux/clk.h>
20#include <linux/msm-bus.h>
21#include <linux/list.h>
22
23#include "msm_drv.h"
24#include "msm_kms.h"
25#include "msm_gpu.h"
26#include "dsi_phy.h"
27#include "dsi_phy_hw.h"
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +053028#include "dsi_clk.h"
29#include "dsi_pwr.h"
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070030#include "dsi_catalog.h"
31
32#define DSI_PHY_DEFAULT_LABEL "MDSS PHY CTRL"
33
34struct dsi_phy_list_item {
35 struct msm_dsi_phy *phy;
36 struct list_head list;
37};
38
39static LIST_HEAD(dsi_phy_list);
40static DEFINE_MUTEX(dsi_phy_list_lock);
41
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053042static const struct dsi_ver_spec_info dsi_phy_v0_0_hpm = {
43 .version = DSI_PHY_VERSION_0_0_HPM,
44 .lane_cfg_count = 4,
45 .strength_cfg_count = 2,
46 .regulator_cfg_count = 1,
47 .timing_cfg_count = 8,
48};
49static const struct dsi_ver_spec_info dsi_phy_v0_0_lpm = {
50 .version = DSI_PHY_VERSION_0_0_LPM,
51 .lane_cfg_count = 4,
52 .strength_cfg_count = 2,
53 .regulator_cfg_count = 1,
54 .timing_cfg_count = 8,
55};
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070056static const struct dsi_ver_spec_info dsi_phy_v1_0 = {
57 .version = DSI_PHY_VERSION_1_0,
58 .lane_cfg_count = 4,
59 .strength_cfg_count = 2,
60 .regulator_cfg_count = 1,
61 .timing_cfg_count = 8,
62};
63static const struct dsi_ver_spec_info dsi_phy_v2_0 = {
64 .version = DSI_PHY_VERSION_2_0,
65 .lane_cfg_count = 4,
66 .strength_cfg_count = 2,
67 .regulator_cfg_count = 1,
68 .timing_cfg_count = 8,
69};
70static const struct dsi_ver_spec_info dsi_phy_v3_0 = {
71 .version = DSI_PHY_VERSION_3_0,
72 .lane_cfg_count = 4,
73 .strength_cfg_count = 2,
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053074 .regulator_cfg_count = 0,
75 .timing_cfg_count = 12,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070076};
77
78static const struct of_device_id msm_dsi_phy_of_match[] = {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053079 { .compatible = "qcom,dsi-phy-v0.0-hpm",
80 .data = &dsi_phy_v0_0_hpm,},
81 { .compatible = "qcom,dsi-phy-v0.0-lpm",
82 .data = &dsi_phy_v0_0_lpm,},
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070083 { .compatible = "qcom,dsi-phy-v1.0",
84 .data = &dsi_phy_v1_0,},
85 { .compatible = "qcom,dsi-phy-v2.0",
86 .data = &dsi_phy_v2_0,},
87 { .compatible = "qcom,dsi-phy-v3.0",
88 .data = &dsi_phy_v3_0,},
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070089 {}
90};
91
92static int dsi_phy_regmap_init(struct platform_device *pdev,
93 struct msm_dsi_phy *phy)
94{
95 int rc = 0;
96 void __iomem *ptr;
97
98 ptr = msm_ioremap(pdev, "dsi_phy", phy->name);
99 if (IS_ERR(ptr)) {
100 rc = PTR_ERR(ptr);
101 return rc;
102 }
103
104 phy->hw.base = ptr;
105
106 pr_debug("[%s] map dsi_phy registers to %p\n", phy->name, phy->hw.base);
107
108 return rc;
109}
110
111static int dsi_phy_regmap_deinit(struct msm_dsi_phy *phy)
112{
113 pr_debug("[%s] unmap registers\n", phy->name);
114 return 0;
115}
116
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700117static int dsi_phy_supplies_init(struct platform_device *pdev,
118 struct msm_dsi_phy *phy)
119{
120 int rc = 0;
121 int i = 0;
122 struct dsi_regulator_info *regs;
123 struct regulator *vreg = NULL;
124
125 regs = &phy->pwr_info.digital;
126 regs->vregs = devm_kzalloc(&pdev->dev, sizeof(struct dsi_vreg),
127 GFP_KERNEL);
128 if (!regs->vregs)
129 goto error;
130
131 regs->count = 1;
132 snprintf(regs->vregs->vreg_name,
133 ARRAY_SIZE(regs->vregs[i].vreg_name),
134 "%s", "gdsc");
135
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530136 rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700137 &phy->pwr_info.phy_pwr,
138 "qcom,phy-supply-entries");
139 if (rc) {
140 pr_err("failed to get host power supplies, rc = %d\n", rc);
141 goto error_digital;
142 }
143
144 regs = &phy->pwr_info.digital;
145 for (i = 0; i < regs->count; i++) {
146 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
147 rc = PTR_RET(vreg);
148 if (rc) {
149 pr_err("failed to get %s regulator\n",
150 regs->vregs[i].vreg_name);
151 goto error_host_pwr;
152 }
153 regs->vregs[i].vreg = vreg;
154 }
155
156 regs = &phy->pwr_info.phy_pwr;
157 for (i = 0; i < regs->count; i++) {
158 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
159 rc = PTR_RET(vreg);
160 if (rc) {
161 pr_err("failed to get %s regulator\n",
162 regs->vregs[i].vreg_name);
163 for (--i; i >= 0; i--)
164 devm_regulator_put(regs->vregs[i].vreg);
165 goto error_digital_put;
166 }
167 regs->vregs[i].vreg = vreg;
168 }
169
170 return rc;
171
172error_digital_put:
173 regs = &phy->pwr_info.digital;
174 for (i = 0; i < regs->count; i++)
175 devm_regulator_put(regs->vregs[i].vreg);
176error_host_pwr:
177 devm_kfree(&pdev->dev, phy->pwr_info.phy_pwr.vregs);
178 phy->pwr_info.phy_pwr.vregs = NULL;
179 phy->pwr_info.phy_pwr.count = 0;
180error_digital:
181 devm_kfree(&pdev->dev, phy->pwr_info.digital.vregs);
182 phy->pwr_info.digital.vregs = NULL;
183 phy->pwr_info.digital.count = 0;
184error:
185 return rc;
186}
187
188static int dsi_phy_supplies_deinit(struct msm_dsi_phy *phy)
189{
190 int i = 0;
191 int rc = 0;
192 struct dsi_regulator_info *regs;
193
194 regs = &phy->pwr_info.digital;
195 for (i = 0; i < regs->count; i++) {
196 if (!regs->vregs[i].vreg)
197 pr_err("vreg is NULL, should not reach here\n");
198 else
199 devm_regulator_put(regs->vregs[i].vreg);
200 }
201
202 regs = &phy->pwr_info.phy_pwr;
203 for (i = 0; i < regs->count; i++) {
204 if (!regs->vregs[i].vreg)
205 pr_err("vreg is NULL, should not reach here\n");
206 else
207 devm_regulator_put(regs->vregs[i].vreg);
208 }
209
210 if (phy->pwr_info.phy_pwr.vregs) {
211 devm_kfree(&phy->pdev->dev, phy->pwr_info.phy_pwr.vregs);
212 phy->pwr_info.phy_pwr.vregs = NULL;
213 phy->pwr_info.phy_pwr.count = 0;
214 }
215 if (phy->pwr_info.digital.vregs) {
216 devm_kfree(&phy->pdev->dev, phy->pwr_info.digital.vregs);
217 phy->pwr_info.digital.vregs = NULL;
218 phy->pwr_info.digital.count = 0;
219 }
220
221 return rc;
222}
223
224static int dsi_phy_parse_dt_per_lane_cfgs(struct platform_device *pdev,
225 struct dsi_phy_per_lane_cfgs *cfg,
226 char *property)
227{
228 int rc = 0, i = 0, j = 0;
229 const u8 *data;
230 u32 len = 0;
231
232 data = of_get_property(pdev->dev.of_node, property, &len);
233 if (!data) {
234 pr_err("Unable to read Phy %s settings\n", property);
235 return -EINVAL;
236 }
237
238 if (len != DSI_LANE_MAX * cfg->count_per_lane) {
239 pr_err("incorrect phy %s settings, exp=%d, act=%d\n",
240 property, (DSI_LANE_MAX * cfg->count_per_lane), len);
241 return -EINVAL;
242 }
243
244 for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
245 for (j = 0; j < cfg->count_per_lane; j++) {
246 cfg->lane[i][j] = *data;
247 data++;
248 }
249 }
250
251 return rc;
252}
253
254static int dsi_phy_settings_init(struct platform_device *pdev,
255 struct msm_dsi_phy *phy)
256{
257 int rc = 0;
258 struct dsi_phy_per_lane_cfgs *lane = &phy->cfg.lanecfg;
259 struct dsi_phy_per_lane_cfgs *strength = &phy->cfg.strength;
260 struct dsi_phy_per_lane_cfgs *timing = &phy->cfg.timing;
261 struct dsi_phy_per_lane_cfgs *regs = &phy->cfg.regulators;
262
263 lane->count_per_lane = phy->ver_info->lane_cfg_count;
264 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, lane,
265 "qcom,platform-lane-config");
266 if (rc) {
267 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
268 goto err;
269 }
270
271 strength->count_per_lane = phy->ver_info->strength_cfg_count;
272 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, strength,
273 "qcom,platform-strength-ctrl");
274 if (rc) {
275 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
276 goto err;
277 }
278
279 regs->count_per_lane = phy->ver_info->regulator_cfg_count;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530280 if (regs->count_per_lane > 0) {
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700281 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, regs,
282 "qcom,platform-regulator-settings");
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530283 if (rc) {
284 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
285 goto err;
286 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700287 }
288
289 /* Actual timing values are dependent on panel */
290 timing->count_per_lane = phy->ver_info->timing_cfg_count;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530291 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700292err:
293 lane->count_per_lane = 0;
294 strength->count_per_lane = 0;
295 regs->count_per_lane = 0;
296 timing->count_per_lane = 0;
297 return rc;
298}
299
300static int dsi_phy_settings_deinit(struct msm_dsi_phy *phy)
301{
302 memset(&phy->cfg.lanecfg, 0x0, sizeof(phy->cfg.lanecfg));
303 memset(&phy->cfg.strength, 0x0, sizeof(phy->cfg.strength));
304 memset(&phy->cfg.timing, 0x0, sizeof(phy->cfg.timing));
305 memset(&phy->cfg.regulators, 0x0, sizeof(phy->cfg.regulators));
306 return 0;
307}
308
309static int dsi_phy_driver_probe(struct platform_device *pdev)
310{
311 struct msm_dsi_phy *dsi_phy;
312 struct dsi_phy_list_item *item;
313 const struct of_device_id *id;
314 const struct dsi_ver_spec_info *ver_info;
315 int rc = 0;
316 u32 index = 0;
317
318 if (!pdev || !pdev->dev.of_node) {
319 pr_err("pdev not found\n");
320 return -ENODEV;
321 }
322
323 id = of_match_node(msm_dsi_phy_of_match, pdev->dev.of_node);
324 if (!id)
325 return -ENODEV;
326
327 ver_info = id->data;
328
329 item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL);
330 if (!item)
331 return -ENOMEM;
332
333
334 dsi_phy = devm_kzalloc(&pdev->dev, sizeof(*dsi_phy), GFP_KERNEL);
335 if (!dsi_phy) {
336 devm_kfree(&pdev->dev, item);
337 return -ENOMEM;
338 }
339
340 rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
341 if (rc) {
342 pr_debug("cell index not set, default to 0\n");
343 index = 0;
344 }
345
346 dsi_phy->index = index;
347
348 dsi_phy->name = of_get_property(pdev->dev.of_node, "label", NULL);
349 if (!dsi_phy->name)
350 dsi_phy->name = DSI_PHY_DEFAULT_LABEL;
351
352 pr_debug("Probing %s device\n", dsi_phy->name);
353
354 rc = dsi_phy_regmap_init(pdev, dsi_phy);
355 if (rc) {
356 pr_err("Failed to parse register information, rc=%d\n", rc);
357 goto fail;
358 }
359
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700360 rc = dsi_phy_supplies_init(pdev, dsi_phy);
361 if (rc) {
362 pr_err("failed to parse voltage supplies, rc = %d\n", rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530363 goto fail_regmap;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700364 }
365
366 rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version,
367 dsi_phy->index);
368 if (rc) {
369 pr_err("Catalog does not support version (%d)\n",
370 ver_info->version);
371 goto fail_supplies;
372 }
373
374 dsi_phy->ver_info = ver_info;
375 rc = dsi_phy_settings_init(pdev, dsi_phy);
376 if (rc) {
377 pr_err("Failed to parse phy setting, rc=%d\n", rc);
378 goto fail_supplies;
379 }
380
381 item->phy = dsi_phy;
382
383 mutex_lock(&dsi_phy_list_lock);
384 list_add(&item->list, &dsi_phy_list);
385 mutex_unlock(&dsi_phy_list_lock);
386
387 mutex_init(&dsi_phy->phy_lock);
388 /** TODO: initialize debugfs */
389 dsi_phy->pdev = pdev;
390 platform_set_drvdata(pdev, dsi_phy);
Shashank Babu Chinta Venkata2f24e982017-04-21 14:57:53 -0700391 pr_info("Probe successful for %s\n", dsi_phy->name);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700392 return 0;
393
394fail_supplies:
395 (void)dsi_phy_supplies_deinit(dsi_phy);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700396fail_regmap:
397 (void)dsi_phy_regmap_deinit(dsi_phy);
398fail:
399 devm_kfree(&pdev->dev, dsi_phy);
400 devm_kfree(&pdev->dev, item);
401 return rc;
402}
403
404static int dsi_phy_driver_remove(struct platform_device *pdev)
405{
406 int rc = 0;
407 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
408 struct list_head *pos, *tmp;
409
410 if (!pdev || !phy) {
411 pr_err("Invalid device\n");
412 return -EINVAL;
413 }
414
415 mutex_lock(&dsi_phy_list_lock);
416 list_for_each_safe(pos, tmp, &dsi_phy_list) {
417 struct dsi_phy_list_item *n;
418
419 n = list_entry(pos, struct dsi_phy_list_item, list);
420 if (n->phy == phy) {
421 list_del(&n->list);
422 devm_kfree(&pdev->dev, n);
423 break;
424 }
425 }
426 mutex_unlock(&dsi_phy_list_lock);
427
428 mutex_lock(&phy->phy_lock);
429 rc = dsi_phy_settings_deinit(phy);
430 if (rc)
431 pr_err("failed to deinitialize phy settings, rc=%d\n", rc);
432
433 rc = dsi_phy_supplies_deinit(phy);
434 if (rc)
435 pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
436
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700437 rc = dsi_phy_regmap_deinit(phy);
438 if (rc)
439 pr_err("failed to deinitialize regmap, rc=%d\n", rc);
440 mutex_unlock(&phy->phy_lock);
441
442 mutex_destroy(&phy->phy_lock);
443 devm_kfree(&pdev->dev, phy);
444
445 platform_set_drvdata(pdev, NULL);
446
447 return 0;
448}
449
450static struct platform_driver dsi_phy_platform_driver = {
451 .probe = dsi_phy_driver_probe,
452 .remove = dsi_phy_driver_remove,
453 .driver = {
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700454 .name = "dsi_phy",
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700455 .of_match_table = msm_dsi_phy_of_match,
456 },
457};
458
459static void dsi_phy_enable_hw(struct msm_dsi_phy *phy)
460{
461 if (phy->hw.ops.regulator_enable)
462 phy->hw.ops.regulator_enable(&phy->hw, &phy->cfg.regulators);
463
464 if (phy->hw.ops.enable)
465 phy->hw.ops.enable(&phy->hw, &phy->cfg);
466}
467
468static void dsi_phy_disable_hw(struct msm_dsi_phy *phy)
469{
470 if (phy->hw.ops.disable)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530471 phy->hw.ops.disable(&phy->hw, &phy->cfg);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700472
473 if (phy->hw.ops.regulator_disable)
474 phy->hw.ops.regulator_disable(&phy->hw);
475}
476
477/**
478 * dsi_phy_get() - get a dsi phy handle from device node
479 * @of_node: device node for dsi phy controller
480 *
481 * Gets the DSI PHY handle for the corresponding of_node. The ref count is
482 * incremented to one all subsequents get will fail until the original client
483 * calls a put.
484 *
485 * Return: DSI PHY handle or an error code.
486 */
487struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node)
488{
489 struct list_head *pos, *tmp;
490 struct msm_dsi_phy *phy = NULL;
491
492 mutex_lock(&dsi_phy_list_lock);
493 list_for_each_safe(pos, tmp, &dsi_phy_list) {
494 struct dsi_phy_list_item *n;
495
496 n = list_entry(pos, struct dsi_phy_list_item, list);
497 if (n->phy->pdev->dev.of_node == of_node) {
498 phy = n->phy;
499 break;
500 }
501 }
502 mutex_unlock(&dsi_phy_list_lock);
503
504 if (!phy) {
505 pr_err("Device with of node not found\n");
506 phy = ERR_PTR(-EPROBE_DEFER);
507 return phy;
508 }
509
510 mutex_lock(&phy->phy_lock);
511 if (phy->refcount > 0) {
512 pr_err("[PHY_%d] Device under use\n", phy->index);
513 phy = ERR_PTR(-EINVAL);
514 } else {
515 phy->refcount++;
516 }
517 mutex_unlock(&phy->phy_lock);
518 return phy;
519}
520
521/**
522 * dsi_phy_put() - release dsi phy handle
523 * @dsi_phy: DSI PHY handle.
524 *
525 * Release the DSI PHY hardware. Driver will clean up all resources and puts
526 * back the DSI PHY into reset state.
527 */
528void dsi_phy_put(struct msm_dsi_phy *dsi_phy)
529{
530 mutex_lock(&dsi_phy->phy_lock);
531
532 if (dsi_phy->refcount == 0)
533 pr_err("Unbalanced dsi_phy_put call\n");
534 else
535 dsi_phy->refcount--;
536
537 mutex_unlock(&dsi_phy->phy_lock);
538}
539
540/**
541 * dsi_phy_drv_init() - initialize dsi phy driver
542 * @dsi_phy: DSI PHY handle.
543 *
544 * Initializes DSI PHY driver. Should be called after dsi_phy_get().
545 *
546 * Return: error code.
547 */
548int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy)
549{
550 return 0;
551}
552
553/**
554 * dsi_phy_drv_deinit() - de-initialize dsi phy driver
555 * @dsi_phy: DSI PHY handle.
556 *
557 * Release all resources acquired by dsi_phy_drv_init().
558 *
559 * Return: error code.
560 */
561int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy)
562{
563 return 0;
564}
565
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530566int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
567 struct clk_ctrl_cb *clk_cb)
568{
569 if (!dsi_phy || !clk_cb) {
570 pr_err("Invalid params\n");
571 return -EINVAL;
572 }
573
574 dsi_phy->clk_cb.priv = clk_cb->priv;
575 dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
576 return 0;
577}
578
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700579/**
580 * dsi_phy_validate_mode() - validate a display mode
581 * @dsi_phy: DSI PHY handle.
582 * @mode: Mode information.
583 *
584 * Validation will fail if the mode cannot be supported by the PHY driver or
585 * hardware.
586 *
587 * Return: error code.
588 */
589int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
590 struct dsi_mode_info *mode)
591{
592 int rc = 0;
593
594 if (!dsi_phy || !mode) {
595 pr_err("Invalid params\n");
596 return -EINVAL;
597 }
598
599 mutex_lock(&dsi_phy->phy_lock);
600
601 pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
602
603 mutex_unlock(&dsi_phy->phy_lock);
604 return rc;
605}
606
607/**
608 * dsi_phy_set_power_state() - enable/disable dsi phy power supplies
609 * @dsi_phy: DSI PHY handle.
610 * @enable: Boolean flag to enable/disable.
611 *
612 * Return: error code.
613 */
614int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable)
615{
616 int rc = 0;
617
618 if (!dsi_phy) {
619 pr_err("Invalid params\n");
620 return -EINVAL;
621 }
622
623 mutex_lock(&dsi_phy->phy_lock);
624
625 if (enable == dsi_phy->power_state) {
626 pr_err("[PHY_%d] No state change\n", dsi_phy->index);
627 goto error;
628 }
629
630 if (enable) {
631 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, true);
632 if (rc) {
633 pr_err("failed to enable digital regulator\n");
634 goto error;
635 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530636
637 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
638 rc = dsi_pwr_enable_regulator(
639 &dsi_phy->pwr_info.phy_pwr, true);
640 if (rc) {
641 pr_err("failed to enable phy power\n");
642 (void)dsi_pwr_enable_regulator(
643 &dsi_phy->pwr_info.digital, false);
644 goto error;
645 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700646 }
647 } else {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530648 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
649 rc = dsi_pwr_enable_regulator(
650 &dsi_phy->pwr_info.phy_pwr, false);
651 if (rc) {
652 pr_err("failed to enable digital regulator\n");
653 goto error;
654 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700655 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530656
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700657 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital,
658 false);
659 if (rc) {
660 pr_err("failed to enable phy power\n");
661 goto error;
662 }
663 }
664
665 dsi_phy->power_state = enable;
666error:
667 mutex_unlock(&dsi_phy->phy_lock);
668 return rc;
669}
670
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530671static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy,
672 struct dsi_host_config *config)
673{
674 int rc = 0;
675 u32 lanes = 0;
676 u32 ulps_lanes;
677
678 if (config->panel_mode == DSI_OP_CMD_MODE)
679 lanes = config->common_config.data_lanes;
680 lanes |= DSI_CLOCK_LANE;
681
682 rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
683 if (rc) {
684 pr_err("lanes not entering idle, skip ULPS\n");
685 return rc;
686 }
687
688 phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
689
690 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
691
692 if ((lanes & ulps_lanes) != lanes) {
693 pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
694 lanes, ulps_lanes);
695 rc = -EIO;
696 }
697
698 return rc;
699}
700
701static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
702 struct dsi_host_config *config)
703{
704 int rc = 0;
705 u32 ulps_lanes, lanes = 0;
706
707 if (config->panel_mode == DSI_OP_CMD_MODE)
708 lanes = config->common_config.data_lanes;
709 lanes |= DSI_CLOCK_LANE;
710
711 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
712
713 if ((lanes & ulps_lanes) != lanes)
714 pr_err("Mismatch between lanes in ULPS\n");
715
716 lanes &= ulps_lanes;
717
718 phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
719
720 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
721 if (ulps_lanes & lanes) {
722 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
723 rc = -EIO;
724 }
725
726 return rc;
727}
728
729
730int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
731 bool enable)
732{
733 int rc = 0;
734
735 if (!phy) {
736 pr_err("Invalid params\n");
737 return -EINVAL;
738 }
739
740 if (!phy->hw.ops.ulps_ops.ulps_request ||
741 !phy->hw.ops.ulps_ops.ulps_exit) {
742 pr_debug("DSI PHY ULPS ops not present\n");
743 return 0;
744 }
745
746 mutex_lock(&phy->phy_lock);
747
748 if (enable)
749 rc = dsi_phy_enable_ulps(phy, config);
750 else
751 rc = dsi_phy_disable_ulps(phy, config);
752
753 if (rc) {
754 pr_err("[DSI_PHY%d] Ulps state change(%d) failed, rc=%d\n",
755 phy->index, enable, rc);
756 goto error;
757 }
758 pr_debug("[DSI_PHY%d] ULPS state = %d\n", phy->index, enable);
759
760error:
761 mutex_unlock(&phy->phy_lock);
762 return rc;
763}
764
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700765/**
766 * dsi_phy_enable() - enable DSI PHY hardware
767 * @dsi_phy: DSI PHY handle.
768 * @config: DSI host configuration.
769 * @pll_source: Source PLL for PHY clock.
770 * @skip_validation: Validation will not be performed on parameters.
771 *
772 * Validates and enables DSI PHY.
773 *
774 * Return: error code.
775 */
776int dsi_phy_enable(struct msm_dsi_phy *phy,
777 struct dsi_host_config *config,
778 enum dsi_phy_pll_source pll_source,
779 bool skip_validation)
780{
781 int rc = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530782 struct dsi_clk_ctrl_info clk_info;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700783
784 if (!phy || !config) {
785 pr_err("Invalid params\n");
786 return -EINVAL;
787 }
788
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530789 clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
790 clk_info.clk_type = DSI_CORE_CLK;
791 clk_info.clk_state = DSI_CLK_ON;
792
793 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
794 if (rc) {
795 pr_err("failed to enable DSI core clocks\n");
796 return rc;
797 }
798
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700799 mutex_lock(&phy->phy_lock);
800
801 if (!skip_validation)
802 pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
803
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700804 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530805 memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700806 phy->data_lanes = config->common_config.data_lanes;
807 phy->dst_format = config->common_config.dst_format;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700808 phy->cfg.pll_source = pll_source;
809
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530810 /**
811 * If PHY timing parameters are not present in panel dtsi file,
812 * then calculate them in the driver
813 */
814 if (!phy->cfg.is_phy_timing_present)
815 rc = phy->hw.ops.calculate_timing_params(&phy->hw,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700816 &phy->mode,
817 &config->common_config,
818 &phy->cfg.timing);
819 if (rc) {
820 pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530821 goto error;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700822 }
823
824 dsi_phy_enable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530825 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700826
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700827error:
828 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530829
830 clk_info.clk_state = DSI_CLK_OFF;
831 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
832 if (rc)
833 pr_err("failed to disable DSI core clocks\n");
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700834 return rc;
835}
836
837/**
838 * dsi_phy_disable() - disable DSI PHY hardware.
839 * @phy: DSI PHY handle.
840 *
841 * Return: error code.
842 */
843int dsi_phy_disable(struct msm_dsi_phy *phy)
844{
845 int rc = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530846 struct dsi_clk_ctrl_info clk_info;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700847
848 if (!phy) {
849 pr_err("Invalid params\n");
850 return -EINVAL;
851 }
852
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530853 clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
854 clk_info.clk_type = DSI_CORE_CLK;
855 clk_info.clk_state = DSI_CLK_ON;
856
857 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
858 if (rc) {
859 pr_err("failed to enable DSI core clocks\n");
860 return rc;
861 }
862
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700863 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700864 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530865 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
866 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700867
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530868 clk_info.clk_state = DSI_CLK_OFF;
869
870 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
871 if (rc)
872 pr_err("failed to disable DSI core clocks\n");
873
874 return rc;
875}
876
877/**
878 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
879 * @phy: DSI PHY handle
880 * @enable: boolean to specify PHY enable/disable.
881 *
882 * Return: error code.
883 */
884
885int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
886{
887 if (!phy) {
888 pr_err("Invalid params\n");
889 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700890 }
891
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530892 mutex_lock(&phy->phy_lock);
893 if (enable) {
894 if (phy->hw.ops.phy_idle_on)
895 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
896
897 if (phy->hw.ops.regulator_enable)
898 phy->hw.ops.regulator_enable(&phy->hw,
899 &phy->cfg.regulators);
900 } else {
901 if (phy->hw.ops.phy_idle_off)
902 phy->hw.ops.phy_idle_off(&phy->hw);
903 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700904 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530905
906 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700907}
908
909/**
910 * dsi_phy_set_timing_params() - timing parameters for the panel
911 * @phy: DSI PHY handle
912 * @timing: array holding timing params.
913 * @size: size of the array.
914 *
915 * When PHY timing calculator is not implemented, this array will be used to
916 * pass PHY timing information.
917 *
918 * Return: error code.
919 */
920int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530921 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700922{
923 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700924
925 if (!phy || !timing || !size) {
926 pr_err("Invalid params\n");
927 return -EINVAL;
928 }
929
930 mutex_lock(&phy->phy_lock);
931
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530932 if (phy->hw.ops.phy_timing_val)
933 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
934 if (!rc)
935 phy->cfg.is_phy_timing_present = true;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700936 mutex_unlock(&phy->phy_lock);
937 return rc;
938}
939
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700940void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700941{
942 platform_driver_register(&dsi_phy_platform_driver);
943}
944
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700945void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700946{
947 platform_driver_unregister(&dsi_phy_platform_driver);
948}