diff options
| -rw-r--r-- | drivers/usb/host/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 5 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-platform.c | 194 | ||||
| -rw-r--r-- | include/linux/usb/ohci_pdriver.h | 38 |
4 files changed, 247 insertions, 0 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b17995829514..1dd6e13077a4 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
| @@ -397,6 +397,16 @@ config USB_CNS3XXX_OHCI | |||
| 397 | Enable support for the CNS3XXX SOC's on-chip OHCI controller. | 397 | Enable support for the CNS3XXX SOC's on-chip OHCI controller. |
| 398 | It is needed for low-speed USB 1.0 device support. | 398 | It is needed for low-speed USB 1.0 device support. |
| 399 | 399 | ||
| 400 | config USB_OHCI_HCD_PLATFORM | ||
| 401 | bool "Generic OHCI driver for a platform device" | ||
| 402 | depends on USB_OHCI_HCD && EXPERIMENTAL | ||
| 403 | default n | ||
| 404 | ---help--- | ||
| 405 | Adds an OHCI host driver for a generic platform device, which | ||
| 406 | provieds a memory space and an irq. | ||
| 407 | |||
| 408 | If unsure, say N. | ||
| 409 | |||
| 400 | config USB_OHCI_BIG_ENDIAN_DESC | 410 | config USB_OHCI_BIG_ENDIAN_DESC |
| 401 | bool | 411 | bool |
| 402 | depends on USB_OHCI_HCD | 412 | depends on USB_OHCI_HCD |
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c1c550f2a517..ddd54c70d0fd 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
| @@ -1121,6 +1121,11 @@ MODULE_LICENSE ("GPL"); | |||
| 1121 | #define PLATFORM_DRIVER ohci_xls_driver | 1121 | #define PLATFORM_DRIVER ohci_xls_driver |
| 1122 | #endif | 1122 | #endif |
| 1123 | 1123 | ||
| 1124 | #ifdef CONFIG_USB_OHCI_HCD_PLATFORM | ||
| 1125 | #include "ohci-platform.c" | ||
| 1126 | #define PLATFORM_DRIVER ohci_platform_driver | ||
| 1127 | #endif | ||
| 1128 | |||
| 1124 | #if !defined(PCI_DRIVER) && \ | 1129 | #if !defined(PCI_DRIVER) && \ |
| 1125 | !defined(PLATFORM_DRIVER) && \ | 1130 | !defined(PLATFORM_DRIVER) && \ |
| 1126 | !defined(OMAP1_PLATFORM_DRIVER) && \ | 1131 | !defined(OMAP1_PLATFORM_DRIVER) && \ |
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c new file mode 100644 index 000000000000..ec5c6791c8b4 --- /dev/null +++ b/drivers/usb/host/ohci-platform.c | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | /* | ||
| 2 | * Generic platform ohci driver | ||
| 3 | * | ||
| 4 | * Copyright 2007 Michael Buesch <m@bues.ch> | ||
| 5 | * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de> | ||
| 6 | * | ||
| 7 | * Derived from the OCHI-SSB driver | ||
| 8 | * Derived from the OHCI-PCI driver | ||
| 9 | * Copyright 1999 Roman Weissgaerber | ||
| 10 | * Copyright 2000-2002 David Brownell | ||
| 11 | * Copyright 1999 Linus Torvalds | ||
| 12 | * Copyright 1999 Gregory P. Smith | ||
| 13 | * | ||
| 14 | * Licensed under the GNU/GPL. See COPYING for details. | ||
| 15 | */ | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/usb/ohci_pdriver.h> | ||
| 18 | |||
| 19 | static int ohci_platform_reset(struct usb_hcd *hcd) | ||
| 20 | { | ||
| 21 | struct platform_device *pdev = to_platform_device(hcd->self.controller); | ||
| 22 | struct usb_ohci_pdata *pdata = pdev->dev.platform_data; | ||
| 23 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
| 24 | int err; | ||
| 25 | |||
| 26 | if (pdata->big_endian_desc) | ||
| 27 | ohci->flags |= OHCI_QUIRK_BE_DESC; | ||
| 28 | if (pdata->big_endian_mmio) | ||
| 29 | ohci->flags |= OHCI_QUIRK_BE_MMIO; | ||
| 30 | if (pdata->no_big_frame_no) | ||
| 31 | ohci->flags |= OHCI_QUIRK_FRAME_NO; | ||
| 32 | |||
| 33 | ohci_hcd_init(ohci); | ||
| 34 | err = ohci_init(ohci); | ||
| 35 | |||
| 36 | return err; | ||
| 37 | } | ||
| 38 | |||
| 39 | static int ohci_platform_start(struct usb_hcd *hcd) | ||
| 40 | { | ||
| 41 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
| 42 | int err; | ||
| 43 | |||
| 44 | err = ohci_run(ohci); | ||
| 45 | if (err < 0) { | ||
| 46 | ohci_err(ohci, "can't start\n"); | ||
| 47 | ohci_stop(hcd); | ||
| 48 | } | ||
| 49 | |||
| 50 | return err; | ||
| 51 | } | ||
| 52 | |||
| 53 | static const struct hc_driver ohci_platform_hc_driver = { | ||
| 54 | .description = hcd_name, | ||
| 55 | .product_desc = "Generic Platform OHCI Controller", | ||
| 56 | .hcd_priv_size = sizeof(struct ohci_hcd), | ||
| 57 | |||
| 58 | .irq = ohci_irq, | ||
| 59 | .flags = HCD_MEMORY | HCD_USB11, | ||
| 60 | |||
| 61 | .reset = ohci_platform_reset, | ||
| 62 | .start = ohci_platform_start, | ||
| 63 | .stop = ohci_stop, | ||
| 64 | .shutdown = ohci_shutdown, | ||
| 65 | |||
| 66 | .urb_enqueue = ohci_urb_enqueue, | ||
| 67 | .urb_dequeue = ohci_urb_dequeue, | ||
| 68 | .endpoint_disable = ohci_endpoint_disable, | ||
| 69 | |||
| 70 | .get_frame_number = ohci_get_frame, | ||
| 71 | |||
| 72 | .hub_status_data = ohci_hub_status_data, | ||
| 73 | .hub_control = ohci_hub_control, | ||
| 74 | #ifdef CONFIG_PM | ||
| 75 | .bus_suspend = ohci_bus_suspend, | ||
| 76 | .bus_resume = ohci_bus_resume, | ||
| 77 | #endif | ||
| 78 | |||
| 79 | .start_port_reset = ohci_start_port_reset, | ||
| 80 | }; | ||
| 81 | |||
| 82 | static int __devinit ohci_platform_probe(struct platform_device *dev) | ||
| 83 | { | ||
| 84 | struct usb_hcd *hcd; | ||
| 85 | struct resource *res_mem; | ||
| 86 | int irq; | ||
| 87 | int err = -ENOMEM; | ||
| 88 | |||
| 89 | BUG_ON(!dev->dev.platform_data); | ||
| 90 | |||
| 91 | if (usb_disabled()) | ||
| 92 | return -ENODEV; | ||
| 93 | |||
| 94 | irq = platform_get_irq(dev, 0); | ||
| 95 | if (irq < 0) { | ||
| 96 | pr_err("no irq provieded"); | ||
| 97 | return irq; | ||
| 98 | } | ||
| 99 | |||
| 100 | res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
| 101 | if (!res_mem) { | ||
| 102 | pr_err("no memory recourse provieded"); | ||
| 103 | return -ENXIO; | ||
| 104 | } | ||
| 105 | |||
| 106 | hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev, | ||
| 107 | dev_name(&dev->dev)); | ||
| 108 | if (!hcd) | ||
| 109 | return -ENOMEM; | ||
| 110 | |||
| 111 | hcd->rsrc_start = res_mem->start; | ||
| 112 | hcd->rsrc_len = resource_size(res_mem); | ||
| 113 | |||
| 114 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | ||
| 115 | pr_err("controller already in use"); | ||
| 116 | err = -EBUSY; | ||
| 117 | goto err_put_hcd; | ||
| 118 | } | ||
| 119 | |||
| 120 | hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); | ||
| 121 | if (!hcd->regs) | ||
| 122 | goto err_release_region; | ||
| 123 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); | ||
| 124 | if (err) | ||
| 125 | goto err_iounmap; | ||
| 126 | |||
| 127 | platform_set_drvdata(dev, hcd); | ||
| 128 | |||
| 129 | return err; | ||
| 130 | |||
| 131 | err_iounmap: | ||
| 132 | iounmap(hcd->regs); | ||
| 133 | err_release_region: | ||
| 134 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
| 135 | err_put_hcd: | ||
| 136 | usb_put_hcd(hcd); | ||
| 137 | return err; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int __devexit ohci_platform_remove(struct platform_device *dev) | ||
| 141 | { | ||
| 142 | struct usb_hcd *hcd = platform_get_drvdata(dev); | ||
| 143 | |||
| 144 | usb_remove_hcd(hcd); | ||
| 145 | iounmap(hcd->regs); | ||
| 146 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
| 147 | usb_put_hcd(hcd); | ||
| 148 | platform_set_drvdata(dev, NULL); | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | #ifdef CONFIG_PM | ||
| 154 | |||
| 155 | static int ohci_platform_suspend(struct device *dev) | ||
| 156 | { | ||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
