Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * ohci-omap3.c - driver for OHCI on OMAP3 and later processors
  3 *
  4 * Bus Glue for OMAP3 USBHOST 3 port OHCI controller
  5 * This controller is also used in later OMAPs and AM35x chips
  6 *
  7 * Copyright (C) 2007-2010 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 * Based on ehci-omap.c and some other ohci glue layers
 13 *
 14 * This program is free software; you can redistribute it and/or modify
 15 * it under the terms of the GNU General Public License as published by
 16 * the Free Software Foundation; either version 2 of the License, or
 17 * (at your option) any later version.
 18 *
 19 * This program is distributed in the hope that it will be useful,
 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 22 * GNU General Public License for more details.
 23 *
 24 * You should have received a copy of the GNU General Public License
 25 * along with this program; if not, write to the Free Software
 26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 27 *
 28 * TODO (last updated Feb 27, 2011):
 29 *	- add kernel-doc
 30 */
 31
 32#include <linux/platform_device.h>
 33#include <plat/usb.h>
 34
 35/*-------------------------------------------------------------------------*/
 36
 37static int ohci_omap3_init(struct usb_hcd *hcd)
 38{
 39	dev_dbg(hcd->self.controller, "starting OHCI controller\n");
 40
 41	return ohci_init(hcd_to_ohci(hcd));
 42}
 43
 44/*-------------------------------------------------------------------------*/
 45
 46static int ohci_omap3_start(struct usb_hcd *hcd)
 47{
 48	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
 49	int ret;
 50
 51	/*
 52	 * RemoteWakeupConnected has to be set explicitly before
 53	 * calling ohci_run. The reset value of RWC is 0.
 54	 */
 55	ohci->hc_control = OHCI_CTRL_RWC;
 56	writel(OHCI_CTRL_RWC, &ohci->regs->control);
 57
 58	ret = ohci_run(ohci);
 59
 60	if (ret < 0) {
 61		dev_err(hcd->self.controller, "can't start\n");
 62		ohci_stop(hcd);
 63	}
 64
 65	return ret;
 66}
 67
 68/*-------------------------------------------------------------------------*/
 69
 70static const struct hc_driver ohci_omap3_hc_driver = {
 71	.description =		hcd_name,
 72	.product_desc =		"OMAP3 OHCI Host Controller",
 73	.hcd_priv_size =	sizeof(struct ohci_hcd),
 74
 75	/*
 76	 * generic hardware linkage
 77	 */
 78	.irq =			ohci_irq,
 79	.flags =		HCD_USB11 | HCD_MEMORY,
 80
 81	/*
 82	 * basic lifecycle operations
 83	 */
 84	.reset =		ohci_omap3_init,
 85	.start =		ohci_omap3_start,
 86	.stop =			ohci_stop,
 87	.shutdown =		ohci_shutdown,
 88
 89	/*
 90	 * managing i/o requests and associated device resources
 91	 */
 92	.urb_enqueue =		ohci_urb_enqueue,
 93	.urb_dequeue =		ohci_urb_dequeue,
 94	.endpoint_disable =	ohci_endpoint_disable,
 95
 96	/*
 97	 * scheduling support
 98	 */
 99	.get_frame_number =	ohci_get_frame,
100
101	/*
102	 * root hub support
103	 */
104	.hub_status_data =	ohci_hub_status_data,
105	.hub_control =		ohci_hub_control,
106#ifdef	CONFIG_PM
107	.bus_suspend =		ohci_bus_suspend,
108	.bus_resume =		ohci_bus_resume,
109#endif
110	.start_port_reset =	ohci_start_port_reset,
111};
112
113/*-------------------------------------------------------------------------*/
114
115/*
116 * configure so an HC device and id are always provided
117 * always called with process context; sleeping is OK
118 */
119
120/**
121 * ohci_hcd_omap3_probe - initialize OMAP-based HCDs
122 *
123 * Allocates basic resources for this USB host controller, and
124 * then invokes the start() method for the HCD associated with it
125 * through the hotplug entry's driver_data.
126 */
127static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
128{
129	struct device		*dev = &pdev->dev;
130	struct usb_hcd		*hcd = NULL;
131	void __iomem		*regs = NULL;
132	struct resource		*res;
133	int			ret = -ENODEV;
134	int			irq;
135
136	if (usb_disabled())
137		goto err_end;
138
139	if (!dev->parent) {
140		dev_err(dev, "Missing parent device\n");
141		return -ENODEV;
142	}
143
144	irq = platform_get_irq_byname(pdev, "ohci-irq");
145	if (irq < 0) {
146		dev_err(dev, "OHCI irq failed\n");
147		return -ENODEV;
148	}
149
150	res = platform_get_resource_byname(pdev,
151				IORESOURCE_MEM, "ohci");
152	if (!ret) {
153		dev_err(dev, "UHH OHCI get resource failed\n");
154		return -ENOMEM;
155	}
156
157	regs = ioremap(res->start, resource_size(res));
158	if (!regs) {
159		dev_err(dev, "UHH OHCI ioremap failed\n");
160		return -ENOMEM;
161	}
162
163
164	hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,
165			dev_name(dev));
166	if (!hcd) {
167		dev_err(dev, "usb_create_hcd failed\n");
168		goto err_io;
169	}
170
171	hcd->rsrc_start = res->start;
172	hcd->rsrc_len = resource_size(res);
173	hcd->regs =  regs;
174
175	ret = omap_usbhs_enable(dev);
176	if (ret) {
177		dev_dbg(dev, "failed to start ohci\n");
178		goto err_end;
179	}
180
181	ohci_hcd_init(hcd_to_ohci(hcd));
182
183	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
184	if (ret) {
185		dev_dbg(dev, "failed to add hcd with err %d\n", ret);
186		goto err_add_hcd;
187	}
188
189	return 0;
190
191err_add_hcd:
192	omap_usbhs_disable(dev);
193
194err_end:
195	usb_put_hcd(hcd);
196
197err_io:
198	iounmap(regs);
199
200	return ret;
201}
202
203/*
204 * may be called without controller electrically present
205 * may be called with controller, bus, and devices active
206 */
207
208/**
209 * ohci_hcd_omap3_remove - shutdown processing for OHCI HCDs
210 * @pdev: USB Host Controller being removed
211 *
212 * Reverses the effect of ohci_hcd_omap3_probe(), first invoking
213 * the HCD's stop() method.  It is always called from a thread
214 * context, normally "rmmod", "apmd", or something similar.
215 */
216static int __devexit ohci_hcd_omap3_remove(struct platform_device *pdev)
217{
218	struct device *dev	= &pdev->dev;
219	struct usb_hcd *hcd	= dev_get_drvdata(dev);
220
221	iounmap(hcd->regs);
222	usb_remove_hcd(hcd);
223	omap_usbhs_disable(dev);
224	usb_put_hcd(hcd);
225
226	return 0;
227}
228
229static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
230{
231	struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
232
233	if (hcd->driver->shutdown)
234		hcd->driver->shutdown(hcd);
235}
236
237static struct platform_driver ohci_hcd_omap3_driver = {
238	.probe		= ohci_hcd_omap3_probe,
239	.remove		= __devexit_p(ohci_hcd_omap3_remove),
240	.shutdown	= ohci_hcd_omap3_shutdown,
241	.driver		= {
242		.name	= "ohci-omap3",
243	},
244};
245
246MODULE_ALIAS("platform:ohci-omap3");
247MODULE_AUTHOR("Anand Gadiyar <gadiyar@ti.com>");