xref: /linux/drivers/usb/phy/phy-tahvo.c (revision 4949009eb8d40a441dcddcd96e101e77d31cf1b2)
1 /*
2  * Tahvo USB transceiver driver
3  *
4  * Copyright (C) 2005-2006 Nokia Corporation
5  *
6  * Parts copied from isp1301_omap.c.
7  * Copyright (C) 2004 Texas Instruments
8  * Copyright (C) 2004 David Brownell
9  *
10  * Original driver written by Juha Yrjölä, Tony Lindgren and Timo Teräs.
11  * Modified for Retu/Tahvo MFD by Aaro Koskinen.
12  *
13  * This file is subject to the terms and conditions of the GNU General
14  * Public License. See the file "COPYING" in the main directory of this
15  * archive for more details.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  */
22 
23 #include <linux/io.h>
24 #include <linux/clk.h>
25 #include <linux/usb.h>
26 #include <linux/extcon.h>
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/usb/otg.h>
30 #include <linux/mfd/retu.h>
31 #include <linux/usb/gadget.h>
32 #include <linux/platform_device.h>
33 
34 #define DRIVER_NAME     "tahvo-usb"
35 
36 #define TAHVO_REG_IDSR	0x02
37 #define TAHVO_REG_USBR	0x06
38 
39 #define USBR_SLAVE_CONTROL	(1 << 8)
40 #define USBR_VPPVIO_SW		(1 << 7)
41 #define USBR_SPEED		(1 << 6)
42 #define USBR_REGOUT		(1 << 5)
43 #define USBR_MASTER_SW2		(1 << 4)
44 #define USBR_MASTER_SW1		(1 << 3)
45 #define USBR_SLAVE_SW		(1 << 2)
46 #define USBR_NSUSPEND		(1 << 1)
47 #define USBR_SEMODE		(1 << 0)
48 
49 #define TAHVO_MODE_HOST		0
50 #define TAHVO_MODE_PERIPHERAL	1
51 
52 struct tahvo_usb {
53 	struct platform_device	*pt_dev;
54 	struct usb_phy		phy;
55 	int			vbus_state;
56 	struct mutex		serialize;
57 	struct clk		*ick;
58 	int			irq;
59 	int			tahvo_mode;
60 	struct extcon_dev	extcon;
61 };
62 
63 static const char *tahvo_cable[] = {
64 	"USB-HOST",
65 	"USB",
66 	NULL,
67 };
68 
69 static ssize_t vbus_state_show(struct device *device,
70 			       struct device_attribute *attr, char *buf)
71 {
72 	struct tahvo_usb *tu = dev_get_drvdata(device);
73 	return sprintf(buf, "%s\n", tu->vbus_state ? "on" : "off");
74 }
75 static DEVICE_ATTR(vbus, 0444, vbus_state_show, NULL);
76 
77 static void check_vbus_state(struct tahvo_usb *tu)
78 {
79 	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
80 	int reg, prev_state;
81 
82 	reg = retu_read(rdev, TAHVO_REG_IDSR);
83 	if (reg & TAHVO_STAT_VBUS) {
84 		switch (tu->phy.otg->state) {
85 		case OTG_STATE_B_IDLE:
86 			/* Enable the gadget driver */
87 			if (tu->phy.otg->gadget)
88 				usb_gadget_vbus_connect(tu->phy.otg->gadget);
89 			tu->phy.otg->state = OTG_STATE_B_PERIPHERAL;
90 			usb_phy_set_event(&tu->phy, USB_EVENT_ENUMERATED);
91 			break;
92 		case OTG_STATE_A_IDLE:
93 			/*
94 			 * Session is now valid assuming the USB hub is driving
95 			 * Vbus.
96 			 */
97 			tu->phy.otg->state = OTG_STATE_A_HOST;
98 			break;
99 		default:
100 			break;
101 		}
102 		dev_info(&tu->pt_dev->dev, "USB cable connected\n");
103 	} else {
104 		switch (tu->phy.otg->state) {
105 		case OTG_STATE_B_PERIPHERAL:
106 			if (tu->phy.otg->gadget)
107 				usb_gadget_vbus_disconnect(tu->phy.otg->gadget);
108 			tu->phy.otg->state = OTG_STATE_B_IDLE;
109 			usb_phy_set_event(&tu->phy, USB_EVENT_NONE);
110 			break;
111 		case OTG_STATE_A_HOST:
112 			tu->phy.otg->state = OTG_STATE_A_IDLE;
113 			break;
114 		default:
115 			break;
116 		}
117 		dev_info(&tu->pt_dev->dev, "USB cable disconnected\n");
118 	}
119 
120 	prev_state = tu->vbus_state;
121 	tu->vbus_state = reg & TAHVO_STAT_VBUS;
122 	if (prev_state != tu->vbus_state) {
123 		extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state);
124 		sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state");
125 	}
126 }
127 
128 static void tahvo_usb_become_host(struct tahvo_usb *tu)
129 {
130 	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
131 
132 	extcon_set_cable_state(&tu->extcon, "USB-HOST", true);
133 
134 	/* Power up the transceiver in USB host mode */
135 	retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
136 		   USBR_MASTER_SW2 | USBR_MASTER_SW1);
137 	tu->phy.otg->state = OTG_STATE_A_IDLE;
138 
139 	check_vbus_state(tu);
140 }
141 
142 static void tahvo_usb_stop_host(struct tahvo_usb *tu)
143 {
144 	tu->phy.otg->state = OTG_STATE_A_IDLE;
145 }
146 
147 static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
148 {
149 	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
150 
151 	extcon_set_cable_state(&tu->extcon, "USB-HOST", false);
152 
153 	/* Power up transceiver and set it in USB peripheral mode */
154 	retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT |
155 		   USBR_NSUSPEND | USBR_SLAVE_SW);
156 	tu->phy.otg->state = OTG_STATE_B_IDLE;
157 
158 	check_vbus_state(tu);
159 }
160 
161 static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu)
162 {
163 	if (tu->phy.otg->gadget)
164 		usb_gadget_vbus_disconnect(tu->phy.otg->gadget);
165 	tu->phy.otg->state = OTG_STATE_B_IDLE;
166 }
167 
168 static void tahvo_usb_power_off(struct tahvo_usb *tu)
169 {
170 	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
171 
172 	/* Disable gadget controller if any */
173 	if (tu->phy.otg->gadget)
174 		usb_gadget_vbus_disconnect(tu->phy.otg->gadget);
175 
176 	/* Power off transceiver */
177 	retu_write(rdev, TAHVO_REG_USBR, 0);
178 	tu->phy.otg->state = OTG_STATE_UNDEFINED;
179 }
180 
181 static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend)
182 {
183 	struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, phy);
184 	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
185 	u16 w;
186 
187 	dev_dbg(&tu->pt_dev->dev, "%s\n", __func__);
188 
189 	w = retu_read(rdev, TAHVO_REG_USBR);
190 	if (suspend)
191 		w &= ~USBR_NSUSPEND;
192 	else
193 		w |= USBR_NSUSPEND;
194 	retu_write(rdev, TAHVO_REG_USBR, w);
195 
196 	return 0;
197 }
198 
199 static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
200 {
201 	struct tahvo_usb *tu = container_of(otg->usb_phy, struct tahvo_usb,
202 					    phy);
203 
204 	dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, host);
205 
206 	mutex_lock(&tu->serialize);
207 
208 	if (host == NULL) {
209 		if (tu->tahvo_mode == TAHVO_MODE_HOST)
210 			tahvo_usb_power_off(tu);
211 		otg->host = NULL;
212 		mutex_unlock(&tu->serialize);
213 		return 0;
214 	}
215 
216 	if (tu->tahvo_mode == TAHVO_MODE_HOST) {
217 		otg->host = NULL;
218 		tahvo_usb_become_host(tu);
219 	}
220 
221 	otg->host = host;
222 
223 	mutex_unlock(&tu->serialize);
224 
225 	return 0;
226 }
227 
228 static int tahvo_usb_set_peripheral(struct usb_otg *otg,
229 				    struct usb_gadget *gadget)
230 {
231 	struct tahvo_usb *tu = container_of(otg->usb_phy, struct tahvo_usb,
232 					    phy);
233 
234 	dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, gadget);
235 
236 	mutex_lock(&tu->serialize);
237 
238 	if (!gadget) {
239 		if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
240 			tahvo_usb_power_off(tu);
241 		tu->phy.otg->gadget = NULL;
242 		mutex_unlock(&tu->serialize);
243 		return 0;
244 	}
245 
246 	tu->phy.otg->gadget = gadget;
247 	if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
248 		tahvo_usb_become_peripheral(tu);
249 
250 	mutex_unlock(&tu->serialize);
251 
252 	return 0;
253 }
254 
255 static irqreturn_t tahvo_usb_vbus_interrupt(int irq, void *_tu)
256 {
257 	struct tahvo_usb *tu = _tu;
258 
259 	mutex_lock(&tu->serialize);
260 	check_vbus_state(tu);
261 	mutex_unlock(&tu->serialize);
262 
263 	return IRQ_HANDLED;
264 }
265 
266 static ssize_t otg_mode_show(struct device *device,
267 			     struct device_attribute *attr, char *buf)
268 {
269 	struct tahvo_usb *tu = dev_get_drvdata(device);
270 
271 	switch (tu->tahvo_mode) {
272 	case TAHVO_MODE_HOST:
273 		return sprintf(buf, "host\n");
274 	case TAHVO_MODE_PERIPHERAL:
275 		return sprintf(buf, "peripheral\n");
276 	}
277 
278 	return -EINVAL;
279 }
280 
281 static ssize_t otg_mode_store(struct device *device,
282 			      struct device_attribute *attr,
283 			      const char *buf, size_t count)
284 {
285 	struct tahvo_usb *tu = dev_get_drvdata(device);
286 	int r;
287 
288 	mutex_lock(&tu->serialize);
289 	if (count >= 4 && strncmp(buf, "host", 4) == 0) {
290 		if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
291 			tahvo_usb_stop_peripheral(tu);
292 		tu->tahvo_mode = TAHVO_MODE_HOST;
293 		if (tu->phy.otg->host) {
294 			dev_info(device, "HOST mode: host controller present\n");
295 			tahvo_usb_become_host(tu);
296 		} else {
297 			dev_info(device, "HOST mode: no host controller, powering off\n");
298 			tahvo_usb_power_off(tu);
299 		}
300 		r = strlen(buf);
301 	} else if (count >= 10 && strncmp(buf, "peripheral", 10) == 0) {
302 		if (tu->tahvo_mode == TAHVO_MODE_HOST)
303 			tahvo_usb_stop_host(tu);
304 		tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
305 		if (tu->phy.otg->gadget) {
306 			dev_info(device, "PERIPHERAL mode: gadget driver present\n");
307 			tahvo_usb_become_peripheral(tu);
308 		} else {
309 			dev_info(device, "PERIPHERAL mode: no gadget driver, powering off\n");
310 			tahvo_usb_power_off(tu);
311 		}
312 		r = strlen(buf);
313 	} else {
314 		r = -EINVAL;
315 	}
316 	mutex_unlock(&tu->serialize);
317 
318 	return r;
319 }
320 static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store);
321 
322 static struct attribute *tahvo_attributes[] = {
323 	&dev_attr_vbus.attr,
324 	&dev_attr_otg_mode.attr,
325 	NULL
326 };
327 
328 static struct attribute_group tahvo_attr_group = {
329 	.attrs = tahvo_attributes,
330 };
331 
332 static int tahvo_usb_probe(struct platform_device *pdev)
333 {
334 	struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent);
335 	struct tahvo_usb *tu;
336 	int ret;
337 
338 	tu = devm_kzalloc(&pdev->dev, sizeof(*tu), GFP_KERNEL);
339 	if (!tu)
340 		return -ENOMEM;
341 
342 	tu->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*tu->phy.otg),
343 				   GFP_KERNEL);
344 	if (!tu->phy.otg)
345 		return -ENOMEM;
346 
347 	tu->pt_dev = pdev;
348 
349 	/* Default mode */
350 #ifdef CONFIG_TAHVO_USB_HOST_BY_DEFAULT
351 	tu->tahvo_mode = TAHVO_MODE_HOST;
352 #else
353 	tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
354 #endif
355 
356 	mutex_init(&tu->serialize);
357 
358 	tu->ick = devm_clk_get(&pdev->dev, "usb_l4_ick");
359 	if (!IS_ERR(tu->ick))
360 		clk_enable(tu->ick);
361 
362 	/*
363 	 * Set initial state, so that we generate kevents only on state changes.
364 	 */
365 	tu->vbus_state = retu_read(rdev, TAHVO_REG_IDSR) & TAHVO_STAT_VBUS;
366 
367 	tu->extcon.name = DRIVER_NAME;
368 	tu->extcon.supported_cable = tahvo_cable;
369 	tu->extcon.dev.parent = &pdev->dev;
370 
371 	ret = extcon_dev_register(&tu->extcon);
372 	if (ret) {
373 		dev_err(&pdev->dev, "could not register extcon device: %d\n",
374 			ret);
375 		goto err_disable_clk;
376 	}
377 
378 	/* Set the initial cable state. */
379 	extcon_set_cable_state(&tu->extcon, "USB-HOST",
380 			       tu->tahvo_mode == TAHVO_MODE_HOST);
381 	extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state);
382 
383 	/* Create OTG interface */
384 	tahvo_usb_power_off(tu);
385 	tu->phy.dev = &pdev->dev;
386 	tu->phy.otg->state = OTG_STATE_UNDEFINED;
387 	tu->phy.label = DRIVER_NAME;
388 	tu->phy.set_suspend = tahvo_usb_set_suspend;
389 
390 	tu->phy.otg->usb_phy = &tu->phy;
391 	tu->phy.otg->set_host = tahvo_usb_set_host;
392 	tu->phy.otg->set_peripheral = tahvo_usb_set_peripheral;
393 
394 	ret = usb_add_phy(&tu->phy, USB_PHY_TYPE_USB2);
395 	if (ret < 0) {
396 		dev_err(&pdev->dev, "cannot register USB transceiver: %d\n",
397 			ret);
398 		goto err_extcon_unreg;
399 	}
400 
401 	dev_set_drvdata(&pdev->dev, tu);
402 
403 	tu->irq = platform_get_irq(pdev, 0);
404 	ret = request_threaded_irq(tu->irq, NULL, tahvo_usb_vbus_interrupt, 0,
405 				   "tahvo-vbus", tu);
406 	if (ret) {
407 		dev_err(&pdev->dev, "could not register tahvo-vbus irq: %d\n",
408 			ret);
409 		goto err_remove_phy;
410 	}
411 
412 	/* Attributes */
413 	ret = sysfs_create_group(&pdev->dev.kobj, &tahvo_attr_group);
414 	if (ret) {
415 		dev_err(&pdev->dev, "cannot create sysfs group: %d\n", ret);
416 		goto err_free_irq;
417 	}
418 
419 	return 0;
420 
421 err_free_irq:
422 	free_irq(tu->irq, tu);
423 err_remove_phy:
424 	usb_remove_phy(&tu->phy);
425 err_extcon_unreg:
426 	extcon_dev_unregister(&tu->extcon);
427 err_disable_clk:
428 	if (!IS_ERR(tu->ick))
429 		clk_disable(tu->ick);
430 
431 	return ret;
432 }
433 
434 static int tahvo_usb_remove(struct platform_device *pdev)
435 {
436 	struct tahvo_usb *tu = platform_get_drvdata(pdev);
437 
438 	sysfs_remove_group(&pdev->dev.kobj, &tahvo_attr_group);
439 	free_irq(tu->irq, tu);
440 	usb_remove_phy(&tu->phy);
441 	extcon_dev_unregister(&tu->extcon);
442 	if (!IS_ERR(tu->ick))
443 		clk_disable(tu->ick);
444 
445 	return 0;
446 }
447 
448 static struct platform_driver tahvo_usb_driver = {
449 	.probe		= tahvo_usb_probe,
450 	.remove		= tahvo_usb_remove,
451 	.driver		= {
452 		.name	= "tahvo-usb",
453 	},
454 };
455 module_platform_driver(tahvo_usb_driver);
456 
457 MODULE_DESCRIPTION("Tahvo USB transceiver driver");
458 MODULE_LICENSE("GPL");
459 MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs");
460 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
461