blob: 27cee05fe4c829f4d9676f46938f4057079cc0a7 [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
42static const struct dsi_ver_spec_info dsi_phy_v1_0 = {
43 .version = DSI_PHY_VERSION_1_0,
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_v2_0 = {
50 .version = DSI_PHY_VERSION_2_0,
51 .lane_cfg_count = 4,
52 .strength_cfg_count = 2,
53 .regulator_cfg_count = 1,
54 .timing_cfg_count = 8,
55};
56static const struct dsi_ver_spec_info dsi_phy_v3_0 = {
57 .version = DSI_PHY_VERSION_3_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_v4_0 = {
64 .version = DSI_PHY_VERSION_4_0,
65 .lane_cfg_count = 4,
66 .strength_cfg_count = 2,
67 .regulator_cfg_count = 1,
68 .timing_cfg_count = 8,
69};
70
71static const struct of_device_id msm_dsi_phy_of_match[] = {
72 { .compatible = "qcom,dsi-phy-v1.0",
73 .data = &dsi_phy_v1_0,},
74 { .compatible = "qcom,dsi-phy-v2.0",
75 .data = &dsi_phy_v2_0,},
76 { .compatible = "qcom,dsi-phy-v3.0",
77 .data = &dsi_phy_v3_0,},
78 { .compatible = "qcom,dsi-phy-v4.0",
79 .data = &dsi_phy_v4_0,},
80 {}
81};
82
83static int dsi_phy_regmap_init(struct platform_device *pdev,
84 struct msm_dsi_phy *phy)
85{
86 int rc = 0;
87 void __iomem *ptr;
88
89 ptr = msm_ioremap(pdev, "dsi_phy", phy->name);
90 if (IS_ERR(ptr)) {
91 rc = PTR_ERR(ptr);
92 return rc;
93 }
94
95 phy->hw.base = ptr;
96
97 pr_debug("[%s] map dsi_phy registers to %p\n", phy->name, phy->hw.base);
98
99 return rc;
100}
101
102static int dsi_phy_regmap_deinit(struct msm_dsi_phy *phy)
103{
104 pr_debug("[%s] unmap registers\n", phy->name);
105 return 0;
106}
107
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700108static int dsi_phy_supplies_init(struct platform_device *pdev,
109 struct msm_dsi_phy *phy)
110{
111 int rc = 0;
112 int i = 0;
113 struct dsi_regulator_info *regs;
114 struct regulator *vreg = NULL;
115
116 regs = &phy->pwr_info.digital;
117 regs->vregs = devm_kzalloc(&pdev->dev, sizeof(struct dsi_vreg),
118 GFP_KERNEL);
119 if (!regs->vregs)
120 goto error;
121
122 regs->count = 1;
123 snprintf(regs->vregs->vreg_name,
124 ARRAY_SIZE(regs->vregs[i].vreg_name),
125 "%s", "gdsc");
126
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530127 rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700128 &phy->pwr_info.phy_pwr,
129 "qcom,phy-supply-entries");
130 if (rc) {
131 pr_err("failed to get host power supplies, rc = %d\n", rc);
132 goto error_digital;
133 }
134
135 regs = &phy->pwr_info.digital;
136 for (i = 0; i < regs->count; i++) {
137 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
138 rc = PTR_RET(vreg);
139 if (rc) {
140 pr_err("failed to get %s regulator\n",
141 regs->vregs[i].vreg_name);
142 goto error_host_pwr;
143 }
144 regs->vregs[i].vreg = vreg;
145 }
146
147 regs = &phy->pwr_info.phy_pwr;
148 for (i = 0; i < regs->count; i++) {
149 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
150 rc = PTR_RET(vreg);
151 if (rc) {
152 pr_err("failed to get %s regulator\n",
153 regs->vregs[i].vreg_name);
154 for (--i; i >= 0; i--)
155 devm_regulator_put(regs->vregs[i].vreg);
156 goto error_digital_put;
157 }
158 regs->vregs[i].vreg = vreg;
159 }
160
161 return rc;
162
163error_digital_put:
164 regs = &phy->pwr_info.digital;
165 for (i = 0; i < regs->count; i++)
166 devm_regulator_put(regs->vregs[i].vreg);
167error_host_pwr:
168 devm_kfree(&pdev->dev, phy->pwr_info.phy_pwr.vregs);
169 phy->pwr_info.phy_pwr.vregs = NULL;
170 phy->pwr_info.phy_pwr.count = 0;
171error_digital:
172 devm_kfree(&pdev->dev, phy->pwr_info.digital.vregs);
173 phy->pwr_info.digital.vregs = NULL;
174 phy->pwr_info.digital.count = 0;
175error:
176 return rc;
177}
178
179static int dsi_phy_supplies_deinit(struct msm_dsi_phy *phy)
180{
181 int i = 0;
182 int rc = 0;
183 struct dsi_regulator_info *regs;
184
185 regs = &phy->pwr_info.digital;
186 for (i = 0; i < regs->count; i++) {
187 if (!regs->vregs[i].vreg)
188 pr_err("vreg is NULL, should not reach here\n");
189 else
190 devm_regulator_put(regs->vregs[i].vreg);
191 }
192
193 regs = &phy->pwr_info.phy_pwr;
194 for (i = 0; i < regs->count; i++) {
195 if (!regs->vregs[i].vreg)
196 pr_err("vreg is NULL, should not reach here\n");
197 else
198 devm_regulator_put(regs->vregs[i].vreg);
199 }
200
201 if (phy->pwr_info.phy_pwr.vregs) {
202 devm_kfree(&phy->pdev->dev, phy->pwr_info.phy_pwr.vregs);
203 phy->pwr_info.phy_pwr.vregs = NULL;
204 phy->pwr_info.phy_pwr.count = 0;
205 }
206 if (phy->pwr_info.digital.vregs) {
207 devm_kfree(&phy->pdev->dev, phy->pwr_info.digital.vregs);
208 phy->pwr_info.digital.vregs = NULL;
209 phy->pwr_info.digital.count = 0;
210 }
211
212 return rc;
213}
214
215static int dsi_phy_parse_dt_per_lane_cfgs(struct platform_device *pdev,
216 struct dsi_phy_per_lane_cfgs *cfg,
217 char *property)
218{
219 int rc = 0, i = 0, j = 0;
220 const u8 *data;
221 u32 len = 0;
222
223 data = of_get_property(pdev->dev.of_node, property, &len);
224 if (!data) {
225 pr_err("Unable to read Phy %s settings\n", property);
226 return -EINVAL;
227 }
228
229 if (len != DSI_LANE_MAX * cfg->count_per_lane) {
230 pr_err("incorrect phy %s settings, exp=%d, act=%d\n",
231 property, (DSI_LANE_MAX * cfg->count_per_lane), len);
232 return -EINVAL;
233 }
234
235 for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
236 for (j = 0; j < cfg->count_per_lane; j++) {
237 cfg->lane[i][j] = *data;
238 data++;
239 }
240 }
241
242 return rc;
243}
244
245static int dsi_phy_settings_init(struct platform_device *pdev,
246 struct msm_dsi_phy *phy)
247{
248 int rc = 0;
249 struct dsi_phy_per_lane_cfgs *lane = &phy->cfg.lanecfg;
250 struct dsi_phy_per_lane_cfgs *strength = &phy->cfg.strength;
251 struct dsi_phy_per_lane_cfgs *timing = &phy->cfg.timing;
252 struct dsi_phy_per_lane_cfgs *regs = &phy->cfg.regulators;
253
254 lane->count_per_lane = phy->ver_info->lane_cfg_count;
255 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, lane,
256 "qcom,platform-lane-config");
257 if (rc) {
258 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
259 goto err;
260 }
261
262 strength->count_per_lane = phy->ver_info->strength_cfg_count;
263 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, strength,
264 "qcom,platform-strength-ctrl");
265 if (rc) {
266 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
267 goto err;
268 }
269
270 regs->count_per_lane = phy->ver_info->regulator_cfg_count;
271 rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, regs,
272 "qcom,platform-regulator-settings");
273 if (rc) {
274 pr_err("failed to parse lane cfgs, rc=%d\n", rc);
275 goto err;
276 }
277
278 /* Actual timing values are dependent on panel */
279 timing->count_per_lane = phy->ver_info->timing_cfg_count;
280
281err:
282 lane->count_per_lane = 0;
283 strength->count_per_lane = 0;
284 regs->count_per_lane = 0;
285 timing->count_per_lane = 0;
286 return rc;
287}
288
289static int dsi_phy_settings_deinit(struct msm_dsi_phy *phy)
290{
291 memset(&phy->cfg.lanecfg, 0x0, sizeof(phy->cfg.lanecfg));
292 memset(&phy->cfg.strength, 0x0, sizeof(phy->cfg.strength));
293 memset(&phy->cfg.timing, 0x0, sizeof(phy->cfg.timing));
294 memset(&phy->cfg.regulators, 0x0, sizeof(phy->cfg.regulators));
295 return 0;
296}
297
298static int dsi_phy_driver_probe(struct platform_device *pdev)
299{
300 struct msm_dsi_phy *dsi_phy;
301 struct dsi_phy_list_item *item;
302 const struct of_device_id *id;
303 const struct dsi_ver_spec_info *ver_info;
304 int rc = 0;
305 u32 index = 0;
306
307 if (!pdev || !pdev->dev.of_node) {
308 pr_err("pdev not found\n");
309 return -ENODEV;
310 }
311
312 id = of_match_node(msm_dsi_phy_of_match, pdev->dev.of_node);
313 if (!id)
314 return -ENODEV;
315
316 ver_info = id->data;
317
318 item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL);
319 if (!item)
320 return -ENOMEM;
321
322
323 dsi_phy = devm_kzalloc(&pdev->dev, sizeof(*dsi_phy), GFP_KERNEL);
324 if (!dsi_phy) {
325 devm_kfree(&pdev->dev, item);
326 return -ENOMEM;
327 }
328
329 rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
330 if (rc) {
331 pr_debug("cell index not set, default to 0\n");
332 index = 0;
333 }
334
335 dsi_phy->index = index;
336
337 dsi_phy->name = of_get_property(pdev->dev.of_node, "label", NULL);
338 if (!dsi_phy->name)
339 dsi_phy->name = DSI_PHY_DEFAULT_LABEL;
340
341 pr_debug("Probing %s device\n", dsi_phy->name);
342
343 rc = dsi_phy_regmap_init(pdev, dsi_phy);
344 if (rc) {
345 pr_err("Failed to parse register information, rc=%d\n", rc);
346 goto fail;
347 }
348
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700349 rc = dsi_phy_supplies_init(pdev, dsi_phy);
350 if (rc) {
351 pr_err("failed to parse voltage supplies, rc = %d\n", rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530352 goto fail_regmap;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700353 }
354
355 rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version,
356 dsi_phy->index);
357 if (rc) {
358 pr_err("Catalog does not support version (%d)\n",
359 ver_info->version);
360 goto fail_supplies;
361 }
362
363 dsi_phy->ver_info = ver_info;
364 rc = dsi_phy_settings_init(pdev, dsi_phy);
365 if (rc) {
366 pr_err("Failed to parse phy setting, rc=%d\n", rc);
367 goto fail_supplies;
368 }
369
370 item->phy = dsi_phy;
371
372 mutex_lock(&dsi_phy_list_lock);
373 list_add(&item->list, &dsi_phy_list);
374 mutex_unlock(&dsi_phy_list_lock);
375
376 mutex_init(&dsi_phy->phy_lock);
377 /** TODO: initialize debugfs */
378 dsi_phy->pdev = pdev;
379 platform_set_drvdata(pdev, dsi_phy);
380 pr_debug("Probe successful for %s\n", dsi_phy->name);
381 return 0;
382
383fail_supplies:
384 (void)dsi_phy_supplies_deinit(dsi_phy);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700385fail_regmap:
386 (void)dsi_phy_regmap_deinit(dsi_phy);
387fail:
388 devm_kfree(&pdev->dev, dsi_phy);
389 devm_kfree(&pdev->dev, item);
390 return rc;
391}
392
393static int dsi_phy_driver_remove(struct platform_device *pdev)
394{
395 int rc = 0;
396 struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
397 struct list_head *pos, *tmp;
398
399 if (!pdev || !phy) {
400 pr_err("Invalid device\n");
401 return -EINVAL;
402 }
403
404 mutex_lock(&dsi_phy_list_lock);
405 list_for_each_safe(pos, tmp, &dsi_phy_list) {
406 struct dsi_phy_list_item *n;
407
408 n = list_entry(pos, struct dsi_phy_list_item, list);
409 if (n->phy == phy) {
410 list_del(&n->list);
411 devm_kfree(&pdev->dev, n);
412 break;
413 }
414 }
415 mutex_unlock(&dsi_phy_list_lock);
416
417 mutex_lock(&phy->phy_lock);
418 rc = dsi_phy_settings_deinit(phy);
419 if (rc)
420 pr_err("failed to deinitialize phy settings, rc=%d\n", rc);
421
422 rc = dsi_phy_supplies_deinit(phy);
423 if (rc)
424 pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
425
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700426 rc = dsi_phy_regmap_deinit(phy);
427 if (rc)
428 pr_err("failed to deinitialize regmap, rc=%d\n", rc);
429 mutex_unlock(&phy->phy_lock);
430
431 mutex_destroy(&phy->phy_lock);
432 devm_kfree(&pdev->dev, phy);
433
434 platform_set_drvdata(pdev, NULL);
435
436 return 0;
437}
438
439static struct platform_driver dsi_phy_platform_driver = {
440 .probe = dsi_phy_driver_probe,
441 .remove = dsi_phy_driver_remove,
442 .driver = {
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700443 .name = "dsi_phy",
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700444 .of_match_table = msm_dsi_phy_of_match,
445 },
446};
447
448static void dsi_phy_enable_hw(struct msm_dsi_phy *phy)
449{
450 if (phy->hw.ops.regulator_enable)
451 phy->hw.ops.regulator_enable(&phy->hw, &phy->cfg.regulators);
452
453 if (phy->hw.ops.enable)
454 phy->hw.ops.enable(&phy->hw, &phy->cfg);
455}
456
457static void dsi_phy_disable_hw(struct msm_dsi_phy *phy)
458{
459 if (phy->hw.ops.disable)
460 phy->hw.ops.disable(&phy->hw);
461
462 if (phy->hw.ops.regulator_disable)
463 phy->hw.ops.regulator_disable(&phy->hw);
464}
465
466/**
467 * dsi_phy_get() - get a dsi phy handle from device node
468 * @of_node: device node for dsi phy controller
469 *
470 * Gets the DSI PHY handle for the corresponding of_node. The ref count is
471 * incremented to one all subsequents get will fail until the original client
472 * calls a put.
473 *
474 * Return: DSI PHY handle or an error code.
475 */
476struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node)
477{
478 struct list_head *pos, *tmp;
479 struct msm_dsi_phy *phy = NULL;
480
481 mutex_lock(&dsi_phy_list_lock);
482 list_for_each_safe(pos, tmp, &dsi_phy_list) {
483 struct dsi_phy_list_item *n;
484
485 n = list_entry(pos, struct dsi_phy_list_item, list);
486 if (n->phy->pdev->dev.of_node == of_node) {
487 phy = n->phy;
488 break;
489 }
490 }
491 mutex_unlock(&dsi_phy_list_lock);
492
493 if (!phy) {
494 pr_err("Device with of node not found\n");
495 phy = ERR_PTR(-EPROBE_DEFER);
496 return phy;
497 }
498
499 mutex_lock(&phy->phy_lock);
500 if (phy->refcount > 0) {
501 pr_err("[PHY_%d] Device under use\n", phy->index);
502 phy = ERR_PTR(-EINVAL);
503 } else {
504 phy->refcount++;
505 }
506 mutex_unlock(&phy->phy_lock);
507 return phy;
508}
509
510/**
511 * dsi_phy_put() - release dsi phy handle
512 * @dsi_phy: DSI PHY handle.
513 *
514 * Release the DSI PHY hardware. Driver will clean up all resources and puts
515 * back the DSI PHY into reset state.
516 */
517void dsi_phy_put(struct msm_dsi_phy *dsi_phy)
518{
519 mutex_lock(&dsi_phy->phy_lock);
520
521 if (dsi_phy->refcount == 0)
522 pr_err("Unbalanced dsi_phy_put call\n");
523 else
524 dsi_phy->refcount--;
525
526 mutex_unlock(&dsi_phy->phy_lock);
527}
528
529/**
530 * dsi_phy_drv_init() - initialize dsi phy driver
531 * @dsi_phy: DSI PHY handle.
532 *
533 * Initializes DSI PHY driver. Should be called after dsi_phy_get().
534 *
535 * Return: error code.
536 */
537int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy)
538{
539 return 0;
540}
541
542/**
543 * dsi_phy_drv_deinit() - de-initialize dsi phy driver
544 * @dsi_phy: DSI PHY handle.
545 *
546 * Release all resources acquired by dsi_phy_drv_init().
547 *
548 * Return: error code.
549 */
550int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy)
551{
552 return 0;
553}
554
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530555int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
556 struct clk_ctrl_cb *clk_cb)
557{
558 if (!dsi_phy || !clk_cb) {
559 pr_err("Invalid params\n");
560 return -EINVAL;
561 }
562
563 dsi_phy->clk_cb.priv = clk_cb->priv;
564 dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
565 return 0;
566}
567
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700568/**
569 * dsi_phy_validate_mode() - validate a display mode
570 * @dsi_phy: DSI PHY handle.
571 * @mode: Mode information.
572 *
573 * Validation will fail if the mode cannot be supported by the PHY driver or
574 * hardware.
575 *
576 * Return: error code.
577 */
578int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
579 struct dsi_mode_info *mode)
580{
581 int rc = 0;
582
583 if (!dsi_phy || !mode) {
584 pr_err("Invalid params\n");
585 return -EINVAL;
586 }
587
588 mutex_lock(&dsi_phy->phy_lock);
589
590 pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
591
592 mutex_unlock(&dsi_phy->phy_lock);
593 return rc;
594}
595
596/**
597 * dsi_phy_set_power_state() - enable/disable dsi phy power supplies
598 * @dsi_phy: DSI PHY handle.
599 * @enable: Boolean flag to enable/disable.
600 *
601 * Return: error code.
602 */
603int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable)
604{
605 int rc = 0;
606
607 if (!dsi_phy) {
608 pr_err("Invalid params\n");
609 return -EINVAL;
610 }
611
612 mutex_lock(&dsi_phy->phy_lock);
613
614 if (enable == dsi_phy->power_state) {
615 pr_err("[PHY_%d] No state change\n", dsi_phy->index);
616 goto error;
617 }
618
619 if (enable) {
620 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, true);
621 if (rc) {
622 pr_err("failed to enable digital regulator\n");
623 goto error;
624 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530625
626 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
627 rc = dsi_pwr_enable_regulator(
628 &dsi_phy->pwr_info.phy_pwr, true);
629 if (rc) {
630 pr_err("failed to enable phy power\n");
631 (void)dsi_pwr_enable_regulator(
632 &dsi_phy->pwr_info.digital, false);
633 goto error;
634 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700635 }
636 } else {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530637 if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
638 rc = dsi_pwr_enable_regulator(
639 &dsi_phy->pwr_info.phy_pwr, false);
640 if (rc) {
641 pr_err("failed to enable digital regulator\n");
642 goto error;
643 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700644 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530645
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700646 rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital,
647 false);
648 if (rc) {
649 pr_err("failed to enable phy power\n");
650 goto error;
651 }
652 }
653
654 dsi_phy->power_state = enable;
655error:
656 mutex_unlock(&dsi_phy->phy_lock);
657 return rc;
658}
659
660/**
661 * dsi_phy_enable() - enable DSI PHY hardware
662 * @dsi_phy: DSI PHY handle.
663 * @config: DSI host configuration.
664 * @pll_source: Source PLL for PHY clock.
665 * @skip_validation: Validation will not be performed on parameters.
666 *
667 * Validates and enables DSI PHY.
668 *
669 * Return: error code.
670 */
671int dsi_phy_enable(struct msm_dsi_phy *phy,
672 struct dsi_host_config *config,
673 enum dsi_phy_pll_source pll_source,
674 bool skip_validation)
675{
676 int rc = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530677 struct dsi_clk_ctrl_info clk_info;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700678
679 if (!phy || !config) {
680 pr_err("Invalid params\n");
681 return -EINVAL;
682 }
683
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530684 clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
685 clk_info.clk_type = DSI_CORE_CLK;
686 clk_info.clk_state = DSI_CLK_ON;
687
688 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
689 if (rc) {
690 pr_err("failed to enable DSI core clocks\n");
691 return rc;
692 }
693
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700694 mutex_lock(&phy->phy_lock);
695
696 if (!skip_validation)
697 pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
698
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700699 memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530700 memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map));
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700701 phy->data_lanes = config->common_config.data_lanes;
702 phy->dst_format = config->common_config.dst_format;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700703 phy->cfg.pll_source = pll_source;
704
705 rc = phy->hw.ops.calculate_timing_params(&phy->hw,
706 &phy->mode,
707 &config->common_config,
708 &phy->cfg.timing);
709 if (rc) {
710 pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530711 goto error;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700712 }
713
714 dsi_phy_enable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530715 phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700716
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700717error:
718 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530719
720 clk_info.clk_state = DSI_CLK_OFF;
721 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
722 if (rc)
723 pr_err("failed to disable DSI core clocks\n");
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700724 return rc;
725}
726
727/**
728 * dsi_phy_disable() - disable DSI PHY hardware.
729 * @phy: DSI PHY handle.
730 *
731 * Return: error code.
732 */
733int dsi_phy_disable(struct msm_dsi_phy *phy)
734{
735 int rc = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530736 struct dsi_clk_ctrl_info clk_info;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700737
738 if (!phy) {
739 pr_err("Invalid params\n");
740 return -EINVAL;
741 }
742
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530743 clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
744 clk_info.clk_type = DSI_CORE_CLK;
745 clk_info.clk_state = DSI_CLK_ON;
746
747 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
748 if (rc) {
749 pr_err("failed to enable DSI core clocks\n");
750 return rc;
751 }
752
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700753 mutex_lock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700754 dsi_phy_disable_hw(phy);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530755 phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
756 mutex_unlock(&phy->phy_lock);
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700757
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530758 clk_info.clk_state = DSI_CLK_OFF;
759
760 rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
761 if (rc)
762 pr_err("failed to disable DSI core clocks\n");
763
764 return rc;
765}
766
767/**
768 * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
769 * @phy: DSI PHY handle
770 * @enable: boolean to specify PHY enable/disable.
771 *
772 * Return: error code.
773 */
774
775int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
776{
777 if (!phy) {
778 pr_err("Invalid params\n");
779 return -EINVAL;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700780 }
781
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530782 mutex_lock(&phy->phy_lock);
783 if (enable) {
784 if (phy->hw.ops.phy_idle_on)
785 phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
786
787 if (phy->hw.ops.regulator_enable)
788 phy->hw.ops.regulator_enable(&phy->hw,
789 &phy->cfg.regulators);
790 } else {
791 if (phy->hw.ops.phy_idle_off)
792 phy->hw.ops.phy_idle_off(&phy->hw);
793 }
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700794 mutex_unlock(&phy->phy_lock);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530795
796 return 0;
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700797}
798
799/**
800 * dsi_phy_set_timing_params() - timing parameters for the panel
801 * @phy: DSI PHY handle
802 * @timing: array holding timing params.
803 * @size: size of the array.
804 *
805 * When PHY timing calculator is not implemented, this array will be used to
806 * pass PHY timing information.
807 *
808 * Return: error code.
809 */
810int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
811 u8 *timing, u32 size)
812{
813 int rc = 0;
814 int i, j;
815 struct dsi_phy_per_lane_cfgs *timing_cfg;
816
817 if (!phy || !timing || !size) {
818 pr_err("Invalid params\n");
819 return -EINVAL;
820 }
821
822 mutex_lock(&phy->phy_lock);
823
824 if (size != (DSI_LANE_MAX * phy->cfg.timing.count_per_lane)) {
825 pr_err("Unexpected timing array size %d\n", size);
826 rc = -EINVAL;
827 } else {
828 timing_cfg = &phy->cfg.timing;
829 for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
830 for (j = 0; j < timing_cfg->count_per_lane; j++) {
831 timing_cfg->lane[i][j] = *timing;
832 timing++;
833 }
834 }
835 }
836 mutex_unlock(&phy->phy_lock);
837 return rc;
838}
839
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700840void dsi_phy_drv_register(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700841{
842 platform_driver_register(&dsi_phy_platform_driver);
843}
844
Ajay Singh Parmar64c19192016-06-10 16:44:56 -0700845void dsi_phy_drv_unregister(void)
Ajay Singh Parmar67f31322016-06-22 17:37:56 -0700846{
847 platform_driver_unregister(&dsi_phy_platform_driver);
848}