linux/drivers/usb/host/uhci-platform.c
<<
>>
Prefs
   1/*
   2 * Generic UHCI HCD (Host Controller Driver) for Platform Devices
   3 *
   4 * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz>
   5 *
   6 * This file is based on uhci-grlib.c
   7 * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
   8 */
   9
  10#include <linux/of.h>
  11#include <linux/platform_device.h>
  12
  13static int uhci_platform_init(struct usb_hcd *hcd)
  14{
  15        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
  16
  17        uhci->rh_numports = uhci_count_ports(hcd);
  18
  19        /* Set up pointers to to generic functions */
  20        uhci->reset_hc = uhci_generic_reset_hc;
  21        uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
  22
  23        /* No special actions need to be taken for the functions below */
  24        uhci->configure_hc = NULL;
  25        uhci->resume_detect_interrupts_are_broken = NULL;
  26        uhci->global_suspend_mode_is_broken = NULL;
  27
  28        /* Reset if the controller isn't already safely quiescent. */
  29        check_and_reset_hc(uhci);
  30        return 0;
  31}
  32
  33static const struct hc_driver uhci_platform_hc_driver = {
  34        .description =          hcd_name,
  35        .product_desc =         "Generic UHCI Host Controller",
  36        .hcd_priv_size =        sizeof(struct uhci_hcd),
  37
  38        /* Generic hardware linkage */
  39        .irq =                  uhci_irq,
  40        .flags =                HCD_MEMORY | HCD_USB11,
  41
  42        /* Basic lifecycle operations */
  43        .reset =                uhci_platform_init,
  44        .start =                uhci_start,
  45#ifdef CONFIG_PM
  46        .pci_suspend =          NULL,
  47        .pci_resume =           NULL,
  48        .bus_suspend =          uhci_rh_suspend,
  49        .bus_resume =           uhci_rh_resume,
  50#endif
  51        .stop =                 uhci_stop,
  52
  53        .urb_enqueue =          uhci_urb_enqueue,
  54        .urb_dequeue =          uhci_urb_dequeue,
  55
  56        .endpoint_disable =     uhci_hcd_endpoint_disable,
  57        .get_frame_number =     uhci_hcd_get_frame_number,
  58
  59        .hub_status_data =      uhci_hub_status_data,
  60        .hub_control =          uhci_hub_control,
  61};
  62
  63static int uhci_hcd_platform_probe(struct platform_device *pdev)
  64{
  65        struct usb_hcd *hcd;
  66        struct uhci_hcd *uhci;
  67        struct resource *res;
  68        int ret;
  69
  70        if (usb_disabled())
  71                return -ENODEV;
  72
  73        /*
  74         * Right now device-tree probed devices don't get dma_mask set.
  75         * Since shared usb code relies on it, set it here for now.
  76         * Once we have dma capability bindings this can go away.
  77         */
  78        if (!pdev->dev.dma_mask)
  79                pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
  80        if (!pdev->dev.coherent_dma_mask)
  81                pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
  82
  83        hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev,
  84                        pdev->name);
  85        if (!hcd)
  86                return -ENOMEM;
  87
  88        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  89        hcd->rsrc_start = res->start;
  90        hcd->rsrc_len = resource_size(res);
  91
  92        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
  93                pr_err("%s: request_mem_region failed\n", __func__);
  94                ret = -EBUSY;
  95                goto err_rmr;
  96        }
  97
  98        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
  99        if (!hcd->regs) {
 100                pr_err("%s: ioremap failed\n", __func__);
 101                ret = -ENOMEM;
 102                goto err_irq;
 103        }
 104        uhci = hcd_to_uhci(hcd);
 105
 106        uhci->regs = hcd->regs;
 107
 108        ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED |
 109                                                                IRQF_SHARED);
 110        if (ret)
 111                goto err_uhci;
 112
 113        return 0;
 114
 115err_uhci:
 116        iounmap(hcd->regs);
 117err_irq:
 118        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 119err_rmr:
 120        usb_put_hcd(hcd);
 121
 122        return ret;
 123}
 124
 125static int uhci_hcd_platform_remove(struct platform_device *pdev)
 126{
 127        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 128
 129        usb_remove_hcd(hcd);
 130        iounmap(hcd->regs);
 131        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 132        usb_put_hcd(hcd);
 133        platform_set_drvdata(pdev, NULL);
 134
 135        return 0;
 136}
 137
 138/* Make sure the controller is quiescent and that we're not using it
 139 * any more.  This is mainly for the benefit of programs which, like kexec,
 140 * expect the hardware to be idle: not doing DMA or generating IRQs.
 141 *
 142 * This routine may be called in a damaged or failing kernel.  Hence we
 143 * do not acquire the spinlock before shutting down the controller.
 144 */
 145static void uhci_hcd_platform_shutdown(struct platform_device *op)
 146{
 147        struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
 148
 149        uhci_hc_died(hcd_to_uhci(hcd));
 150}
 151
 152static const struct of_device_id platform_uhci_ids[] = {
 153        { .compatible = "platform-uhci", },
 154        {}
 155};
 156
 157static struct platform_driver uhci_platform_driver = {
 158        .probe          = uhci_hcd_platform_probe,
 159        .remove         = uhci_hcd_platform_remove,
 160        .shutdown       = uhci_hcd_platform_shutdown,
 161        .driver = {
 162                .name = "platform-uhci",
 163                .owner = THIS_MODULE,
 164                .of_match_table = of_match_ptr(platform_uhci_ids),
 165        },
 166};
 167