linux/drivers/usb/host/ohci-omap3.c
<<
>>
Prefs
   1/*
   2 * ohci-omap3.c - driver for OHCI on OMAP3 and later processors
   3 *
   4 * Bus Glue for OMAP3 USBHOST 3 port OHCI controller
   5 * This controller is also used in later OMAPs and AM35x chips
   6 *
   7 * Copyright (C) 2007-2010 Texas Instruments, Inc.
   8 * Author: Vikram Pandita <vikram.pandita@ti.com>
   9 * Author: Anand Gadiyar <gadiyar@ti.com>
  10 * Author: Keshava Munegowda <keshava_mgowda@ti.com>
  11 *
  12 * Based on ehci-omap.c and some other ohci glue layers
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License as published by
  16 * the Free Software Foundation; either version 2 of the License, or
  17 * (at your option) any later version.
  18 *
  19 * This program is distributed in the hope that it will be useful,
  20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22 * GNU General Public License for more details.
  23 *
  24 * You should have received a copy of the GNU General Public License
  25 * along with this program; if not, write to the Free Software
  26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  27 *
  28 * TODO (last updated Feb 27, 2011):
  29 *      - add kernel-doc
  30 */
  31
  32#include <linux/platform_device.h>
  33#include <linux/pm_runtime.h>
  34#include <linux/of.h>
  35#include <linux/dma-mapping.h>
  36
  37/*-------------------------------------------------------------------------*/
  38
  39static int ohci_omap3_init(struct usb_hcd *hcd)
  40{
  41        dev_dbg(hcd->self.controller, "starting OHCI controller\n");
  42
  43        return ohci_init(hcd_to_ohci(hcd));
  44}
  45
  46/*-------------------------------------------------------------------------*/
  47
  48static int ohci_omap3_start(struct usb_hcd *hcd)
  49{
  50        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  51        int ret;
  52
  53        /*
  54         * RemoteWakeupConnected has to be set explicitly before
  55         * calling ohci_run. The reset value of RWC is 0.
  56         */
  57        ohci->hc_control = OHCI_CTRL_RWC;
  58        writel(OHCI_CTRL_RWC, &ohci->regs->control);
  59
  60        ret = ohci_run(ohci);
  61
  62        if (ret < 0) {
  63                dev_err(hcd->self.controller, "can't start\n");
  64                ohci_stop(hcd);
  65        }
  66
  67        return ret;
  68}
  69
  70/*-------------------------------------------------------------------------*/
  71
  72static const struct hc_driver ohci_omap3_hc_driver = {
  73        .description =          hcd_name,
  74        .product_desc =         "OMAP3 OHCI Host Controller",
  75        .hcd_priv_size =        sizeof(struct ohci_hcd),
  76
  77        /*
  78         * generic hardware linkage
  79         */
  80        .irq =                  ohci_irq,
  81        .flags =                HCD_USB11 | HCD_MEMORY,
  82
  83        /*
  84         * basic lifecycle operations
  85         */
  86        .reset =                ohci_omap3_init,
  87        .start =                ohci_omap3_start,
  88        .stop =                 ohci_stop,
  89        .shutdown =             ohci_shutdown,
  90
  91        /*
  92         * managing i/o requests and associated device resources
  93         */
  94        .urb_enqueue =          ohci_urb_enqueue,
  95        .urb_dequeue =          ohci_urb_dequeue,
  96        .endpoint_disable =     ohci_endpoint_disable,
  97
  98        /*
  99         * scheduling support
 100         */
 101        .get_frame_number =     ohci_get_frame,
 102
 103        /*
 104         * root hub support
 105         */
 106        .hub_status_data =      ohci_hub_status_data,
 107        .hub_control =          ohci_hub_control,
 108#ifdef  CONFIG_PM
 109        .bus_suspend =          ohci_bus_suspend,
 110        .bus_resume =           ohci_bus_resume,
 111#endif
 112        .start_port_reset =     ohci_start_port_reset,
 113};
 114
 115/*-------------------------------------------------------------------------*/
 116
 117/*
 118 * configure so an HC device and id are always provided
 119 * always called with process context; sleeping is OK
 120 */
 121
 122/**
 123 * ohci_hcd_omap3_probe - initialize OMAP-based HCDs
 124 *
 125 * Allocates basic resources for this USB host controller, and
 126 * then invokes the start() method for the HCD associated with it
 127 * through the hotplug entry's driver_data.
 128 */
 129static int ohci_hcd_omap3_probe(struct platform_device *pdev)
 130{
 131        struct device           *dev = &pdev->dev;
 132        struct usb_hcd          *hcd = NULL;
 133        void __iomem            *regs = NULL;
 134        struct resource         *res;
 135        int                     ret = -ENODEV;
 136        int                     irq;
 137
 138        if (usb_disabled())
 139                return -ENODEV;
 140
 141        if (!dev->parent) {
 142                dev_err(dev, "Missing parent device\n");
 143                return -ENODEV;
 144        }
 145
 146        irq = platform_get_irq(pdev, 0);
 147        if (irq < 0) {
 148                dev_err(dev, "OHCI irq failed\n");
 149                return -ENODEV;
 150        }
 151
 152        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 153        if (!res) {
 154                dev_err(dev, "UHH OHCI get resource failed\n");
 155                return -ENOMEM;
 156        }
 157
 158        regs = ioremap(res->start, resource_size(res));
 159        if (!regs) {
 160                dev_err(dev, "UHH OHCI ioremap failed\n");
 161                return -ENOMEM;
 162        }
 163
 164        /*
 165         * Right now device-tree probed devices don't get dma_mask set.
 166         * Since shared usb code relies on it, set it here for now.
 167         * Once we have dma capability bindings this can go away.
 168         */
 169        if (!dev->dma_mask)
 170                dev->dma_mask = &dev->coherent_dma_mask;
 171        if (!dev->coherent_dma_mask)
 172                dev->coherent_dma_mask = DMA_BIT_MASK(32);
 173
 174        hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,
 175                        dev_name(dev));
 176        if (!hcd) {
 177                dev_err(dev, "usb_create_hcd failed\n");
 178                goto err_io;
 179        }
 180
 181        hcd->rsrc_start = res->start;
 182        hcd->rsrc_len = resource_size(res);
 183        hcd->regs =  regs;
 184
 185        pm_runtime_enable(dev);
 186        pm_runtime_get_sync(dev);
 187
 188        ohci_hcd_init(hcd_to_ohci(hcd));
 189
 190        ret = usb_add_hcd(hcd, irq, 0);
 191        if (ret) {
 192                dev_dbg(dev, "failed to add hcd with err %d\n", ret);
 193                goto err_add_hcd;
 194        }
 195
 196        return 0;
 197
 198err_add_hcd:
 199        pm_runtime_put_sync(dev);
 200        usb_put_hcd(hcd);
 201
 202err_io:
 203        iounmap(regs);
 204
 205        return ret;
 206}
 207
 208/*
 209 * may be called without controller electrically present
 210 * may be called with controller, bus, and devices active
 211 */
 212
 213/**
 214 * ohci_hcd_omap3_remove - shutdown processing for OHCI HCDs
 215 * @pdev: USB Host Controller being removed
 216 *
 217 * Reverses the effect of ohci_hcd_omap3_probe(), first invoking
 218 * the HCD's stop() method.  It is always called from a thread
 219 * context, normally "rmmod", "apmd", or something similar.
 220 */
 221static int ohci_hcd_omap3_remove(struct platform_device *pdev)
 222{
 223        struct device *dev      = &pdev->dev;
 224        struct usb_hcd *hcd     = dev_get_drvdata(dev);
 225
 226        iounmap(hcd->regs);
 227        usb_remove_hcd(hcd);
 228        pm_runtime_put_sync(dev);
 229        pm_runtime_disable(dev);
 230        usb_put_hcd(hcd);
 231        return 0;
 232}
 233
 234static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
 235{
 236        struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
 237
 238        if (hcd->driver->shutdown)
 239                hcd->driver->shutdown(hcd);
 240}
 241
 242static const struct of_device_id omap_ohci_dt_ids[] = {
 243        { .compatible = "ti,ohci-omap3" },
 244        { }
 245};
 246
 247MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids);
 248
 249static struct platform_driver ohci_hcd_omap3_driver = {
 250        .probe          = ohci_hcd_omap3_probe,
 251        .remove         = ohci_hcd_omap3_remove,
 252        .shutdown       = ohci_hcd_omap3_shutdown,
 253        .driver         = {
 254                .name   = "ohci-omap3",
 255                .of_match_table = of_match_ptr(omap_ohci_dt_ids),
 256        },
 257};
 258
 259MODULE_ALIAS("platform:ohci-omap3");
 260MODULE_AUTHOR("Anand Gadiyar <gadiyar@ti.com>");
 261