USB: at91-ohci, handle extra at91sam9261 ahb clock
[safe/jmp/linux-2.6] / drivers / usb / host / ohci-at91.c
index 53f62cf..d849c80 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/hardware.h>
 #include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
 
 #ifndef CONFIG_ARCH_AT91
 #error "CONFIG_ARCH_AT91 must be defined."
 #endif
 
-/* interface and function clocks */
-static struct clk *iclk, *fclk;
+/* interface and function clocks; sometimes also an AHB clock */
+static struct clk *iclk, *fclk, *hclk;
 static int clocked;
 
 extern int usb_disabled(void);
 
 /*-------------------------------------------------------------------------*/
 
+static void at91_start_clock(void)
+{
+       if (cpu_is_at91sam9261())
+               clk_enable(hclk);
+       clk_enable(iclk);
+       clk_enable(fclk);
+       clocked = 1;
+}
+
+static void at91_stop_clock(void)
+{
+       clk_disable(fclk);
+       clk_disable(iclk);
+       if (cpu_is_at91sam9261())
+               clk_disable(hclk);
+       clocked = 0;
+}
+
 static void at91_start_hc(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
@@ -41,9 +60,7 @@ static void at91_start_hc(struct platform_device *pdev)
        /*
         * Start the USB clocks.
         */
-       clk_enable(iclk);
-       clk_enable(fclk);
-       clocked = 1;
+       at91_start_clock();
 
        /*
         * The USB host controller must remain in reset.
@@ -66,9 +83,7 @@ static void at91_stop_hc(struct platform_device *pdev)
        /*
         * Stop the USB clocks.
         */
-       clk_disable(fclk);
-       clk_disable(iclk);
-       clocked = 0;
+       at91_stop_clock();
 }
 
 
@@ -126,6 +141,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
 
        iclk = clk_get(&pdev->dev, "ohci_clk");
        fclk = clk_get(&pdev->dev, "uhpck");
+       if (cpu_is_at91sam9261())
+               hclk = clk_get(&pdev->dev, "hck0");
 
        at91_start_hc(pdev);
        ohci_hcd_init(hcd_to_ohci(hcd));
@@ -137,6 +154,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
        /* Error handling */
        at91_stop_hc(pdev);
 
+       if (cpu_is_at91sam9261())
+               clk_put(hclk);
        clk_put(fclk);
        clk_put(iclk);
 
@@ -170,11 +189,12 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd,
        at91_stop_hc(pdev);
        iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-       disable_irq_wake(hcd->irq);
 
+       if (cpu_is_at91sam9261())
+               clk_put(hclk);
        clk_put(fclk);
        clk_put(iclk);
-       fclk = iclk = NULL;
+       fclk = iclk = hclk = NULL;
 
        dev_set_drvdata(&pdev->dev, NULL);
        return 0;
@@ -271,8 +291,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
 
        if (device_may_wakeup(&pdev->dev))
                enable_irq_wake(hcd->irq);
-       else
-               disable_irq_wake(hcd->irq);
 
        /*
         * The integrated transceivers seem unable to notice disconnect,
@@ -283,9 +301,7 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
         */
        if (at91_suspend_entering_slow_clock()) {
                ohci_usb_reset (ohci);
-               clk_disable(fclk);
-               clk_disable(iclk);
-               clocked = 0;
+               at91_stop_clock();
        }
 
        return 0;
@@ -293,11 +309,13 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
 
 static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
 {
-       if (!clocked) {
-               clk_enable(iclk);
-               clk_enable(fclk);
-               clocked = 1;
-       }
+       struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(hcd->irq);
+
+       if (!clocked)
+               at91_start_clock();
 
        return 0;
 }