diff options
author | Andrew Victor <andrew@sanpeople.com> | 2007-02-16 13:18:58 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-16 18:32:24 -0500 |
commit | ed077bb714816e942ea9b740156659a28a34112f (patch) | |
tree | 55300d9853b47112a17c4ff5495b8eb22461377a /drivers/usb/host | |
parent | ebaf494e2ad19c92d3af48feaf9d65fdb656ea28 (diff) |
USB: at91-ohci, handle extra at91sam9261 ahb clock
The AT91SAM9261 needs to activate an AHB clock (HCK0) to use the USB Host
controller. Previously clock.c would just enable it at startup, but now
all the unused clocks are automatically disabled.
Based on patch from Nicolas Ferre.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ohci-at91.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 930346487278..d849c809acbd 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c | |||
@@ -18,19 +18,38 @@ | |||
18 | #include <asm/mach-types.h> | 18 | #include <asm/mach-types.h> |
19 | #include <asm/hardware.h> | 19 | #include <asm/hardware.h> |
20 | #include <asm/arch/board.h> | 20 | #include <asm/arch/board.h> |
21 | #include <asm/arch/cpu.h> | ||
21 | 22 | ||
22 | #ifndef CONFIG_ARCH_AT91 | 23 | #ifndef CONFIG_ARCH_AT91 |
23 | #error "CONFIG_ARCH_AT91 must be defined." | 24 | #error "CONFIG_ARCH_AT91 must be defined." |
24 | #endif | 25 | #endif |
25 | 26 | ||
26 | /* interface and function clocks */ | 27 | /* interface and function clocks; sometimes also an AHB clock */ |
27 | static struct clk *iclk, *fclk; | 28 | static struct clk *iclk, *fclk, *hclk; |
28 | static int clocked; | 29 | static int clocked; |
29 | 30 | ||
30 | extern int usb_disabled(void); | 31 | extern int usb_disabled(void); |
31 | 32 | ||
32 | /*-------------------------------------------------------------------------*/ | 33 | /*-------------------------------------------------------------------------*/ |
33 | 34 | ||
35 | static void at91_start_clock(void) | ||
36 | { | ||
37 | if (cpu_is_at91sam9261()) | ||
38 | clk_enable(hclk); | ||
39 | clk_enable(iclk); | ||
40 | clk_enable(fclk); | ||
41 | clocked = 1; | ||
42 | } | ||
43 | |||
44 | static void at91_stop_clock(void) | ||
45 | { | ||
46 | clk_disable(fclk); | ||
47 | clk_disable(iclk); | ||
48 | if (cpu_is_at91sam9261()) | ||
49 | clk_disable(hclk); | ||
50 | clocked = 0; | ||
51 | } | ||
52 | |||
34 | static void at91_start_hc(struct platform_device *pdev) | 53 | static void at91_start_hc(struct platform_device *pdev) |
35 | { | 54 | { |
36 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | 55 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
@@ -41,9 +60,7 @@ static void at91_start_hc(struct platform_device *pdev) | |||
41 | /* | 60 | /* |
42 | * Start the USB clocks. | 61 | * Start the USB clocks. |
43 | */ | 62 | */ |
44 | clk_enable(iclk); | 63 | at91_start_clock(); |
45 | clk_enable(fclk); | ||
46 | clocked = 1; | ||
47 | 64 | ||
48 | /* | 65 | /* |
49 | * The USB host controller must remain in reset. | 66 | * The USB host controller must remain in reset. |
@@ -66,9 +83,7 @@ static void at91_stop_hc(struct platform_device *pdev) | |||
66 | /* | 83 | /* |
67 | * Stop the USB clocks. | 84 | * Stop the USB clocks. |
68 | */ | 85 | */ |
69 | clk_disable(fclk); | 86 | at91_stop_clock(); |
70 | clk_disable(iclk); | ||
71 | clocked = 0; | ||
72 | } | 87 | } |
73 | 88 | ||
74 | 89 | ||
@@ -126,6 +141,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, | |||
126 | 141 | ||
127 | iclk = clk_get(&pdev->dev, "ohci_clk"); | 142 | iclk = clk_get(&pdev->dev, "ohci_clk"); |
128 | fclk = clk_get(&pdev->dev, "uhpck"); | 143 | fclk = clk_get(&pdev->dev, "uhpck"); |
144 | if (cpu_is_at91sam9261()) | ||
145 | hclk = clk_get(&pdev->dev, "hck0"); | ||
129 | 146 | ||
130 | at91_start_hc(pdev); | 147 | at91_start_hc(pdev); |
131 | ohci_hcd_init(hcd_to_ohci(hcd)); | 148 | ohci_hcd_init(hcd_to_ohci(hcd)); |
@@ -137,6 +154,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, | |||
137 | /* Error handling */ | 154 | /* Error handling */ |
138 | at91_stop_hc(pdev); | 155 | at91_stop_hc(pdev); |
139 | 156 | ||
157 | if (cpu_is_at91sam9261()) | ||
158 | clk_put(hclk); | ||
140 | clk_put(fclk); | 159 | clk_put(fclk); |
141 | clk_put(iclk); | 160 | clk_put(iclk); |
142 | 161 | ||
@@ -171,9 +190,11 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd, | |||
171 | iounmap(hcd->regs); | 190 | iounmap(hcd->regs); |
172 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 191 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
173 | 192 | ||
193 | if (cpu_is_at91sam9261()) | ||
194 | clk_put(hclk); | ||
174 | clk_put(fclk); | 195 | clk_put(fclk); |
175 | clk_put(iclk); | 196 | clk_put(iclk); |
176 | fclk = iclk = NULL; | 197 | fclk = iclk = hclk = NULL; |
177 | 198 | ||
178 | dev_set_drvdata(&pdev->dev, NULL); | 199 | dev_set_drvdata(&pdev->dev, NULL); |
179 | return 0; | 200 | return 0; |
@@ -280,9 +301,7 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) | |||
280 | */ | 301 | */ |
281 | if (at91_suspend_entering_slow_clock()) { | 302 | if (at91_suspend_entering_slow_clock()) { |
282 | ohci_usb_reset (ohci); | 303 | ohci_usb_reset (ohci); |
283 | clk_disable(fclk); | 304 | at91_stop_clock(); |
284 | clk_disable(iclk); | ||
285 | clocked = 0; | ||
286 | } | 305 | } |
287 | 306 | ||
288 | return 0; | 307 | return 0; |
@@ -295,11 +314,8 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) | |||
295 | if (device_may_wakeup(&pdev->dev)) | 314 | if (device_may_wakeup(&pdev->dev)) |
296 | disable_irq_wake(hcd->irq); | 315 | disable_irq_wake(hcd->irq); |
297 | 316 | ||
298 | if (!clocked) { | 317 | if (!clocked) |
299 | clk_enable(iclk); | 318 | at91_start_clock(); |
300 | clk_enable(fclk); | ||
301 | clocked = 1; | ||
302 | } | ||
303 | 319 | ||
304 | return 0; | 320 | return 0; |
305 | } | 321 | } |