clk-axm5516.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * drivers/clk/clk-axm5516.c
  4. *
  5. * Provides clock implementations for three different types of clock devices on
  6. * the Axxia device: PLL clock, a clock divider and a clock mux.
  7. *
  8. * Copyright (C) 2014 LSI Corporation
  9. */
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/slab.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/of.h>
  15. #include <linux/of_address.h>
  16. #include <linux/clk-provider.h>
  17. #include <linux/regmap.h>
  18. #include <dt-bindings/clock/lsi,axm5516-clks.h>
  19. /**
  20. * struct axxia_clk - Common struct to all Axxia clocks.
  21. * @hw: clk_hw for the common clk framework
  22. * @regmap: Regmap for the clock control registers
  23. */
  24. struct axxia_clk {
  25. struct clk_hw hw;
  26. struct regmap *regmap;
  27. };
  28. #define to_axxia_clk(_hw) container_of(_hw, struct axxia_clk, hw)
  29. /**
  30. * struct axxia_pllclk - Axxia PLL generated clock.
  31. * @aclk: Common struct
  32. * @reg: Offset into regmap for PLL control register
  33. */
  34. struct axxia_pllclk {
  35. struct axxia_clk aclk;
  36. u32 reg;
  37. };
  38. #define to_axxia_pllclk(_aclk) container_of(_aclk, struct axxia_pllclk, aclk)
  39. /**
  40. * axxia_pllclk_recalc - Calculate the PLL generated clock rate given the
  41. * parent clock rate.
  42. */
  43. static unsigned long
  44. axxia_pllclk_recalc(struct clk_hw *hw, unsigned long parent_rate)
  45. {
  46. struct axxia_clk *aclk = to_axxia_clk(hw);
  47. struct axxia_pllclk *pll = to_axxia_pllclk(aclk);
  48. unsigned long rate, fbdiv, refdiv, postdiv;
  49. u32 control;
  50. regmap_read(aclk->regmap, pll->reg, &control);
  51. postdiv = ((control >> 0) & 0xf) + 1;
  52. fbdiv = ((control >> 4) & 0xfff) + 3;
  53. refdiv = ((control >> 16) & 0x1f) + 1;
  54. rate = (parent_rate / (refdiv * postdiv)) * fbdiv;
  55. return rate;
  56. }
  57. static const struct clk_ops axxia_pllclk_ops = {
  58. .recalc_rate = axxia_pllclk_recalc,
  59. };
  60. /**
  61. * struct axxia_divclk - Axxia clock divider
  62. * @aclk: Common struct
  63. * @reg: Offset into regmap for PLL control register
  64. * @shift: Bit position for divider value
  65. * @width: Number of bits in divider value
  66. */
  67. struct axxia_divclk {
  68. struct axxia_clk aclk;
  69. u32 reg;
  70. u32 shift;
  71. u32 width;
  72. };
  73. #define to_axxia_divclk(_aclk) container_of(_aclk, struct axxia_divclk, aclk)
  74. /**
  75. * axxia_divclk_recalc_rate - Calculate clock divider output rage
  76. */
  77. static unsigned long
  78. axxia_divclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
  79. {
  80. struct axxia_clk *aclk = to_axxia_clk(hw);
  81. struct axxia_divclk *divclk = to_axxia_divclk(aclk);
  82. u32 ctrl, div;
  83. regmap_read(aclk->regmap, divclk->reg, &ctrl);
  84. div = 1 + ((ctrl >> divclk->shift) & ((1 << divclk->width)-1));
  85. return parent_rate / div;
  86. }
  87. static const struct clk_ops axxia_divclk_ops = {
  88. .recalc_rate = axxia_divclk_recalc_rate,
  89. };
  90. /**
  91. * struct axxia_clkmux - Axxia clock mux
  92. * @aclk: Common struct
  93. * @reg: Offset into regmap for PLL control register
  94. * @shift: Bit position for selection value
  95. * @width: Number of bits in selection value
  96. */
  97. struct axxia_clkmux {
  98. struct axxia_clk aclk;
  99. u32 reg;
  100. u32 shift;
  101. u32 width;
  102. };
  103. #define to_axxia_clkmux(_aclk) container_of(_aclk, struct axxia_clkmux, aclk)
  104. /**
  105. * axxia_clkmux_get_parent - Return the index of selected parent clock
  106. */
  107. static u8 axxia_clkmux_get_parent(struct clk_hw *hw)
  108. {
  109. struct axxia_clk *aclk = to_axxia_clk(hw);
  110. struct axxia_clkmux *mux = to_axxia_clkmux(aclk);
  111. u32 ctrl, parent;
  112. regmap_read(aclk->regmap, mux->reg, &ctrl);
  113. parent = (ctrl >> mux->shift) & ((1 << mux->width) - 1);
  114. return (u8) parent;
  115. }
  116. static const struct clk_ops axxia_clkmux_ops = {
  117. .get_parent = axxia_clkmux_get_parent,
  118. };
  119. /*
  120. * PLLs
  121. */
  122. static struct axxia_pllclk clk_fab_pll = {
  123. .aclk.hw.init = &(struct clk_init_data){
  124. .name = "clk_fab_pll",
  125. .parent_names = (const char *[]){
  126. "clk_ref0"
  127. },
  128. .num_parents = 1,
  129. .ops = &axxia_pllclk_ops,
  130. },
  131. .reg = 0x01800,
  132. };
  133. static struct axxia_pllclk clk_cpu_pll = {
  134. .aclk.hw.init = &(struct clk_init_data){
  135. .name = "clk_cpu_pll",
  136. .parent_names = (const char *[]){
  137. "clk_ref0"
  138. },
  139. .num_parents = 1,
  140. .ops = &axxia_pllclk_ops,
  141. },
  142. .reg = 0x02000,
  143. };
  144. static struct axxia_pllclk clk_sys_pll = {
  145. .aclk.hw.init = &(struct clk_init_data){
  146. .name = "clk_sys_pll",
  147. .parent_names = (const char *[]){
  148. "clk_ref0"
  149. },
  150. .num_parents = 1,
  151. .ops = &axxia_pllclk_ops,
  152. },
  153. .reg = 0x02800,
  154. };
  155. static struct axxia_pllclk clk_sm0_pll = {
  156. .aclk.hw.init = &(struct clk_init_data){
  157. .name = "clk_sm0_pll",
  158. .parent_names = (const char *[]){
  159. "clk_ref2"
  160. },
  161. .num_parents = 1,
  162. .ops = &axxia_pllclk_ops,
  163. },
  164. .reg = 0x03000,
  165. };
  166. static struct axxia_pllclk clk_sm1_pll = {
  167. .aclk.hw.init = &(struct clk_init_data){
  168. .name = "clk_sm1_pll",
  169. .parent_names = (const char *[]){
  170. "clk_ref1"
  171. },
  172. .num_parents = 1,
  173. .ops = &axxia_pllclk_ops,
  174. },
  175. .reg = 0x03800,
  176. };
  177. /*
  178. * Clock dividers
  179. */
  180. static struct axxia_divclk clk_cpu0_div = {
  181. .aclk.hw.init = &(struct clk_init_data){
  182. .name = "clk_cpu0_div",
  183. .parent_names = (const char *[]){
  184. "clk_cpu_pll"
  185. },
  186. .num_parents = 1,
  187. .ops = &axxia_divclk_ops,
  188. },
  189. .reg = 0x10008,
  190. .shift = 0,
  191. .width = 4,
  192. };
  193. static struct axxia_divclk clk_cpu1_div = {
  194. .aclk.hw.init = &(struct clk_init_data){
  195. .name = "clk_cpu1_div",
  196. .parent_names = (const char *[]){
  197. "clk_cpu_pll"
  198. },
  199. .num_parents = 1,
  200. .ops = &axxia_divclk_ops,
  201. },
  202. .reg = 0x10008,
  203. .shift = 4,
  204. .width = 4,
  205. };
  206. static struct axxia_divclk clk_cpu2_div = {
  207. .aclk.hw.init = &(struct clk_init_data){
  208. .name = "clk_cpu2_div",
  209. .parent_names = (const char *[]){
  210. "clk_cpu_pll"
  211. },
  212. .num_parents = 1,
  213. .ops = &axxia_divclk_ops,
  214. },
  215. .reg = 0x10008,
  216. .shift = 8,
  217. .width = 4,
  218. };
  219. static struct axxia_divclk clk_cpu3_div = {
  220. .aclk.hw.init = &(struct clk_init_data){
  221. .name = "clk_cpu3_div",
  222. .parent_names = (const char *[]){
  223. "clk_cpu_pll"
  224. },
  225. .num_parents = 1,
  226. .ops = &axxia_divclk_ops,
  227. },
  228. .reg = 0x10008,
  229. .shift = 12,
  230. .width = 4,
  231. };
  232. static struct axxia_divclk clk_nrcp_div = {
  233. .aclk.hw.init = &(struct clk_init_data){
  234. .name = "clk_nrcp_div",
  235. .parent_names = (const char *[]){
  236. "clk_sys_pll"
  237. },
  238. .num_parents = 1,
  239. .ops = &axxia_divclk_ops,
  240. },
  241. .reg = 0x1000c,
  242. .shift = 0,
  243. .width = 4,
  244. };
  245. static struct axxia_divclk clk_sys_div = {
  246. .aclk.hw.init = &(struct clk_init_data){
  247. .name = "clk_sys_div",
  248. .parent_names = (const char *[]){
  249. "clk_sys_pll"
  250. },
  251. .num_parents = 1,
  252. .ops = &axxia_divclk_ops,
  253. },
  254. .reg = 0x1000c,
  255. .shift = 4,
  256. .width = 4,
  257. };
  258. static struct axxia_divclk clk_fab_div = {
  259. .aclk.hw.init = &(struct clk_init_data){
  260. .name = "clk_fab_div",
  261. .parent_names = (const char *[]){
  262. "clk_fab_pll"
  263. },
  264. .num_parents = 1,
  265. .ops = &axxia_divclk_ops,
  266. },
  267. .reg = 0x1000c,
  268. .shift = 8,
  269. .width = 4,
  270. };
  271. static struct axxia_divclk clk_per_div = {
  272. .aclk.hw.init = &(struct clk_init_data){
  273. .name = "clk_per_div",
  274. .parent_names = (const char *[]){
  275. "clk_sm1_pll"
  276. },
  277. .num_parents = 1,
  278. .ops = &axxia_divclk_ops,
  279. },
  280. .reg = 0x1000c,
  281. .shift = 12,
  282. .width = 4,
  283. };
  284. static struct axxia_divclk clk_mmc_div = {
  285. .aclk.hw.init = &(struct clk_init_data){
  286. .name = "clk_mmc_div",
  287. .parent_names = (const char *[]){
  288. "clk_sm1_pll"
  289. },
  290. .num_parents = 1,
  291. .ops = &axxia_divclk_ops,
  292. },
  293. .reg = 0x1000c,
  294. .shift = 16,
  295. .width = 4,
  296. };
  297. /*
  298. * Clock MUXes
  299. */
  300. static struct axxia_clkmux clk_cpu0_mux = {
  301. .aclk.hw.init = &(struct clk_init_data){
  302. .name = "clk_cpu0",
  303. .parent_names = (const char *[]){
  304. "clk_ref0",
  305. "clk_cpu_pll",
  306. "clk_cpu0_div",
  307. "clk_cpu0_div"
  308. },
  309. .num_parents = 4,
  310. .ops = &axxia_clkmux_ops,
  311. },
  312. .reg = 0x10000,
  313. .shift = 0,
  314. .width = 2,
  315. };
  316. static struct axxia_clkmux clk_cpu1_mux = {
  317. .aclk.hw.init = &(struct clk_init_data){
  318. .name = "clk_cpu1",
  319. .parent_names = (const char *[]){
  320. "clk_ref0",
  321. "clk_cpu_pll",
  322. "clk_cpu1_div",
  323. "clk_cpu1_div"
  324. },
  325. .num_parents = 4,
  326. .ops = &axxia_clkmux_ops,
  327. },
  328. .reg = 0x10000,
  329. .shift = 2,
  330. .width = 2,
  331. };
  332. static struct axxia_clkmux clk_cpu2_mux = {
  333. .aclk.hw.init = &(struct clk_init_data){
  334. .name = "clk_cpu2",
  335. .parent_names = (const char *[]){
  336. "clk_ref0",
  337. "clk_cpu_pll",
  338. "clk_cpu2_div",
  339. "clk_cpu2_div"
  340. },
  341. .num_parents = 4,
  342. .ops = &axxia_clkmux_ops,
  343. },
  344. .reg = 0x10000,
  345. .shift = 4,
  346. .width = 2,
  347. };
  348. static struct axxia_clkmux clk_cpu3_mux = {
  349. .aclk.hw.init = &(struct clk_init_data){
  350. .name = "clk_cpu3",
  351. .parent_names = (const char *[]){
  352. "clk_ref0",
  353. "clk_cpu_pll",
  354. "clk_cpu3_div",
  355. "clk_cpu3_div"
  356. },
  357. .num_parents = 4,
  358. .ops = &axxia_clkmux_ops,
  359. },
  360. .reg = 0x10000,
  361. .shift = 6,
  362. .width = 2,
  363. };
  364. static struct axxia_clkmux clk_nrcp_mux = {
  365. .aclk.hw.init = &(struct clk_init_data){
  366. .name = "clk_nrcp",
  367. .parent_names = (const char *[]){
  368. "clk_ref0",
  369. "clk_sys_pll",
  370. "clk_nrcp_div",
  371. "clk_nrcp_div"
  372. },
  373. .num_parents = 4,
  374. .ops = &axxia_clkmux_ops,
  375. },
  376. .reg = 0x10004,
  377. .shift = 0,
  378. .width = 2,
  379. };
  380. static struct axxia_clkmux clk_sys_mux = {
  381. .aclk.hw.init = &(struct clk_init_data){
  382. .name = "clk_sys",
  383. .parent_names = (const char *[]){
  384. "clk_ref0",
  385. "clk_sys_pll",
  386. "clk_sys_div",
  387. "clk_sys_div"
  388. },
  389. .num_parents = 4,
  390. .ops = &axxia_clkmux_ops,
  391. },
  392. .reg = 0x10004,
  393. .shift = 2,
  394. .width = 2,
  395. };
  396. static struct axxia_clkmux clk_fab_mux = {
  397. .aclk.hw.init = &(struct clk_init_data){
  398. .name = "clk_fab",
  399. .parent_names = (const char *[]){
  400. "clk_ref0",
  401. "clk_fab_pll",
  402. "clk_fab_div",
  403. "clk_fab_div"
  404. },
  405. .num_parents = 4,
  406. .ops = &axxia_clkmux_ops,
  407. },
  408. .reg = 0x10004,
  409. .shift = 4,
  410. .width = 2,
  411. };
  412. static struct axxia_clkmux clk_per_mux = {
  413. .aclk.hw.init = &(struct clk_init_data){
  414. .name = "clk_per",
  415. .parent_names = (const char *[]){
  416. "clk_ref1",
  417. "clk_per_div"
  418. },
  419. .num_parents = 2,
  420. .ops = &axxia_clkmux_ops,
  421. },
  422. .reg = 0x10004,
  423. .shift = 6,
  424. .width = 1,
  425. };
  426. static struct axxia_clkmux clk_mmc_mux = {
  427. .aclk.hw.init = &(struct clk_init_data){
  428. .name = "clk_mmc",
  429. .parent_names = (const char *[]){
  430. "clk_ref1",
  431. "clk_mmc_div"
  432. },
  433. .num_parents = 2,
  434. .ops = &axxia_clkmux_ops,
  435. },
  436. .reg = 0x10004,
  437. .shift = 9,
  438. .width = 1,
  439. };
  440. /* Table of all supported clocks indexed by the clock identifiers from the
  441. * device tree binding
  442. */
  443. static struct axxia_clk *axmclk_clocks[] = {
  444. [AXXIA_CLK_FAB_PLL] = &clk_fab_pll.aclk,
  445. [AXXIA_CLK_CPU_PLL] = &clk_cpu_pll.aclk,
  446. [AXXIA_CLK_SYS_PLL] = &clk_sys_pll.aclk,
  447. [AXXIA_CLK_SM0_PLL] = &clk_sm0_pll.aclk,
  448. [AXXIA_CLK_SM1_PLL] = &clk_sm1_pll.aclk,
  449. [AXXIA_CLK_FAB_DIV] = &clk_fab_div.aclk,
  450. [AXXIA_CLK_SYS_DIV] = &clk_sys_div.aclk,
  451. [AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk,
  452. [AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk,
  453. [AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk,
  454. [AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk,
  455. [AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk,
  456. [AXXIA_CLK_PER_DIV] = &clk_per_div.aclk,
  457. [AXXIA_CLK_MMC_DIV] = &clk_mmc_div.aclk,
  458. [AXXIA_CLK_FAB] = &clk_fab_mux.aclk,
  459. [AXXIA_CLK_SYS] = &clk_sys_mux.aclk,
  460. [AXXIA_CLK_NRCP] = &clk_nrcp_mux.aclk,
  461. [AXXIA_CLK_CPU0] = &clk_cpu0_mux.aclk,
  462. [AXXIA_CLK_CPU1] = &clk_cpu1_mux.aclk,
  463. [AXXIA_CLK_CPU2] = &clk_cpu2_mux.aclk,
  464. [AXXIA_CLK_CPU3] = &clk_cpu3_mux.aclk,
  465. [AXXIA_CLK_PER] = &clk_per_mux.aclk,
  466. [AXXIA_CLK_MMC] = &clk_mmc_mux.aclk,
  467. };
  468. static struct clk_hw *
  469. of_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused)
  470. {
  471. unsigned int idx = clkspec->args[0];
  472. if (idx >= ARRAY_SIZE(axmclk_clocks)) {
  473. pr_err("%s: invalid index %u\n", __func__, idx);
  474. return ERR_PTR(-EINVAL);
  475. }
  476. return &axmclk_clocks[idx]->hw;
  477. }
  478. static const struct regmap_config axmclk_regmap_config = {
  479. .reg_bits = 32,
  480. .reg_stride = 4,
  481. .val_bits = 32,
  482. .max_register = 0x1fffc,
  483. .fast_io = true,
  484. };
  485. static const struct of_device_id axmclk_match_table[] = {
  486. { .compatible = "lsi,axm5516-clks" },
  487. { }
  488. };
  489. MODULE_DEVICE_TABLE(of, axmclk_match_table);
  490. static int axmclk_probe(struct platform_device *pdev)
  491. {
  492. void __iomem *base;
  493. struct resource *res;
  494. int i, ret;
  495. struct device *dev = &pdev->dev;
  496. struct regmap *regmap;
  497. size_t num_clks;
  498. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  499. base = devm_ioremap_resource(dev, res);
  500. if (IS_ERR(base))
  501. return PTR_ERR(base);
  502. regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config);
  503. if (IS_ERR(regmap))
  504. return PTR_ERR(regmap);
  505. num_clks = ARRAY_SIZE(axmclk_clocks);
  506. pr_info("axmclk: supporting %zu clocks\n", num_clks);
  507. /* Update each entry with the allocated regmap and register the clock
  508. * with the common clock framework
  509. */
  510. for (i = 0; i < num_clks; i++) {
  511. axmclk_clocks[i]->regmap = regmap;
  512. ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw);
  513. if (ret)
  514. return ret;
  515. }
  516. return of_clk_add_hw_provider(dev->of_node, of_clk_axmclk_get, NULL);
  517. }
  518. static int axmclk_remove(struct platform_device *pdev)
  519. {
  520. of_clk_del_provider(pdev->dev.of_node);
  521. return 0;
  522. }
  523. static struct platform_driver axmclk_driver = {
  524. .probe = axmclk_probe,
  525. .remove = axmclk_remove,
  526. .driver = {
  527. .name = "clk-axm5516",
  528. .of_match_table = axmclk_match_table,
  529. },
  530. };
  531. static int __init axmclk_init(void)
  532. {
  533. return platform_driver_register(&axmclk_driver);
  534. }
  535. core_initcall(axmclk_init);
  536. static void __exit axmclk_exit(void)
  537. {
  538. platform_driver_unregister(&axmclk_driver);
  539. }
  540. module_exit(axmclk_exit);
  541. MODULE_DESCRIPTION("AXM5516 clock driver");
  542. MODULE_LICENSE("GPL v2");
  543. MODULE_ALIAS("platform:clk-axm5516");