clk-sun4i-tcon-ch1.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * Copyright 2015 Maxime Ripard
  3. *
  4. * Maxime Ripard <maxime.ripard@free-electrons.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/clk-provider.h>
  17. #include <linux/of.h>
  18. #include <linux/of_address.h>
  19. #include <linux/slab.h>
  20. #include <linux/spinlock.h>
  21. #define TCON_CH1_SCLK2_PARENTS 4
  22. #define TCON_CH1_SCLK2_GATE_BIT BIT(31)
  23. #define TCON_CH1_SCLK2_MUX_MASK 3
  24. #define TCON_CH1_SCLK2_MUX_SHIFT 24
  25. #define TCON_CH1_SCLK2_DIV_MASK 0xf
  26. #define TCON_CH1_SCLK2_DIV_SHIFT 0
  27. #define TCON_CH1_SCLK1_GATE_BIT BIT(15)
  28. #define TCON_CH1_SCLK1_HALF_BIT BIT(11)
  29. struct tcon_ch1_clk {
  30. struct clk_hw hw;
  31. spinlock_t lock;
  32. void __iomem *reg;
  33. };
  34. #define hw_to_tclk(hw) container_of(hw, struct tcon_ch1_clk, hw)
  35. static void tcon_ch1_disable(struct clk_hw *hw)
  36. {
  37. struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
  38. unsigned long flags;
  39. u32 reg;
  40. spin_lock_irqsave(&tclk->lock, flags);
  41. reg = readl(tclk->reg);
  42. reg &= ~(TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT);
  43. writel(reg, tclk->reg);
  44. spin_unlock_irqrestore(&tclk->lock, flags);
  45. }
  46. static int tcon_ch1_enable(struct clk_hw *hw)
  47. {
  48. struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
  49. unsigned long flags;
  50. u32 reg;
  51. spin_lock_irqsave(&tclk->lock, flags);
  52. reg = readl(tclk->reg);
  53. reg |= TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT;
  54. writel(reg, tclk->reg);
  55. spin_unlock_irqrestore(&tclk->lock, flags);
  56. return 0;
  57. }
  58. static int tcon_ch1_is_enabled(struct clk_hw *hw)
  59. {
  60. struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
  61. u32 reg;
  62. reg = readl(tclk->reg);
  63. return reg & (TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT);
  64. }
  65. static u8 tcon_ch1_get_parent(struct clk_hw *hw)
  66. {
  67. struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
  68. u32 reg;
  69. reg = readl(tclk->reg) >> TCON_CH1_SCLK2_MUX_SHIFT;
  70. reg &= reg >> TCON_CH1_SCLK2_MUX_MASK;
  71. return reg;
  72. }
  73. static int tcon_ch1_set_parent(struct clk_hw *hw, u8 index)
  74. {
  75. struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
  76. unsigned long flags;
  77. u32 reg;
  78. spin_lock_irqsave(&tclk->lock, flags);
  79. reg = readl(tclk->reg);
  80. reg &= ~(TCON_CH1_SCLK2_MUX_MASK << TCON_CH1_SCLK2_MUX_SHIFT);
  81. reg |= index << TCON_CH1_SCLK2_MUX_SHIFT;
  82. writel(reg, tclk->reg);
  83. spin_unlock_irqrestore(&tclk->lock, flags);
  84. return 0;
  85. };
  86. static unsigned long tcon_ch1_calc_divider(unsigned long rate,
  87. unsigned long parent_rate,
  88. u8 *div,
  89. bool *half)
  90. {
  91. unsigned long best_rate = 0;
  92. u8 best_m = 0, m;
  93. bool is_double;
  94. for (m = 1; m < 16; m++) {
  95. u8 d;
  96. for (d = 1; d < 3; d++) {
  97. unsigned long tmp_rate;
  98. tmp_rate = parent_rate / m / d;
  99. if (tmp_rate > rate)
  100. continue;
  101. if (!best_rate ||
  102. (rate - tmp_rate) < (rate - best_rate)) {
  103. best_rate = tmp_rate;
  104. best_m = m;
  105. is_double = d;
  106. }
  107. }
  108. }
  109. if (div && half) {
  110. *div = best_m;
  111. *half = is_double;
  112. }
  113. return best_rate;
  114. }
  115. static int tcon_ch1_determine_rate(struct clk_hw *hw,
  116. struct clk_rate_request *req)
  117. {
  118. long best_rate = -EINVAL;
  119. int i;
  120. for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
  121. unsigned long parent_rate;
  122. unsigned long tmp_rate;
  123. struct clk_hw *parent;
  124. parent = clk_hw_get_parent_by_index(hw, i);
  125. if (!parent)
  126. continue;
  127. parent_rate = clk_hw_get_rate(parent);
  128. tmp_rate = tcon_ch1_calc_divider(req->rate, parent_rate,
  129. NULL, NULL);
  130. if (best_rate < 0 ||
  131. (req->rate - tmp_rate) < (req->rate - best_rate)) {
  132. best_rate = tmp_rate;
  133. req->best_parent_rate = parent_rate;
  134. req->best_parent_hw = parent;
  135. }
  136. }
  137. if (best_rate < 0)
  138. return best_rate;
  139. req->rate = best_rate;
  140. return 0;
  141. }
  142. static unsigned long tcon_ch1_recalc_rate(struct clk_hw *hw,
  143. unsigned long parent_rate)
  144. {
  145. struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
  146. u32 reg;
  147. reg = readl(tclk->reg);
  148. parent_rate /= (reg & TCON_CH1_SCLK2_DIV_MASK) + 1;
  149. if (reg & TCON_CH1_SCLK1_HALF_BIT)
  150. parent_rate /= 2;
  151. return parent_rate;
  152. }
  153. static int tcon_ch1_set_rate(struct clk_hw *hw, unsigned long rate,
  154. unsigned long parent_rate)
  155. {
  156. struct tcon_ch1_clk *tclk = hw_to_tclk(hw);
  157. unsigned long flags;
  158. bool half;
  159. u8 div_m;
  160. u32 reg;
  161. tcon_ch1_calc_divider(rate, parent_rate, &div_m, &half);
  162. spin_lock_irqsave(&tclk->lock, flags);
  163. reg = readl(tclk->reg);
  164. reg &= ~(TCON_CH1_SCLK2_DIV_MASK | TCON_CH1_SCLK1_HALF_BIT);
  165. reg |= (div_m - 1) & TCON_CH1_SCLK2_DIV_MASK;
  166. if (half)
  167. reg |= TCON_CH1_SCLK1_HALF_BIT;
  168. writel(reg, tclk->reg);
  169. spin_unlock_irqrestore(&tclk->lock, flags);
  170. return 0;
  171. }
  172. static const struct clk_ops tcon_ch1_ops = {
  173. .disable = tcon_ch1_disable,
  174. .enable = tcon_ch1_enable,
  175. .is_enabled = tcon_ch1_is_enabled,
  176. .get_parent = tcon_ch1_get_parent,
  177. .set_parent = tcon_ch1_set_parent,
  178. .determine_rate = tcon_ch1_determine_rate,
  179. .recalc_rate = tcon_ch1_recalc_rate,
  180. .set_rate = tcon_ch1_set_rate,
  181. };
  182. static void __init tcon_ch1_setup(struct device_node *node)
  183. {
  184. const char *parents[TCON_CH1_SCLK2_PARENTS];
  185. const char *clk_name = node->name;
  186. struct clk_init_data init;
  187. struct tcon_ch1_clk *tclk;
  188. struct resource res;
  189. struct clk *clk;
  190. void __iomem *reg;
  191. int ret;
  192. of_property_read_string(node, "clock-output-names", &clk_name);
  193. reg = of_io_request_and_map(node, 0, of_node_full_name(node));
  194. if (IS_ERR(reg)) {
  195. pr_err("%s: Could not map the clock registers\n", clk_name);
  196. return;
  197. }
  198. ret = of_clk_parent_fill(node, parents, TCON_CH1_SCLK2_PARENTS);
  199. if (ret != TCON_CH1_SCLK2_PARENTS) {
  200. pr_err("%s Could not retrieve the parents\n", clk_name);
  201. goto err_unmap;
  202. }
  203. tclk = kzalloc(sizeof(*tclk), GFP_KERNEL);
  204. if (!tclk)
  205. goto err_unmap;
  206. init.name = clk_name;
  207. init.ops = &tcon_ch1_ops;
  208. init.parent_names = parents;
  209. init.num_parents = TCON_CH1_SCLK2_PARENTS;
  210. init.flags = CLK_SET_RATE_PARENT;
  211. tclk->reg = reg;
  212. tclk->hw.init = &init;
  213. spin_lock_init(&tclk->lock);
  214. clk = clk_register(NULL, &tclk->hw);
  215. if (IS_ERR(clk)) {
  216. pr_err("%s: Couldn't register the clock\n", clk_name);
  217. goto err_free_data;
  218. }
  219. ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
  220. if (ret) {
  221. pr_err("%s: Couldn't register our clock provider\n", clk_name);
  222. goto err_unregister_clk;
  223. }
  224. return;
  225. err_unregister_clk:
  226. clk_unregister(clk);
  227. err_free_data:
  228. kfree(tclk);
  229. err_unmap:
  230. iounmap(reg);
  231. of_address_to_resource(node, 0, &res);
  232. release_mem_region(res.start, resource_size(&res));
  233. }
  234. CLK_OF_DECLARE(tcon_ch1, "allwinner,sun4i-a10-tcon-ch1-clk",
  235. tcon_ch1_setup);