blob: f140842aaca2e19c8acfbfbf5b750313bcb348b7 [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);
391 pr_debug("Probe successful for %s\n", dsi_phy->name);
392 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,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700672 struct dsi_host_config *config, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530673{
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
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700682 /*
683 * If DSI clamps are enabled, it means that the DSI lanes are
684 * already in idle state. Checking for lanes to be in idle state
685 * should be skipped during ULPS entry programming while coming
686 * out of idle screen.
687 */
688 if (!clamp_enabled) {
689 rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
690 if (rc) {
691 pr_err("lanes not entering idle, skip ULPS\n");
692 return rc;
693 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530694 }
695
696 phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
697
698 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
699
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700700 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530701 pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
702 lanes, ulps_lanes);
703 rc = -EIO;
704 }
705
706 return rc;
707}
708
709static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
710 struct dsi_host_config *config)
711{
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530712 u32 ulps_lanes, lanes = 0;
713
714 if (config->panel_mode == DSI_OP_CMD_MODE)
715 lanes = config->common_config.data_lanes;
716 lanes |= DSI_CLOCK_LANE;
717
718 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
719
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700720 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
721 pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
722 lanes, ulps_lanes);
723 return -EIO;
724 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530725
726 phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
727
728 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700729
730 if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530731 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700732 return -EIO;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530733 }
734
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700735 return 0;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530736}
737
738
739int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700740 bool enable, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530741{
742 int rc = 0;
743
744 if (!phy) {
745 pr_err("Invalid params\n");
746 return -EINVAL;
747 }
748
749 if (!phy->hw.ops.ulps_ops.ulps_request ||
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700750 !phy->hw.ops.ulps_ops.ulps_exit ||
751 !phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
752 !phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
753 !phy->hw.ops.ulps_ops.wait_for_lane_idle) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530754 pr_debug("DSI PHY ULPS ops not present\n");
755 return 0;
756 }
757
758 mutex_lock(&phy->phy_lock);
759
760 if (enable)
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700761 rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530762 else
763 rc = dsi_phy_disable_ulps(phy, config);
764
765 if (rc) {
766 pr_err("[DSI_PHY%d] Ulps state change(%d) failed, rc=%d\n",
767 phy->index, enable, rc);
768 goto error;
769 }
770 pr_debug("[DSI_PHY%d] ULPS state = %d\n", phy->index, enable);
771
772error:
773 mutex_unlock(&phy->phy_lock);
774 return rc;
775}
776
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700777/**
778 * dsi_phy_enable() - enable DSI PHY hardware
779 * @dsi_phy: DSI PHY handle.
780 * @config: DSI host configuration.
781 * @pll_source: Source PLL for PHY clock.
782 * @skip_validation: Validation will not be performed on parameters.
783 *
784 * Validates and enables DSI PHY.
785 *
786 * Return: error code.
787 */
788int dsi_phy_enable(struct msm_dsi_phy *phy,
789 struct dsi_host_config *config,
790 enum dsi_phy_pll_source pll_source,
791 bool skip_validation)
792{
793 int rc = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530794 struct dsi_clk_ctrl_info clk_info;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700795
796 if (!phy || !config) {
797 pr_err("Invalid params\n");
798 return -EINVAL;
799 }
800
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530801 clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
802 clk_info.clk_type = DSI_CORE_CLK;
803 clk_info.clk_state = DSI_CLK_ON;
804
805 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
806 if (rc) {
807 pr_err("failed to enable DSI core clocks\n");
808 return rc;
809 }
810
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700811 mutex_lock(&phy->phy_lock);
812
813 if (!skip_validation)
814 pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
815
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700816 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530817 memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700818 phy->data_lanes = config->common_config.data_lanes;
819 phy->dst_format = config->common_config.dst_format;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700820 phy->cfg.pll_source = pll_source;
821
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530822 /**
823 * If PHY timing parameters are not present in panel dtsi file,
824 * then calculate them in the driver
825 */
826 if (!phy->cfg.is_phy_timing_present)
827 rc = phy->hw.ops.calculate_timing_params(&phy->hw,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700828 &phy->mode,
829 &config->common_config,
830 &phy->cfg.timing);
831 if (rc) {
832 pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530833 goto error;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700834 }
835
836 dsi_phy_enable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530837 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700838
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700839error:
840 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530841
842 clk_info.clk_state = DSI_CLK_OFF;
843 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
844 if (rc)
845 pr_err("failed to disable DSI core clocks\n");
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700846 return rc;
847}
848
849/**
850 * dsi_phy_disable() - disable DSI PHY hardware.
851 * @phy: DSI PHY handle.
852 *
853 * Return: error code.
854 */
855int dsi_phy_disable(struct msm_dsi_phy *phy)
856{
857 int rc = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530858 struct dsi_clk_ctrl_info clk_info;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700859
860 if (!phy) {
861 pr_err("Invalid params\n");
862 return -EINVAL;
863 }
864
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530865 clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
866 clk_info.clk_type = DSI_CORE_CLK;
867 clk_info.clk_state = DSI_CLK_ON;
868
869 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
870 if (rc) {
871 pr_err("failed to enable DSI core clocks\n");
872 return rc;
873 }
874
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700875 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700876 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530877 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
878 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700879
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530880 clk_info.clk_state = DSI_CLK_OFF;
881
882 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
883 if (rc)
884 pr_err("failed to disable DSI core clocks\n");
885
886 return rc;
887}
888
889/**
890 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
891 * @phy: DSI PHY handle
892 * @enable: boolean to specify PHY enable/disable.
893 *
894 * Return: error code.
895 */
896
897int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
898{
899 if (!phy) {
900 pr_err("Invalid params\n");
901 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700902 }
903
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530904 mutex_lock(&phy->phy_lock);
905 if (enable) {
906 if (phy->hw.ops.phy_idle_on)
907 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
908
909 if (phy->hw.ops.regulator_enable)
910 phy->hw.ops.regulator_enable(&phy->hw,
911 &phy->cfg.regulators);
912 } else {
913 if (phy->hw.ops.phy_idle_off)
914 phy->hw.ops.phy_idle_off(&phy->hw);
915 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700916 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530917
918 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700919}
920
921/**
922 * dsi_phy_set_timing_params() - timing parameters for the panel
923 * @phy: DSI PHY handle
924 * @timing: array holding timing params.
925 * @size: size of the array.
926 *
927 * When PHY timing calculator is not implemented, this array will be used to
928 * pass PHY timing information.
929 *
930 * Return: error code.
931 */
932int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530933 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700934{
935 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700936
937 if (!phy || !timing || !size) {
938 pr_err("Invalid params\n");
939 return -EINVAL;
940 }
941
942 mutex_lock(&phy->phy_lock);
943
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530944 if (phy->hw.ops.phy_timing_val)
945 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
946 if (!rc)
947 phy->cfg.is_phy_timing_present = true;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700948 mutex_unlock(&phy->phy_lock);
949 return rc;
950}
951
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700952void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700953{
954 platform_driver_register(&dsi_phy_platform_driver);
955}
956
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700957void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700958{
959 platform_driver_unregister(&dsi_phy_platform_driver);
960}