jz4740-cgu.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * Ingenic JZ4740 SoC CGU driver
  3. *
  4. * Copyright (c) 2015 Imagination Technologies
  5. * Author: Paul Burton <paul.burton@imgtec.com>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include <linux/clk-provider.h>
  18. #include <linux/delay.h>
  19. #include <linux/of.h>
  20. #include <dt-bindings/clock/jz4740-cgu.h>
  21. #include <asm/mach-jz4740/clock.h>
  22. #include "cgu.h"
  23. /* CGU register offsets */
  24. #define CGU_REG_CPCCR 0x00
  25. #define CGU_REG_LCR 0x04
  26. #define CGU_REG_CPPCR 0x10
  27. #define CGU_REG_CLKGR 0x20
  28. #define CGU_REG_SCR 0x24
  29. #define CGU_REG_I2SCDR 0x60
  30. #define CGU_REG_LPCDR 0x64
  31. #define CGU_REG_MSCCDR 0x68
  32. #define CGU_REG_UHCCDR 0x6c
  33. #define CGU_REG_SSICDR 0x74
  34. /* bits within a PLL control register */
  35. #define PLLCTL_M_SHIFT 23
  36. #define PLLCTL_M_MASK (0x1ff << PLLCTL_M_SHIFT)
  37. #define PLLCTL_N_SHIFT 18
  38. #define PLLCTL_N_MASK (0x1f << PLLCTL_N_SHIFT)
  39. #define PLLCTL_OD_SHIFT 16
  40. #define PLLCTL_OD_MASK (0x3 << PLLCTL_OD_SHIFT)
  41. #define PLLCTL_STABLE (1 << 10)
  42. #define PLLCTL_BYPASS (1 << 9)
  43. #define PLLCTL_ENABLE (1 << 8)
  44. /* bits within the LCR register */
  45. #define LCR_SLEEP (1 << 0)
  46. /* bits within the CLKGR register */
  47. #define CLKGR_UDC (1 << 11)
  48. static struct ingenic_cgu *cgu;
  49. static const s8 pll_od_encoding[4] = {
  50. 0x0, 0x1, -1, 0x3,
  51. };
  52. static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
  53. /* External clocks */
  54. [JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT },
  55. [JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT },
  56. [JZ4740_CLK_PLL] = {
  57. "pll", CGU_CLK_PLL,
  58. .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
  59. .pll = {
  60. .reg = CGU_REG_CPPCR,
  61. .m_shift = 23,
  62. .m_bits = 9,
  63. .m_offset = 2,
  64. .n_shift = 18,
  65. .n_bits = 5,
  66. .n_offset = 2,
  67. .od_shift = 16,
  68. .od_bits = 2,
  69. .od_max = 4,
  70. .od_encoding = pll_od_encoding,
  71. .stable_bit = 10,
  72. .bypass_bit = 9,
  73. .enable_bit = 8,
  74. },
  75. },
  76. /* Muxes & dividers */
  77. [JZ4740_CLK_PLL_HALF] = {
  78. "pll half", CGU_CLK_DIV,
  79. .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
  80. .div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 },
  81. },
  82. [JZ4740_CLK_CCLK] = {
  83. "cclk", CGU_CLK_DIV,
  84. .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
  85. .div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 },
  86. },
  87. [JZ4740_CLK_HCLK] = {
  88. "hclk", CGU_CLK_DIV,
  89. .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
  90. .div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 },
  91. },
  92. [JZ4740_CLK_PCLK] = {
  93. "pclk", CGU_CLK_DIV,
  94. .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
  95. .div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 },
  96. },
  97. [JZ4740_CLK_MCLK] = {
  98. "mclk", CGU_CLK_DIV,
  99. .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
  100. .div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 },
  101. },
  102. [JZ4740_CLK_LCD] = {
  103. "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
  104. .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
  105. .div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 },
  106. .gate = { CGU_REG_CLKGR, 10 },
  107. },
  108. [JZ4740_CLK_LCD_PCLK] = {
  109. "lcd_pclk", CGU_CLK_DIV,
  110. .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
  111. .div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 },
  112. },
  113. [JZ4740_CLK_I2S] = {
  114. "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
  115. .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
  116. .mux = { CGU_REG_CPCCR, 31, 1 },
  117. .div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 },
  118. .gate = { CGU_REG_CLKGR, 6 },
  119. },
  120. [JZ4740_CLK_SPI] = {
  121. "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
  122. .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 },
  123. .mux = { CGU_REG_SSICDR, 31, 1 },
  124. .div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 },
  125. .gate = { CGU_REG_CLKGR, 4 },
  126. },
  127. [JZ4740_CLK_MMC] = {
  128. "mmc", CGU_CLK_DIV | CGU_CLK_GATE,
  129. .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
  130. .div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 },
  131. .gate = { CGU_REG_CLKGR, 7 },
  132. },
  133. [JZ4740_CLK_UHC] = {
  134. "uhc", CGU_CLK_DIV | CGU_CLK_GATE,
  135. .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
  136. .div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 },
  137. .gate = { CGU_REG_CLKGR, 14 },
  138. },
  139. [JZ4740_CLK_UDC] = {
  140. "udc", CGU_CLK_MUX | CGU_CLK_DIV,
  141. .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
  142. .mux = { CGU_REG_CPCCR, 29, 1 },
  143. .div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 },
  144. .gate = { CGU_REG_SCR, 6 },
  145. },
  146. /* Gate-only clocks */
  147. [JZ4740_CLK_UART0] = {
  148. "uart0", CGU_CLK_GATE,
  149. .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
  150. .gate = { CGU_REG_CLKGR, 0 },
  151. },
  152. [JZ4740_CLK_UART1] = {
  153. "uart1", CGU_CLK_GATE,
  154. .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
  155. .gate = { CGU_REG_CLKGR, 15 },
  156. },
  157. [JZ4740_CLK_DMA] = {
  158. "dma", CGU_CLK_GATE,
  159. .parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
  160. .gate = { CGU_REG_CLKGR, 12 },
  161. },
  162. [JZ4740_CLK_IPU] = {
  163. "ipu", CGU_CLK_GATE,
  164. .parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
  165. .gate = { CGU_REG_CLKGR, 13 },
  166. },
  167. [JZ4740_CLK_ADC] = {
  168. "adc", CGU_CLK_GATE,
  169. .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
  170. .gate = { CGU_REG_CLKGR, 8 },
  171. },
  172. [JZ4740_CLK_I2C] = {
  173. "i2c", CGU_CLK_GATE,
  174. .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
  175. .gate = { CGU_REG_CLKGR, 3 },
  176. },
  177. [JZ4740_CLK_AIC] = {
  178. "aic", CGU_CLK_GATE,
  179. .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
  180. .gate = { CGU_REG_CLKGR, 5 },
  181. },
  182. };
  183. static void __init jz4740_cgu_init(struct device_node *np)
  184. {
  185. int retval;
  186. cgu = ingenic_cgu_new(jz4740_cgu_clocks,
  187. ARRAY_SIZE(jz4740_cgu_clocks), np);
  188. if (!cgu) {
  189. pr_err("%s: failed to initialise CGU\n", __func__);
  190. return;
  191. }
  192. retval = ingenic_cgu_register_clocks(cgu);
  193. if (retval)
  194. pr_err("%s: failed to register CGU Clocks\n", __func__);
  195. }
  196. CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
  197. void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
  198. {
  199. uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
  200. switch (mode) {
  201. case JZ4740_WAIT_MODE_IDLE:
  202. lcr &= ~LCR_SLEEP;
  203. break;
  204. case JZ4740_WAIT_MODE_SLEEP:
  205. lcr |= LCR_SLEEP;
  206. break;
  207. }
  208. writel(lcr, cgu->base + CGU_REG_LCR);
  209. }
  210. void jz4740_clock_udc_disable_auto_suspend(void)
  211. {
  212. uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
  213. clkgr &= ~CLKGR_UDC;
  214. writel(clkgr, cgu->base + CGU_REG_CLKGR);
  215. }
  216. EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
  217. void jz4740_clock_udc_enable_auto_suspend(void)
  218. {
  219. uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
  220. clkgr |= CLKGR_UDC;
  221. writel(clkgr, cgu->base + CGU_REG_CLKGR);
  222. }
  223. EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
  224. #define JZ_CLOCK_GATE_UART0 BIT(0)
  225. #define JZ_CLOCK_GATE_TCU BIT(1)
  226. #define JZ_CLOCK_GATE_DMAC BIT(12)
  227. void jz4740_clock_suspend(void)
  228. {
  229. uint32_t clkgr, cppcr;
  230. clkgr = readl(cgu->base + CGU_REG_CLKGR);
  231. clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
  232. writel(clkgr, cgu->base + CGU_REG_CLKGR);
  233. cppcr = readl(cgu->base + CGU_REG_CPPCR);
  234. cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
  235. writel(cppcr, cgu->base + CGU_REG_CPPCR);
  236. }
  237. void jz4740_clock_resume(void)
  238. {
  239. uint32_t clkgr, cppcr, stable;
  240. cppcr = readl(cgu->base + CGU_REG_CPPCR);
  241. cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
  242. writel(cppcr, cgu->base + CGU_REG_CPPCR);
  243. stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit);
  244. do {
  245. cppcr = readl(cgu->base + CGU_REG_CPPCR);
  246. } while (!(cppcr & stable));
  247. clkgr = readl(cgu->base + CGU_REG_CLKGR);
  248. clkgr &= ~JZ_CLOCK_GATE_TCU;
  249. clkgr &= ~JZ_CLOCK_GATE_DMAC;
  250. clkgr &= ~JZ_CLOCK_GATE_UART0;
  251. writel(clkgr, cgu->base + CGU_REG_CLKGR);
  252. }