xref: /openbmc/linux/drivers/usb/mtu3/mtu3_dr.c (revision efe4a1ac)
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 	if (!ssusb->otg_switch.is_u3_drd) {
43 		mtu3_setbits(ssusb->mac_base, U3D_DEVICE_CONTROL, DC_SESSION);
44 		mtu3_setbits(ssusb->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN);
45 	}
46 }
47 
48 /* only port0 supports dual-role mode */
49 static int ssusb_port0_switch(struct ssusb_mtk *ssusb,
50 	int version, bool tohost)
51 {
52 	void __iomem *ibase = ssusb->ippc_base;
53 	u32 value;
54 
55 	dev_dbg(ssusb->dev, "%s (switch u%d port0 to %s)\n", __func__,
56 		version, tohost ? "host" : "device");
57 
58 	if (version == USB2_PORT) {
59 		/* 1. power off and disable u2 port0 */
60 		value = mtu3_readl(ibase, SSUSB_U2_CTRL(0));
61 		value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS;
62 		mtu3_writel(ibase, SSUSB_U2_CTRL(0), value);
63 
64 		/* 2. power on, enable u2 port0 and select its mode */
65 		value = mtu3_readl(ibase, SSUSB_U2_CTRL(0));
66 		value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
67 		value = tohost ? (value | SSUSB_U2_PORT_HOST_SEL) :
68 			(value & (~SSUSB_U2_PORT_HOST_SEL));
69 		mtu3_writel(ibase, SSUSB_U2_CTRL(0), value);
70 	} else {
71 		/* 1. power off and disable u3 port0 */
72 		value = mtu3_readl(ibase, SSUSB_U3_CTRL(0));
73 		value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS;
74 		mtu3_writel(ibase, SSUSB_U3_CTRL(0), value);
75 
76 		/* 2. power on, enable u3 port0 and select its mode */
77 		value = mtu3_readl(ibase, SSUSB_U3_CTRL(0));
78 		value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
79 		value = tohost ? (value | SSUSB_U3_PORT_HOST_SEL) :
80 			(value & (~SSUSB_U3_PORT_HOST_SEL));
81 		mtu3_writel(ibase, SSUSB_U3_CTRL(0), value);
82 	}
83 
84 	return 0;
85 }
86 
87 static void switch_port_to_host(struct ssusb_mtk *ssusb)
88 {
89 	u32 check_clk = 0;
90 
91 	dev_dbg(ssusb->dev, "%s\n", __func__);
92 
93 	ssusb_port0_switch(ssusb, USB2_PORT, true);
94 
95 	if (ssusb->otg_switch.is_u3_drd) {
96 		ssusb_port0_switch(ssusb, USB3_PORT, true);
97 		check_clk = SSUSB_U3_MAC_RST_B_STS;
98 	}
99 
100 	ssusb_check_clocks(ssusb, check_clk);
101 
102 	/* after all clocks are stable */
103 	toggle_opstate(ssusb);
104 }
105 
106 static void switch_port_to_device(struct ssusb_mtk *ssusb)
107 {
108 	u32 check_clk = 0;
109 
110 	dev_dbg(ssusb->dev, "%s\n", __func__);
111 
112 	ssusb_port0_switch(ssusb, USB2_PORT, false);
113 
114 	if (ssusb->otg_switch.is_u3_drd) {
115 		ssusb_port0_switch(ssusb, USB3_PORT, false);
116 		check_clk = SSUSB_U3_MAC_RST_B_STS;
117 	}
118 
119 	ssusb_check_clocks(ssusb, check_clk);
120 }
121 
122 int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
123 {
124 	struct ssusb_mtk *ssusb =
125 		container_of(otg_sx, struct ssusb_mtk, otg_switch);
126 	struct regulator *vbus = otg_sx->vbus;
127 	int ret;
128 
129 	/* vbus is optional */
130 	if (!vbus)
131 		return 0;
132 
133 	dev_dbg(ssusb->dev, "%s: turn %s\n", __func__, is_on ? "on" : "off");
134 
135 	if (is_on) {
136 		ret = regulator_enable(vbus);
137 		if (ret) {
138 			dev_err(ssusb->dev, "vbus regulator enable failed\n");
139 			return ret;
140 		}
141 	} else {
142 		regulator_disable(vbus);
143 	}
144 
145 	return 0;
146 }
147 
148 /*
149  * switch to host: -> MTU3_VBUS_OFF --> MTU3_ID_GROUND
150  * switch to device: -> MTU3_ID_FLOAT --> MTU3_VBUS_VALID
151  */
152 static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
153 	enum mtu3_vbus_id_state status)
154 {
155 	struct ssusb_mtk *ssusb =
156 		container_of(otg_sx, struct ssusb_mtk, otg_switch);
157 	struct mtu3 *mtu = ssusb->u3d;
158 
159 	dev_dbg(ssusb->dev, "mailbox state(%d)\n", status);
160 
161 	switch (status) {
162 	case MTU3_ID_GROUND:
163 		switch_port_to_host(ssusb);
164 		ssusb_set_vbus(otg_sx, 1);
165 		ssusb->is_host = true;
166 		break;
167 	case MTU3_ID_FLOAT:
168 		ssusb->is_host = false;
169 		ssusb_set_vbus(otg_sx, 0);
170 		switch_port_to_device(ssusb);
171 		break;
172 	case MTU3_VBUS_OFF:
173 		mtu3_stop(mtu);
174 		pm_relax(ssusb->dev);
175 		break;
176 	case MTU3_VBUS_VALID:
177 		/* avoid suspend when works as device */
178 		pm_stay_awake(ssusb->dev);
179 		mtu3_start(mtu);
180 		break;
181 	default:
182 		dev_err(ssusb->dev, "invalid state\n");
183 	}
184 }
185 
186 static int ssusb_id_notifier(struct notifier_block *nb,
187 	unsigned long event, void *ptr)
188 {
189 	struct otg_switch_mtk *otg_sx =
190 		container_of(nb, struct otg_switch_mtk, id_nb);
191 
192 	if (event)
193 		ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
194 	else
195 		ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
196 
197 	return NOTIFY_DONE;
198 }
199 
200 static int ssusb_vbus_notifier(struct notifier_block *nb,
201 	unsigned long event, void *ptr)
202 {
203 	struct otg_switch_mtk *otg_sx =
204 		container_of(nb, struct otg_switch_mtk, vbus_nb);
205 
206 	if (event)
207 		ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
208 	else
209 		ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
210 
211 	return NOTIFY_DONE;
212 }
213 
214 static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
215 {
216 	struct ssusb_mtk *ssusb =
217 		container_of(otg_sx, struct ssusb_mtk, otg_switch);
218 	struct extcon_dev *edev = otg_sx->edev;
219 	int ret;
220 
221 	/* extcon is optional */
222 	if (!edev)
223 		return 0;
224 
225 	otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
226 	ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB,
227 					&otg_sx->vbus_nb);
228 	if (ret < 0)
229 		dev_err(ssusb->dev, "failed to register notifier for USB\n");
230 
231 	otg_sx->id_nb.notifier_call = ssusb_id_notifier;
232 	ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST,
233 					&otg_sx->id_nb);
234 	if (ret < 0)
235 		dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n");
236 
237 	dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
238 		extcon_get_state(edev, EXTCON_USB),
239 		extcon_get_state(edev, EXTCON_USB_HOST));
240 
241 	/* default as host, switch to device mode if needed */
242 	if (extcon_get_state(edev, EXTCON_USB_HOST) == false)
243 		ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
244 	if (extcon_get_state(edev, EXTCON_USB) == true)
245 		ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
246 
247 	return 0;
248 }
249 
250 static void extcon_register_dwork(struct work_struct *work)
251 {
252 	struct delayed_work *dwork = to_delayed_work(work);
253 	struct otg_switch_mtk *otg_sx =
254 	    container_of(dwork, struct otg_switch_mtk, extcon_reg_dwork);
255 
256 	ssusb_extcon_register(otg_sx);
257 }
258 
259 /*
260  * We provide an interface via debugfs to switch between host and device modes
261  * depending on user input.
262  * This is useful in special cases, such as uses TYPE-A receptacle but also
263  * wants to support dual-role mode.
264  * It generates cable state changes by pulling up/down IDPIN and
265  * notifies driver to switch mode by "extcon-usb-gpio".
266  * NOTE: when use MICRO receptacle, should not enable this interface.
267  */
268 static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
269 {
270 	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
271 
272 	if (to_host)
273 		pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
274 	else
275 		pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
276 }
277 
278 
279 static int ssusb_mode_show(struct seq_file *sf, void *unused)
280 {
281 	struct ssusb_mtk *ssusb = sf->private;
282 
283 	seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n",
284 		ssusb->is_host ? "host" : "device",
285 		ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto");
286 
287 	return 0;
288 }
289 
290 static int ssusb_mode_open(struct inode *inode, struct file *file)
291 {
292 	return single_open(file, ssusb_mode_show, inode->i_private);
293 }
294 
295 static ssize_t ssusb_mode_write(struct file *file,
296 	const char __user *ubuf, size_t count, loff_t *ppos)
297 {
298 	struct seq_file *sf = file->private_data;
299 	struct ssusb_mtk *ssusb = sf->private;
300 	char buf[16];
301 
302 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
303 		return -EFAULT;
304 
305 	if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
306 		ssusb_mode_manual_switch(ssusb, 1);
307 	} else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
308 		ssusb_mode_manual_switch(ssusb, 0);
309 	} else {
310 		dev_err(ssusb->dev, "wrong or duplicated setting\n");
311 		return -EINVAL;
312 	}
313 
314 	return count;
315 }
316 
317 static const struct file_operations ssusb_mode_fops = {
318 	.open = ssusb_mode_open,
319 	.write = ssusb_mode_write,
320 	.read = seq_read,
321 	.llseek = seq_lseek,
322 	.release = single_release,
323 };
324 
325 static void ssusb_debugfs_init(struct ssusb_mtk *ssusb)
326 {
327 	struct dentry *root;
328 	struct dentry *file;
329 
330 	root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
331 	if (IS_ERR_OR_NULL(root)) {
332 		if (!root)
333 			dev_err(ssusb->dev, "create debugfs root failed\n");
334 		return;
335 	}
336 	ssusb->dbgfs_root = root;
337 
338 	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
339 			ssusb, &ssusb_mode_fops);
340 	if (!file)
341 		dev_dbg(ssusb->dev, "create debugfs mode failed\n");
342 }
343 
344 static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
345 {
346 	debugfs_remove_recursive(ssusb->dbgfs_root);
347 }
348 
349 int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
350 {
351 	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
352 
353 	INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
354 
355 	if (otg_sx->manual_drd_enabled)
356 		ssusb_debugfs_init(ssusb);
357 
358 	/* It is enough to delay 1s for waiting for host initialization */
359 	schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
360 
361 	return 0;
362 }
363 
364 void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
365 {
366 	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
367 
368 	cancel_delayed_work(&otg_sx->extcon_reg_dwork);
369 
370 	if (otg_sx->manual_drd_enabled)
371 		ssusb_debugfs_exit(ssusb);
372 }
373