pwm-clock.c 11 KB

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