]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/clk/ingenic/jz4725b-cgu.c
clk: ingenic: Add support for divider tables
[linux.git] / drivers / clk / ingenic / jz4725b-cgu.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Ingenic JZ4725B SoC CGU driver
4  *
5  * Copyright (C) 2018 Paul Cercueil
6  * Author: Paul Cercueil <paul@crapouillou.net>
7  */
8
9 #include <linux/clk-provider.h>
10 #include <linux/delay.h>
11 #include <linux/of.h>
12 #include <dt-bindings/clock/jz4725b-cgu.h>
13 #include "cgu.h"
14
15 /* CGU register offsets */
16 #define CGU_REG_CPCCR           0x00
17 #define CGU_REG_LCR             0x04
18 #define CGU_REG_CPPCR           0x10
19 #define CGU_REG_CLKGR           0x20
20 #define CGU_REG_OPCR            0x24
21 #define CGU_REG_I2SCDR          0x60
22 #define CGU_REG_LPCDR           0x64
23 #define CGU_REG_MSCCDR          0x68
24 #define CGU_REG_SSICDR          0x74
25 #define CGU_REG_CIMCDR          0x78
26
27 /* bits within the LCR register */
28 #define LCR_SLEEP               BIT(0)
29
30 static struct ingenic_cgu *cgu;
31
32 static const s8 pll_od_encoding[4] = {
33         0x0, 0x1, -1, 0x3,
34 };
35
36 static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
37
38         /* External clocks */
39
40         [JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT },
41         [JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
42
43         [JZ4725B_CLK_PLL] = {
44                 "pll", CGU_CLK_PLL,
45                 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
46                 .pll = {
47                         .reg = CGU_REG_CPPCR,
48                         .m_shift = 23,
49                         .m_bits = 9,
50                         .m_offset = 2,
51                         .n_shift = 18,
52                         .n_bits = 5,
53                         .n_offset = 2,
54                         .od_shift = 16,
55                         .od_bits = 2,
56                         .od_max = 4,
57                         .od_encoding = pll_od_encoding,
58                         .stable_bit = 10,
59                         .bypass_bit = 9,
60                         .enable_bit = 8,
61                 },
62         },
63
64         /* Muxes & dividers */
65
66         [JZ4725B_CLK_PLL_HALF] = {
67                 "pll half", CGU_CLK_DIV,
68                 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
69                 .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 },
70         },
71
72         [JZ4725B_CLK_CCLK] = {
73                 "cclk", CGU_CLK_DIV,
74                 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
75                 .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
76         },
77
78         [JZ4725B_CLK_HCLK] = {
79                 "hclk", CGU_CLK_DIV,
80                 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
81                 .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
82         },
83
84         [JZ4725B_CLK_PCLK] = {
85                 "pclk", CGU_CLK_DIV,
86                 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
87                 .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
88         },
89
90         [JZ4725B_CLK_MCLK] = {
91                 "mclk", CGU_CLK_DIV,
92                 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
93                 .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
94         },
95
96         [JZ4725B_CLK_IPU] = {
97                 "ipu", CGU_CLK_DIV | CGU_CLK_GATE,
98                 .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
99                 .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
100                 .gate = { CGU_REG_CLKGR, 13 },
101         },
102
103         [JZ4725B_CLK_LCD] = {
104                 "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
105                 .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },
106                 .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
107                 .gate = { CGU_REG_CLKGR, 9 },
108         },
109
110         [JZ4725B_CLK_I2S] = {
111                 "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
112                 .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
113                 .mux = { CGU_REG_CPCCR, 31, 1 },
114                 .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
115                 .gate = { CGU_REG_CLKGR, 6 },
116         },
117
118         [JZ4725B_CLK_SPI] = {
119                 "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
120                 .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 },
121                 .mux = { CGU_REG_SSICDR, 31, 1 },
122                 .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
123                 .gate = { CGU_REG_CLKGR, 4 },
124         },
125
126         [JZ4725B_CLK_MMC_MUX] = {
127                 "mmc_mux", CGU_CLK_DIV,
128                 .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },
129                 .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
130         },
131
132         [JZ4725B_CLK_UDC] = {
133                 "udc", CGU_CLK_MUX | CGU_CLK_DIV,
134                 .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
135                 .mux = { CGU_REG_CPCCR, 29, 1 },
136                 .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
137         },
138
139         /* Gate-only clocks */
140
141         [JZ4725B_CLK_UART] = {
142                 "uart", CGU_CLK_GATE,
143                 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
144                 .gate = { CGU_REG_CLKGR, 0 },
145         },
146
147         [JZ4725B_CLK_DMA] = {
148                 "dma", CGU_CLK_GATE,
149                 .parents = { JZ4725B_CLK_PCLK, -1, -1, -1 },
150                 .gate = { CGU_REG_CLKGR, 12 },
151         },
152
153         [JZ4725B_CLK_ADC] = {
154                 "adc", CGU_CLK_GATE,
155                 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
156                 .gate = { CGU_REG_CLKGR, 7 },
157         },
158
159         [JZ4725B_CLK_I2C] = {
160                 "i2c", CGU_CLK_GATE,
161                 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
162                 .gate = { CGU_REG_CLKGR, 3 },
163         },
164
165         [JZ4725B_CLK_AIC] = {
166                 "aic", CGU_CLK_GATE,
167                 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
168                 .gate = { CGU_REG_CLKGR, 5 },
169         },
170
171         [JZ4725B_CLK_MMC0] = {
172                 "mmc0", CGU_CLK_GATE,
173                 .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },
174                 .gate = { CGU_REG_CLKGR, 6 },
175         },
176
177         [JZ4725B_CLK_MMC1] = {
178                 "mmc1", CGU_CLK_GATE,
179                 .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },
180                 .gate = { CGU_REG_CLKGR, 16 },
181         },
182
183         [JZ4725B_CLK_BCH] = {
184                 "bch", CGU_CLK_GATE,
185                 .parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 },
186                 .gate = { CGU_REG_CLKGR, 11 },
187         },
188
189         [JZ4725B_CLK_TCU] = {
190                 "tcu", CGU_CLK_GATE,
191                 .parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 },
192                 .gate = { CGU_REG_CLKGR, 1 },
193         },
194
195         [JZ4725B_CLK_EXT512] = {
196                 "ext/512", CGU_CLK_FIXDIV,
197                 .parents = { JZ4725B_CLK_EXT },
198
199                 /* Doc calls it EXT512, but it seems to be /256... */
200                 .fixdiv = { 256 },
201         },
202
203         [JZ4725B_CLK_RTC] = {
204                 "rtc", CGU_CLK_MUX,
205                 .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 },
206                 .mux = { CGU_REG_OPCR, 2, 1},
207         },
208
209         [JZ4725B_CLK_UDC_PHY] = {
210                 "udc_phy", CGU_CLK_GATE,
211                 .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
212                 .gate = { CGU_REG_OPCR, 6, true },
213         },
214 };
215
216 static void __init jz4725b_cgu_init(struct device_node *np)
217 {
218         int retval;
219
220         cgu = ingenic_cgu_new(jz4725b_cgu_clocks,
221                               ARRAY_SIZE(jz4725b_cgu_clocks), np);
222         if (!cgu) {
223                 pr_err("%s: failed to initialise CGU\n", __func__);
224                 return;
225         }
226
227         retval = ingenic_cgu_register_clocks(cgu);
228         if (retval)
229                 pr_err("%s: failed to register CGU Clocks\n", __func__);
230 }
231 CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);