Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
xhci-plat.c
Go to the documentation of this file.
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 <[email protected]>
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 
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 
198 {
199  return platform_driver_register(&usb_xhci_driver);
200 }
201 
203 {
204  platform_driver_unregister(&usb_xhci_driver);
205 }