SoCs will generally use the platform bus type, in order to simplify re-use of xHCI driver by SoCs, we introduce a generic file which is to be re-used by anyone with an xHCI using the platform bus_type. Also avoid always compiling xhci-pci.c, not all architectures have PCI. Signed-off-by: Felipe Balbi <balbi@xxxxxx> --- drivers/usb/host/Kconfig | 4 + drivers/usb/host/Makefile | 5 +- drivers/usb/host/xhci-platform.c | 234 ++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.c | 14 ++- drivers/usb/host/xhci.h | 6 + 5 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/host/xhci-platform.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index ab085f1..f91619a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -27,6 +27,10 @@ config USB_XHCI_HCD To compile this driver as a module, choose M here: the module will be called xhci-hcd. +config USB_XHCI_PLATFORM + bool + depends on USB_XHCI_HCD + config USB_XHCI_HCD_DEBUGGING bool "Debugging for the xHCI host controller" depends on USB_XHCI_HCD diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 624a362..fd4f2ab 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -11,9 +11,12 @@ fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o -xhci-hcd-y := xhci.o xhci-mem.o xhci-pci.o +xhci-hcd-y := xhci.o xhci-mem.o xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o +xhci-hcd-$(CONFIG_PCI) += xhci-pci.o +xhci-hcd-$(CONFIG_USB_XHCI_PLATFORM) += xhci-platform.o + obj-$(CONFIG_USB_WHCI_HCD) += whci/ obj-$(CONFIG_PCI) += pci-quirks.o diff --git a/drivers/usb/host/xhci-platform.c b/drivers/usb/host/xhci-platform.c new file mode 100644 index 0000000..7a6e7f8 --- /dev/null +++ b/drivers/usb/host/xhci-platform.c @@ -0,0 +1,234 @@ +/** + * xhci-platform.c - XHCI Platform Driver Glue + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: Felipe Balbi <balbi@xxxxxx>, + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2, as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/usb.h> + +#include <linux/usb/hcd.h> + +#include "xhci.h" + +static const char hcd_name[] = "xhci_hcd"; + +static int xhci_platform_setup(struct usb_hcd *hcd) +{ + return 0; +} + +static const struct hc_driver xhci_platform_hc_driver= { + .description = hcd_name, + .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_platform_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 __devinit xhci_platform_probe(struct platform_device *pdev) +{ + const struct hc_driver *driver = &xhci_platform_hc_driver; + struct xhci_hcd *xhci; + struct usb_hcd *hcd; + struct resource *res; + int ret; + int irq; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "found HC with no IRQ\n"); + ret = -ENODEV; + goto err0; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing memory address\n"); + ret = -ENXIO; + goto err0; + } + + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + dev_err(&pdev->dev, "can't create HCD\n"); + ret = -ENOMEM; + goto err0; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + platform_set_drvdata(pdev, hcd); + + res = request_mem_region(res->start, resource_size(res), + driver->description); + if (!res) { + dev_err(&pdev->dev, "controller in use\n"); + ret = -EBUSY; + goto err1; + } + + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&pdev->dev, "failed mapping memory\n"); + ret = -EFAULT; + goto err2; + } + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(&pdev->dev, "failed adding HCD\n"); + goto err3; + } + + 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 err4; + } + + *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; + + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(&pdev->dev, "failed adding Shared HCD\n"); + goto err5; + } + + return 0; + +err5: + usb_put_hcd(xhci->shared_hcd); + +err4: + usb_remove_hcd(hcd); + +err3: + iounmap(hcd->regs); + +err2: + release_mem_region(res->start, resource_size(res)); + +err1: + usb_put_hcd(hcd); + +err0: + return ret; +} + +static int __devexit xhci_platform_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + 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); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + usb_put_hcd(hcd); + + return 0; +} + +static struct platform_driver xhci_platform_driver = { + .probe = xhci_platform_probe, + .remove = __devexit_p(xhci_platform_remove), + .driver = { + .name = "xhci", + }, +}; + +MODULE_AUTHOR("Felipe Balbi <balbi@xxxxxx>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("XHCI Platform Glue Driver"); + +int __init xhci_register_platform(void) +{ + return platform_driver_register(&xhci_platform_driver); +} + +void __exit xhci_unregister_platform(void) +{ + platform_driver_unregister(&xhci_platform_driver); +} diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f647d91..ae1c4d4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3057,9 +3057,9 @@ MODULE_LICENSE("GPL"); static int __init xhci_hcd_init(void) { -#ifdef CONFIG_PCI int retval = 0; +#ifdef CONFIG_PCI retval = xhci_register_pci(); if (retval < 0) { @@ -3067,6 +3067,14 @@ static int __init xhci_hcd_init(void) return retval; } #endif + +#ifdef CONFIG_USB_XHCI_PLATFORM + retval = xhci_register_platform(); + if (retval) { + printk(KERN_DEBUG "Problem registering Platform driver.\n"); + return retval; + } +#endif /* * Check the compiler generated sizes of structures that must be laid * out in specific ways for hardware access. @@ -3094,5 +3102,9 @@ static void __exit xhci_hcd_cleanup(void) #ifdef CONFIG_PCI xhci_unregister_pci(); #endif + +#ifdef CONFIG_USB_XHCI_PLATFORM + xhci_unregister_platform(); +#endif } module_exit(xhci_hcd_cleanup); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index cae8e23..78637ce 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1485,6 +1485,12 @@ int xhci_register_pci(void); void xhci_unregister_pci(void); #endif +#ifdef CONFIG_USB_XHCI_PLATFORM +/* xHCI Platform glue */ +int xhci_register_platform(void); +void xhci_unregister_platform(void); +#endif + /* xHCI host controller glue */ void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); -- 1.7.6.396.ge0613 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html