]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
[PATCH] ARM: OMAP: USB clock changes from Juha
authorTony Lindgren <tony@atomide.com>
Tue, 3 Jan 2006 17:39:24 +0000 (09:39 -0800)
committerTony Lindgren <tony@atomide.com>
Tue, 3 Jan 2006 17:39:24 +0000 (09:39 -0800)
This patch from Juha Yrjola adds two missing USB clocks.

Please note that CONFIG_OMAP_RESET_CLOCKS may still need to be
disabled in .config for USB to work on some platforms (OSK).

drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/omap_udc.h
drivers/usb/host/ohci-omap.c

index 16136388ff0d0d02199a2cdb916add2b81f872ff..7a6ba6ad7acdb023dc52e635c1897a7fe49794c1 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 #include <asm/mach-types.h>
+#include <asm/hardware/clock.h>
 
 #include <asm/arch/dma.h>
 #include <asm/arch/usb.h>
@@ -1306,6 +1307,23 @@ static void pullup_disable(struct omap_udc *udc)
        UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
 }
 
+static struct omap_udc *udc;
+
+static void omap_udc_enable_clock(int enable)
+{
+       if (udc == NULL || udc->dc_clk == NULL || udc->hhc_clk == NULL)
+               return;
+
+       if (enable) {
+               clk_use(udc->dc_clk);
+               clk_use(udc->hhc_clk);
+               udelay(100);
+       } else {
+               clk_unuse(udc->hhc_clk);
+               clk_unuse(udc->dc_clk);
+       }
+}
+
 /*
  * Called by whatever detects VBUS sessions:  external transceiver
  * driver, or maybe GPIO0 VBUS IRQ.  May request 48 MHz clock.
@@ -1326,10 +1344,22 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
                else
                        FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
        }
+       if (udc->dc_clk != NULL && is_active) {
+               if (!udc->clk_requested) {
+                       omap_udc_enable_clock(1);
+                       udc->clk_requested = 1;
+               }
+       }
        if (can_pullup(udc))
                pullup_enable(udc);
        else
                pullup_disable(udc);
+       if (udc->dc_clk != NULL && !is_active) {
+               if (udc->clk_requested) {
+                       omap_udc_enable_clock(0);
+                       udc->clk_requested = 0;
+               }
+       }
        spin_unlock_irqrestore(&udc->lock, flags);
        return 0;
 }
@@ -2039,7 +2069,6 @@ omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r)
 
 /*-------------------------------------------------------------------------*/
 
-static struct omap_udc *udc;
 
 int usb_gadget_register_driver (struct usb_gadget_driver *driver)
 {
@@ -2082,6 +2111,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
        udc->gadget.dev.driver = &driver->driver;
        spin_unlock_irqrestore(&udc->lock, flags);
 
+       if (udc->dc_clk != NULL)
+               omap_udc_enable_clock(1);
+
        status = driver->bind (&udc->gadget);
        if (status) {
                DBG("bind to %s --> %d\n", driver->driver.name, status);
@@ -2117,6 +2149,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                omap_vbus_session(&udc->gadget, 1);
 
 done:
+       if (udc->dc_clk != NULL)
+               omap_udc_enable_clock(0);
        return status;
 }
 EXPORT_SYMBOL(usb_gadget_register_driver);
@@ -2131,6 +2165,9 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        if (!driver || driver != udc->driver)
                return -EINVAL;
 
+       if (udc->dc_clk != NULL)
+               omap_udc_enable_clock(1);
+
        if (machine_is_omap_innovator() || machine_is_omap_osk())
                omap_vbus_session(&udc->gadget, 0);
 
@@ -2147,6 +2184,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        udc->gadget.dev.driver = NULL;
        udc->driver = NULL;
 
+       if (udc->dc_clk != NULL)
+               omap_udc_enable_clock(0);
        DBG("unregistered driver '%s'\n", driver->driver.name);
        return status;
 }
@@ -2720,6 +2759,8 @@ static int __init omap_udc_probe(struct platform_device *pdev)
        struct otg_transceiver  *xceiv = NULL;
        const char              *type = NULL;
        struct omap_usb_config  *config = pdev->dev.platform_data;
+       struct clk              *dc_clk;
+       struct clk              *hhc_clk;
 
        /* NOTE:  "knows" the order of the resources! */
        if (!request_mem_region(pdev->resource[0].start, 
@@ -2729,6 +2770,16 @@ static int __init omap_udc_probe(struct platform_device *pdev)
                return -EBUSY;
        }
 
+       if (cpu_is_omap16xx()) {
+               dc_clk = clk_get(dev, "usb_dc_ck");
+               hhc_clk = clk_get(dev, "usb_hhc_ck");
+               BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
+               /* can't use omap_udc_enable_clock yet */
+               clk_use(dc_clk);
+               clk_use(hhc_clk);
+               udelay(100);
+       }
+
        INFO("OMAP UDC rev %d.%d%s\n",
                UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
                config->otg ? ", Mini-AB" : "");
@@ -2851,6 +2902,12 @@ bad_on_1710:
                goto cleanup3;
        }
 #endif
+       if (cpu_is_omap16xx()) {
+               udc->dc_clk = dc_clk;
+               udc->hhc_clk = hhc_clk;
+               clk_unuse(hhc_clk);
+               clk_unuse(dc_clk);
+       }
 
        create_proc_file();
        device_add(&udc->gadget.dev);
