aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/Makefile3
-rw-r--r--drivers/clk/ingenic/Makefile3
-rw-r--r--drivers/clk/ingenic/cgu.c711
-rw-r--r--drivers/clk/ingenic/cgu.h223
-rw-r--r--drivers/clk/ingenic/jz4740-cgu.c303
-rw-r--r--drivers/clk/ingenic/jz4780-cgu.c733
6 files changed, 1975 insertions, 1 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 5b6af6a9319f..8732e4c5bf3c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -24,7 +24,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
24obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o 24obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
25obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o 25obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
26obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o 26obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
27obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o 27obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o
28obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o 28obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o
29obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o 29obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
30obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o 30obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o
@@ -51,6 +51,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
51obj-$(CONFIG_ARCH_HIP04) += hisilicon/ 51obj-$(CONFIG_ARCH_HIP04) += hisilicon/
52obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/ 52obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
53obj-$(CONFIG_ARCH_MXC) += imx/ 53obj-$(CONFIG_ARCH_MXC) += imx/
54obj-$(CONFIG_MACH_INGENIC) += ingenic/
54obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ 55obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
55ifeq ($(CONFIG_COMMON_CLK), y) 56ifeq ($(CONFIG_COMMON_CLK), y)
56obj-$(CONFIG_ARCH_MMP) += mmp/ 57obj-$(CONFIG_ARCH_MMP) += mmp/
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
new file mode 100644
index 000000000000..cd47b0664c2b
--- /dev/null
+++ b/drivers/clk/ingenic/Makefile
@@ -0,0 +1,3 @@
1obj-y += cgu.o
2obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
3obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
new file mode 100644
index 000000000000..b936cdd1a13c
--- /dev/null
+++ b/drivers/clk/ingenic/cgu.c
@@ -0,0 +1,711 @@
1/*
2 * Ingenic SoC CGU driver
3 *
4 * Copyright (c) 2013-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
18#include <linux/bitops.h>
19#include <linux/clk-provider.h>
20#include <linux/clkdev.h>
21#include <linux/delay.h>
22#include <linux/math64.h>
23#include <linux/of.h>
24#include <linux/of_address.h>
25#include <linux/slab.h>
26#include <linux/spinlock.h>
27#include "cgu.h"
28
29#define MHZ (1000 * 1000)
30
31/**
32 * ingenic_cgu_gate_get() - get the value of clock gate register bit
33 * @cgu: reference to the CGU whose registers should be read
34 * @info: info struct describing the gate bit
35 *
36 * Retrieves the state of the clock gate bit described by info. The
37 * caller must hold cgu->lock.
38 *
39 * Return: true if the gate bit is set, else false.
40 */
41static inline bool
42ingenic_cgu_gate_get(struct ingenic_cgu *cgu,
43 const struct ingenic_cgu_gate_info *info)
44{
45 return readl(cgu->base + info->reg) & BIT(info->bit);
46}
47
48/**
49 * ingenic_cgu_gate_set() - set the value of clock gate register bit
50 * @cgu: reference to the CGU whose registers should be modified
51 * @info: info struct describing the gate bit
52 * @val: non-zero to gate a clock, otherwise zero
53 *
54 * Sets the given gate bit in order to gate or ungate a clock.
55 *
56 * The caller must hold cgu->lock.
57 */
58static inline void
59ingenic_cgu_gate_set(struct ingenic_cgu *cgu,
60 const struct ingenic_cgu_gate_info *info, bool val)
61{
62 u32 clkgr = readl(cgu->base + info->reg);
63
64 if (val)
65 clkgr |= BIT(info->bit);
66 else
67 clkgr &= ~BIT(info->bit);
68
69 writel(clkgr, cgu->base + info->reg);
70}
71
72/*
73 * PLL operations
74 */
75
76static unsigned long
77ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
78{
79 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
80 struct ingenic_cgu *cgu = ingenic_clk->cgu;
81 const struct ingenic_cgu_clk_info *clk_info;
82 const struct ingenic_cgu_pll_info *pll_info;
83 unsigned m, n, od_enc, od;
84 bool bypass, enable;
85 unsigned long flags;
86 u32 ctl;
87
88 clk_info = &cgu->clock_info[ingenic_clk->idx];
89 BUG_ON(clk_info->type != CGU_CLK_PLL);
90 pll_info = &clk_info->pll;
91
92 spin_lock_irqsave(&cgu->lock, flags);
93 ctl = readl(cgu->base + pll_info->reg);
94 spin_unlock_irqrestore(&cgu->lock, flags);
95
96 m = (ctl >> pll_info->m_shift) & GENMASK(pll_info->m_bits - 1, 0);
97 m += pll_info->m_offset;
98 n = (ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0);
99 n += pll_info->n_offset;
100 od_enc = ctl >> pll_info->od_shift;
101 od_enc &= GENMASK(pll_info->od_bits - 1, 0);
102 bypass = !!(ctl & BIT(pll_info->bypass_bit));
103 enable = !!(ctl & BIT(pll_info->enable_bit));
104
105 if (bypass)
106 return parent_rate;
107
108 if (!enable)
109 return 0;
110
111 for (od = 0; od < pll_info->od_max; od++) {
112 if (pll_info->od_encoding[od] == od_enc)
113 break;
114 }
115 BUG_ON(od == pll_info->od_max);
116 od++;
117
118 return div_u64((u64)parent_rate * m, n * od);
119}
120
121static unsigned long
122ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
123 unsigned long rate, unsigned long parent_rate,
124 unsigned *pm, unsigned *pn, unsigned *pod)
125{
126 const struct ingenic_cgu_pll_info *pll_info;
127 unsigned m, n, od;
128
129 pll_info = &clk_info->pll;
130 od = 1;
131
132 /*
133 * The frequency after the input divider must be between 10 and 50 MHz.
134 * The highest divider yields the best resolution.
135 */
136 n = parent_rate / (10 * MHZ);
137 n = min_t(unsigned, n, 1 << clk_info->pll.n_bits);
138 n = max_t(unsigned, n, pll_info->n_offset);
139
140 m = (rate / MHZ) * od * n / (parent_rate / MHZ);
141 m = min_t(unsigned, m, 1 << clk_info->pll.m_bits);
142 m = max_t(unsigned, m, pll_info->m_offset);
143
144 if (pm)
145 *pm = m;
146 if (pn)
147 *pn = n;
148 if (pod)
149 *pod = od;
150
151 return div_u64((u64)parent_rate * m, n * od);
152}
153
154static long
155ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
156 unsigned long *prate)
157{
158 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
159 struct ingenic_cgu *cgu = ingenic_clk->cgu;
160 const struct ingenic_cgu_clk_info *clk_info;
161
162 clk_info = &cgu->clock_info[ingenic_clk->idx];
163 BUG_ON(clk_info->type != CGU_CLK_PLL);
164
165 return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
166}
167
168static int
169ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
170 unsigned long parent_rate)
171{
172 const unsigned timeout = 100;
173 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
174 struct ingenic_cgu *cgu = ingenic_clk->cgu;
175 const struct ingenic_cgu_clk_info *clk_info;
176 const struct ingenic_cgu_pll_info *pll_info;
177 unsigned long rate, flags;
178 unsigned m, n, od, i;
179 u32 ctl;
180
181 clk_info = &cgu->clock_info[ingenic_clk->idx];
182 BUG_ON(clk_info->type != CGU_CLK_PLL);
183 pll_info = &clk_info->pll;
184
185 rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
186 &m, &n, &od);
187 if (rate != req_rate)
188 pr_info("ingenic-cgu: request '%s' rate %luHz, actual %luHz\n",
189 clk_info->name, req_rate, rate);
190
191 spin_lock_irqsave(&cgu->lock, flags);
192 ctl = readl(cgu->base + pll_info->reg);
193
194 ctl &= ~(GENMASK(pll_info->m_bits - 1, 0) << pll_info->m_shift);
195 ctl |= (m - pll_info->m_offset) << pll_info->m_shift;
196
197 ctl &= ~(GENMASK(pll_info->n_bits - 1, 0) << pll_info->n_shift);
198 ctl |= (n - pll_info->n_offset) << pll_info->n_shift;
199
200 ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
201 ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
202
203 ctl &= ~BIT(pll_info->bypass_bit);
204 ctl |= BIT(pll_info->enable_bit);
205
206 writel(ctl, cgu->base + pll_info->reg);
207
208 /* wait for the PLL to stabilise */
209 for (i = 0; i < timeout; i++) {
210 ctl = readl(cgu->base + pll_info->reg);
211 if (ctl & BIT(pll_info->stable_bit))
212 break;
213 mdelay(1);
214 }
215
216 spin_unlock_irqrestore(&cgu->lock, flags);
217
218 if (i == timeout)
219 return -EBUSY;
220
221 return 0;
222}
223
224static const struct clk_ops ingenic_pll_ops = {
225 .recalc_rate = ingenic_pll_recalc_rate,
226 .round_rate = ingenic_pll_round_rate,
227 .set_rate = ingenic_pll_set_rate,
228};
229
230/*
231 * Operations for all non-PLL clocks
232 */
233
234static u8 ingenic_clk_get_parent(struct clk_hw *hw)
235{
236 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
237 struct ingenic_cgu *cgu = ingenic_clk->cgu;
238 const struct ingenic_cgu_clk_info *clk_info;
239 u32 reg;
240 u8 i, hw_idx, idx = 0;
241
242 clk_info = &cgu->clock_info[ingenic_clk->idx];
243
244 if (clk_info->type & CGU_CLK_MUX) {
245 reg = readl(cgu->base + clk_info->mux.reg);
246 hw_idx = (reg >> clk_info->mux.shift) &
247 GENMASK(clk_info->mux.bits - 1, 0);
248
249 /*
250 * Convert the hardware index to the parent index by skipping
251 * over any -1's in the parents array.
252 */
253 for (i = 0; i < hw_idx; i++) {
254 if (clk_info->parents[i] != -1)
255 idx++;
256 }
257 }
258
259 return idx;
260}
261
262static int ingenic_clk_set_parent(struct clk_hw *hw, u8 idx)
263{
264 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
265 struct ingenic_cgu *cgu = ingenic_clk->cgu;
266 const struct ingenic_cgu_clk_info *clk_info;
267 unsigned long flags;
268 u8 curr_idx, hw_idx, num_poss;
269 u32 reg, mask;
270
271 clk_info = &cgu->clock_info[ingenic_clk->idx];
272
273 if (clk_info->type & CGU_CLK_MUX) {
274 /*
275 * Convert the parent index to the hardware index by adding
276 * 1 for any -1 in the parents array preceding the given
277 * index. That is, we want the index of idx'th entry in
278 * clk_info->parents which does not equal -1.
279 */
280 hw_idx = curr_idx = 0;
281 num_poss = 1 << clk_info->mux.bits;
282 for (; hw_idx < num_poss; hw_idx++) {
283 if (clk_info->parents[hw_idx] == -1)
284 continue;
285 if (curr_idx == idx)
286 break;
287 curr_idx++;
288 }
289
290 /* idx should always be a valid parent */
291 BUG_ON(curr_idx != idx);
292
293 mask = GENMASK(clk_info->mux.bits - 1, 0);
294 mask <<= clk_info->mux.shift;
295
296 spin_lock_irqsave(&cgu->lock, flags);
297
298 /* write the register */
299 reg = readl(cgu->base + clk_info->mux.reg);
300 reg &= ~mask;
301 reg |= hw_idx << clk_info->mux.shift;
302 writel(reg, cgu->base + clk_info->mux.reg);
303
304 spin_unlock_irqrestore(&cgu->lock, flags);
305 return 0;
306 }
307
308 return idx ? -EINVAL : 0;
309}
310
311static unsigned long
312ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
313{
314 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
315 struct ingenic_cgu *cgu = ingenic_clk->cgu;
316 const struct ingenic_cgu_clk_info *clk_info;
317 unsigned long rate = parent_rate;
318 u32 div_reg, div;
319
320 clk_info = &cgu->clock_info[ingenic_clk->idx];
321
322 if (clk_info->type & CGU_CLK_DIV) {
323 div_reg = readl(cgu->base + clk_info->div.reg);
324 div = (div_reg >> clk_info->div.shift) &
325 GENMASK(clk_info->div.bits - 1, 0);
326 div += 1;
327
328 rate /= div;
329 }
330
331 return rate;
332}
333
334static unsigned
335ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
336 unsigned long parent_rate, unsigned long req_rate)
337{
338 unsigned div;
339
340 /* calculate the divide */
341 div = DIV_ROUND_UP(parent_rate, req_rate);
342
343 /* and impose hardware constraints */
344 div = min_t(unsigned, div, 1 << clk_info->div.bits);
345 div = max_t(unsigned, div, 1);
346
347 return div;
348}
349
350static long
351ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
352 unsigned long *parent_rate)
353{
354 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
355 struct ingenic_cgu *cgu = ingenic_clk->cgu;
356 const struct ingenic_cgu_clk_info *clk_info;
357 long rate = *parent_rate;
358
359 clk_info = &cgu->clock_info[ingenic_clk->idx];
360
361 if (clk_info->type & CGU_CLK_DIV)
362 rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
363 else if (clk_info->type & CGU_CLK_FIXDIV)
364 rate /= clk_info->fixdiv.div;
365
366 return rate;
367}
368
369static int
370ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
371 unsigned long parent_rate)
372{
373 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
374 struct ingenic_cgu *cgu = ingenic_clk->cgu;
375 const struct ingenic_cgu_clk_info *clk_info;
376 const unsigned timeout = 100;
377 unsigned long rate, flags;
378 unsigned div, i;
379 u32 reg, mask;
380 int ret = 0;
381
382 clk_info = &cgu->clock_info[ingenic_clk->idx];
383
384 if (clk_info->type & CGU_CLK_DIV) {
385 div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
386 rate = parent_rate / div;
387
388 if (rate != req_rate)
389 return -EINVAL;
390
391 spin_lock_irqsave(&cgu->lock, flags);
392 reg = readl(cgu->base + clk_info->div.reg);
393
394 /* update the divide */
395 mask = GENMASK(clk_info->div.bits - 1, 0);
396 reg &= ~(mask << clk_info->div.shift);
397 reg |= (div - 1) << clk_info->div.shift;
398
399 /* clear the stop bit */
400 if (clk_info->div.stop_bit != -1)
401 reg &= ~BIT(clk_info->div.stop_bit);
402
403 /* set the change enable bit */
404 if (clk_info->div.ce_bit != -1)
405 reg |= BIT(clk_info->div.ce_bit);
406
407 /* update the hardware */
408 writel(reg, cgu->base + clk_info->div.reg);
409
410 /* wait for the change to take effect */
411 if (clk_info->div.busy_bit != -1) {
412 for (i = 0; i < timeout; i++) {
413 reg = readl(cgu->base + clk_info->div.reg);
414 if (!(reg & BIT(clk_info->div.busy_bit)))
415 break;
416 mdelay(1);
417 }
418 if (i == timeout)
419 ret = -EBUSY;
420 }
421
422 spin_unlock_irqrestore(&cgu->lock, flags);
423 return ret;
424 }
425
426 return -EINVAL;
427}
428
429static int ingenic_clk_enable(struct clk_hw *hw)
430{
431 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
432 struct ingenic_cgu *cgu = ingenic_clk->cgu;
433 const struct ingenic_cgu_clk_info *clk_info;
434 unsigned long flags;
435
436 clk_info = &cgu->clock_info[ingenic_clk->idx];
437
438 if (clk_info->type & CGU_CLK_GATE) {
439 /* ungate the clock */
440 spin_lock_irqsave(&cgu->lock, flags);
441 ingenic_cgu_gate_set(cgu, &clk_info->gate, false);
442 spin_unlock_irqrestore(&cgu->lock, flags);
443 }
444
445 return 0;
446}
447
448static void ingenic_clk_disable(struct clk_hw *hw)
449{
450 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
451 struct ingenic_cgu *cgu = ingenic_clk->cgu;
452 const struct ingenic_cgu_clk_info *clk_info;
453 unsigned long flags;
454
455 clk_info = &cgu->clock_info[ingenic_clk->idx];
456
457 if (clk_info->type & CGU_CLK_GATE) {
458 /* gate the clock */
459 spin_lock_irqsave(&cgu->lock, flags);
460 ingenic_cgu_gate_set(cgu, &clk_info->gate, true);
461 spin_unlock_irqrestore(&cgu->lock, flags);
462 }
463}
464
465static int ingenic_clk_is_enabled(struct clk_hw *hw)
466{
467 struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
468 struct ingenic_cgu *cgu = ingenic_clk->cgu;
469 const struct ingenic_cgu_clk_info *clk_info;
470 unsigned long flags;
471 int enabled = 1;
472
473 clk_info = &cgu->clock_info[ingenic_clk->idx];
474
475 if (clk_info->type & CGU_CLK_GATE) {
476 spin_lock_irqsave(&cgu->lock, flags);
477 enabled = !ingenic_cgu_gate_get(cgu, &clk_info->gate);
478 spin_unlock_irqrestore(&cgu->lock, flags);
479 }
480
481 return enabled;
482}
483
484static const struct clk_ops ingenic_clk_ops = {
485 .get_parent = ingenic_clk_get_parent,
486 .set_parent = ingenic_clk_set_parent,
487
488 .recalc_rate = ingenic_clk_recalc_rate,
489 .round_rate = ingenic_clk_round_rate,
490 .set_rate = ingenic_clk_set_rate,
491
492 .enable = ingenic_clk_enable,
493 .disable = ingenic_clk_disable,
494 .is_enabled = ingenic_clk_is_enabled,
495};
496
497/*
498 * Setup functions.
499 */
500
501static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
502{
503 const struct ingenic_cgu_clk_info *clk_info = &cgu->clock_info[idx];
504 struct clk_init_data clk_init;
505 struct ingenic_clk *ingenic_clk = NULL;
506 struct clk *clk, *parent;
507 const char *parent_names[4];
508 unsigned caps, i, num_possible;
509 int err = -EINVAL;
510
511 BUILD_BUG_ON(ARRAY_SIZE(clk_info->parents) > ARRAY_SIZE(parent_names));
512
513 if (clk_info->type == CGU_CLK_EXT) {
514 clk = of_clk_get_by_name(cgu->np, clk_info->name);
515 if (IS_ERR(clk)) {
516 pr_err("%s: no external clock '%s' provided\n",
517 __func__, clk_info->name);
518 err = -ENODEV;
519 goto out;
520 }
521 err = clk_register_clkdev(clk, clk_info->name, NULL);
522 if (err) {
523 clk_put(clk);
524 goto out;
525 }
526 cgu->clocks.clks[idx] = clk;
527 return 0;
528 }
529
530 if (!clk_info->type) {
531 pr_err("%s: no clock type specified for '%s'\n", __func__,
532 clk_info->name);
533 goto out;
534 }
535
536 ingenic_clk = kzalloc(sizeof(*ingenic_clk), GFP_KERNEL);
537 if (!ingenic_clk) {
538 err = -ENOMEM;
539 goto out;
540 }
541
542 ingenic_clk->hw.init = &clk_init;
543 ingenic_clk->cgu = cgu;
544 ingenic_clk->idx = idx;
545
546 clk_init.name = clk_info->name;
547 clk_init.flags = 0;
548 clk_init.parent_names = parent_names;
549
550 caps = clk_info->type;
551
552 if (caps & (CGU_CLK_MUX | CGU_CLK_CUSTOM)) {
553 clk_init.num_parents = 0;
554
555 if (caps & CGU_CLK_MUX)
556 num_possible = 1 << clk_info->mux.bits;
557 else
558 num_possible = ARRAY_SIZE(clk_info->parents);
559
560 for (i = 0; i < num_possible; i++) {
561 if (clk_info->parents[i] == -1)
562 continue;
563
564 parent = cgu->clocks.clks[clk_info->parents[i]];
565 parent_names[clk_init.num_parents] =
566 __clk_get_name(parent);
567 clk_init.num_parents++;
568 }
569
570 BUG_ON(!clk_init.num_parents);
571 BUG_ON(clk_init.num_parents > ARRAY_SIZE(parent_names));
572 } else {
573 BUG_ON(clk_info->parents[0] == -1);
574 clk_init.num_parents = 1;
575 parent = cgu->clocks.clks[clk_info->parents[0]];
576 parent_names[0] = __clk_get_name(parent);
577 }
578
579 if (caps & CGU_CLK_CUSTOM) {
580 clk_init.ops = clk_info->custom.clk_ops;
581
582 caps &= ~CGU_CLK_CUSTOM;
583
584 if (caps) {
585 pr_err("%s: custom clock may not be combined with type 0x%x\n",
586 __func__, caps);
587 goto out;
588 }
589 } else if (caps & CGU_CLK_PLL) {
590 clk_init.ops = &ingenic_pll_ops;
591
592 caps &= ~CGU_CLK_PLL;
593
594 if (caps) {
595 pr_err("%s: PLL may not be combined with type 0x%x\n",
596 __func__, caps);
597 goto out;
598 }
599 } else {
600 clk_init.ops = &ingenic_clk_ops;
601 }
602
603 /* nothing to do for gates or fixed dividers */
604 caps &= ~(CGU_CLK_GATE | CGU_CLK_FIXDIV);
605
606 if (caps & CGU_CLK_MUX) {
607 if (!(caps & CGU_CLK_MUX_GLITCHFREE))
608 clk_init.flags |= CLK_SET_PARENT_GATE;
609
610 caps &= ~(CGU_CLK_MUX | CGU_CLK_MUX_GLITCHFREE);
611 }
612
613 if (caps & CGU_CLK_DIV) {
614 caps &= ~CGU_CLK_DIV;
615 } else {
616 /* pass rate changes to the parent clock */
617 clk_init.flags |= CLK_SET_RATE_PARENT;
618 }
619
620 if (caps) {
621 pr_err("%s: unknown clock type 0x%x\n", __func__, caps);
622 goto out;
623 }
624
625 clk = clk_register(NULL, &ingenic_clk->hw);
626 if (IS_ERR(clk)) {
627 pr_err("%s: failed to register clock '%s'\n", __func__,
628 clk_info->name);
629 err = PTR_ERR(clk);
630 goto out;
631 }
632
633 err = clk_register_clkdev(clk, clk_info->name, NULL);
634 if (err)
635 goto out;
636
637 cgu->clocks.clks[idx] = clk;
638out:
639 if (err)
640 kfree(ingenic_clk);
641 return err;
642}
643
644struct ingenic_cgu *
645ingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info,
646 unsigned num_clocks, struct device_node *np)
647{
648 struct ingenic_cgu *cgu;
649
650 cgu = kzalloc(sizeof(*cgu), GFP_KERNEL);
651 if (!cgu)
652 goto err_out;
653
654 cgu->base = of_iomap(np, 0);
655 if (!cgu->base) {
656 pr_err("%s: failed to map CGU registers\n", __func__);
657 goto err_out_free;
658 }
659
660 cgu->np = np;
661 cgu->clock_info = clock_info;
662 cgu->clocks.clk_num = num_clocks;
663
664 spin_lock_init(&cgu->lock);
665
666 return cgu;
667
668err_out_free:
669 kfree(cgu);
670err_out:
671 return NULL;
672}
673
674int ingenic_cgu_register_clocks(struct ingenic_cgu *cgu)
675{
676 unsigned i;
677 int err;
678
679 cgu->clocks.clks = kcalloc(cgu->clocks.clk_num, sizeof(struct clk *),
680 GFP_KERNEL);
681 if (!cgu->clocks.clks) {
682 err = -ENOMEM;
683 goto err_out;
684 }
685
686 for (i = 0; i < cgu->clocks.clk_num; i++) {
687 err = ingenic_register_clock(cgu, i);
688 if (err)
689 goto err_out_unregister;
690 }
691
692 err = of_clk_add_provider(cgu->np, of_clk_src_onecell_get,
693 &cgu->clocks);
694 if (err)
695 goto err_out_unregister;
696
697 return 0;
698
699err_out_unregister:
700 for (i = 0; i < cgu->clocks.clk_num; i++) {
701 if (!cgu->clocks.clks[i])
702 continue;
703 if (cgu->clock_info[i].type & CGU_CLK_EXT)
704 clk_put(cgu->clocks.clks[i]);
705 else
706 clk_unregister(cgu->clocks.clks[i]);
707 }
708 kfree(cgu->clocks.clks);
709err_out:
710 return err;
711}
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
new file mode 100644
index 000000000000..99347e2b97e8
--- /dev/null
+++ b/drivers/clk/ingenic/cgu.h
@@ -0,0 +1,223 @@
1/*
2 * Ingenic SoC CGU driver
3 *
4 * Copyright (c) 2013-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
18#ifndef __DRIVERS_CLK_INGENIC_CGU_H__
19#define __DRIVERS_CLK_INGENIC_CGU_H__
20
21#include <linux/bitops.h>
22#include <linux/of.h>
23#include <linux/spinlock.h>
24
25/**
26 * struct ingenic_cgu_pll_info - information about a PLL
27 * @reg: the offset of the PLL's control register within the CGU
28 * @m_shift: the number of bits to shift the multiplier value by (ie. the
29 * index of the lowest bit of the multiplier value in the PLL's
30 * control register)
31 * @m_bits: the size of the multiplier field in bits
32 * @m_offset: the multiplier value which encodes to 0 in the PLL's control
33 * register
34 * @n_shift: the number of bits to shift the divider value by (ie. the
35 * index of the lowest bit of the divider value in the PLL's
36 * control register)
37 * @n_bits: the size of the divider field in bits
38 * @n_offset: the divider value which encodes to 0 in the PLL's control
39 * register
40 * @od_shift: the number of bits to shift the post-VCO divider value by (ie.
41 * the index of the lowest bit of the post-VCO divider value in
42 * the PLL's control register)
43 * @od_bits: the size of the post-VCO divider field in bits
44 * @od_max: the maximum post-VCO divider value
45 * @od_encoding: a pointer to an array mapping post-VCO divider values to
46 * their encoded values in the PLL control register, or -1 for
47 * unsupported values
48 * @bypass_bit: the index of the bypass bit in the PLL control register
49 * @enable_bit: the index of the enable bit in the PLL control register
50 * @stable_bit: the index of the stable bit in the PLL control register
51 */
52struct ingenic_cgu_pll_info {
53 unsigned reg;
54 const s8 *od_encoding;
55 u8 m_shift, m_bits, m_offset;
56 u8 n_shift, n_bits, n_offset;
57 u8 od_shift, od_bits, od_max;
58 u8 bypass_bit;
59 u8 enable_bit;
60 u8 stable_bit;
61};
62
63/**
64 * struct ingenic_cgu_mux_info - information about a clock mux
65 * @reg: offset of the mux control register within the CGU
66 * @shift: number of bits to shift the mux value by (ie. the index of
67 * the lowest bit of the mux value within its control register)
68 * @bits: the size of the mux value in bits
69 */
70struct ingenic_cgu_mux_info {
71 unsigned reg;
72 u8 shift;
73 u8 bits;
74};
75
76/**
77 * struct ingenic_cgu_div_info - information about a divider
78 * @reg: offset of the divider control register within the CGU
79 * @shift: number of bits to shift the divide value by (ie. the index of
80 * the lowest bit of the divide value within its control register)
81 * @bits: the size of the divide value in bits
82 * @ce_bit: the index of the change enable bit within reg, or -1 if there
83 * isn't one
84 * @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
85 * @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
86 */
87struct ingenic_cgu_div_info {
88 unsigned reg;
89 u8 shift;
90 u8 bits;
91 s8 ce_bit;
92 s8 busy_bit;
93 s8 stop_bit;
94};
95
96/**
97 * struct ingenic_cgu_fixdiv_info - information about a fixed divider
98 * @div: the divider applied to the parent clock
99 */
100struct ingenic_cgu_fixdiv_info {
101 unsigned div;
102};
103
104/**
105 * struct ingenic_cgu_gate_info - information about a clock gate
106 * @reg: offset of the gate control register within the CGU
107 * @bit: offset of the bit in the register that controls the gate
108 */
109struct ingenic_cgu_gate_info {
110 unsigned reg;
111 u8 bit;
112};
113
114/**
115 * struct ingenic_cgu_custom_info - information about a custom (SoC) clock
116 * @clk_ops: custom clock operation callbacks
117 */
118struct ingenic_cgu_custom_info {
119 struct clk_ops *clk_ops;
120};
121
122/**
123 * struct ingenic_cgu_clk_info - information about a clock
124 * @name: name of the clock
125 * @type: a bitmask formed from CGU_CLK_* values
126 * @parents: an array of the indices of potential parents of this clock
127 * within the clock_info array of the CGU, or -1 in entries
128 * which correspond to no valid parent
129 * @pll: information valid if type includes CGU_CLK_PLL
130 * @gate: information valid if type includes CGU_CLK_GATE
131 * @mux: information valid if type includes CGU_CLK_MUX
132 * @div: information valid if type includes CGU_CLK_DIV
133 * @fixdiv: information valid if type includes CGU_CLK_FIXDIV
134 * @custom: information valid if type includes CGU_CLK_CUSTOM
135 */
136struct ingenic_cgu_clk_info {
137 const char *name;
138
139 enum {
140 CGU_CLK_NONE = 0,
141 CGU_CLK_EXT = BIT(0),
142 CGU_CLK_PLL = BIT(1),
143 CGU_CLK_GATE = BIT(2),
144 CGU_CLK_MUX = BIT(3),
145 CGU_CLK_MUX_GLITCHFREE = BIT(4),
146 CGU_CLK_DIV = BIT(5),
147 CGU_CLK_FIXDIV = BIT(6),
148 CGU_CLK_CUSTOM = BIT(7),
149 } type;
150
151 int parents[4];
152
153 union {
154 struct ingenic_cgu_pll_info pll;
155
156 struct {
157 struct ingenic_cgu_gate_info gate;
158 struct ingenic_cgu_mux_info mux;
159 struct ingenic_cgu_div_info div;
160 struct ingenic_cgu_fixdiv_info fixdiv;
161 };
162
163 struct ingenic_cgu_custom_info custom;
164 };
165};
166
167/**
168 * struct ingenic_cgu - data about the CGU
169 * @np: the device tree node that caused the CGU to be probed
170 * @base: the ioremap'ed base address of the CGU registers
171 * @clock_info: an array containing information about implemented clocks
172 * @clocks: used to provide clocks to DT, allows lookup of struct clk*
173 * @lock: lock to be held whilst manipulating CGU registers
174 */
175struct ingenic_cgu {
176 struct device_node *np;
177 void __iomem *base;
178
179 const struct ingenic_cgu_clk_info *clock_info;
180 struct clk_onecell_data clocks;
181
182 spinlock_t lock;
183};
184
185/**
186 * struct ingenic_clk - private data for a clock
187 * @hw: see Documentation/clk.txt
188 * @cgu: a pointer to the CGU data
189 * @idx: the index of this clock in cgu->clock_info
190 */
191struct ingenic_clk {
192 struct clk_hw hw;
193 struct ingenic_cgu *cgu;
194 unsigned idx;
195};
196
197#define to_ingenic_clk(_hw) container_of(_hw, struct ingenic_clk, hw)
198
199/**
200 * ingenic_cgu_new() - create a new CGU instance
201 * @clock_info: an array of clock information structures describing the clocks
202 * which are implemented by the CGU
203 * @num_clocks: the number of entries in clock_info
204 * @np: the device tree node which causes this CGU to be probed
205 *
206 * Return: a pointer to the CGU instance if initialisation is successful,
207 * otherwise NULL.
208 */
209struct ingenic_cgu *
210ingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info,
211 unsigned num_clocks, struct device_node *np);
212
213/**
214 * ingenic_cgu_register_clocks() - Registers the clocks
215 * @cgu: pointer to cgu data
216 *
217 * Register the clocks described by the CGU with the common clock framework.
218 *
219 * Return: 0 on success or -errno if unsuccesful.
220 */
221int ingenic_cgu_register_clocks(struct ingenic_cgu *cgu);
222
223#endif /* __DRIVERS_CLK_INGENIC_CGU_H__ */
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
new file mode 100644
index 000000000000..305a26c2a800
--- /dev/null
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -0,0 +1,303 @@
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
18#include <linux/clk-provider.h>
19#include <linux/delay.h>
20#include <linux/of.h>
21#include <dt-bindings/clock/jz4740-cgu.h>
22#include <asm/mach-jz4740/clock.h>
23#include "cgu.h"
24
25/* CGU register offsets */
26#define CGU_REG_CPCCR 0x00
27#define CGU_REG_LCR 0x04
28#define CGU_REG_CPPCR 0x10
29#define CGU_REG_CLKGR 0x20
30#define CGU_REG_SCR 0x24
31#define CGU_REG_I2SCDR 0x60
32#define CGU_REG_LPCDR 0x64
33#define CGU_REG_MSCCDR 0x68
34#define CGU_REG_UHCCDR 0x6c
35#define CGU_REG_SSICDR 0x74
36
37/* bits within a PLL control register */
38#define PLLCTL_M_SHIFT 23
39#define PLLCTL_M_MASK (0x1ff << PLLCTL_M_SHIFT)
40#define PLLCTL_N_SHIFT 18
41#define PLLCTL_N_MASK (0x1f << PLLCTL_N_SHIFT)
42#define PLLCTL_OD_SHIFT 16
43#define PLLCTL_OD_MASK (0x3 << PLLCTL_OD_SHIFT)
44#define PLLCTL_STABLE (1 << 10)
45#define PLLCTL_BYPASS (1 << 9)
46#define PLLCTL_ENABLE (1 << 8)
47
48/* bits within the LCR register */
49#define LCR_SLEEP (1 << 0)
50
51/* bits within the CLKGR register */
52#define CLKGR_UDC (1 << 11)
53
54static struct ingenic_cgu *cgu;
55
56static const s8 pll_od_encoding[4] = {
57 0x0, 0x1, -1, 0x3,
58};
59
60static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
61
62 /* External clocks */
63
64 [JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT },
65 [JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT },
66
67 [JZ4740_CLK_PLL] = {
68 "pll", CGU_CLK_PLL,
69 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
70 .pll = {
71 .reg = CGU_REG_CPPCR,
72 .m_shift = 23,
73 .m_bits = 9,
74 .m_offset = 2,
75 .n_shift = 18,
76 .n_bits = 5,
77 .n_offset = 2,
78 .od_shift = 16,
79 .od_bits = 2,
80 .od_max = 4,
81 .od_encoding = pll_od_encoding,
82 .stable_bit = 10,
83 .bypass_bit = 9,
84 .enable_bit = 8,
85 },
86 },
87
88 /* Muxes & dividers */
89
90 [JZ4740_CLK_PLL_HALF] = {
91 "pll half", CGU_CLK_DIV,
92 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
93 .div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 },
94 },
95
96 [JZ4740_CLK_CCLK] = {
97 "cclk", CGU_CLK_DIV,
98 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
99 .div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 },
100 },
101
102 [JZ4740_CLK_HCLK] = {
103 "hclk", CGU_CLK_DIV,
104 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
105 .div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 },
106 },
107
108 [JZ4740_CLK_PCLK] = {
109 "pclk", CGU_CLK_DIV,
110 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
111 .div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 },
112 },
113
114 [JZ4740_CLK_MCLK] = {
115 "mclk", CGU_CLK_DIV,
116 .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
117 .div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 },
118 },
119
120 [JZ4740_CLK_LCD] = {
121 "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
122 .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
123 .div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 },
124 .gate = { CGU_REG_CLKGR, 10 },
125 },
126
127 [JZ4740_CLK_LCD_PCLK] = {
128 "lcd_pclk", CGU_CLK_DIV,
129 .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
130 .div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 },
131 },
132
133 [JZ4740_CLK_I2S] = {
134 "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
135 .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
136 .mux = { CGU_REG_CPCCR, 31, 1 },
137 .div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 },
138 .gate = { CGU_REG_CLKGR, 6 },
139 },
140
141 [JZ4740_CLK_SPI] = {
142 "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
143 .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 },
144 .mux = { CGU_REG_SSICDR, 31, 1 },
145 .div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 },
146 .gate = { CGU_REG_CLKGR, 4 },
147 },
148
149 [JZ4740_CLK_MMC] = {
150 "mmc", CGU_CLK_DIV | CGU_CLK_GATE,
151 .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
152 .div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 },
153 .gate = { CGU_REG_CLKGR, 7 },
154 },
155
156 [JZ4740_CLK_UHC] = {
157 "uhc", CGU_CLK_DIV | CGU_CLK_GATE,
158 .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
159 .div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 },
160 .gate = { CGU_REG_CLKGR, 14 },
161 },
162
163 [JZ4740_CLK_UDC] = {
164 "udc", CGU_CLK_MUX | CGU_CLK_DIV,
165 .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
166 .mux = { CGU_REG_CPCCR, 29, 1 },
167 .div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 },
168 .gate = { CGU_REG_SCR, 6 },
169 },
170
171 /* Gate-only clocks */
172
173 [JZ4740_CLK_UART0] = {
174 "uart0", CGU_CLK_GATE,
175 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
176 .gate = { CGU_REG_CLKGR, 0 },
177 },
178
179 [JZ4740_CLK_UART1] = {
180 "uart1", CGU_CLK_GATE,
181 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
182 .gate = { CGU_REG_CLKGR, 15 },
183 },
184
185 [JZ4740_CLK_DMA] = {
186 "dma", CGU_CLK_GATE,
187 .parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
188 .gate = { CGU_REG_CLKGR, 12 },
189 },
190
191 [JZ4740_CLK_IPU] = {
192 "ipu", CGU_CLK_GATE,
193 .parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
194 .gate = { CGU_REG_CLKGR, 13 },
195 },
196
197 [JZ4740_CLK_ADC] = {
198 "adc", CGU_CLK_GATE,
199 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
200 .gate = { CGU_REG_CLKGR, 8 },
201 },
202
203 [JZ4740_CLK_I2C] = {
204 "i2c", CGU_CLK_GATE,
205 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
206 .gate = { CGU_REG_CLKGR, 3 },
207 },
208
209 [JZ4740_CLK_AIC] = {
210 "aic", CGU_CLK_GATE,
211 .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
212 .gate = { CGU_REG_CLKGR, 5 },
213 },
214};
215
216static void __init jz4740_cgu_init(struct device_node *np)
217{
218 int retval;
219
220 cgu = ingenic_cgu_new(jz4740_cgu_clocks,
221 ARRAY_SIZE(jz4740_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}
231CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
232
233void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
234{
235 uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
236
237 switch (mode) {
238 case JZ4740_WAIT_MODE_IDLE:
239 lcr &= ~LCR_SLEEP;
240 break;
241
242 case JZ4740_WAIT_MODE_SLEEP:
243 lcr |= LCR_SLEEP;
244 break;
245 }
246
247 writel(lcr, cgu->base + CGU_REG_LCR);
248}
249
250void jz4740_clock_udc_disable_auto_suspend(void)
251{
252 uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
253
254 clkgr &= ~CLKGR_UDC;
255 writel(clkgr, cgu->base + CGU_REG_CLKGR);
256}
257EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
258
259void jz4740_clock_udc_enable_auto_suspend(void)
260{
261 uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
262
263 clkgr |= CLKGR_UDC;
264 writel(clkgr, cgu->base + CGU_REG_CLKGR);
265}
266EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
267
268#define JZ_CLOCK_GATE_UART0 BIT(0)
269#define JZ_CLOCK_GATE_TCU BIT(1)
270#define JZ_CLOCK_GATE_DMAC BIT(12)
271
272void jz4740_clock_suspend(void)
273{
274 uint32_t clkgr, cppcr;
275
276 clkgr = readl(cgu->base + CGU_REG_CLKGR);
277 clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
278 writel(clkgr, cgu->base + CGU_REG_CLKGR);
279
280 cppcr = readl(cgu->base + CGU_REG_CPPCR);
281 cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
282 writel(cppcr, cgu->base + CGU_REG_CPPCR);
283}
284
285void jz4740_clock_resume(void)
286{
287 uint32_t clkgr, cppcr, stable;
288
289 cppcr = readl(cgu->base + CGU_REG_CPPCR);
290 cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
291 writel(cppcr, cgu->base + CGU_REG_CPPCR);
292
293 stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit);
294 do {
295 cppcr = readl(cgu->base + CGU_REG_CPPCR);
296 } while (!(cppcr & stable));
297
298 clkgr = readl(cgu->base + CGU_REG_CLKGR);
299 clkgr &= ~JZ_CLOCK_GATE_TCU;
300 clkgr &= ~JZ_CLOCK_GATE_DMAC;
301 clkgr &= ~JZ_CLOCK_GATE_UART0;
302 writel(clkgr, cgu->base + CGU_REG_CLKGR);
303}
diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c
new file mode 100644
index 000000000000..431f962300b6
--- /dev/null
+++ b/drivers/clk/ingenic/jz4780-cgu.c
@@ -0,0 +1,733 @@
1/*
2 * Ingenic JZ4780 SoC CGU driver
3 *
4 * Copyright (c) 2013-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
18#include <linux/clk-provider.h>
19#include <linux/delay.h>
20#include <linux/of.h>
21#include <dt-bindings/clock/jz4780-cgu.h>
22#include "cgu.h"
23
24/* CGU register offsets */
25#define CGU_REG_CLOCKCONTROL 0x00
26#define CGU_REG_PLLCONTROL 0x0c
27#define CGU_REG_APLL 0x10
28#define CGU_REG_MPLL 0x14
29#define CGU_REG_EPLL 0x18
30#define CGU_REG_VPLL 0x1c
31#define CGU_REG_CLKGR0 0x20
32#define CGU_REG_OPCR 0x24
33#define CGU_REG_CLKGR1 0x28
34#define CGU_REG_DDRCDR 0x2c
35#define CGU_REG_VPUCDR 0x30
36#define CGU_REG_USBPCR 0x3c
37#define CGU_REG_USBRDT 0x40
38#define CGU_REG_USBVBFIL 0x44
39#define CGU_REG_USBPCR1 0x48
40#define CGU_REG_LP0CDR 0x54
41#define CGU_REG_I2SCDR 0x60
42#define CGU_REG_LP1CDR 0x64
43#define CGU_REG_MSC0CDR 0x68
44#define CGU_REG_UHCCDR 0x6c
45#define CGU_REG_SSICDR 0x74
46#define CGU_REG_CIMCDR 0x7c
47#define CGU_REG_PCMCDR 0x84
48#define CGU_REG_GPUCDR 0x88
49#define CGU_REG_HDMICDR 0x8c
50#define CGU_REG_MSC1CDR 0xa4
51#define CGU_REG_MSC2CDR 0xa8
52#define CGU_REG_BCHCDR 0xac
53#define CGU_REG_CLOCKSTATUS 0xd4
54
55/* bits within the OPCR register */
56#define OPCR_SPENDN0 (1 << 7)
57#define OPCR_SPENDN1 (1 << 6)
58
59/* bits within the USBPCR register */
60#define USBPCR_USB_MODE BIT(31)
61#define USBPCR_IDPULLUP_MASK (0x3 << 28)
62#define USBPCR_COMMONONN BIT(25)
63#define USBPCR_VBUSVLDEXT BIT(24)
64#define USBPCR_VBUSVLDEXTSEL BIT(23)
65#define USBPCR_POR BIT(22)
66#define USBPCR_OTG_DISABLE BIT(20)
67#define USBPCR_COMPDISTUNE_MASK (0x7 << 17)
68#define USBPCR_OTGTUNE_MASK (0x7 << 14)
69#define USBPCR_SQRXTUNE_MASK (0x7 << 11)
70#define USBPCR_TXFSLSTUNE_MASK (0xf << 7)
71#define USBPCR_TXPREEMPHTUNE BIT(6)
72#define USBPCR_TXHSXVTUNE_MASK (0x3 << 4)
73#define USBPCR_TXVREFTUNE_MASK 0xf
74
75/* bits within the USBPCR1 register */
76#define USBPCR1_REFCLKSEL_SHIFT 26
77#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
78#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
79#define USBPCR1_REFCLKDIV_SHIFT 24
80#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
81#define USBPCR1_REFCLKDIV_19_2 (0x3 << USBPCR1_REFCLKDIV_SHIFT)
82#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
83#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
84#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
85#define USBPCR1_USB_SEL BIT(28)
86#define USBPCR1_WORD_IF0 BIT(19)
87#define USBPCR1_WORD_IF1 BIT(18)
88
89/* bits within the USBRDT register */
90#define USBRDT_VBFIL_LD_EN BIT(25)
91#define USBRDT_USBRDT_MASK 0x7fffff
92
93/* bits within the USBVBFIL register */
94#define USBVBFIL_IDDIGFIL_SHIFT 16
95#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT)
96#define USBVBFIL_USBVBFIL_MASK (0xffff)
97
98static struct ingenic_cgu *cgu;
99
100static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
101{
102 /* we only use CLKCORE, revisit if that ever changes */
103 return 0;
104}
105
106static int jz4780_otg_phy_set_parent(struct clk_hw *hw, u8 idx)
107{
108 unsigned long flags;
109 u32 usbpcr1;
110
111 if (idx > 0)
112 return -EINVAL;
113
114 spin_lock_irqsave(&cgu->lock, flags);
115
116 usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
117 usbpcr1 &= ~USBPCR1_REFCLKSEL_MASK;
118 /* we only use CLKCORE */
119 usbpcr1 |= USBPCR1_REFCLKSEL_CORE;
120 writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
121
122 spin_unlock_irqrestore(&cgu->lock, flags);
123 return 0;
124}
125
126static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
127 unsigned long parent_rate)
128{
129 u32 usbpcr1;
130 unsigned refclk_div;
131
132 usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
133 refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
134
135 switch (refclk_div) {
136 case USBPCR1_REFCLKDIV_12:
137 return 12000000;
138
139 case USBPCR1_REFCLKDIV_24:
140 return 24000000;
141
142 case USBPCR1_REFCLKDIV_48:
143 return 48000000;
144
145 case USBPCR1_REFCLKDIV_19_2:
146 return 19200000;
147 }
148
149 BUG();
150 return parent_rate;
151}
152
153static long jz4780_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
154 unsigned long *parent_rate)
155{
156 if (req_rate < 15600000)
157 return 12000000;
158
159 if (req_rate < 21600000)
160 return 19200000;
161
162 if (req_rate < 36000000)
163 return 24000000;
164
165 return 48000000;
166}
167
168static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
169 unsigned long parent_rate)
170{
171 unsigned long flags;
172 u32 usbpcr1, div_bits;
173
174 switch (req_rate) {
175 case 12000000:
176 div_bits = USBPCR1_REFCLKDIV_12;
177 break;
178
179 case 19200000:
180 div_bits = USBPCR1_REFCLKDIV_19_2;
181 break;
182
183 case 24000000:
184 div_bits = USBPCR1_REFCLKDIV_24;
185 break;
186
187 case 48000000:
188 div_bits = USBPCR1_REFCLKDIV_48;
189 break;
190
191 default:
192 return -EINVAL;
193 }
194
195 spin_lock_irqsave(&cgu->lock, flags);
196
197 usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
198 usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
199 usbpcr1 |= div_bits;
200 writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
201
202 spin_unlock_irqrestore(&cgu->lock, flags);
203 return 0;
204}
205
206static struct clk_ops jz4780_otg_phy_ops = {
207 .get_parent = jz4780_otg_phy_get_parent,
208 .set_parent = jz4780_otg_phy_set_parent,
209
210 .recalc_rate = jz4780_otg_phy_recalc_rate,
211 .round_rate = jz4780_otg_phy_round_rate,
212 .set_rate = jz4780_otg_phy_set_rate,
213};
214
215static const s8 pll_od_encoding[16] = {
216 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
217 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
218};
219
220static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = {
221
222 /* External clocks */
223
224 [JZ4780_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
225 [JZ4780_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
226
227 /* PLLs */
228
229#define DEF_PLL(name) { \
230 .reg = CGU_REG_ ## name, \
231 .m_shift = 19, \
232 .m_bits = 13, \
233 .m_offset = 1, \
234 .n_shift = 13, \
235 .n_bits = 6, \
236 .n_offset = 1, \
237 .od_shift = 9, \
238 .od_bits = 4, \
239 .od_max = 16, \
240 .od_encoding = pll_od_encoding, \
241 .stable_bit = 6, \
242 .bypass_bit = 1, \
243 .enable_bit = 0, \
244}
245
246 [JZ4780_CLK_APLL] = {
247 "apll", CGU_CLK_PLL,
248 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
249 .pll = DEF_PLL(APLL),
250 },
251
252 [JZ4780_CLK_MPLL] = {
253 "mpll", CGU_CLK_PLL,
254 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
255 .pll = DEF_PLL(MPLL),
256 },
257
258 [JZ4780_CLK_EPLL] = {
259 "epll", CGU_CLK_PLL,
260 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
261 .pll = DEF_PLL(EPLL),
262 },
263
264 [JZ4780_CLK_VPLL] = {
265 "vpll", CGU_CLK_PLL,
266 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
267 .pll = DEF_PLL(VPLL),
268 },
269
270#undef DEF_PLL
271
272 /* Custom (SoC-specific) OTG PHY */
273
274 [JZ4780_CLK_OTGPHY] = {
275 "otg_phy", CGU_CLK_CUSTOM,
276 .parents = { -1, -1, JZ4780_CLK_EXCLK, -1 },
277 .custom = { &jz4780_otg_phy_ops },
278 },
279
280 /* Muxes & dividers */
281
282 [JZ4780_CLK_SCLKA] = {
283 "sclk_a", CGU_CLK_MUX,
284 .parents = { -1, JZ4780_CLK_APLL, JZ4780_CLK_EXCLK,
285 JZ4780_CLK_RTCLK },
286 .mux = { CGU_REG_CLOCKCONTROL, 30, 2 },
287 },
288
289 [JZ4780_CLK_CPUMUX] = {
290 "cpumux", CGU_CLK_MUX,
291 .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
292 JZ4780_CLK_EPLL },
293 .mux = { CGU_REG_CLOCKCONTROL, 28, 2 },
294 },
295
296 [JZ4780_CLK_CPU] = {
297 "cpu", CGU_CLK_DIV,
298 .parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 },
299 .div = { CGU_REG_CLOCKCONTROL, 0, 4, 22, -1, -1 },
300 },
301
302 [JZ4780_CLK_L2CACHE] = {
303 "l2cache", CGU_CLK_DIV,
304 .parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 },
305 .div = { CGU_REG_CLOCKCONTROL, 4, 4, -1, -1, -1 },
306 },
307
308 [JZ4780_CLK_AHB0] = {
309 "ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
310 .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
311 JZ4780_CLK_EPLL },
312 .mux = { CGU_REG_CLOCKCONTROL, 26, 2 },
313 .div = { CGU_REG_CLOCKCONTROL, 8, 4, 21, -1, -1 },
314 },
315
316 [JZ4780_CLK_AHB2PMUX] = {
317 "ahb2_apb_mux", CGU_CLK_MUX,
318 .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
319 JZ4780_CLK_RTCLK },
320 .mux = { CGU_REG_CLOCKCONTROL, 24, 2 },
321 },
322
323 [JZ4780_CLK_AHB2] = {
324 "ahb2", CGU_CLK_DIV,
325 .parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 },
326 .div = { CGU_REG_CLOCKCONTROL, 12, 4, 20, -1, -1 },
327 },
328
329 [JZ4780_CLK_PCLK] = {
330 "pclk", CGU_CLK_DIV,
331 .parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 },
332 .div = { CGU_REG_CLOCKCONTROL, 16, 4, 20, -1, -1 },
333 },
334
335 [JZ4780_CLK_DDR] = {
336 "ddr", CGU_CLK_MUX | CGU_CLK_DIV,
337 .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
338 .mux = { CGU_REG_DDRCDR, 30, 2 },
339 .div = { CGU_REG_DDRCDR, 0, 4, 29, 28, 27 },
340 },
341
342 [JZ4780_CLK_VPU] = {
343 "vpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
344 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
345 JZ4780_CLK_EPLL, -1 },
346 .mux = { CGU_REG_VPUCDR, 30, 2 },
347 .div = { CGU_REG_VPUCDR, 0, 4, 29, 28, 27 },
348 .gate = { CGU_REG_CLKGR1, 2 },
349 },
350
351 [JZ4780_CLK_I2SPLL] = {
352 "i2s_pll", CGU_CLK_MUX | CGU_CLK_DIV,
353 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_EPLL, -1, -1 },
354 .mux = { CGU_REG_I2SCDR, 30, 1 },
355 .div = { CGU_REG_I2SCDR, 0, 8, 29, 28, 27 },
356 },
357
358 [JZ4780_CLK_I2S] = {
359 "i2s", CGU_CLK_MUX,
360 .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_I2SPLL, -1, -1 },
361 .mux = { CGU_REG_I2SCDR, 31, 1 },
362 },
363
364 [JZ4780_CLK_LCD0PIXCLK] = {
365 "lcd0pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
366 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
367 JZ4780_CLK_VPLL, -1 },
368 .mux = { CGU_REG_LP0CDR, 30, 2 },
369 .div = { CGU_REG_LP0CDR, 0, 8, 28, 27, 26 },
370 },
371
372 [JZ4780_CLK_LCD1PIXCLK] = {
373 "lcd1pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
374 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
375 JZ4780_CLK_VPLL, -1 },
376 .mux = { CGU_REG_LP1CDR, 30, 2 },
377 .div = { CGU_REG_LP1CDR, 0, 8, 28, 27, 26 },
378 },
379
380 [JZ4780_CLK_MSCMUX] = {
381 "msc_mux", CGU_CLK_MUX,
382 .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
383 .mux = { CGU_REG_MSC0CDR, 30, 2 },
384 },
385
386 [JZ4780_CLK_MSC0] = {
387 "msc0", CGU_CLK_DIV | CGU_CLK_GATE,
388 .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
389 .div = { CGU_REG_MSC0CDR, 0, 8, 29, 28, 27 },
390 .gate = { CGU_REG_CLKGR0, 3 },
391 },
392
393 [JZ4780_CLK_MSC1] = {
394 "msc1", CGU_CLK_DIV | CGU_CLK_GATE,
395 .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
396 .div = { CGU_REG_MSC1CDR, 0, 8, 29, 28, 27 },
397 .gate = { CGU_REG_CLKGR0, 11 },
398 },
399
400 [JZ4780_CLK_MSC2] = {
401 "msc2", CGU_CLK_DIV | CGU_CLK_GATE,
402 .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
403 .div = { CGU_REG_MSC2CDR, 0, 8, 29, 28, 27 },
404 .gate = { CGU_REG_CLKGR0, 12 },
405 },
406
407 [JZ4780_CLK_UHC] = {
408 "uhc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
409 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
410 JZ4780_CLK_EPLL, JZ4780_CLK_OTGPHY },
411 .mux = { CGU_REG_UHCCDR, 30, 2 },
412 .div = { CGU_REG_UHCCDR, 0, 8, 29, 28, 27 },
413 .gate = { CGU_REG_CLKGR0, 24 },
414 },
415
416 [JZ4780_CLK_SSIPLL] = {
417 "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
418 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 },
419 .mux = { CGU_REG_SSICDR, 30, 1 },
420 .div = { CGU_REG_SSICDR, 0, 8, 29, 28, 27 },
421 },
422
423 [JZ4780_CLK_SSI] = {
424 "ssi", CGU_CLK_MUX,
425 .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_SSIPLL, -1, -1 },
426 .mux = { CGU_REG_SSICDR, 31, 1 },
427 },
428
429 [JZ4780_CLK_CIMMCLK] = {
430 "cim_mclk", CGU_CLK_MUX | CGU_CLK_DIV,
431 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 },
432 .mux = { CGU_REG_CIMCDR, 31, 1 },
433 .div = { CGU_REG_CIMCDR, 0, 8, 30, 29, 28 },
434 },
435
436 [JZ4780_CLK_PCMPLL] = {
437 "pcm_pll", CGU_CLK_MUX | CGU_CLK_DIV,
438 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
439 JZ4780_CLK_EPLL, JZ4780_CLK_VPLL },
440 .mux = { CGU_REG_PCMCDR, 29, 2 },
441 .div = { CGU_REG_PCMCDR, 0, 8, 28, 27, 26 },
442 },
443
444 [JZ4780_CLK_PCM] = {
445 "pcm", CGU_CLK_MUX | CGU_CLK_GATE,
446 .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_PCMPLL, -1, -1 },
447 .mux = { CGU_REG_PCMCDR, 31, 1 },
448 .gate = { CGU_REG_CLKGR1, 3 },
449 },
450
451 [JZ4780_CLK_GPU] = {
452 "gpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
453 .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
454 JZ4780_CLK_EPLL },
455 .mux = { CGU_REG_GPUCDR, 30, 2 },
456 .div = { CGU_REG_GPUCDR, 0, 4, 29, 28, 27 },
457 .gate = { CGU_REG_CLKGR1, 4 },
458 },
459
460 [JZ4780_CLK_HDMI] = {
461 "hdmi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
462 .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
463 JZ4780_CLK_VPLL, -1 },
464 .mux = { CGU_REG_HDMICDR, 30, 2 },
465 .div = { CGU_REG_HDMICDR, 0, 8, 29, 28, 26 },
466 .gate = { CGU_REG_CLKGR1, 9 },
467 },
468
469 [JZ4780_CLK_BCH] = {
470 "bch", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
471 .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
472 JZ4780_CLK_EPLL },
473 .mux = { CGU_REG_BCHCDR, 30, 2 },
474 .div = { CGU_REG_BCHCDR, 0, 4, 29, 28, 27 },
475 .gate = { CGU_REG_CLKGR0, 1 },
476 },
477
478 /* Gate-only clocks */
479
480 [JZ4780_CLK_NEMC] = {
481 "nemc", CGU_CLK_GATE,
482 .parents = { JZ4780_CLK_AHB2, -1, -1, -1 },
483 .gate = { CGU_REG_CLKGR0, 0 },
484 },
485
486 [JZ4780_CLK_OTG0] = {
487 "otg0", CGU_CLK_GATE,
488 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
489 .gate = { CGU_REG_CLKGR0, 2 },
490 },
491
492 [JZ4780_CLK_SSI0] = {
493 "ssi0", CGU_CLK_GATE,
494 .parents = { JZ4780_CLK_SSI, -1, -1, -1 },
495 .gate = { CGU_REG_CLKGR0, 4 },
496 },
497
498 [JZ4780_CLK_SMB0] = {
499 "smb0", CGU_CLK_GATE,
500 .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
501 .gate = { CGU_REG_CLKGR0, 5 },
502 },
503
504 [JZ4780_CLK_SMB1] = {
505 "smb1", CGU_CLK_GATE,
506 .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
507 .gate = { CGU_REG_CLKGR0, 6 },
508 },
509
510 [JZ4780_CLK_SCC] = {
511 "scc", CGU_CLK_GATE,
512 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
513 .gate = { CGU_REG_CLKGR0, 7 },
514 },
515
516 [JZ4780_CLK_AIC] = {
517 "aic", CGU_CLK_GATE,
518 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
519 .gate = { CGU_REG_CLKGR0, 8 },
520 },
521
522 [JZ4780_CLK_TSSI0] = {
523 "tssi0", CGU_CLK_GATE,
524 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
525 .gate = { CGU_REG_CLKGR0, 9 },
526 },
527
528 [JZ4780_CLK_OWI] = {
529 "owi", CGU_CLK_GATE,
530 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
531 .gate = { CGU_REG_CLKGR0, 10 },
532 },
533
534 [JZ4780_CLK_KBC] = {
535 "kbc", CGU_CLK_GATE,
536 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
537 .gate = { CGU_REG_CLKGR0, 13 },
538 },
539
540 [JZ4780_CLK_SADC] = {
541 "sadc", CGU_CLK_GATE,
542 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
543 .gate = { CGU_REG_CLKGR0, 14 },
544 },
545
546 [JZ4780_CLK_UART0] = {
547 "uart0", CGU_CLK_GATE,
548 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
549 .gate = { CGU_REG_CLKGR0, 15 },
550 },
551
552 [JZ4780_CLK_UART1] = {
553 "uart1", CGU_CLK_GATE,
554 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
555 .gate = { CGU_REG_CLKGR0, 16 },
556 },
557
558 [JZ4780_CLK_UART2] = {
559 "uart2", CGU_CLK_GATE,
560 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
561 .gate = { CGU_REG_CLKGR0, 17 },
562 },
563
564 [JZ4780_CLK_UART3] = {
565 "uart3", CGU_CLK_GATE,
566 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
567 .gate = { CGU_REG_CLKGR0, 18 },
568 },
569
570 [JZ4780_CLK_SSI1] = {
571 "ssi1", CGU_CLK_GATE,
572 .parents = { JZ4780_CLK_SSI, -1, -1, -1 },
573 .gate = { CGU_REG_CLKGR0, 19 },
574 },
575
576 [JZ4780_CLK_SSI2] = {
577 "ssi2", CGU_CLK_GATE,
578 .parents = { JZ4780_CLK_SSI, -1, -1, -1 },
579 .gate = { CGU_REG_CLKGR0, 20 },
580 },
581
582 [JZ4780_CLK_PDMA] = {
583 "pdma", CGU_CLK_GATE,
584 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
585 .gate = { CGU_REG_CLKGR0, 21 },
586 },
587
588 [JZ4780_CLK_GPS] = {
589 "gps", CGU_CLK_GATE,
590 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
591 .gate = { CGU_REG_CLKGR0, 22 },
592 },
593
594 [JZ4780_CLK_MAC] = {
595 "mac", CGU_CLK_GATE,
596 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
597 .gate = { CGU_REG_CLKGR0, 23 },
598 },
599
600 [JZ4780_CLK_SMB2] = {
601 "smb2", CGU_CLK_GATE,
602 .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
603 .gate = { CGU_REG_CLKGR0, 24 },
604 },
605
606 [JZ4780_CLK_CIM] = {
607 "cim", CGU_CLK_GATE,
608 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
609 .gate = { CGU_REG_CLKGR0, 26 },
610 },
611
612 [JZ4780_CLK_LCD] = {
613 "lcd", CGU_CLK_GATE,
614 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
615 .gate = { CGU_REG_CLKGR0, 28 },
616 },
617
618 [JZ4780_CLK_TVE] = {
619 "tve", CGU_CLK_GATE,
620 .parents = { JZ4780_CLK_LCD, -1, -1, -1 },
621 .gate = { CGU_REG_CLKGR0, 27 },
622 },
623
624 [JZ4780_CLK_IPU] = {
625 "ipu", CGU_CLK_GATE,
626 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
627 .gate = { CGU_REG_CLKGR0, 29 },
628 },
629
630 [JZ4780_CLK_DDR0] = {
631 "ddr0", CGU_CLK_GATE,
632 .parents = { JZ4780_CLK_DDR, -1, -1, -1 },
633 .gate = { CGU_REG_CLKGR0, 30 },
634 },
635
636 [JZ4780_CLK_DDR1] = {
637 "ddr1", CGU_CLK_GATE,
638 .parents = { JZ4780_CLK_DDR, -1, -1, -1 },
639 .gate = { CGU_REG_CLKGR0, 31 },
640 },
641
642 [JZ4780_CLK_SMB3] = {
643 "smb3", CGU_CLK_GATE,
644 .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
645 .gate = { CGU_REG_CLKGR1, 0 },
646 },
647
648 [JZ4780_CLK_TSSI1] = {
649 "tssi1", CGU_CLK_GATE,
650 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
651 .gate = { CGU_REG_CLKGR1, 1 },
652 },
653
654 [JZ4780_CLK_COMPRESS] = {
655 "compress", CGU_CLK_GATE,
656 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
657 .gate = { CGU_REG_CLKGR1, 5 },
658 },
659
660 [JZ4780_CLK_AIC1] = {
661 "aic1", CGU_CLK_GATE,
662 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
663 .gate = { CGU_REG_CLKGR1, 6 },
664 },
665
666 [JZ4780_CLK_GPVLC] = {
667 "gpvlc", CGU_CLK_GATE,
668 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
669 .gate = { CGU_REG_CLKGR1, 7 },
670 },
671
672 [JZ4780_CLK_OTG1] = {
673 "otg1", CGU_CLK_GATE,
674 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
675 .gate = { CGU_REG_CLKGR1, 8 },
676 },
677
678 [JZ4780_CLK_UART4] = {
679 "uart4", CGU_CLK_GATE,
680 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
681 .gate = { CGU_REG_CLKGR1, 10 },
682 },
683
684 [JZ4780_CLK_AHBMON] = {
685 "ahb_mon", CGU_CLK_GATE,
686 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
687 .gate = { CGU_REG_CLKGR1, 11 },
688 },
689
690 [JZ4780_CLK_SMB4] = {
691 "smb4", CGU_CLK_GATE,
692 .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
693 .gate = { CGU_REG_CLKGR1, 12 },
694 },
695
696 [JZ4780_CLK_DES] = {
697 "des", CGU_CLK_GATE,
698 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
699 .gate = { CGU_REG_CLKGR1, 13 },
700 },
701
702 [JZ4780_CLK_X2D] = {
703 "x2d", CGU_CLK_GATE,
704 .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
705 .gate = { CGU_REG_CLKGR1, 14 },
706 },
707
708 [JZ4780_CLK_CORE1] = {
709 "core1", CGU_CLK_GATE,
710 .parents = { JZ4780_CLK_CPU, -1, -1, -1 },
711 .gate = { CGU_REG_CLKGR1, 15 },
712 },
713
714};
715
716static void __init jz4780_cgu_init(struct device_node *np)
717{
718 int retval;
719
720 cgu = ingenic_cgu_new(jz4780_cgu_clocks,
721 ARRAY_SIZE(jz4780_cgu_clocks), np);
722 if (!cgu) {
723 pr_err("%s: failed to initialise CGU\n", __func__);
724 return;
725 }
726
727 retval = ingenic_cgu_register_clocks(cgu);
728 if (retval) {
729 pr_err("%s: failed to register CGU Clocks\n", __func__);
730 return;
731 }
732}
733CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);