GNU Linux-libre 4.14.302-gnu1
[releases.git] / drivers / usb / mtu3 / mtu3_dr.c
1 /*
2  * mtu3_dr.c - dual role switch and host glue layer
3  *
4  * Copyright (C) 2016 MediaTek Inc.
5  *
6  * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  */
18
19 #include <linux/debugfs.h>
20 #include <linux/irq.h>
21 #include <linux/kernel.h>
22 #include <linux/of_device.h>
23 #include <linux/pinctrl/consumer.h>
24 #include <linux/seq_file.h>
25 #include <linux/uaccess.h>
26
27 #include "mtu3.h"
28 #include "mtu3_dr.h"
29
30 #define USB2_PORT 2
31 #define USB3_PORT 3
32
33 enum mtu3_vbus_id_state {
34         MTU3_ID_FLOAT = 1,
35         MTU3_ID_GROUND,
36         MTU3_VBUS_OFF,
37         MTU3_VBUS_VALID,
38 };
39
40 static void toggle_opstate(struct ssusb_mtk *ssusb)
41 {
42         mtu3_setbits(ssusb->mac_base, U3D_DEVICE_CONTROL, DC_SESSION);
43         mtu3_setbits(ssusb->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN);
44 }
45
46 /* only port0 supports dual-role mode */
47 static int ssusb_port0_switch(struct ssusb_mtk *ssusb,
48         int version, bool tohost)
49 {
50         void __iomem *ibase = ssusb->ippc_base;
51         u32 value;
52
53         dev_dbg(ssusb->dev, "%s (switch u%d port0 to %s)\n", __func__,
54                 version, tohost ? "host" : "device");
55
56         if (version == USB2_PORT) {
57                 /* 1. power off and disable u2 port0 */
58                 value = mtu3_readl(ibase, SSUSB_U2_CTRL(0));
59                 value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS;
60                 mtu3_writel(ibase, SSUSB_U2_CTRL(0), value);
61
62                 /* 2. power on, enable u2 port0 and select its mode */
63                 value = mtu3_readl(ibase, SSUSB_U2_CTRL(0));
64                 value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
65                 value = tohost ? (value | SSUSB_U2_PORT_HOST_SEL) :
66                         (value & (~SSUSB_U2_PORT_HOST_SEL));
67                 mtu3_writel(ibase, SSUSB_U2_CTRL(0), value);
68         } else {
69                 /* 1. power off and disable u3 port0 */
70                 value = mtu3_readl(ibase, SSUSB_U3_CTRL(0));
71                 value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS;
72                 mtu3_writel(ibase, SSUSB_U3_CTRL(0), value);
73
74                 /* 2. power on, enable u3 port0 and select its mode */
75                 value = mtu3_readl(ibase, SSUSB_U3_CTRL(0));
76                 value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
77                 value = tohost ? (value | SSUSB_U3_PORT_HOST_SEL) :
78                         (value & (~SSUSB_U3_PORT_HOST_SEL));
79                 mtu3_writel(ibase, SSUSB_U3_CTRL(0), value);
80         }
81
82         return 0;
83 }
84
85 static void switch_port_to_host(struct ssusb_mtk *ssusb)
86 {
87         u32 check_clk = 0;
88
89         dev_dbg(ssusb->dev, "%s\n", __func__);
90
91         ssusb_port0_switch(ssusb, USB2_PORT, true);
92
93         if (ssusb->otg_switch.is_u3_drd) {
94                 ssusb_port0_switch(ssusb, USB3_PORT, true);
95                 check_clk = SSUSB_U3_MAC_RST_B_STS;
96         }
97
98         ssusb_check_clocks(ssusb, check_clk);
99
100         /* after all clocks are stable */
101         toggle_opstate(ssusb);
102 }
103
104 static void switch_port_to_device(struct ssusb_mtk *ssusb)
105 {
106         u32 check_clk = 0;
107
108         dev_dbg(ssusb->dev, "%s\n", __func__);
109
110         ssusb_port0_switch(ssusb, USB2_PORT, false);
111
112         if (ssusb->otg_switch.is_u3_drd) {
113                 ssusb_port0_switch(ssusb, USB3_PORT, false);
114                 check_clk = SSUSB_U3_MAC_RST_B_STS;
115         }
116
117         ssusb_check_clocks(ssusb, check_clk);
118 }
119
120 int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
121 {
122         struct ssusb_mtk *ssusb =
123                 container_of(otg_sx, struct ssusb_mtk, otg_switch);
124         struct regulator *vbus = otg_sx->vbus;
125         int ret;
126
127         /* vbus is optional */
128         if (!vbus)
129                 return 0;
130
131         dev_dbg(ssusb->dev, "%s: turn %s\n", __func__, is_on ? "on" : "off");
132
133         if (is_on) {
134                 ret = regulator_enable(vbus);
135                 if (ret) {
136                         dev_err(ssusb->dev, "vbus regulator enable failed\n");
137                         return ret;
138                 }
139         } else {
140                 regulator_disable(vbus);
141         }
142
143         return 0;
144 }
145
146 /*
147  * switch to host: -> MTU3_VBUS_OFF --> MTU3_ID_GROUND
148  * switch to device: -> MTU3_ID_FLOAT --> MTU3_VBUS_VALID
149  */
150 static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
151         enum mtu3_vbus_id_state status)
152 {
153         struct ssusb_mtk *ssusb =
154                 container_of(otg_sx, struct ssusb_mtk, otg_switch);
155         struct mtu3 *mtu = ssusb->u3d;
156
157         dev_dbg(ssusb->dev, "mailbox state(%d)\n", status);
158
159         switch (status) {
160         case MTU3_ID_GROUND:
161                 switch_port_to_host(ssusb);
162                 ssusb_set_vbus(otg_sx, 1);
163                 ssusb->is_host = true;
164                 break;
165         case MTU3_ID_FLOAT:
166                 ssusb->is_host = false;
167                 ssusb_set_vbus(otg_sx, 0);
168                 switch_port_to_device(ssusb);
169                 break;
170         case MTU3_VBUS_OFF:
171                 mtu3_stop(mtu);
172                 pm_relax(ssusb->dev);
173                 break;
174         case MTU3_VBUS_VALID:
175                 /* avoid suspend when works as device */
176                 pm_stay_awake(ssusb->dev);
177                 mtu3_start(mtu);
178                 break;
179         default:
180                 dev_err(ssusb->dev, "invalid state\n");
181         }
182 }
183
184 static int ssusb_id_notifier(struct notifier_block *nb,
185         unsigned long event, void *ptr)
186 {
187         struct otg_switch_mtk *otg_sx =
188                 container_of(nb, struct otg_switch_mtk, id_nb);
189
190         if (event)
191                 ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
192         else
193                 ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
194
195         return NOTIFY_DONE;
196 }
197
198 static int ssusb_vbus_notifier(struct notifier_block *nb,
199         unsigned long event, void *ptr)
200 {
201         struct otg_switch_mtk *otg_sx =
202                 container_of(nb, struct otg_switch_mtk, vbus_nb);
203
204         if (event)
205                 ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
206         else
207                 ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
208
209         return NOTIFY_DONE;
210 }
211
212 static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
213 {
214         struct ssusb_mtk *ssusb =
215                 container_of(otg_sx, struct ssusb_mtk, otg_switch);
216         struct extcon_dev *edev = otg_sx->edev;
217         int ret;
218
219         /* extcon is optional */
220         if (!edev)
221                 return 0;
222
223         otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
224         ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB,
225                                         &otg_sx->vbus_nb);
226         if (ret < 0)
227                 dev_err(ssusb->dev, "failed to register notifier for USB\n");
228
229         otg_sx->id_nb.notifier_call = ssusb_id_notifier;
230         ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST,
231                                         &otg_sx->id_nb);
232         if (ret < 0)
233                 dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n");
234
235         dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
236                 extcon_get_state(edev, EXTCON_USB),
237                 extcon_get_state(edev, EXTCON_USB_HOST));
238
239         /* default as host, switch to device mode if needed */
240         if (extcon_get_state(edev, EXTCON_USB_HOST) == false)
241                 ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
242         if (extcon_get_state(edev, EXTCON_USB) == true)
243                 ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
244
245         return 0;
246 }
247
248 static void extcon_register_dwork(struct work_struct *work)
249 {
250         struct delayed_work *dwork = to_delayed_work(work);
251         struct otg_switch_mtk *otg_sx =
252             container_of(dwork, struct otg_switch_mtk, extcon_reg_dwork);
253
254         ssusb_extcon_register(otg_sx);
255 }
256
257 /*
258  * We provide an interface via debugfs to switch between host and device modes
259  * depending on user input.
260  * This is useful in special cases, such as uses TYPE-A receptacle but also
261  * wants to support dual-role mode.
262  * It generates cable state changes by pulling up/down IDPIN and
263  * notifies driver to switch mode by "extcon-usb-gpio".
264  * NOTE: when use MICRO receptacle, should not enable this interface.
265  */
266 static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
267 {
268         struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
269
270         if (to_host)
271                 pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
272         else
273                 pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
274 }
275
276
277 static int ssusb_mode_show(struct seq_file *sf, void *unused)
278 {
279         struct ssusb_mtk *ssusb = sf->private;
280
281         seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n",
282                 ssusb->is_host ? "host" : "device",
283                 ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto");
284
285         return 0;
286 }
287
288 static int ssusb_mode_open(struct inode *inode, struct file *file)
289 {
290         return single_open(file, ssusb_mode_show, inode->i_private);
291 }
292
293 static ssize_t ssusb_mode_write(struct file *file,
294         const char __user *ubuf, size_t count, loff_t *ppos)
295 {
296         struct seq_file *sf = file->private_data;
297         struct ssusb_mtk *ssusb = sf->private;
298         char buf[16];
299
300         if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
301                 return -EFAULT;
302
303         if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
304                 ssusb_mode_manual_switch(ssusb, 1);
305         } else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
306                 ssusb_mode_manual_switch(ssusb, 0);
307         } else {
308                 dev_err(ssusb->dev, "wrong or duplicated setting\n");
309                 return -EINVAL;
310         }
311
312         return count;
313 }
314
315 static const struct file_operations ssusb_mode_fops = {
316         .open = ssusb_mode_open,
317         .write = ssusb_mode_write,
318         .read = seq_read,
319         .llseek = seq_lseek,
320         .release = single_release,
321 };
322
323 static int ssusb_vbus_show(struct seq_file *sf, void *unused)
324 {
325         struct ssusb_mtk *ssusb = sf->private;
326         struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
327
328         seq_printf(sf, "vbus state: %s\n(echo on/off)\n",
329                 regulator_is_enabled(otg_sx->vbus) ? "on" : "off");
330
331         return 0;
332 }
333
334 static int ssusb_vbus_open(struct inode *inode, struct file *file)
335 {
336         return single_open(file, ssusb_vbus_show, inode->i_private);
337 }
338
339 static ssize_t ssusb_vbus_write(struct file *file,
340         const char __user *ubuf, size_t count, loff_t *ppos)
341 {
342         struct seq_file *sf = file->private_data;
343         struct ssusb_mtk *ssusb = sf->private;
344         struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
345         char buf[16];
346         bool enable;
347
348         if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
349                 return -EFAULT;
350
351         if (kstrtobool(buf, &enable)) {
352                 dev_err(ssusb->dev, "wrong setting\n");
353                 return -EINVAL;
354         }
355
356         ssusb_set_vbus(otg_sx, enable);
357
358         return count;
359 }
360
361 static const struct file_operations ssusb_vbus_fops = {
362         .open = ssusb_vbus_open,
363         .write = ssusb_vbus_write,
364         .read = seq_read,
365         .llseek = seq_lseek,
366         .release = single_release,
367 };
368
369 static void ssusb_debugfs_init(struct ssusb_mtk *ssusb)
370 {
371         struct dentry *root;
372
373         root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
374         if (!root) {
375                 dev_err(ssusb->dev, "create debugfs root failed\n");
376                 return;
377         }
378         ssusb->dbgfs_root = root;
379
380         debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops);
381         debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops);
382 }
383
384 static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
385 {
386         debugfs_remove_recursive(ssusb->dbgfs_root);
387 }
388
389 int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
390 {
391         struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
392
393         INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
394
395         if (otg_sx->manual_drd_enabled)
396                 ssusb_debugfs_init(ssusb);
397
398         /* It is enough to delay 1s for waiting for host initialization */
399         schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
400
401         return 0;
402 }
403
404 void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
405 {
406         struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
407
408         cancel_delayed_work(&otg_sx->extcon_reg_dwork);
409
410         if (otg_sx->manual_drd_enabled)
411                 ssusb_debugfs_exit(ssusb);
412 }