linux/drivers/usb/host/ehci-platform.c
<<
>>
Prefs
   1/*
   2 * Generic platform ehci driver
   3 *
   4 * Copyright 2007 Steven Brown <sbrown@cortland.com>
   5 * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
   6 *
   7 * Derived from the ohci-ssb driver
   8 * Copyright 2007 Michael Buesch <m@bues.ch>
   9 *
  10 * Derived from the EHCI-PCI driver
  11 * Copyright (c) 2000-2004 by David Brownell
  12 *
  13 * Derived from the ohci-pci driver
  14 * Copyright 1999 Roman Weissgaerber
  15 * Copyright 2000-2002 David Brownell
  16 * Copyright 1999 Linus Torvalds
  17 * Copyright 1999 Gregory P. Smith
  18 *
  19 * Licensed under the GNU/GPL. See COPYING for details.
  20 */
  21#include <linux/platform_device.h>
  22#include <linux/usb/ehci_pdriver.h>
  23
  24static int ehci_platform_reset(struct usb_hcd *hcd)
  25{
  26        struct platform_device *pdev = to_platform_device(hcd->self.controller);
  27        struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
  28        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
  29        int retval;
  30
  31        hcd->has_tt = pdata->has_tt;
  32        ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
  33        ehci->big_endian_desc = pdata->big_endian_desc;
  34        ehci->big_endian_mmio = pdata->big_endian_mmio;
  35
  36        ehci->caps = hcd->regs + pdata->caps_offset;
  37        retval = ehci_setup(hcd);
  38        if (retval)
  39                return retval;
  40
  41        if (pdata->port_power_on)
  42                ehci_port_power(ehci, 1);
  43        if (pdata->port_power_off)
  44                ehci_port_power(ehci, 0);
  45
  46        return 0;
  47}
  48
  49static const struct hc_driver ehci_platform_hc_driver = {
  50        .description            = hcd_name,
  51        .product_desc           = "Generic Platform EHCI Controller",
  52        .hcd_priv_size          = sizeof(struct ehci_hcd),
  53
  54        .irq                    = ehci_irq,
  55        .flags                  = HCD_MEMORY | HCD_USB2,
  56
  57        .reset                  = ehci_platform_reset,
  58        .start                  = ehci_run,
  59        .stop                   = ehci_stop,
  60        .shutdown               = ehci_shutdown,
  61
  62        .urb_enqueue            = ehci_urb_enqueue,
  63        .urb_dequeue            = ehci_urb_dequeue,
  64        .endpoint_disable       = ehci_endpoint_disable,
  65        .endpoint_reset         = ehci_endpoint_reset,
  66
  67        .get_frame_number       = ehci_get_frame,
  68
  69        .hub_status_data        = ehci_hub_status_data,
  70        .hub_control            = ehci_hub_control,
  71#if defined(CONFIG_PM)
  72        .bus_suspend            = ehci_bus_suspend,
  73        .bus_resume             = ehci_bus_resume,
  74#endif
  75        .relinquish_port        = ehci_relinquish_port,
  76        .port_handed_over       = ehci_port_handed_over,
  77
  78        .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
  79};
  80
  81static int __devinit ehci_platform_probe(struct platform_device *dev)
  82{
  83        struct usb_hcd *hcd;
  84        struct resource *res_mem;
  85        int irq;
  86        int err = -ENOMEM;
  87
  88        BUG_ON(!dev->dev.platform_data);
  89
  90        if (usb_disabled())
  91                return -ENODEV;
  92
  93        irq = platform_get_irq(dev, 0);
  94        if (irq < 0) {
  95                pr_err("no irq provided");
  96                return irq;
  97        }
  98        res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
  99        if (!res_mem) {
 100                pr_err("no memory recourse provided");
 101                return -ENXIO;
 102        }
 103
 104        hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
 105                             dev_name(&dev->dev));
 106        if (!hcd)
 107                return -ENOMEM;
 108
 109        hcd->rsrc_start = res_mem->start;
 110        hcd->rsrc_len = resource_size(res_mem);
 111
 112        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 113                pr_err("controller already in use");
 114                err = -EBUSY;
 115                goto err_put_hcd;
 116        }
 117
 118        hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
 119        if (!hcd->regs)
 120                goto err_release_region;
 121        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 122        if (err)
 123                goto err_iounmap;
 124
 125        platform_set_drvdata(dev, hcd);
 126
 127        return err;
 128
 129err_iounmap:
 130        iounmap(hcd->regs);
 131err_release_region:
 132        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 133err_put_hcd:
 134        usb_put_hcd(hcd);
 135        return err;
 136}
 137
 138static int __devexit ehci_platform_remove(struct platform_device *dev)
 139{
 140        struct usb_hcd *hcd = platform_get_drvdata(dev);
 141
 142        usb_remove_hcd(hcd);
 143        iounmap(hcd->regs);
 144        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 145        usb_put_hcd(hcd);
 146        platform_set_drvdata(dev, NULL);
 147
 148        return 0;
 149}
 150
 151#ifdef CONFIG_PM
 152
 153static int ehci_platform_suspend(struct device *dev)
 154{
 155        struct usb_hcd *hcd = dev_get_drvdata(dev);
 156        bool do_wakeup = device_may_wakeup(dev);
 157
 158        return ehci_suspend(hcd, do_wakeup);
 159}
 160
 161static int ehci_platform_resume(struct device *dev)
 162{
 163        struct usb_hcd *hcd = dev_get_drvdata(dev);
 164
 165        ehci_resume(hcd, false);
 166        return 0;
 167}
 168
 169#else /* !CONFIG_PM */
 170#define ehci_platform_suspend   NULL
 171#define ehci_platform_resume    NULL
 172#endif /* CONFIG_PM */
 173
 174static const struct platform_device_id ehci_platform_table[] = {
 175        { "ehci-platform", 0 },
 176        { }
 177};
 178MODULE_DEVICE_TABLE(platform, ehci_platform_table);
 179
 180static const struct dev_pm_ops ehci_platform_pm_ops = {
 181        .suspend        = ehci_platform_suspend,
 182        .resume         = ehci_platform_resume,
 183};
 184
 185static struct platform_driver ehci_platform_driver = {
 186        .id_table       = ehci_platform_table,
 187        .probe          = ehci_platform_probe,
 188        .remove         = __devexit_p(ehci_platform_remove),
 189        .shutdown       = usb_hcd_platform_shutdown,
 190        .driver         = {
 191                .owner  = THIS_MODULE,
 192                .name   = "ehci-platform",
 193                .pm     = &ehci_platform_pm_ops,
 194        }
 195};
 196