clk-mux.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2011 Sascha Hauer, Pengutronix <[email protected]>
  4. * Copyright (C) 2011 Richard Zhao, Linaro <[email protected]>
  5. * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <[email protected]>
  6. *
  7. * Simple multiplexer clock implementation
  8. */
  9. #include <linux/clk-provider.h>
  10. #include <linux/device.h>
  11. #include <linux/module.h>
  12. #include <linux/slab.h>
  13. #include <linux/io.h>
  14. #include <linux/err.h>
  15. /*
  16. * DOC: basic adjustable multiplexer clock that cannot gate
  17. *
  18. * Traits of this clock:
  19. * prepare - clk_prepare only ensures that parents are prepared
  20. * enable - clk_enable only ensures that parents are enabled
  21. * rate - rate is only affected by parent switching. No clk_set_rate support
  22. * parent - parent is adjustable through clk_set_parent
  23. */
  24. static inline u32 clk_mux_readl(struct clk_mux *mux)
  25. {
  26. if (mux->flags & CLK_MUX_BIG_ENDIAN)
  27. return ioread32be(mux->reg);
  28. return readl(mux->reg);
  29. }
  30. static inline void clk_mux_writel(struct clk_mux *mux, u32 val)
  31. {
  32. if (mux->flags & CLK_MUX_BIG_ENDIAN)
  33. iowrite32be(val, mux->reg);
  34. else
  35. writel(val, mux->reg);
  36. }
  37. int clk_mux_val_to_index(struct clk_hw *hw, const u32 *table, unsigned int flags,
  38. unsigned int val)
  39. {
  40. int num_parents = clk_hw_get_num_parents(hw);
  41. if (table) {
  42. int i;
  43. for (i = 0; i < num_parents; i++)
  44. if (table[i] == val)
  45. return i;
  46. return -EINVAL;
  47. }
  48. if (val && (flags & CLK_MUX_INDEX_BIT))
  49. val = ffs(val) - 1;
  50. if (val && (flags & CLK_MUX_INDEX_ONE))
  51. val--;
  52. if (val >= num_parents)
  53. return -EINVAL;
  54. return val;
  55. }
  56. EXPORT_SYMBOL_GPL(clk_mux_val_to_index);
  57. unsigned int clk_mux_index_to_val(const u32 *table, unsigned int flags, u8 index)
  58. {
  59. unsigned int val = index;
  60. if (table) {
  61. val = table[index];
  62. } else {
  63. if (flags & CLK_MUX_INDEX_BIT)
  64. val = 1 << index;
  65. if (flags & CLK_MUX_INDEX_ONE)
  66. val++;
  67. }
  68. return val;
  69. }
  70. EXPORT_SYMBOL_GPL(clk_mux_index_to_val);
  71. static u8 clk_mux_get_parent(struct clk_hw *hw)
  72. {
  73. struct clk_mux *mux = to_clk_mux(hw);
  74. u32 val;
  75. val = clk_mux_readl(mux) >> mux->shift;
  76. val &= mux->mask;
  77. return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
  78. }
  79. static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
  80. {
  81. struct clk_mux *mux = to_clk_mux(hw);
  82. u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
  83. unsigned long flags = 0;
  84. u32 reg;
  85. if (mux->lock)
  86. spin_lock_irqsave(mux->lock, flags);
  87. else
  88. __acquire(mux->lock);
  89. if (mux->flags & CLK_MUX_HIWORD_MASK) {
  90. reg = mux->mask << (mux->shift + 16);
  91. } else {
  92. reg = clk_mux_readl(mux);
  93. reg &= ~(mux->mask << mux->shift);
  94. }
  95. val = val << mux->shift;
  96. reg |= val;
  97. clk_mux_writel(mux, reg);
  98. if (mux->lock)
  99. spin_unlock_irqrestore(mux->lock, flags);
  100. else
  101. __release(mux->lock);
  102. return 0;
  103. }
  104. static int clk_mux_determine_rate(struct clk_hw *hw,
  105. struct clk_rate_request *req)
  106. {
  107. struct clk_mux *mux = to_clk_mux(hw);
  108. return clk_mux_determine_rate_flags(hw, req, mux->flags);
  109. }
  110. const struct clk_ops clk_mux_ops = {
  111. .get_parent = clk_mux_get_parent,
  112. .set_parent = clk_mux_set_parent,
  113. .determine_rate = clk_mux_determine_rate,
  114. };
  115. EXPORT_SYMBOL_GPL(clk_mux_ops);
  116. const struct clk_ops clk_mux_ro_ops = {
  117. .get_parent = clk_mux_get_parent,
  118. };
  119. EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
  120. struct clk_hw *__clk_hw_register_mux(struct device *dev, struct device_node *np,
  121. const char *name, u8 num_parents,
  122. const char * const *parent_names,
  123. const struct clk_hw **parent_hws,
  124. const struct clk_parent_data *parent_data,
  125. unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
  126. u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
  127. {
  128. struct clk_mux *mux;
  129. struct clk_hw *hw;
  130. struct clk_init_data init = {};
  131. int ret = -EINVAL;
  132. if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
  133. u8 width = fls(mask) - ffs(mask) + 1;
  134. if (width + shift > 16) {
  135. pr_err("mux value exceeds LOWORD field\n");
  136. return ERR_PTR(-EINVAL);
  137. }
  138. }
  139. /* allocate the mux */
  140. mux = kzalloc(sizeof(*mux), GFP_KERNEL);
  141. if (!mux)
  142. return ERR_PTR(-ENOMEM);
  143. init.name = name;
  144. if (clk_mux_flags & CLK_MUX_READ_ONLY)
  145. init.ops = &clk_mux_ro_ops;
  146. else
  147. init.ops = &clk_mux_ops;
  148. init.flags = flags;
  149. init.parent_names = parent_names;
  150. init.parent_data = parent_data;
  151. init.parent_hws = parent_hws;
  152. init.num_parents = num_parents;
  153. /* struct clk_mux assignments */
  154. mux->reg = reg;
  155. mux->shift = shift;
  156. mux->mask = mask;
  157. mux->flags = clk_mux_flags;
  158. mux->lock = lock;
  159. mux->table = table;
  160. mux->hw.init = &init;
  161. hw = &mux->hw;
  162. if (dev || !np)
  163. ret = clk_hw_register(dev, hw);
  164. else if (np)
  165. ret = of_clk_hw_register(np, hw);
  166. if (ret) {
  167. kfree(mux);
  168. hw = ERR_PTR(ret);
  169. }
  170. return hw;
  171. }
  172. EXPORT_SYMBOL_GPL(__clk_hw_register_mux);
  173. static void devm_clk_hw_release_mux(struct device *dev, void *res)
  174. {
  175. clk_hw_unregister_mux(*(struct clk_hw **)res);
  176. }
  177. struct clk_hw *__devm_clk_hw_register_mux(struct device *dev, struct device_node *np,
  178. const char *name, u8 num_parents,
  179. const char * const *parent_names,
  180. const struct clk_hw **parent_hws,
  181. const struct clk_parent_data *parent_data,
  182. unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
  183. u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
  184. {
  185. struct clk_hw **ptr, *hw;
  186. ptr = devres_alloc(devm_clk_hw_release_mux, sizeof(*ptr), GFP_KERNEL);
  187. if (!ptr)
  188. return ERR_PTR(-ENOMEM);
  189. hw = __clk_hw_register_mux(dev, np, name, num_parents, parent_names, parent_hws,
  190. parent_data, flags, reg, shift, mask,
  191. clk_mux_flags, table, lock);
  192. if (!IS_ERR(hw)) {
  193. *ptr = hw;
  194. devres_add(dev, ptr);
  195. } else {
  196. devres_free(ptr);
  197. }
  198. return hw;
  199. }
  200. EXPORT_SYMBOL_GPL(__devm_clk_hw_register_mux);
  201. struct clk *clk_register_mux_table(struct device *dev, const char *name,
  202. const char * const *parent_names, u8 num_parents,
  203. unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
  204. u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
  205. {
  206. struct clk_hw *hw;
  207. hw = clk_hw_register_mux_table(dev, name, parent_names,
  208. num_parents, flags, reg, shift, mask,
  209. clk_mux_flags, table, lock);
  210. if (IS_ERR(hw))
  211. return ERR_CAST(hw);
  212. return hw->clk;
  213. }
  214. EXPORT_SYMBOL_GPL(clk_register_mux_table);
  215. void clk_unregister_mux(struct clk *clk)
  216. {
  217. struct clk_mux *mux;
  218. struct clk_hw *hw;
  219. hw = __clk_get_hw(clk);
  220. if (!hw)
  221. return;
  222. mux = to_clk_mux(hw);
  223. clk_unregister(clk);
  224. kfree(mux);
  225. }
  226. EXPORT_SYMBOL_GPL(clk_unregister_mux);
  227. void clk_hw_unregister_mux(struct clk_hw *hw)
  228. {
  229. struct clk_mux *mux;
  230. mux = to_clk_mux(hw);
  231. clk_hw_unregister(hw);
  232. kfree(mux);
  233. }
  234. EXPORT_SYMBOL_GPL(clk_hw_unregister_mux);