-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
usb: host: xhci: add platform driver support
This adds a fairly simple xhci-platform driver support. Currently it is used by the dwc3 driver for supporting host mode. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
- Loading branch information
Sebastian Andrzej Siewior
authored and
Sarah Sharp
committed
Mar 13, 2012
1 parent
fdaf8b3
commit 3429e91
Showing
5 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
/* | ||
* xhci-plat.c - xHCI host controller driver platform Bus Glue. | ||
* | ||
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com | ||
* Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> | ||
* | ||
* A lot of code borrowed from the Linux xHCI driver. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* version 2 as published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/platform_device.h> | ||
#include <linux/module.h> | ||
#include <linux/slab.h> | ||
|
||
#include "xhci.h" | ||
|
||
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) | ||
{ | ||
/* | ||
* As of now platform drivers don't provide MSI support so we ensure | ||
* here that the generic code does not try to make a pci_dev from our | ||
* dev struct in order to setup MSI | ||
*/ | ||
xhci->quirks |= XHCI_BROKEN_MSI; | ||
} | ||
|
||
/* called during probe() after chip reset completes */ | ||
static int xhci_plat_setup(struct usb_hcd *hcd) | ||
{ | ||
return xhci_gen_setup(hcd, xhci_plat_quirks); | ||
} | ||
|
||
static const struct hc_driver xhci_plat_xhci_driver = { | ||
.description = "xhci-hcd", | ||
.product_desc = "xHCI Host Controller", | ||
.hcd_priv_size = sizeof(struct xhci_hcd *), | ||
|
||
/* | ||
* generic hardware linkage | ||
*/ | ||
.irq = xhci_irq, | ||
.flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, | ||
|
||
/* | ||
* basic lifecycle operations | ||
*/ | ||
.reset = xhci_plat_setup, | ||
.start = xhci_run, | ||
.stop = xhci_stop, | ||
.shutdown = xhci_shutdown, | ||
|
||
/* | ||
* managing i/o requests and associated device resources | ||
*/ | ||
.urb_enqueue = xhci_urb_enqueue, | ||
.urb_dequeue = xhci_urb_dequeue, | ||
.alloc_dev = xhci_alloc_dev, | ||
.free_dev = xhci_free_dev, | ||
.alloc_streams = xhci_alloc_streams, | ||
.free_streams = xhci_free_streams, | ||
.add_endpoint = xhci_add_endpoint, | ||
.drop_endpoint = xhci_drop_endpoint, | ||
.endpoint_reset = xhci_endpoint_reset, | ||
.check_bandwidth = xhci_check_bandwidth, | ||
.reset_bandwidth = xhci_reset_bandwidth, | ||
.address_device = xhci_address_device, | ||
.update_hub_device = xhci_update_hub_device, | ||
.reset_device = xhci_discover_or_reset_device, | ||
|
||
/* | ||
* scheduling support | ||
*/ | ||
.get_frame_number = xhci_get_frame, | ||
|
||
/* Root hub support */ | ||
.hub_control = xhci_hub_control, | ||
.hub_status_data = xhci_hub_status_data, | ||
.bus_suspend = xhci_bus_suspend, | ||
.bus_resume = xhci_bus_resume, | ||
}; | ||
|
||
static int xhci_plat_probe(struct platform_device *pdev) | ||
{ | ||
const struct hc_driver *driver; | ||
struct xhci_hcd *xhci; | ||
struct resource *res; | ||
struct usb_hcd *hcd; | ||
int ret; | ||
int irq; | ||
|
||
if (usb_disabled()) | ||
return -ENODEV; | ||
|
||
driver = &xhci_plat_xhci_driver; | ||
|
||
irq = platform_get_irq(pdev, 0); | ||
if (irq < 0) | ||
return -ENODEV; | ||
|
||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
if (!res) | ||
return -ENODEV; | ||
|
||
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); | ||
if (!hcd) | ||
return -ENOMEM; | ||
|
||
hcd->rsrc_start = res->start; | ||
hcd->rsrc_len = resource_size(res); | ||
|
||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, | ||
driver->description)) { | ||
dev_dbg(&pdev->dev, "controller already in use\n"); | ||
ret = -EBUSY; | ||
goto put_hcd; | ||
} | ||
|
||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
if (!hcd->regs) { | ||
dev_dbg(&pdev->dev, "error mapping memory\n"); | ||
ret = -EFAULT; | ||
goto release_mem_region; | ||
} | ||
|
||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED); | ||
if (ret) | ||
goto unmap_registers; | ||
|
||
/* USB 2.0 roothub is stored in the platform_device now. */ | ||
hcd = dev_get_drvdata(&pdev->dev); | ||
xhci = hcd_to_xhci(hcd); | ||
xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, | ||
dev_name(&pdev->dev), hcd); | ||
if (!xhci->shared_hcd) { | ||
ret = -ENOMEM; | ||
goto dealloc_usb2_hcd; | ||
} | ||
|
||
/* | ||
* Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) | ||
* is called by usb_add_hcd(). | ||
*/ | ||
*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; | ||
|
||
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); | ||
if (ret) | ||
goto put_usb3_hcd; | ||
|
||
return 0; | ||
|
||
put_usb3_hcd: | ||
usb_put_hcd(xhci->shared_hcd); | ||
|
||
dealloc_usb2_hcd: | ||
usb_remove_hcd(hcd); | ||
|
||
unmap_registers: | ||
iounmap(hcd->regs); | ||
|
||
release_mem_region: | ||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
|
||
put_hcd: | ||
usb_put_hcd(hcd); | ||
|
||
return ret; | ||
} | ||
|
||
static int xhci_plat_remove(struct platform_device *dev) | ||
{ | ||
struct usb_hcd *hcd = platform_get_drvdata(dev); | ||
struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
|
||
usb_remove_hcd(xhci->shared_hcd); | ||
usb_put_hcd(xhci->shared_hcd); | ||
|
||
usb_remove_hcd(hcd); | ||
iounmap(hcd->regs); | ||
usb_put_hcd(hcd); | ||
kfree(xhci); | ||
|
||
return 0; | ||
} | ||
|
||
static struct platform_driver usb_xhci_driver = { | ||
.probe = xhci_plat_probe, | ||
.remove = xhci_plat_remove, | ||
.driver = { | ||
.name = "xhci-hcd", | ||
}, | ||
}; | ||
MODULE_ALIAS("platform:xhci-hcd"); | ||
|
||
int xhci_register_plat(void) | ||
{ | ||
return platform_driver_register(&usb_xhci_driver); | ||
} | ||
|
||
void xhci_unregister_plat(void) | ||
{ | ||
platform_driver_unregister(&usb_xhci_driver); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters