blob: 287afda1abd0a4d2609b1905376b0814889a3fb1 [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
Dhaval Patela2430842017-06-15 14:32:36 -070032#include "sde_dbg.h"
33
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070034#define DSI_PHY_DEFAULT_LABEL "MDSS PHY CTRL"
35
36struct dsi_phy_list_item {
37 struct msm_dsi_phy *phy;
38 struct list_head list;
39};
40
41static LIST_HEAD(dsi_phy_list);
42static DEFINE_MUTEX(dsi_phy_list_lock);
43
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053044static const struct dsi_ver_spec_info dsi_phy_v0_0_hpm = {
45 .version = DSI_PHY_VERSION_0_0_HPM,
46 .lane_cfg_count = 4,
47 .strength_cfg_count = 2,
48 .regulator_cfg_count = 1,
49 .timing_cfg_count = 8,
50};
51static const struct dsi_ver_spec_info dsi_phy_v0_0_lpm = {
52 .version = DSI_PHY_VERSION_0_0_LPM,
53 .lane_cfg_count = 4,
54 .strength_cfg_count = 2,
55 .regulator_cfg_count = 1,
56 .timing_cfg_count = 8,
57};
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070058static const struct dsi_ver_spec_info dsi_phy_v1_0 = {
59 .version = DSI_PHY_VERSION_1_0,
60 .lane_cfg_count = 4,
61 .strength_cfg_count = 2,
62 .regulator_cfg_count = 1,
63 .timing_cfg_count = 8,
64};
65static const struct dsi_ver_spec_info dsi_phy_v2_0 = {
66 .version = DSI_PHY_VERSION_2_0,
67 .lane_cfg_count = 4,
68 .strength_cfg_count = 2,
69 .regulator_cfg_count = 1,
70 .timing_cfg_count = 8,
71};
72static const struct dsi_ver_spec_info dsi_phy_v3_0 = {
73 .version = DSI_PHY_VERSION_3_0,
74 .lane_cfg_count = 4,
75 .strength_cfg_count = 2,
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053076 .regulator_cfg_count = 0,
77 .timing_cfg_count = 12,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070078};
79
80static const struct of_device_id msm_dsi_phy_of_match[] = {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +053081 { .compatible = "qcom,dsi-phy-v0.0-hpm",
82 .data = &dsi_phy_v0_0_hpm,},
83 { .compatible = "qcom,dsi-phy-v0.0-lpm",
84 .data = &dsi_phy_v0_0_lpm,},
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070085 { .compatible = "qcom,dsi-phy-v1.0",
86 .data = &dsi_phy_v1_0,},
87 { .compatible = "qcom,dsi-phy-v2.0",
88 .data = &dsi_phy_v2_0,},
89 { .compatible = "qcom,dsi-phy-v3.0",
90 .data = &dsi_phy_v3_0,},
Ajay Singh Parmar67f31322016-06-22 17:37:56 -070091 {}
92};
93
94static int dsi_phy_regmap_init(struct platform_device *pdev,
95 struct msm_dsi_phy *phy)
96{
97 int rc = 0;
98 void __iomem *ptr;
99
100 ptr = msm_ioremap(pdev, "dsi_phy", phy->name);
101 if (IS_ERR(ptr)) {
102 rc = PTR_ERR(ptr);
103 return rc;
104 }
105
106 phy->hw.base = ptr;
107
108 pr_debug("[%s] map dsi_phy registers to %p\n", phy->name, phy->hw.base);
109
110 return rc;
111}
112
113static int dsi_phy_regmap_deinit(struct msm_dsi_phy *phy)
114{
115 pr_debug("[%s] unmap registers\n", phy->name);
116 return 0;
117}
118
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700119static int dsi_phy_supplies_init(struct platform_device *pdev,
120 struct msm_dsi_phy *phy)
121{
122 int rc = 0;
123 int i = 0;
124 struct dsi_regulator_info *regs;
125 struct regulator *vreg = NULL;
126
127 regs = &phy->pwr_info.digital;
128 regs->vregs = devm_kzalloc(&pdev->dev, sizeof(struct dsi_vreg),
129 GFP_KERNEL);
130 if (!regs->vregs)
131 goto error;
132
133 regs->count = 1;
134 snprintf(regs->vregs->vreg_name,
135 ARRAY_SIZE(regs->vregs[i].vreg_name),
136 "%s", "gdsc");
137
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530138 rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700139 &phy->pwr_info.phy_pwr,
140 "qcom,phy-supply-entries");
141 if (rc) {
142 pr_err("failed to get host power supplies, rc = %d\n", rc);
143 goto error_digital;
144 }
145
146 regs = &phy->pwr_info.digital;
147 for (i = 0; i < regs->count; i++) {
148 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
149 rc = PTR_RET(vreg);
150 if (rc) {
151 pr_err("failed to get %s regulator\n",
152 regs->vregs[i].vreg_name);
153 goto error_host_pwr;
154 }
155 regs->vregs[i].vreg = vreg;
156 }
157
158 regs = &phy->pwr_info.phy_pwr;
159 for (i = 0; i < regs->count; i++) {
160 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
161 rc = PTR_RET(vreg);
162 if (rc) {
163 pr_err("failed to get %s regulator\n",
164 regs->vregs[i].vreg_name);
165 for (--i; i >= 0; i--)
166 devm_regulator_put(regs->vregs[i].vreg);
167 goto error_digital_put;
168 }
169 regs->vregs[i].vreg = vreg;
170 }
171
172 return rc;
173
174error_digital_put:
175 regs = &phy->pwr_info.digital;
176 for (i = 0; i < regs->count; i++)
177 devm_regulator_put(regs->vregs[i].vreg);
178error_host_pwr:
179 devm_kfree(&pdev->dev, phy->pwr_info.phy_pwr.vregs);
180 phy->pwr_info.phy_pwr.vregs = NULL;
181 phy->pwr_info.phy_pwr.count = 0;
182error_digital:
183 devm_kfree(&pdev->dev, phy->pwr_info.digital.vregs);
184 phy->pwr_info.digital.vregs = NULL;
185 phy->pwr_info.digital.count = 0;
186error:
187 return rc;
188}
189
190static int dsi_phy_supplies_deinit(struct msm_dsi_phy *phy)
191{
192 int i = 0;
193 int rc = 0;
194 struct dsi_regulator_info *regs;
195
196 regs = &phy->pwr_info.digital;
197 for (i = 0; i < regs->count; i++) {
198 if (!regs->vregs[i].vreg)
199 pr_err("vreg is NULL, should not reach here\n");
200 else
201 devm_regulator_put(regs->vregs[i].vreg);
202 }
203
204 regs = &phy->pwr_info.phy_pwr;
205 for (i = 0; i < regs->count; i++) {
206 if (!regs->vregs[i].vreg)
207 pr_err("vreg is NULL, should not reach here\n");
208 else
209 devm_regulator_put(regs->vregs[i].vreg);
210 }
211
212 if (phy->pwr_info.phy_pwr.vregs) {
213 devm_kfree(&phy->pdev->dev, phy->pwr_info.phy_pwr.vregs);
214 phy->pwr_info.phy_pwr.vregs = NULL;
215 phy->pwr_info.phy_pwr.count = 0;
216 }
217 if (phy->pwr_info.digital.vregs) {
218 devm_kfree(&phy->pdev->dev, phy->pwr_info.digital.vregs);
219 phy->pwr_info.digital.vregs = NULL;
220 phy->pwr_info.digital.count = 0;
221 }
222
223 return rc;
224}
225
226static int dsi_phy_parse_dt_per_lane_cfgs(struct platform_device *pdev,
227 struct dsi_phy_per_lane_cfgs *cfg,
228 char *property)
229{
230 int rc = 0, i = 0, j = 0;
231 const u8 *data;
232 u32 len = 0;
233
234 data = of_get_property(pdev->dev.of_node, property, &len);
235 if (!data) {
236 pr_err("Unable to read Phy %s settings\n", property);
237 return -EINVAL;
238 }
239
240 if (len != DSI_LANE_MAX * cfg->count_per_lane) {
241 pr_err("incorrect phy %s settings, exp=%d, act=%d\n",
242 property, (DSI_LANE_MAX * cfg->count_per_lane), len);
243 return -EINVAL;
244 }
245
246 for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
247 for (j = 0; j < cfg->count_per_lane; j++) {
248 cfg->lane[i][j] = *data;
249 data++;
250 }
251 }
252
253 return rc;
254}
255
256static int dsi_phy_settings_init(struct platform_device *pdev,
257 struct msm_dsi_phy *phy)
258{
259 int rc = 0;
260 struct dsi_phy_per_lane_cfgs *lane = &phy->cfg.lanecfg;
261 struct dsi_phy_per_lane_cfgs *strength = &phy->cfg.strength;
262 struct dsi_phy_per_lane_cfgs *timing = &phy->cfg.timing;
263 struct dsi_phy_per_lane_cfgs *regs = &phy->cfg.regulators;
264
265 lane->count_per_lane = phy->ver_info->lane_cfg_count;
266 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, lane,
267 "qcom,platform-lane-config");
268 if (rc) {
269 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
270 goto err;
271 }
272
273 strength->count_per_lane = phy->ver_info->strength_cfg_count;
274 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, strength,
275 "qcom,platform-strength-ctrl");
276 if (rc) {
277 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
278 goto err;
279 }
280
281 regs->count_per_lane = phy->ver_info->regulator_cfg_count;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530282 if (regs->count_per_lane > 0) {
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700283 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, regs,
284 "qcom,platform-regulator-settings");
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530285 if (rc) {
286 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
287 goto err;
288 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700289 }
290
291 /* Actual timing values are dependent on panel */
292 timing->count_per_lane = phy->ver_info->timing_cfg_count;
Alan Kwong797e0892017-10-17 09:37:24 -0400293
294 phy->allow_phy_power_off = of_property_read_bool(pdev->dev.of_node,
295 "qcom,panel-allow-phy-poweroff");
296
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530297 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700298err:
299 lane->count_per_lane = 0;
300 strength->count_per_lane = 0;
301 regs->count_per_lane = 0;
302 timing->count_per_lane = 0;
303 return rc;
304}
305
306static int dsi_phy_settings_deinit(struct msm_dsi_phy *phy)
307{
308 memset(&phy->cfg.lanecfg, 0x0, sizeof(phy->cfg.lanecfg));
309 memset(&phy->cfg.strength, 0x0, sizeof(phy->cfg.strength));
310 memset(&phy->cfg.timing, 0x0, sizeof(phy->cfg.timing));
311 memset(&phy->cfg.regulators, 0x0, sizeof(phy->cfg.regulators));
312 return 0;
313}
314
315static int dsi_phy_driver_probe(struct platform_device *pdev)
316{
317 struct msm_dsi_phy *dsi_phy;
318 struct dsi_phy_list_item *item;
319 const struct of_device_id *id;
320 const struct dsi_ver_spec_info *ver_info;
321 int rc = 0;
322 u32 index = 0;
323
324 if (!pdev || !pdev->dev.of_node) {
325 pr_err("pdev not found\n");
326 return -ENODEV;
327 }
328
329 id = of_match_node(msm_dsi_phy_of_match, pdev->dev.of_node);
330 if (!id)
331 return -ENODEV;
332
333 ver_info = id->data;
334
335 item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL);
336 if (!item)
337 return -ENOMEM;
338
339
340 dsi_phy = devm_kzalloc(&pdev->dev, sizeof(*dsi_phy), GFP_KERNEL);
341 if (!dsi_phy) {
342 devm_kfree(&pdev->dev, item);
343 return -ENOMEM;
344 }
345
346 rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
347 if (rc) {
348 pr_debug("cell index not set, default to 0\n");
349 index = 0;
350 }
351
352 dsi_phy->index = index;
353
354 dsi_phy->name = of_get_property(pdev->dev.of_node, "label", NULL);
355 if (!dsi_phy->name)
356 dsi_phy->name = DSI_PHY_DEFAULT_LABEL;
357
358 pr_debug("Probing %s device\n", dsi_phy->name);
359
360 rc = dsi_phy_regmap_init(pdev, dsi_phy);
361 if (rc) {
362 pr_err("Failed to parse register information, rc=%d\n", rc);
363 goto fail;
364 }
365
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700366 rc = dsi_phy_supplies_init(pdev, dsi_phy);
367 if (rc) {
368 pr_err("failed to parse voltage supplies, rc = %d\n", rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530369 goto fail_regmap;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700370 }
371
372 rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version,
373 dsi_phy->index);
374 if (rc) {
375 pr_err("Catalog does not support version (%d)\n",
376 ver_info->version);
377 goto fail_supplies;
378 }
379
380 dsi_phy->ver_info = ver_info;
381 rc = dsi_phy_settings_init(pdev, dsi_phy);
382 if (rc) {
383 pr_err("Failed to parse phy setting, rc=%d\n", rc);
384 goto fail_supplies;
385 }
386
387 item->phy = dsi_phy;
388
389 mutex_lock(&dsi_phy_list_lock);
390 list_add(&item->list, &dsi_phy_list);
391 mutex_unlock(&dsi_phy_list_lock);
392
393 mutex_init(&dsi_phy->phy_lock);
394 /** TODO: initialize debugfs */
395 dsi_phy->pdev = pdev;
396 platform_set_drvdata(pdev, dsi_phy);
Shashank Babu Chinta Venkata2f24e982017-04-21 14:57:53 -0700397 pr_info("Probe successful for %s\n", dsi_phy->name);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700398 return 0;
399
400fail_supplies:
401 (void)dsi_phy_supplies_deinit(dsi_phy);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700402fail_regmap:
403 (void)dsi_phy_regmap_deinit(dsi_phy);
404fail:
405 devm_kfree(&pdev->dev, dsi_phy);
406 devm_kfree(&pdev->dev, item);
407 return rc;
408}
409
410static int dsi_phy_driver_remove(struct platform_device *pdev)
411{
412 int rc = 0;
413 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
414 struct list_head *pos, *tmp;
415
416 if (!pdev || !phy) {
417 pr_err("Invalid device\n");
418 return -EINVAL;
419 }
420
421 mutex_lock(&dsi_phy_list_lock);
422 list_for_each_safe(pos, tmp, &dsi_phy_list) {
423 struct dsi_phy_list_item *n;
424
425 n = list_entry(pos, struct dsi_phy_list_item, list);
426 if (n->phy == phy) {
427 list_del(&n->list);
428 devm_kfree(&pdev->dev, n);
429 break;
430 }
431 }
432 mutex_unlock(&dsi_phy_list_lock);
433
434 mutex_lock(&phy->phy_lock);
435 rc = dsi_phy_settings_deinit(phy);
436 if (rc)
437 pr_err("failed to deinitialize phy settings, rc=%d\n", rc);
438
439 rc = dsi_phy_supplies_deinit(phy);
440 if (rc)
441 pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
442
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700443 rc = dsi_phy_regmap_deinit(phy);
444 if (rc)
445 pr_err("failed to deinitialize regmap, rc=%d\n", rc);
446 mutex_unlock(&phy->phy_lock);
447
448 mutex_destroy(&phy->phy_lock);
449 devm_kfree(&pdev->dev, phy);
450
451 platform_set_drvdata(pdev, NULL);
452
453 return 0;
454}
455
456static struct platform_driver dsi_phy_platform_driver = {
457 .probe = dsi_phy_driver_probe,
458 .remove = dsi_phy_driver_remove,
459 .driver = {
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700460 .name = "dsi_phy",
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700461 .of_match_table = msm_dsi_phy_of_match,
462 },
463};
464
465static void dsi_phy_enable_hw(struct msm_dsi_phy *phy)
466{
467 if (phy->hw.ops.regulator_enable)
468 phy->hw.ops.regulator_enable(&phy->hw, &phy->cfg.regulators);
469
470 if (phy->hw.ops.enable)
471 phy->hw.ops.enable(&phy->hw, &phy->cfg);
472}
473
474static void dsi_phy_disable_hw(struct msm_dsi_phy *phy)
475{
476 if (phy->hw.ops.disable)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530477 phy->hw.ops.disable(&phy->hw, &phy->cfg);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700478
479 if (phy->hw.ops.regulator_disable)
480 phy->hw.ops.regulator_disable(&phy->hw);
481}
482
483/**
484 * dsi_phy_get() - get a dsi phy handle from device node
485 * @of_node: device node for dsi phy controller
486 *
487 * Gets the DSI PHY handle for the corresponding of_node. The ref count is
488 * incremented to one all subsequents get will fail until the original client
489 * calls a put.
490 *
491 * Return: DSI PHY handle or an error code.
492 */
493struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node)
494{
495 struct list_head *pos, *tmp;
496 struct msm_dsi_phy *phy = NULL;
497
498 mutex_lock(&dsi_phy_list_lock);
499 list_for_each_safe(pos, tmp, &dsi_phy_list) {
500 struct dsi_phy_list_item *n;
501
502 n = list_entry(pos, struct dsi_phy_list_item, list);
503 if (n->phy->pdev->dev.of_node == of_node) {
504 phy = n->phy;
505 break;
506 }
507 }
508 mutex_unlock(&dsi_phy_list_lock);
509
510 if (!phy) {
511 pr_err("Device with of node not found\n");
512 phy = ERR_PTR(-EPROBE_DEFER);
513 return phy;
514 }
515
516 mutex_lock(&phy->phy_lock);
517 if (phy->refcount > 0) {
518 pr_err("[PHY_%d] Device under use\n", phy->index);
519 phy = ERR_PTR(-EINVAL);
520 } else {
521 phy->refcount++;
522 }
523 mutex_unlock(&phy->phy_lock);
524 return phy;
525}
526
527/**
528 * dsi_phy_put() - release dsi phy handle
529 * @dsi_phy: DSI PHY handle.
530 *
531 * Release the DSI PHY hardware. Driver will clean up all resources and puts
532 * back the DSI PHY into reset state.
533 */
534void dsi_phy_put(struct msm_dsi_phy *dsi_phy)
535{
536 mutex_lock(&dsi_phy->phy_lock);
537
538 if (dsi_phy->refcount == 0)
539 pr_err("Unbalanced dsi_phy_put call\n");
540 else
541 dsi_phy->refcount--;
542
543 mutex_unlock(&dsi_phy->phy_lock);
544}
545
546/**
547 * dsi_phy_drv_init() - initialize dsi phy driver
548 * @dsi_phy: DSI PHY handle.
549 *
550 * Initializes DSI PHY driver. Should be called after dsi_phy_get().
551 *
552 * Return: error code.
553 */
554int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy)
555{
Dhaval Patela2430842017-06-15 14:32:36 -0700556 char dbg_name[DSI_DEBUG_NAME_LEN];
557
558 snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_phy", dsi_phy->index);
559 sde_dbg_reg_register_base(dbg_name, dsi_phy->hw.base,
560 msm_iomap_size(dsi_phy->pdev, "dsi_phy"));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700561 return 0;
562}
563
564/**
565 * dsi_phy_drv_deinit() - de-initialize dsi phy driver
566 * @dsi_phy: DSI PHY handle.
567 *
568 * Release all resources acquired by dsi_phy_drv_init().
569 *
570 * Return: error code.
571 */
572int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy)
573{
574 return 0;
575}
576
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530577int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
578 struct clk_ctrl_cb *clk_cb)
579{
580 if (!dsi_phy || !clk_cb) {
581 pr_err("Invalid params\n");
582 return -EINVAL;
583 }
584
585 dsi_phy->clk_cb.priv = clk_cb->priv;
586 dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
587 return 0;
588}
589
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700590/**
591 * dsi_phy_validate_mode() - validate a display mode
592 * @dsi_phy: DSI PHY handle.
593 * @mode: Mode information.
594 *
595 * Validation will fail if the mode cannot be supported by the PHY driver or
596 * hardware.
597 *
598 * Return: error code.
599 */
600int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
601 struct dsi_mode_info *mode)
602{
603 int rc = 0;
604
605 if (!dsi_phy || !mode) {
606 pr_err("Invalid params\n");
607 return -EINVAL;
608 }
609
610 mutex_lock(&dsi_phy->phy_lock);
611
612 pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
613
614 mutex_unlock(&dsi_phy->phy_lock);
615 return rc;
616}
617
618/**
619 * dsi_phy_set_power_state() - enable/disable dsi phy power supplies
620 * @dsi_phy: DSI PHY handle.
621 * @enable: Boolean flag to enable/disable.
622 *
623 * Return: error code.
624 */
625int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable)
626{
627 int rc = 0;
628
629 if (!dsi_phy) {
630 pr_err("Invalid params\n");
631 return -EINVAL;
632 }
633
634 mutex_lock(&dsi_phy->phy_lock);
635
636 if (enable == dsi_phy->power_state) {
637 pr_err("[PHY_%d] No state change\n", dsi_phy->index);
638 goto error;
639 }
640
641 if (enable) {
642 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, true);
643 if (rc) {
644 pr_err("failed to enable digital regulator\n");
645 goto error;
646 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530647
648 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
649 rc = dsi_pwr_enable_regulator(
650 &dsi_phy->pwr_info.phy_pwr, true);
651 if (rc) {
652 pr_err("failed to enable phy power\n");
653 (void)dsi_pwr_enable_regulator(
654 &dsi_phy->pwr_info.digital, false);
655 goto error;
656 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700657 }
658 } else {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530659 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
660 rc = dsi_pwr_enable_regulator(
661 &dsi_phy->pwr_info.phy_pwr, false);
662 if (rc) {
663 pr_err("failed to enable digital regulator\n");
664 goto error;
665 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700666 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530667
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700668 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital,
669 false);
670 if (rc) {
671 pr_err("failed to enable phy power\n");
672 goto error;
673 }
674 }
675
676 dsi_phy->power_state = enable;
677error:
678 mutex_unlock(&dsi_phy->phy_lock);
679 return rc;
680}
681
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530682static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700683 struct dsi_host_config *config, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530684{
685 int rc = 0;
686 u32 lanes = 0;
687 u32 ulps_lanes;
688
689 if (config->panel_mode == DSI_OP_CMD_MODE)
690 lanes = config->common_config.data_lanes;
691 lanes |= DSI_CLOCK_LANE;
692
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700693 /*
694 * If DSI clamps are enabled, it means that the DSI lanes are
695 * already in idle state. Checking for lanes to be in idle state
696 * should be skipped during ULPS entry programming while coming
697 * out of idle screen.
698 */
699 if (!clamp_enabled) {
700 rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
701 if (rc) {
702 pr_err("lanes not entering idle, skip ULPS\n");
703 return rc;
704 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530705 }
706
707 phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
708
709 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
710
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700711 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530712 pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
713 lanes, ulps_lanes);
714 rc = -EIO;
715 }
716
717 return rc;
718}
719
720static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
721 struct dsi_host_config *config)
722{
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530723 u32 ulps_lanes, lanes = 0;
724
725 if (config->panel_mode == DSI_OP_CMD_MODE)
726 lanes = config->common_config.data_lanes;
727 lanes |= DSI_CLOCK_LANE;
728
729 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
730
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700731 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
732 pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
733 lanes, ulps_lanes);
734 return -EIO;
735 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530736
737 phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
738
739 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700740
741 if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530742 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700743 return -EIO;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530744 }
745
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700746 return 0;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530747}
748
749
750int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700751 bool enable, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530752{
753 int rc = 0;
754
755 if (!phy) {
756 pr_err("Invalid params\n");
757 return -EINVAL;
758 }
759
760 if (!phy->hw.ops.ulps_ops.ulps_request ||
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700761 !phy->hw.ops.ulps_ops.ulps_exit ||
762 !phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
763 !phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
764 !phy->hw.ops.ulps_ops.wait_for_lane_idle) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530765 pr_debug("DSI PHY ULPS ops not present\n");
766 return 0;
767 }
768
769 mutex_lock(&phy->phy_lock);
770
771 if (enable)
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700772 rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530773 else
774 rc = dsi_phy_disable_ulps(phy, config);
775
776 if (rc) {
777 pr_err("[DSI_PHY%d] Ulps state change(%d) failed, rc=%d\n",
778 phy->index, enable, rc);
779 goto error;
780 }
781 pr_debug("[DSI_PHY%d] ULPS state = %d\n", phy->index, enable);
782
783error:
784 mutex_unlock(&phy->phy_lock);
785 return rc;
786}
787
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700788/**
789 * dsi_phy_enable() - enable DSI PHY hardware
790 * @dsi_phy: DSI PHY handle.
791 * @config: DSI host configuration.
792 * @pll_source: Source PLL for PHY clock.
793 * @skip_validation: Validation will not be performed on parameters.
794 *
795 * Validates and enables DSI PHY.
796 *
797 * Return: error code.
798 */
799int dsi_phy_enable(struct msm_dsi_phy *phy,
800 struct dsi_host_config *config,
801 enum dsi_phy_pll_source pll_source,
802 bool skip_validation)
803{
804 int rc = 0;
805
806 if (!phy || !config) {
807 pr_err("Invalid params\n");
808 return -EINVAL;
809 }
810
811 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
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700842 return rc;
843}
844
845/**
846 * dsi_phy_disable() - disable DSI PHY hardware.
847 * @phy: DSI PHY handle.
848 *
849 * Return: error code.
850 */
851int dsi_phy_disable(struct msm_dsi_phy *phy)
852{
853 int rc = 0;
854
855 if (!phy) {
856 pr_err("Invalid params\n");
857 return -EINVAL;
858 }
859
860 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700861 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530862 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
863 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700864
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530865 return rc;
866}
867
868/**
869 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
870 * @phy: DSI PHY handle
871 * @enable: boolean to specify PHY enable/disable.
872 *
873 * Return: error code.
874 */
875
876int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
877{
878 if (!phy) {
879 pr_err("Invalid params\n");
880 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700881 }
882
Alan Kwong797e0892017-10-17 09:37:24 -0400883 pr_debug("[%s] enable=%d\n", phy->name, enable);
884
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530885 mutex_lock(&phy->phy_lock);
886 if (enable) {
887 if (phy->hw.ops.phy_idle_on)
888 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
889
890 if (phy->hw.ops.regulator_enable)
891 phy->hw.ops.regulator_enable(&phy->hw,
892 &phy->cfg.regulators);
Alan Kwong797e0892017-10-17 09:37:24 -0400893
894 if (phy->hw.ops.enable)
895 phy->hw.ops.enable(&phy->hw, &phy->cfg);
896
897 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530898 } else {
Alan Kwong797e0892017-10-17 09:37:24 -0400899 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
900
901 if (phy->hw.ops.disable)
902 phy->hw.ops.disable(&phy->hw, &phy->cfg);
903
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530904 if (phy->hw.ops.phy_idle_off)
905 phy->hw.ops.phy_idle_off(&phy->hw);
906 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700907 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530908
909 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700910}
911
912/**
913 * dsi_phy_set_timing_params() - timing parameters for the panel
914 * @phy: DSI PHY handle
915 * @timing: array holding timing params.
916 * @size: size of the array.
917 *
918 * When PHY timing calculator is not implemented, this array will be used to
919 * pass PHY timing information.
920 *
921 * Return: error code.
922 */
923int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530924 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700925{
926 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700927
928 if (!phy || !timing || !size) {
929 pr_err("Invalid params\n");
930 return -EINVAL;
931 }
932
933 mutex_lock(&phy->phy_lock);
934
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530935 if (phy->hw.ops.phy_timing_val)
936 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
937 if (!rc)
938 phy->cfg.is_phy_timing_present = true;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700939 mutex_unlock(&phy->phy_lock);
940 return rc;
941}
942
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700943void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700944{
945 platform_driver_register(&dsi_phy_platform_driver);
946}
947
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700948void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700949{
950 platform_driver_unregister(&dsi_phy_platform_driver);
951}