xref: /openbmc/linux/drivers/usb/host/ehci-omap.c (revision 95e9fd10)
1 /*
2  * ehci-omap.c - driver for USBHOST on OMAP3/4 processors
3  *
4  * Bus Glue for the EHCI controllers in OMAP3/4
5  * Tested on several OMAP3 boards, and OMAP4 Pandaboard
6  *
7  * Copyright (C) 2007-2011 Texas Instruments, Inc.
8  *	Author: Vikram Pandita <vikram.pandita@ti.com>
9  *	Author: Anand Gadiyar <gadiyar@ti.com>
10  *	Author: Keshava Munegowda <keshava_mgowda@ti.com>
11  *
12  * Copyright (C) 2009 Nokia Corporation
13  *	Contact: Felipe Balbi <felipe.balbi@nokia.com>
14  *
15  * Based on "ehci-fsl.c" and "ehci-au1xxx.c" ehci glue layers
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
30  *
31  * TODO (last updated Feb 27, 2010):
32  *	- add kernel-doc
33  *	- enable AUTOIDLE
34  *	- add suspend/resume
35  *	- add HSIC and TLL support
36  *	- convert to use hwmod and runtime PM
37  */
38 
39 #include <linux/platform_device.h>
40 #include <linux/slab.h>
41 #include <linux/usb/ulpi.h>
42 #include <plat/usb.h>
43 #include <linux/regulator/consumer.h>
44 #include <linux/pm_runtime.h>
45 #include <linux/gpio.h>
46 #include <linux/clk.h>
47 
48 /* EHCI Register Set */
49 #define EHCI_INSNREG04					(0xA0)
50 #define EHCI_INSNREG04_DISABLE_UNSUSPEND		(1 << 5)
51 #define	EHCI_INSNREG05_ULPI				(0xA4)
52 #define	EHCI_INSNREG05_ULPI_CONTROL_SHIFT		31
53 #define	EHCI_INSNREG05_ULPI_PORTSEL_SHIFT		24
54 #define	EHCI_INSNREG05_ULPI_OPSEL_SHIFT			22
55 #define	EHCI_INSNREG05_ULPI_REGADD_SHIFT		16
56 #define	EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT		8
57 #define	EHCI_INSNREG05_ULPI_WRDATA_SHIFT		0
58 
59 /*-------------------------------------------------------------------------*/
60 
61 static const struct hc_driver ehci_omap_hc_driver;
62 
63 
64 static inline void ehci_write(void __iomem *base, u32 reg, u32 val)
65 {
66 	__raw_writel(val, base + reg);
67 }
68 
69 static inline u32 ehci_read(void __iomem *base, u32 reg)
70 {
71 	return __raw_readl(base + reg);
72 }
73 
74 
75 static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
76 {
77 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
78 	unsigned reg = 0;
79 
80 	reg = ULPI_FUNC_CTRL_RESET
81 		/* FUNCTION_CTRL_SET register */
82 		| (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT)
83 		/* Write */
84 		| (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT)
85 		/* PORTn */
86 		| ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT)
87 		/* start ULPI access*/
88 		| (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT);
89 
90 	ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg);
91 
92 	/* Wait for ULPI access completion */
93 	while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI)
94 			& (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) {
95 		cpu_relax();
96 
97 		if (time_after(jiffies, timeout)) {
98 			dev_dbg(hcd->self.controller,
99 					"phy reset operation timed out\n");
100 			break;
101 		}
102 	}
103 }
104 
105 static int omap_ehci_init(struct usb_hcd *hcd)
106 {
107 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
108 	int			rc;
109 	struct ehci_hcd_omap_platform_data	*pdata;
110 
111 	pdata = hcd->self.controller->platform_data;
112 
113 	/* Hold PHYs in reset while initializing EHCI controller */
114 	if (pdata->phy_reset) {
115 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
116 			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
117 
118 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
119 			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
120 
121 		/* Hold the PHY in RESET for enough time till DIR is high */
122 		udelay(10);
123 	}
124 
125 	/* Soft reset the PHY using PHY reset command over ULPI */
126 	if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
127 		omap_ehci_soft_phy_reset(hcd, 0);
128 	if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
129 		omap_ehci_soft_phy_reset(hcd, 1);
130 
131 	/* we know this is the memory we want, no need to ioremap again */
132 	ehci->caps = hcd->regs;
133 
134 	rc = ehci_setup(hcd);
135 
136 	if (pdata->phy_reset) {
137 		/* Hold the PHY in RESET for enough time till
138 		 * PHY is settled and ready
139 		 */
140 		udelay(10);
141 
142 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
143 			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
144 
145 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
146 			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
147 	}
148 
149 	/* root ports should always stay powered */
150 	ehci_port_power(ehci, 1);
151 
152 	return rc;
153 }
154 
155 static void disable_put_regulator(
156 		struct ehci_hcd_omap_platform_data *pdata)
157 {
158 	int i;
159 
160 	for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
161 		if (pdata->regulator[i]) {
162 			regulator_disable(pdata->regulator[i]);
163 			regulator_put(pdata->regulator[i]);
164 		}
165 	}
166 }
167 
168 /* configure so an HC device and id are always provided */
169 /* always called with process context; sleeping is OK */
170 
171 /**
172  * ehci_hcd_omap_probe - initialize TI-based HCDs
173  *
174  * Allocates basic resources for this USB host controller, and
175  * then invokes the start() method for the HCD associated with it
176  * through the hotplug entry's driver_data.
177  */
178 static int ehci_hcd_omap_probe(struct platform_device *pdev)
179 {
180 	struct device				*dev = &pdev->dev;
181 	struct ehci_hcd_omap_platform_data	*pdata = dev->platform_data;
182 	struct resource				*res;
183 	struct usb_hcd				*hcd;
184 	void __iomem				*regs;
185 	int					ret = -ENODEV;
186 	int					irq;
187 	int					i;
188 	char					supply[7];
189 
190 	if (usb_disabled())
191 		return -ENODEV;
192 
193 	if (!dev->parent) {
194 		dev_err(dev, "Missing parent device\n");
195 		return -ENODEV;
196 	}
197 
198 	irq = platform_get_irq_byname(pdev, "ehci-irq");
199 	if (irq < 0) {
200 		dev_err(dev, "EHCI irq failed\n");
201 		return -ENODEV;
202 	}
203 
204 	res =  platform_get_resource_byname(pdev,
205 				IORESOURCE_MEM, "ehci");
206 	if (!res) {
207 		dev_err(dev, "UHH EHCI get resource failed\n");
208 		return -ENODEV;
209 	}
210 
211 	regs = ioremap(res->start, resource_size(res));
212 	if (!regs) {
213 		dev_err(dev, "UHH EHCI ioremap failed\n");
214 		return -ENOMEM;
215 	}
216 
217 	hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,
218 			dev_name(dev));
219 	if (!hcd) {
220 		dev_err(dev, "failed to create hcd with err %d\n", ret);
221 		ret = -ENOMEM;
222 		goto err_io;
223 	}
224 
225 	hcd->rsrc_start = res->start;
226 	hcd->rsrc_len = resource_size(res);
227 	hcd->regs = regs;
228 
229 	/* get ehci regulator and enable */
230 	for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
231 		if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
232 			pdata->regulator[i] = NULL;
233 			continue;
234 		}
235 		snprintf(supply, sizeof(supply), "hsusb%d", i);
236 		pdata->regulator[i] = regulator_get(dev, supply);
237 		if (IS_ERR(pdata->regulator[i])) {
238 			pdata->regulator[i] = NULL;
239 			dev_dbg(dev,
240 			"failed to get ehci port%d regulator\n", i);
241 		} else {
242 			regulator_enable(pdata->regulator[i]);
243 		}
244 	}
245 
246 	pm_runtime_enable(dev);
247 	pm_runtime_get_sync(dev);
248 
249 	/*
250 	 * An undocumented "feature" in the OMAP3 EHCI controller,
251 	 * causes suspended ports to be taken out of suspend when
252 	 * the USBCMD.Run/Stop bit is cleared (for example when
253 	 * we do ehci_bus_suspend).
254 	 * This breaks suspend-resume if the root-hub is allowed
255 	 * to suspend. Writing 1 to this undocumented register bit
256 	 * disables this feature and restores normal behavior.
257 	 */
258 	ehci_write(regs, EHCI_INSNREG04,
259 				EHCI_INSNREG04_DISABLE_UNSUSPEND);
260 
261 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
262 	if (ret) {
263 		dev_err(dev, "failed to add hcd with err %d\n", ret);
264 		goto err_pm_runtime;
265 	}
266 
267 
268 	return 0;
269 
270 err_pm_runtime:
271 	disable_put_regulator(pdata);
272 	pm_runtime_put_sync(dev);
273 	usb_put_hcd(hcd);
274 
275 err_io:
276 	iounmap(regs);
277 	return ret;
278 }
279 
280 
281 /**
282  * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs
283  * @pdev: USB Host Controller being removed
284  *
285  * Reverses the effect of usb_ehci_hcd_omap_probe(), first invoking
286  * the HCD's stop() method.  It is always called from a thread
287  * context, normally "rmmod", "apmd", or something similar.
288  */
289 static int ehci_hcd_omap_remove(struct platform_device *pdev)
290 {
291 	struct device *dev				= &pdev->dev;
292 	struct usb_hcd *hcd				= dev_get_drvdata(dev);
293 	struct ehci_hcd_omap_platform_data *pdata	= dev->platform_data;
294 
295 	usb_remove_hcd(hcd);
296 	disable_put_regulator(dev->platform_data);
297 	iounmap(hcd->regs);
298 	usb_put_hcd(hcd);
299 
300 	pm_runtime_put_sync(dev);
301 	pm_runtime_disable(dev);
302 
303 	if (pdata->phy_reset) {
304 		if (gpio_is_valid(pdata->reset_gpio_port[0]))
305 			gpio_free(pdata->reset_gpio_port[0]);
306 
307 		if (gpio_is_valid(pdata->reset_gpio_port[1]))
308 			gpio_free(pdata->reset_gpio_port[1]);
309 	}
310 	return 0;
311 }
312 
313 static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
314 {
315 	struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
316 
317 	if (hcd->driver->shutdown)
318 		hcd->driver->shutdown(hcd);
319 }
320 
321 static struct platform_driver ehci_hcd_omap_driver = {
322 	.probe			= ehci_hcd_omap_probe,
323 	.remove			= ehci_hcd_omap_remove,
324 	.shutdown		= ehci_hcd_omap_shutdown,
325 	/*.suspend		= ehci_hcd_omap_suspend, */
326 	/*.resume		= ehci_hcd_omap_resume, */
327 	.driver = {
328 		.name		= "ehci-omap",
329 	}
330 };
331 
332 /*-------------------------------------------------------------------------*/
333 
334 static const struct hc_driver ehci_omap_hc_driver = {
335 	.description		= hcd_name,
336 	.product_desc		= "OMAP-EHCI Host Controller",
337 	.hcd_priv_size		= sizeof(struct ehci_hcd),
338 
339 	/*
340 	 * generic hardware linkage
341 	 */
342 	.irq			= ehci_irq,
343 	.flags			= HCD_MEMORY | HCD_USB2,
344 
345 	/*
346 	 * basic lifecycle operations
347 	 */
348 	.reset			= omap_ehci_init,
349 	.start			= ehci_run,
350 	.stop			= ehci_stop,
351 	.shutdown		= ehci_shutdown,
352 
353 	/*
354 	 * managing i/o requests and associated device resources
355 	 */
356 	.urb_enqueue		= ehci_urb_enqueue,
357 	.urb_dequeue		= ehci_urb_dequeue,
358 	.endpoint_disable	= ehci_endpoint_disable,
359 	.endpoint_reset		= ehci_endpoint_reset,
360 
361 	/*
362 	 * scheduling support
363 	 */
364 	.get_frame_number	= ehci_get_frame,
365 
366 	/*
367 	 * root hub support
368 	 */
369 	.hub_status_data	= ehci_hub_status_data,
370 	.hub_control		= ehci_hub_control,
371 	.bus_suspend		= ehci_bus_suspend,
372 	.bus_resume		= ehci_bus_resume,
373 
374 	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
375 };
376 
377 MODULE_ALIAS("platform:omap-ehci");
378 MODULE_AUTHOR("Texas Instruments, Inc.");
379 MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
380 
381