linux/drivers/usb/host/ohci-da8xx.c
<<
>>
Prefs
   1/*
   2 * OHCI HCD (Host Controller Driver) for USB.
   3 *
   4 * TI DA8xx (OMAP-L1x) Bus Glue
   5 *
   6 * Derived from: ohci-omap.c and ohci-s3c2410.c
   7 * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
   8 *
   9 * This file is licensed under the terms of the GNU General Public License
  10 * version 2. This program is licensed "as is" without any warranty of any
  11 * kind, whether express or implied.
  12 */
  13
  14#include <linux/interrupt.h>
  15#include <linux/jiffies.h>
  16#include <linux/platform_device.h>
  17#include <linux/clk.h>
  18
  19#include <mach/da8xx.h>
  20#include <linux/platform_data/usb-davinci.h>
  21
  22#ifndef CONFIG_ARCH_DAVINCI_DA8XX
  23#error "This file is DA8xx bus glue.  Define CONFIG_ARCH_DAVINCI_DA8XX."
  24#endif
  25
  26#define CFGCHIP2        DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)
  27
  28static struct clk *usb11_clk;
  29static struct clk *usb20_clk;
  30
  31/* Over-current indicator change bitmask */
  32static volatile u16 ocic_mask;
  33
  34static void ohci_da8xx_clock(int on)
  35{
  36        u32 cfgchip2;
  37
  38        cfgchip2 = __raw_readl(CFGCHIP2);
  39        if (on) {
  40                clk_enable(usb11_clk);
  41
  42                /*
  43                 * If USB 1.1 reference clock is sourced from USB 2.0 PHY, we
  44                 * need to enable the USB 2.0 module clocking, start its PHY,
  45                 * and not allow it to stop the clock during USB 2.0 suspend.
  46                 */
  47                if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX)) {
  48                        clk_enable(usb20_clk);
  49
  50                        cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN);
  51                        cfgchip2 |= CFGCHIP2_PHY_PLLON;
  52                        __raw_writel(cfgchip2, CFGCHIP2);
  53
  54                        pr_info("Waiting for USB PHY clock good...\n");
  55                        while (!(__raw_readl(CFGCHIP2) & CFGCHIP2_PHYCLKGD))
  56                                cpu_relax();
  57                }
  58
  59                /* Enable USB 1.1 PHY */
  60                cfgchip2 |= CFGCHIP2_USB1SUSPENDM;
  61        } else {
  62                clk_disable(usb11_clk);
  63                if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX))
  64                        clk_disable(usb20_clk);
  65
  66                /* Disable USB 1.1 PHY */
  67                cfgchip2 &= ~CFGCHIP2_USB1SUSPENDM;
  68        }
  69        __raw_writel(cfgchip2, CFGCHIP2);
  70}
  71
  72/*
  73 * Handle the port over-current indicator change.
  74 */
  75static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
  76                                    unsigned port)
  77{
  78        ocic_mask |= 1 << port;
  79
  80        /* Once over-current is detected, the port needs to be powered down */
  81        if (hub->get_oci(port) > 0)
  82                hub->set_power(port, 0);
  83}
  84
  85static int ohci_da8xx_init(struct usb_hcd *hcd)
  86{
  87        struct device *dev              = hcd->self.controller;
  88        struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
  89        struct ohci_hcd *ohci           = hcd_to_ohci(hcd);
  90        int result;
  91        u32 rh_a;
  92
  93        dev_dbg(dev, "starting USB controller\n");
  94
  95        ohci_da8xx_clock(1);
  96
  97        /*
  98         * DA8xx only have 1 port connected to the pins but the HC root hub
  99         * register A reports 2 ports, thus we'll have to override it...
 100         */
 101        ohci->num_ports = 1;
 102
 103        result = ohci_init(ohci);
 104        if (result < 0)
 105                return result;
 106
 107        /*
 108         * Since we're providing a board-specific root hub port power control
 109         * and over-current reporting, we have to override the HC root hub A
 110         * register's default value, so that ohci_hub_control() could return
 111         * the correct hub descriptor...
 112         */
 113        rh_a = ohci_readl(ohci, &ohci->regs->roothub.a);
 114        if (hub->set_power) {
 115                rh_a &= ~RH_A_NPS;
 116                rh_a |=  RH_A_PSM;
 117        }
 118        if (hub->get_oci) {
 119                rh_a &= ~RH_A_NOCP;
 120                rh_a |=  RH_A_OCPM;
 121        }
 122        rh_a &= ~RH_A_POTPGT;
 123        rh_a |= hub->potpgt << 24;
 124        ohci_writel(ohci, rh_a, &ohci->regs->roothub.a);
 125
 126        return result;
 127}
 128
 129static void ohci_da8xx_stop(struct usb_hcd *hcd)
 130{
 131        ohci_stop(hcd);
 132        ohci_da8xx_clock(0);
 133}
 134
 135static int ohci_da8xx_start(struct usb_hcd *hcd)
 136{
 137        struct ohci_hcd *ohci           = hcd_to_ohci(hcd);
 138        int result;
 139
 140        result = ohci_run(ohci);
 141        if (result < 0)
 142                ohci_da8xx_stop(hcd);
 143
 144        return result;
 145}
 146
 147/*
 148 * Update the status data from the hub with the over-current indicator change.
 149 */
 150static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
 151{
 152        int length              = ohci_hub_status_data(hcd, buf);
 153
 154        /* See if we have OCIC bit set on port 1 */
 155        if (ocic_mask & (1 << 1)) {
 156                dev_dbg(hcd->self.controller, "over-current indicator change "
 157                        "on port 1\n");
 158
 159                if (!length)
 160                        length = 1;
 161
 162                buf[0] |= 1 << 1;
 163        }
 164        return length;
 165}
 166
 167/*
 168 * Look at the control requests to the root hub and see if we need to override.
 169 */
 170static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 171                                  u16 wIndex, char *buf, u16 wLength)
 172{
 173        struct device *dev              = hcd->self.controller;
 174        struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
 175        int temp;
 176
 177        switch (typeReq) {
 178        case GetPortStatus:
 179                /* Check the port number */
 180                if (wIndex != 1)
 181                        break;
 182
 183                dev_dbg(dev, "GetPortStatus(%u)\n", wIndex);
 184
 185                temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
 186
 187                /* The port power status (PPS) bit defaults to 1 */
 188                if (hub->get_power && hub->get_power(wIndex) == 0)
 189                        temp &= ~RH_PS_PPS;
 190
 191                /* The port over-current indicator (POCI) bit is always 0 */
 192                if (hub->get_oci && hub->get_oci(wIndex) > 0)
 193                        temp |=  RH_PS_POCI;
 194
 195                /* The over-current indicator change (OCIC) bit is 0 too */
 196                if (ocic_mask & (1 << wIndex))
 197                        temp |=  RH_PS_OCIC;
 198
 199                put_unaligned(cpu_to_le32(temp), (__le32 *)buf);
 200                return 0;
 201        case SetPortFeature:
 202                temp = 1;
 203                goto check_port;
 204        case ClearPortFeature:
 205                temp = 0;
 206
 207check_port:
 208                /* Check the port number */
 209                if (wIndex != 1)
 210                        break;
 211
 212                switch (wValue) {
 213                case USB_PORT_FEAT_POWER:
 214                        dev_dbg(dev, "%sPortFeature(%u): %s\n",
 215                                temp ? "Set" : "Clear", wIndex, "POWER");
 216
 217                        if (!hub->set_power)
 218                                return -EPIPE;
 219
 220                        return hub->set_power(wIndex, temp) ? -EPIPE : 0;
 221                case USB_PORT_FEAT_C_OVER_CURRENT:
 222                        dev_dbg(dev, "%sPortFeature(%u): %s\n",
 223                                temp ? "Set" : "Clear", wIndex,
 224                                "C_OVER_CURRENT");
 225
 226                        if (temp)
 227                                ocic_mask |= 1 << wIndex;
 228                        else
 229                                ocic_mask &= ~(1 << wIndex);
 230                        return 0;
 231                }
 232        }
 233
 234        return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
 235}
 236
 237static const struct hc_driver ohci_da8xx_hc_driver = {
 238        .description            = hcd_name,
 239        .product_desc           = "DA8xx OHCI",
 240        .hcd_priv_size          = sizeof(struct ohci_hcd),
 241
 242        /*
 243         * generic hardware linkage
 244         */
 245        .irq                    = ohci_irq,
 246        .flags                  = HCD_USB11 | HCD_MEMORY,
 247
 248        /*
 249         * basic lifecycle operations
 250         */
 251        .reset                  = ohci_da8xx_init,
 252        .start                  = ohci_da8xx_start,
 253        .stop                   = ohci_da8xx_stop,
 254        .shutdown               = ohci_shutdown,
 255
 256        /*
 257         * managing i/o requests and associated device resources
 258         */
 259        .urb_enqueue            = ohci_urb_enqueue,
 260        .urb_dequeue            = ohci_urb_dequeue,
 261        .endpoint_disable       = ohci_endpoint_disable,
 262
 263        /*
 264         * scheduling support
 265         */
 266        .get_frame_number       = ohci_get_frame,
 267
 268        /*
 269         * root hub support
 270         */
 271        .hub_status_data        = ohci_da8xx_hub_status_data,
 272        .hub_control            = ohci_da8xx_hub_control,
 273
 274#ifdef  CONFIG_PM
 275        .bus_suspend            = ohci_bus_suspend,
 276        .bus_resume             = ohci_bus_resume,
 277#endif
 278        .start_port_reset       = ohci_start_port_reset,
 279};
 280
 281/*-------------------------------------------------------------------------*/
 282
 283
 284/**
 285 * usb_hcd_da8xx_probe - initialize DA8xx-based HCDs
 286 * Context: !in_interrupt()
 287 *
 288 * Allocates basic resources for this USB host controller, and
 289 * then invokes the start() method for the HCD associated with it
 290 * through the hotplug entry's driver_data.
 291 */
 292static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
 293                               struct platform_device *pdev)
 294{
 295        struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
 296        struct usb_hcd  *hcd;
 297        struct resource *mem;
 298        int error, irq;
 299
 300        if (hub == NULL)
 301                return -ENODEV;
 302
 303        usb11_clk = devm_clk_get(&pdev->dev, "usb11");
 304        if (IS_ERR(usb11_clk))
 305                return PTR_ERR(usb11_clk);
 306
 307        usb20_clk = devm_clk_get(&pdev->dev, "usb20");
 308        if (IS_ERR(usb20_clk))
 309                return PTR_ERR(usb20_clk);
 310
 311        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
 312        if (!hcd)
 313                return -ENOMEM;
 314
 315        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 316        hcd->regs = devm_ioremap_resource(&pdev->dev, mem);
 317        if (IS_ERR(hcd->regs)) {
 318                error = PTR_ERR(hcd->regs);
 319                goto err;
 320        }
 321        hcd->rsrc_start = mem->start;
 322        hcd->rsrc_len = resource_size(mem);
 323
 324        ohci_hcd_init(hcd_to_ohci(hcd));
 325
 326        irq = platform_get_irq(pdev, 0);
 327        if (irq < 0) {
 328                error = -ENODEV;
 329                goto err;
 330        }
 331        error = usb_add_hcd(hcd, irq, 0);
 332        if (error)
 333                goto err;
 334
 335        device_wakeup_enable(hcd->self.controller);
 336
 337        if (hub->ocic_notify) {
 338                error = hub->ocic_notify(ohci_da8xx_ocic_handler);
 339                if (!error)
 340                        return 0;
 341        }
 342
 343        usb_remove_hcd(hcd);
 344err:
 345        usb_put_hcd(hcd);
 346        return error;
 347}
 348
 349/**
 350 * usb_hcd_da8xx_remove - shutdown processing for DA8xx-based HCDs
 351 * @dev: USB Host Controller being removed
 352 * Context: !in_interrupt()
 353 *
 354 * Reverses the effect of usb_hcd_da8xx_probe(), first invoking
 355 * the HCD's stop() method.  It is always called from a thread
 356 * context, normally "rmmod", "apmd", or something similar.
 357 */
 358static inline void
 359usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
 360{
 361        struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
 362
 363        hub->ocic_notify(NULL);
 364        usb_remove_hcd(hcd);
 365        usb_put_hcd(hcd);
 366}
 367
 368static int ohci_hcd_da8xx_drv_probe(struct platform_device *dev)
 369{
 370        return usb_hcd_da8xx_probe(&ohci_da8xx_hc_driver, dev);
 371}
 372
 373static int ohci_hcd_da8xx_drv_remove(struct platform_device *dev)
 374{
 375        struct usb_hcd  *hcd = platform_get_drvdata(dev);
 376
 377        usb_hcd_da8xx_remove(hcd, dev);
 378
 379        return 0;
 380}
 381
 382#ifdef CONFIG_PM
 383static int ohci_da8xx_suspend(struct platform_device *pdev,
 384                                pm_message_t message)
 385{
 386        struct usb_hcd  *hcd    = platform_get_drvdata(pdev);
 387        struct ohci_hcd *ohci   = hcd_to_ohci(hcd);
 388        bool            do_wakeup       = device_may_wakeup(&pdev->dev);
 389        int             ret;
 390
 391
 392        if (time_before(jiffies, ohci->next_statechange))
 393                msleep(5);
 394        ohci->next_statechange = jiffies;
 395
 396        ret = ohci_suspend(hcd, do_wakeup);
 397        if (ret)
 398                return ret;
 399
 400        ohci_da8xx_clock(0);
 401        hcd->state = HC_STATE_SUSPENDED;
 402
 403        return ret;
 404}
 405
 406static int ohci_da8xx_resume(struct platform_device *dev)
 407{
 408        struct usb_hcd  *hcd    = platform_get_drvdata(dev);
 409        struct ohci_hcd *ohci   = hcd_to_ohci(hcd);
 410
 411        if (time_before(jiffies, ohci->next_statechange))
 412                msleep(5);
 413        ohci->next_statechange = jiffies;
 414
 415        ohci_da8xx_clock(1);
 416        dev->dev.power.power_state = PMSG_ON;
 417        usb_hcd_resume_root_hub(hcd);
 418        return 0;
 419}
 420#endif
 421
 422/*
 423 * Driver definition to register with platform structure.
 424 */
 425static struct platform_driver ohci_hcd_da8xx_driver = {
 426        .probe          = ohci_hcd_da8xx_drv_probe,
 427        .remove         = ohci_hcd_da8xx_drv_remove,
 428        .shutdown       = usb_hcd_platform_shutdown,
 429#ifdef  CONFIG_PM
 430        .suspend        = ohci_da8xx_suspend,
 431        .resume         = ohci_da8xx_resume,
 432#endif
 433        .driver         = {
 434                .name   = "ohci",
 435        },
 436};
 437
 438MODULE_ALIAS("platform:ohci");
 439