clk-wm831x.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * WM831x clock control
  4. *
  5. * Copyright 2011-2 Wolfson Microelectronics PLC.
  6. *
  7. * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  8. */
  9. #include <linux/clk-provider.h>
  10. #include <linux/delay.h>
  11. #include <linux/module.h>
  12. #include <linux/slab.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/mfd/wm831x/core.h>
  15. struct wm831x_clk {
  16. struct wm831x *wm831x;
  17. struct clk_hw xtal_hw;
  18. struct clk_hw fll_hw;
  19. struct clk_hw clkout_hw;
  20. bool xtal_ena;
  21. };
  22. static int wm831x_xtal_is_prepared(struct clk_hw *hw)
  23. {
  24. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  25. xtal_hw);
  26. return clkdata->xtal_ena;
  27. }
  28. static unsigned long wm831x_xtal_recalc_rate(struct clk_hw *hw,
  29. unsigned long parent_rate)
  30. {
  31. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  32. xtal_hw);
  33. if (clkdata->xtal_ena)
  34. return 32768;
  35. else
  36. return 0;
  37. }
  38. static const struct clk_ops wm831x_xtal_ops = {
  39. .is_prepared = wm831x_xtal_is_prepared,
  40. .recalc_rate = wm831x_xtal_recalc_rate,
  41. };
  42. static const struct clk_init_data wm831x_xtal_init = {
  43. .name = "xtal",
  44. .ops = &wm831x_xtal_ops,
  45. };
  46. static const unsigned long wm831x_fll_auto_rates[] = {
  47. 2048000,
  48. 11289600,
  49. 12000000,
  50. 12288000,
  51. 19200000,
  52. 22579600,
  53. 24000000,
  54. 24576000,
  55. };
  56. static int wm831x_fll_is_prepared(struct clk_hw *hw)
  57. {
  58. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  59. fll_hw);
  60. struct wm831x *wm831x = clkdata->wm831x;
  61. int ret;
  62. ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_1);
  63. if (ret < 0) {
  64. dev_err(wm831x->dev, "Unable to read FLL_CONTROL_1: %d\n",
  65. ret);
  66. return true;
  67. }
  68. return (ret & WM831X_FLL_ENA) != 0;
  69. }
  70. static int wm831x_fll_prepare(struct clk_hw *hw)
  71. {
  72. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  73. fll_hw);
  74. struct wm831x *wm831x = clkdata->wm831x;
  75. int ret;
  76. ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1,
  77. WM831X_FLL_ENA, WM831X_FLL_ENA);
  78. if (ret != 0)
  79. dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret);
  80. /* wait 2-3 ms for new frequency taking effect */
  81. usleep_range(2000, 3000);
  82. return ret;
  83. }
  84. static void wm831x_fll_unprepare(struct clk_hw *hw)
  85. {
  86. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  87. fll_hw);
  88. struct wm831x *wm831x = clkdata->wm831x;
  89. int ret;
  90. ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1, WM831X_FLL_ENA, 0);
  91. if (ret != 0)
  92. dev_crit(wm831x->dev, "Failed to disable FLL: %d\n", ret);
  93. }
  94. static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw,
  95. unsigned long parent_rate)
  96. {
  97. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  98. fll_hw);
  99. struct wm831x *wm831x = clkdata->wm831x;
  100. int ret;
  101. ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
  102. if (ret < 0) {
  103. dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
  104. ret);
  105. return 0;
  106. }
  107. if (ret & WM831X_FLL_AUTO)
  108. return wm831x_fll_auto_rates[ret & WM831X_FLL_AUTO_FREQ_MASK];
  109. dev_err(wm831x->dev, "FLL only supported in AUTO mode\n");
  110. return 0;
  111. }
  112. static int wm831x_fll_determine_rate(struct clk_hw *hw,
  113. struct clk_rate_request *req)
  114. {
  115. int best = 0;
  116. int i;
  117. for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
  118. if (abs(wm831x_fll_auto_rates[i] - req->rate) <
  119. abs(wm831x_fll_auto_rates[best] - req->rate))
  120. best = i;
  121. req->rate = wm831x_fll_auto_rates[best];
  122. return 0;
  123. }
  124. static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate,
  125. unsigned long parent_rate)
  126. {
  127. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  128. fll_hw);
  129. struct wm831x *wm831x = clkdata->wm831x;
  130. int i;
  131. for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
  132. if (wm831x_fll_auto_rates[i] == rate)
  133. break;
  134. if (i == ARRAY_SIZE(wm831x_fll_auto_rates))
  135. return -EINVAL;
  136. if (wm831x_fll_is_prepared(hw))
  137. return -EPERM;
  138. return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_2,
  139. WM831X_FLL_AUTO_FREQ_MASK, i);
  140. }
  141. static const char *wm831x_fll_parents[] = {
  142. "xtal",
  143. "clkin",
  144. };
  145. static u8 wm831x_fll_get_parent(struct clk_hw *hw)
  146. {
  147. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  148. fll_hw);
  149. struct wm831x *wm831x = clkdata->wm831x;
  150. int ret;
  151. /* AUTO mode is always clocked from the crystal */
  152. ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
  153. if (ret < 0) {
  154. dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
  155. ret);
  156. return 0;
  157. }
  158. if (ret & WM831X_FLL_AUTO)
  159. return 0;
  160. ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_5);
  161. if (ret < 0) {
  162. dev_err(wm831x->dev, "Unable to read FLL_CONTROL_5: %d\n",
  163. ret);
  164. return 0;
  165. }
  166. switch (ret & WM831X_FLL_CLK_SRC_MASK) {
  167. case 0:
  168. return 0;
  169. case 1:
  170. return 1;
  171. default:
  172. dev_err(wm831x->dev, "Unsupported FLL clock source %d\n",
  173. ret & WM831X_FLL_CLK_SRC_MASK);
  174. return 0;
  175. }
  176. }
  177. static const struct clk_ops wm831x_fll_ops = {
  178. .is_prepared = wm831x_fll_is_prepared,
  179. .prepare = wm831x_fll_prepare,
  180. .unprepare = wm831x_fll_unprepare,
  181. .determine_rate = wm831x_fll_determine_rate,
  182. .recalc_rate = wm831x_fll_recalc_rate,
  183. .set_rate = wm831x_fll_set_rate,
  184. .get_parent = wm831x_fll_get_parent,
  185. };
  186. static const struct clk_init_data wm831x_fll_init = {
  187. .name = "fll",
  188. .ops = &wm831x_fll_ops,
  189. .parent_names = wm831x_fll_parents,
  190. .num_parents = ARRAY_SIZE(wm831x_fll_parents),
  191. .flags = CLK_SET_RATE_GATE,
  192. };
  193. static int wm831x_clkout_is_prepared(struct clk_hw *hw)
  194. {
  195. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  196. clkout_hw);
  197. struct wm831x *wm831x = clkdata->wm831x;
  198. int ret;
  199. ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1);
  200. if (ret < 0) {
  201. dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
  202. ret);
  203. return false;
  204. }
  205. return (ret & WM831X_CLKOUT_ENA) != 0;
  206. }
  207. static int wm831x_clkout_prepare(struct clk_hw *hw)
  208. {
  209. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  210. clkout_hw);
  211. struct wm831x *wm831x = clkdata->wm831x;
  212. int ret;
  213. ret = wm831x_reg_unlock(wm831x);
  214. if (ret != 0) {
  215. dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret);
  216. return ret;
  217. }
  218. ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
  219. WM831X_CLKOUT_ENA, WM831X_CLKOUT_ENA);
  220. if (ret != 0)
  221. dev_crit(wm831x->dev, "Failed to enable CLKOUT: %d\n", ret);
  222. wm831x_reg_lock(wm831x);
  223. return ret;
  224. }
  225. static void wm831x_clkout_unprepare(struct clk_hw *hw)
  226. {
  227. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  228. clkout_hw);
  229. struct wm831x *wm831x = clkdata->wm831x;
  230. int ret;
  231. ret = wm831x_reg_unlock(wm831x);
  232. if (ret != 0) {
  233. dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret);
  234. return;
  235. }
  236. ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
  237. WM831X_CLKOUT_ENA, 0);
  238. if (ret != 0)
  239. dev_crit(wm831x->dev, "Failed to disable CLKOUT: %d\n", ret);
  240. wm831x_reg_lock(wm831x);
  241. }
  242. static const char *wm831x_clkout_parents[] = {
  243. "fll",
  244. "xtal",
  245. };
  246. static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
  247. {
  248. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  249. clkout_hw);
  250. struct wm831x *wm831x = clkdata->wm831x;
  251. int ret;
  252. ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1);
  253. if (ret < 0) {
  254. dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
  255. ret);
  256. return 0;
  257. }
  258. if (ret & WM831X_CLKOUT_SRC)
  259. return 1;
  260. else
  261. return 0;
  262. }
  263. static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
  264. {
  265. struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
  266. clkout_hw);
  267. struct wm831x *wm831x = clkdata->wm831x;
  268. return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
  269. WM831X_CLKOUT_SRC,
  270. parent << WM831X_CLKOUT_SRC_SHIFT);
  271. }
  272. static const struct clk_ops wm831x_clkout_ops = {
  273. .is_prepared = wm831x_clkout_is_prepared,
  274. .prepare = wm831x_clkout_prepare,
  275. .unprepare = wm831x_clkout_unprepare,
  276. .determine_rate = clk_hw_determine_rate_no_reparent,
  277. .get_parent = wm831x_clkout_get_parent,
  278. .set_parent = wm831x_clkout_set_parent,
  279. };
  280. static const struct clk_init_data wm831x_clkout_init = {
  281. .name = "clkout",
  282. .ops = &wm831x_clkout_ops,
  283. .parent_names = wm831x_clkout_parents,
  284. .num_parents = ARRAY_SIZE(wm831x_clkout_parents),
  285. .flags = CLK_SET_RATE_PARENT,
  286. };
  287. static int wm831x_clk_probe(struct platform_device *pdev)
  288. {
  289. struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
  290. struct wm831x_clk *clkdata;
  291. int ret;
  292. clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
  293. if (!clkdata)
  294. return -ENOMEM;
  295. clkdata->wm831x = wm831x;
  296. /* XTAL_ENA can only be set via OTP/InstantConfig so just read once */
  297. ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
  298. if (ret < 0) {
  299. dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
  300. ret);
  301. return ret;
  302. }
  303. clkdata->xtal_ena = ret & WM831X_XTAL_ENA;
  304. clkdata->xtal_hw.init = &wm831x_xtal_init;
  305. ret = devm_clk_hw_register(&pdev->dev, &clkdata->xtal_hw);
  306. if (ret)
  307. return ret;
  308. clkdata->fll_hw.init = &wm831x_fll_init;
  309. ret = devm_clk_hw_register(&pdev->dev, &clkdata->fll_hw);
  310. if (ret)
  311. return ret;
  312. clkdata->clkout_hw.init = &wm831x_clkout_init;
  313. ret = devm_clk_hw_register(&pdev->dev, &clkdata->clkout_hw);
  314. if (ret)
  315. return ret;
  316. platform_set_drvdata(pdev, clkdata);
  317. return 0;
  318. }
  319. static struct platform_driver wm831x_clk_driver = {
  320. .probe = wm831x_clk_probe,
  321. .driver = {
  322. .name = "wm831x-clk",
  323. },
  324. };
  325. module_platform_driver(wm831x_clk_driver);
  326. /* Module information */
  327. MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
  328. MODULE_DESCRIPTION("WM831x clock driver");
  329. MODULE_LICENSE("GPL");
  330. MODULE_ALIAS("platform:wm831x-clk");