/kern_2.6.32/arch/arm/plat-s3c/pwm-clock.c

http://omnia2droid.googlecode.com/ · C · 435 lines · 312 code · 67 blank · 56 comment · 31 complexity · aa49ab3b1f73846662a8fe74fae42138 MD5 · raw file

  1. /* linux/arch/arm/plat-s3c/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. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/kernel.h>
  14. #include <linux/list.h>
  15. #include <linux/errno.h>
  16. #include <linux/clk.h>
  17. #include <linux/err.h>
  18. #include <linux/io.h>
  19. #include <mach/hardware.h>
  20. #include <mach/map.h>
  21. #include <asm/irq.h>
  22. #include <plat/clock.h>
  23. #include <plat/cpu.h>
  24. #include <plat/regs-timer.h>
  25. /* Each of the timers 0 through 5 go through the following
  26. * clock tree, with the inputs depending on the timers.
  27. *
  28. * pclk ---- [ prescaler 0 ] -+---> timer 0
  29. * +---> timer 1
  30. *
  31. * pclk ---- [ prescaler 1 ] -+---> timer 2
  32. * +---> timer 3
  33. * \---> timer 4
  34. *
  35. * Which are fed into the timers as so:
  36. *
  37. * prescaled 0 ---- [ div 2,4,8,16 ] ---\
  38. * [mux] -> timer 0
  39. * tclk 0 ------------------------------/
  40. *
  41. * prescaled 0 ---- [ div 2,4,8,16 ] ---\
  42. * [mux] -> timer 1
  43. * tclk 0 ------------------------------/
  44. *
  45. *
  46. * prescaled 1 ---- [ div 2,4,8,16 ] ---\
  47. * [mux] -> timer 2
  48. * tclk 1 ------------------------------/
  49. *
  50. * prescaled 1 ---- [ div 2,4,8,16 ] ---\
  51. * [mux] -> timer 3
  52. * tclk 1 ------------------------------/
  53. *
  54. * prescaled 1 ---- [ div 2,4,8, 16 ] --\
  55. * [mux] -> timer 4
  56. * tclk 1 ------------------------------/
  57. *
  58. * Since the mux and the divider are tied together in the
  59. * same register space, it is impossible to set the parent
  60. * and the rate at the same time. To avoid this, we add an
  61. * intermediate 'prescaled-and-divided' clock to select
  62. * as the parent for the timer input clock called tdiv.
  63. *
  64. * prescaled clk --> pwm-tdiv ---\
  65. * [ mux ] --> timer X
  66. * tclk -------------------------/
  67. */
  68. static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
  69. {
  70. unsigned long tcfg0 = __raw_readl(S3C_TCFG0);
  71. if (clk->id == 1) {
  72. tcfg0 &= S3C_TCFG_PRESCALER1_MASK;
  73. tcfg0 >>= S3C_TCFG_PRESCALER1_SHIFT;
  74. } else {
  75. tcfg0 &= S3C_TCFG_PRESCALER0_MASK;
  76. }
  77. return clk_get_rate(clk->parent) / (tcfg0 + 1);
  78. }
  79. /* TODO - add set rate calls. */
  80. static struct clk clk_timer_scaler[] = {
  81. [0] = {
  82. .name = "pwm-scaler0",
  83. .id = -1,
  84. .get_rate = clk_pwm_scaler_getrate,
  85. },
  86. [1] = {
  87. .name = "pwm-scaler1",
  88. .id = -1,
  89. .get_rate = clk_pwm_scaler_getrate,
  90. },
  91. };
  92. static struct clk clk_timer_tclk[] = {
  93. [0] = {
  94. .name = "pwm-tclk0",
  95. .id = -1,
  96. },
  97. [1] = {
  98. .name = "pwm-tclk1",
  99. .id = -1,
  100. },
  101. };
  102. struct pwm_tdiv_clk {
  103. struct clk clk;
  104. unsigned int divisor;
  105. };
  106. static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
  107. {
  108. return container_of(clk, struct pwm_tdiv_clk, clk);
  109. }
  110. static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
  111. {
  112. return 1 << (1 + tcfg1);
  113. }
  114. static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
  115. {
  116. unsigned long tcfg1 = __raw_readl(S3C_TCFG1);
  117. unsigned int divisor;
  118. tcfg1 >>= S3C_TCFG1_SHIFT(clk->id);
  119. tcfg1 &= S3C_TCFG1_MUX_MASK;
  120. if (tcfg1 == S3C_TCFG1_MUX_TCLK)
  121. divisor = to_tdiv(clk)->divisor;
  122. else
  123. divisor = tcfg_to_divisor(tcfg1);
  124. return clk_get_rate(clk->parent) / divisor;
  125. }
  126. static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
  127. unsigned long rate)
  128. {
  129. unsigned long parent_rate;
  130. unsigned long divisor;
  131. parent_rate = clk_get_rate(clk->parent);
  132. divisor = parent_rate / rate;
  133. if (divisor <= 2)
  134. divisor = 2;
  135. else if (divisor <= 4)
  136. divisor = 4;
  137. else if (divisor <= 8)
  138. divisor = 8;
  139. else
  140. divisor = 16;
  141. return parent_rate / divisor;
  142. }
  143. static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
  144. {
  145. unsigned long bits;
  146. switch (divclk->divisor) {
  147. case 2:
  148. bits = S3C_TCFG1_MUX_DIV2;
  149. break;
  150. case 4:
  151. bits = S3C_TCFG1_MUX_DIV4;
  152. break;
  153. case 8:
  154. bits = S3C_TCFG1_MUX_DIV8;
  155. break;
  156. case 16:
  157. default:
  158. bits = S3C_TCFG1_MUX_DIV16;
  159. break;
  160. }
  161. return bits;
  162. }
  163. static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
  164. {
  165. unsigned long tcfg1 = __raw_readl(S3C_TCFG1);
  166. unsigned long bits = clk_pwm_tdiv_bits(divclk);
  167. unsigned long flags;
  168. unsigned long shift = S3C_TCFG1_SHIFT(divclk->clk.id);
  169. local_irq_save(flags);
  170. tcfg1 = __raw_readl(S3C_TCFG1);
  171. tcfg1 &= ~(S3C_TCFG1_MUX_MASK << shift);
  172. tcfg1 |= bits << shift;
  173. __raw_writel(tcfg1, S3C_TCFG1);
  174. local_irq_restore(flags);
  175. }
  176. static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
  177. {
  178. struct pwm_tdiv_clk *divclk = to_tdiv(clk);
  179. unsigned long tcfg1 = __raw_readl(S3C_TCFG1);
  180. unsigned long parent_rate = clk_get_rate(clk->parent);
  181. unsigned long divisor;
  182. tcfg1 >>= S3C_TCFG1_SHIFT(clk->id);
  183. tcfg1 &= S3C_TCFG1_MUX_MASK;
  184. rate = clk_round_rate(clk, rate);
  185. divisor = parent_rate / rate;
  186. if (divisor > 16)
  187. return -EINVAL;
  188. divclk->divisor = divisor;
  189. /* Update the current MUX settings if we are currently
  190. * selected as the clock source for this clock. */
  191. if (tcfg1 != S3C_TCFG1_MUX_TCLK)
  192. clk_pwm_tdiv_update(divclk);
  193. return 0;
  194. }
  195. static struct pwm_tdiv_clk clk_timer_tdiv[] = {
  196. [0] = {
  197. .clk = {
  198. .name = "pwm-tdiv",
  199. .parent = &clk_timer_scaler[0],
  200. .get_rate = clk_pwm_tdiv_get_rate,
  201. .set_rate = clk_pwm_tdiv_set_rate,
  202. .round_rate = clk_pwm_tdiv_round_rate,
  203. },
  204. },
  205. [1] = {
  206. .clk = {
  207. .name = "pwm-tdiv",
  208. .parent = &clk_timer_scaler[0],
  209. .get_rate = clk_pwm_tdiv_get_rate,
  210. .set_rate = clk_pwm_tdiv_set_rate,
  211. .round_rate = clk_pwm_tdiv_round_rate,
  212. }
  213. },
  214. [2] = {
  215. .clk = {
  216. .name = "pwm-tdiv",
  217. .parent = &clk_timer_scaler[1],
  218. .get_rate = clk_pwm_tdiv_get_rate,
  219. .set_rate = clk_pwm_tdiv_set_rate,
  220. .round_rate = clk_pwm_tdiv_round_rate,
  221. },
  222. },
  223. [3] = {
  224. .clk = {
  225. .name = "pwm-tdiv",
  226. .parent = &clk_timer_scaler[1],
  227. .get_rate = clk_pwm_tdiv_get_rate,
  228. .set_rate = clk_pwm_tdiv_set_rate,
  229. .round_rate = clk_pwm_tdiv_round_rate,
  230. },
  231. },
  232. [4] = {
  233. .clk = {
  234. .name = "pwm-tdiv",
  235. .parent = &clk_timer_scaler[1],
  236. .get_rate = clk_pwm_tdiv_get_rate,
  237. .set_rate = clk_pwm_tdiv_set_rate,
  238. .round_rate = clk_pwm_tdiv_round_rate,
  239. },
  240. },
  241. };
  242. static int __init clk_pwm_tdiv_register(unsigned int id)
  243. {
  244. struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
  245. unsigned long tcfg1 = __raw_readl(S3C_TCFG1);
  246. tcfg1 >>= S3C_TCFG1_SHIFT(id);
  247. tcfg1 &= S3C_TCFG1_MUX_MASK;
  248. divclk->clk.id = id;
  249. divclk->divisor = tcfg_to_divisor(tcfg1);
  250. return s3c_register_clock(&divclk->clk);
  251. }
  252. static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
  253. {
  254. return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
  255. }
  256. static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
  257. {
  258. return &clk_timer_tdiv[id].clk;
  259. }
  260. static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
  261. {
  262. unsigned int id = clk->id;
  263. unsigned long tcfg1;
  264. unsigned long flags;
  265. unsigned long bits;
  266. unsigned long shift = S3C_TCFG1_SHIFT(id);
  267. if (parent == s3c24xx_pwmclk_tclk(id))
  268. bits = S3C_TCFG1_MUX_TCLK << shift;
  269. else if (parent == s3c24xx_pwmclk_tdiv(id))
  270. bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
  271. else
  272. return -EINVAL;
  273. clk->parent = parent;
  274. local_irq_save(flags);
  275. tcfg1 = __raw_readl(S3C_TCFG1);
  276. tcfg1 &= ~(S3C_TCFG1_MUX_MASK << shift);
  277. __raw_writel(tcfg1 | bits, S3C_TCFG1);
  278. local_irq_restore(flags);
  279. return 0;
  280. }
  281. static struct clk clk_tin[] = {
  282. [0] = {
  283. .name = "pwm-tin",
  284. .id = 0,
  285. .set_parent = clk_pwm_tin_set_parent,
  286. },
  287. [1] = {
  288. .name = "pwm-tin",
  289. .id = 1,
  290. .set_parent = clk_pwm_tin_set_parent,
  291. },
  292. [2] = {
  293. .name = "pwm-tin",
  294. .id = 2,
  295. .set_parent = clk_pwm_tin_set_parent,
  296. },
  297. [3] = {
  298. .name = "pwm-tin",
  299. .id = 3,
  300. .set_parent = clk_pwm_tin_set_parent,
  301. },
  302. [4] = {
  303. .name = "pwm-tin",
  304. .id = 4,
  305. .set_parent = clk_pwm_tin_set_parent,
  306. },
  307. };
  308. static __init int clk_pwm_tin_register(struct clk *pwm)
  309. {
  310. unsigned long tcfg1 = __raw_readl(S3C_TCFG1);
  311. unsigned int id = pwm->id;
  312. struct clk *parent;
  313. int ret;
  314. ret = s3c_register_clock(pwm);
  315. if (ret < 0)
  316. return ret;
  317. tcfg1 >>= S3C_TCFG1_SHIFT(id);
  318. tcfg1 &= S3C_TCFG1_MUX_MASK;
  319. if (tcfg1 == S3C_TCFG1_MUX_TCLK)
  320. parent = s3c24xx_pwmclk_tclk(id);
  321. else
  322. parent = s3c24xx_pwmclk_tdiv(id);
  323. return clk_set_parent(pwm, parent);
  324. }
  325. static __init int s3c24xx_pwmclk_init(void)
  326. {
  327. struct clk *clk_timers;
  328. unsigned int clk;
  329. int ret;
  330. clk_timers = clk_get(NULL, "timers");
  331. if (IS_ERR(clk_timers)) {
  332. printk(KERN_ERR "%s: no parent clock\n", __func__);
  333. return -EINVAL;
  334. }
  335. for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
  336. clk_timer_scaler[clk].parent = clk_timers;
  337. ret = s3c_register_clock(&clk_timer_scaler[clk]);
  338. if (ret < 0) {
  339. printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
  340. goto err;
  341. }
  342. }
  343. for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
  344. ret = s3c_register_clock(&clk_timer_tclk[clk]);
  345. if (ret < 0) {
  346. printk(KERN_ERR "error adding pww tclk%d\n", clk);
  347. goto err;
  348. }
  349. }
  350. for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
  351. ret = clk_pwm_tdiv_register(clk);
  352. if (ret < 0) {
  353. printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
  354. goto err;
  355. }
  356. }
  357. for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
  358. ret = clk_pwm_tin_register(&clk_tin[clk]);
  359. if (ret < 0) {
  360. printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
  361. goto err;
  362. }
  363. }
  364. return 0;
  365. err:
  366. return ret;
  367. }
  368. arch_initcall(s3c24xx_pwmclk_init);