blob: b9f40e94e1fdb06d8e8fb6b2d9b495326d76e366 [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/kernel.h>
24#include <linux/gpio.h>
25#include <linux/delay.h>
Rajesh Bharathwaj7a0a6702020-04-20 17:15:22 -070026#include "tusb1064.h"
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -080027
28struct tusb1064 {
29 struct device *dev;
30 struct device_node *host_node;
31 u8 i2c_addr;
32 u32 dp_3v3_en;
33 struct i2c_client *i2c_client;
34 bool power_on;
35};
36
37static struct tusb1064 *pdata;
Rajesh Bharathwaj00b57ac2020-03-24 23:16:35 -070038static bool standalone_mode;
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -080039
40static int tusb1064_read(struct i2c_client *client, u8 reg, char *buf, u32 size)
41{
42 struct i2c_msg msg[2] = {
43 {
44 .addr = client->addr,
45 .flags = 0,
46 .len = 1,
47 .buf = &reg,
48 },
49 {
50 .addr = client->addr,
51 .flags = I2C_M_RD,
52 .len = size,
53 .buf = buf,
54 }
55 };
56
57 if (i2c_transfer(client->adapter, msg, 2) != 2) {
58 pr_err("%s i2c read failed\n", __func__);
59 return -EIO;
60 }
61 pr_debug("%s, reg:%x buf[0]:%x\n", __func__, reg, buf[0]);
62
63 return 0;
64}
65
66static int tusb1064_write(struct i2c_client *client, u8 reg, u8 val)
67{
68 u8 buf[2] = {reg, val};
69 struct i2c_msg msg = {
70 .addr = client->addr,
71 .flags = 0,
72 .len = 2,
73 .buf = buf,
74 };
75
76 pr_debug("%s, reg:%x, val:%x\n", __func__, reg, val);
77 if (i2c_transfer(client->adapter, &msg, 1) < 1) {
78 pr_err("i2c write failed\n");
79 return -EIO;
80 }
81 return 0;
82}
83
Rajesh Bharathwaj7a0a6702020-04-20 17:15:22 -070084void tusb1064_usb_event(bool flip)
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -080085{
86 if (pdata) {
87 if (flip) {
Rajesh Bharathwaj7a0a6702020-04-20 17:15:22 -070088 if (standalone_mode)
89 tusb1064_write(pdata->i2c_client, 0x0A, 0x05);
90 else
91 tusb1064_write(pdata->i2c_client, 0x0A, 0x06);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -080092 } else {
Rajesh Bharathwaj7a0a6702020-04-20 17:15:22 -070093 if (standalone_mode)
94 tusb1064_write(pdata->i2c_client, 0x0A, 0x01);
95 else
96 tusb1064_write(pdata->i2c_client, 0x0A, 0x02);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -080097 }
98 }
99}
Rajesh Bharathwaj7a0a6702020-04-20 17:15:22 -0700100EXPORT_SYMBOL(tusb1064_usb_event);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800101
102static int tusb1064_probe(struct i2c_client *client,
103 const struct i2c_device_id *id)
104{
105 char buf[2];
106
107 if (!client || !client->dev.of_node) {
108 pr_err("%s invalid input\n", __func__);
109 return -EINVAL;
110 }
111
112 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
113 pr_err("%s device doesn't support I2C\n", __func__);
114 return -ENODEV;
115 }
116
117 pdata = devm_kzalloc(&client->dev,
118 sizeof(struct tusb1064), GFP_KERNEL);
119 if (!pdata)
120 return -ENOMEM;
121
122 pdata->dev = &client->dev;
123 pdata->i2c_client = client;
124 pr_debug("%s I2C address is %x\n", __func__, client->addr);
125
126 i2c_set_clientdata(client, pdata);
127 dev_set_drvdata(&client->dev, pdata);
128
129 tusb1064_read(pdata->i2c_client, 0x0A, buf, 2);
130 tusb1064_read(pdata->i2c_client, 0x13, buf, 2);
131 /*Enable 4-lane DP with FLip and enable EQ_OVERRIDe*/
132 /*tusb1064_write(pdata, 0x0A, 0x13); */
133 /*written usb sideEnable 4-lane DP with FLip and enable EQ_OVERRIDe */
134 /*tusb1064_write(pdata, 0x0A, 0x12); */
135
Rajesh Bharathwaj00b57ac2020-03-24 23:16:35 -0700136 if (standalone_mode) {
137 /*Enable 3.1 USB, no DP */
138 if (tusb1064_write(pdata->i2c_client, 0x0A, 0x01) < 0)
139 goto fail;
140 } else {
141 /*Enable 4-lane DP with Flip and enable EQ_OVERRIDe */
142 if (tusb1064_write(pdata->i2c_client, 0x0A, 0x02) < 0)
143 goto fail;
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800144
Rajesh Bharathwaj00b57ac2020-03-24 23:16:35 -0700145 pr_debug("%s setting SBU1 to AUXN, SBU2 to AUXP\n", __func__);
Rajesh Bharathwaj00b57ac2020-03-24 23:16:35 -0700146 }
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800147 tusb1064_read(pdata->i2c_client, 0x0A, buf, 2);
148 tusb1064_read(pdata->i2c_client, 0x13, buf, 2);
149 tusb1064_read(pdata->i2c_client, 0x10, buf, 2);
150 tusb1064_read(pdata->i2c_client, 0x11, buf, 2);
151
152 pr_debug("%s probe successfully\n", __func__);
153 return 0;
154fail:
155 devm_kfree(&client->dev, pdata);
156 return -EINVAL;
157}
158
159static int tusb1064_remove(struct i2c_client *client)
160{
161 struct tusb1064 *pdata = i2c_get_clientdata(client);
162
163 if (pdata)
164 devm_kfree(&client->dev, pdata);
165 return 0;
166}
167
168static void tusb1064_shutdown(struct i2c_client *client)
169{
170 dev_info(&(client->dev), "shutdown");
171}
172
173static int tusb1064_suspend(struct device *dev, pm_message_t state)
174{
175 dev_info(dev, "suspend");
176 return 0;
177}
178
179static int tusb1064_resume(struct device *dev)
180{
181 dev_info(dev, "resume");
182 return 0;
183}
184
185static const struct i2c_device_id tusb1064_id_table[] = {
186 {"tusb1064", 0},
187 {}
188};
189
190static struct i2c_driver tusb1064_i2c_driver = {
191 .probe = tusb1064_probe,
192 .remove = tusb1064_remove,
193 .shutdown = tusb1064_shutdown,
194 .driver = {
195 .name = "tusb1064",
196 .owner = THIS_MODULE,
197 .suspend = tusb1064_suspend,
198 .resume = tusb1064_resume,
199 },
200 .id_table = tusb1064_id_table,
201};
Rajesh Bharathwaj00b57ac2020-03-24 23:16:35 -0700202
203static int __init tusb1064_init(void)
204{
205 char *cmdline;
206
207 cmdline = strnstr(boot_command_line,
208 "msm_drm.dsi_display0=dsi_sim_vid_display",
209 strlen(boot_command_line));
210 if (cmdline) {
211 pr_debug("%s tethered mode cmdline:%s\n",
212 __func__, cmdline);
213 standalone_mode = false;
214 } else {
215 pr_debug("%s standalone mode cmdline:%s\n",
216 __func__, cmdline);
217 standalone_mode = true;
218 }
219
220 return 0;
221}
222
223device_initcall(tusb1064_init);
Rajesh Bharathwajdcc7af82019-12-15 22:42:55 -0800224module_i2c_driver(tusb1064_i2c_driver);
225MODULE_DEVICE_TABLE(i2c, tusb1064_id_table);
226MODULE_DESCRIPTION("TUSB1064 USB Bridge");