Commit | Line | Data |
---|---|---|
b04e0b8f JE |
1 | /* |
2 | * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU) | |
3 | * | |
4 | * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> | |
5 | * | |
6 | * This file is licensed under the terms of the GNU General Public | |
7 | * License version 2. This program is licensed "as is" without any | |
8 | * warranty of any kind, whether express or implied. | |
9 | */ | |
10 | ||
b04e0b8f JE |
11 | #include <linux/clk-provider.h> |
12 | #include <linux/delay.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/of.h> | |
15 | #include <linux/of_address.h> | |
16 | ||
17 | #include <dt-bindings/clock/lpc18xx-cgu.h> | |
18 | ||
19 | /* Clock Generation Unit (CGU) registers */ | |
20 | #define LPC18XX_CGU_XTAL_OSC_CTRL 0x018 | |
21 | #define LPC18XX_CGU_PLL0USB_STAT 0x01c | |
22 | #define LPC18XX_CGU_PLL0USB_CTRL 0x020 | |
23 | #define LPC18XX_CGU_PLL0USB_MDIV 0x024 | |
24 | #define LPC18XX_CGU_PLL0USB_NP_DIV 0x028 | |
25 | #define LPC18XX_CGU_PLL0AUDIO_STAT 0x02c | |
26 | #define LPC18XX_CGU_PLL0AUDIO_CTRL 0x030 | |
27 | #define LPC18XX_CGU_PLL0AUDIO_MDIV 0x034 | |
28 | #define LPC18XX_CGU_PLL0AUDIO_NP_DIV 0x038 | |
29 | #define LPC18XX_CGU_PLL0AUDIO_FRAC 0x03c | |
30 | #define LPC18XX_CGU_PLL1_STAT 0x040 | |
31 | #define LPC18XX_CGU_PLL1_CTRL 0x044 | |
32 | #define LPC18XX_PLL1_CTRL_FBSEL BIT(6) | |
33 | #define LPC18XX_PLL1_CTRL_DIRECT BIT(7) | |
34 | #define LPC18XX_CGU_IDIV_CTRL(n) (0x048 + (n) * sizeof(u32)) | |
35 | #define LPC18XX_CGU_BASE_CLK(id) (0x05c + (id) * sizeof(u32)) | |
36 | #define LPC18XX_CGU_PLL_CTRL_OFFSET 0x4 | |
37 | ||
38 | /* PLL0 bits common to both audio and USB PLL */ | |
39 | #define LPC18XX_PLL0_STAT_LOCK BIT(0) | |
40 | #define LPC18XX_PLL0_CTRL_PD BIT(0) | |
41 | #define LPC18XX_PLL0_CTRL_BYPASS BIT(1) | |
42 | #define LPC18XX_PLL0_CTRL_DIRECTI BIT(2) | |
43 | #define LPC18XX_PLL0_CTRL_DIRECTO BIT(3) | |
44 | #define LPC18XX_PLL0_CTRL_CLKEN BIT(4) | |
45 | #define LPC18XX_PLL0_MDIV_MDEC_MASK 0x1ffff | |
46 | #define LPC18XX_PLL0_MDIV_SELP_SHIFT 17 | |
47 | #define LPC18XX_PLL0_MDIV_SELI_SHIFT 22 | |
48 | #define LPC18XX_PLL0_MSEL_MAX BIT(15) | |
49 | ||
50 | /* Register value that gives PLL0 post/pre dividers equal to 1 */ | |
51 | #define LPC18XX_PLL0_NP_DIVS_1 0x00302062 | |
52 | ||
53 | enum { | |
54 | CLK_SRC_OSC32, | |
55 | CLK_SRC_IRC, | |
56 | CLK_SRC_ENET_RX_CLK, | |
57 | CLK_SRC_ENET_TX_CLK, | |
58 | CLK_SRC_GP_CLKIN, | |
59 | CLK_SRC_RESERVED1, | |
60 | CLK_SRC_OSC, | |
61 | CLK_SRC_PLL0USB, | |
62 | CLK_SRC_PLL0AUDIO, | |
63 | CLK_SRC_PLL1, | |
64 | CLK_SRC_RESERVED2, | |
65 | CLK_SRC_RESERVED3, | |
66 | CLK_SRC_IDIVA, | |
67 | CLK_SRC_IDIVB, | |
68 | CLK_SRC_IDIVC, | |
69 | CLK_SRC_IDIVD, | |
70 | CLK_SRC_IDIVE, | |
71 | CLK_SRC_MAX | |
72 | }; | |
73 | ||
74 | static const char *clk_src_names[CLK_SRC_MAX] = { | |
75 | [CLK_SRC_OSC32] = "osc32", | |
76 | [CLK_SRC_IRC] = "irc", | |
77 | [CLK_SRC_ENET_RX_CLK] = "enet_rx_clk", | |
78 | [CLK_SRC_ENET_TX_CLK] = "enet_tx_clk", | |
79 | [CLK_SRC_GP_CLKIN] = "gp_clkin", | |
80 | [CLK_SRC_OSC] = "osc", | |
81 | [CLK_SRC_PLL0USB] = "pll0usb", | |
82 | [CLK_SRC_PLL0AUDIO] = "pll0audio", | |
83 | [CLK_SRC_PLL1] = "pll1", | |
84 | [CLK_SRC_IDIVA] = "idiva", | |
85 | [CLK_SRC_IDIVB] = "idivb", | |
86 | [CLK_SRC_IDIVC] = "idivc", | |
87 | [CLK_SRC_IDIVD] = "idivd", | |
88 | [CLK_SRC_IDIVE] = "idive", | |
89 | }; | |
90 | ||
91 | static const char *clk_base_names[BASE_CLK_MAX] = { | |
92 | [BASE_SAFE_CLK] = "base_safe_clk", | |
93 | [BASE_USB0_CLK] = "base_usb0_clk", | |
94 | [BASE_PERIPH_CLK] = "base_periph_clk", | |
95 | [BASE_USB1_CLK] = "base_usb1_clk", | |
96 | [BASE_CPU_CLK] = "base_cpu_clk", | |
97 | [BASE_SPIFI_CLK] = "base_spifi_clk", | |
98 | [BASE_SPI_CLK] = "base_spi_clk", | |
99 | [BASE_PHY_RX_CLK] = "base_phy_rx_clk", | |
100 | [BASE_PHY_TX_CLK] = "base_phy_tx_clk", | |
101 | [BASE_APB1_CLK] = "base_apb1_clk", | |
102 | [BASE_APB3_CLK] = "base_apb3_clk", | |
103 | [BASE_LCD_CLK] = "base_lcd_clk", | |
104 | [BASE_ADCHS_CLK] = "base_adchs_clk", | |
105 | [BASE_SDIO_CLK] = "base_sdio_clk", | |
106 | [BASE_SSP0_CLK] = "base_ssp0_clk", | |
107 | [BASE_SSP1_CLK] = "base_ssp1_clk", | |
108 | [BASE_UART0_CLK] = "base_uart0_clk", | |
109 | [BASE_UART1_CLK] = "base_uart1_clk", | |
110 | [BASE_UART2_CLK] = "base_uart2_clk", | |
111 | [BASE_UART3_CLK] = "base_uart3_clk", | |
112 | [BASE_OUT_CLK] = "base_out_clk", | |
113 | [BASE_AUDIO_CLK] = "base_audio_clk", | |
114 | [BASE_CGU_OUT0_CLK] = "base_cgu_out0_clk", | |
115 | [BASE_CGU_OUT1_CLK] = "base_cgu_out1_clk", | |
116 | }; | |
117 | ||
118 | static u32 lpc18xx_cgu_pll0_src_ids[] = { | |
119 | CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, | |
120 | CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, | |
121 | CLK_SRC_PLL1, CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC, | |
122 | CLK_SRC_IDIVD, CLK_SRC_IDIVE, | |
123 | }; | |
124 | ||
125 | static u32 lpc18xx_cgu_pll1_src_ids[] = { | |
126 | CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, | |
127 | CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, | |
128 | CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_IDIVA, | |
129 | CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE, | |
130 | }; | |
131 | ||
132 | static u32 lpc18xx_cgu_idiva_src_ids[] = { | |
133 | CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, | |
134 | CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, | |
135 | CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1 | |
136 | }; | |
137 | ||
138 | static u32 lpc18xx_cgu_idivbcde_src_ids[] = { | |
139 | CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, | |
140 | CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, | |
141 | CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA, | |
142 | }; | |
143 | ||
144 | static u32 lpc18xx_cgu_base_irc_src_ids[] = {CLK_SRC_IRC}; | |
145 | ||
146 | static u32 lpc18xx_cgu_base_usb0_src_ids[] = {CLK_SRC_PLL0USB}; | |
147 | ||
148 | static u32 lpc18xx_cgu_base_common_src_ids[] = { | |
149 | CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, | |
150 | CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, | |
151 | CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA, | |
152 | CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE, | |
153 | }; | |
154 | ||
155 | static u32 lpc18xx_cgu_base_all_src_ids[] = { | |
156 | CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, | |
157 | CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, | |
158 | CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, | |
159 | CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC, | |
160 | CLK_SRC_IDIVD, CLK_SRC_IDIVE, | |
161 | }; | |
162 | ||
163 | struct lpc18xx_cgu_src_clk_div { | |
164 | u8 clk_id; | |
165 | u8 n_parents; | |
166 | struct clk_divider div; | |
167 | struct clk_mux mux; | |
168 | struct clk_gate gate; | |
169 | }; | |
170 | ||
171 | #define LPC1XX_CGU_SRC_CLK_DIV(_id, _width, _table) \ | |
172 | { \ | |
173 | .clk_id = CLK_SRC_ ##_id, \ | |
174 | .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ | |
175 | .div = { \ | |
176 | .shift = 2, \ | |
177 | .width = _width, \ | |
178 | }, \ | |
179 | .mux = { \ | |
180 | .mask = 0x1f, \ | |
181 | .shift = 24, \ | |
182 | .table = lpc18xx_cgu_ ##_table, \ | |
183 | }, \ | |
184 | .gate = { \ | |
185 | .bit_idx = 0, \ | |
186 | .flags = CLK_GATE_SET_TO_DISABLE, \ | |
187 | }, \ | |
188 | } | |
189 | ||
190 | static struct lpc18xx_cgu_src_clk_div lpc18xx_cgu_src_clk_divs[] = { | |
191 | LPC1XX_CGU_SRC_CLK_DIV(IDIVA, 2, idiva_src_ids), | |
192 | LPC1XX_CGU_SRC_CLK_DIV(IDIVB, 4, idivbcde_src_ids), | |
193 | LPC1XX_CGU_SRC_CLK_DIV(IDIVC, 4, idivbcde_src_ids), | |
194 | LPC1XX_CGU_SRC_CLK_DIV(IDIVD, 4, idivbcde_src_ids), | |
195 | LPC1XX_CGU_SRC_CLK_DIV(IDIVE, 8, idivbcde_src_ids), | |
196 | }; | |
197 | ||
198 | struct lpc18xx_cgu_base_clk { | |
199 | u8 clk_id; | |
200 | u8 n_parents; | |
201 | struct clk_mux mux; | |
202 | struct clk_gate gate; | |
203 | }; | |
204 | ||
205 | #define LPC1XX_CGU_BASE_CLK(_id, _table, _flags) \ | |
206 | { \ | |
207 | .clk_id = BASE_ ##_id ##_CLK, \ | |
208 | .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ | |
209 | .mux = { \ | |
210 | .mask = 0x1f, \ | |
211 | .shift = 24, \ | |
212 | .table = lpc18xx_cgu_ ##_table, \ | |
213 | .flags = _flags, \ | |
214 | }, \ | |
215 | .gate = { \ | |
216 | .bit_idx = 0, \ | |
217 | .flags = CLK_GATE_SET_TO_DISABLE, \ | |
218 | }, \ | |
219 | } | |
220 | ||
221 | static struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = { | |
222 | LPC1XX_CGU_BASE_CLK(SAFE, base_irc_src_ids, CLK_MUX_READ_ONLY), | |
223 | LPC1XX_CGU_BASE_CLK(USB0, base_usb0_src_ids, 0), | |
224 | LPC1XX_CGU_BASE_CLK(PERIPH, base_common_src_ids, 0), | |
225 | LPC1XX_CGU_BASE_CLK(USB1, base_all_src_ids, 0), | |
226 | LPC1XX_CGU_BASE_CLK(CPU, base_common_src_ids, 0), | |
227 | LPC1XX_CGU_BASE_CLK(SPIFI, base_common_src_ids, 0), | |
228 | LPC1XX_CGU_BASE_CLK(SPI, base_common_src_ids, 0), | |
229 | LPC1XX_CGU_BASE_CLK(PHY_RX, base_common_src_ids, 0), | |
230 | LPC1XX_CGU_BASE_CLK(PHY_TX, base_common_src_ids, 0), | |
231 | LPC1XX_CGU_BASE_CLK(APB1, base_common_src_ids, 0), | |
232 | LPC1XX_CGU_BASE_CLK(APB3, base_common_src_ids, 0), | |
233 | LPC1XX_CGU_BASE_CLK(LCD, base_common_src_ids, 0), | |
234 | LPC1XX_CGU_BASE_CLK(ADCHS, base_common_src_ids, 0), | |
235 | LPC1XX_CGU_BASE_CLK(SDIO, base_common_src_ids, 0), | |
236 | LPC1XX_CGU_BASE_CLK(SSP0, base_common_src_ids, 0), | |
237 | LPC1XX_CGU_BASE_CLK(SSP1, base_common_src_ids, 0), | |
238 | LPC1XX_CGU_BASE_CLK(UART0, base_common_src_ids, 0), | |
239 | LPC1XX_CGU_BASE_CLK(UART1, base_common_src_ids, 0), | |
240 | LPC1XX_CGU_BASE_CLK(UART2, base_common_src_ids, 0), | |
241 | LPC1XX_CGU_BASE_CLK(UART3, base_common_src_ids, 0), | |
242 | LPC1XX_CGU_BASE_CLK(OUT, base_all_src_ids, 0), | |
243 | { /* 21 reserved */ }, | |
244 | { /* 22 reserved */ }, | |
245 | { /* 23 reserved */ }, | |
246 | { /* 24 reserved */ }, | |
247 | LPC1XX_CGU_BASE_CLK(AUDIO, base_common_src_ids, 0), | |
248 | LPC1XX_CGU_BASE_CLK(CGU_OUT0, base_all_src_ids, 0), | |
249 | LPC1XX_CGU_BASE_CLK(CGU_OUT1, base_all_src_ids, 0), | |
250 | }; | |
251 | ||
252 | struct lpc18xx_pll { | |
253 | struct clk_hw hw; | |
254 | void __iomem *reg; | |
255 | spinlock_t *lock; | |
256 | u8 flags; | |
257 | }; | |
258 | ||
259 | #define to_lpc_pll(hw) container_of(hw, struct lpc18xx_pll, hw) | |
260 | ||
261 | struct lpc18xx_cgu_pll_clk { | |
262 | u8 clk_id; | |
263 | u8 n_parents; | |
264 | u8 reg_offset; | |
265 | struct clk_mux mux; | |
266 | struct clk_gate gate; | |
267 | struct lpc18xx_pll pll; | |
268 | const struct clk_ops *pll_ops; | |
269 | }; | |
270 | ||
271 | #define LPC1XX_CGU_CLK_PLL(_id, _table, _pll_ops) \ | |
272 | { \ | |
273 | .clk_id = CLK_SRC_ ##_id, \ | |
274 | .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ | |
275 | .reg_offset = LPC18XX_CGU_ ##_id ##_STAT, \ | |
276 | .mux = { \ | |
277 | .mask = 0x1f, \ | |
278 | .shift = 24, \ | |
279 | .table = lpc18xx_cgu_ ##_table, \ | |
280 | }, \ | |
281 | .gate = { \ | |
282 | .bit_idx = 0, \ | |
283 | .flags = CLK_GATE_SET_TO_DISABLE, \ | |
284 | }, \ | |
285 | .pll_ops = &lpc18xx_ ##_pll_ops, \ | |
286 | } | |
287 | ||
288 | /* | |
289 | * PLL0 uses a special register value encoding. The compute functions below | |
290 | * are taken or derived from the LPC1850 user manual (section 12.6.3.3). | |
291 | */ | |
292 | ||
293 | /* Compute PLL0 multiplier from decoded version */ | |
294 | static u32 lpc18xx_pll0_mdec2msel(u32 x) | |
295 | { | |
296 | int i; | |
297 | ||
298 | switch (x) { | |
299 | case 0x18003: return 1; | |
300 | case 0x10003: return 2; | |
301 | default: | |
302 | for (i = LPC18XX_PLL0_MSEL_MAX + 1; x != 0x4000 && i > 0; i--) | |
303 | x = ((x ^ x >> 14) & 1) | (x << 1 & 0x7fff); | |
304 | return i; | |
305 | } | |
306 | } | |
307 | /* Compute PLL0 decoded multiplier from binary version */ | |
308 | static u32 lpc18xx_pll0_msel2mdec(u32 msel) | |
309 | { | |
310 | u32 i, x = 0x4000; | |
311 | ||
312 | switch (msel) { | |
313 | case 0: return 0; | |
314 | case 1: return 0x18003; | |
315 | case 2: return 0x10003; | |
316 | default: | |
317 | for (i = msel; i <= LPC18XX_PLL0_MSEL_MAX; i++) | |
318 | x = ((x ^ x >> 1) & 1) << 14 | (x >> 1 & 0xffff); | |
319 | return x; | |
320 | } | |
321 | } | |
322 | ||
323 | /* Compute PLL0 bandwidth SELI reg from multiplier */ | |
324 | static u32 lpc18xx_pll0_msel2seli(u32 msel) | |
325 | { | |
326 | u32 tmp; | |
327 | ||
328 | if (msel > 16384) return 1; | |
329 | if (msel > 8192) return 2; | |
330 | if (msel > 2048) return 4; | |
331 | if (msel >= 501) return 8; | |
332 | if (msel >= 60) { | |
333 | tmp = 1024 / (msel + 9); | |
334 | return ((1024 == (tmp * (msel + 9))) == 0) ? tmp * 4 : (tmp + 1) * 4; | |
335 | } | |
336 | ||
337 | return (msel & 0x3c) + 4; | |
338 | } | |
339 | ||
340 | /* Compute PLL0 bandwidth SELP reg from multiplier */ | |
341 | static u32 lpc18xx_pll0_msel2selp(u32 msel) | |
342 | { | |
343 | if (msel < 60) | |
344 | return (msel >> 1) + 1; | |
345 | ||
346 | return 31; | |
347 | } | |
348 | ||
349 | static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw, | |
350 | unsigned long parent_rate) | |
351 | { | |
352 | struct lpc18xx_pll *pll = to_lpc_pll(hw); | |
353 | u32 ctrl, mdiv, msel, npdiv; | |
354 | ||
355 | ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); | |
356 | mdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV); | |
357 | npdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); | |
358 | ||
359 | if (ctrl & LPC18XX_PLL0_CTRL_BYPASS) | |
360 | return parent_rate; | |
361 | ||
362 | if (npdiv != LPC18XX_PLL0_NP_DIVS_1) { | |
363 | pr_warn("%s: pre/post dividers not supported\n", __func__); | |
364 | return 0; | |
365 | } | |
366 | ||
367 | msel = lpc18xx_pll0_mdec2msel(mdiv & LPC18XX_PLL0_MDIV_MDEC_MASK); | |
368 | if (msel) | |
369 | return 2 * msel * parent_rate; | |
370 | ||
371 | pr_warn("%s: unable to calculate rate\n", __func__); | |
372 | ||
373 | return 0; | |
374 | } | |
375 | ||
376 | static long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate, | |
377 | unsigned long *prate) | |
378 | { | |
379 | unsigned long m; | |
380 | ||
381 | if (*prate < rate) { | |
382 | pr_warn("%s: pll dividers not supported\n", __func__); | |
383 | return -EINVAL; | |
384 | } | |
385 | ||
386 | m = DIV_ROUND_UP_ULL(*prate, rate * 2); | |
387 | if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { | |
388 | pr_warn("%s: unable to support rate %lu\n", __func__, rate); | |
389 | return -EINVAL; | |
390 | } | |
391 | ||
392 | return 2 * *prate * m; | |
393 | } | |
394 | ||
395 | static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate, | |
396 | unsigned long parent_rate) | |
397 | { | |
398 | struct lpc18xx_pll *pll = to_lpc_pll(hw); | |
399 | u32 ctrl, stat, m; | |
400 | int retry = 3; | |
401 | ||
402 | if (parent_rate < rate) { | |
403 | pr_warn("%s: pll dividers not supported\n", __func__); | |
404 | return -EINVAL; | |
405 | } | |
406 | ||
407 | m = DIV_ROUND_UP_ULL(parent_rate, rate * 2); | |
408 | if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { | |
409 | pr_warn("%s: unable to support rate %lu\n", __func__, rate); | |
410 | return -EINVAL; | |
411 | } | |
412 | ||
413 | m = lpc18xx_pll0_msel2mdec(m); | |
414 | m |= lpc18xx_pll0_msel2selp(m) << LPC18XX_PLL0_MDIV_SELP_SHIFT; | |
415 | m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT; | |
416 | ||
417 | /* Power down PLL, disable clk output and dividers */ | |
418 | ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); | |
419 | ctrl |= LPC18XX_PLL0_CTRL_PD; | |
420 | ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI | | |
421 | LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN); | |
422 | clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); | |
423 | ||
424 | /* Configure new PLL settings */ | |
425 | clk_writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV); | |
426 | clk_writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); | |
427 | ||
428 | /* Power up PLL and wait for lock */ | |
429 | ctrl &= ~LPC18XX_PLL0_CTRL_PD; | |
430 | clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); | |
431 | do { | |
432 | udelay(10); | |
433 | stat = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT); | |
434 | if (stat & LPC18XX_PLL0_STAT_LOCK) { | |
435 | ctrl |= LPC18XX_PLL0_CTRL_CLKEN; | |
436 | clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); | |
437 | ||
438 | return 0; | |
439 | } | |
440 | } while (retry--); | |
441 | ||
442 | pr_warn("%s: unable to lock pll\n", __func__); | |
443 | ||
444 | return -EINVAL; | |
445 | } | |
446 | ||
447 | static const struct clk_ops lpc18xx_pll0_ops = { | |
448 | .recalc_rate = lpc18xx_pll0_recalc_rate, | |
449 | .round_rate = lpc18xx_pll0_round_rate, | |
450 | .set_rate = lpc18xx_pll0_set_rate, | |
451 | }; | |
452 | ||
453 | static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw, | |
454 | unsigned long parent_rate) | |
455 | { | |
456 | struct lpc18xx_pll *pll = to_lpc_pll(hw); | |
457 | u16 msel, nsel, psel; | |
458 | bool direct, fbsel; | |
459 | u32 stat, ctrl; | |
460 | ||
461 | stat = clk_readl(pll->reg + LPC18XX_CGU_PLL1_STAT); | |
462 | ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL1_CTRL); | |
463 | ||
464 | direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false; | |
465 | fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false; | |
466 | ||
467 | msel = ((ctrl >> 16) & 0xff) + 1; | |
468 | nsel = ((ctrl >> 12) & 0x3) + 1; | |
469 | ||
470 | if (direct || fbsel) | |
471 | return msel * (parent_rate / nsel); | |
472 | ||
473 | psel = (ctrl >> 8) & 0x3; | |
474 | psel = 1 << psel; | |
475 | ||
476 | return (msel / (2 * psel)) * (parent_rate / nsel); | |
477 | } | |
478 | ||
479 | static const struct clk_ops lpc18xx_pll1_ops = { | |
480 | .recalc_rate = lpc18xx_pll1_recalc_rate, | |
481 | }; | |
482 | ||
c23a5847 JE |
483 | static int lpc18xx_cgu_gate_enable(struct clk_hw *hw) |
484 | { | |
485 | return clk_gate_ops.enable(hw); | |
486 | } | |
487 | ||
488 | static void lpc18xx_cgu_gate_disable(struct clk_hw *hw) | |
489 | { | |
490 | clk_gate_ops.disable(hw); | |
491 | } | |
492 | ||
493 | static int lpc18xx_cgu_gate_is_enabled(struct clk_hw *hw) | |
494 | { | |
495 | const struct clk_hw *parent; | |
496 | ||
497 | /* | |
498 | * The consumer of base clocks needs know if the | |
499 | * base clock is really enabled before it can be | |
500 | * accessed. It is therefore necessary to verify | |
501 | * this all the way up. | |
502 | */ | |
503 | parent = clk_hw_get_parent(hw); | |
504 | if (!parent) | |
505 | return 0; | |
506 | ||
507 | if (!clk_hw_is_enabled(parent)) | |
508 | return 0; | |
509 | ||
510 | return clk_gate_ops.is_enabled(hw); | |
511 | } | |
512 | ||
513 | static const struct clk_ops lpc18xx_gate_ops = { | |
514 | .enable = lpc18xx_cgu_gate_enable, | |
515 | .disable = lpc18xx_cgu_gate_disable, | |
516 | .is_enabled = lpc18xx_cgu_gate_is_enabled, | |
517 | }; | |
518 | ||
b04e0b8f JE |
519 | static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = { |
520 | LPC1XX_CGU_CLK_PLL(PLL0USB, pll0_src_ids, pll0_ops), | |
521 | LPC1XX_CGU_CLK_PLL(PLL0AUDIO, pll0_src_ids, pll0_ops), | |
522 | LPC1XX_CGU_CLK_PLL(PLL1, pll1_src_ids, pll1_ops), | |
523 | }; | |
524 | ||
525 | static void lpc18xx_fill_parent_names(const char **parent, u32 *id, int size) | |
526 | { | |
527 | int i; | |
528 | ||
529 | for (i = 0; i < size; i++) | |
530 | parent[i] = clk_src_names[id[i]]; | |
531 | } | |
532 | ||
533 | static struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk, | |
534 | void __iomem *base, int n) | |
535 | { | |
536 | void __iomem *reg = base + LPC18XX_CGU_IDIV_CTRL(n); | |
537 | const char *name = clk_src_names[clk->clk_id]; | |
538 | const char *parents[CLK_SRC_MAX]; | |
539 | ||
540 | clk->div.reg = reg; | |
541 | clk->mux.reg = reg; | |
542 | clk->gate.reg = reg; | |
543 | ||
544 | lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); | |
545 | ||
546 | return clk_register_composite(NULL, name, parents, clk->n_parents, | |
547 | &clk->mux.hw, &clk_mux_ops, | |
548 | &clk->div.hw, &clk_divider_ops, | |
c23a5847 | 549 | &clk->gate.hw, &lpc18xx_gate_ops, 0); |
b04e0b8f JE |
550 | } |
551 | ||
552 | ||
553 | static struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk, | |
554 | void __iomem *reg_base, int n) | |
555 | { | |
556 | void __iomem *reg = reg_base + LPC18XX_CGU_BASE_CLK(n); | |
557 | const char *name = clk_base_names[clk->clk_id]; | |
558 | const char *parents[CLK_SRC_MAX]; | |
559 | ||
560 | if (clk->n_parents == 0) | |
561 | return ERR_PTR(-ENOENT); | |
562 | ||
563 | clk->mux.reg = reg; | |
564 | clk->gate.reg = reg; | |
565 | ||
566 | lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); | |
567 | ||
568 | /* SAFE_CLK can not be turned off */ | |
569 | if (n == BASE_SAFE_CLK) | |
570 | return clk_register_composite(NULL, name, parents, clk->n_parents, | |
571 | &clk->mux.hw, &clk_mux_ops, | |
572 | NULL, NULL, NULL, NULL, 0); | |
573 | ||
574 | return clk_register_composite(NULL, name, parents, clk->n_parents, | |
575 | &clk->mux.hw, &clk_mux_ops, | |
576 | NULL, NULL, | |
c23a5847 | 577 | &clk->gate.hw, &lpc18xx_gate_ops, 0); |
b04e0b8f JE |
578 | } |
579 | ||
580 | ||
581 | static struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk, | |
582 | void __iomem *base) | |
583 | { | |
584 | const char *name = clk_src_names[clk->clk_id]; | |
585 | const char *parents[CLK_SRC_MAX]; | |
586 | ||
587 | clk->pll.reg = base; | |
588 | clk->mux.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET; | |
589 | clk->gate.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET; | |
590 | ||
591 | lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); | |
592 | ||
593 | return clk_register_composite(NULL, name, parents, clk->n_parents, | |
594 | &clk->mux.hw, &clk_mux_ops, | |
595 | &clk->pll.hw, clk->pll_ops, | |
c23a5847 | 596 | &clk->gate.hw, &lpc18xx_gate_ops, 0); |
b04e0b8f JE |
597 | } |
598 | ||
599 | static void __init lpc18xx_cgu_register_source_clks(struct device_node *np, | |
600 | void __iomem *base) | |
601 | { | |
602 | const char *parents[CLK_SRC_MAX]; | |
603 | struct clk *clk; | |
604 | int i; | |
605 | ||
606 | /* Register the internal 12 MHz RC oscillator (IRC) */ | |
607 | clk = clk_register_fixed_rate(NULL, clk_src_names[CLK_SRC_IRC], | |
608 | NULL, CLK_IS_ROOT, 12000000); | |
609 | if (IS_ERR(clk)) | |
610 | pr_warn("%s: failed to register irc clk\n", __func__); | |
611 | ||
612 | /* Register crystal oscillator controlller */ | |
613 | parents[0] = of_clk_get_parent_name(np, 0); | |
614 | clk = clk_register_gate(NULL, clk_src_names[CLK_SRC_OSC], parents[0], | |
615 | 0, base + LPC18XX_CGU_XTAL_OSC_CTRL, | |
616 | 0, CLK_GATE_SET_TO_DISABLE, NULL); | |
617 | if (IS_ERR(clk)) | |
618 | pr_warn("%s: failed to register osc clk\n", __func__); | |
619 | ||
620 | /* Register all PLLs */ | |
621 | for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_plls); i++) { | |
622 | clk = lpc18xx_cgu_register_pll(&lpc18xx_cgu_src_clk_plls[i], | |
623 | base); | |
624 | if (IS_ERR(clk)) | |
625 | pr_warn("%s: failed to register pll (%d)\n", __func__, i); | |
626 | } | |
627 | ||
628 | /* Register all clock dividers A-E */ | |
629 | for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_divs); i++) { | |
630 | clk = lpc18xx_cgu_register_div(&lpc18xx_cgu_src_clk_divs[i], | |
631 | base, i); | |
632 | if (IS_ERR(clk)) | |
633 | pr_warn("%s: failed to register div %d\n", __func__, i); | |
634 | } | |
635 | } | |
636 | ||
637 | static struct clk *clk_base[BASE_CLK_MAX]; | |
638 | static struct clk_onecell_data clk_base_data = { | |
639 | .clks = clk_base, | |
640 | .clk_num = BASE_CLK_MAX, | |
641 | }; | |
642 | ||
643 | static void __init lpc18xx_cgu_register_base_clks(void __iomem *reg_base) | |
644 | { | |
645 | int i; | |
646 | ||
647 | for (i = BASE_SAFE_CLK; i < BASE_CLK_MAX; i++) { | |
648 | clk_base[i] = lpc18xx_register_base_clk(&lpc18xx_cgu_base_clks[i], | |
649 | reg_base, i); | |
650 | if (IS_ERR(clk_base[i]) && PTR_ERR(clk_base[i]) != -ENOENT) | |
651 | pr_warn("%s: register base clk %d failed\n", __func__, i); | |
652 | } | |
653 | } | |
654 | ||
655 | static void __init lpc18xx_cgu_init(struct device_node *np) | |
656 | { | |
657 | void __iomem *reg_base; | |
658 | ||
659 | reg_base = of_iomap(np, 0); | |
660 | if (!reg_base) { | |
661 | pr_warn("%s: failed to map address range\n", __func__); | |
662 | return; | |
663 | } | |
664 | ||
665 | lpc18xx_cgu_register_source_clks(np, reg_base); | |
666 | lpc18xx_cgu_register_base_clks(reg_base); | |
667 | ||
668 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_base_data); | |
669 | } | |
670 | CLK_OF_DECLARE(lpc18xx_cgu, "nxp,lpc1850-cgu", lpc18xx_cgu_init); |