blob: 7388adeba56c54eed323a1bcd4c2975b707b8489 [file] [log] [blame]
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -08001/*
2 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
3 *
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
15#include <linux/device.h>
16#include <linux/i2c.h>
17#include <linux/slab.h>
18#include <linux/platform_device.h>
19#include <linux/input.h>
20#include <linux/types.h>
21#include <linux/module.h>
22#include <linux/fs.h>
23#include <linux/of.h>
24#include <linux/of_graph.h>
25#include <linux/kernel.h>
26#include <linux/of_gpio.h>
27#include <linux/gpio.h>
28#include <linux/delay.h>
29#include <linux/regulator/consumer.h>
30#include <linux/rwlock.h>
31#include <linux/leds.h>
32
33struct vxr7200 {
34 struct device *dev;
35 struct device_node *host_node;
36
37 u8 i2c_addr;
38 int irq;
39 u32 vxr_3v3_en;
40 u32 led_5v_en;
41 u32 led_drive_en1;
42 u32 led_drive_en2;
43 u32 display_1v8_en;
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -070044 u32 mipi_switch_1v8_en;
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -080045 u32 display_res1;
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -080046 bool gpioInit;
47
48 struct i2c_client *i2c_client;
49
50 struct regulator *vddio;
51 struct regulator *lab;
52 struct regulator *ibb;
53
54 bool power_on;
55};
56
Rajesh Bharathwaj9cd60e02020-03-24 18:04:14 -070057static bool dsi_way;
58
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -080059static int vxr7200_read(struct vxr7200 *pdata, u8 *reg, u8 *buf, u32 size)
60{
61 struct i2c_client *client = pdata->i2c_client;
62 struct i2c_msg msg[2] = {
63 {
64 .addr = client->addr,
65 .flags = 0,
66 .len = 4,
67 .buf = reg,
68 },
69 {
70 .addr = client->addr,
71 .flags = I2C_M_RD,
72 .len = size,
73 .buf = buf,
74 }
75 };
76
77 if (i2c_transfer(client->adapter, msg, 2) != 2) {
78 pr_err("i2c read failed\n");
79 return -EIO;
80 }
81
82 return 0;
83}
84
85static int turnGpio(struct vxr7200 *pdata, int gpio, char *name, bool on)
86{
87 int ret = -1;
88
89 pr_info("%s vxr7200 gpio:%d, name:%s, on:%d\n", __func__, gpio,
90 name, on);
91 if (!pdata->gpioInit) {
92 ret = gpio_request(gpio, name);
93 if (ret) {
94 pr_err("vxr7200 %s gpio request failed\n", name);
95 goto error;
96 }
97 }
98 if (on) {
99 ret = gpio_direction_output(gpio, 0);
100 if (ret) {
101 pr_err("vxr7200 gpio direction failed\n");
102 goto error;
103 }
104 gpio_set_value(gpio, 1);
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700105 msleep(20);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800106 pr_debug("%s vxr7200 gpio:%d set to high\n", __func__, gpio);
107 } else {
108 ret = gpio_direction_output(gpio, 1);
109 if (ret) {
110 pr_err("vxr7200 gpio direction failed\n");
111 goto error;
112 }
113 gpio_set_value(gpio, 0);
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700114 msleep(20);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800115 pr_debug("%s vxr7200 gpio:%d set to low\n", __func__, gpio);
116 }
117 return 0;
118error:
119 return -EINVAL;
120}
121
122static void vxr7200_set_gpios(struct vxr7200 *pdata, bool turnOn)
123{
124 int rc;
125
126 pr_debug("%s, turnOn:%d\n", __func__, turnOn);
127 if (pdata) {
128 rc = turnGpio(pdata, pdata->vxr_3v3_en, "vxr_3v3_en", turnOn);
129 if (rc)
130 goto gpio1Fail;
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700131
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800132 rc = turnGpio(pdata, pdata->display_res1,
133 "display_res1", turnOn);
134 if (rc)
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700135 goto gpio2Fail;
136
137 rc = turnGpio(pdata, pdata->display_1v8_en,
138 "disp_1v8_en", turnOn);
139 if (rc)
140 goto gpio3Fail;
141
142 rc = turnGpio(pdata, pdata->mipi_switch_1v8_en,
143 "mipi_switch_1v8_en", turnOn);
144 if (rc)
145 goto gpio4Fail;
146
147 rc = turnGpio(pdata, pdata->led_5v_en, "led_5v_en", turnOn);
148 if (rc)
149 goto gpio5Fail;
150
151 rc = turnGpio(pdata, pdata->led_drive_en1,
152 "led_drive_en1", turnOn);
153 if (rc)
154 goto gpio6Fail;
155
156 rc = turnGpio(pdata, pdata->led_drive_en2,
157 "led_drive_en2", turnOn);
158 if (rc)
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800159 goto gpio7Fail;
160 }
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700161 return;
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800162
163gpio7Fail:
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800164 gpio_free(pdata->led_drive_en2);
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700165gpio6Fail:
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800166 gpio_free(pdata->led_drive_en1);
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700167gpio5Fail:
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800168 gpio_free(pdata->led_5v_en);
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700169gpio4Fail:
170 gpio_free(pdata->mipi_switch_1v8_en);
171gpio3Fail:
172 gpio_free(pdata->display_1v8_en);
173gpio2Fail:
174 gpio_free(pdata->display_res1);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800175gpio1Fail:
176 gpio_free(pdata->vxr_3v3_en);
177}
178
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800179static int vxr7200_parse_dt(struct device *dev,
180 struct vxr7200 *pdata)
181{
182 struct device_node *np = dev->of_node;
183 int rc = 0;
184
185 pdata->vxr_3v3_en =
186 of_get_named_gpio(np, "qcom,vxr_3v3_en", 0);
187 if (!gpio_is_valid(pdata->vxr_3v3_en)) {
188 pr_err("vxr_3v3_en gpio not specified\n");
189 rc = -EINVAL;
190 }
191
192 pdata->led_5v_en =
193 of_get_named_gpio(np, "qcom,led-5v-en-gpio", 0);
194 if (!gpio_is_valid(pdata->led_5v_en)) {
195 pr_err("led_5v_en gpio not specified\n");
196 rc = -EINVAL;
197 }
198
199 pdata->led_drive_en1 =
200 of_get_named_gpio(np, "qcom,led-driver-en1-gpio", 0);
201 if (!gpio_is_valid(pdata->led_drive_en1)) {
202 pr_err("led_drive_en1 gpio not specified\n");
203 rc = -EINVAL;
204 }
205
206 pdata->led_drive_en2 =
207 of_get_named_gpio(np, "qcom,led-driver-en2-gpio", 0);
208 if (!gpio_is_valid(pdata->led_drive_en2)) {
209 pr_err("led_drive_en2 gpio not specified\n");
210 rc = -EINVAL;
211 }
212
213 pdata->display_1v8_en =
214 of_get_named_gpio(np, "qcom,1p8-en-gpio", 0);
215 if (!gpio_is_valid(pdata->display_1v8_en)) {
216 pr_err("display_1v8_en gpio not specified\n");
217 rc = -EINVAL;
218 }
219
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700220 pdata->mipi_switch_1v8_en =
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800221 of_get_named_gpio(np, "qcom,switch-power-gpio", 0);
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700222 if (!gpio_is_valid(pdata->mipi_switch_1v8_en)) {
223 pr_err("mipi_switch_1v8_en gpio not specified\n");
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800224 rc = -EINVAL;
225 }
226
227 pdata->display_res1 =
228 of_get_named_gpio(np, "qcom,platform-reset-gpio", 0);
229 if (!gpio_is_valid(pdata->display_res1)) {
230 pr_err("display_res1 gpio not specified\n");
231 rc = -EINVAL;
232 }
233
234 if (!rc)
235 vxr7200_set_gpios(pdata, true);
236
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800237 if (!pdata->gpioInit)
238 pdata->gpioInit = true;
239
240 return rc;
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800241}
242
243static void vxr7200_display_pwr_enable_vregs(struct vxr7200 *pdata)
244{
245 int rc = 0;
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800246 pdata->vddio = devm_regulator_get(pdata->dev, "pm660_l11");
247 rc = PTR_RET(pdata->vddio);
248 if (rc) {
249 pr_err("Failed to get pm660_l11 regulator %s\n", __func__);
250 goto vddio_fail;
251 }
252 rc = regulator_set_load(pdata->vddio, 62000);
253 if (rc < 0) {
254 pr_err("Load setting failed for vddio %s\n", __func__);
255 goto vddio_fail;
256 }
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800257 rc = regulator_enable(pdata->vddio);
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700258 msleep(20);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800259 if (rc) {
260 pr_err("enable failed for vddio, rc=%d %s\n", rc, __func__);
261 goto vddio_fail;
262 }
263
264 pdata->lab = devm_regulator_get(pdata->dev, "lcdb_ldo");
265 rc = PTR_RET(pdata->lab);
266 if (rc) {
267 pr_err("Failed to get lcdb_ldo_vreg regulator %s\n", __func__);
268 goto lab_fail;
269 }
270 rc = regulator_set_load(pdata->lab, 100000);
271 if (rc < 0) {
272 pr_err("Load Setting failed for lab %s\n", __func__);
273 goto lab_fail;
274 }
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800275 rc = regulator_enable(pdata->lab);
276 if (rc) {
277 pr_err("enable failed for lab, rc=%d %s\n", rc, __func__);
278 goto lab_fail;
279 }
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700280 msleep(20);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800281
282 pdata->ibb = devm_regulator_get(pdata->dev, "lcdb_ncp");
283 rc = PTR_RET(pdata->ibb);
284 if (rc) {
285 pr_err("Failed to get lcdb_ncp_vreg regulator %s\n", __func__);
286 goto ibb_fail;
287 }
288 rc = regulator_set_load(pdata->ibb, 100000);
289 if (rc < 0) {
290 pr_err("Load Setting failed for ibb %s\n", __func__);
291 goto ibb_fail;
292 }
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800293 rc = regulator_enable(pdata->ibb);
294 if (rc) {
295 pr_err("enable failed for ibb, rc=%d %s\n", rc, __func__);
296 goto ibb_fail;
297 }
Rajesh Bharathwaj60ae8e42020-04-14 15:26:03 -0700298 msleep(20);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800299
300 return;
301
302ibb_fail:
303 devm_regulator_put(pdata->ibb);
304 (void)regulator_set_load(pdata->ibb, 100);
305 (void)regulator_set_voltage(pdata->ibb, 0, 6000000);
306
307lab_fail:
308 (void)regulator_set_voltage(pdata->lab, 0, 6000000);
309 (void)regulator_set_load(pdata->lab, 100);
310 devm_regulator_put(pdata->lab);
311
312vddio_fail:
313 (void)regulator_set_load(pdata->vddio, 100);
314 (void)regulator_set_voltage(pdata->vddio, 0, 1800000);
315 devm_regulator_put(pdata->vddio);
316}
317
Rajesh Bharathwaj9cd60e02020-03-24 18:04:14 -0700318static int vxr7200_probe(struct i2c_client *client,
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800319 const struct i2c_device_id *id)
320{
321 int rc;
322 struct vxr7200 *pdata;
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800323 u8 reg[4] = {0x00, 0x20, 0x01, 0x60};
324 u8 buf[4] = {0x00, 0x0, 0x0, 0x0};
325
326 if (!client || !client->dev.of_node) {
327 pr_err("%s invalid input\n", __func__);
328 return -EINVAL;
329 }
330
331 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
332 pr_err("%s device doesn't support I2C\n", __func__);
333 return -ENODEV;
334 }
335
Rajesh Bharathwaj9cd60e02020-03-24 18:04:14 -0700336 if (dsi_way)
337 return -EINVAL;
338
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800339 pdata = devm_kzalloc(&client->dev,
340 sizeof(struct vxr7200), GFP_KERNEL);
341 if (!pdata)
342 return -ENOMEM;
343
344 pdata->gpioInit = false;
345
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800346 rc = vxr7200_parse_dt(&client->dev, pdata);
347 if (rc) {
348 pr_err("%s failed to parse device tree\n", __func__);
349 goto err_dt_parse;
350 }
351 pdata->dev = &client->dev;
352 pdata->i2c_client = client;
353
354 vxr7200_display_pwr_enable_vregs(pdata);
355
356 i2c_set_clientdata(client, pdata);
357 dev_set_drvdata(&client->dev, pdata);
358
359 //vxr7200_write(pdata, 0x0A, 0x02);//Enable 4-lane DP
360 vxr7200_read(pdata, reg, buf, 4);//Enable 4-lane DP
361
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800362err_dt_parse:
363 devm_kfree(&client->dev, pdata);
364
365 return rc;
366}
367
368static int vxr7200_remove(struct i2c_client *client)
369{
370 struct vxr7200 *pdata = i2c_get_clientdata(client);
371
372 if (pdata)
373 devm_kfree(&client->dev, pdata);
374 return 0;
375}
376
377
378static void vxr7200_shutdown(struct i2c_client *client)
379{
380 dev_info(&(client->dev), "shutdown");
381}
382
383static int vxr7200_pm_freeze(struct device *dev)
384{
385 struct i2c_client *client = to_i2c_client(dev);
386 struct vxr7200 *pdata = i2c_get_clientdata(client);
387
388 dev_info(dev, "freeze");
389 vxr7200_set_gpios(pdata, false);
390 return 0;
391}
392static int vxr7200_pm_restore(struct device *dev)
393{
394 struct i2c_client *client = to_i2c_client(dev);
395 struct vxr7200 *pdata = i2c_get_clientdata(client);
396
397 dev_info(dev, "restore");
398 vxr7200_set_gpios(pdata, true);
399 return 0;
400}
401static int vxr7200_pm_suspend(struct device *dev)
402{
403 struct i2c_client *client = to_i2c_client(dev);
404 struct vxr7200 *pdata = i2c_get_clientdata(client);
405
406 dev_info(dev, "suspend");
407 vxr7200_set_gpios(pdata, false);
408 return 0;
409}
410
411static int vxr7200_pm_resume(struct device *dev)
412{
413 struct i2c_client *client = to_i2c_client(dev);
414 struct vxr7200 *pdata = i2c_get_clientdata(client);
415
416 dev_info(dev, "resume");
417 vxr7200_set_gpios(pdata, true);
418 return 0;
419}
420
421static const struct dev_pm_ops vxr7200_dev_pm_ops = {
422 .suspend = vxr7200_pm_suspend,
423 .resume = vxr7200_pm_resume,
424 .freeze = vxr7200_pm_freeze,
425 .restore = vxr7200_pm_restore,
426 .thaw = vxr7200_pm_restore,
427 .poweroff = vxr7200_pm_suspend,
428};
429
430static const struct i2c_device_id vxr7200_id_table[] = {
431 {"vxr7200", 0},
432 {}
433};
434
435static struct i2c_driver vxr7200_i2c_driver = {
436 .probe = vxr7200_probe,
437 .remove = vxr7200_remove,
438 .shutdown = vxr7200_shutdown,
439 .driver = {
440 .name = "vxr7200",
441 .owner = THIS_MODULE,
442 .pm = &vxr7200_dev_pm_ops,
443 },
444 .id_table = vxr7200_id_table,
445};
Rajesh Bharathwaj9cd60e02020-03-24 18:04:14 -0700446
447static int __init vxr7200_init(void)
448{
449 char *cmdline;
450
451 cmdline = strnstr(boot_command_line,
452 "msm_drm.dsi_display0=dsi_sim_vid_display",
453 strlen(boot_command_line));
454 if (cmdline) {
455 pr_debug("%s DSI SIM mode, going to dp init cmdline:%s\n",
456 __func__, cmdline);
457 dsi_way = false;
458 } else {
459 pr_debug("%s DSI WAY, going to dsi init cmdline:%s\n",
460 __func__, cmdline);
461 dsi_way = true;
462 }
463
464 return 0;
465
466}
467
468device_initcall(vxr7200_init);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800469module_i2c_driver(vxr7200_i2c_driver);
470MODULE_DEVICE_TABLE(i2c, vxr7200_id_table);
471MODULE_DESCRIPTION("VXR7200 DP2DSI Bridge");