linux/drivers/usb/host/ohci-sa1111.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-2002 David Brownell <dbrownell@users.sourceforge.net>
   6 * (C) Copyright 2002 Hewlett-Packard Company
   7 *
   8 * SA1111 Bus Glue
   9 *
  10 * Written by Christopher Hoover <ch@hpl.hp.com>
  11 * Based on fragments of previous driver by Russell King et al.
  12 *
  13 * This file is licenced under the GPL.
  14 */
  15
  16#include <mach/hardware.h>
  17#include <asm/mach-types.h>
  18#include <mach/assabet.h>
  19#include <asm/hardware/sa1111.h>
  20
  21#ifndef CONFIG_SA1111
  22#error "This file is SA-1111 bus glue.  CONFIG_SA1111 must be defined."
  23#endif
  24
  25#define USB_STATUS      0x0118
  26#define USB_RESET       0x011c
  27#define USB_IRQTEST     0x0120
  28
  29#define USB_RESET_FORCEIFRESET  (1 << 0)
  30#define USB_RESET_FORCEHCRESET  (1 << 1)
  31#define USB_RESET_CLKGENRESET   (1 << 2)
  32#define USB_RESET_SIMSCALEDOWN  (1 << 3)
  33#define USB_RESET_USBINTTEST    (1 << 4)
  34#define USB_RESET_SLEEPSTBYEN   (1 << 5)
  35#define USB_RESET_PWRSENSELOW   (1 << 6)
  36#define USB_RESET_PWRCTRLLOW    (1 << 7)
  37
  38#define USB_STATUS_IRQHCIRMTWKUP  (1 <<  7)
  39#define USB_STATUS_IRQHCIBUFFACC  (1 <<  8)
  40#define USB_STATUS_NIRQHCIM       (1 <<  9)
  41#define USB_STATUS_NHCIMFCLR      (1 << 10)
  42#define USB_STATUS_USBPWRSENSE    (1 << 11)
  43
  44#if 0
  45static void dump_hci_status(struct usb_hcd *hcd, const char *label)
  46{
  47        unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
  48
  49        printk(KERN_DEBUG "%s USB_STATUS = { %s%s%s%s%s}\n", label,
  50             ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
  51             ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
  52             ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
  53             ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
  54             ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
  55}
  56#endif
  57
  58static int ohci_sa1111_reset(struct usb_hcd *hcd)
  59{
  60        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  61
  62        ohci_hcd_init(ohci);
  63        return ohci_init(ohci);
  64}
  65
  66static int ohci_sa1111_start(struct usb_hcd *hcd)
  67{
  68        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  69        int ret;
  70
  71        ret = ohci_run(ohci);
  72        if (ret < 0) {
  73                ohci_err(ohci, "can't start\n");
  74                ohci_stop(hcd);
  75        }
  76        return ret;
  77}
  78
  79static const struct hc_driver ohci_sa1111_hc_driver = {
  80        .description =          hcd_name,
  81        .product_desc =         "SA-1111 OHCI",
  82        .hcd_priv_size =        sizeof(struct ohci_hcd),
  83
  84        /*
  85         * generic hardware linkage
  86         */
  87        .irq =                  ohci_irq,
  88        .flags =                HCD_USB11 | HCD_MEMORY,
  89
  90        /*
  91         * basic lifecycle operations
  92         */
  93        .reset =                ohci_sa1111_reset,
  94        .start =                ohci_sa1111_start,
  95        .stop =                 ohci_stop,
  96        .shutdown =             ohci_shutdown,
  97
  98        /*
  99         * managing i/o requests and associated device resources
 100         */
 101        .urb_enqueue =          ohci_urb_enqueue,
 102        .urb_dequeue =          ohci_urb_dequeue,
 103        .endpoint_disable =     ohci_endpoint_disable,
 104
 105        /*
 106         * scheduling support
 107         */
 108        .get_frame_number =     ohci_get_frame,
 109
 110        /*
 111         * root hub support
 112         */
 113        .hub_status_data =      ohci_hub_status_data,
 114        .hub_control =          ohci_hub_control,
 115#ifdef  CONFIG_PM
 116        .bus_suspend =          ohci_bus_suspend,
 117        .bus_resume =           ohci_bus_resume,
 118#endif
 119        .start_port_reset =     ohci_start_port_reset,
 120};
 121
 122static int sa1111_start_hc(struct sa1111_dev *dev)
 123{
 124        unsigned int usb_rst = 0;
 125        int ret;
 126
 127        dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
 128
 129        if (machine_is_xp860() ||
 130            machine_has_neponset() ||
 131            machine_is_pfs168() ||
 132            machine_is_badge4())
 133                usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
 134
 135        /*
 136         * Configure the power sense and control lines.  Place the USB
 137         * host controller in reset.
 138         */
 139        sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
 140                      dev->mapbase + USB_RESET);
 141
 142        /*
 143         * Now, carefully enable the USB clock, and take
 144         * the USB host controller out of reset.
 145         */
 146        ret = sa1111_enable_device(dev);
 147        if (ret == 0) {
 148                udelay(11);
 149                sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
 150        }
 151
 152        return ret;
 153}
 154
 155static void sa1111_stop_hc(struct sa1111_dev *dev)
 156{
 157        unsigned int usb_rst;
 158
 159        dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
 160
 161        /*
 162         * Put the USB host controller into reset.
 163         */
 164        usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
 165        sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
 166                      dev->mapbase + USB_RESET);
 167
 168        /*
 169         * Stop the USB clock.
 170         */
 171        sa1111_disable_device(dev);
 172}
 173
 174/**
 175 * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs
 176 *
 177 * Allocates basic resources for this USB host controller, and
 178 * then invokes the start() method for the HCD associated with it.
 179 */
 180static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
 181{
 182        struct usb_hcd *hcd;
 183        int ret;
 184
 185        if (usb_disabled())
 186                return -ENODEV;
 187
 188        hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");
 189        if (!hcd)
 190                return -ENOMEM;
 191
 192        hcd->rsrc_start = dev->res.start;
 193        hcd->rsrc_len = resource_size(&dev->res);
 194
 195        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 196                dev_dbg(&dev->dev, "request_mem_region failed\n");
 197                ret = -EBUSY;
 198                goto err1;
 199        }
 200
 201        hcd->regs = dev->mapbase;
 202
 203        ret = sa1111_start_hc(dev);
 204        if (ret)
 205                goto err2;
 206
 207        ret = usb_add_hcd(hcd, dev->irq[1], 0);
 208        if (ret == 0)
 209                return ret;
 210
 211        sa1111_stop_hc(dev);
 212 err2:
 213        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 214 err1:
 215        usb_put_hcd(hcd);
 216        return ret;
 217}
 218
 219/**
 220 * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
 221 * @dev: USB Host Controller being removed
 222 *
 223 * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
 224 * the HCD's stop() method.
 225 */
 226static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
 227{
 228        struct usb_hcd *hcd = sa1111_get_drvdata(dev);
 229
 230        usb_remove_hcd(hcd);
 231        sa1111_stop_hc(dev);
 232        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 233        usb_put_hcd(hcd);
 234
 235        return 0;
 236}
 237
 238static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev)
 239{
 240        struct usb_hcd *hcd = sa1111_get_drvdata(dev);
 241
 242        if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
 243                hcd->driver->shutdown(hcd);
 244                sa1111_stop_hc(dev);
 245        }
 246}
 247
 248static struct sa1111_driver ohci_hcd_sa1111_driver = {
 249        .drv = {
 250                .name   = "sa1111-ohci",
 251                .owner  = THIS_MODULE,
 252        },
 253        .devid          = SA1111_DEVID_USB,
 254        .probe          = ohci_hcd_sa1111_probe,
 255        .remove         = ohci_hcd_sa1111_remove,
 256        .shutdown       = ohci_hcd_sa1111_shutdown,
 257};
 258