Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: Add support for VIA VT8500 and compatibles in EHCI HCD

VIA and WonderMedia Systems-on-Chip feature a standard EHCI host
controller. This adds necessary glue to use the standard driver
with these systems.

Signed-off-by: Alexey Charkov <alchark@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Alexey Charkov and committed by
Greg Kroah-Hartman
ad78acaf 8be8a9d3

+178
+1
drivers/usb/Kconfig
··· 66 66 default y if ARCH_AT91SAM9G45 67 67 default y if ARCH_MXC 68 68 default y if ARCH_OMAP3 69 + default y if ARCH_VT8500 69 70 default PCI 70 71 71 72 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
+5
drivers/usb/host/ehci-hcd.c
··· 1216 1216 #define PLATFORM_DRIVER ehci_octeon_driver 1217 1217 #endif 1218 1218 1219 + #ifdef CONFIG_ARCH_VT8500 1220 + #include "ehci-vt8500.c" 1221 + #define PLATFORM_DRIVER vt8500_ehci_driver 1222 + #endif 1223 + 1219 1224 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ 1220 1225 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ 1221 1226 !defined(XILINX_OF_PLATFORM_DRIVER)
+172
drivers/usb/host/ehci-vt8500.c
··· 1 + /* 2 + * drivers/usb/host/ehci-vt8500.c 3 + * 4 + * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> 5 + * 6 + * Based on ehci-au1xxx.c 7 + * 8 + * This software is licensed under the terms of the GNU General Public 9 + * License version 2, as published by the Free Software Foundation, and 10 + * may be copied, distributed, and modified under those terms. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + */ 18 + 19 + #include <linux/platform_device.h> 20 + 21 + static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) 22 + { 23 + struct ehci_hcd *ehci = hcd_to_ehci(hcd); 24 + int rc = 0; 25 + 26 + if (!udev->parent) /* udev is root hub itself, impossible */ 27 + rc = -1; 28 + /* we only support lpm device connected to root hub yet */ 29 + if (ehci->has_lpm && !udev->parent->parent) { 30 + rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum); 31 + if (!rc) 32 + rc = ehci_lpm_check(ehci, udev->portnum); 33 + } 34 + return rc; 35 + } 36 + 37 + static const struct hc_driver vt8500_ehci_hc_driver = { 38 + .description = hcd_name, 39 + .product_desc = "VT8500 EHCI", 40 + .hcd_priv_size = sizeof(struct ehci_hcd), 41 + 42 + /* 43 + * generic hardware linkage 44 + */ 45 + .irq = ehci_irq, 46 + .flags = HCD_MEMORY | HCD_USB2, 47 + 48 + /* 49 + * basic lifecycle operations 50 + */ 51 + .reset = ehci_init, 52 + .start = ehci_run, 53 + .stop = ehci_stop, 54 + .shutdown = ehci_shutdown, 55 + 56 + /* 57 + * managing i/o requests and associated device resources 58 + */ 59 + .urb_enqueue = ehci_urb_enqueue, 60 + .urb_dequeue = ehci_urb_dequeue, 61 + .endpoint_disable = ehci_endpoint_disable, 62 + .endpoint_reset = ehci_endpoint_reset, 63 + 64 + /* 65 + * scheduling support 66 + */ 67 + .get_frame_number = ehci_get_frame, 68 + 69 + /* 70 + * root hub support 71 + */ 72 + .hub_status_data = ehci_hub_status_data, 73 + .hub_control = ehci_hub_control, 74 + .bus_suspend = ehci_bus_suspend, 75 + .bus_resume = ehci_bus_resume, 76 + .relinquish_port = ehci_relinquish_port, 77 + .port_handed_over = ehci_port_handed_over, 78 + 79 + /* 80 + * call back when device connected and addressed 81 + */ 82 + .update_device = ehci_update_device, 83 + 84 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 85 + }; 86 + 87 + static int vt8500_ehci_drv_probe(struct platform_device *pdev) 88 + { 89 + struct usb_hcd *hcd; 90 + struct ehci_hcd *ehci; 91 + struct resource *res; 92 + int ret; 93 + 94 + if (usb_disabled()) 95 + return -ENODEV; 96 + 97 + if (pdev->resource[1].flags != IORESOURCE_IRQ) { 98 + pr_debug("resource[1] is not IORESOURCE_IRQ"); 99 + return -ENOMEM; 100 + } 101 + hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500"); 102 + if (!hcd) 103 + return -ENOMEM; 104 + 105 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 106 + hcd->rsrc_start = res->start; 107 + hcd->rsrc_len = resource_size(res); 108 + 109 + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { 110 + pr_debug("request_mem_region failed"); 111 + ret = -EBUSY; 112 + goto err1; 113 + } 114 + 115 + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); 116 + if (!hcd->regs) { 117 + pr_debug("ioremap failed"); 118 + ret = -ENOMEM; 119 + goto err2; 120 + } 121 + 122 + ehci = hcd_to_ehci(hcd); 123 + ehci->caps = hcd->regs; 124 + ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase)); 125 + 126 + dbg_hcs_params(ehci, "reset"); 127 + dbg_hcc_params(ehci, "reset"); 128 + 129 + /* cache this readonly data; minimize chip reads */ 130 + ehci->hcs_params = readl(&ehci->caps->hcs_params); 131 + 132 + ehci_port_power(ehci, 1); 133 + 134 + ret = usb_add_hcd(hcd, pdev->resource[1].start, 135 + IRQF_DISABLED | IRQF_SHARED); 136 + if (ret == 0) { 137 + platform_set_drvdata(pdev, hcd); 138 + return ret; 139 + } 140 + 141 + iounmap(hcd->regs); 142 + err2: 143 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 144 + err1: 145 + usb_put_hcd(hcd); 146 + return ret; 147 + } 148 + 149 + static int vt8500_ehci_drv_remove(struct platform_device *pdev) 150 + { 151 + struct usb_hcd *hcd = platform_get_drvdata(pdev); 152 + 153 + usb_remove_hcd(hcd); 154 + iounmap(hcd->regs); 155 + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 156 + usb_put_hcd(hcd); 157 + platform_set_drvdata(pdev, NULL); 158 + 159 + return 0; 160 + } 161 + 162 + static struct platform_driver vt8500_ehci_driver = { 163 + .probe = vt8500_ehci_drv_probe, 164 + .remove = vt8500_ehci_drv_remove, 165 + .shutdown = usb_hcd_platform_shutdown, 166 + .driver = { 167 + .name = "vt8500-ehci", 168 + .owner = THIS_MODULE, 169 + } 170 + }; 171 + 172 + MODULE_ALIAS("platform:vt8500-ehci");