sckc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. * drivers/clk/at91/sckc.c
  3. *
  4. * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. */
  12. #include <linux/clk-provider.h>
  13. #include <linux/clkdev.h>
  14. #include <linux/delay.h>
  15. #include <linux/of.h>
  16. #include <linux/of_address.h>
  17. #include <linux/io.h>
  18. #define SLOW_CLOCK_FREQ 32768
  19. #define SLOWCK_SW_CYCLES 5
  20. #define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
  21. SLOW_CLOCK_FREQ)
  22. #define AT91_SCKC_CR 0x00
  23. #define AT91_SCKC_RCEN (1 << 0)
  24. #define AT91_SCKC_OSC32EN (1 << 1)
  25. #define AT91_SCKC_OSC32BYP (1 << 2)
  26. #define AT91_SCKC_OSCSEL (1 << 3)
  27. struct clk_slow_osc {
  28. struct clk_hw hw;
  29. void __iomem *sckcr;
  30. unsigned long startup_usec;
  31. };
  32. #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
  33. struct clk_sama5d4_slow_osc {
  34. struct clk_hw hw;
  35. void __iomem *sckcr;
  36. unsigned long startup_usec;
  37. bool prepared;
  38. };
  39. #define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw)
  40. struct clk_slow_rc_osc {
  41. struct clk_hw hw;
  42. void __iomem *sckcr;
  43. unsigned long frequency;
  44. unsigned long accuracy;
  45. unsigned long startup_usec;
  46. };
  47. #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
  48. struct clk_sam9x5_slow {
  49. struct clk_hw hw;
  50. void __iomem *sckcr;
  51. u8 parent;
  52. };
  53. #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
  54. static int clk_slow_osc_prepare(struct clk_hw *hw)
  55. {
  56. struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  57. void __iomem *sckcr = osc->sckcr;
  58. u32 tmp = readl(sckcr);
  59. if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN))
  60. return 0;
  61. writel(tmp | AT91_SCKC_OSC32EN, sckcr);
  62. usleep_range(osc->startup_usec, osc->startup_usec + 1);
  63. return 0;
  64. }
  65. static void clk_slow_osc_unprepare(struct clk_hw *hw)
  66. {
  67. struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  68. void __iomem *sckcr = osc->sckcr;
  69. u32 tmp = readl(sckcr);
  70. if (tmp & AT91_SCKC_OSC32BYP)
  71. return;
  72. writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
  73. }
  74. static int clk_slow_osc_is_prepared(struct clk_hw *hw)
  75. {
  76. struct clk_slow_osc *osc = to_clk_slow_osc(hw);
  77. void __iomem *sckcr = osc->sckcr;
  78. u32 tmp = readl(sckcr);
  79. if (tmp & AT91_SCKC_OSC32BYP)
  80. return 1;
  81. return !!(tmp & AT91_SCKC_OSC32EN);
  82. }
  83. static const struct clk_ops slow_osc_ops = {
  84. .prepare = clk_slow_osc_prepare,
  85. .unprepare = clk_slow_osc_unprepare,
  86. .is_prepared = clk_slow_osc_is_prepared,
  87. };
  88. static struct clk_hw * __init
  89. at91_clk_register_slow_osc(void __iomem *sckcr,
  90. const char *name,
  91. const char *parent_name,
  92. unsigned long startup,
  93. bool bypass)
  94. {
  95. struct clk_slow_osc *osc;
  96. struct clk_hw *hw;
  97. struct clk_init_data init;
  98. int ret;
  99. if (!sckcr || !name || !parent_name)
  100. return ERR_PTR(-EINVAL);
  101. osc = kzalloc(sizeof(*osc), GFP_KERNEL);
  102. if (!osc)
  103. return ERR_PTR(-ENOMEM);
  104. init.name = name;
  105. init.ops = &slow_osc_ops;
  106. init.parent_names = &parent_name;
  107. init.num_parents = 1;
  108. init.flags = CLK_IGNORE_UNUSED;
  109. osc->hw.init = &init;
  110. osc->sckcr = sckcr;
  111. osc->startup_usec = startup;
  112. if (bypass)
  113. writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
  114. sckcr);
  115. hw = &osc->hw;
  116. ret = clk_hw_register(NULL, &osc->hw);
  117. if (ret) {
  118. kfree(osc);
  119. hw = ERR_PTR(ret);
  120. }
  121. return hw;
  122. }
  123. static void __init
  124. of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr)
  125. {
  126. struct clk_hw *hw;
  127. const char *parent_name;
  128. const char *name = np->name;
  129. u32 startup;
  130. bool bypass;
  131. parent_name = of_clk_get_parent_name(np, 0);
  132. of_property_read_string(np, "clock-output-names", &name);
  133. of_property_read_u32(np, "atmel,startup-time-usec", &startup);
  134. bypass = of_property_read_bool(np, "atmel,osc-bypass");
  135. hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
  136. bypass);
  137. if (IS_ERR(hw))
  138. return;
  139. of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
  140. }
  141. static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
  142. unsigned long parent_rate)
  143. {
  144. struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
  145. return osc->frequency;
  146. }
  147. static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
  148. unsigned long parent_acc)
  149. {
  150. struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
  151. return osc->accuracy;
  152. }
  153. static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
  154. {
  155. struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
  156. void __iomem *sckcr = osc->sckcr;
  157. writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
  158. usleep_range(osc->startup_usec, osc->startup_usec + 1);
  159. return 0;
  160. }
  161. static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
  162. {
  163. struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
  164. void __iomem *sckcr = osc->sckcr;
  165. writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
  166. }
  167. static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
  168. {
  169. struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
  170. return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
  171. }
  172. static const struct clk_ops slow_rc_osc_ops = {
  173. .prepare = clk_slow_rc_osc_prepare,
  174. .unprepare = clk_slow_rc_osc_unprepare,
  175. .is_prepared = clk_slow_rc_osc_is_prepared,
  176. .recalc_rate = clk_slow_rc_osc_recalc_rate,
  177. .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
  178. };
  179. static struct clk_hw * __init
  180. at91_clk_register_slow_rc_osc(void __iomem *sckcr,
  181. const char *name,
  182. unsigned long frequency,
  183. unsigned long accuracy,
  184. unsigned long startup)
  185. {
  186. struct clk_slow_rc_osc *osc;
  187. struct clk_hw *hw;
  188. struct clk_init_data init;
  189. int ret;
  190. if (!sckcr || !name)
  191. return ERR_PTR(-EINVAL);
  192. osc = kzalloc(sizeof(*osc), GFP_KERNEL);
  193. if (!osc)
  194. return ERR_PTR(-ENOMEM);
  195. init.name = name;
  196. init.ops = &slow_rc_osc_ops;
  197. init.parent_names = NULL;
  198. init.num_parents = 0;
  199. init.flags = CLK_IGNORE_UNUSED;
  200. osc->hw.init = &init;
  201. osc->sckcr = sckcr;
  202. osc->frequency = frequency;
  203. osc->accuracy = accuracy;
  204. osc->startup_usec = startup;
  205. hw = &osc->hw;
  206. ret = clk_hw_register(NULL, &osc->hw);
  207. if (ret) {
  208. kfree(osc);
  209. hw = ERR_PTR(ret);
  210. }
  211. return hw;
  212. }
  213. static void __init
  214. of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr)
  215. {
  216. struct clk_hw *hw;
  217. u32 frequency = 0;
  218. u32 accuracy = 0;
  219. u32 startup = 0;
  220. const char *name = np->name;
  221. of_property_read_string(np, "clock-output-names", &name);
  222. of_property_read_u32(np, "clock-frequency", &frequency);
  223. of_property_read_u32(np, "clock-accuracy", &accuracy);
  224. of_property_read_u32(np, "atmel,startup-time-usec", &startup);
  225. hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
  226. startup);
  227. if (IS_ERR(hw))
  228. return;
  229. of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
  230. }
  231. static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
  232. {
  233. struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
  234. void __iomem *sckcr = slowck->sckcr;
  235. u32 tmp;
  236. if (index > 1)
  237. return -EINVAL;
  238. tmp = readl(sckcr);
  239. if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
  240. (index && (tmp & AT91_SCKC_OSCSEL)))
  241. return 0;
  242. if (index)
  243. tmp |= AT91_SCKC_OSCSEL;
  244. else
  245. tmp &= ~AT91_SCKC_OSCSEL;
  246. writel(tmp, sckcr);
  247. usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
  248. return 0;
  249. }
  250. static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
  251. {
  252. struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
  253. return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
  254. }
  255. static const struct clk_ops sam9x5_slow_ops = {
  256. .set_parent = clk_sam9x5_slow_set_parent,
  257. .get_parent = clk_sam9x5_slow_get_parent,
  258. };
  259. static struct clk_hw * __init
  260. at91_clk_register_sam9x5_slow(void __iomem *sckcr,
  261. const char *name,
  262. const char **parent_names,
  263. int num_parents)
  264. {
  265. struct clk_sam9x5_slow *slowck;
  266. struct clk_hw *hw;
  267. struct clk_init_data init;
  268. int ret;
  269. if (!sckcr || !name || !parent_names || !num_parents)
  270. return ERR_PTR(-EINVAL);
  271. slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
  272. if (!slowck)
  273. return ERR_PTR(-ENOMEM);
  274. init.name = name;
  275. init.ops = &sam9x5_slow_ops;
  276. init.parent_names = parent_names;
  277. init.num_parents = num_parents;
  278. init.flags = 0;
  279. slowck->hw.init = &init;
  280. slowck->sckcr = sckcr;
  281. slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
  282. hw = &slowck->hw;
  283. ret = clk_hw_register(NULL, &slowck->hw);
  284. if (ret) {
  285. kfree(slowck);
  286. hw = ERR_PTR(ret);
  287. }
  288. return hw;
  289. }
  290. static void __init
  291. of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr)
  292. {
  293. struct clk_hw *hw;
  294. const char *parent_names[2];
  295. unsigned int num_parents;
  296. const char *name = np->name;
  297. num_parents = of_clk_get_parent_count(np);
  298. if (num_parents == 0 || num_parents > 2)
  299. return;
  300. of_clk_parent_fill(np, parent_names, num_parents);
  301. of_property_read_string(np, "clock-output-names", &name);
  302. hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
  303. num_parents);
  304. if (IS_ERR(hw))
  305. return;
  306. of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
  307. }
  308. static const struct of_device_id sckc_clk_ids[] __initconst = {
  309. /* Slow clock */
  310. {
  311. .compatible = "atmel,at91sam9x5-clk-slow-osc",
  312. .data = of_at91sam9x5_clk_slow_osc_setup,
  313. },
  314. {
  315. .compatible = "atmel,at91sam9x5-clk-slow-rc-osc",
  316. .data = of_at91sam9x5_clk_slow_rc_osc_setup,
  317. },
  318. {
  319. .compatible = "atmel,at91sam9x5-clk-slow",
  320. .data = of_at91sam9x5_clk_slow_setup,
  321. },
  322. { /*sentinel*/ }
  323. };
  324. static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
  325. {
  326. struct device_node *childnp;
  327. void (*clk_setup)(struct device_node *, void __iomem *);
  328. const struct of_device_id *clk_id;
  329. void __iomem *regbase = of_iomap(np, 0);
  330. if (!regbase)
  331. return;
  332. for_each_child_of_node(np, childnp) {
  333. clk_id = of_match_node(sckc_clk_ids, childnp);
  334. if (!clk_id)
  335. continue;
  336. clk_setup = clk_id->data;
  337. clk_setup(childnp, regbase);
  338. }
  339. }
  340. CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
  341. of_at91sam9x5_sckc_setup);
  342. static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
  343. {
  344. struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
  345. if (osc->prepared)
  346. return 0;
  347. /*
  348. * Assume that if it has already been selected (for example by the
  349. * bootloader), enough time has aready passed.
  350. */
  351. if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) {
  352. osc->prepared = true;
  353. return 0;
  354. }
  355. usleep_range(osc->startup_usec, osc->startup_usec + 1);
  356. osc->prepared = true;
  357. return 0;
  358. }
  359. static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
  360. {
  361. struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
  362. return osc->prepared;
  363. }
  364. static const struct clk_ops sama5d4_slow_osc_ops = {
  365. .prepare = clk_sama5d4_slow_osc_prepare,
  366. .is_prepared = clk_sama5d4_slow_osc_is_prepared,
  367. };
  368. static void __init of_sama5d4_sckc_setup(struct device_node *np)
  369. {
  370. void __iomem *regbase = of_iomap(np, 0);
  371. struct clk_hw *hw;
  372. struct clk_sama5d4_slow_osc *osc;
  373. struct clk_init_data init;
  374. const char *xtal_name;
  375. const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
  376. bool bypass;
  377. int ret;
  378. if (!regbase)
  379. return;
  380. hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
  381. NULL, 0, 32768,
  382. 250000000);
  383. if (IS_ERR(hw))
  384. return;
  385. xtal_name = of_clk_get_parent_name(np, 0);
  386. bypass = of_property_read_bool(np, "atmel,osc-bypass");
  387. osc = kzalloc(sizeof(*osc), GFP_KERNEL);
  388. if (!osc)
  389. return;
  390. init.name = parent_names[1];
  391. init.ops = &sama5d4_slow_osc_ops;
  392. init.parent_names = &xtal_name;
  393. init.num_parents = 1;
  394. init.flags = CLK_IGNORE_UNUSED;
  395. osc->hw.init = &init;
  396. osc->sckcr = regbase;
  397. osc->startup_usec = 1200000;
  398. if (bypass)
  399. writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase);
  400. hw = &osc->hw;
  401. ret = clk_hw_register(NULL, &osc->hw);
  402. if (ret) {
  403. kfree(osc);
  404. return;
  405. }
  406. hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
  407. if (IS_ERR(hw))
  408. return;
  409. of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
  410. }
  411. CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
  412. of_sama5d4_sckc_setup);