@@ -2871,8 +2928,17 @@ cleanup1:
 cleanup0:
        if (xceiv)
                put_device(xceiv->dev);
+
+       if (cpu_is_omap16xx()) {
+               clk_unuse(hhc_clk);
+               clk_unuse(dc_clk);
+               clk_put(hhc_clk);
+               clk_put(dc_clk);
+       }
+
        release_mem_region(pdev->resource[0].start,
                        pdev->resource[0].end - pdev->resource[0].start + 1);
+
        return status;
 }
 
@@ -2900,6 +2966,13 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
        free_irq(pdev->resource[2].start, udc);
        free_irq(pdev->resource[1].start, udc);
 
+       if (udc->dc_clk) {
+               if (udc->clk_requested)
+                       omap_udc_enable_clock(0);
+               clk_put(udc->hhc_clk);
+               clk_put(udc->dc_clk);
+       }
+
        release_mem_region(pdev->resource[0].start,
                        pdev->resource[0].end - pdev->resource[0].start + 1);
 
index 652ee462734470345eed415a474c096fbe4a7909..1dc398bb9ab2ae408f0d77ee2c24d3d9c966c838 100644 (file)
@@ -175,6 +175,9 @@ struct omap_udc {
        unsigned                        ep0_reset_config:1;
        unsigned                        ep0_setup:1;
        struct completion               *done;
+       struct clk                      *dc_clk;
+       struct clk                      *hhc_clk;
+       unsigned                        clk_requested:1;
 };
 
 /*-------------------------------------------------------------------------*/
index ae97252eeac8366e2a700b6d5ab3ed41f350a136..a0ad788e000935f1958e8226e95022677acbcf7b 100644 (file)
@@ -66,15 +66,20 @@ extern int usb_disabled(void);
 extern int ocpi_enable(void);
 
 static struct clk *usb_host_ck;
+static struct clk *usb_dc_ck;
+static int host_enabled;
+static int host_initialized;
 
 static void omap_ohci_clock_power(int on)
 {
        if (on) {
+               clk_use(usb_dc_ck);
                clk_use(usb_host_ck);
                /* guesstimate for T5 == 1x 32K clock + APLL lock time */
                udelay(100);
        } else {
                clk_unuse(usb_host_ck);
+               clk_unuse(usb_dc_ck);
        }
 }
 
@@ -280,6 +285,43 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
 /* always called with process context; sleeping is OK */
 
 
+int ohci_omap_host_enable(struct usb_bus *host, int enable)
+{
+       struct usb_hcd *hcd;
+       struct ohci_hcd *ohci;
+       int retval;
+
+       if (host_enabled == enable)
+               return 0;
+
+       host_enabled = enable;
+
+       if (!host_initialized)
+               return 0;
+
+       hcd = (struct usb_hcd *)host->hcpriv;
+       ohci = hcd_to_ohci(hcd);
+       if (enable) {
+               omap_ohci_clock_power(1);
+               if ((retval = ohci_init(ohci)) < 0) {
+                       dev_err(hcd->self.controller, "init error %d\n",
+                               retval);
+                       return retval;
+               }
+               if ((retval = hcd->driver->start(hcd)) < 0) {
+                       dev_err(hcd->self.controller, "startup error %d\n",
+                               retval);
+                       return retval;
+               }
+       } else {
+               usb_disconnect(&hcd->self.root_hub);
+               hcd->driver->stop(hcd);
+               omap_ohci_clock_power(0);
+       }
+
+       return 0;
+}
+
 /**
  * usb_hcd_omap_probe - initialize OMAP-based HCDs
  * Context: !in_interrupt()
@@ -311,6 +353,13 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
        if (IS_ERR(usb_host_ck))
                return PTR_ERR(usb_host_ck);
 
+       usb_dc_ck = clk_get(0, "usb_dc_ck");
+       if (IS_ERR(usb_dc_ck)) {
+               clk_put(usb_host_ck);
+               return PTR_ERR(usb_dc_ck);
+       }
+
+
        hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
        if (!hcd) {
                retval = -ENOMEM;
@@ -330,20 +379,32 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
        ohci = hcd_to_ohci(hcd);
        ohci_hcd_init(ohci);
 
+       host_initialized = 0;
+       host_enabled = 1;
+
        retval = omap_start_hc(ohci, pdev);
        if (retval < 0)
                goto err2;
 
        retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
-       if (retval == 0)
-               return retval;
 
+       if (retval)
+               goto err3;
+
+       host_initialized = 1;
+
+       if (!host_enabled)
+               omap_ohci_clock_power(0);
+
+       return 0;
+err3:
        omap_stop_hc(pdev);
 err2:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
 err0:
+       clk_put(usb_dc_ck);
        clk_put(usb_host_ck);
        return retval;
 }
@@ -369,18 +430,21 @@ void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
        omap_stop_hc(pdev);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
+       clk_put(usb_dc_ck);
        clk_put(usb_host_ck);
 }
 
 /*-------------------------------------------------------------------------*/
 
-static int __devinit
+static int
 ohci_omap_start (struct usb_hcd *hcd)
 {
        struct omap_usb_config *config;
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
        int             ret;
 
+       if (!host_enabled)
+               return 0;
        config = hcd->self.controller->platform_data;
        if (config->otg || config->rwc)
                writel(OHCI_CTRL_RWC, &ohci->regs->control);