c3-pll.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Amlogic C3 PLL Controller Driver
  4. *
  5. * Copyright (c) 2023 Amlogic, inc.
  6. * Author: Chuan Liu <chuan.liu@amlogic.com>
  7. */
  8. #include <linux/clk-provider.h>
  9. #include <linux/platform_device.h>
  10. #include "clk-regmap.h"
  11. #include "clk-pll.h"
  12. #include "meson-clkc-utils.h"
  13. #include <dt-bindings/clock/amlogic,c3-pll-clkc.h>
  14. #define ANACTRL_FIXPLL_CTRL4 0x50
  15. #define ANACTRL_GP0PLL_CTRL0 0x80
  16. #define ANACTRL_GP0PLL_CTRL1 0x84
  17. #define ANACTRL_GP0PLL_CTRL2 0x88
  18. #define ANACTRL_GP0PLL_CTRL3 0x8c
  19. #define ANACTRL_GP0PLL_CTRL4 0x90
  20. #define ANACTRL_GP0PLL_CTRL5 0x94
  21. #define ANACTRL_GP0PLL_CTRL6 0x98
  22. #define ANACTRL_HIFIPLL_CTRL0 0x100
  23. #define ANACTRL_HIFIPLL_CTRL1 0x104
  24. #define ANACTRL_HIFIPLL_CTRL2 0x108
  25. #define ANACTRL_HIFIPLL_CTRL3 0x10c
  26. #define ANACTRL_HIFIPLL_CTRL4 0x110
  27. #define ANACTRL_HIFIPLL_CTRL5 0x114
  28. #define ANACTRL_HIFIPLL_CTRL6 0x118
  29. #define ANACTRL_MPLL_CTRL0 0x180
  30. #define ANACTRL_MPLL_CTRL1 0x184
  31. #define ANACTRL_MPLL_CTRL2 0x188
  32. #define ANACTRL_MPLL_CTRL3 0x18c
  33. #define ANACTRL_MPLL_CTRL4 0x190
  34. static struct clk_regmap fclk_50m_en = {
  35. .data = &(struct clk_regmap_gate_data) {
  36. .offset = ANACTRL_FIXPLL_CTRL4,
  37. .bit_idx = 0,
  38. },
  39. .hw.init = &(struct clk_init_data) {
  40. .name = "fclk_50m_en",
  41. .ops = &clk_regmap_gate_ro_ops,
  42. .parent_data = &(const struct clk_parent_data) {
  43. .fw_name = "fix"
  44. },
  45. .num_parents = 1,
  46. },
  47. };
  48. static struct clk_fixed_factor fclk_50m = {
  49. .mult = 1,
  50. .div = 40,
  51. .hw.init = &(struct clk_init_data) {
  52. .name = "fclk_50m",
  53. .ops = &clk_fixed_factor_ops,
  54. .parent_hws = (const struct clk_hw *[]) {
  55. &fclk_50m_en.hw
  56. },
  57. .num_parents = 1,
  58. },
  59. };
  60. static struct clk_fixed_factor fclk_div2_div = {
  61. .mult = 1,
  62. .div = 2,
  63. .hw.init = &(struct clk_init_data) {
  64. .name = "fclk_div2_div",
  65. .ops = &clk_fixed_factor_ops,
  66. .parent_data = &(const struct clk_parent_data) {
  67. .fw_name = "fix"
  68. },
  69. .num_parents = 1,
  70. },
  71. };
  72. static struct clk_regmap fclk_div2 = {
  73. .data = &(struct clk_regmap_gate_data) {
  74. .offset = ANACTRL_FIXPLL_CTRL4,
  75. .bit_idx = 24,
  76. },
  77. .hw.init = &(struct clk_init_data) {
  78. .name = "fclk_div2",
  79. .ops = &clk_regmap_gate_ro_ops,
  80. .parent_hws = (const struct clk_hw *[]) {
  81. &fclk_div2_div.hw
  82. },
  83. .num_parents = 1,
  84. },
  85. };
  86. static struct clk_fixed_factor fclk_div2p5_div = {
  87. .mult = 2,
  88. .div = 5,
  89. .hw.init = &(struct clk_init_data) {
  90. .name = "fclk_div2p5_div",
  91. .ops = &clk_fixed_factor_ops,
  92. .parent_data = &(const struct clk_parent_data) {
  93. .fw_name = "fix"
  94. },
  95. .num_parents = 1,
  96. },
  97. };
  98. static struct clk_regmap fclk_div2p5 = {
  99. .data = &(struct clk_regmap_gate_data) {
  100. .offset = ANACTRL_FIXPLL_CTRL4,
  101. .bit_idx = 4,
  102. },
  103. .hw.init = &(struct clk_init_data) {
  104. .name = "fclk_div2p5",
  105. .ops = &clk_regmap_gate_ro_ops,
  106. .parent_hws = (const struct clk_hw *[]) {
  107. &fclk_div2p5_div.hw
  108. },
  109. .num_parents = 1,
  110. },
  111. };
  112. static struct clk_fixed_factor fclk_div3_div = {
  113. .mult = 1,
  114. .div = 3,
  115. .hw.init = &(struct clk_init_data) {
  116. .name = "fclk_div3_div",
  117. .ops = &clk_fixed_factor_ops,
  118. .parent_data = &(const struct clk_parent_data) {
  119. .fw_name = "fix"
  120. },
  121. .num_parents = 1,
  122. },
  123. };
  124. static struct clk_regmap fclk_div3 = {
  125. .data = &(struct clk_regmap_gate_data) {
  126. .offset = ANACTRL_FIXPLL_CTRL4,
  127. .bit_idx = 20,
  128. },
  129. .hw.init = &(struct clk_init_data) {
  130. .name = "fclk_div3",
  131. .ops = &clk_regmap_gate_ro_ops,
  132. .parent_hws = (const struct clk_hw *[]) {
  133. &fclk_div3_div.hw
  134. },
  135. .num_parents = 1,
  136. },
  137. };
  138. static struct clk_fixed_factor fclk_div4_div = {
  139. .mult = 1,
  140. .div = 4,
  141. .hw.init = &(struct clk_init_data) {
  142. .name = "fclk_div4_div",
  143. .ops = &clk_fixed_factor_ops,
  144. .parent_data = &(const struct clk_parent_data) {
  145. .fw_name = "fix"
  146. },
  147. .num_parents = 1,
  148. },
  149. };
  150. static struct clk_regmap fclk_div4 = {
  151. .data = &(struct clk_regmap_gate_data) {
  152. .offset = ANACTRL_FIXPLL_CTRL4,
  153. .bit_idx = 21,
  154. },
  155. .hw.init = &(struct clk_init_data) {
  156. .name = "fclk_div4",
  157. .ops = &clk_regmap_gate_ro_ops,
  158. .parent_hws = (const struct clk_hw *[]) {
  159. &fclk_div4_div.hw
  160. },
  161. .num_parents = 1,
  162. },
  163. };
  164. static struct clk_fixed_factor fclk_div5_div = {
  165. .mult = 1,
  166. .div = 5,
  167. .hw.init = &(struct clk_init_data) {
  168. .name = "fclk_div5_div",
  169. .ops = &clk_fixed_factor_ops,
  170. .parent_data = &(const struct clk_parent_data) {
  171. .fw_name = "fix"
  172. },
  173. .num_parents = 1,
  174. },
  175. };
  176. static struct clk_regmap fclk_div5 = {
  177. .data = &(struct clk_regmap_gate_data) {
  178. .offset = ANACTRL_FIXPLL_CTRL4,
  179. .bit_idx = 22,
  180. },
  181. .hw.init = &(struct clk_init_data) {
  182. .name = "fclk_div5",
  183. .ops = &clk_regmap_gate_ro_ops,
  184. .parent_hws = (const struct clk_hw *[]) {
  185. &fclk_div5_div.hw
  186. },
  187. .num_parents = 1,
  188. },
  189. };
  190. static struct clk_fixed_factor fclk_div7_div = {
  191. .mult = 1,
  192. .div = 7,
  193. .hw.init = &(struct clk_init_data) {
  194. .name = "fclk_div7_div",
  195. .ops = &clk_fixed_factor_ops,
  196. .parent_data = &(const struct clk_parent_data) {
  197. .fw_name = "fix"
  198. },
  199. .num_parents = 1,
  200. },
  201. };
  202. static struct clk_regmap fclk_div7 = {
  203. .data = &(struct clk_regmap_gate_data) {
  204. .offset = ANACTRL_FIXPLL_CTRL4,
  205. .bit_idx = 23,
  206. },
  207. .hw.init = &(struct clk_init_data) {
  208. .name = "fclk_div7",
  209. .ops = &clk_regmap_gate_ro_ops,
  210. .parent_hws = (const struct clk_hw *[]) {
  211. &fclk_div7_div.hw
  212. },
  213. .num_parents = 1,
  214. },
  215. };
  216. static const struct reg_sequence c3_gp0_init_regs[] = {
  217. { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x0 },
  218. { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 },
  219. { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 },
  220. { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x3927200a },
  221. { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x56540000 },
  222. };
  223. static const struct pll_mult_range c3_gp0_pll_mult_range = {
  224. .min = 125,
  225. .max = 250,
  226. };
  227. static struct clk_regmap gp0_pll_dco = {
  228. .data = &(struct meson_clk_pll_data) {
  229. .en = {
  230. .reg_off = ANACTRL_GP0PLL_CTRL0,
  231. .shift = 28,
  232. .width = 1,
  233. },
  234. .m = {
  235. .reg_off = ANACTRL_GP0PLL_CTRL0,
  236. .shift = 0,
  237. .width = 9,
  238. },
  239. .frac = {
  240. .reg_off = ANACTRL_GP0PLL_CTRL1,
  241. .shift = 0,
  242. .width = 19,
  243. },
  244. .n = {
  245. .reg_off = ANACTRL_GP0PLL_CTRL0,
  246. .shift = 10,
  247. .width = 5,
  248. },
  249. .l = {
  250. .reg_off = ANACTRL_GP0PLL_CTRL0,
  251. .shift = 31,
  252. .width = 1,
  253. },
  254. .rst = {
  255. .reg_off = ANACTRL_GP0PLL_CTRL0,
  256. .shift = 29,
  257. .width = 1,
  258. },
  259. .range = &c3_gp0_pll_mult_range,
  260. .init_regs = c3_gp0_init_regs,
  261. .init_count = ARRAY_SIZE(c3_gp0_init_regs),
  262. },
  263. .hw.init = &(struct clk_init_data) {
  264. .name = "gp0_pll_dco",
  265. .ops = &meson_clk_pll_ops,
  266. .parent_data = &(const struct clk_parent_data) {
  267. .fw_name = "top",
  268. },
  269. .num_parents = 1,
  270. },
  271. };
  272. /* The maximum frequency divider supports is 32, not 128(2^7) */
  273. static const struct clk_div_table c3_gp0_pll_od_table[] = {
  274. { 0, 1 },
  275. { 1, 2 },
  276. { 2, 4 },
  277. { 3, 8 },
  278. { 4, 16 },
  279. { 5, 32 },
  280. { /* sentinel */ }
  281. };
  282. static struct clk_regmap gp0_pll = {
  283. .data = &(struct clk_regmap_div_data) {
  284. .offset = ANACTRL_GP0PLL_CTRL0,
  285. .shift = 16,
  286. .width = 3,
  287. .table = c3_gp0_pll_od_table,
  288. },
  289. .hw.init = &(struct clk_init_data) {
  290. .name = "gp0_pll",
  291. .ops = &clk_regmap_divider_ops,
  292. .parent_hws = (const struct clk_hw *[]) {
  293. &gp0_pll_dco.hw
  294. },
  295. .num_parents = 1,
  296. .flags = CLK_SET_RATE_PARENT,
  297. },
  298. };
  299. static const struct reg_sequence c3_hifi_init_regs[] = {
  300. { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x0 },
  301. { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 },
  302. { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },
  303. { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x3927200a },
  304. { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 },
  305. };
  306. static struct clk_regmap hifi_pll_dco = {
  307. .data = &(struct meson_clk_pll_data) {
  308. .en = {
  309. .reg_off = ANACTRL_HIFIPLL_CTRL0,
  310. .shift = 28,
  311. .width = 1,
  312. },
  313. .m = {
  314. .reg_off = ANACTRL_HIFIPLL_CTRL0,
  315. .shift = 0,
  316. .width = 8,
  317. },
  318. .frac = {
  319. .reg_off = ANACTRL_HIFIPLL_CTRL1,
  320. .shift = 0,
  321. .width = 19,
  322. },
  323. .n = {
  324. .reg_off = ANACTRL_HIFIPLL_CTRL0,
  325. .shift = 10,
  326. .width = 5,
  327. },
  328. .l = {
  329. .reg_off = ANACTRL_HIFIPLL_CTRL0,
  330. .shift = 31,
  331. .width = 1,
  332. },
  333. .rst = {
  334. .reg_off = ANACTRL_HIFIPLL_CTRL0,
  335. .shift = 29,
  336. .width = 1,
  337. },
  338. .range = &c3_gp0_pll_mult_range,
  339. .init_regs = c3_hifi_init_regs,
  340. .init_count = ARRAY_SIZE(c3_hifi_init_regs),
  341. },
  342. .hw.init = &(struct clk_init_data) {
  343. .name = "hifi_pll_dco",
  344. .ops = &meson_clk_pll_ops,
  345. .parent_data = &(const struct clk_parent_data) {
  346. .fw_name = "top",
  347. },
  348. .num_parents = 1,
  349. },
  350. };
  351. static struct clk_regmap hifi_pll = {
  352. .data = &(struct clk_regmap_div_data) {
  353. .offset = ANACTRL_HIFIPLL_CTRL0,
  354. .shift = 16,
  355. .width = 2,
  356. .flags = CLK_DIVIDER_POWER_OF_TWO,
  357. },
  358. .hw.init = &(struct clk_init_data) {
  359. .name = "hifi_pll",
  360. .ops = &clk_regmap_divider_ops,
  361. .parent_hws = (const struct clk_hw *[]) {
  362. &hifi_pll_dco.hw
  363. },
  364. .num_parents = 1,
  365. .flags = CLK_SET_RATE_PARENT,
  366. },
  367. };
  368. static const struct reg_sequence c3_mclk_init_regs[] = {
  369. { .reg = ANACTRL_MPLL_CTRL1, .def = 0x1420500f },
  370. { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023041 },
  371. { .reg = ANACTRL_MPLL_CTRL3, .def = 0x18180000 },
  372. { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023001 }
  373. };
  374. static const struct pll_mult_range c3_mclk_pll_mult_range = {
  375. .min = 67,
  376. .max = 133,
  377. };
  378. static struct clk_regmap mclk_pll_dco = {
  379. .data = &(struct meson_clk_pll_data) {
  380. .en = {
  381. .reg_off = ANACTRL_MPLL_CTRL0,
  382. .shift = 28,
  383. .width = 1,
  384. },
  385. .m = {
  386. .reg_off = ANACTRL_MPLL_CTRL0,
  387. .shift = 0,
  388. .width = 8,
  389. },
  390. .n = {
  391. .reg_off = ANACTRL_MPLL_CTRL0,
  392. .shift = 16,
  393. .width = 5,
  394. },
  395. .l = {
  396. .reg_off = ANACTRL_MPLL_CTRL0,
  397. .shift = 31,
  398. .width = 1,
  399. },
  400. .rst = {
  401. .reg_off = ANACTRL_MPLL_CTRL0,
  402. .shift = 29,
  403. .width = 1,
  404. },
  405. .range = &c3_mclk_pll_mult_range,
  406. .init_regs = c3_mclk_init_regs,
  407. .init_count = ARRAY_SIZE(c3_mclk_init_regs),
  408. },
  409. .hw.init = &(struct clk_init_data) {
  410. .name = "mclk_pll_dco",
  411. .ops = &meson_clk_pll_ops,
  412. .parent_data = &(const struct clk_parent_data) {
  413. .fw_name = "mclk",
  414. },
  415. .num_parents = 1,
  416. },
  417. };
  418. static const struct clk_div_table c3_mpll_od_table[] = {
  419. { 0, 1 },
  420. { 1, 2 },
  421. { 2, 4 },
  422. { 3, 8 },
  423. { 4, 16 },
  424. { /* sentinel */ }
  425. };
  426. static struct clk_regmap mclk_pll_od = {
  427. .data = &(struct clk_regmap_div_data) {
  428. .offset = ANACTRL_MPLL_CTRL0,
  429. .shift = 12,
  430. .width = 3,
  431. .table = c3_mpll_od_table,
  432. },
  433. .hw.init = &(struct clk_init_data) {
  434. .name = "mclk_pll_od",
  435. .ops = &clk_regmap_divider_ops,
  436. .parent_hws = (const struct clk_hw *[]) {
  437. &mclk_pll_dco.hw },
  438. .num_parents = 1,
  439. .flags = CLK_SET_RATE_PARENT,
  440. },
  441. };
  442. /* both value 0 and 1 gives divide the input rate by one */
  443. static struct clk_regmap mclk_pll = {
  444. .data = &(struct clk_regmap_div_data) {
  445. .offset = ANACTRL_MPLL_CTRL4,
  446. .shift = 16,
  447. .width = 5,
  448. .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
  449. },
  450. .hw.init = &(struct clk_init_data) {
  451. .name = "mclk_pll",
  452. .ops = &clk_regmap_divider_ops,
  453. .parent_hws = (const struct clk_hw *[]) {
  454. &mclk_pll_od.hw
  455. },
  456. .num_parents = 1,
  457. .flags = CLK_SET_RATE_PARENT,
  458. },
  459. };
  460. static const struct clk_parent_data mclk_parent[] = {
  461. { .hw = &mclk_pll.hw },
  462. { .fw_name = "mclk" },
  463. { .hw = &fclk_50m.hw }
  464. };
  465. static struct clk_regmap mclk0_sel = {
  466. .data = &(struct clk_regmap_mux_data) {
  467. .offset = ANACTRL_MPLL_CTRL4,
  468. .mask = 0x3,
  469. .shift = 4,
  470. },
  471. .hw.init = &(struct clk_init_data) {
  472. .name = "mclk0_sel",
  473. .ops = &clk_regmap_mux_ops,
  474. .parent_data = mclk_parent,
  475. .num_parents = ARRAY_SIZE(mclk_parent),
  476. },
  477. };
  478. static struct clk_regmap mclk0_div_en = {
  479. .data = &(struct clk_regmap_gate_data) {
  480. .offset = ANACTRL_MPLL_CTRL4,
  481. .bit_idx = 1,
  482. },
  483. .hw.init = &(struct clk_init_data) {
  484. .name = "mclk0_div_en",
  485. .ops = &clk_regmap_gate_ops,
  486. .parent_hws = (const struct clk_hw *[]) {
  487. &mclk0_sel.hw
  488. },
  489. .num_parents = 1,
  490. .flags = CLK_SET_RATE_PARENT,
  491. },
  492. };
  493. static struct clk_regmap mclk0_div = {
  494. .data = &(struct clk_regmap_div_data) {
  495. .offset = ANACTRL_MPLL_CTRL4,
  496. .shift = 2,
  497. .width = 1,
  498. },
  499. .hw.init = &(struct clk_init_data) {
  500. .name = "mclk0_div",
  501. .ops = &clk_regmap_divider_ops,
  502. .parent_hws = (const struct clk_hw *[]) {
  503. &mclk0_div_en.hw
  504. },
  505. .num_parents = 1,
  506. .flags = CLK_SET_RATE_PARENT,
  507. },
  508. };
  509. static struct clk_regmap mclk0 = {
  510. .data = &(struct clk_regmap_gate_data) {
  511. .offset = ANACTRL_MPLL_CTRL4,
  512. .bit_idx = 0,
  513. },
  514. .hw.init = &(struct clk_init_data) {
  515. .name = "mclk0",
  516. .ops = &clk_regmap_gate_ops,
  517. .parent_hws = (const struct clk_hw *[]) {
  518. &mclk0_div.hw
  519. },
  520. .num_parents = 1,
  521. .flags = CLK_SET_RATE_PARENT,
  522. },
  523. };
  524. static struct clk_regmap mclk1_sel = {
  525. .data = &(struct clk_regmap_mux_data) {
  526. .offset = ANACTRL_MPLL_CTRL4,
  527. .mask = 0x3,
  528. .shift = 12,
  529. },
  530. .hw.init = &(struct clk_init_data) {
  531. .name = "mclk1_sel",
  532. .ops = &clk_regmap_mux_ops,
  533. .parent_data = mclk_parent,
  534. .num_parents = ARRAY_SIZE(mclk_parent),
  535. },
  536. };
  537. static struct clk_regmap mclk1_div_en = {
  538. .data = &(struct clk_regmap_gate_data) {
  539. .offset = ANACTRL_MPLL_CTRL4,
  540. .bit_idx = 9,
  541. },
  542. .hw.init = &(struct clk_init_data) {
  543. .name = "mclk1_div_en",
  544. .ops = &clk_regmap_gate_ops,
  545. .parent_hws = (const struct clk_hw *[]) {
  546. &mclk1_sel.hw
  547. },
  548. .num_parents = 1,
  549. .flags = CLK_SET_RATE_PARENT,
  550. },
  551. };
  552. static struct clk_regmap mclk1_div = {
  553. .data = &(struct clk_regmap_div_data) {
  554. .offset = ANACTRL_MPLL_CTRL4,
  555. .shift = 10,
  556. .width = 1,
  557. },
  558. .hw.init = &(struct clk_init_data) {
  559. .name = "mclk1_div",
  560. .ops = &clk_regmap_divider_ops,
  561. .parent_hws = (const struct clk_hw *[]) {
  562. &mclk1_div_en.hw
  563. },
  564. .num_parents = 1,
  565. .flags = CLK_SET_RATE_PARENT,
  566. },
  567. };
  568. static struct clk_regmap mclk1 = {
  569. .data = &(struct clk_regmap_gate_data) {
  570. .offset = ANACTRL_MPLL_CTRL4,
  571. .bit_idx = 8,
  572. },
  573. .hw.init = &(struct clk_init_data) {
  574. .name = "mclk1",
  575. .ops = &clk_regmap_gate_ops,
  576. .parent_hws = (const struct clk_hw *[]) {
  577. &mclk1_div.hw
  578. },
  579. .num_parents = 1,
  580. .flags = CLK_SET_RATE_PARENT,
  581. },
  582. };
  583. static struct clk_hw *c3_pll_hw_clks[] = {
  584. [CLKID_FCLK_50M_EN] = &fclk_50m_en.hw,
  585. [CLKID_FCLK_50M] = &fclk_50m.hw,
  586. [CLKID_FCLK_DIV2_DIV] = &fclk_div2_div.hw,
  587. [CLKID_FCLK_DIV2] = &fclk_div2.hw,
  588. [CLKID_FCLK_DIV2P5_DIV] = &fclk_div2p5_div.hw,
  589. [CLKID_FCLK_DIV2P5] = &fclk_div2p5.hw,
  590. [CLKID_FCLK_DIV3_DIV] = &fclk_div3_div.hw,
  591. [CLKID_FCLK_DIV3] = &fclk_div3.hw,
  592. [CLKID_FCLK_DIV4_DIV] = &fclk_div4_div.hw,
  593. [CLKID_FCLK_DIV4] = &fclk_div4.hw,
  594. [CLKID_FCLK_DIV5_DIV] = &fclk_div5_div.hw,
  595. [CLKID_FCLK_DIV5] = &fclk_div5.hw,
  596. [CLKID_FCLK_DIV7_DIV] = &fclk_div7_div.hw,
  597. [CLKID_FCLK_DIV7] = &fclk_div7.hw,
  598. [CLKID_GP0_PLL_DCO] = &gp0_pll_dco.hw,
  599. [CLKID_GP0_PLL] = &gp0_pll.hw,
  600. [CLKID_HIFI_PLL_DCO] = &hifi_pll_dco.hw,
  601. [CLKID_HIFI_PLL] = &hifi_pll.hw,
  602. [CLKID_MCLK_PLL_DCO] = &mclk_pll_dco.hw,
  603. [CLKID_MCLK_PLL_OD] = &mclk_pll_od.hw,
  604. [CLKID_MCLK_PLL] = &mclk_pll.hw,
  605. [CLKID_MCLK0_SEL] = &mclk0_sel.hw,
  606. [CLKID_MCLK0_SEL_EN] = &mclk0_div_en.hw,
  607. [CLKID_MCLK0_DIV] = &mclk0_div.hw,
  608. [CLKID_MCLK0] = &mclk0.hw,
  609. [CLKID_MCLK1_SEL] = &mclk1_sel.hw,
  610. [CLKID_MCLK1_SEL_EN] = &mclk1_div_en.hw,
  611. [CLKID_MCLK1_DIV] = &mclk1_div.hw,
  612. [CLKID_MCLK1] = &mclk1.hw
  613. };
  614. /* Convenience table to populate regmap in .probe */
  615. static struct clk_regmap *const c3_pll_clk_regmaps[] = {
  616. &fclk_50m_en,
  617. &fclk_div2,
  618. &fclk_div2p5,
  619. &fclk_div3,
  620. &fclk_div4,
  621. &fclk_div5,
  622. &fclk_div7,
  623. &gp0_pll_dco,
  624. &gp0_pll,
  625. &hifi_pll_dco,
  626. &hifi_pll,
  627. &mclk_pll_dco,
  628. &mclk_pll_od,
  629. &mclk_pll,
  630. &mclk0_sel,
  631. &mclk0_div_en,
  632. &mclk0_div,
  633. &mclk0,
  634. &mclk1_sel,
  635. &mclk1_div_en,
  636. &mclk1_div,
  637. &mclk1,
  638. };
  639. static const struct regmap_config clkc_regmap_config = {
  640. .reg_bits = 32,
  641. .val_bits = 32,
  642. .reg_stride = 4,
  643. .max_register = ANACTRL_MPLL_CTRL4,
  644. };
  645. static struct meson_clk_hw_data c3_pll_clks = {
  646. .hws = c3_pll_hw_clks,
  647. .num = ARRAY_SIZE(c3_pll_hw_clks),
  648. };
  649. static int c3_pll_probe(struct platform_device *pdev)
  650. {
  651. struct device *dev = &pdev->dev;
  652. struct regmap *regmap;
  653. void __iomem *base;
  654. int clkid, ret, i;
  655. base = devm_platform_ioremap_resource(pdev, 0);
  656. if (IS_ERR(base))
  657. return PTR_ERR(base);
  658. regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
  659. if (IS_ERR(regmap))
  660. return PTR_ERR(regmap);
  661. /* Populate regmap for the regmap backed clocks */
  662. for (i = 0; i < ARRAY_SIZE(c3_pll_clk_regmaps); i++)
  663. c3_pll_clk_regmaps[i]->map = regmap;
  664. for (clkid = 0; clkid < c3_pll_clks.num; clkid++) {
  665. /* array might be sparse */
  666. if (!c3_pll_clks.hws[clkid])
  667. continue;
  668. ret = devm_clk_hw_register(dev, c3_pll_clks.hws[clkid]);
  669. if (ret) {
  670. dev_err(dev, "Clock registration failed\n");
  671. return ret;
  672. }
  673. }
  674. return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
  675. &c3_pll_clks);
  676. }
  677. static const struct of_device_id c3_pll_clkc_match_table[] = {
  678. {
  679. .compatible = "amlogic,c3-pll-clkc",
  680. },
  681. {}
  682. };
  683. MODULE_DEVICE_TABLE(of, c3_pll_clkc_match_table);
  684. static struct platform_driver c3_pll_driver = {
  685. .probe = c3_pll_probe,
  686. .driver = {
  687. .name = "c3-pll-clkc",
  688. .of_match_table = c3_pll_clkc_match_table,
  689. },
  690. };
  691. module_platform_driver(c3_pll_driver);
  692. MODULE_DESCRIPTION("Amlogic C3 PLL Clock Controller driver");
  693. MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>");
  694. MODULE_LICENSE("GPL");
  695. MODULE_IMPORT_NS(CLK_MESON);