blob: b747d2a41a65a49fad5f53eb471f81a776e68ff4 [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;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530293 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700294err:
295 lane->count_per_lane = 0;
296 strength->count_per_lane = 0;
297 regs->count_per_lane = 0;
298 timing->count_per_lane = 0;
299 return rc;
300}
301
302static int dsi_phy_settings_deinit(struct msm_dsi_phy *phy)
303{
304 memset(&phy->cfg.lanecfg, 0x0, sizeof(phy->cfg.lanecfg));
305 memset(&phy->cfg.strength, 0x0, sizeof(phy->cfg.strength));
306 memset(&phy->cfg.timing, 0x0, sizeof(phy->cfg.timing));
307 memset(&phy->cfg.regulators, 0x0, sizeof(phy->cfg.regulators));
308 return 0;
309}
310
311static int dsi_phy_driver_probe(struct platform_device *pdev)
312{
313 struct msm_dsi_phy *dsi_phy;
314 struct dsi_phy_list_item *item;
315 const struct of_device_id *id;
316 const struct dsi_ver_spec_info *ver_info;
317 int rc = 0;
318 u32 index = 0;
319
320 if (!pdev || !pdev->dev.of_node) {
321 pr_err("pdev not found\n");
322 return -ENODEV;
323 }
324
325 id = of_match_node(msm_dsi_phy_of_match, pdev->dev.of_node);
326 if (!id)
327 return -ENODEV;
328
329 ver_info = id->data;
330
331 item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL);
332 if (!item)
333 return -ENOMEM;
334
335
336 dsi_phy = devm_kzalloc(&pdev->dev, sizeof(*dsi_phy), GFP_KERNEL);
337 if (!dsi_phy) {
338 devm_kfree(&pdev->dev, item);
339 return -ENOMEM;
340 }
341
342 rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
343 if (rc) {
344 pr_debug("cell index not set, default to 0\n");
345 index = 0;
346 }
347
348 dsi_phy->index = index;
349
350 dsi_phy->name = of_get_property(pdev->dev.of_node, "label", NULL);
351 if (!dsi_phy->name)
352 dsi_phy->name = DSI_PHY_DEFAULT_LABEL;
353
354 pr_debug("Probing %s device\n", dsi_phy->name);
355
356 rc = dsi_phy_regmap_init(pdev, dsi_phy);
357 if (rc) {
358 pr_err("Failed to parse register information, rc=%d\n", rc);
359 goto fail;
360 }
361
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700362 rc = dsi_phy_supplies_init(pdev, dsi_phy);
363 if (rc) {
364 pr_err("failed to parse voltage supplies, rc = %d\n", rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530365 goto fail_regmap;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700366 }
367
368 rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version,
369 dsi_phy->index);
370 if (rc) {
371 pr_err("Catalog does not support version (%d)\n",
372 ver_info->version);
373 goto fail_supplies;
374 }
375
376 dsi_phy->ver_info = ver_info;
377 rc = dsi_phy_settings_init(pdev, dsi_phy);
378 if (rc) {
379 pr_err("Failed to parse phy setting, rc=%d\n", rc);
380 goto fail_supplies;
381 }
382
383 item->phy = dsi_phy;
384
385 mutex_lock(&dsi_phy_list_lock);
386 list_add(&item->list, &dsi_phy_list);
387 mutex_unlock(&dsi_phy_list_lock);
388
389 mutex_init(&dsi_phy->phy_lock);
390 /** TODO: initialize debugfs */
391 dsi_phy->pdev = pdev;
392 platform_set_drvdata(pdev, dsi_phy);
Shashank Babu Chinta Venkata2f24e982017-04-21 14:57:53 -0700393 pr_info("Probe successful for %s\n", dsi_phy->name);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700394 return 0;
395
396fail_supplies:
397 (void)dsi_phy_supplies_deinit(dsi_phy);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700398fail_regmap:
399 (void)dsi_phy_regmap_deinit(dsi_phy);
400fail:
401 devm_kfree(&pdev->dev, dsi_phy);
402 devm_kfree(&pdev->dev, item);
403 return rc;
404}
405
406static int dsi_phy_driver_remove(struct platform_device *pdev)
407{
408 int rc = 0;
409 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
410 struct list_head *pos, *tmp;
411
412 if (!pdev || !phy) {
413 pr_err("Invalid device\n");
414 return -EINVAL;
415 }
416
417 mutex_lock(&dsi_phy_list_lock);
418 list_for_each_safe(pos, tmp, &dsi_phy_list) {
419 struct dsi_phy_list_item *n;
420
421 n = list_entry(pos, struct dsi_phy_list_item, list);
422 if (n->phy == phy) {
423 list_del(&n->list);
424 devm_kfree(&pdev->dev, n);
425 break;
426 }
427 }
428 mutex_unlock(&dsi_phy_list_lock);
429
430 mutex_lock(&phy->phy_lock);
431 rc = dsi_phy_settings_deinit(phy);
432 if (rc)
433 pr_err("failed to deinitialize phy settings, rc=%d\n", rc);
434
435 rc = dsi_phy_supplies_deinit(phy);
436 if (rc)
437 pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
438
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700439 rc = dsi_phy_regmap_deinit(phy);
440 if (rc)
441 pr_err("failed to deinitialize regmap, rc=%d\n", rc);
442 mutex_unlock(&phy->phy_lock);
443
444 mutex_destroy(&phy->phy_lock);
445 devm_kfree(&pdev->dev, phy);
446
447 platform_set_drvdata(pdev, NULL);
448
449 return 0;
450}
451
452static struct platform_driver dsi_phy_platform_driver = {
453 .probe = dsi_phy_driver_probe,
454 .remove = dsi_phy_driver_remove,
455 .driver = {
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700456 .name = "dsi_phy",
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700457 .of_match_table = msm_dsi_phy_of_match,
458 },
459};
460
461static void dsi_phy_enable_hw(struct msm_dsi_phy *phy)
462{
463 if (phy->hw.ops.regulator_enable)
464 phy->hw.ops.regulator_enable(&phy->hw, &phy->cfg.regulators);
465
466 if (phy->hw.ops.enable)
467 phy->hw.ops.enable(&phy->hw, &phy->cfg);
468}
469
470static void dsi_phy_disable_hw(struct msm_dsi_phy *phy)
471{
472 if (phy->hw.ops.disable)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530473 phy->hw.ops.disable(&phy->hw, &phy->cfg);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700474
475 if (phy->hw.ops.regulator_disable)
476 phy->hw.ops.regulator_disable(&phy->hw);
477}
478
479/**
480 * dsi_phy_get() - get a dsi phy handle from device node
481 * @of_node: device node for dsi phy controller
482 *
483 * Gets the DSI PHY handle for the corresponding of_node. The ref count is
484 * incremented to one all subsequents get will fail until the original client
485 * calls a put.
486 *
487 * Return: DSI PHY handle or an error code.
488 */
489struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node)
490{
491 struct list_head *pos, *tmp;
492 struct msm_dsi_phy *phy = NULL;
493
494 mutex_lock(&dsi_phy_list_lock);
495 list_for_each_safe(pos, tmp, &dsi_phy_list) {
496 struct dsi_phy_list_item *n;
497
498 n = list_entry(pos, struct dsi_phy_list_item, list);
499 if (n->phy->pdev->dev.of_node == of_node) {
500 phy = n->phy;
501 break;
502 }
503 }
504 mutex_unlock(&dsi_phy_list_lock);
505
506 if (!phy) {
507 pr_err("Device with of node not found\n");
508 phy = ERR_PTR(-EPROBE_DEFER);
509 return phy;
510 }
511
512 mutex_lock(&phy->phy_lock);
513 if (phy->refcount > 0) {
514 pr_err("[PHY_%d] Device under use\n", phy->index);
515 phy = ERR_PTR(-EINVAL);
516 } else {
517 phy->refcount++;
518 }
519 mutex_unlock(&phy->phy_lock);
520 return phy;
521}
522
523/**
524 * dsi_phy_put() - release dsi phy handle
525 * @dsi_phy: DSI PHY handle.
526 *
527 * Release the DSI PHY hardware. Driver will clean up all resources and puts
528 * back the DSI PHY into reset state.
529 */
530void dsi_phy_put(struct msm_dsi_phy *dsi_phy)
531{
532 mutex_lock(&dsi_phy->phy_lock);
533
534 if (dsi_phy->refcount == 0)
535 pr_err("Unbalanced dsi_phy_put call\n");
536 else
537 dsi_phy->refcount--;
538
539 mutex_unlock(&dsi_phy->phy_lock);
540}
541
542/**
543 * dsi_phy_drv_init() - initialize dsi phy driver
544 * @dsi_phy: DSI PHY handle.
545 *
546 * Initializes DSI PHY driver. Should be called after dsi_phy_get().
547 *
548 * Return: error code.
549 */
550int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy)
551{
Dhaval Patela2430842017-06-15 14:32:36 -0700552 char dbg_name[DSI_DEBUG_NAME_LEN];
553
554 snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_phy", dsi_phy->index);
555 sde_dbg_reg_register_base(dbg_name, dsi_phy->hw.base,
556 msm_iomap_size(dsi_phy->pdev, "dsi_phy"));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700557 return 0;
558}
559
560/**
561 * dsi_phy_drv_deinit() - de-initialize dsi phy driver
562 * @dsi_phy: DSI PHY handle.
563 *
564 * Release all resources acquired by dsi_phy_drv_init().
565 *
566 * Return: error code.
567 */
568int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy)
569{
570 return 0;
571}
572
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530573int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
574 struct clk_ctrl_cb *clk_cb)
575{
576 if (!dsi_phy || !clk_cb) {
577 pr_err("Invalid params\n");
578 return -EINVAL;
579 }
580
581 dsi_phy->clk_cb.priv = clk_cb->priv;
582 dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
583 return 0;
584}
585
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700586/**
587 * dsi_phy_validate_mode() - validate a display mode
588 * @dsi_phy: DSI PHY handle.
589 * @mode: Mode information.
590 *
591 * Validation will fail if the mode cannot be supported by the PHY driver or
592 * hardware.
593 *
594 * Return: error code.
595 */
596int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
597 struct dsi_mode_info *mode)
598{
599 int rc = 0;
600
601 if (!dsi_phy || !mode) {
602 pr_err("Invalid params\n");
603 return -EINVAL;
604 }
605
606 mutex_lock(&dsi_phy->phy_lock);
607
608 pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
609
610 mutex_unlock(&dsi_phy->phy_lock);
611 return rc;
612}
613
614/**
615 * dsi_phy_set_power_state() - enable/disable dsi phy power supplies
616 * @dsi_phy: DSI PHY handle.
617 * @enable: Boolean flag to enable/disable.
618 *
619 * Return: error code.
620 */
621int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable)
622{
623 int rc = 0;
624
625 if (!dsi_phy) {
626 pr_err("Invalid params\n");
627 return -EINVAL;
628 }
629
630 mutex_lock(&dsi_phy->phy_lock);
631
632 if (enable == dsi_phy->power_state) {
633 pr_err("[PHY_%d] No state change\n", dsi_phy->index);
634 goto error;
635 }
636
637 if (enable) {
638 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, true);
639 if (rc) {
640 pr_err("failed to enable digital regulator\n");
641 goto error;
642 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530643
644 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
645 rc = dsi_pwr_enable_regulator(
646 &dsi_phy->pwr_info.phy_pwr, true);
647 if (rc) {
648 pr_err("failed to enable phy power\n");
649 (void)dsi_pwr_enable_regulator(
650 &dsi_phy->pwr_info.digital, false);
651 goto error;
652 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700653 }
654 } else {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530655 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
656 rc = dsi_pwr_enable_regulator(
657 &dsi_phy->pwr_info.phy_pwr, false);
658 if (rc) {
659 pr_err("failed to enable digital regulator\n");
660 goto error;
661 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700662 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530663
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700664 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital,
665 false);
666 if (rc) {
667 pr_err("failed to enable phy power\n");
668 goto error;
669 }
670 }
671
672 dsi_phy->power_state = enable;
673error:
674 mutex_unlock(&dsi_phy->phy_lock);
675 return rc;
676}
677
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530678static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700679 struct dsi_host_config *config, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530680{
681 int rc = 0;
682 u32 lanes = 0;
683 u32 ulps_lanes;
684
685 if (config->panel_mode == DSI_OP_CMD_MODE)
686 lanes = config->common_config.data_lanes;
687 lanes |= DSI_CLOCK_LANE;
688
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700689 /*
690 * If DSI clamps are enabled, it means that the DSI lanes are
691 * already in idle state. Checking for lanes to be in idle state
692 * should be skipped during ULPS entry programming while coming
693 * out of idle screen.
694 */
695 if (!clamp_enabled) {
696 rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
697 if (rc) {
698 pr_err("lanes not entering idle, skip ULPS\n");
699 return rc;
700 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530701 }
702
703 phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
704
705 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
706
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700707 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530708 pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
709 lanes, ulps_lanes);
710 rc = -EIO;
711 }
712
713 return rc;
714}
715
716static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
717 struct dsi_host_config *config)
718{
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530719 u32 ulps_lanes, lanes = 0;
720
721 if (config->panel_mode == DSI_OP_CMD_MODE)
722 lanes = config->common_config.data_lanes;
723 lanes |= DSI_CLOCK_LANE;
724
725 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
726
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700727 if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
728 pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
729 lanes, ulps_lanes);
730 return -EIO;
731 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530732
733 phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
734
735 ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700736
737 if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530738 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700739 return -EIO;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530740 }
741
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700742 return 0;
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530743}
744
745
746int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700747 bool enable, bool clamp_enabled)
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530748{
749 int rc = 0;
750
751 if (!phy) {
752 pr_err("Invalid params\n");
753 return -EINVAL;
754 }
755
756 if (!phy->hw.ops.ulps_ops.ulps_request ||
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700757 !phy->hw.ops.ulps_ops.ulps_exit ||
758 !phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
759 !phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
760 !phy->hw.ops.ulps_ops.wait_for_lane_idle) {
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530761 pr_debug("DSI PHY ULPS ops not present\n");
762 return 0;
763 }
764
765 mutex_lock(&phy->phy_lock);
766
767 if (enable)
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700768 rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530769 else
770 rc = dsi_phy_disable_ulps(phy, config);
771
772 if (rc) {
773 pr_err("[DSI_PHY%d] Ulps state change(%d) failed, rc=%d\n",
774 phy->index, enable, rc);
775 goto error;
776 }
777 pr_debug("[DSI_PHY%d] ULPS state = %d\n", phy->index, enable);
778
779error:
780 mutex_unlock(&phy->phy_lock);
781 return rc;
782}
783
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700784/**
785 * dsi_phy_enable() - enable DSI PHY hardware
786 * @dsi_phy: DSI PHY handle.
787 * @config: DSI host configuration.
788 * @pll_source: Source PLL for PHY clock.
789 * @skip_validation: Validation will not be performed on parameters.
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700790 * @is_cont_splash_enabled: check whether continuous splash enabled.
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700791 *
792 * Validates and enables DSI PHY.
793 *
794 * Return: error code.
795 */
796int dsi_phy_enable(struct msm_dsi_phy *phy,
797 struct dsi_host_config *config,
798 enum dsi_phy_pll_source pll_source,
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700799 bool skip_validation,
800 bool is_cont_splash_enabled)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700801{
802 int rc = 0;
803
804 if (!phy || !config) {
805 pr_err("Invalid params\n");
806 return -EINVAL;
807 }
808
809 mutex_lock(&phy->phy_lock);
810
811 if (!skip_validation)
812 pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
813
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700814 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530815 memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700816 phy->data_lanes = config->common_config.data_lanes;
817 phy->dst_format = config->common_config.dst_format;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700818 phy->cfg.pll_source = pll_source;
819
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530820 /**
821 * If PHY timing parameters are not present in panel dtsi file,
822 * then calculate them in the driver
823 */
824 if (!phy->cfg.is_phy_timing_present)
825 rc = phy->hw.ops.calculate_timing_params(&phy->hw,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700826 &phy->mode,
827 &config->common_config,
828 &phy->cfg.timing);
829 if (rc) {
830 pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530831 goto error;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700832 }
833
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700834 if (!is_cont_splash_enabled) {
835 dsi_phy_enable_hw(phy);
836 pr_debug("cont splash not enabled, phy enable required\n");
837 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530838 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700839
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700840error:
841 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530842
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700843 return rc;
844}
845
846/**
847 * dsi_phy_disable() - disable DSI PHY hardware.
848 * @phy: DSI PHY handle.
849 *
850 * Return: error code.
851 */
852int dsi_phy_disable(struct msm_dsi_phy *phy)
853{
854 int rc = 0;
855
856 if (!phy) {
857 pr_err("Invalid params\n");
858 return -EINVAL;
859 }
860
861 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700862 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530863 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
864 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700865
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530866 return rc;
867}
868
869/**
870 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
871 * @phy: DSI PHY handle
872 * @enable: boolean to specify PHY enable/disable.
873 *
874 * Return: error code.
875 */
876
877int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
878{
879 if (!phy) {
880 pr_err("Invalid params\n");
881 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700882 }
883
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530884 mutex_lock(&phy->phy_lock);
885 if (enable) {
886 if (phy->hw.ops.phy_idle_on)
887 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
888
889 if (phy->hw.ops.regulator_enable)
890 phy->hw.ops.regulator_enable(&phy->hw,
891 &phy->cfg.regulators);
892 } else {
893 if (phy->hw.ops.phy_idle_off)
894 phy->hw.ops.phy_idle_off(&phy->hw);
895 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700896 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530897
898 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700899}
900
901/**
902 * dsi_phy_set_timing_params() - timing parameters for the panel
903 * @phy: DSI PHY handle
904 * @timing: array holding timing params.
905 * @size: size of the array.
906 *
907 * When PHY timing calculator is not implemented, this array will be used to
908 * pass PHY timing information.
909 *
910 * Return: error code.
911 */
912int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530913 u32 *timing, u32 size)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700914{
915 int rc = 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700916
917 if (!phy || !timing || !size) {
918 pr_err("Invalid params\n");
919 return -EINVAL;
920 }
921
922 mutex_lock(&phy->phy_lock);
923
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +0530924 if (phy->hw.ops.phy_timing_val)
925 rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
926 if (!rc)
927 phy->cfg.is_phy_timing_present = true;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700928 mutex_unlock(&phy->phy_lock);
929 return rc;
930}
931
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700932void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700933{
934 platform_driver_register(&dsi_phy_platform_driver);
935}
936
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700937void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700938{
939 platform_driver_unregister(&dsi_phy_platform_driver);
940}