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, mem->end - mem->start + 1,
 107                                pdev->name)) {
 108                dev_err(dev, "request_mem_region failed\n");
 109                retval = -EBUSY;
 110                goto err0;
 111        }
 112
 113        /* The sm501 chip is equipped with local memory that may be used
 114         * by on-chip devices such as the video controller and the usb host.
 115         * This driver uses dma_declare_coherent_memory() to make sure
 116         * usb allocations with dma_alloc_coherent() allocate from
 117         * this local memory. The dma_handle returned by dma_alloc_coherent()
 118         * will be an offset starting from 0 for the first local memory byte.
 119         *
 120         * So as long as data is allocated using dma_alloc_coherent() all is
 121         * fine. This is however not always the case - buffers may be allocated
 122         * using kmalloc() - so the usb core needs to be told that it must copy
 123         * data into our local memory if the buffers happen to be placed in
 124         * regular memory. The HCD_LOCAL_MEM flag does just that.
 125         */
 126
 127        if (!dma_declare_coherent_memory(dev, mem->start,
 128                                         mem->start - mem->parent->start,
 129                                         (mem->end - mem->start) + 1,
 130                                         DMA_MEMORY_MAP |
 131                                         DMA_MEMORY_EXCLUSIVE)) {
 132                dev_err(dev, "cannot declare coherent memory\n");
 133                retval = -ENXIO;
 134                goto err1;
 135        }
 136
 137        /* allocate, reserve and remap resources for registers */
 138        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 139        if (res == NULL) {
 140                dev_err(dev, "no resource definition for registers\n");
 141                retval = -ENOENT;
 142                goto err2;
 143        }
 144
 145        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
 146        if (!hcd) {
 147                retval = -ENOMEM;
 148                goto err2;
 149        }
 150
 151        hcd->rsrc_start = res->start;
 152        hcd->rsrc_len = res->end - res->start + 1;
 153
 154        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) {
 155                dev_err(dev, "request_mem_region failed\n");
 156                retval = -EBUSY;
 157                goto err3;
 158        }
 159
 160        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 161        if (hcd->regs == NULL) {
 162                dev_err(dev, "cannot remap registers\n");
 163                retval = -ENXIO;
 164                goto err4;
 165        }
 166
 167        ohci_hcd_init(hcd_to_ohci(hcd));
 168
 169        retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 170        if (retval)
 171                goto err4;
 172
 173        /* enable power and unmask interrupts */
 174
 175        sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
 176        sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0);
 177
 178        return 0;
 179err4:
 180        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 181err3:
 182        usb_put_hcd(hcd);
 183err2:
 184        dma_release_declared_memory(dev);
 185err1:
 186        release_mem_region(mem->start, mem->end - mem->start + 1);
 187err0:
 188        return retval;
 189}
 190
 191static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
 192{
 193        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 194        struct resource *mem;
 195
 196        usb_remove_hcd(hcd);
 197        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 198        usb_put_hcd(hcd);
 199        dma_release_declared_memory(&pdev->dev);
 200        mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 201        if (mem)
 202                release_mem_region(mem->start, mem->end - mem->start + 1);
 203
 204        /* mask interrupts and disable power */
 205
 206        sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6);
 207        sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0);
 208
 209        platform_set_drvdata(pdev, NULL);
 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        ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
 227        return 0;
 228}
 229
 230static int ohci_sm501_resume(struct platform_device *pdev)
 231{
 232        struct device *dev = &pdev->dev;
 233        struct usb_hcd  *hcd = platform_get_drvdata(pdev);
 234        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
 235
 236        if (time_before(jiffies, ohci->next_statechange))
 237                msleep(5);
 238        ohci->next_statechange = jiffies;
 239
 240        sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
 241        ohci_finish_controller_resume(hcd);
 242        return 0;
 243}
 244#else
 245#define ohci_sm501_suspend NULL
 246#define ohci_sm501_resume NULL
 247#endif
 248
 249/*-------------------------------------------------------------------------*/
 250
 251/*
 252 * Driver definition to register with the SM501 bus
 253 */
 254static struct platform_driver ohci_hcd_sm501_driver = {
 255        .probe          = ohci_hcd_sm501_drv_probe,
 256        .remove         = ohci_hcd_sm501_drv_remove,
 257        .shutdown       = usb_hcd_platform_shutdown,
 258        .suspend        = ohci_sm501_suspend,
 259        .resume         = ohci_sm501_resume,
 260        .driver         = {
 261                .owner  = THIS_MODULE,
 262                .name   = "sm501-usb",
 263        },
 264};
 265MODULE_ALIAS("platform:sm501-usb");
 266