aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/octeon2-common.c
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2011-04-27 13:54:20 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-03 13:09:31 -0400
commitf5ced99725d05f521ef0f597e688c19835e59c55 (patch)
treead43e943897b61d26d009a14c325fe9782aa1765 /drivers/usb/host/octeon2-common.c
parentdbc265465a3fc8ac8d75d3ede7e84ea122a8fd0a (diff)
USB: octeon2-common: Don't reinitialize the clocks.
The UCTL clock initialization will cause the ehci and ohci blocks to become inoperable if the clocks are reinitialized. Check to see if the clocks have already been initialized. Also use a mutex to protect the clock initialization code so that there can be no attempt to use the clocks before they are fully configured. Signed-off-by: David Daney <ddaney@caviumnetworks.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/octeon2-common.c')
-rw-r--r--drivers/usb/host/octeon2-common.c38
1 files changed, 24 insertions, 14 deletions
diff --git a/drivers/usb/host/octeon2-common.c b/drivers/usb/host/octeon2-common.c
index 72d672cfcf39..5a0feed03561 100644
--- a/drivers/usb/host/octeon2-common.c
+++ b/drivers/usb/host/octeon2-common.c
@@ -3,18 +3,19 @@
3 * License. See the file "COPYING" in the main directory of this archive 3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details. 4 * for more details.
5 * 5 *
6 * Copyright (C) 2010 Cavium Networks 6 * Copyright (C) 2010, 2011 Cavium Networks
7 */ 7 */
8 8
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/mutex.h>
10#include <linux/delay.h> 11#include <linux/delay.h>
11 12
12#include <asm/atomic.h>
13
14#include <asm/octeon/octeon.h> 13#include <asm/octeon/octeon.h>
15#include <asm/octeon/cvmx-uctlx-defs.h> 14#include <asm/octeon/cvmx-uctlx-defs.h>
16 15
17static atomic_t octeon2_usb_clock_start_cnt = ATOMIC_INIT(0); 16static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
17
18static int octeon2_usb_clock_start_cnt;
18 19
19void octeon2_usb_clocks_start(void) 20void octeon2_usb_clocks_start(void)
20{ 21{
@@ -26,8 +27,12 @@ void octeon2_usb_clocks_start(void)
26 int i; 27 int i;
27 unsigned long io_clk_64_to_ns; 28 unsigned long io_clk_64_to_ns;
28 29
29 if (atomic_inc_return(&octeon2_usb_clock_start_cnt) != 1) 30
30 return; 31 mutex_lock(&octeon2_usb_clocks_mutex);
32
33 octeon2_usb_clock_start_cnt++;
34 if (octeon2_usb_clock_start_cnt != 1)
35 goto exit;
31 36
32 io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); 37 io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
33 38
@@ -43,6 +48,13 @@ void octeon2_usb_clocks_start(void)
43 48
44 /* Step 3: Configure the reference clock, PHY, and HCLK */ 49 /* Step 3: Configure the reference clock, PHY, and HCLK */
45 clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); 50 clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
51
52 /*
53 * If the UCTL looks like it has already been started, skip
54 * the initialization, otherwise bus errors are obtained.
55 */
56 if (clk_rst_ctl.s.hrst)
57 goto end_clock;
46 /* 3a */ 58 /* 3a */
47 clk_rst_ctl.s.p_por = 1; 59 clk_rst_ctl.s.p_por = 1;
48 clk_rst_ctl.s.hrst = 0; 60 clk_rst_ctl.s.hrst = 0;
@@ -158,6 +170,7 @@ void octeon2_usb_clocks_start(void)
158 clk_rst_ctl.s.hrst = 1; 170 clk_rst_ctl.s.hrst = 1;
159 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); 171 cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
160 172
173end_clock:
161 /* Now we can set some other registers. */ 174 /* Now we can set some other registers. */
162 175
163 for (i = 0; i <= 1; i++) { 176 for (i = 0; i <= 1; i++) {
@@ -168,18 +181,15 @@ void octeon2_usb_clocks_start(void)
168 cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), 181 cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
169 port_ctl_status.u64); 182 port_ctl_status.u64);
170 } 183 }
184exit:
185 mutex_unlock(&octeon2_usb_clocks_mutex);
171} 186}
172EXPORT_SYMBOL(octeon2_usb_clocks_start); 187EXPORT_SYMBOL(octeon2_usb_clocks_start);
173 188
174void octeon2_usb_clocks_stop(void) 189void octeon2_usb_clocks_stop(void)
175{ 190{
176 union cvmx_uctlx_if_ena if_ena; 191 mutex_lock(&octeon2_usb_clocks_mutex);
177 192 octeon2_usb_clock_start_cnt--;
178 if (atomic_dec_return(&octeon2_usb_clock_start_cnt) != 0) 193 mutex_unlock(&octeon2_usb_clocks_mutex);
179 return;
180
181 if_ena.u64 = 0;
182 if_ena.s.en = 0;
183 cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
184} 194}
185EXPORT_SYMBOL(octeon2_usb_clocks_stop); 195EXPORT_SYMBOL(octeon2_usb_clocks_stop);