clk-gate.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * Copyright 2011-2012 Calxeda, Inc.
  3. * Copyright (C) 2012-2013 Altera Corporation <www.altera.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * Based from clk-highbank.c
  16. *
  17. */
  18. #include <linux/clk.h>
  19. #include <linux/clkdev.h>
  20. #include <linux/clk-provider.h>
  21. #include <linux/io.h>
  22. #include <linux/mfd/syscon.h>
  23. #include <linux/of.h>
  24. #include <linux/regmap.h>
  25. #include "clk.h"
  26. #define SOCFPGA_L4_MP_CLK "l4_mp_clk"
  27. #define SOCFPGA_L4_SP_CLK "l4_sp_clk"
  28. #define SOCFPGA_NAND_CLK "nand_clk"
  29. #define SOCFPGA_NAND_X_CLK "nand_x_clk"
  30. #define SOCFPGA_MMC_CLK "sdmmc_clk"
  31. #define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8
  32. #define streq(a, b) (strcmp((a), (b)) == 0)
  33. #define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
  34. /* SDMMC Group for System Manager defines */
  35. #define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108
  36. #define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
  37. ((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
  38. static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
  39. {
  40. u32 l4_src;
  41. u32 perpll_src;
  42. if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
  43. l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
  44. return l4_src &= 0x1;
  45. }
  46. if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
  47. l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
  48. return !!(l4_src & 2);
  49. }
  50. perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
  51. if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
  52. return perpll_src &= 0x3;
  53. if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
  54. streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
  55. return (perpll_src >> 2) & 3;
  56. /* QSPI clock */
  57. return (perpll_src >> 4) & 3;
  58. }
  59. static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
  60. {
  61. u32 src_reg;
  62. if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
  63. src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
  64. src_reg &= ~0x1;
  65. src_reg |= parent;
  66. writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
  67. } else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
  68. src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
  69. src_reg &= ~0x2;
  70. src_reg |= (parent << 1);
  71. writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
  72. } else {
  73. src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
  74. if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) {
  75. src_reg &= ~0x3;
  76. src_reg |= parent;
  77. } else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
  78. streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) {
  79. src_reg &= ~0xC;
  80. src_reg |= (parent << 2);
  81. } else {/* QSPI clock */
  82. src_reg &= ~0x30;
  83. src_reg |= (parent << 4);
  84. }
  85. writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
  86. }
  87. return 0;
  88. }
  89. static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
  90. unsigned long parent_rate)
  91. {
  92. struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
  93. u32 div = 1, val;
  94. if (socfpgaclk->fixed_div)
  95. div = socfpgaclk->fixed_div;
  96. else if (socfpgaclk->div_reg) {
  97. val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
  98. val &= div_mask(socfpgaclk->width);
  99. /* Check for GPIO_DB_CLK by its offset */
  100. if ((int) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET)
  101. div = val + 1;
  102. else
  103. div = (1 << val);
  104. }
  105. return parent_rate / div;
  106. }
  107. static int socfpga_clk_prepare(struct clk_hw *hwclk)
  108. {
  109. struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
  110. struct regmap *sys_mgr_base_addr;
  111. int i;
  112. u32 hs_timing;
  113. u32 clk_phase[2];
  114. if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
  115. sys_mgr_base_addr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
  116. if (IS_ERR(sys_mgr_base_addr)) {
  117. pr_err("%s: failed to find altr,sys-mgr regmap!\n", __func__);
  118. return -EINVAL;
  119. }
  120. for (i = 0; i < 2; i++) {
  121. switch (socfpgaclk->clk_phase[i]) {
  122. case 0:
  123. clk_phase[i] = 0;
  124. break;
  125. case 45:
  126. clk_phase[i] = 1;
  127. break;
  128. case 90:
  129. clk_phase[i] = 2;
  130. break;
  131. case 135:
  132. clk_phase[i] = 3;
  133. break;
  134. case 180:
  135. clk_phase[i] = 4;
  136. break;
  137. case 225:
  138. clk_phase[i] = 5;
  139. break;
  140. case 270:
  141. clk_phase[i] = 6;
  142. break;
  143. case 315:
  144. clk_phase[i] = 7;
  145. break;
  146. default:
  147. clk_phase[i] = 0;
  148. break;
  149. }
  150. }
  151. hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1]);
  152. regmap_write(sys_mgr_base_addr, SYSMGR_SDMMCGRP_CTRL_OFFSET,
  153. hs_timing);
  154. }
  155. return 0;
  156. }
  157. static struct clk_ops gateclk_ops = {
  158. .prepare = socfpga_clk_prepare,
  159. .recalc_rate = socfpga_clk_recalc_rate,
  160. .get_parent = socfpga_clk_get_parent,
  161. .set_parent = socfpga_clk_set_parent,
  162. };
  163. static void __init __socfpga_gate_init(struct device_node *node,
  164. const struct clk_ops *ops)
  165. {
  166. u32 clk_gate[2];
  167. u32 div_reg[3];
  168. u32 clk_phase[2];
  169. u32 fixed_div;
  170. struct clk *clk;
  171. struct socfpga_gate_clk *socfpga_clk;
  172. const char *clk_name = node->name;
  173. const char *parent_name[SOCFPGA_MAX_PARENTS];
  174. struct clk_init_data init;
  175. int rc;
  176. int i = 0;
  177. socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
  178. if (WARN_ON(!socfpga_clk))
  179. return;
  180. rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
  181. if (rc)
  182. clk_gate[0] = 0;
  183. if (clk_gate[0]) {
  184. socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
  185. socfpga_clk->hw.bit_idx = clk_gate[1];
  186. gateclk_ops.enable = clk_gate_ops.enable;
  187. gateclk_ops.disable = clk_gate_ops.disable;
  188. }
  189. rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
  190. if (rc)
  191. socfpga_clk->fixed_div = 0;
  192. else
  193. socfpga_clk->fixed_div = fixed_div;
  194. rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
  195. if (!rc) {
  196. socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
  197. socfpga_clk->shift = div_reg[1];
  198. socfpga_clk->width = div_reg[2];
  199. } else {
  200. socfpga_clk->div_reg = 0;
  201. }
  202. rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
  203. if (!rc) {
  204. socfpga_clk->clk_phase[0] = clk_phase[0];
  205. socfpga_clk->clk_phase[1] = clk_phase[1];
  206. }
  207. of_property_read_string(node, "clock-output-names", &clk_name);
  208. init.name = clk_name;
  209. init.ops = ops;
  210. init.flags = 0;
  211. while (i < SOCFPGA_MAX_PARENTS && (parent_name[i] =
  212. of_clk_get_parent_name(node, i)) != NULL)
  213. i++;
  214. init.parent_names = parent_name;
  215. init.num_parents = i;
  216. socfpga_clk->hw.hw.init = &init;
  217. clk = clk_register(NULL, &socfpga_clk->hw.hw);
  218. if (WARN_ON(IS_ERR(clk))) {
  219. kfree(socfpga_clk);
  220. return;
  221. }
  222. rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
  223. if (WARN_ON(rc))
  224. return;
  225. }
  226. void __init socfpga_gate_init(struct device_node *node)
  227. {
  228. __socfpga_gate_init(node, &gateclk_ops);
  229. }