aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-at91.c
diff options
context:
space:
mode:
authorManjunath Goudar <manjunath.goudar@linaro.org>2013-09-21 07:08:42 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-26 14:35:02 -0400
commite3825b48e2cc8014b3088f8bff1c5f35652f298d (patch)
treec0519457e480d2e27f06ad9d1d3b7f084a4a4a3a /drivers/usb/host/ohci-at91.c
parent1cc6ac59ffaa164c12003c5c3ce9590b0cba3b50 (diff)
USB: OHCI: make ohci-at91 a separate driver
Separate the TI OHCI Atmel host controller driver from ohci-hcd host code so that it can be built as a separate driver module. This work is part of enabling multi-platform kernels on ARM. Signed-off-by: Manjunath Goudar <manjunath.goudar@linaro.org> Signed-off-by: Deepak Saxena <dsaxena@linaro.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> Cc: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ohci-at91.c')
-rw-r--r--drivers/usb/host/ohci-at91.c156
1 files changed, 70 insertions, 86 deletions
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index caa3764a3407..476b5a5baf25 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -13,19 +13,24 @@
13 */ 13 */
14 14
15#include <linux/clk.h> 15#include <linux/clk.h>
16#include <linux/platform_device.h> 16#include <linux/dma-mapping.h>
17#include <linux/of_platform.h> 17#include <linux/of_platform.h>
18#include <linux/of_gpio.h> 18#include <linux/of_gpio.h>
19#include <linux/platform_device.h>
19#include <linux/platform_data/atmel.h> 20#include <linux/platform_data/atmel.h>
21#include <linux/io.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/usb.h>
25#include <linux/usb/hcd.h>
20 26
21#include <mach/hardware.h> 27#include <mach/hardware.h>
22#include <asm/gpio.h> 28#include <asm/gpio.h>
23 29
24#include <mach/cpu.h> 30#include <mach/cpu.h>
25 31
26#ifndef CONFIG_ARCH_AT91 32
27#error "CONFIG_ARCH_AT91 must be defined." 33#include "ohci.h"
28#endif
29 34
30#define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) 35#define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS)
31#define at91_for_each_port(index) \ 36#define at91_for_each_port(index) \
@@ -33,7 +38,17 @@
33 38
34/* interface, function and usb clocks; sometimes also an AHB clock */ 39/* interface, function and usb clocks; sometimes also an AHB clock */
35static struct clk *iclk, *fclk, *uclk, *hclk; 40static struct clk *iclk, *fclk, *uclk, *hclk;
41/* interface and function clocks; sometimes also an AHB clock */
42
43#define DRIVER_DESC "OHCI Atmel driver"
44
45static const char hcd_name[] = "ohci-atmel";
46
47static struct hc_driver __read_mostly ohci_at91_hc_driver;
36static int clocked; 48static int clocked;
49static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq,
50 u16 wValue, u16 wIndex, char *buf, u16 wLength);
51static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf);
37 52
38extern int usb_disabled(void); 53extern int usb_disabled(void);
39 54
@@ -117,6 +132,8 @@ static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
117static int usb_hcd_at91_probe(const struct hc_driver *driver, 132static int usb_hcd_at91_probe(const struct hc_driver *driver,
118 struct platform_device *pdev) 133 struct platform_device *pdev)
119{ 134{
135 struct at91_usbh_data *board;
136 struct ohci_hcd *ohci;
120 int retval; 137 int retval;
121 struct usb_hcd *hcd = NULL; 138 struct usb_hcd *hcd = NULL;
122 139
@@ -177,8 +194,10 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
177 } 194 }
178 } 195 }
179 196
197 board = hcd->self.controller->platform_data;
198 ohci = hcd_to_ohci(hcd);
199 ohci->num_ports = board->ports;
180 at91_start_hc(pdev); 200 at91_start_hc(pdev);
181 ohci_hcd_init(hcd_to_ohci(hcd));
182 201
183 retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); 202 retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
184 if (retval == 0) 203 if (retval == 0)
@@ -238,36 +257,6 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd,
238} 257}
239 258
240/*-------------------------------------------------------------------------*/ 259/*-------------------------------------------------------------------------*/
241
242static int
243ohci_at91_reset (struct usb_hcd *hcd)
244{
245 struct at91_usbh_data *board = dev_get_platdata(hcd->self.controller);
246 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
247 int ret;
248
249 if ((ret = ohci_init(ohci)) < 0)
250 return ret;
251
252 ohci->num_ports = board->ports;
253 return 0;
254}
255
256static int
257ohci_at91_start (struct usb_hcd *hcd)
258{
259 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
260 int ret;
261
262 if ((ret = ohci_run(ohci)) < 0) {
263 dev_err(hcd->self.controller, "can't start %s\n",
264 hcd->self.bus_name);
265 ohci_stop(hcd);
266 return ret;
267 }
268 return 0;
269}
270
271static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) 260static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable)
272{ 261{
273 if (!valid_port(port)) 262 if (!valid_port(port))
@@ -297,8 +286,8 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
297 */ 286 */
298static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) 287static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
299{ 288{
300 struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); 289 struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
301 int length = ohci_hub_status_data(hcd, buf); 290 int length = orig_ohci_hub_status_data(hcd, buf);
302 int port; 291 int port;
303 292
304 at91_for_each_port(port) { 293 at91_for_each_port(port) {
@@ -376,7 +365,8 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
376 break; 365 break;
377 } 366 }
378 367
379 ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength); 368 ret = orig_ohci_hub_control(hcd, typeReq, wValue, wIndex + 1,
369 buf, wLength);
380 if (ret) 370 if (ret)
381 goto out; 371 goto out;
382 372
@@ -430,51 +420,6 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
430 420
431/*-------------------------------------------------------------------------*/ 421/*-------------------------------------------------------------------------*/
432 422
433static const struct hc_driver ohci_at91_hc_driver = {
434 .description = hcd_name,
435 .product_desc = "AT91 OHCI",
436 .hcd_priv_size = sizeof(struct ohci_hcd),
437
438 /*
439 * generic hardware linkage
440 */
441 .irq = ohci_irq,
442 .flags = HCD_USB11 | HCD_MEMORY,
443
444 /*
445 * basic lifecycle operations
446 */
447 .reset = ohci_at91_reset,
448 .start = ohci_at91_start,
449 .stop = ohci_stop,
450 .shutdown = ohci_shutdown,
451
452 /*
453 * managing i/o requests and associated device resources
454 */
455 .urb_enqueue = ohci_urb_enqueue,
456 .urb_dequeue = ohci_urb_dequeue,
457 .endpoint_disable = ohci_endpoint_disable,
458
459 /*
460 * scheduling support
461 */
462 .get_frame_number = ohci_get_frame,
463
464 /*
465 * root hub support
466 */
467 .hub_status_data = ohci_at91_hub_status_data,
468 .hub_control = ohci_at91_hub_control,
469#ifdef CONFIG_PM
470 .bus_suspend = ohci_bus_suspend,
471 .bus_resume = ohci_bus_resume,
472#endif
473 .start_port_reset = ohci_start_port_reset,
474};
475
476/*-------------------------------------------------------------------------*/
477
478static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) 423static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
479{ 424{
480 struct platform_device *pdev = data; 425 struct platform_device *pdev = data;
@@ -703,7 +648,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
703 * REVISIT: some boards will be able to turn VBUS off... 648 * REVISIT: some boards will be able to turn VBUS off...
704 */ 649 */
705 if (at91_suspend_entering_slow_clock()) { 650 if (at91_suspend_entering_slow_clock()) {
706 ohci_usb_reset (ohci); 651 ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
652 ohci->hc_control &= OHCI_CTRL_RWC;
653 ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
654 ohci->rh_state = OHCI_RH_HALTED;
655
707 /* flush the writes */ 656 /* flush the writes */
708 (void) ohci_readl (ohci, &ohci->regs->control); 657 (void) ohci_readl (ohci, &ohci->regs->control);
709 at91_stop_clock(); 658 at91_stop_clock();
@@ -730,8 +679,6 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
730#define ohci_hcd_at91_drv_resume NULL 679#define ohci_hcd_at91_drv_resume NULL
731#endif 680#endif
732 681
733MODULE_ALIAS("platform:at91_ohci");
734
735static struct platform_driver ohci_hcd_at91_driver = { 682static struct platform_driver ohci_hcd_at91_driver = {
736 .probe = ohci_hcd_at91_drv_probe, 683 .probe = ohci_hcd_at91_drv_probe,
737 .remove = ohci_hcd_at91_drv_remove, 684 .remove = ohci_hcd_at91_drv_remove,
@@ -744,3 +691,40 @@ static struct platform_driver ohci_hcd_at91_driver = {
744 .of_match_table = of_match_ptr(at91_ohci_dt_ids), 691 .of_match_table = of_match_ptr(at91_ohci_dt_ids),
745 }, 692 },
746}; 693};
694
695static int __init ohci_at91_init(void)
696{
697 if (usb_disabled())
698 return -ENODEV;
699
700 pr_info("%s: " DRIVER_DESC "\n", hcd_name);
701 ohci_init_driver(&ohci_at91_hc_driver, NULL);
702
703 /*
704 * The Atmel HW has some unusual quirks, which require Atmel-specific
705 * workarounds. We override certain hc_driver functions here to
706 * achieve that. We explicitly do not enhance ohci_driver_overrides to
707 * allow this more easily, since this is an unusual case, and we don't
708 * want to encourage others to override these functions by making it
709 * too easy.
710 */
711
712 orig_ohci_hub_control = ohci_at91_hc_driver.hub_control;
713 orig_ohci_hub_status_data = ohci_at91_hc_driver.hub_status_data;
714
715 ohci_at91_hc_driver.hub_status_data = ohci_at91_hub_status_data;
716 ohci_at91_hc_driver.hub_control = ohci_at91_hub_control;
717
718 return platform_driver_register(&ohci_hcd_at91_driver);
719}
720module_init(ohci_at91_init);
721
722static void __exit ohci_at91_cleanup(void)
723{
724 platform_driver_unregister(&ohci_hcd_at91_driver);
725}
726module_exit(ohci_at91_cleanup);
727
728MODULE_DESCRIPTION(DRIVER_DESC);
729MODULE_LICENSE("GPL");
730MODULE_ALIAS("platform:at91_ohci");