1/* linux/arch/arm/plat-s3c24xx/pwm-clock.c 2 * 3 * Copyright (c) 2007 Simtec Electronics 4 * Copyright (c) 2007, 2008 Ben Dooks 5 * Ben Dooks <ben-linux@fluff.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License. 10*/ 11 12#include <linux/init.h> 13#include <linux/module.h> 14#include <linux/kernel.h> 15#include <linux/list.h> 16#include <linux/errno.h> 17#include <linux/log2.h> 18#include <linux/clk.h> 19#include <linux/err.h> 20#include <linux/io.h> 21 22#include <mach/hardware.h> 23#include <mach/map.h> 24#include <asm/irq.h> 25 26#include <plat/clock.h> 27#include <plat/cpu.h> 28 29#include <plat/regs-timer.h> 30#include <mach/pwm-clock.h> 31 32/* Each of the timers 0 through 5 go through the following 33 * clock tree, with the inputs depending on the timers. 34 * 35 * pclk ---- [ prescaler 0 ] -+---> timer 0 36 * +---> timer 1 37 * 38 * pclk ---- [ prescaler 1 ] -+---> timer 2 39 * +---> timer 3 40 * \---> timer 4 41 * 42 * Which are fed into the timers as so: 43 * 44 * prescaled 0 ---- [ div 2,4,8,16 ] ---\ 45 * [mux] -> timer 0 46 * tclk 0 ------------------------------/ 47 * 48 * prescaled 0 ---- [ div 2,4,8,16 ] ---\ 49 * [mux] -> timer 1 50 * tclk 0 ------------------------------/ 51 * 52 * 53 * prescaled 1 ---- [ div 2,4,8,16 ] ---\ 54 * [mux] -> timer 2 55 * tclk 1 ------------------------------/ 56 * 57 * prescaled 1 ---- [ div 2,4,8,16 ] ---\ 58 * [mux] -> timer 3 59 * tclk 1 ------------------------------/ 60 * 61 * prescaled 1 ---- [ div 2,4,8, 16 ] --\ 62 * [mux] -> timer 4 63 * tclk 1 ------------------------------/ 64 * 65 * Since the mux and the divider are tied together in the 66 * same register space, it is impossible to set the parent 67 * and the rate at the same time. To avoid this, we add an 68 * intermediate 'prescaled-and-divided' clock to select 69 * as the parent for the timer input clock called tdiv. 70 * 71 * prescaled clk --> pwm-tdiv ---\ 72 * [ mux ] --> timer X 73 * tclk -------------------------/ 74*/ 75 76static struct clk clk_timer_scaler[]; 77 78static unsigned long clk_pwm_scaler_get_rate(struct clk *clk) 79{ 80 unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0); 81 82 if (clk == &clk_timer_scaler[1]) { 83 tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK; 84 tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT; 85 } else { 86 tcfg0 &= S3C2410_TCFG_PRESCALER0_MASK; 87 } 88 89 return clk_get_rate(clk->parent) / (tcfg0 + 1); 90} 91 92static unsigned long clk_pwm_scaler_round_rate(struct clk *clk, 93 unsigned long rate) 94{ 95 unsigned long parent_rate = clk_get_rate(clk->parent); 96 unsigned long divisor = parent_rate / rate; 97 98 if (divisor > 256) 99 divisor = 256; 100 else if (divisor < 2) 101 divisor = 2; 102 103 return parent_rate / divisor; 104} 105 106static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate) 107{ 108 unsigned long round = clk_pwm_scaler_round_rate(clk, rate); 109 unsigned long tcfg0; 110 unsigned long divisor; 111 unsigned long flags; 112 113 divisor = clk_get_rate(clk->parent) / round; 114 divisor--; 115 116 local_irq_save(flags); 117 tcfg0 = __raw_readl(S3C2410_TCFG0); 118 119 if (clk == &clk_timer_scaler[1]) { 120 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; 121 tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT; 122 } else { 123 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; 124 tcfg0 |= divisor; 125 } 126 127 __raw_writel(tcfg0, S3C2410_TCFG0); 128 local_irq_restore(flags); 129 130 return 0; 131} 132 133static struct clk_ops clk_pwm_scaler_ops = { 134 .get_rate = clk_pwm_scaler_get_rate, 135 .set_rate = clk_pwm_scaler_set_rate, 136 .round_rate = clk_pwm_scaler_round_rate, 137}; 138 139static struct clk clk_timer_scaler[] = { 140 [0] = { 141 .name = "pwm-scaler0", 142 .id = -1, 143 .ops = &clk_pwm_scaler_ops, 144 }, 145 [1] = { 146 .name = "pwm-scaler1", 147 .id = -1, 148 .ops = &clk_pwm_scaler_ops, 149 }, 150}; 151 152static struct clk clk_timer_tclk[] = { 153 [0] = { 154 .name = "pwm-tclk0", 155 .id = -1, 156 }, 157 [1] = { 158 .name = "pwm-tclk1", 159 .id = -1, 160 }, 161}; 162 163struct pwm_tdiv_clk { 164 struct clk clk; 165 unsigned int divisor; 166}; 167 168static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk) 169{ 170 return container_of(clk, struct pwm_tdiv_clk, clk); 171} 172 173static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk) 174{ 175 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1); 176 unsigned int divisor; 177 178 tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id); 179 tcfg1 &= S3C2410_TCFG1_MUX_MASK; 180 181 if (pwm_cfg_src_is_tclk(tcfg1)) 182 divisor = to_tdiv(clk)->divisor; 183 else 184 divisor = tcfg_to_divisor(tcfg1); 185 186 return clk_get_rate(clk->parent) / divisor; 187} 188 189static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk, 190 unsigned long rate) 191{ 192 unsigned long parent_rate; 193 unsigned long divisor; 194 195 parent_rate = clk_get_rate(clk->parent); 196 divisor = parent_rate / rate; 197 198 if (divisor <= 1 && pwm_tdiv_has_div1()) 199 divisor = 1; 200 else if (divisor <= 2) 201 divisor = 2; 202 else if (divisor <= 4) 203 divisor = 4; 204 else if (divisor <= 8) 205 divisor = 8; 206 else 207 divisor = 16; 208 209 return parent_rate / divisor; 210} 211 212static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk) 213{ 214 return pwm_tdiv_div_bits(divclk->divisor); 215} 216 217static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk) 218{ 219 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1); 220 unsigned long bits = clk_pwm_tdiv_bits(divclk); 221 unsigned long flags; 222 unsigned long shift = S3C2410_TCFG1_SHIFT(divclk->clk.id); 223 224 local_irq_save(flags); 225 226 tcfg1 = __raw_readl(S3C2410_TCFG1); 227 tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift); 228 tcfg1 |= bits << shift; 229 __raw_writel(tcfg1, S3C2410_TCFG1); 230 231 local_irq_restore(flags); 232} 233 234static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate) 235{ 236 struct pwm_tdiv_clk *divclk = to_tdiv(clk); 237 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1); 238 unsigned long parent_rate = clk_get_rate(clk->parent); 239 unsigned long divisor; 240 241 tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id); 242 tcfg1 &= S3C2410_TCFG1_MUX_MASK; 243 244 rate = clk_round_rate(clk, rate); 245 divisor = parent_rate / rate; 246 247 if (divisor > 16) 248 return -EINVAL; 249 250 divclk->divisor = divisor; 251 252 /* Update the current MUX settings if we are currently 253 * selected as the clock source for this clock. */ 254 255 if (!pwm_cfg_src_is_tclk(tcfg1)) 256 clk_pwm_tdiv_update(divclk); 257 258 return 0; 259} 260 261static struct clk_ops clk_tdiv_ops = { 262 .get_rate = clk_pwm_tdiv_get_rate, 263 .set_rate = clk_pwm_tdiv_set_rate, 264 .round_rate = clk_pwm_tdiv_round_rate, 265}; 266 267static struct pwm_tdiv_clk clk_timer_tdiv[] = { 268 [0] = { 269 .clk = { 270 .name = "pwm-tdiv", 271 .ops = &clk_tdiv_ops, 272 .parent = &clk_timer_scaler[0], 273 }, 274 }, 275 [1] = { 276 .clk = { 277 .name = "pwm-tdiv", 278 .ops = &clk_tdiv_ops, 279 .parent = &clk_timer_scaler[0], 280 } 281 }, 282 [2] = { 283 .clk = { 284 .name = "pwm-tdiv", 285 .ops = &clk_tdiv_ops, 286 .parent = &clk_timer_scaler[1], 287 }, 288 }, 289 [3] = { 290 .clk = { 291 .name = "pwm-tdiv", 292 .ops = &clk_tdiv_ops, 293 .parent = &clk_timer_scaler[1], 294 }, 295 }, 296 [4] = { 297 .clk = { 298 .name = "pwm-tdiv", 299 .ops = &clk_tdiv_ops, 300 .parent = &clk_timer_scaler[1], 301 }, 302 }, 303}; 304 305static int __init clk_pwm_tdiv_register(unsigned int id) 306{ 307 struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id]; 308 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1); 309 310 tcfg1 >>= S3C2410_TCFG1_SHIFT(id); 311 tcfg1 &= S3C2410_TCFG1_MUX_MASK; 312 313 divclk->clk.id = id; 314 divclk->divisor = tcfg_to_divisor(tcfg1); 315 316 return s3c24xx_register_clock(&divclk->clk); 317} 318 319static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id) 320{ 321 return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0]; 322} 323 324static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id) 325{ 326 return &clk_timer_tdiv[id].clk; 327} 328 329static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent) 330{ 331 unsigned int id = clk->id; 332 unsigned long tcfg1; 333 unsigned long flags; 334 unsigned long bits; 335 unsigned long shift = S3C2410_TCFG1_SHIFT(id); 336 337 if (parent == s3c24xx_pwmclk_tclk(id)) 338 bits = S3C_TCFG1_MUX_TCLK << shift; 339 else if (parent == s3c24xx_pwmclk_tdiv(id)) 340 bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift; 341 else 342 return -EINVAL; 343 344 clk->parent = parent; 345 346 local_irq_save(flags); 347 348 tcfg1 = __raw_readl(S3C2410_TCFG1); 349 tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift); 350 __raw_writel(tcfg1 | bits, S3C2410_TCFG1); 351 352 local_irq_restore(flags); 353 354 return 0; 355} 356 357static struct clk_ops clk_tin_ops = { 358 .set_parent = clk_pwm_tin_set_parent, 359}; 360 361static struct clk clk_tin[] = { 362 [0] = { 363 .name = "pwm-tin", 364 .id = 0, 365 .ops = &clk_tin_ops, 366 }, 367 [1] = { 368 .name = "pwm-tin", 369 .id = 1, 370 .ops = &clk_tin_ops, 371 }, 372 [2] = { 373 .name = "pwm-tin", 374 .id = 2, 375 .ops = &clk_tin_ops, 376 }, 377 [3] = { 378 .name = "pwm-tin", 379 .id = 3, 380 .ops = &clk_tin_ops, 381 }, 382 [4] = { 383 .name = "pwm-tin", 384 .id = 4, 385 .ops = &clk_tin_ops, 386 }, 387}; 388 389static __init int clk_pwm_tin_register(struct clk *pwm) 390{ 391 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1); 392 unsigned int id = pwm->id; 393 394 struct clk *parent; 395 int ret; 396 397 ret = s3c24xx_register_clock(pwm); 398 if (ret < 0) 399 return ret; 400 401 tcfg1 >>= S3C2410_TCFG1_SHIFT(id); 402 tcfg1 &= S3C2410_TCFG1_MUX_MASK; 403 404 if (pwm_cfg_src_is_tclk(tcfg1)) 405 parent = s3c24xx_pwmclk_tclk(id); 406 else 407 parent = s3c24xx_pwmclk_tdiv(id); 408 409 return clk_set_parent(pwm, parent); 410} 411 412/** 413 * s3c_pwmclk_init() - initialise pwm clocks 414 * 415 * Initialise and register the clocks which provide the inputs for the 416 * pwm timer blocks. 417 * 418 * Note, this call is required by the time core, so must be called after 419 * the base clocks are added and before any of the initcalls are run. 420 */ 421__init void s3c_pwmclk_init(void) 422{ 423 struct clk *clk_timers; 424 unsigned int clk; 425 int ret; 426 427 clk_timers = clk_get(NULL, "timers"); 428 if (IS_ERR(clk_timers)) { 429 printk(KERN_ERR "%s: no parent clock\n", __func__); 430 return; 431 } 432 433 for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) 434 clk_timer_scaler[clk].parent = clk_timers; 435 436 s3c_register_clocks(clk_timer_scaler, ARRAY_SIZE(clk_timer_scaler)); 437 s3c_register_clocks(clk_timer_tclk, ARRAY_SIZE(clk_timer_tclk)); 438 439 for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) { 440 ret = clk_pwm_tdiv_register(clk); 441 442 if (ret < 0) { 443 printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk); 444 return; 445 } 446 } 447 448 for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) { 449 ret = clk_pwm_tin_register(&clk_tin[clk]); 450 if (ret < 0) { 451 printk(KERN_ERR "error adding pwm%d tin clock\n", clk); 452 return; 453 } 454 } 455} 456