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/device.h>
  12#include <linux/platform_device.h>
  13
  14static int uhci_platform_init(struct usb_hcd *hcd)
  15{
  16        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
  17
  18        uhci->rh_numports = uhci_count_ports(hcd);
  19
  20        /* Set up pointers to to generic functions */
  21        uhci->reset_hc = uhci_generic_reset_hc;
  22        uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
  23
  24        /* No special actions need to be taken for the functions below */
  25        uhci->configure_hc = NULL;
  26        uhci->resume_detect_interrupts_are_broken = NULL;
  27        uhci->global_suspend_mode_is_broken = NULL;
  28
  29        /* Reset if the controller isn't already safely quiescent. */
  30        check_and_reset_hc(uhci);
  31        return 0;
  32}
  33
  34static const struct hc_driver uhci_platform_hc_driver = {
  35        .description =          hcd_name,
  36        .product_desc =         "Generic UHCI Host Controller",
  37        .hcd_priv_size =        sizeof(struct uhci_hcd),
  38
  39        /* Generic hardware linkage */
  40        .irq =                  uhci_irq,
  41        .flags =                HCD_MEMORY | HCD_USB11,
  42
  43        /* Basic lifecycle operations */
  44        .reset =                uhci_platform_init,
  45        .start =                uhci_start,
  46#ifdef CONFIG_PM
  47        .pci_suspend =          NULL,
  48        .pci_resume =           NULL,
  49        .bus_suspend =          uhci_rh_suspend,
  50        .bus_resume =           uhci_rh_resume,
  51#endif
  52        .stop =                 uhci_stop,
  53
  54        .urb_enqueue =          uhci_urb_enqueue,
  55        .urb_dequeue =          uhci_urb_dequeue,
  56
  57        .endpoint_disable =     uhci_hcd_endpoint_disable,
  58        .get_frame_number =     uhci_hcd_get_frame_number,
  59
  60        .hub_status_data =      uhci_hub_status_data,
  61        .hub_control =          uhci_hub_control,
  62};
  63
  64static int uhci_hcd_platform_probe(struct platform_device *pdev)
  65{
  66        struct usb_hcd *hcd;
  67        struct uhci_hcd *uhci;
  68        struct resource *res;
  69        int ret;
  70
  71        if (usb_disabled())
  72                return -ENODEV;
  73
  74        /*
  75         * Right now device-tree probed devices don't get dma_mask set.
  76         * Since shared usb code relies on it, set it here for now.
  77         * Once we have dma capability bindings this can go away.
  78         */
  79        ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
  80        if (ret)
  81                return ret;
  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->regs = devm_ioremap_resource(&pdev->dev, res);
  90        if (IS_ERR(hcd->regs)) {
  91                ret = PTR_ERR(hcd->regs);
  92                goto err_rmr;
  93        }
  94        hcd->rsrc_start = res->start;
  95        hcd->rsrc_len = resource_size(res);
  96
  97        uhci = hcd_to_uhci(hcd);
  98
  99        uhci->regs = hcd->regs;
 100
 101        ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
 102        if (ret)
 103                goto err_rmr;
 104
 105        device_wakeup_enable(hcd->self.controller);
 106        return 0;
 107
 108err_rmr:
 109        usb_put_hcd(hcd);
 110
 111        return ret;
 112}
 113
 114static int uhci_hcd_platform_remove(struct platform_device *pdev)
 115{
 116        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 117
 118        usb_remove_hcd(hcd);
 119        usb_put_hcd(hcd);
 120
 121        return 0;
 122}
 123
 124/* Make sure the controller is quiescent and that we're not using it
 125 * any more.  This is mainly for the benefit of programs which, like kexec,
 126 * expect the hardware to be idle: not doing DMA or generating IRQs.
 127 *
 128 * This routine may be called in a damaged or failing kernel.  Hence we
 129 * do not acquire the spinlock before shutting down the controller.
 130 */
 131static void uhci_hcd_platform_shutdown(struct platform_device *op)
 132{
 133        struct usb_hcd *hcd = platform_get_drvdata(op);
 134
 135        uhci_hc_died(hcd_to_uhci(hcd));
 136}
 137
 138static const struct of_device_id platform_uhci_ids[] = {
 139        { .compatible = "generic-uhci", },
 140        { .compatible = "platform-uhci", },
 141        {}
 142};
 143
 144static struct platform_driver uhci_platform_driver = {
 145        .probe          = uhci_hcd_platform_probe,
 146        .remove         = uhci_hcd_platform_remove,
 147        .shutdown       = uhci_hcd_platform_shutdown,
 148        .driver = {
 149                .name = "platform-uhci",
 150                .of_match_table = platform_uhci_ids,
 151        },
 152};
 153