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