diff options
| author | Hans-Christian Egtvedt <hcegtvedt@atmel.com> | 2007-12-19 03:29:19 -0500 |
|---|---|---|
| committer | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2008-04-19 20:40:08 -0400 |
| commit | 35bf50ccc80584a1404982f02fc4368e991ff55c (patch) | |
| tree | bb9add62acc4151b36c88b6bc893dc2000f08029 | |
| parent | e723ff666a5da8f7fda4e36ebfeafac2175a5c6e (diff) | |
avr32: Implement set_rate(), set_parent() and mode() for pll1
This patch is a take two of adding full functionality to PLL1 on
AT32AP7000. This allows board-specific code and drivers to configure
and enable PLL1. This is useful when precise control over the
frequency of e.g. a genclock is needed and requested by users for the
ABDAC device.
The patch is based upon previous patches from both Haavard Skinnemoen
and David Brownell.
Signed-off-by: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
| -rw-r--r-- | arch/avr32/mach-at32ap/at32ap700x.c | 153 |
1 files changed, 150 insertions, 3 deletions
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index 22c302ad9b3f..0f24b4f85c17 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
| 7 | */ | 7 | */ |
| 8 | #include <linux/clk.h> | 8 | #include <linux/clk.h> |
| 9 | #include <linux/delay.h> | ||
| 9 | #include <linux/fb.h> | 10 | #include <linux/fb.h> |
| 10 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| 11 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
| @@ -99,6 +100,9 @@ unsigned long at32ap7000_osc_rates[3] = { | |||
| 99 | [2] = 12000000, | 100 | [2] = 12000000, |
| 100 | }; | 101 | }; |
| 101 | 102 | ||
| 103 | static struct clk osc0; | ||
| 104 | static struct clk osc1; | ||
| 105 | |||
| 102 | static unsigned long osc_get_rate(struct clk *clk) | 106 | static unsigned long osc_get_rate(struct clk *clk) |
| 103 | { | 107 | { |
| 104 | return at32ap7000_osc_rates[clk->index]; | 108 | return at32ap7000_osc_rates[clk->index]; |
| @@ -108,9 +112,6 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control) | |||
| 108 | { | 112 | { |
| 109 | unsigned long div, mul, rate; | 113 | unsigned long div, mul, rate; |
| 110 | 114 | ||
| 111 | if (!(control & PM_BIT(PLLEN))) | ||
| 112 | return 0; | ||
| 113 | |||
| 114 | div = PM_BFEXT(PLLDIV, control) + 1; | 115 | div = PM_BFEXT(PLLDIV, control) + 1; |
| 115 | mul = PM_BFEXT(PLLMUL, control) + 1; | 116 | mul = PM_BFEXT(PLLMUL, control) + 1; |
| 116 | 117 | ||
| @@ -121,6 +122,71 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control) | |||
| 121 | return rate; | 122 | return rate; |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 125 | static long pll_set_rate(struct clk *clk, unsigned long rate, | ||
| 126 | u32 *pll_ctrl) | ||
| 127 | { | ||
| 128 | unsigned long mul; | ||
| 129 | unsigned long mul_best_fit = 0; | ||
| 130 | unsigned long div; | ||
| 131 | unsigned long div_min; | ||
| 132 | unsigned long div_max; | ||
| 133 | unsigned long div_best_fit = 0; | ||
| 134 | unsigned long base; | ||
| 135 | unsigned long pll_in; | ||
| 136 | unsigned long actual = 0; | ||
| 137 | unsigned long rate_error; | ||
| 138 | unsigned long rate_error_prev = ~0UL; | ||
| 139 | u32 ctrl; | ||
| 140 | |||
| 141 | /* Rate must be between 80 MHz and 200 Mhz. */ | ||
| 142 | if (rate < 80000000UL || rate > 200000000UL) | ||
| 143 | return -EINVAL; | ||
| 144 | |||
| 145 | ctrl = PM_BF(PLLOPT, 4); | ||
| 146 | base = clk->parent->get_rate(clk->parent); | ||
| 147 | |||
| 148 | /* PLL input frequency must be between 6 MHz and 32 MHz. */ | ||
| 149 | div_min = DIV_ROUND_UP(base, 32000000UL); | ||
| 150 | div_max = base / 6000000UL; | ||
| 151 | |||
| 152 | if (div_max < div_min) | ||
| 153 | return -EINVAL; | ||
| 154 | |||
| 155 | for (div = div_min; div <= div_max; div++) { | ||
| 156 | pll_in = (base + div / 2) / div; | ||
| 157 | mul = (rate + pll_in / 2) / pll_in; | ||
| 158 | |||
| 159 | if (mul == 0) | ||
| 160 | continue; | ||
| 161 | |||
| 162 | actual = pll_in * mul; | ||
| 163 | rate_error = abs(actual - rate); | ||
| 164 | |||
| 165 | if (rate_error < rate_error_prev) { | ||
| 166 | mul_best_fit = mul; | ||
| 167 | div_best_fit = div; | ||
| 168 | rate_error_prev = rate_error; | ||
| 169 | } | ||
| 170 | |||
| 171 | if (rate_error == 0) | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | |||
| 175 | if (div_best_fit == 0) | ||
| 176 | return -EINVAL; | ||
| 177 | |||
| 178 | ctrl |= PM_BF(PLLMUL, mul_best_fit - 1); | ||
| 179 | ctrl |= PM_BF(PLLDIV, div_best_fit - 1); | ||
| 180 | ctrl |= PM_BF(PLLCOUNT, 16); | ||
| 181 | |||
| 182 | if (clk->parent == &osc1) | ||
| 183 | ctrl |= PM_BIT(PLLOSC); | ||
| 184 | |||
| 185 | *pll_ctrl = ctrl; | ||
| 186 | |||
| 187 | return actual; | ||
| 188 | } | ||
| 189 | |||
| 124 | static unsigned long pll0_get_rate(struct clk *clk) | 190 | static unsigned long pll0_get_rate(struct clk *clk) |
| 125 | { | 191 | { |
| 126 | u32 control; | 192 | u32 control; |
| @@ -130,6 +196,41 @@ static unsigned long pll0_get_rate(struct clk *clk) | |||
| 130 | return pll_get_rate(clk, control); | 196 | return pll_get_rate(clk, control); |
| 131 | } | 197 | } |
| 132 | 198 | ||
| 199 | static void pll1_mode(struct clk *clk, int enabled) | ||
| 200 | { | ||
| 201 | unsigned long timeout; | ||
| 202 | u32 status; | ||
| 203 | u32 ctrl; | ||
| 204 | |||
| 205 | ctrl = pm_readl(PLL1); | ||
| 206 | |||
| 207 | if (enabled) { | ||
| 208 | if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) { | ||
| 209 | pr_debug("clk %s: failed to enable, rate not set\n", | ||
| 210 | clk->name); | ||
| 211 | return; | ||
| 212 | } | ||
| 213 | |||
| 214 | ctrl |= PM_BIT(PLLEN); | ||
| 215 | pm_writel(PLL1, ctrl); | ||
| 216 | |||
| 217 | /* Wait for PLL lock. */ | ||
| 218 | for (timeout = 10000; timeout; timeout--) { | ||
| 219 | status = pm_readl(ISR); | ||
| 220 | if (status & PM_BIT(LOCK1)) | ||
| 221 | break; | ||
| 222 | udelay(10); | ||
| 223 | } | ||
| 224 | |||
| 225 | if (!(status & PM_BIT(LOCK1))) | ||
| 226 | printk(KERN_ERR "clk %s: timeout waiting for lock\n", | ||
| 227 | clk->name); | ||
| 228 | } else { | ||
| 229 | ctrl &= ~PM_BIT(PLLEN); | ||
| 230 | pm_writel(PLL1, ctrl); | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 133 | static unsigned long pll1_get_rate(struct clk *clk) | 234 | static unsigned long pll1_get_rate(struct clk *clk) |
| 134 | { | 235 | { |
| 135 | u32 control; | 236 | u32 control; |
| @@ -139,6 +240,49 @@ static unsigned long pll1_get_rate(struct clk *clk) | |||
| 139 | return pll_get_rate(clk, control); | 240 | return pll_get_rate(clk, control); |
| 140 | } | 241 | } |
| 141 | 242 | ||
| 243 | static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply) | ||
| 244 | { | ||
| 245 | u32 ctrl = 0; | ||
| 246 | unsigned long actual_rate; | ||
| 247 | |||
| 248 | actual_rate = pll_set_rate(clk, rate, &ctrl); | ||
| 249 | |||
| 250 | if (apply) { | ||
| 251 | if (actual_rate != rate) | ||
| 252 | return -EINVAL; | ||
| 253 | if (clk->users > 0) | ||
| 254 | return -EBUSY; | ||
| 255 | pr_debug(KERN_INFO "clk %s: new rate %lu (actual rate %lu)\n", | ||
| 256 | clk->name, rate, actual_rate); | ||
| 257 | pm_writel(PLL1, ctrl); | ||
| 258 | } | ||
| 259 | |||
| 260 | return actual_rate; | ||
| 261 | } | ||
| 262 | |||
| 263 | static int pll1_set_parent(struct clk *clk, struct clk *parent) | ||
| 264 | { | ||
| 265 | u32 ctrl; | ||
| 266 | |||
| 267 | if (clk->users > 0) | ||
| 268 | return -EBUSY; | ||
| 269 | |||
| 270 | ctrl = pm_readl(PLL1); | ||
| 271 | WARN_ON(ctrl & PM_BIT(PLLEN)); | ||
| 272 | |||
| 273 | if (parent == &osc0) | ||
| 274 | ctrl &= ~PM_BIT(PLLOSC); | ||
| 275 | else if (parent == &osc1) | ||
| 276 | ctrl |= PM_BIT(PLLOSC); | ||
| 277 | else | ||
| 278 | return -EINVAL; | ||
| 279 | |||
| 280 | pm_writel(PLL1, ctrl); | ||
| 281 | clk->parent = parent; | ||
| 282 | |||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 142 | /* | 286 | /* |
| 143 | * The AT32AP7000 has five primary clock sources: One 32kHz | 287 | * The AT32AP7000 has five primary clock sources: One 32kHz |
| 144 | * oscillator, two crystal oscillators and two PLLs. | 288 | * oscillator, two crystal oscillators and two PLLs. |
| @@ -167,7 +311,10 @@ static struct clk pll0 = { | |||
| 167 | }; | 311 | }; |
| 168 | static struct clk pll1 = { | 312 | static struct clk pll1 = { |
| 169 | .name = "pll1", | 313 | .name = "pll1", |
| 314 | .mode = pll1_mode, | ||
| 170 | .get_rate = pll1_get_rate, | 315 | .get_rate = pll1_get_rate, |
| 316 | .set_rate = pll1_set_rate, | ||
| 317 | .set_parent = pll1_set_parent, | ||
| 171 | .parent = &osc0, | 318 | .parent = &osc0, |
| 172 | }; | 319 | }; |
| 173 | 320 | ||
