1 /* 2 * xhci-plat.c - xHCI host controller driver platform Bus Glue. 3 * 4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com 5 * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> 6 * 7 * A lot of code borrowed from the Linux xHCI driver. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * version 2 as published by the Free Software Foundation. 12 */ 13 14 #include <linux/platform_device.h> 15 #include <linux/module.h> 16 #include <linux/slab.h> 17 18 #include "xhci.h" 19 20 static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) 21 { 22 /* 23 * As of now platform drivers don't provide MSI support so we ensure 24 * here that the generic code does not try to make a pci_dev from our 25 * dev struct in order to setup MSI 26 */ 27 xhci->quirks |= XHCI_BROKEN_MSI; 28 } 29 30 /* called during probe() after chip reset completes */ 31 static int xhci_plat_setup(struct usb_hcd *hcd) 32 { 33 return xhci_gen_setup(hcd, xhci_plat_quirks); 34 } 35 36 static const struct hc_driver xhci_plat_xhci_driver = { 37 .description = "xhci-hcd", 38 .product_desc = "xHCI Host Controller", 39 .hcd_priv_size = sizeof(struct xhci_hcd *), 40 41 /* 42 * generic hardware linkage 43 */ 44 .irq = xhci_irq, 45 .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, 46 47 /* 48 * basic lifecycle operations 49 */ 50 .reset = xhci_plat_setup, 51 .start = xhci_run, 52 .stop = xhci_stop, 53 .shutdown = xhci_shutdown, 54 55 /* 56 * managing i/o requests and associated device resources 57 */ 58 .urb_enqueue = xhci_urb_enqueue, 59 .urb_dequeue = xhci_urb_dequeue, 60 .alloc_dev = xhci_alloc_dev, 61 .free_dev = xhci_free_dev, 62 .alloc_streams = xhci_alloc_streams, 63 .free_streams = xhci_free_streams, 64 .add_endpoint = xhci_add_endpoint, 65 .drop_endpoint = xhci_drop_endpoint, 66 .endpoint_reset = xhci_endpoint_reset, 67 .check_bandwidth = xhci_check_bandwidth, 68 .reset_bandwidth = xhci_reset_bandwidth, 69 .address_device = xhci_address_device, 70 .update_hub_device = xhci_update_hub_device, 71 .reset_device = xhci_discover_or_reset_device, 72 73 /* 74 * scheduling support 75 */ 76 .get_frame_number = xhci_get_frame, 77 78 /* Root hub support */ 79 .hub_control = xhci_hub_control, 80 .hub_status_data = xhci_hub_status_data, 81 .bus_suspend = xhci_bus_suspend, 82 .bus_resume = xhci_bus_resume, 83 }; 84 85 static int xhci_plat_probe(struct platform_device *pdev) 86 { 87 const struct hc_driver *driver; 88 struct xhci_hcd *xhci; 89 struct resource *res; 90 struct usb_hcd *hcd; 91 int ret; 92 int irq; 93 94 if (usb_disabled()) 95 return -ENODEV; 96 97 driver = &xhci_plat_xhci_driver; 98 99 irq = platform_get_irq(pdev, 0); 100 if (irq < 0) 101 return -ENODEV; 102 103 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 104 if (!res) 105 return -ENODEV; 106 107 hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); 108 if (!hcd) 109 return -ENOMEM; 110 111 hcd->rsrc_start = res->start; 112 hcd->rsrc_len = resource_size(res); 113 114 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, 115 driver->description)) { 116 dev_dbg(&pdev->dev, "controller already in use\n"); 117 ret = -EBUSY; 118 goto put_hcd; 119 } 120 121 hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); 122 if (!hcd->regs) { 123 dev_dbg(&pdev->dev, "error mapping memory\n"); 124 ret = -EFAULT; 125 goto release_mem_region; 126 } 127 128 ret = usb_add_hcd(hcd, irq, IRQF_SHARED); 129 if (ret) 130 goto unmap_registers; 131 132 /* USB 2.0 roothub is stored in the platform_device now. */ 133 hcd = dev_get_drvdata(&pdev->dev); 134 xhci = hcd_to_xhci(hcd); 135 xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, 136 dev_name(&pdev->dev), hcd); 137 if (!xhci->shared_hcd) { 138 ret = -ENOMEM; 139 goto dealloc_usb2_hcd; 140 } 141 142 /* 143 * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) 144 * is called by usb_add_hcd(). 145 */ 146 *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; 147 148 ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); 149 if (ret) 150 goto put_usb3_hcd; 151 152 return 0; 153 154 put_usb3_hcd: 155 usb_put_hcd(xhci->shared_hcd); 156 157 dealloc_usb2_hcd: 158 usb_remove_hcd(hcd); 159 160 unmap_registers: 161 iounmap(hcd->regs); 162 163 release_mem_region: 164 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 165 166 put_hcd: 167 usb_put_hcd(hcd); 168 169 return ret; 170 } 171 172 static int xhci_plat_remove(struct platform_device *dev) 173 { 174 struct usb_hcd *hcd = platform_get_drvdata(dev); 175 struct xhci_hcd *xhci = hcd_to_xhci(hcd); 176 177 usb_remove_hcd(xhci->shared_hcd); 178 usb_put_hcd(xhci->shared_hcd); 179 180 usb_remove_hcd(hcd); 181 iounmap(hcd->regs); 182 usb_put_hcd(hcd); 183 kfree(xhci); 184 185 return 0; 186 } 187 188 static struct platform_driver usb_xhci_driver = { 189 .probe = xhci_plat_probe, 190 .remove = xhci_plat_remove, 191 .driver = { 192 .name = "xhci-hcd", 193 }, 194 }; 195 MODULE_ALIAS("platform:xhci-hcd"); 196 197 int xhci_register_plat(void) 198 { 199 return platform_driver_register(&usb_xhci_driver); 200 } 201 202 void xhci_unregister_plat(void) 203 { 204 platform_driver_unregister(&usb_xhci_driver); 205 } 206