Linux Audio

Check our new training course

Embedded Linux training

Mar 31-Apr 8, 2025
Register
Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Generic platform ehci driver
  3 *
  4 * Copyright 2007 Steven Brown <sbrown@cortland.com>
  5 * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
  6 *
  7 * Derived from the ohci-ssb driver
  8 * Copyright 2007 Michael Buesch <m@bues.ch>
  9 *
 10 * Derived from the EHCI-PCI driver
 11 * Copyright (c) 2000-2004 by David Brownell
 12 *
 13 * Derived from the ohci-pci driver
 14 * Copyright 1999 Roman Weissgaerber
 15 * Copyright 2000-2002 David Brownell
 16 * Copyright 1999 Linus Torvalds
 17 * Copyright 1999 Gregory P. Smith
 18 *
 19 * Licensed under the GNU/GPL. See COPYING for details.
 20 */
 21#include <linux/platform_device.h>
 22#include <linux/usb/ehci_pdriver.h>
 23
 24static int ehci_platform_reset(struct usb_hcd *hcd)
 25{
 26	struct platform_device *pdev = to_platform_device(hcd->self.controller);
 27	struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
 28	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 29	int retval;
 30
 31	hcd->has_tt = pdata->has_tt;
 32	ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
 33	ehci->big_endian_desc = pdata->big_endian_desc;
 34	ehci->big_endian_mmio = pdata->big_endian_mmio;
 35
 36	ehci->caps = hcd->regs + pdata->caps_offset;
 37	retval = ehci_setup(hcd);
 38	if (retval)
 39		return retval;
 40
 41	if (pdata->port_power_on)
 42		ehci_port_power(ehci, 1);
 43	if (pdata->port_power_off)
 44		ehci_port_power(ehci, 0);
 45
 46	return 0;
 47}
 48
 49static const struct hc_driver ehci_platform_hc_driver = {
 50	.description		= hcd_name,
 51	.product_desc		= "Generic Platform EHCI Controller",
 52	.hcd_priv_size		= sizeof(struct ehci_hcd),
 53
 54	.irq			= ehci_irq,
 55	.flags			= HCD_MEMORY | HCD_USB2,
 56
 57	.reset			= ehci_platform_reset,
 58	.start			= ehci_run,
 59	.stop			= ehci_stop,
 60	.shutdown		= ehci_shutdown,
 61
 62	.urb_enqueue		= ehci_urb_enqueue,
 63	.urb_dequeue		= ehci_urb_dequeue,
 64	.endpoint_disable	= ehci_endpoint_disable,
 65	.endpoint_reset		= ehci_endpoint_reset,
 66
 67	.get_frame_number	= ehci_get_frame,
 68
 69	.hub_status_data	= ehci_hub_status_data,
 70	.hub_control		= ehci_hub_control,
 71#if defined(CONFIG_PM)
 72	.bus_suspend		= ehci_bus_suspend,
 73	.bus_resume		= ehci_bus_resume,
 74#endif
 75	.relinquish_port	= ehci_relinquish_port,
 76	.port_handed_over	= ehci_port_handed_over,
 77
 78	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
 79};
 80
 81static int __devinit ehci_platform_probe(struct platform_device *dev)
 82{
 83	struct usb_hcd *hcd;
 84	struct resource *res_mem;
 85	int irq;
 86	int err = -ENOMEM;
 87
 88	BUG_ON(!dev->dev.platform_data);
 89
 90	if (usb_disabled())
 91		return -ENODEV;
 92
 93	irq = platform_get_irq(dev, 0);
 94	if (irq < 0) {
 95		pr_err("no irq provided");
 96		return irq;
 97	}
 98	res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
 99	if (!res_mem) {
100		pr_err("no memory recourse provided");
101		return -ENXIO;
102	}
103
104	hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
105			     dev_name(&dev->dev));
106	if (!hcd)
107		return -ENOMEM;
108
109	hcd->rsrc_start = res_mem->start;
110	hcd->rsrc_len = resource_size(res_mem);
111
112	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
113		pr_err("controller already in use");
114		err = -EBUSY;
115		goto err_put_hcd;
116	}
117
118	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
119	if (!hcd->regs)
120		goto err_release_region;
121	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
122	if (err)
123		goto err_iounmap;
124
125	platform_set_drvdata(dev, hcd);
126
127	return err;
128
129err_iounmap:
130	iounmap(hcd->regs);
131err_release_region:
132	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
133err_put_hcd:
134	usb_put_hcd(hcd);
135	return err;
136}
137
138static int __devexit ehci_platform_remove(struct platform_device *dev)
139{
140	struct usb_hcd *hcd = platform_get_drvdata(dev);
141
142	usb_remove_hcd(hcd);
143	iounmap(hcd->regs);
144	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
145	usb_put_hcd(hcd);
146	platform_set_drvdata(dev, NULL);
147
148	return 0;
149}
150
151#ifdef CONFIG_PM
152
153static int ehci_platform_suspend(struct device *dev)
154{
155	struct usb_hcd *hcd = dev_get_drvdata(dev);
156	bool wakeup = device_may_wakeup(dev);
157
158	ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
159	return 0;
160}
161
162static int ehci_platform_resume(struct device *dev)
163{
164	struct usb_hcd *hcd = dev_get_drvdata(dev);
165
166	ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
167	return 0;
168}
169
170#else /* !CONFIG_PM */
171#define ehci_platform_suspend	NULL
172#define ehci_platform_resume	NULL
173#endif /* CONFIG_PM */
174
175static const struct platform_device_id ehci_platform_table[] = {
176	{ "ehci-platform", 0 },
177	{ }
178};
179MODULE_DEVICE_TABLE(platform, ehci_platform_table);
180
181static const struct dev_pm_ops ehci_platform_pm_ops = {
182	.suspend	= ehci_platform_suspend,
183	.resume		= ehci_platform_resume,
184};
185
186static struct platform_driver ehci_platform_driver = {
187	.id_table	= ehci_platform_table,
188	.probe		= ehci_platform_probe,
189	.remove		= __devexit_p(ehci_platform_remove),
190	.shutdown	= usb_hcd_platform_shutdown,
191	.driver		= {
192		.owner	= THIS_MODULE,
193		.name	= "ehci-platform",
194		.pm	= &ehci_platform_pm_ops,
195	}
196};