linux/drivers/usb/host/ohci-sm501.c
<<
>>
Prefs
   1/*
   2 * OHCI HCD (Host Controller Driver) for USB.
   3 *
   4 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
   5 * (C) Copyright 2000-2005 David Brownell
   6 * (C) Copyright 2002 Hewlett-Packard Company
   7 * (C) Copyright 2008 Magnus Damm
   8 *
   9 * SM501 Bus Glue - based on ohci-omap.c
  10 *
  11 * This file is licenced under the GPL.
  12 */
  13
  14#include <linux/interrupt.h>
  15#include <linux/jiffies.h>
  16#include <linux/platform_device.h>
  17#include <linux/dma-mapping.h>
  18#include <linux/sm501.h>
  19#include <linux/sm501-regs.h>
  20
  21static int ohci_sm501_init(struct usb_hcd *hcd)
  22{
  23        return ohci_init(hcd_to_ohci(hcd));
  24}
  25
  26static int ohci_sm501_start(struct usb_hcd *hcd)
  27{
  28        struct device *dev = hcd->self.controller;
  29        int ret;
  30
  31        ret = ohci_run(hcd_to_ohci(hcd));
  32        if (ret < 0) {
  33                dev_err(dev, "can't start %s", hcd->self.bus_name);
  34                ohci_stop(hcd);
  35        }
  36
  37        return ret;
  38}
  39
  40/*-------------------------------------------------------------------------*/
  41
  42static const struct hc_driver ohci_sm501_hc_driver = {
  43        .description =          hcd_name,
  44        .product_desc =         "SM501 OHCI",
  45        .hcd_priv_size =        sizeof(struct ohci_hcd),
  46
  47        /*
  48         * generic hardware linkage
  49         */
  50        .irq =                  ohci_irq,
  51        .flags =                HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
  52
  53        /*
  54         * basic lifecycle operations
  55         */
  56        .reset =                ohci_sm501_init,
  57        .start =                ohci_sm501_start,
  58        .stop =                 ohci_stop,
  59        .shutdown =             ohci_shutdown,
  60
  61        /*
  62         * managing i/o requests and associated device resources
  63         */
  64        .urb_enqueue =          ohci_urb_enqueue,
  65        .urb_dequeue =          ohci_urb_dequeue,
  66        .endpoint_disable =     ohci_endpoint_disable,
  67
  68        /*
  69         * scheduling support
  70         */
  71        .get_frame_number =     ohci_get_frame,
  72
  73        /*
  74         * root hub support
  75         */
  76        .hub_status_data =      ohci_hub_status_data,
  77        .hub_control =          ohci_hub_control,
  78#ifdef  CONFIG_PM
  79        .bus_suspend =          ohci_bus_suspend,
  80        .bus_resume =           ohci_bus_resume,
  81#endif
  82        .start_port_reset =     ohci_start_port_reset,
  83};
  84
  85/*-------------------------------------------------------------------------*/
  86
  87static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
  88{
  89        const struct hc_driver *driver = &ohci_sm501_hc_driver;
  90        struct device *dev = &pdev->dev;
  91        struct resource *res, *mem;
  92        int retval, irq;
  93        struct usb_hcd *hcd = NULL;
  94
  95        irq = retval = platform_get_irq(pdev, 0);
  96        if (retval < 0)
  97                goto err0;
  98
  99        mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 100        if (mem == NULL) {
 101                dev_err(dev, "no resource definition for memory\n");
 102                retval = -ENOENT;
 103                goto err0;
 104        }
 105
 106        if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
 107                dev_err(dev, "request_mem_region failed\n");
 108                retval = -EBUSY;
 109                goto err0;
 110        }
 111
 112        /* The sm501 chip is equipped with local memory that may be used
 113         * by on-chip devices such as the video controller and the usb host.
 114         * This driver uses dma_declare_coherent_memory() to make sure
 115         * usb allocations with dma_alloc_coherent() allocate from
 116         * this local memory. The dma_handle returned by dma_alloc_coherent()
 117         * will be an offset starting from 0 for the first local memory byte.
 118         *
 119         * So as long as data is allocated using dma_alloc_coherent() all is
 120         * fine. This is however not always the case - buffers may be allocated
 121         * using kmalloc() - so the usb core needs to be told that it must copy
 122         * data into our local memory if the buffers happen to be placed in
 123         * regular memory. The HCD_LOCAL_MEM flag does just that.
 124         */
 125
 126        if (!dma_declare_coherent_memory(dev, mem->start,
 127                                         mem->start - mem->parent->start,
 128                                         resource_size(mem),
 129                                         DMA_MEMORY_MAP |
 130                                         DMA_MEMORY_EXCLUSIVE)) {
 131                dev_err(dev, "cannot declare coherent memory\n");
 132                retval = -ENXIO;
 133                goto err1;
 134        }
 135
 136        /* allocate, reserve and remap resources for registers */
 137        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 138        if (res == NULL) {
 139                dev_err(dev, "no resource definition for registers\n");
 140                retval = -ENOENT;
 141                goto err2;
 142        }
 143
 144        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
 145        if (!hcd) {
 146                retval = -ENOMEM;
 147                goto err2;
 148        }
 149
 150        hcd->rsrc_start = res->start;
 151        hcd->rsrc_len = resource_size(res);
 152
 153        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) {
 154                dev_err(dev, "request_mem_region failed\n");
 155                retval = -EBUSY;
 156                goto err3;
 157        }
 158
 159        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 160        if (hcd->regs == NULL) {
 161                dev_err(dev, "cannot remap registers\n");
 162                retval = -ENXIO;
 163                goto err4;
 164        }
 165
 166        ohci_hcd_init(hcd_to_ohci(hcd));
 167
 168        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
 169        if (retval)
 170                goto err5;
 171
 172        /* enable power and unmask interrupts */
 173
 174        sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
 175        sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0);
 176
 177        return 0;
 178err5:
 179        iounmap(hcd->regs);
 180err4:
 181        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 182err3:
 183        usb_put_hcd(hcd);
 184err2:
 185        dma_release_declared_memory(dev);
 186err1:
 187        release_mem_region(mem->start, resource_size(mem));
 188err0:
 189        return retval;
 190}
 191
 192static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
 193{
 194        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 195        struct resource *mem;
 196
 197        usb_remove_hcd(hcd);
 198        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 199        usb_put_hcd(hcd);
 200        dma_release_declared_memory(&pdev->dev);
 201        mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 202        if (mem)
 203                release_mem_region(mem->start, resource_size(mem));
 204
 205        /* mask interrupts and disable power */
 206
 207        sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6);
 208        sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0);
 209
 210        return 0;
 211}
 212
 213/*-------------------------------------------------------------------------*/
 214
 215#ifdef CONFIG_PM
 216static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)
 217{
 218        struct device *dev = &pdev->dev;
 219        struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev));
 220
 221        if (time_before(jiffies, ohci->next_statechange))
 222                msleep(5);
 223        ohci->next_statechange = jiffies;
 224
 225        sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0);
 226        return 0;
 227}
 228
 229static int ohci_sm501_resume(struct platform_device *pdev)
 230{
 231        struct device *dev = &pdev->dev;
 232        struct usb_hcd  *hcd = platform_get_drvdata(pdev);
 233        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
 234
 235        if (time_before(jiffies, ohci->next_statechange))
 236                msleep(5);
 237        ohci->next_statechange = jiffies;
 238
 239        sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
 240        ohci_resume(hcd, false);
 241        return 0;
 242}
 243#else
 244#define ohci_sm501_suspend NULL
 245#define ohci_sm501_resume NULL
 246#endif
 247
 248/*-------------------------------------------------------------------------*/
 249
 250/*
 251 * Driver definition to register with the SM501 bus
 252 */
 253static struct platform_driver ohci_hcd_sm501_driver = {
 254        .probe          = ohci_hcd_sm501_drv_probe,
 255        .remove         = ohci_hcd_sm501_drv_remove,
 256        .shutdown       = usb_hcd_platform_shutdown,
 257        .suspend        = ohci_sm501_suspend,
 258        .resume         = ohci_sm501_resume,
 259        .driver         = {
 260                .owner  = THIS_MODULE,
 261                .name   = "sm501-usb",
 262        },
 263};
 264MODULE_ALIAS("platform:sm501-usb");
 265