aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ep93xx/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ep93xx/clock.c')
-rw-r--r--arch/arm/mach-ep93xx/clock.c123
1 files changed, 88 insertions, 35 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index e8ebeaea6c48..6c4c1633ed12 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -21,15 +21,50 @@
21#include <asm/div64.h> 21#include <asm/div64.h>
22#include <mach/hardware.h> 22#include <mach/hardware.h>
23 23
24
25/*
26 * The EP93xx has two external crystal oscillators. To generate the
27 * required high-frequency clocks, the processor uses two phase-locked-
28 * loops (PLLs) to multiply the incoming external clock signal to much
29 * higher frequencies that are then divided down by programmable dividers
30 * to produce the needed clocks. The PLLs operate independently of one
31 * another.
32 */
33#define EP93XX_EXT_CLK_RATE 14745600
34#define EP93XX_EXT_RTC_RATE 32768
35
36
24struct clk { 37struct clk {
25 unsigned long rate; 38 unsigned long rate;
26 int users; 39 int users;
40 int sw_locked;
27 u32 enable_reg; 41 u32 enable_reg;
28 u32 enable_mask; 42 u32 enable_mask;
43
44 unsigned long (*get_rate)(struct clk *clk);
29}; 45};
30 46
31static struct clk clk_uart = { 47
32 .rate = 14745600, 48static unsigned long get_uart_rate(struct clk *clk);
49
50
51static struct clk clk_uart1 = {
52 .sw_locked = 1,
53 .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
54 .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U1EN,
55 .get_rate = get_uart_rate,
56};
57static struct clk clk_uart2 = {
58 .sw_locked = 1,
59 .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
60 .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U2EN,
61 .get_rate = get_uart_rate,
62};
63static struct clk clk_uart3 = {
64 .sw_locked = 1,
65 .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
66 .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U3EN,
67 .get_rate = get_uart_rate,
33}; 68};
34static struct clk clk_pll1; 69static struct clk clk_pll1;
35static struct clk clk_f; 70static struct clk clk_f;
@@ -37,73 +72,73 @@ static struct clk clk_h;
37static struct clk clk_p; 72static struct clk clk_p;
38static struct clk clk_pll2; 73static struct clk clk_pll2;
39static struct clk clk_usb_host = { 74static struct clk clk_usb_host = {
40 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 75 .enable_reg = EP93XX_SYSCON_PWRCNT,
41 .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, 76 .enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN,
42}; 77};
43 78
44/* DMA Clocks */ 79/* DMA Clocks */
45static struct clk clk_m2p0 = { 80static struct clk clk_m2p0 = {
46 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 81 .enable_reg = EP93XX_SYSCON_PWRCNT,
47 .enable_mask = 0x00020000, 82 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P0,
48}; 83};
49static struct clk clk_m2p1 = { 84static struct clk clk_m2p1 = {
50 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 85 .enable_reg = EP93XX_SYSCON_PWRCNT,
51 .enable_mask = 0x00010000, 86 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P1,
52}; 87};
53static struct clk clk_m2p2 = { 88static struct clk clk_m2p2 = {
54 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 89 .enable_reg = EP93XX_SYSCON_PWRCNT,
55 .enable_mask = 0x00080000, 90 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P2,
56}; 91};
57static struct clk clk_m2p3 = { 92static struct clk clk_m2p3 = {
58 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 93 .enable_reg = EP93XX_SYSCON_PWRCNT,
59 .enable_mask = 0x00040000, 94 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P3,
60}; 95};
61static struct clk clk_m2p4 = { 96static struct clk clk_m2p4 = {
62 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 97 .enable_reg = EP93XX_SYSCON_PWRCNT,
63 .enable_mask = 0x00200000, 98 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P4,
64}; 99};
65static struct clk clk_m2p5 = { 100static struct clk clk_m2p5 = {
66 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 101 .enable_reg = EP93XX_SYSCON_PWRCNT,
67 .enable_mask = 0x00100000, 102 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P5,
68}; 103};
69static struct clk clk_m2p6 = { 104static struct clk clk_m2p6 = {
70 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 105 .enable_reg = EP93XX_SYSCON_PWRCNT,
71 .enable_mask = 0x00800000, 106 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P6,
72}; 107};
73static struct clk clk_m2p7 = { 108static struct clk clk_m2p7 = {
74 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 109 .enable_reg = EP93XX_SYSCON_PWRCNT,
75 .enable_mask = 0x00400000, 110 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P7,
76}; 111};
77static struct clk clk_m2p8 = { 112static struct clk clk_m2p8 = {
78 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 113 .enable_reg = EP93XX_SYSCON_PWRCNT,
79 .enable_mask = 0x02000000, 114 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P8,
80}; 115};
81static struct clk clk_m2p9 = { 116static struct clk clk_m2p9 = {
82 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 117 .enable_reg = EP93XX_SYSCON_PWRCNT,
83 .enable_mask = 0x01000000, 118 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P9,
84}; 119};
85static struct clk clk_m2m0 = { 120static struct clk clk_m2m0 = {
86 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 121 .enable_reg = EP93XX_SYSCON_PWRCNT,
87 .enable_mask = 0x04000000, 122 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M0,
88}; 123};
89static struct clk clk_m2m1 = { 124static struct clk clk_m2m1 = {
90 .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, 125 .enable_reg = EP93XX_SYSCON_PWRCNT,
91 .enable_mask = 0x08000000, 126 .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M1,
92}; 127};
93 128
94#define INIT_CK(dev,con,ck) \ 129#define INIT_CK(dev,con,ck) \
95 { .dev_id = dev, .con_id = con, .clk = ck } 130 { .dev_id = dev, .con_id = con, .clk = ck }
96 131
97static struct clk_lookup clocks[] = { 132static struct clk_lookup clocks[] = {
98 INIT_CK("apb:uart1", NULL, &clk_uart), 133 INIT_CK("apb:uart1", NULL, &clk_uart1),
99 INIT_CK("apb:uart2", NULL, &clk_uart), 134 INIT_CK("apb:uart2", NULL, &clk_uart2),
100 INIT_CK("apb:uart3", NULL, &clk_uart), 135 INIT_CK("apb:uart3", NULL, &clk_uart3),
101 INIT_CK(NULL, "pll1", &clk_pll1), 136 INIT_CK(NULL, "pll1", &clk_pll1),
102 INIT_CK(NULL, "fclk", &clk_f), 137 INIT_CK(NULL, "fclk", &clk_f),
103 INIT_CK(NULL, "hclk", &clk_h), 138 INIT_CK(NULL, "hclk", &clk_h),
104 INIT_CK(NULL, "pclk", &clk_p), 139 INIT_CK(NULL, "pclk", &clk_p),
105 INIT_CK(NULL, "pll2", &clk_pll2), 140 INIT_CK(NULL, "pll2", &clk_pll2),
106 INIT_CK(NULL, "usb_host", &clk_usb_host), 141 INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
107 INIT_CK(NULL, "m2p0", &clk_m2p0), 142 INIT_CK(NULL, "m2p0", &clk_m2p0),
108 INIT_CK(NULL, "m2p1", &clk_m2p1), 143 INIT_CK(NULL, "m2p1", &clk_m2p1),
109 INIT_CK(NULL, "m2p2", &clk_m2p2), 144 INIT_CK(NULL, "m2p2", &clk_m2p2),
@@ -125,6 +160,8 @@ int clk_enable(struct clk *clk)
125 u32 value; 160 u32 value;
126 161
127 value = __raw_readl(clk->enable_reg); 162 value = __raw_readl(clk->enable_reg);
163 if (clk->sw_locked)
164 __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
128 __raw_writel(value | clk->enable_mask, clk->enable_reg); 165 __raw_writel(value | clk->enable_mask, clk->enable_reg);
129 } 166 }
130 167
@@ -138,13 +175,29 @@ void clk_disable(struct clk *clk)
138 u32 value; 175 u32 value;
139 176
140 value = __raw_readl(clk->enable_reg); 177 value = __raw_readl(clk->enable_reg);
178 if (clk->sw_locked)
179 __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
141 __raw_writel(value & ~clk->enable_mask, clk->enable_reg); 180 __raw_writel(value & ~clk->enable_mask, clk->enable_reg);
142 } 181 }
143} 182}
144EXPORT_SYMBOL(clk_disable); 183EXPORT_SYMBOL(clk_disable);
145 184
185static unsigned long get_uart_rate(struct clk *clk)
186{
187 u32 value;
188
189 value = __raw_readl(EP93XX_SYSCON_PWRCNT);
190 if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD)
191 return EP93XX_EXT_CLK_RATE;
192 else
193 return EP93XX_EXT_CLK_RATE / 2;
194}
195
146unsigned long clk_get_rate(struct clk *clk) 196unsigned long clk_get_rate(struct clk *clk)
147{ 197{
198 if (clk->get_rate)
199 return clk->get_rate(clk);
200
148 return clk->rate; 201 return clk->rate;
149} 202}
150EXPORT_SYMBOL(clk_get_rate); 203EXPORT_SYMBOL(clk_get_rate);
@@ -162,7 +215,7 @@ static unsigned long calc_pll_rate(u32 config_word)
162 unsigned long long rate; 215 unsigned long long rate;
163 int i; 216 int i;
164 217
165 rate = 14745600; 218 rate = EP93XX_EXT_CLK_RATE;
166 rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ 219 rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
167 rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ 220 rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
168 do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ 221 do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
@@ -195,7 +248,7 @@ static int __init ep93xx_clock_init(void)
195 248
196 value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); 249 value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
197 if (!(value & 0x00800000)) { /* PLL1 bypassed? */ 250 if (!(value & 0x00800000)) { /* PLL1 bypassed? */
198 clk_pll1.rate = 14745600; 251 clk_pll1.rate = EP93XX_EXT_CLK_RATE;
199 } else { 252 } else {
200 clk_pll1.rate = calc_pll_rate(value); 253 clk_pll1.rate = calc_pll_rate(value);
201 } 254 }
@@ -206,7 +259,7 @@ static int __init ep93xx_clock_init(void)
206 259
207 value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); 260 value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);
208 if (!(value & 0x00080000)) { /* PLL2 bypassed? */ 261 if (!(value & 0x00080000)) { /* PLL2 bypassed? */
209 clk_pll2.rate = 14745600; 262 clk_pll2.rate = EP93XX_EXT_CLK_RATE;
210 } else if (value & 0x00040000) { /* PLL2 enabled? */ 263 } else if (value & 0x00040000) { /* PLL2 enabled? */
211 clk_pll2.rate = calc_pll_rate(value); 264 clk_pll2.rate = calc_pll_rate(value);
212 } else { 265 } else {