clk-pmc-atom.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Intel Atom platform clocks driver for BayTrail and CherryTrail SoCs
  4. *
  5. * Copyright (C) 2016, Intel Corporation
  6. * Author: Irina Tirdea <irina.tirdea@intel.com>
  7. */
  8. #include <linux/clk-provider.h>
  9. #include <linux/clkdev.h>
  10. #include <linux/err.h>
  11. #include <linux/io.h>
  12. #include <linux/platform_data/x86/clk-pmc-atom.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/slab.h>
  15. #define PLT_CLK_NAME_BASE "pmc_plt_clk"
  16. #define PMC_CLK_CTL_OFFSET 0x60
  17. #define PMC_CLK_CTL_SIZE 4
  18. #define PMC_CLK_NUM 6
  19. #define PMC_CLK_CTL_GATED_ON_D3 0x0
  20. #define PMC_CLK_CTL_FORCE_ON 0x1
  21. #define PMC_CLK_CTL_FORCE_OFF 0x2
  22. #define PMC_CLK_CTL_RESERVED 0x3
  23. #define PMC_MASK_CLK_CTL GENMASK(1, 0)
  24. #define PMC_MASK_CLK_FREQ BIT(2)
  25. #define PMC_CLK_FREQ_XTAL (0 << 2) /* 25 MHz */
  26. #define PMC_CLK_FREQ_PLL (1 << 2) /* 19.2 MHz */
  27. struct clk_plt_fixed {
  28. struct clk_hw *clk;
  29. struct clk_lookup *lookup;
  30. };
  31. struct clk_plt {
  32. struct clk_hw hw;
  33. void __iomem *reg;
  34. struct clk_lookup *lookup;
  35. /* protect access to PMC registers */
  36. spinlock_t lock;
  37. };
  38. #define to_clk_plt(_hw) container_of(_hw, struct clk_plt, hw)
  39. struct clk_plt_data {
  40. struct clk_plt_fixed **parents;
  41. u8 nparents;
  42. struct clk_plt *clks[PMC_CLK_NUM];
  43. struct clk_lookup *mclk_lookup;
  44. struct clk_lookup *ether_clk_lookup;
  45. };
  46. /* Return an index in parent table */
  47. static inline int plt_reg_to_parent(int reg)
  48. {
  49. switch (reg & PMC_MASK_CLK_FREQ) {
  50. default:
  51. case PMC_CLK_FREQ_XTAL:
  52. return 0;
  53. case PMC_CLK_FREQ_PLL:
  54. return 1;
  55. }
  56. }
  57. /* Return clk index of parent */
  58. static inline int plt_parent_to_reg(int index)
  59. {
  60. switch (index) {
  61. default:
  62. case 0:
  63. return PMC_CLK_FREQ_XTAL;
  64. case 1:
  65. return PMC_CLK_FREQ_PLL;
  66. }
  67. }
  68. /* Abstract status in simpler enabled/disabled value */
  69. static inline int plt_reg_to_enabled(int reg)
  70. {
  71. switch (reg & PMC_MASK_CLK_CTL) {
  72. case PMC_CLK_CTL_GATED_ON_D3:
  73. case PMC_CLK_CTL_FORCE_ON:
  74. return 1; /* enabled */
  75. case PMC_CLK_CTL_FORCE_OFF:
  76. case PMC_CLK_CTL_RESERVED:
  77. default:
  78. return 0; /* disabled */
  79. }
  80. }
  81. static void plt_clk_reg_update(struct clk_plt *clk, u32 mask, u32 val)
  82. {
  83. u32 tmp;
  84. unsigned long flags;
  85. spin_lock_irqsave(&clk->lock, flags);
  86. tmp = readl(clk->reg);
  87. tmp = (tmp & ~mask) | (val & mask);
  88. writel(tmp, clk->reg);
  89. spin_unlock_irqrestore(&clk->lock, flags);
  90. }
  91. static int plt_clk_set_parent(struct clk_hw *hw, u8 index)
  92. {
  93. struct clk_plt *clk = to_clk_plt(hw);
  94. plt_clk_reg_update(clk, PMC_MASK_CLK_FREQ, plt_parent_to_reg(index));
  95. return 0;
  96. }
  97. static u8 plt_clk_get_parent(struct clk_hw *hw)
  98. {
  99. struct clk_plt *clk = to_clk_plt(hw);
  100. u32 value;
  101. value = readl(clk->reg);
  102. return plt_reg_to_parent(value);
  103. }
  104. static int plt_clk_enable(struct clk_hw *hw)
  105. {
  106. struct clk_plt *clk = to_clk_plt(hw);
  107. plt_clk_reg_update(clk, PMC_MASK_CLK_CTL, PMC_CLK_CTL_FORCE_ON);
  108. return 0;
  109. }
  110. static void plt_clk_disable(struct clk_hw *hw)
  111. {
  112. struct clk_plt *clk = to_clk_plt(hw);
  113. plt_clk_reg_update(clk, PMC_MASK_CLK_CTL, PMC_CLK_CTL_FORCE_OFF);
  114. }
  115. static int plt_clk_is_enabled(struct clk_hw *hw)
  116. {
  117. struct clk_plt *clk = to_clk_plt(hw);
  118. u32 value;
  119. value = readl(clk->reg);
  120. return plt_reg_to_enabled(value);
  121. }
  122. static const struct clk_ops plt_clk_ops = {
  123. .enable = plt_clk_enable,
  124. .disable = plt_clk_disable,
  125. .is_enabled = plt_clk_is_enabled,
  126. .get_parent = plt_clk_get_parent,
  127. .set_parent = plt_clk_set_parent,
  128. .determine_rate = __clk_mux_determine_rate,
  129. };
  130. static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id,
  131. const struct pmc_clk_data *pmc_data,
  132. const char **parent_names,
  133. int num_parents)
  134. {
  135. struct clk_plt *pclk;
  136. struct clk_init_data init;
  137. int ret;
  138. pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL);
  139. if (!pclk)
  140. return ERR_PTR(-ENOMEM);
  141. init.name = kasprintf(GFP_KERNEL, "%s_%d", PLT_CLK_NAME_BASE, id);
  142. init.ops = &plt_clk_ops;
  143. init.flags = 0;
  144. init.parent_names = parent_names;
  145. init.num_parents = num_parents;
  146. pclk->hw.init = &init;
  147. pclk->reg = pmc_data->base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE;
  148. spin_lock_init(&pclk->lock);
  149. /*
  150. * On some systems, the pmc_plt_clocks already enabled by the
  151. * firmware are being marked as critical to avoid them being
  152. * gated by the clock framework.
  153. */
  154. if (pmc_data->critical && plt_clk_is_enabled(&pclk->hw))
  155. init.flags |= CLK_IS_CRITICAL;
  156. ret = devm_clk_hw_register(&pdev->dev, &pclk->hw);
  157. if (ret) {
  158. pclk = ERR_PTR(ret);
  159. goto err_free_init;
  160. }
  161. pclk->lookup = clkdev_hw_create(&pclk->hw, init.name, NULL);
  162. if (!pclk->lookup) {
  163. pclk = ERR_PTR(-ENOMEM);
  164. goto err_free_init;
  165. }
  166. err_free_init:
  167. kfree(init.name);
  168. return pclk;
  169. }
  170. static void plt_clk_unregister(struct clk_plt *pclk)
  171. {
  172. clkdev_drop(pclk->lookup);
  173. }
  174. static struct clk_plt_fixed *plt_clk_register_fixed_rate(struct platform_device *pdev,
  175. const char *name,
  176. const char *parent_name,
  177. unsigned long fixed_rate)
  178. {
  179. struct clk_plt_fixed *pclk;
  180. pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL);
  181. if (!pclk)
  182. return ERR_PTR(-ENOMEM);
  183. pclk->clk = clk_hw_register_fixed_rate(&pdev->dev, name, parent_name,
  184. 0, fixed_rate);
  185. if (IS_ERR(pclk->clk))
  186. return ERR_CAST(pclk->clk);
  187. pclk->lookup = clkdev_hw_create(pclk->clk, name, NULL);
  188. if (!pclk->lookup) {
  189. clk_hw_unregister_fixed_rate(pclk->clk);
  190. return ERR_PTR(-ENOMEM);
  191. }
  192. return pclk;
  193. }
  194. static void plt_clk_unregister_fixed_rate(struct clk_plt_fixed *pclk)
  195. {
  196. clkdev_drop(pclk->lookup);
  197. clk_hw_unregister_fixed_rate(pclk->clk);
  198. }
  199. static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data,
  200. unsigned int i)
  201. {
  202. while (i--)
  203. plt_clk_unregister_fixed_rate(data->parents[i]);
  204. }
  205. static void plt_clk_free_parent_names_loop(const char **parent_names,
  206. unsigned int i)
  207. {
  208. while (i--)
  209. kfree_const(parent_names[i]);
  210. kfree(parent_names);
  211. }
  212. static void plt_clk_unregister_loop(struct clk_plt_data *data,
  213. unsigned int i)
  214. {
  215. while (i--)
  216. plt_clk_unregister(data->clks[i]);
  217. }
  218. static const char **plt_clk_register_parents(struct platform_device *pdev,
  219. struct clk_plt_data *data,
  220. const struct pmc_clk *clks)
  221. {
  222. const char **parent_names;
  223. unsigned int i;
  224. int err;
  225. int nparents = 0;
  226. data->nparents = 0;
  227. while (clks[nparents].name)
  228. nparents++;
  229. data->parents = devm_kcalloc(&pdev->dev, nparents,
  230. sizeof(*data->parents), GFP_KERNEL);
  231. if (!data->parents)
  232. return ERR_PTR(-ENOMEM);
  233. parent_names = kcalloc(nparents, sizeof(*parent_names),
  234. GFP_KERNEL);
  235. if (!parent_names)
  236. return ERR_PTR(-ENOMEM);
  237. for (i = 0; i < nparents; i++) {
  238. data->parents[i] =
  239. plt_clk_register_fixed_rate(pdev, clks[i].name,
  240. clks[i].parent_name,
  241. clks[i].freq);
  242. if (IS_ERR(data->parents[i])) {
  243. err = PTR_ERR(data->parents[i]);
  244. goto err_unreg;
  245. }
  246. parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL);
  247. }
  248. data->nparents = nparents;
  249. return parent_names;
  250. err_unreg:
  251. plt_clk_unregister_fixed_rate_loop(data, i);
  252. plt_clk_free_parent_names_loop(parent_names, i);
  253. return ERR_PTR(err);
  254. }
  255. static void plt_clk_unregister_parents(struct clk_plt_data *data)
  256. {
  257. plt_clk_unregister_fixed_rate_loop(data, data->nparents);
  258. }
  259. static int plt_clk_probe(struct platform_device *pdev)
  260. {
  261. const struct pmc_clk_data *pmc_data;
  262. const char **parent_names;
  263. struct clk_plt_data *data;
  264. unsigned int i;
  265. int err;
  266. pmc_data = dev_get_platdata(&pdev->dev);
  267. if (!pmc_data || !pmc_data->clks)
  268. return -EINVAL;
  269. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  270. if (!data)
  271. return -ENOMEM;
  272. parent_names = plt_clk_register_parents(pdev, data, pmc_data->clks);
  273. if (IS_ERR(parent_names))
  274. return PTR_ERR(parent_names);
  275. for (i = 0; i < PMC_CLK_NUM; i++) {
  276. data->clks[i] = plt_clk_register(pdev, i, pmc_data,
  277. parent_names, data->nparents);
  278. if (IS_ERR(data->clks[i])) {
  279. err = PTR_ERR(data->clks[i]);
  280. goto err_unreg_clk_plt;
  281. }
  282. }
  283. data->mclk_lookup = clkdev_hw_create(&data->clks[3]->hw, "mclk", NULL);
  284. if (!data->mclk_lookup) {
  285. err = -ENOMEM;
  286. goto err_unreg_clk_plt;
  287. }
  288. data->ether_clk_lookup = clkdev_hw_create(&data->clks[4]->hw,
  289. "ether_clk", NULL);
  290. if (!data->ether_clk_lookup) {
  291. err = -ENOMEM;
  292. goto err_drop_mclk;
  293. }
  294. plt_clk_free_parent_names_loop(parent_names, data->nparents);
  295. platform_set_drvdata(pdev, data);
  296. return 0;
  297. err_drop_mclk:
  298. clkdev_drop(data->mclk_lookup);
  299. err_unreg_clk_plt:
  300. plt_clk_unregister_loop(data, i);
  301. plt_clk_unregister_parents(data);
  302. plt_clk_free_parent_names_loop(parent_names, data->nparents);
  303. return err;
  304. }
  305. static int plt_clk_remove(struct platform_device *pdev)
  306. {
  307. struct clk_plt_data *data;
  308. data = platform_get_drvdata(pdev);
  309. clkdev_drop(data->ether_clk_lookup);
  310. clkdev_drop(data->mclk_lookup);
  311. plt_clk_unregister_loop(data, PMC_CLK_NUM);
  312. plt_clk_unregister_parents(data);
  313. return 0;
  314. }
  315. static struct platform_driver plt_clk_driver = {
  316. .driver = {
  317. .name = "clk-pmc-atom",
  318. },
  319. .probe = plt_clk_probe,
  320. .remove = plt_clk_remove,
  321. };
  322. builtin_platform_driver(plt_clk_driver);