* [PATCH v5 00/37] JZ4780 & CI20 support
@ 2015-05-24 15:11 Paul Burton
2015-05-24 15:11 ` [PATCH v5 25/37] clk: ingenic: add driver for Ingenic SoC CGU clocks Paul Burton
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Paul Burton @ 2015-05-24 15:11 UTC (permalink / raw)
To: linux-mips
Cc: Paul Burton, Mike Turquette, Arnd Bergmann, Jiri Slaby,
Joshua Kinard, Thierry Reding, Linus Walleij, Philipp Zabel,
Kumar Gala, Jason Cooper, Ian Campbell, Rob Herring,
Antony Pavlov, Felix Fietkau, Apelete Seketeli, linux-clk,
Steven J. Hill, Andrew Bresticker, Huacai Chen, Maciej W. Rozycki,
Thomas Gleixner, Leonid Yegoshin, Pawel Moll, Markos Chandras,
Lars-Peter Clausen, Ralf Baechle, Alexandre Courbot,
Matthias Brugger, Greg Kroah-Hartman, devicetree, Qais Yousef,
linux-serial, Stephen Boyd, Kuninori Morimoto, Brian Norris,
Andreas Herrmann, Sebastian Andrzej Siewior, Hayato Suzuki,
Alan Cox, Fabian Frederick, Deng-Cheng Zhu, Peter Hurley,
linux-kernel, Stephen Warren, Arnaud Ebalard, Dmitry Torokhov,
Tony Lindgren, Ricardo Ribalda Delgado, Mark Rutland,
John Crispin
This series introduces initial support for the Ingenic JZ4780 SoC and
the Imagination Technologies MIPS Creator CI20 board which is built
around it. In the process the existing JZ4740 & qi_lb60 code gains
initial support for using DeviceTree such that much of the existing
platform code under arch/mips/jz4740 can be shared.
The series applies atop v4.1-rc4. Review appreciated, and hopefully
this can make it in for v4.2.
Paul Burton (37):
devicetree/bindings: add Ingenic Semiconductor vendor prefix
devicetree/bindings: add Qi Hardware vendor prefix
MIPS: JZ4740: introduce CONFIG_MACH_INGENIC
MIPS: ingenic: add newer vendor IDs
MIPS: JZ4740: require & include DT
MIPS: irq_cpu: declare irqchip table entry
MIPS: JZ4740: probe CPU interrupt controller via DT
MIPS: JZ4740: use generic plat_irq_dispatch
MIPS: JZ4740: move arch_init_irq out of arch/mips/jz4740/irq.c
devicetree: document Ingenic SoC interrupt controller binding
MIPS: JZ4740: probe interrupt controller via DT
MIPS: JZ4740: parse SoC interrupt controller parent IRQ from DT
MIPS: JZ4740: register an irq_domain for the interrupt controller
MIPS: JZ4740: drop intc debugfs code
MIPS: JZ4740: remove jz_intc_base global
MIPS: JZ4740: support >32 interrupts
MIPS: JZ4740: define IRQ numbers based on number of intc IRQs
MIPS: JZ4740: read intc base address from DT
MIPS: JZ4740: avoid JZ4740-specific naming
MIPS: JZ4740: support newer SoC interrupt controllers
irqchip: move Ingenic SoC intc driver to drivers/irqchip
MIPS: JZ4740: call jz4740_clock_init earlier
MIPS: JZ4740: replace use of jz4740_clock_bdata
devicetree: add Ingenic CGU binding documentation
clk: ingenic: add driver for Ingenic SoC CGU clocks
MIPS,clk: migrate JZ4740 to common clock framework
MIPS,clk: move jz4740_clock_set_wait_mode to jz4740-cgu
MIPS, clk: move jz4740 UDC auto suspend functions to jz4740-cgu
MIPS, clk: move jz4740 clock suspend, resume functions to jz4740-cgu
clk: ingenic: add JZ4780 CGU support
MIPS: JZ4740: remove clock.h
MIPS: JZ4740: only detect RAM size if not specified in DT
devicetree: document Ingenic SoC UART binding
serial: 8250_ingenic: support for Ingenic SoC UARTs
MIPS: JZ4740: use Ingenic SoC UART driver
MIPS: ingenic: initial JZ4780 support
MIPS: ingenic: initial MIPS Creator CI20 support
.../devicetree/bindings/clock/ingenic,cgu.txt | 53 ++
.../bindings/interrupt-controller/ingenic,intc.txt | 28 +
.../devicetree/bindings/serial/ingenic,uart.txt | 22 +
.../devicetree/bindings/vendor-prefixes.txt | 2 +
arch/mips/Kconfig | 11 +-
arch/mips/boot/dts/Makefile | 1 +
arch/mips/boot/dts/ingenic/Makefile | 10 +
arch/mips/boot/dts/ingenic/ci20.dts | 44 +
arch/mips/boot/dts/ingenic/jz4740.dtsi | 68 ++
arch/mips/boot/dts/ingenic/jz4780.dtsi | 111 +++
arch/mips/boot/dts/ingenic/qi_lb60.dts | 15 +
arch/mips/configs/ci20_defconfig | 162 ++++
arch/mips/configs/qi_lb60_defconfig | 3 +-
arch/mips/include/asm/cpu-type.h | 2 +-
arch/mips/include/asm/cpu.h | 6 +-
arch/mips/include/asm/mach-jz4740/clock.h | 3 +
.../asm/mach-jz4740/cpu-feature-overrides.h | 3 -
arch/mips/include/asm/mach-jz4740/irq.h | 14 +-
arch/mips/include/asm/mach-jz4740/platform.h | 2 -
arch/mips/jz4740/Kconfig | 17 +-
arch/mips/jz4740/Makefile | 8 +-
arch/mips/jz4740/Platform | 8 +-
arch/mips/jz4740/board-qi_lb60.c | 7 -
arch/mips/jz4740/clock-debugfs.c | 108 ---
arch/mips/jz4740/clock.c | 924 ---------------------
arch/mips/jz4740/clock.h | 76 --
arch/mips/jz4740/gpio.c | 7 +-
arch/mips/jz4740/irq.c | 162 ----
arch/mips/jz4740/platform.c | 38 +-
arch/mips/jz4740/pm.c | 2 -
arch/mips/jz4740/prom.c | 13 -
arch/mips/jz4740/reset.c | 13 +-
arch/mips/jz4740/serial.c | 33 -
arch/mips/jz4740/serial.h | 23 -
arch/mips/jz4740/setup.c | 36 +-
arch/mips/jz4740/time.c | 19 +-
arch/mips/kernel/cpu-probe.c | 4 +-
arch/mips/kernel/irq_cpu.c | 3 +
drivers/clk/Makefile | 1 +
drivers/clk/ingenic/Makefile | 3 +
drivers/clk/ingenic/cgu.c | 711 ++++++++++++++++
drivers/clk/ingenic/cgu.h | 223 +++++
drivers/clk/ingenic/jz4740-cgu.c | 303 +++++++
drivers/clk/ingenic/jz4780-cgu.c | 733 ++++++++++++++++
drivers/irqchip/Kconfig | 5 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-ingenic.c | 177 ++++
drivers/tty/serial/8250/8250_ingenic.c | 266 ++++++
drivers/tty/serial/8250/Kconfig | 9 +
drivers/tty/serial/8250/Makefile | 3 +
include/dt-bindings/clock/jz4740-cgu.h | 37 +
include/dt-bindings/clock/jz4780-cgu.h | 88 ++
.../irq.h => include/linux/irqchip/ingenic.h | 8 +-
53 files changed, 3205 insertions(+), 1424 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/ingenic,cgu.txt
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.txt
create mode 100644 Documentation/devicetree/bindings/serial/ingenic,uart.txt
create mode 100644 arch/mips/boot/dts/ingenic/Makefile
create mode 100644 arch/mips/boot/dts/ingenic/ci20.dts
create mode 100644 arch/mips/boot/dts/ingenic/jz4740.dtsi
create mode 100644 arch/mips/boot/dts/ingenic/jz4780.dtsi
create mode 100644 arch/mips/boot/dts/ingenic/qi_lb60.dts
create mode 100644 arch/mips/configs/ci20_defconfig
delete mode 100644 arch/mips/jz4740/clock-debugfs.c
delete mode 100644 arch/mips/jz4740/clock.c
delete mode 100644 arch/mips/jz4740/clock.h
delete mode 100644 arch/mips/jz4740/irq.c
delete mode 100644 arch/mips/jz4740/serial.c
delete mode 100644 arch/mips/jz4740/serial.h
create mode 100644 drivers/clk/ingenic/Makefile
create mode 100644 drivers/clk/ingenic/cgu.c
create mode 100644 drivers/clk/ingenic/cgu.h
create mode 100644 drivers/clk/ingenic/jz4740-cgu.c
create mode 100644 drivers/clk/ingenic/jz4780-cgu.c
create mode 100644 drivers/irqchip/irq-ingenic.c
create mode 100644 drivers/tty/serial/8250/8250_ingenic.c
create mode 100644 include/dt-bindings/clock/jz4740-cgu.h
create mode 100644 include/dt-bindings/clock/jz4780-cgu.h
rename arch/mips/jz4740/irq.h => include/linux/irqchip/ingenic.h (74%)
--
2.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v5 25/37] clk: ingenic: add driver for Ingenic SoC CGU clocks
2015-05-24 15:11 [PATCH v5 00/37] JZ4780 & CI20 support Paul Burton
@ 2015-05-24 15:11 ` Paul Burton
2015-05-24 15:11 ` [PATCH v5 26/37] MIPS,clk: migrate JZ4740 to common clock framework Paul Burton
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Paul Burton @ 2015-05-24 15:11 UTC (permalink / raw)
To: linux-mips
Cc: Paul Burton, Lars-Peter Clausen, Mike Turquette, Stephen Boyd,
linux-clk, linux-kernel
This driver supports the CGU clocks for Ingenic SoCs. It is generic
enough to be usable across at least the JZ4740 to the JZ4780, and will
be made use of on such devices in subsequent commits. This patch by
itself only adds the SoC-agnostic infrastructure that forms the bulk of
the CGU driver for the aforementioned further commits to make use of.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Co-authored-by: Paul Cercueil <paul@crapouillou.net>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: linux-clk@vger.kernel.org
---
Changes in v5:
- Drop some extraneous brackets in ingenic_pll_recalc_rate.
- s/register_clock/ingenic_register_clock/.
- Correct documentation of ingenic_cgu_register_clocks return value to
indicate 0 is returned upon success.
- Drop extraneous braces in ingenic_clk_round_rate.
Changes in v4:
- Add brackets to functions in kerneldoc comments.
- Correct some stale comments.
- Return bool from ingenic_cgu_gate_get.
- Use div_u64 to avoid potential overflows in PLL rate calculations.
- Honor m_offset & n_offset in ingenic_pll_calc.
- Avoid incorrectly calculating the value to write to a mux field in
ingenic_clk_set_parent when the desired parent is the first (idx ==
0) and the hardware's zero value is not a valid parent (ie.
clk_info->parents[0] == -1).
- Return parent rate for non-dividing clocks in
ingenic_clk_round_rate.
- Drop redundant cgu != NULL check in ingenic_cgu_register_clocks
error path.
- Consistently use u8/s8 for bit specifications where the bit is
required or optional respectively.
- Use BIT & GENMASK macros in a few more places, replacing open coded
versions.
- Simplify & correct locking. CGU registers aren't always neatly
divided into those controlling whether clocks are enabled & those
controlling other attributes of the clock (rate, parent etc). Thus
accesses to many of these registers can occur from either of the two
groups of operations described by Documentation/clk.txt and from
either atomic or non-atomic context. The split of functionality
between different CGU registers also differs between SoCs. Simplify
handling all of this by using a single spinlock, which at least
is simple, works correctly and can be revisited if it ever proves to
be a performance issue in future.
Changes in v3:
- s/jz47xx/ingenic/ since Ingenic have changed their naming scheme to
"Mxxx" for newer SoCs.
- Allow clock gating with registers other than CLKGR* (pcercuei).
- Fixup dividers to never exceed the requested rate (pcercuei).
- Fixup PLL calculations to work better with more restricted
coefficient bit widths (pcercuei).
Changes in v2:
- Fix spinlock handling in jz47xx_clk_set_rate error path (ZubairLK).
drivers/clk/Makefile | 1 +
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/cgu.c | 711 +++++++++++++++++++++++++++++++++++++++++++
drivers/clk/ingenic/cgu.h | 223 ++++++++++++++
4 files changed, 936 insertions(+)
create mode 100644 drivers/clk/ingenic/Makefile
create mode 100644 drivers/clk/ingenic/cgu.c
create mode 100644 drivers/clk/ingenic/cgu.h
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 3d00c25..cc77327 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
+obj-$(CONFIG_MACH_INGENIC) += ingenic/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
new file mode 100644
index 0000000..5ac2fd9
--- /dev/null
+++ b/drivers/clk/ingenic/Makefile
@@ -0,0 +1 @@
+obj-y += cgu.o
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
new file mode 100644
index 0000000..b936cdd
--- /dev/null
+++ b/drivers/clk/ingenic/cgu.c
@@ -0,0 +1,711 @@
+/*
+ * Ingenic SoC CGU driver
+ *
+ * Copyright (c) 2013-2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/math64.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "cgu.h"
+
+#define MHZ (1000 * 1000)
+
+/**
+ * ingenic_cgu_gate_get() - get the value of clock gate register bit
+ * @cgu: reference to the CGU whose registers should be read
+ * @info: info struct describing the gate bit
+ *
+ * Retrieves the state of the clock gate bit described by info. The
+ * caller must hold cgu->lock.
+ *
+ * Return: true if the gate bit is set, else false.
+ */
+static inline bool
+ingenic_cgu_gate_get(struct ingenic_cgu *cgu,
+ const struct ingenic_cgu_gate_info *info)
+{
+ return readl(cgu->base + info->reg) & BIT(info->bit);
+}
+
+/**
+ * ingenic_cgu_gate_set() - set the value of clock gate register bit
+ * @cgu: reference to the CGU whose registers should be modified
+ * @info: info struct describing the gate bit
+ * @val: non-zero to gate a clock, otherwise zero
+ *
+ * Sets the given gate bit in order to gate or ungate a clock.
+ *
+ * The caller must hold cgu->lock.
+ */
+static inline void
+ingenic_cgu_gate_set(struct ingenic_cgu *cgu,
+ const struct ingenic_cgu_gate_info *info, bool val)
+{
+ u32 clkgr = readl(cgu->base + info->reg);
+
+ if (val)
+ clkgr |= BIT(info->bit);
+ else
+ clkgr &= ~BIT(info->bit);
+
+ writel(clkgr, cgu->base + info->reg);
+}
+
+/*
+ * PLL operations
+ */
+
+static unsigned long
+ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ const struct ingenic_cgu_pll_info *pll_info;
+ unsigned m, n, od_enc, od;
+ bool bypass, enable;
+ unsigned long flags;
+ u32 ctl;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+ BUG_ON(clk_info->type != CGU_CLK_PLL);
+ pll_info = &clk_info->pll;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ m = (ctl >> pll_info->m_shift) & GENMASK(pll_info->m_bits - 1, 0);
+ m += pll_info->m_offset;
+ n = (ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0);
+ n += pll_info->n_offset;
+ od_enc = ctl >> pll_info->od_shift;
+ od_enc &= GENMASK(pll_info->od_bits - 1, 0);
+ bypass = !!(ctl & BIT(pll_info->bypass_bit));
+ enable = !!(ctl & BIT(pll_info->enable_bit));
+
+ if (bypass)
+ return parent_rate;
+
+ if (!enable)
+ return 0;
+
+ for (od = 0; od < pll_info->od_max; od++) {
+ if (pll_info->od_encoding[od] == od_enc)
+ break;
+ }
+ BUG_ON(od == pll_info->od_max);
+ od++;
+
+ return div_u64((u64)parent_rate * m, n * od);
+}
+
+static unsigned long
+ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
+ unsigned long rate, unsigned long parent_rate,
+ unsigned *pm, unsigned *pn, unsigned *pod)
+{
+ const struct ingenic_cgu_pll_info *pll_info;
+ unsigned m, n, od;
+
+ pll_info = &clk_info->pll;
+ od = 1;
+
+ /*
+ * The frequency after the input divider must be between 10 and 50 MHz.
+ * The highest divider yields the best resolution.
+ */
+ n = parent_rate / (10 * MHZ);
+ n = min_t(unsigned, n, 1 << clk_info->pll.n_bits);
+ n = max_t(unsigned, n, pll_info->n_offset);
+
+ m = (rate / MHZ) * od * n / (parent_rate / MHZ);
+ m = min_t(unsigned, m, 1 << clk_info->pll.m_bits);
+ m = max_t(unsigned, m, pll_info->m_offset);
+
+ if (pm)
+ *pm = m;
+ if (pn)
+ *pn = n;
+ if (pod)
+ *pod = od;
+
+ return div_u64((u64)parent_rate * m, n * od);
+}
+
+static long
+ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *prate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+ BUG_ON(clk_info->type != CGU_CLK_PLL);
+
+ return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
+}
+
+static int
+ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long parent_rate)
+{
+ const unsigned timeout = 100;
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ const struct ingenic_cgu_pll_info *pll_info;
+ unsigned long rate, flags;
+ unsigned m, n, od, i;
+ u32 ctl;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+ BUG_ON(clk_info->type != CGU_CLK_PLL);
+ pll_info = &clk_info->pll;
+
+ rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
+ &m, &n, &od);
+ if (rate != req_rate)
+ pr_info("ingenic-cgu: request '%s' rate %luHz, actual %luHz\n",
+ clk_info->name, req_rate, rate);
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ ctl = readl(cgu->base + pll_info->reg);
+
+ ctl &= ~(GENMASK(pll_info->m_bits - 1, 0) << pll_info->m_shift);
+ ctl |= (m - pll_info->m_offset) << pll_info->m_shift;
+
+ ctl &= ~(GENMASK(pll_info->n_bits - 1, 0) << pll_info->n_shift);
+ ctl |= (n - pll_info->n_offset) << pll_info->n_shift;
+
+ ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
+ ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
+
+ ctl &= ~BIT(pll_info->bypass_bit);
+ ctl |= BIT(pll_info->enable_bit);
+
+ writel(ctl, cgu->base + pll_info->reg);
+
+ /* wait for the PLL to stabilise */
+ for (i = 0; i < timeout; i++) {
+ ctl = readl(cgu->base + pll_info->reg);
+ if (ctl & BIT(pll_info->stable_bit))
+ break;
+ mdelay(1);
+ }
+
+ spin_unlock_irqrestore(&cgu->lock, flags);
+
+ if (i == timeout)
+ return -EBUSY;
+
+ return 0;
+}
+
+static const struct clk_ops ingenic_pll_ops = {
+ .recalc_rate = ingenic_pll_recalc_rate,
+ .round_rate = ingenic_pll_round_rate,
+ .set_rate = ingenic_pll_set_rate,
+};
+
+/*
+ * Operations for all non-PLL clocks
+ */
+
+static u8 ingenic_clk_get_parent(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ u32 reg;
+ u8 i, hw_idx, idx = 0;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+
+ if (clk_info->type & CGU_CLK_MUX) {
+ reg = readl(cgu->base + clk_info->mux.reg);
+ hw_idx = (reg >> clk_info->mux.shift) &
+ GENMASK(clk_info->mux.bits - 1, 0);
+
+ /*
+ * Convert the hardware index to the parent index by skipping
+ * over any -1's in the parents array.
+ */
+ for (i = 0; i < hw_idx; i++) {
+ if (clk_info->parents[i] != -1)
+ idx++;
+ }
+ }
+
+ return idx;
+}
+
+static int ingenic_clk_set_parent(struct clk_hw *hw, u8 idx)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ unsigned long flags;
+ u8 curr_idx, hw_idx, num_poss;
+ u32 reg, mask;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+
+ if (clk_info->type & CGU_CLK_MUX) {
+ /*
+ * Convert the parent index to the hardware index by adding
+ * 1 for any -1 in the parents array preceding the given
+ * index. That is, we want the index of idx'th entry in
+ * clk_info->parents which does not equal -1.
+ */
+ hw_idx = curr_idx = 0;
+ num_poss = 1 << clk_info->mux.bits;
+ for (; hw_idx < num_poss; hw_idx++) {
+ if (clk_info->parents[hw_idx] == -1)
+ continue;
+ if (curr_idx == idx)
+ break;
+ curr_idx++;
+ }
+
+ /* idx should always be a valid parent */
+ BUG_ON(curr_idx != idx);
+
+ mask = GENMASK(clk_info->mux.bits - 1, 0);
+ mask <<= clk_info->mux.shift;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+
+ /* write the register */
+ reg = readl(cgu->base + clk_info->mux.reg);
+ reg &= ~mask;
+ reg |= hw_idx << clk_info->mux.shift;
+ writel(reg, cgu->base + clk_info->mux.reg);
+
+ spin_unlock_irqrestore(&cgu->lock, flags);
+ return 0;
+ }
+
+ return idx ? -EINVAL : 0;
+}
+
+static unsigned long
+ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ unsigned long rate = parent_rate;
+ u32 div_reg, div;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+
+ if (clk_info->type & CGU_CLK_DIV) {
+ div_reg = readl(cgu->base + clk_info->div.reg);
+ div = (div_reg >> clk_info->div.shift) &
+ GENMASK(clk_info->div.bits - 1, 0);
+ div += 1;
+
+ rate /= div;
+ }
+
+ return rate;
+}
+
+static unsigned
+ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
+ unsigned long parent_rate, unsigned long req_rate)
+{
+ unsigned div;
+
+ /* calculate the divide */
+ div = DIV_ROUND_UP(parent_rate, req_rate);
+
+ /* and impose hardware constraints */
+ div = min_t(unsigned, div, 1 << clk_info->div.bits);
+ div = max_t(unsigned, div, 1);
+
+ return div;
+}
+
+static long
+ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *parent_rate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ long rate = *parent_rate;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+
+ if (clk_info->type & CGU_CLK_DIV)
+ rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
+ else if (clk_info->type & CGU_CLK_FIXDIV)
+ rate /= clk_info->fixdiv.div;
+
+ return rate;
+}
+
+static int
+ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long parent_rate)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ const unsigned timeout = 100;
+ unsigned long rate, flags;
+ unsigned div, i;
+ u32 reg, mask;
+ int ret = 0;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+
+ if (clk_info->type & CGU_CLK_DIV) {
+ div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
+ rate = parent_rate / div;
+
+ if (rate != req_rate)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+ reg = readl(cgu->base + clk_info->div.reg);
+
+ /* update the divide */
+ mask = GENMASK(clk_info->div.bits - 1, 0);
+ reg &= ~(mask << clk_info->div.shift);
+ reg |= (div - 1) << clk_info->div.shift;
+
+ /* clear the stop bit */
+ if (clk_info->div.stop_bit != -1)
+ reg &= ~BIT(clk_info->div.stop_bit);
+
+ /* set the change enable bit */
+ if (clk_info->div.ce_bit != -1)
+ reg |= BIT(clk_info->div.ce_bit);
+
+ /* update the hardware */
+ writel(reg, cgu->base + clk_info->div.reg);
+
+ /* wait for the change to take effect */
+ if (clk_info->div.busy_bit != -1) {
+ for (i = 0; i < timeout; i++) {
+ reg = readl(cgu->base + clk_info->div.reg);
+ if (!(reg & BIT(clk_info->div.busy_bit)))
+ break;
+ mdelay(1);
+ }
+ if (i == timeout)
+ ret = -EBUSY;
+ }
+
+ spin_unlock_irqrestore(&cgu->lock, flags);
+ return ret;
+ }
+
+ return -EINVAL;
+}
+
+static int ingenic_clk_enable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ unsigned long flags;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+
+ if (clk_info->type & CGU_CLK_GATE) {
+ /* ungate the clock */
+ spin_lock_irqsave(&cgu->lock, flags);
+ ingenic_cgu_gate_set(cgu, &clk_info->gate, false);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+ }
+
+ return 0;
+}
+
+static void ingenic_clk_disable(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ unsigned long flags;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+
+ if (clk_info->type & CGU_CLK_GATE) {
+ /* gate the clock */
+ spin_lock_irqsave(&cgu->lock, flags);
+ ingenic_cgu_gate_set(cgu, &clk_info->gate, true);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+ }
+}
+
+static int ingenic_clk_is_enabled(struct clk_hw *hw)
+{
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
+ const struct ingenic_cgu_clk_info *clk_info;
+ unsigned long flags;
+ int enabled = 1;
+
+ clk_info = &cgu->clock_info[ingenic_clk->idx];
+
+ if (clk_info->type & CGU_CLK_GATE) {
+ spin_lock_irqsave(&cgu->lock, flags);
+ enabled = !ingenic_cgu_gate_get(cgu, &clk_info->gate);
+ spin_unlock_irqrestore(&cgu->lock, flags);
+ }
+
+ return enabled;
+}
+
+static const struct clk_ops ingenic_clk_ops = {
+ .get_parent = ingenic_clk_get_parent,
+ .set_parent = ingenic_clk_set_parent,
+
+ .recalc_rate = ingenic_clk_recalc_rate,
+ .round_rate = ingenic_clk_round_rate,
+ .set_rate = ingenic_clk_set_rate,
+
+ .enable = ingenic_clk_enable,
+ .disable = ingenic_clk_disable,
+ .is_enabled = ingenic_clk_is_enabled,
+};
+
+/*
+ * Setup functions.
+ */
+
+static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
+{
+ const struct ingenic_cgu_clk_info *clk_info = &cgu->clock_info[idx];
+ struct clk_init_data clk_init;
+ struct ingenic_clk *ingenic_clk = NULL;
+ struct clk *clk, *parent;
+ const char *parent_names[4];
+ unsigned caps, i, num_possible;
+ int err = -EINVAL;
+
+ BUILD_BUG_ON(ARRAY_SIZE(clk_info->parents) > ARRAY_SIZE(parent_names));
+
+ if (clk_info->type == CGU_CLK_EXT) {
+ clk = of_clk_get_by_name(cgu->np, clk_info->name);
+ if (IS_ERR(clk)) {
+ pr_err("%s: no external clock '%s' provided\n",
+ __func__, clk_info->name);
+ err = -ENODEV;
+ goto out;
+ }
+ err = clk_register_clkdev(clk, clk_info->name, NULL);
+ if (err) {
+ clk_put(clk);
+ goto out;
+ }
+ cgu->clocks.clks[idx] = clk;
+ return 0;
+ }
+
+ if (!clk_info->type) {
+ pr_err("%s: no clock type specified for '%s'\n", __func__,
+ clk_info->name);
+ goto out;
+ }
+
+ ingenic_clk = kzalloc(sizeof(*ingenic_clk), GFP_KERNEL);
+ if (!ingenic_clk) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ ingenic_clk->hw.init = &clk_init;
+ ingenic_clk->cgu = cgu;
+ ingenic_clk->idx = idx;
+
+ clk_init.name = clk_info->name;
+ clk_init.flags = 0;
+ clk_init.parent_names = parent_names;
+
+ caps = clk_info->type;
+
+ if (caps & (CGU_CLK_MUX | CGU_CLK_CUSTOM)) {
+ clk_init.num_parents = 0;
+
+ if (caps & CGU_CLK_MUX)
+ num_possible = 1 << clk_info->mux.bits;
+ else
+ num_possible = ARRAY_SIZE(clk_info->parents);
+
+ for (i = 0; i < num_possible; i++) {
+ if (clk_info->parents[i] == -1)
+ continue;
+
+ parent = cgu->clocks.clks[clk_info->parents[i]];
+ parent_names[clk_init.num_parents] =
+ __clk_get_name(parent);
+ clk_init.num_parents++;
+ }
+
+ BUG_ON(!clk_init.num_parents);
+ BUG_ON(clk_init.num_parents > ARRAY_SIZE(parent_names));
+ } else {
+ BUG_ON(clk_info->parents[0] == -1);
+ clk_init.num_parents = 1;
+ parent = cgu->clocks.clks[clk_info->parents[0]];
+ parent_names[0] = __clk_get_name(parent);
+ }
+
+ if (caps & CGU_CLK_CUSTOM) {
+ clk_init.ops = clk_info->custom.clk_ops;
+
+ caps &= ~CGU_CLK_CUSTOM;
+
+ if (caps) {
+ pr_err("%s: custom clock may not be combined with type 0x%x\n",
+ __func__, caps);
+ goto out;
+ }
+ } else if (caps & CGU_CLK_PLL) {
+ clk_init.ops = &ingenic_pll_ops;
+
+ caps &= ~CGU_CLK_PLL;
+
+ if (caps) {
+ pr_err("%s: PLL may not be combined with type 0x%x\n",
+ __func__, caps);
+ goto out;
+ }
+ } else {
+ clk_init.ops = &ingenic_clk_ops;
+ }
+
+ /* nothing to do for gates or fixed dividers */
+ caps &= ~(CGU_CLK_GATE | CGU_CLK_FIXDIV);
+
+ if (caps & CGU_CLK_MUX) {
+ if (!(caps & CGU_CLK_MUX_GLITCHFREE))
+ clk_init.flags |= CLK_SET_PARENT_GATE;
+
+ caps &= ~(CGU_CLK_MUX | CGU_CLK_MUX_GLITCHFREE);
+ }
+
+ if (caps & CGU_CLK_DIV) {
+ caps &= ~CGU_CLK_DIV;
+ } else {
+ /* pass rate changes to the parent clock */
+ clk_init.flags |= CLK_SET_RATE_PARENT;
+ }
+
+ if (caps) {
+ pr_err("%s: unknown clock type 0x%x\n", __func__, caps);
+ goto out;
+ }
+
+ clk = clk_register(NULL, &ingenic_clk->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock '%s'\n", __func__,
+ clk_info->name);
+ err = PTR_ERR(clk);
+ goto out;
+ }
+
+ err = clk_register_clkdev(clk, clk_info->name, NULL);
+ if (err)
+ goto out;
+
+ cgu->clocks.clks[idx] = clk;
+out:
+ if (err)
+ kfree(ingenic_clk);
+ return err;
+}
+
+struct ingenic_cgu *
+ingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info,
+ unsigned num_clocks, struct device_node *np)
+{
+ struct ingenic_cgu *cgu;
+
+ cgu = kzalloc(sizeof(*cgu), GFP_KERNEL);
+ if (!cgu)
+ goto err_out;
+
+ cgu->base = of_iomap(np, 0);
+ if (!cgu->base) {
+ pr_err("%s: failed to map CGU registers\n", __func__);
+ goto err_out_free;
+ }
+
+ cgu->np = np;
+ cgu->clock_info = clock_info;
+ cgu->clocks.clk_num = num_clocks;
+
+ spin_lock_init(&cgu->lock);
+
+ return cgu;
+
+err_out_free:
+ kfree(cgu);
+err_out:
+ return NULL;
+}
+
+int ingenic_cgu_register_clocks(struct ingenic_cgu *cgu)
+{
+ unsigned i;
+ int err;
+
+ cgu->clocks.clks = kcalloc(cgu->clocks.clk_num, sizeof(struct clk *),
+ GFP_KERNEL);
+ if (!cgu->clocks.clks) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ for (i = 0; i < cgu->clocks.clk_num; i++) {
+ err = ingenic_register_clock(cgu, i);
+ if (err)
+ goto err_out_unregister;
+ }
+
+ err = of_clk_add_provider(cgu->np, of_clk_src_onecell_get,
+ &cgu->clocks);
+ if (err)
+ goto err_out_unregister;
+
+ return 0;
+
+err_out_unregister:
+ for (i = 0; i < cgu->clocks.clk_num; i++) {
+ if (!cgu->clocks.clks[i])
+ continue;
+ if (cgu->clock_info[i].type & CGU_CLK_EXT)
+ clk_put(cgu->clocks.clks[i]);
+ else
+ clk_unregister(cgu->clocks.clks[i]);
+ }
+ kfree(cgu->clocks.clks);
+err_out:
+ return err;
+}
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
new file mode 100644
index 0000000..99347e2
--- /dev/null
+++ b/drivers/clk/ingenic/cgu.h
@@ -0,0 +1,223 @@
+/*
+ * Ingenic SoC CGU driver
+ *
+ * Copyright (c) 2013-2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRIVERS_CLK_INGENIC_CGU_H__
+#define __DRIVERS_CLK_INGENIC_CGU_H__
+
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+/**
+ * struct ingenic_cgu_pll_info - information about a PLL
+ * @reg: the offset of the PLL's control register within the CGU
+ * @m_shift: the number of bits to shift the multiplier value by (ie. the
+ * index of the lowest bit of the multiplier value in the PLL's
+ * control register)
+ * @m_bits: the size of the multiplier field in bits
+ * @m_offset: the multiplier value which encodes to 0 in the PLL's control
+ * register
+ * @n_shift: the number of bits to shift the divider value by (ie. the
+ * index of the lowest bit of the divider value in the PLL's
+ * control register)
+ * @n_bits: the size of the divider field in bits
+ * @n_offset: the divider value which encodes to 0 in the PLL's control
+ * register
+ * @od_shift: the number of bits to shift the post-VCO divider value by (ie.
+ * the index of the lowest bit of the post-VCO divider value in
+ * the PLL's control register)
+ * @od_bits: the size of the post-VCO divider field in bits
+ * @od_max: the maximum post-VCO divider value
+ * @od_encoding: a pointer to an array mapping post-VCO divider values to
+ * their encoded values in the PLL control register, or -1 for
+ * unsupported values
+ * @bypass_bit: the index of the bypass bit in the PLL control register
+ * @enable_bit: the index of the enable bit in the PLL control register
+ * @stable_bit: the index of the stable bit in the PLL control register
+ */
+struct ingenic_cgu_pll_info {
+ unsigned reg;
+ const s8 *od_encoding;
+ u8 m_shift, m_bits, m_offset;
+ u8 n_shift, n_bits, n_offset;
+ u8 od_shift, od_bits, od_max;
+ u8 bypass_bit;
+ u8 enable_bit;
+ u8 stable_bit;
+};
+
+/**
+ * struct ingenic_cgu_mux_info - information about a clock mux
+ * @reg: offset of the mux control register within the CGU
+ * @shift: number of bits to shift the mux value by (ie. the index of
+ * the lowest bit of the mux value within its control register)
+ * @bits: the size of the mux value in bits
+ */
+struct ingenic_cgu_mux_info {
+ unsigned reg;
+ u8 shift;
+ u8 bits;
+};
+
+/**
+ * struct ingenic_cgu_div_info - information about a divider
+ * @reg: offset of the divider control register within the CGU
+ * @shift: number of bits to shift the divide value by (ie. the index of
+ * the lowest bit of the divide value within its control register)
+ * @bits: the size of the divide value in bits
+ * @ce_bit: the index of the change enable bit within reg, or -1 if there
+ * isn't one
+ * @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
+ * @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
+ */
+struct ingenic_cgu_div_info {
+ unsigned reg;
+ u8 shift;
+ u8 bits;
+ s8 ce_bit;
+ s8 busy_bit;
+ s8 stop_bit;
+};
+
+/**
+ * struct ingenic_cgu_fixdiv_info - information about a fixed divider
+ * @div: the divider applied to the parent clock
+ */
+struct ingenic_cgu_fixdiv_info {
+ unsigned div;
+};
+
+/**
+ * struct ingenic_cgu_gate_info - information about a clock gate
+ * @reg: offset of the gate control register within the CGU
+ * @bit: offset of the bit in the register that controls the gate
+ */
+struct ingenic_cgu_gate_info {
+ unsigned reg;
+ u8 bit;
+};
+
+/**
+ * struct ingenic_cgu_custom_info - information about a custom (SoC) clock
+ * @clk_ops: custom clock operation callbacks
+ */
+struct ingenic_cgu_custom_info {
+ struct clk_ops *clk_ops;
+};
+
+/**
+ * struct ingenic_cgu_clk_info - information about a clock
+ * @name: name of the clock
+ * @type: a bitmask formed from CGU_CLK_* values
+ * @parents: an array of the indices of potential parents of this clock
+ * within the clock_info array of the CGU, or -1 in entries
+ * which correspond to no valid parent
+ * @pll: information valid if type includes CGU_CLK_PLL
+ * @gate: information valid if type includes CGU_CLK_GATE
+ * @mux: information valid if type includes CGU_CLK_MUX
+ * @div: information valid if type includes CGU_CLK_DIV
+ * @fixdiv: information valid if type includes CGU_CLK_FIXDIV
+ * @custom: information valid if type includes CGU_CLK_CUSTOM
+ */
+struct ingenic_cgu_clk_info {
+ const char *name;
+
+ enum {
+ CGU_CLK_NONE = 0,
+ CGU_CLK_EXT = BIT(0),
+ CGU_CLK_PLL = BIT(1),
+ CGU_CLK_GATE = BIT(2),
+ CGU_CLK_MUX = BIT(3),
+ CGU_CLK_MUX_GLITCHFREE = BIT(4),
+ CGU_CLK_DIV = BIT(5),
+ CGU_CLK_FIXDIV = BIT(6),
+ CGU_CLK_CUSTOM = BIT(7),
+ } type;
+
+ int parents[4];
+
+ union {
+ struct ingenic_cgu_pll_info pll;
+
+ struct {
+ struct ingenic_cgu_gate_info gate;
+ struct ingenic_cgu_mux_info mux;
+ struct ingenic_cgu_div_info div;
+ struct ingenic_cgu_fixdiv_info fixdiv;
+ };
+
+ struct ingenic_cgu_custom_info custom;
+ };
+};
+
+/**
+ * struct ingenic_cgu - data about the CGU
+ * @np: the device tree node that caused the CGU to be probed
+ * @base: the ioremap'ed base address of the CGU registers
+ * @clock_info: an array containing information about implemented clocks
+ * @clocks: used to provide clocks to DT, allows lookup of struct clk*
+ * @lock: lock to be held whilst manipulating CGU registers
+ */
+struct ingenic_cgu {
+ struct device_node *np;
+ void __iomem *base;
+
+ const struct ingenic_cgu_clk_info *clock_info;
+ struct clk_onecell_data clocks;
+
+ spinlock_t lock;
+};
+
+/**
+ * struct ingenic_clk - private data for a clock
+ * @hw: see Documentation/clk.txt
+ * @cgu: a pointer to the CGU data
+ * @idx: the index of this clock in cgu->clock_info
+ */
+struct ingenic_clk {
+ struct clk_hw hw;
+ struct ingenic_cgu *cgu;
+ unsigned idx;
+};
+
+#define to_ingenic_clk(_hw) container_of(_hw, struct ingenic_clk, hw)
+
+/**
+ * ingenic_cgu_new() - create a new CGU instance
+ * @clock_info: an array of clock information structures describing the clocks
+ * which are implemented by the CGU
+ * @num_clocks: the number of entries in clock_info
+ * @np: the device tree node which causes this CGU to be probed
+ *
+ * Return: a pointer to the CGU instance if initialisation is successful,
+ * otherwise NULL.
+ */
+struct ingenic_cgu *
+ingenic_cgu_new(const struct ingenic_cgu_clk_info *clock_info,
+ unsigned num_clocks, struct device_node *np);
+
+/**
+ * ingenic_cgu_register_clocks() - Registers the clocks
+ * @cgu: pointer to cgu data
+ *
+ * Register the clocks described by the CGU with the common clock framework.
+ *
+ * Return: 0 on success or -errno if unsuccesful.
+ */
+int ingenic_cgu_register_clocks(struct ingenic_cgu *cgu);
+
+#endif /* __DRIVERS_CLK_INGENIC_CGU_H__ */
--
2.4.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 26/37] MIPS,clk: migrate JZ4740 to common clock framework
2015-05-24 15:11 [PATCH v5 00/37] JZ4780 & CI20 support Paul Burton
2015-05-24 15:11 ` [PATCH v5 25/37] clk: ingenic: add driver for Ingenic SoC CGU clocks Paul Burton
@ 2015-05-24 15:11 ` Paul Burton
2015-05-24 15:11 ` [PATCH v5 27/37] MIPS,clk: move jz4740_clock_set_wait_mode to jz4740-cgu Paul Burton
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Paul Burton @ 2015-05-24 15:11 UTC (permalink / raw)
To: linux-mips
Cc: Paul Burton, Ian Campbell, Kumar Gala, Lars-Peter Clausen,
Mark Rutland, Mike Turquette, Pawel Moll, Ralf Baechle,
Rob Herring, Stephen Boyd, devicetree, linux-clk,
Fabian Frederick, Deng-Cheng Zhu, Linus Walleij, Stephen Warren,
linux-kernel, Brian Norris
Migrate the JZ4740 & the qi_lb60 board to use common clock framework
via the new Ingenic SoC CGU driver. Note that the JZ4740-specific
debugfs code is removed since common clock framework provides its own
debug capabilities.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Co-authored-by: Paul Cercueil <paul@crapouillou.net>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: devicetree@vger.kernel.org
Cc: linux-clk@vger.kernel.org
Cc: linux-mips@linux-mips.org
---
Changes in v5: None
Changes in v4:
- Return on ingenic_cgu_new failure.
- Mention debugfs changes in commit message.
- Initialise all unused clock parent fields to -1. Zero initialisation
works out so long as the common clock framework only ever attempts
to set a parent clock that was specified in the parent array (which
is OK), and so long as the hardware state is always valid according
to the clock description (which is hopefully OK). Initialising to -1
makes sense for resilience should the latter ever not be the case,
and to avoid that bit of implicit magic knowledge.
Changes in v3:
- Handle gating the "udc" clock.
Changes in v2: None
arch/mips/Kconfig | 2 +-
arch/mips/boot/dts/ingenic/jz4740.dtsi | 23 +
arch/mips/boot/dts/ingenic/qi_lb60.dts | 4 +
arch/mips/jz4740/Makefile | 2 -
arch/mips/jz4740/board-qi_lb60.c | 5 -
arch/mips/jz4740/clock-debugfs.c | 108 -----
arch/mips/jz4740/clock.c | 801 +--------------------------------
arch/mips/jz4740/clock.h | 53 +--
arch/mips/jz4740/time.c | 2 +
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/jz4740-cgu.c | 222 +++++++++
11 files changed, 255 insertions(+), 968 deletions(-)
delete mode 100644 arch/mips/jz4740/clock-debugfs.c
create mode 100644 drivers/clk/ingenic/jz4740-cgu.c
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 741e364..e3c859c 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -297,7 +297,7 @@ config MACH_INGENIC
select IRQ_CPU
select ARCH_REQUIRE_GPIOLIB
select SYS_HAS_EARLY_PRINTK
- select HAVE_CLK
+ select COMMON_CLK
select GENERIC_IRQ_CHIP
select BUILTIN_DTB
select USE_OF
diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi
index 3142e6c..9903ab2 100644
--- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
@@ -1,3 +1,5 @@
+#include <dt-bindings/clock/jz4740-cgu.h>
+
/ {
#address-cells = <1>;
#size-cells = <1>;
@@ -20,4 +22,25 @@
interrupt-parent = <&cpuintc>;
interrupts = <2>;
};
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+
+ rtc: rtc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ cgu: jz4740-cgu@10000000 {
+ compatible = "ingenic,jz4740-cgu";
+ reg = <0x10000000 0x100>;
+
+ clocks = <&ext>, <&rtc>;
+ clock-names = "ext", "rtc";
+
+ #clock-cells = <1>;
+ };
};
diff --git a/arch/mips/boot/dts/ingenic/qi_lb60.dts b/arch/mips/boot/dts/ingenic/qi_lb60.dts
index 0c0f639..106d13c 100644
--- a/arch/mips/boot/dts/ingenic/qi_lb60.dts
+++ b/arch/mips/boot/dts/ingenic/qi_lb60.dts
@@ -5,3 +5,7 @@
/ {
compatible = "qi,lb60", "ingenic,jz4740";
};
+
+&ext {
+ clock-frequency = <12000000>;
+};
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 6cf5dd4..fdb12efc 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -7,8 +7,6 @@
obj-y += prom.o time.o reset.o setup.o \
gpio.o clock.o platform.o timer.o serial.o
-obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
-
# board specific support
obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 9dd051e..21b034c 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -497,11 +497,6 @@ static int __init qi_lb60_init_platform_devices(void)
}
-struct jz4740_clock_board_data jz4740_clock_bdata = {
- .ext_rate = 12000000,
- .rtc_rate = 32768,
-};
-
static __init int board_avt2(char *str)
{
qi_lb60_mmc_pdata.card_detect_active_low = 1;
diff --git a/arch/mips/jz4740/clock-debugfs.c b/arch/mips/jz4740/clock-debugfs.c
deleted file mode 100644
index 325422d0..0000000
--- a/arch/mips/jz4740/clock-debugfs.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- * JZ4740 SoC clock support debugfs entries
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-
-#include <asm/mach-jz4740/clock.h>
-#include "clock.h"
-
-static struct dentry *jz4740_clock_debugfs;
-
-static int jz4740_clock_debugfs_show_enabled(void *data, uint64_t *value)
-{
- struct clk *clk = data;
- *value = clk_is_enabled(clk);
-
- return 0;
-}
-
-static int jz4740_clock_debugfs_set_enabled(void *data, uint64_t value)
-{
- struct clk *clk = data;
-
- if (value)
- return clk_enable(clk);
- else
- clk_disable(clk);
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_enabled,
- jz4740_clock_debugfs_show_enabled,
- jz4740_clock_debugfs_set_enabled,
- "%llu\n");
-
-static int jz4740_clock_debugfs_show_rate(void *data, uint64_t *value)
-{
- struct clk *clk = data;
- *value = clk_get_rate(clk);
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_rate,
- jz4740_clock_debugfs_show_rate,
- NULL,
- "%llu\n");
-
-void jz4740_clock_debugfs_add_clk(struct clk *clk)
-{
- if (!jz4740_clock_debugfs)
- return;
-
- clk->debugfs_entry = debugfs_create_dir(clk->name, jz4740_clock_debugfs);
- debugfs_create_file("rate", S_IWUGO | S_IRUGO, clk->debugfs_entry, clk,
- &jz4740_clock_debugfs_ops_rate);
- debugfs_create_file("enabled", S_IRUGO, clk->debugfs_entry, clk,
- &jz4740_clock_debugfs_ops_enabled);
-
- if (clk->parent) {
- char parent_path[100];
- snprintf(parent_path, 100, "../%s", clk->parent->name);
- clk->debugfs_parent_entry = debugfs_create_symlink("parent",
- clk->debugfs_entry,
- parent_path);
- }
-}
-
-/* TODO: Locking */
-void jz4740_clock_debugfs_update_parent(struct clk *clk)
-{
- debugfs_remove(clk->debugfs_parent_entry);
-
- if (clk->parent) {
- char parent_path[100];
- snprintf(parent_path, 100, "../%s", clk->parent->name);
- clk->debugfs_parent_entry = debugfs_create_symlink("parent",
- clk->debugfs_entry,
- parent_path);
- } else {
- clk->debugfs_parent_entry = NULL;
- }
-}
-
-void jz4740_clock_debugfs_init(void)
-{
- jz4740_clock_debugfs = debugfs_create_dir("jz4740-clock", NULL);
- if (IS_ERR(jz4740_clock_debugfs))
- jz4740_clock_debugfs = NULL;
-}
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
index c257073..dedee7c 100644
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -27,820 +28,44 @@
#include "clock.h"
-#define JZ_REG_CLOCK_CTRL 0x00
#define JZ_REG_CLOCK_LOW_POWER 0x04
#define JZ_REG_CLOCK_PLL 0x10
#define JZ_REG_CLOCK_GATE 0x20
-#define JZ_REG_CLOCK_SLEEP_CTRL 0x24
-#define JZ_REG_CLOCK_I2S 0x60
-#define JZ_REG_CLOCK_LCD 0x64
-#define JZ_REG_CLOCK_MMC 0x68
-#define JZ_REG_CLOCK_UHC 0x6C
-#define JZ_REG_CLOCK_SPI 0x74
-
-#define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31)
-#define JZ_CLOCK_CTRL_KO_ENABLE BIT(30)
-#define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29)
-#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000
-#define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22)
-#define JZ_CLOCK_CTRL_PLL_HALF BIT(21)
-#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000
-#define JZ_CLOCK_CTRL_UDIV_OFFSET 23
-#define JZ_CLOCK_CTRL_LDIV_OFFSET 16
-#define JZ_CLOCK_CTRL_MDIV_OFFSET 12
-#define JZ_CLOCK_CTRL_PDIV_OFFSET 8
-#define JZ_CLOCK_CTRL_HDIV_OFFSET 4
-#define JZ_CLOCK_CTRL_CDIV_OFFSET 0
#define JZ_CLOCK_GATE_UART0 BIT(0)
#define JZ_CLOCK_GATE_TCU BIT(1)
-#define JZ_CLOCK_GATE_RTC BIT(2)
-#define JZ_CLOCK_GATE_I2C BIT(3)
-#define JZ_CLOCK_GATE_SPI BIT(4)
-#define JZ_CLOCK_GATE_AIC BIT(5)
-#define JZ_CLOCK_GATE_I2S BIT(6)
-#define JZ_CLOCK_GATE_MMC BIT(7)
-#define JZ_CLOCK_GATE_ADC BIT(8)
-#define JZ_CLOCK_GATE_CIM BIT(9)
-#define JZ_CLOCK_GATE_LCD BIT(10)
#define JZ_CLOCK_GATE_UDC BIT(11)
#define JZ_CLOCK_GATE_DMAC BIT(12)
-#define JZ_CLOCK_GATE_IPU BIT(13)
-#define JZ_CLOCK_GATE_UHC BIT(14)
-#define JZ_CLOCK_GATE_UART1 BIT(15)
-
-#define JZ_CLOCK_I2S_DIV_MASK 0x01ff
-
-#define JZ_CLOCK_LCD_DIV_MASK 0x01ff
-
-#define JZ_CLOCK_MMC_DIV_MASK 0x001f
-#define JZ_CLOCK_UHC_DIV_MASK 0x000f
-
-#define JZ_CLOCK_SPI_SRC_PLL BIT(31)
-#define JZ_CLOCK_SPI_DIV_MASK 0x000f
-
-#define JZ_CLOCK_PLL_M_MASK 0x01ff
-#define JZ_CLOCK_PLL_N_MASK 0x001f
-#define JZ_CLOCK_PLL_OD_MASK 0x0003
#define JZ_CLOCK_PLL_STABLE BIT(10)
-#define JZ_CLOCK_PLL_BYPASS BIT(9)
#define JZ_CLOCK_PLL_ENABLED BIT(8)
-#define JZ_CLOCK_PLL_STABLIZE_MASK 0x000f
-#define JZ_CLOCK_PLL_M_OFFSET 23
-#define JZ_CLOCK_PLL_N_OFFSET 18
-#define JZ_CLOCK_PLL_OD_OFFSET 16
#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
-#define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7)
-#define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6)
-
static void __iomem *jz_clock_base;
-static spinlock_t jz_clock_lock;
-static LIST_HEAD(jz_clocks);
-
-struct main_clk {
- struct clk clk;
- uint32_t div_offset;
-};
-
-struct divided_clk {
- struct clk clk;
- uint32_t reg;
- uint32_t mask;
-};
-
-struct static_clk {
- struct clk clk;
- unsigned long rate;
-};
static uint32_t jz_clk_reg_read(int reg)
{
return readl(jz_clock_base + reg);
}
-static void jz_clk_reg_write_mask(int reg, uint32_t val, uint32_t mask)
-{
- uint32_t val2;
-
- spin_lock(&jz_clock_lock);
- val2 = readl(jz_clock_base + reg);
- val2 &= ~mask;
- val2 |= val;
- writel(val2, jz_clock_base + reg);
- spin_unlock(&jz_clock_lock);
-}
-
static void jz_clk_reg_set_bits(int reg, uint32_t mask)
{
uint32_t val;
- spin_lock(&jz_clock_lock);
val = readl(jz_clock_base + reg);
val |= mask;
writel(val, jz_clock_base + reg);
- spin_unlock(&jz_clock_lock);
}
static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
{
uint32_t val;
- spin_lock(&jz_clock_lock);
val = readl(jz_clock_base + reg);
val &= ~mask;
writel(val, jz_clock_base + reg);
- spin_unlock(&jz_clock_lock);
-}
-
-static int jz_clk_enable_gating(struct clk *clk)
-{
- if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
- return -EINVAL;
-
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
- return 0;
-}
-
-static int jz_clk_disable_gating(struct clk *clk)
-{
- if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
- return -EINVAL;
-
- jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
- return 0;
-}
-
-static int jz_clk_is_enabled_gating(struct clk *clk)
-{
- if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
- return 1;
-
- return !(jz_clk_reg_read(JZ_REG_CLOCK_GATE) & clk->gate_bit);
-}
-
-static unsigned long jz_clk_static_get_rate(struct clk *clk)
-{
- return ((struct static_clk *)clk)->rate;
-}
-
-static int jz_clk_ko_enable(struct clk *clk)
-{
- jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
- return 0;
-}
-
-static int jz_clk_ko_disable(struct clk *clk)
-{
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
- return 0;
-}
-
-static int jz_clk_ko_is_enabled(struct clk *clk)
-{
- return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE);
-}
-
-static const int pllno[] = {1, 2, 2, 4};
-
-static unsigned long jz_clk_pll_get_rate(struct clk *clk)
-{
- uint32_t val;
- int m;
- int n;
- int od;
-
- val = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
-
- if (val & JZ_CLOCK_PLL_BYPASS)
- return clk_get_rate(clk->parent);
-
- m = ((val >> 23) & 0x1ff) + 2;
- n = ((val >> 18) & 0x1f) + 2;
- od = (val >> 16) & 0x3;
-
- return ((clk_get_rate(clk->parent) / n) * m) / pllno[od];
-}
-
-static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
-{
- uint32_t reg;
-
- reg = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
- if (reg & JZ_CLOCK_CTRL_PLL_HALF)
- return jz_clk_pll_get_rate(clk->parent);
- return jz_clk_pll_get_rate(clk->parent) >> 1;
-}
-
-static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
-
-static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate)
-{
- unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
- int div;
-
- div = parent_rate / rate;
- if (div > 32)
- return parent_rate / 32;
- else if (div < 1)
- return parent_rate;
-
- div &= (0x3 << (ffs(div) - 1));
-
- return parent_rate / div;
-}
-
-static unsigned long jz_clk_main_get_rate(struct clk *clk)
-{
- struct main_clk *mclk = (struct main_clk *)clk;
- uint32_t div;
-
- div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
-
- div >>= mclk->div_offset;
- div &= 0xf;
-
- if (div >= ARRAY_SIZE(jz_clk_main_divs))
- div = ARRAY_SIZE(jz_clk_main_divs) - 1;
-
- return jz_clk_pll_get_rate(clk->parent) / jz_clk_main_divs[div];
-}
-
-static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate)
-{
- struct main_clk *mclk = (struct main_clk *)clk;
- int i;
- int div;
- unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
-
- rate = jz_clk_main_round_rate(clk, rate);
-
- div = parent_rate / rate;
-
- i = (ffs(div) - 1) << 1;
- if (i > 0 && !(div & BIT(i-1)))
- i -= 1;
-
- jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, i << mclk->div_offset,
- 0xf << mclk->div_offset);
-
- return 0;
-}
-
-static struct clk_ops jz_clk_static_ops = {
- .get_rate = jz_clk_static_get_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
-};
-
-static struct static_clk jz_clk_ext = {
- .clk = {
- .name = "ext",
- .gate_bit = JZ4740_CLK_NOT_GATED,
- .ops = &jz_clk_static_ops,
- },
-};
-
-static struct clk_ops jz_clk_pll_ops = {
- .get_rate = jz_clk_pll_get_rate,
-};
-
-static struct clk jz_clk_pll = {
- .name = "pll",
- .parent = &jz_clk_ext.clk,
- .ops = &jz_clk_pll_ops,
-};
-
-static struct clk_ops jz_clk_pll_half_ops = {
- .get_rate = jz_clk_pll_half_get_rate,
-};
-
-static struct clk jz_clk_pll_half = {
- .name = "pll half",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_pll_half_ops,
-};
-
-static const struct clk_ops jz_clk_main_ops = {
- .get_rate = jz_clk_main_get_rate,
- .set_rate = jz_clk_main_set_rate,
- .round_rate = jz_clk_main_round_rate,
-};
-
-static struct main_clk jz_clk_cpu = {
- .clk = {
- .name = "cclk",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_main_ops,
- },
- .div_offset = JZ_CLOCK_CTRL_CDIV_OFFSET,
-};
-
-static struct main_clk jz_clk_memory = {
- .clk = {
- .name = "mclk",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_main_ops,
- },
- .div_offset = JZ_CLOCK_CTRL_MDIV_OFFSET,
-};
-
-static struct main_clk jz_clk_high_speed_peripheral = {
- .clk = {
- .name = "hclk",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_main_ops,
- },
- .div_offset = JZ_CLOCK_CTRL_HDIV_OFFSET,
-};
-
-
-static struct main_clk jz_clk_low_speed_peripheral = {
- .clk = {
- .name = "pclk",
- .parent = &jz_clk_pll,
- .ops = &jz_clk_main_ops,
- },
- .div_offset = JZ_CLOCK_CTRL_PDIV_OFFSET,
-};
-
-static const struct clk_ops jz_clk_ko_ops = {
- .enable = jz_clk_ko_enable,
- .disable = jz_clk_ko_disable,
- .is_enabled = jz_clk_ko_is_enabled,
-};
-
-static struct clk jz_clk_ko = {
- .name = "cko",
- .parent = &jz_clk_memory.clk,
- .ops = &jz_clk_ko_ops,
-};
-
-static int jz_clk_spi_set_parent(struct clk *clk, struct clk *parent)
-{
- if (parent == &jz_clk_pll)
- jz_clk_reg_set_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
- else if (parent == &jz_clk_ext.clk)
- jz_clk_reg_clear_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
- else
- return -EINVAL;
-
- clk->parent = parent;
-
- return 0;
-}
-
-static int jz_clk_i2s_set_parent(struct clk *clk, struct clk *parent)
-{
- if (parent == &jz_clk_pll_half)
- jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
- else if (parent == &jz_clk_ext.clk)
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
- else
- return -EINVAL;
-
- clk->parent = parent;
-
- return 0;
-}
-
-static int jz_clk_udc_enable(struct clk *clk)
-{
- jz_clk_reg_set_bits(JZ_REG_CLOCK_SLEEP_CTRL,
- JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
-
- return 0;
-}
-
-static int jz_clk_udc_disable(struct clk *clk)
-{
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_SLEEP_CTRL,
- JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
-
- return 0;
-}
-
-static int jz_clk_udc_is_enabled(struct clk *clk)
-{
- return !!(jz_clk_reg_read(JZ_REG_CLOCK_SLEEP_CTRL) &
- JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
-}
-
-static int jz_clk_udc_set_parent(struct clk *clk, struct clk *parent)
-{
- if (parent == &jz_clk_pll_half)
- jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
- else if (parent == &jz_clk_ext.clk)
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
- else
- return -EINVAL;
-
- clk->parent = parent;
-
- return 0;
-}
-
-static int jz_clk_udc_set_rate(struct clk *clk, unsigned long rate)
-{
- int div;
-
- if (clk->parent == &jz_clk_ext.clk)
- return -EINVAL;
-
- div = clk_get_rate(clk->parent) / rate - 1;
-
- if (div < 0)
- div = 0;
- else if (div > 63)
- div = 63;
-
- jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_UDIV_OFFSET,
- JZ_CLOCK_CTRL_UDIV_MASK);
- return 0;
-}
-
-static unsigned long jz_clk_udc_get_rate(struct clk *clk)
-{
- int div;
-
- if (clk->parent == &jz_clk_ext.clk)
- return clk_get_rate(clk->parent);
-
- div = (jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_UDIV_MASK);
- div >>= JZ_CLOCK_CTRL_UDIV_OFFSET;
- div += 1;
-
- return clk_get_rate(clk->parent) / div;
-}
-
-static unsigned long jz_clk_divided_get_rate(struct clk *clk)
-{
- struct divided_clk *dclk = (struct divided_clk *)clk;
- int div;
-
- if (clk->parent == &jz_clk_ext.clk)
- return clk_get_rate(clk->parent);
-
- div = (jz_clk_reg_read(dclk->reg) & dclk->mask) + 1;
-
- return clk_get_rate(clk->parent) / div;
-}
-
-static int jz_clk_divided_set_rate(struct clk *clk, unsigned long rate)
-{
- struct divided_clk *dclk = (struct divided_clk *)clk;
- int div;
-
- if (clk->parent == &jz_clk_ext.clk)
- return -EINVAL;
-
- div = clk_get_rate(clk->parent) / rate - 1;
-
- if (div < 0)
- div = 0;
- else if (div > dclk->mask)
- div = dclk->mask;
-
- jz_clk_reg_write_mask(dclk->reg, div, dclk->mask);
-
- return 0;
-}
-
-static unsigned long jz_clk_ldclk_round_rate(struct clk *clk, unsigned long rate)
-{
- int div;
- unsigned long parent_rate = jz_clk_pll_half_get_rate(clk->parent);
-
- if (rate > 150000000)
- return 150000000;
-
- div = parent_rate / rate;
- if (div < 1)
- div = 1;
- else if (div > 32)
- div = 32;
-
- return parent_rate / div;
-}
-
-static int jz_clk_ldclk_set_rate(struct clk *clk, unsigned long rate)
-{
- int div;
-
- if (rate > 150000000)
- return -EINVAL;
-
- div = jz_clk_pll_half_get_rate(clk->parent) / rate - 1;
- if (div < 0)
- div = 0;
- else if (div > 31)
- div = 31;
-
- jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_LDIV_OFFSET,
- JZ_CLOCK_CTRL_LDIV_MASK);
-
- return 0;
-}
-
-static unsigned long jz_clk_ldclk_get_rate(struct clk *clk)
-{
- int div;
-
- div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_LDIV_MASK;
- div >>= JZ_CLOCK_CTRL_LDIV_OFFSET;
-
- return jz_clk_pll_half_get_rate(clk->parent) / (div + 1);
-}
-
-static const struct clk_ops jz_clk_ops_ld = {
- .set_rate = jz_clk_ldclk_set_rate,
- .get_rate = jz_clk_ldclk_get_rate,
- .round_rate = jz_clk_ldclk_round_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
-};
-
-static struct clk jz_clk_ld = {
- .name = "lcd",
- .gate_bit = JZ_CLOCK_GATE_LCD,
- .parent = &jz_clk_pll_half,
- .ops = &jz_clk_ops_ld,
-};
-
-static const struct clk_ops jz_clk_i2s_ops = {
- .set_rate = jz_clk_divided_set_rate,
- .get_rate = jz_clk_divided_get_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
- .set_parent = jz_clk_i2s_set_parent,
-};
-
-static const struct clk_ops jz_clk_spi_ops = {
- .set_rate = jz_clk_divided_set_rate,
- .get_rate = jz_clk_divided_get_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
- .set_parent = jz_clk_spi_set_parent,
-};
-
-static const struct clk_ops jz_clk_divided_ops = {
- .set_rate = jz_clk_divided_set_rate,
- .get_rate = jz_clk_divided_get_rate,
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
-};
-
-static struct divided_clk jz4740_clock_divided_clks[] = {
- [0] = {
- .clk = {
- .name = "i2s",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_I2S,
- .ops = &jz_clk_i2s_ops,
- },
- .reg = JZ_REG_CLOCK_I2S,
- .mask = JZ_CLOCK_I2S_DIV_MASK,
- },
- [1] = {
- .clk = {
- .name = "spi",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_SPI,
- .ops = &jz_clk_spi_ops,
- },
- .reg = JZ_REG_CLOCK_SPI,
- .mask = JZ_CLOCK_SPI_DIV_MASK,
- },
- [2] = {
- .clk = {
- .name = "lcd_pclk",
- .parent = &jz_clk_pll_half,
- .gate_bit = JZ4740_CLK_NOT_GATED,
- .ops = &jz_clk_divided_ops,
- },
- .reg = JZ_REG_CLOCK_LCD,
- .mask = JZ_CLOCK_LCD_DIV_MASK,
- },
- [3] = {
- .clk = {
- .name = "mmc",
- .parent = &jz_clk_pll_half,
- .gate_bit = JZ_CLOCK_GATE_MMC,
- .ops = &jz_clk_divided_ops,
- },
- .reg = JZ_REG_CLOCK_MMC,
- .mask = JZ_CLOCK_MMC_DIV_MASK,
- },
- [4] = {
- .clk = {
- .name = "uhc",
- .parent = &jz_clk_pll_half,
- .gate_bit = JZ_CLOCK_GATE_UHC,
- .ops = &jz_clk_divided_ops,
- },
- .reg = JZ_REG_CLOCK_UHC,
- .mask = JZ_CLOCK_UHC_DIV_MASK,
- },
-};
-
-static const struct clk_ops jz_clk_udc_ops = {
- .set_parent = jz_clk_udc_set_parent,
- .set_rate = jz_clk_udc_set_rate,
- .get_rate = jz_clk_udc_get_rate,
- .enable = jz_clk_udc_enable,
- .disable = jz_clk_udc_disable,
- .is_enabled = jz_clk_udc_is_enabled,
-};
-
-static const struct clk_ops jz_clk_simple_ops = {
- .enable = jz_clk_enable_gating,
- .disable = jz_clk_disable_gating,
- .is_enabled = jz_clk_is_enabled_gating,
-};
-
-static struct clk jz4740_clock_simple_clks[] = {
- [0] = {
- .name = "udc",
- .parent = &jz_clk_ext.clk,
- .ops = &jz_clk_udc_ops,
- },
- [1] = {
- .name = "uart0",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_UART0,
- .ops = &jz_clk_simple_ops,
- },
- [2] = {
- .name = "uart1",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_UART1,
- .ops = &jz_clk_simple_ops,
- },
- [3] = {
- .name = "dma",
- .parent = &jz_clk_high_speed_peripheral.clk,
- .gate_bit = JZ_CLOCK_GATE_DMAC,
- .ops = &jz_clk_simple_ops,
- },
- [4] = {
- .name = "ipu",
- .parent = &jz_clk_high_speed_peripheral.clk,
- .gate_bit = JZ_CLOCK_GATE_IPU,
- .ops = &jz_clk_simple_ops,
- },
- [5] = {
- .name = "adc",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_ADC,
- .ops = &jz_clk_simple_ops,
- },
- [6] = {
- .name = "i2c",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_I2C,
- .ops = &jz_clk_simple_ops,
- },
- [7] = {
- .name = "aic",
- .parent = &jz_clk_ext.clk,
- .gate_bit = JZ_CLOCK_GATE_AIC,
- .ops = &jz_clk_simple_ops,
- },
-};
-
-static struct static_clk jz_clk_rtc = {
- .clk = {
- .name = "rtc",
- .gate_bit = JZ_CLOCK_GATE_RTC,
- .ops = &jz_clk_static_ops,
- },
- .rate = 32768,
-};
-
-int clk_enable(struct clk *clk)
-{
- if (!clk->ops->enable)
- return -EINVAL;
-
- return clk->ops->enable(clk);
-}
-EXPORT_SYMBOL_GPL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
- if (clk->ops->disable)
- clk->ops->disable(clk);
-}
-EXPORT_SYMBOL_GPL(clk_disable);
-
-int clk_is_enabled(struct clk *clk)
-{
- if (clk->ops->is_enabled)
- return clk->ops->is_enabled(clk);
-
- return 1;
-}
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- if (clk->ops->get_rate)
- return clk->ops->get_rate(clk);
- if (clk->parent)
- return clk_get_rate(clk->parent);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(clk_get_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- if (!clk->ops->set_rate)
- return -EINVAL;
- return clk->ops->set_rate(clk, rate);
-}
-EXPORT_SYMBOL_GPL(clk_set_rate);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
- if (clk->ops->round_rate)
- return clk->ops->round_rate(clk, rate);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(clk_round_rate);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
- int ret;
- int enabled;
-
- if (!clk->ops->set_parent)
- return -EINVAL;
-
- enabled = clk_is_enabled(clk);
- if (enabled)
- clk_disable(clk);
- ret = clk->ops->set_parent(clk, parent);
- if (enabled)
- clk_enable(clk);
-
- jz4740_clock_debugfs_update_parent(clk);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(clk_set_parent);
-
-struct clk *clk_get(struct device *dev, const char *name)
-{
- struct clk *clk;
-
- list_for_each_entry(clk, &jz_clocks, list) {
- if (strcmp(clk->name, name) == 0)
- return clk;
- }
- return ERR_PTR(-ENXIO);
-}
-EXPORT_SYMBOL_GPL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL_GPL(clk_put);
-
-static inline void clk_add(struct clk *clk)
-{
- list_add_tail(&clk->list, &jz_clocks);
-
- jz4740_clock_debugfs_add_clk(clk);
-}
-
-static void clk_register_clks(void)
-{
- size_t i;
-
- clk_add(&jz_clk_ext.clk);
- clk_add(&jz_clk_pll);
- clk_add(&jz_clk_pll_half);
- clk_add(&jz_clk_cpu.clk);
- clk_add(&jz_clk_high_speed_peripheral.clk);
- clk_add(&jz_clk_low_speed_peripheral.clk);
- clk_add(&jz_clk_ko);
- clk_add(&jz_clk_ld);
- clk_add(&jz_clk_rtc.clk);
-
- for (i = 0; i < ARRAY_SIZE(jz4740_clock_divided_clks); ++i)
- clk_add(&jz4740_clock_divided_clks[i].clk);
-
- for (i = 0; i < ARRAY_SIZE(jz4740_clock_simple_clks); ++i)
- clk_add(&jz4740_clock_simple_clks[i]);
}
void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
@@ -891,33 +116,9 @@ void jz4740_clock_resume(void)
int jz4740_clock_init(void)
{
- uint32_t val;
-
jz_clock_base = ioremap(JZ4740_CPM_BASE_ADDR, 0x100);
if (!jz_clock_base)
return -EBUSY;
- spin_lock_init(&jz_clock_lock);
-
- jz_clk_ext.rate = jz4740_clock_bdata.ext_rate;
- jz_clk_rtc.rate = jz4740_clock_bdata.rtc_rate;
-
- val = jz_clk_reg_read(JZ_REG_CLOCK_SPI);
-
- if (val & JZ_CLOCK_SPI_SRC_PLL)
- jz4740_clock_divided_clks[1].clk.parent = &jz_clk_pll_half;
-
- val = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
-
- if (val & JZ_CLOCK_CTRL_I2S_SRC_PLL)
- jz4740_clock_divided_clks[0].clk.parent = &jz_clk_pll_half;
-
- if (val & JZ_CLOCK_CTRL_UDC_SRC_PLL)
- jz4740_clock_simple_clks[0].parent = &jz_clk_pll_half;
-
- jz4740_clock_debugfs_init();
-
- clk_register_clks();
-
return 0;
}
diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h
index 5d07499..86a3e01 100644
--- a/arch/mips/jz4740/clock.h
+++ b/arch/mips/jz4740/clock.h
@@ -16,61 +16,10 @@
#ifndef __MIPS_JZ4740_CLOCK_H__
#define __MIPS_JZ4740_CLOCK_H__
+#include <linux/clk.h>
#include <linux/list.h>
-struct jz4740_clock_board_data {
- unsigned long ext_rate;
- unsigned long rtc_rate;
-};
-
-extern struct jz4740_clock_board_data jz4740_clock_bdata;
-
void jz4740_clock_suspend(void);
void jz4740_clock_resume(void);
-struct clk;
-
-struct clk_ops {
- unsigned long (*get_rate)(struct clk *clk);
- unsigned long (*round_rate)(struct clk *clk, unsigned long rate);
- int (*set_rate)(struct clk *clk, unsigned long rate);
- int (*enable)(struct clk *clk);
- int (*disable)(struct clk *clk);
- int (*is_enabled)(struct clk *clk);
-
- int (*set_parent)(struct clk *clk, struct clk *parent);
-
-};
-
-struct clk {
- const char *name;
- struct clk *parent;
-
- uint32_t gate_bit;
-
- const struct clk_ops *ops;
-
- struct list_head list;
-
-#ifdef CONFIG_DEBUG_FS
- struct dentry *debugfs_entry;
- struct dentry *debugfs_parent_entry;
-#endif
-
-};
-
-#define JZ4740_CLK_NOT_GATED ((uint32_t)-1)
-
-int clk_is_enabled(struct clk *clk);
-
-#ifdef CONFIG_DEBUG_FS
-void jz4740_clock_debugfs_init(void);
-void jz4740_clock_debugfs_add_clk(struct clk *clk);
-void jz4740_clock_debugfs_update_parent(struct clk *clk);
-#else
-static inline void jz4740_clock_debugfs_init(void) {};
-static inline void jz4740_clock_debugfs_add_clk(struct clk *clk) {};
-static inline void jz4740_clock_debugfs_update_parent(struct clk *clk) {};
-#endif
-
#endif
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index f66f7f5..be9b0a3 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -14,6 +14,7 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/time.h>
@@ -118,6 +119,7 @@ void __init plat_time_init(void)
uint16_t ctrl;
struct clk *ext_clk;
+ of_clk_init(NULL);
jz4740_clock_init();
jz4740_timer_init();
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index 5ac2fd9..e6db7da 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1 +1,2 @@
obj-y += cgu.o
+obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
new file mode 100644
index 0000000..d5bb7a3
--- /dev/null
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -0,0 +1,222 @@
+/*
+ * Ingenic JZ4740 SoC CGU driver
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <dt-bindings/clock/jz4740-cgu.h>
+#include "cgu.h"
+
+/* CGU register offsets */
+#define CGU_REG_CPCCR 0x00
+#define CGU_REG_CPPCR 0x10
+#define CGU_REG_SCR 0x24
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LPCDR 0x64
+#define CGU_REG_MSCCDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+
+/* bits within a PLL control register */
+#define PLLCTL_M_SHIFT 23
+#define PLLCTL_M_MASK (0x1ff << PLLCTL_M_SHIFT)
+#define PLLCTL_N_SHIFT 18
+#define PLLCTL_N_MASK (0x1f << PLLCTL_N_SHIFT)
+#define PLLCTL_OD_SHIFT 16
+#define PLLCTL_OD_MASK (0x3 << PLLCTL_OD_SHIFT)
+#define PLLCTL_STABLE (1 << 10)
+#define PLLCTL_BYPASS (1 << 9)
+#define PLLCTL_ENABLE (1 << 8)
+
+static struct ingenic_cgu *cgu;
+
+static const s8 pll_od_encoding[4] = {
+ 0x0, 0x1, -1, 0x3,
+};
+
+static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT },
+
+ [JZ4740_CLK_PLL] = {
+ "pll", CGU_CLK_PLL,
+ .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
+ .pll = {
+ .reg = CGU_REG_CPPCR,
+ .m_shift = 23,
+ .m_bits = 9,
+ .m_offset = 2,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 2,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 4,
+ .od_encoding = pll_od_encoding,
+ .stable_bit = 10,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ },
+ },
+
+ /* Muxes & dividers */
+
+ [JZ4740_CLK_PLL_HALF] = {
+ "pll half", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 21, 1, -1, -1, -1 },
+ },
+
+ [JZ4740_CLK_CCLK] = {
+ "cclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 0, 4, 22, -1, -1 },
+ },
+
+ [JZ4740_CLK_HCLK] = {
+ "hclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 4, 4, 22, -1, -1 },
+ },
+
+ [JZ4740_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 8, 4, 22, -1, -1 },
+ },
+
+ [JZ4740_CLK_MCLK] = {
+ "mclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 12, 4, 22, -1, -1 },
+ },
+
+ [JZ4740_CLK_LCD] = {
+ "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 16, 5, 22, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 10 },
+ },
+
+ [JZ4740_CLK_LCD_PCLK] = {
+ "lcd_pclk", CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
+ .div = { CGU_REG_LPCDR, 0, 11, -1, -1, -1 },
+ },
+
+ [JZ4740_CLK_I2S] = {
+ "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
+ .mux = { CGU_REG_CPCCR, 31, 1 },
+ .div = { CGU_REG_I2SCDR, 0, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 6 },
+ },
+
+ [JZ4740_CLK_SPI] = {
+ "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 },
+ .mux = { CGU_REG_SSICDR, 31, 1 },
+ .div = { CGU_REG_SSICDR, 0, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 4 },
+ },
+
+ [JZ4740_CLK_MMC] = {
+ "mmc", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
+ .div = { CGU_REG_MSCCDR, 0, 5, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 7 },
+ },
+
+ [JZ4740_CLK_UHC] = {
+ "uhc", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
+ .div = { CGU_REG_UHCCDR, 0, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 14 },
+ },
+
+ [JZ4740_CLK_UDC] = {
+ "udc", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
+ .mux = { CGU_REG_CPCCR, 29, 1 },
+ .div = { CGU_REG_CPCCR, 23, 6, -1, -1, -1 },
+ .gate = { CGU_REG_SCR, 6 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4740_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 0 },
+ },
+
+ [JZ4740_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 15 },
+ },
+
+ [JZ4740_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 12 },
+ },
+
+ [JZ4740_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 13 },
+ },
+
+ [JZ4740_CLK_ADC] = {
+ "adc", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 8 },
+ },
+
+ [JZ4740_CLK_I2C] = {
+ "i2c", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 3 },
+ },
+
+ [JZ4740_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4740_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 5 },
+ },
+};
+
+static void __init jz4740_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4740_cgu_clocks,
+ ARRAY_SIZE(jz4740_cgu_clocks), np);
+ if (!cgu) {
+ pr_err("%s: failed to initialise CGU\n", __func__);
+ return;
+ }
+
+ retval = ingenic_cgu_register_clocks(cgu);
+ if (retval)
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+}
+CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
--
2.4.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 27/37] MIPS,clk: move jz4740_clock_set_wait_mode to jz4740-cgu
2015-05-24 15:11 [PATCH v5 00/37] JZ4780 & CI20 support Paul Burton
2015-05-24 15:11 ` [PATCH v5 25/37] clk: ingenic: add driver for Ingenic SoC CGU clocks Paul Burton
2015-05-24 15:11 ` [PATCH v5 26/37] MIPS,clk: migrate JZ4740 to common clock framework Paul Burton
@ 2015-05-24 15:11 ` Paul Burton
2015-05-24 15:11 ` [PATCH v5 28/37] MIPS, clk: move jz4740 UDC auto suspend functions " Paul Burton
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Paul Burton @ 2015-05-24 15:11 UTC (permalink / raw)
To: linux-mips
Cc: Paul Burton, Lars-Peter Clausen, Mike Turquette, Ralf Baechle,
Stephen Boyd, linux-clk, linux-kernel
The jz4740-cgu driver already has access to the CGU, so it makes sense
to move the few remaining accesses to the CGU from arch/mips/jz4740
there too. Move jz4740_clock_set_wait_mode for such consistency.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: linux-clk@vger.kernel.org
Cc: linux-mips@linux-mips.org
---
Changes in v5: None
Changes in v4: None
Changes in v3:
- Rebase.
Changes in v2: None
arch/mips/jz4740/clock.c | 16 ----------------
drivers/clk/ingenic/jz4740-cgu.c | 22 ++++++++++++++++++++++
2 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
index dedee7c..90b44d7 100644
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -28,7 +28,6 @@
#include "clock.h"
-#define JZ_REG_CLOCK_LOW_POWER 0x04
#define JZ_REG_CLOCK_PLL 0x10
#define JZ_REG_CLOCK_GATE 0x20
@@ -40,9 +39,6 @@
#define JZ_CLOCK_PLL_STABLE BIT(10)
#define JZ_CLOCK_PLL_ENABLED BIT(8)
-#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
-#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
-
static void __iomem *jz_clock_base;
static uint32_t jz_clk_reg_read(int reg)
@@ -68,18 +64,6 @@ static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
writel(val, jz_clock_base + reg);
}
-void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
-{
- switch (mode) {
- case JZ4740_WAIT_MODE_IDLE:
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
- break;
- case JZ4740_WAIT_MODE_SLEEP:
- jz_clk_reg_set_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
- break;
- }
-}
-
void jz4740_clock_udc_disable_auto_suspend(void)
{
jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
index d5bb7a3..0209ed6 100644
--- a/drivers/clk/ingenic/jz4740-cgu.c
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -19,10 +19,12 @@
#include <linux/delay.h>
#include <linux/of.h>
#include <dt-bindings/clock/jz4740-cgu.h>
+#include <asm/mach-jz4740/clock.h>
#include "cgu.h"
/* CGU register offsets */
#define CGU_REG_CPCCR 0x00
+#define CGU_REG_LCR 0x04
#define CGU_REG_CPPCR 0x10
#define CGU_REG_SCR 0x24
#define CGU_REG_I2SCDR 0x60
@@ -42,6 +44,9 @@
#define PLLCTL_BYPASS (1 << 9)
#define PLLCTL_ENABLE (1 << 8)
+/* bits within the LCR register */
+#define LCR_SLEEP (1 << 0)
+
static struct ingenic_cgu *cgu;
static const s8 pll_od_encoding[4] = {
@@ -220,3 +225,20 @@ static void __init jz4740_cgu_init(struct device_node *np)
pr_err("%s: failed to register CGU Clocks\n", __func__);
}
CLK_OF_DECLARE(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
+
+void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
+{
+ uint32_t lcr = readl(cgu->base + CGU_REG_LCR);
+
+ switch (mode) {
+ case JZ4740_WAIT_MODE_IDLE:
+ lcr &= ~LCR_SLEEP;
+ break;
+
+ case JZ4740_WAIT_MODE_SLEEP:
+ lcr |= LCR_SLEEP;
+ break;
+ }
+
+ writel(lcr, cgu->base + CGU_REG_LCR);
+}
--
2.4.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 28/37] MIPS, clk: move jz4740 UDC auto suspend functions to jz4740-cgu
2015-05-24 15:11 [PATCH v5 00/37] JZ4780 & CI20 support Paul Burton
` (2 preceding siblings ...)
2015-05-24 15:11 ` [PATCH v5 27/37] MIPS,clk: move jz4740_clock_set_wait_mode to jz4740-cgu Paul Burton
@ 2015-05-24 15:11 ` Paul Burton
2015-05-24 15:11 ` [PATCH v5 29/37] MIPS, clk: move jz4740 clock suspend, resume " Paul Burton
2015-05-24 15:11 ` [PATCH v5 30/37] clk: ingenic: add JZ4780 CGU support Paul Burton
5 siblings, 0 replies; 8+ messages in thread
From: Paul Burton @ 2015-05-24 15:11 UTC (permalink / raw)
To: linux-mips
Cc: Paul Burton, Lars-Peter Clausen, Mike Turquette, Ralf Baechle,
Stephen Boyd, linux-clk, linux-kernel
The jz4740-cgu driver already has access to the CGU, so it makes sense
to move the few remaining accesses to the CGU from arch/mips/jz4740
there too. Move the jz4740_clock_udc_{dis,en}able_auto_suspend functions
there for such consistency.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: linux-clk@vger.kernel.org
Cc: linux-mips@linux-mips.org
---
Changes in v5: None
Changes in v4: None
Changes in v3:
- Rebase.
Changes in v2: None
arch/mips/jz4740/clock.c | 13 -------------
drivers/clk/ingenic/jz4740-cgu.c | 22 ++++++++++++++++++++++
2 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
index 90b44d7..2a10829 100644
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -33,7 +33,6 @@
#define JZ_CLOCK_GATE_UART0 BIT(0)
#define JZ_CLOCK_GATE_TCU BIT(1)
-#define JZ_CLOCK_GATE_UDC BIT(11)
#define JZ_CLOCK_GATE_DMAC BIT(12)
#define JZ_CLOCK_PLL_STABLE BIT(10)
@@ -64,18 +63,6 @@ static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
writel(val, jz_clock_base + reg);
}
-void jz4740_clock_udc_disable_auto_suspend(void)
-{
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
-
-void jz4740_clock_udc_enable_auto_suspend(void)
-{
- jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
-}
-EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
-
void jz4740_clock_suspend(void)
{
jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE,
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
index 0209ed6..0e692ed 100644
--- a/drivers/clk/ingenic/jz4740-cgu.c
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -26,6 +26,7 @@
#define CGU_REG_CPCCR 0x00
#define CGU_REG_LCR 0x04
#define CGU_REG_CPPCR 0x10
+#define CGU_REG_CLKGR 0x20
#define CGU_REG_SCR 0x24
#define CGU_REG_I2SCDR 0x60
#define CGU_REG_LPCDR 0x64
@@ -47,6 +48,9 @@
/* bits within the LCR register */
#define LCR_SLEEP (1 << 0)
+/* bits within the CLKGR register */
+#define CLKGR_UDC (1 << 11)
+
static struct ingenic_cgu *cgu;
static const s8 pll_od_encoding[4] = {
@@ -242,3 +246,21 @@ void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
writel(lcr, cgu->base + CGU_REG_LCR);
}
+
+void jz4740_clock_udc_disable_auto_suspend(void)
+{
+ uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
+
+ clkgr &= ~CLKGR_UDC;
+ writel(clkgr, cgu->base + CGU_REG_CLKGR);
+}
+EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
+
+void jz4740_clock_udc_enable_auto_suspend(void)
+{
+ uint32_t clkgr = readl(cgu->base + CGU_REG_CLKGR);
+
+ clkgr |= CLKGR_UDC;
+ writel(clkgr, cgu->base + CGU_REG_CLKGR);
+}
+EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
--
2.4.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 29/37] MIPS, clk: move jz4740 clock suspend, resume functions to jz4740-cgu
2015-05-24 15:11 [PATCH v5 00/37] JZ4780 & CI20 support Paul Burton
` (3 preceding siblings ...)
2015-05-24 15:11 ` [PATCH v5 28/37] MIPS, clk: move jz4740 UDC auto suspend functions " Paul Burton
@ 2015-05-24 15:11 ` Paul Burton
2015-05-24 15:11 ` [PATCH v5 30/37] clk: ingenic: add JZ4780 CGU support Paul Burton
5 siblings, 0 replies; 8+ messages in thread
From: Paul Burton @ 2015-05-24 15:11 UTC (permalink / raw)
To: linux-mips
Cc: Paul Burton, Lars-Peter Clausen, Mike Turquette, Ralf Baechle,
Stephen Boyd, linux-clk, Deng-Cheng Zhu, linux-kernel
The jz4740-cgu driver already has access to the CGU, so it makes sense
to move the few remaining accesses to the CGU from arch/mips/jz4740
there too. Move the jz4740_clock_{suspend,resume} functions there for
such consistency. The arch/mips/jz4740/clock.c file now contains nothing
more of use & so is removed.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: linux-clk@vger.kernel.org
Cc: linux-mips@linux-mips.org
---
Changes in v5: None
Changes in v4: None
Changes in v3:
- Rebase.
Changes in v2: None
arch/mips/include/asm/mach-jz4740/clock.h | 2 -
arch/mips/jz4740/Makefile | 2 +-
arch/mips/jz4740/clock.c | 95 -------------------------------
arch/mips/jz4740/time.c | 1 -
drivers/clk/ingenic/jz4740-cgu.c | 37 ++++++++++++
5 files changed, 38 insertions(+), 99 deletions(-)
delete mode 100644 arch/mips/jz4740/clock.c
diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h
index 01d8468..16659cd 100644
--- a/arch/mips/include/asm/mach-jz4740/clock.h
+++ b/arch/mips/include/asm/mach-jz4740/clock.h
@@ -20,8 +20,6 @@ enum jz4740_wait_mode {
JZ4740_WAIT_MODE_SLEEP,
};
-int jz4740_clock_init(void);
-
void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode);
void jz4740_clock_udc_enable_auto_suspend(void);
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index fdb12efc..7636432 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -5,7 +5,7 @@
# Object file lists.
obj-y += prom.o time.o reset.o setup.o \
- gpio.o clock.o platform.o timer.o serial.o
+ gpio.o platform.o timer.o serial.o
# board specific support
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
deleted file mode 100644
index 2a10829..0000000
--- a/arch/mips/jz4740/clock.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- * JZ4740 SoC clock support
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/err.h>
-
-#include <asm/mach-jz4740/clock.h>
-#include <asm/mach-jz4740/base.h>
-
-#include "clock.h"
-
-#define JZ_REG_CLOCK_PLL 0x10
-#define JZ_REG_CLOCK_GATE 0x20
-
-#define JZ_CLOCK_GATE_UART0 BIT(0)
-#define JZ_CLOCK_GATE_TCU BIT(1)
-#define JZ_CLOCK_GATE_DMAC BIT(12)
-
-#define JZ_CLOCK_PLL_STABLE BIT(10)
-#define JZ_CLOCK_PLL_ENABLED BIT(8)
-
-static void __iomem *jz_clock_base;
-
-static uint32_t jz_clk_reg_read(int reg)
-{
- return readl(jz_clock_base + reg);
-}
-
-static void jz_clk_reg_set_bits(int reg, uint32_t mask)
-{
- uint32_t val;
-
- val = readl(jz_clock_base + reg);
- val |= mask;
- writel(val, jz_clock_base + reg);
-}
-
-static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
-{
- uint32_t val;
-
- val = readl(jz_clock_base + reg);
- val &= ~mask;
- writel(val, jz_clock_base + reg);
-}
-
-void jz4740_clock_suspend(void)
-{
- jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE,
- JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
-
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
-}
-
-void jz4740_clock_resume(void)
-{
- uint32_t pll;
-
- jz_clk_reg_set_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
-
- do {
- pll = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
- } while (!(pll & JZ_CLOCK_PLL_STABLE));
-
- jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE,
- JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
-}
-
-int jz4740_clock_init(void)
-{
- jz_clock_base = ioremap(JZ4740_CPM_BASE_ADDR, 0x100);
- if (!jz_clock_base)
- return -EBUSY;
-
- return 0;
-}
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index be9b0a3..9172553 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -120,7 +120,6 @@ void __init plat_time_init(void)
struct clk *ext_clk;
of_clk_init(NULL);
- jz4740_clock_init();
jz4740_timer_init();
ext_clk = clk_get(NULL, "ext");
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
index 0e692ed..305a26c2 100644
--- a/drivers/clk/ingenic/jz4740-cgu.c
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -264,3 +264,40 @@ void jz4740_clock_udc_enable_auto_suspend(void)
writel(clkgr, cgu->base + CGU_REG_CLKGR);
}
EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
+
+#define JZ_CLOCK_GATE_UART0 BIT(0)
+#define JZ_CLOCK_GATE_TCU BIT(1)
+#define JZ_CLOCK_GATE_DMAC BIT(12)
+
+void jz4740_clock_suspend(void)
+{
+ uint32_t clkgr, cppcr;
+
+ clkgr = readl(cgu->base + CGU_REG_CLKGR);
+ clkgr |= JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0;
+ writel(clkgr, cgu->base + CGU_REG_CLKGR);
+
+ cppcr = readl(cgu->base + CGU_REG_CPPCR);
+ cppcr &= ~BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
+ writel(cppcr, cgu->base + CGU_REG_CPPCR);
+}
+
+void jz4740_clock_resume(void)
+{
+ uint32_t clkgr, cppcr, stable;
+
+ cppcr = readl(cgu->base + CGU_REG_CPPCR);
+ cppcr |= BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.enable_bit);
+ writel(cppcr, cgu->base + CGU_REG_CPPCR);
+
+ stable = BIT(jz4740_cgu_clocks[JZ4740_CLK_PLL].pll.stable_bit);
+ do {
+ cppcr = readl(cgu->base + CGU_REG_CPPCR);
+ } while (!(cppcr & stable));
+
+ clkgr = readl(cgu->base + CGU_REG_CLKGR);
+ clkgr &= ~JZ_CLOCK_GATE_TCU;
+ clkgr &= ~JZ_CLOCK_GATE_DMAC;
+ clkgr &= ~JZ_CLOCK_GATE_UART0;
+ writel(clkgr, cgu->base + CGU_REG_CLKGR);
+}
--
2.4.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 30/37] clk: ingenic: add JZ4780 CGU support
2015-05-24 15:11 [PATCH v5 00/37] JZ4780 & CI20 support Paul Burton
` (4 preceding siblings ...)
2015-05-24 15:11 ` [PATCH v5 29/37] MIPS, clk: move jz4740 clock suspend, resume " Paul Burton
@ 2015-05-24 15:11 ` Paul Burton
2015-06-03 23:32 ` Michael Turquette
5 siblings, 1 reply; 8+ messages in thread
From: Paul Burton @ 2015-05-24 15:11 UTC (permalink / raw)
To: linux-mips
Cc: Paul Burton, Lars-Peter Clausen, Mike Turquette, Ralf Baechle,
Stephen Boyd, linux-clk, linux-kernel
Add support for the clocks provided by the CGU in the Ingenic JZ4780
SoC, making use of the SoC-agnostic CGU code to do the heavy lifting.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Co-authored-by: Paul Cercueil <paul@crapouillou.net>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: linux-clk@vger.kernel.org
Cc: linux-mips@linux-mips.org
---
Changes in v5:
- Declare jz4780_otg_phy_ops static.
- Drop setting the parent of the UHC clock during probe - USB isn't
supported as of this patchset anyway, so it can be dealt with in
whatever's deemed the best way later.
Changes in v4:
- Return on ingenic_cgu_new or ingenic_cgu_register_clocks failure.
- Initialise all unused clock parent fields to -1. Zero initialisation
works out so long as the common clock framework only ever attempts
to set a parent clock that was specified in the parent array (which
is OK), and so long as the hardware state is always valid according
to the clock description (which is hopefully OK). Initialising to -1
makes sense for resilience should the latter ever not be the case,
and to avoid that bit of implicit magic knowledge.
Changes in v3:
- Rebase.
Changes in v2:
- Remove FSF address per checkpatch (ZubairLK).
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/jz4780-cgu.c | 733 +++++++++++++++++++++++++++++++++++++++
2 files changed, 734 insertions(+)
create mode 100644 drivers/clk/ingenic/jz4780-cgu.c
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index e6db7da..cd47b06 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,2 +1,3 @@
obj-y += cgu.o
obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
+obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c
new file mode 100644
index 0000000..431f962
--- /dev/null
+++ b/drivers/clk/ingenic/jz4780-cgu.c
@@ -0,0 +1,733 @@
+/*
+ * Ingenic JZ4780 SoC CGU driver
+ *
+ * Copyright (c) 2013-2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <dt-bindings/clock/jz4780-cgu.h>
+#include "cgu.h"
+
+/* CGU register offsets */
+#define CGU_REG_CLOCKCONTROL 0x00
+#define CGU_REG_PLLCONTROL 0x0c
+#define CGU_REG_APLL 0x10
+#define CGU_REG_MPLL 0x14
+#define CGU_REG_EPLL 0x18
+#define CGU_REG_VPLL 0x1c
+#define CGU_REG_CLKGR0 0x20
+#define CGU_REG_OPCR 0x24
+#define CGU_REG_CLKGR1 0x28
+#define CGU_REG_DDRCDR 0x2c
+#define CGU_REG_VPUCDR 0x30
+#define CGU_REG_USBPCR 0x3c
+#define CGU_REG_USBRDT 0x40
+#define CGU_REG_USBVBFIL 0x44
+#define CGU_REG_USBPCR1 0x48
+#define CGU_REG_LP0CDR 0x54
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LP1CDR 0x64
+#define CGU_REG_MSC0CDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+#define CGU_REG_CIMCDR 0x7c
+#define CGU_REG_PCMCDR 0x84
+#define CGU_REG_GPUCDR 0x88
+#define CGU_REG_HDMICDR 0x8c
+#define CGU_REG_MSC1CDR 0xa4
+#define CGU_REG_MSC2CDR 0xa8
+#define CGU_REG_BCHCDR 0xac
+#define CGU_REG_CLOCKSTATUS 0xd4
+
+/* bits within the OPCR register */
+#define OPCR_SPENDN0 (1 << 7)
+#define OPCR_SPENDN1 (1 << 6)
+
+/* bits within the USBPCR register */
+#define USBPCR_USB_MODE BIT(31)
+#define USBPCR_IDPULLUP_MASK (0x3 << 28)
+#define USBPCR_COMMONONN BIT(25)
+#define USBPCR_VBUSVLDEXT BIT(24)
+#define USBPCR_VBUSVLDEXTSEL BIT(23)
+#define USBPCR_POR BIT(22)
+#define USBPCR_OTG_DISABLE BIT(20)
+#define USBPCR_COMPDISTUNE_MASK (0x7 << 17)
+#define USBPCR_OTGTUNE_MASK (0x7 << 14)
+#define USBPCR_SQRXTUNE_MASK (0x7 << 11)
+#define USBPCR_TXFSLSTUNE_MASK (0xf << 7)
+#define USBPCR_TXPREEMPHTUNE BIT(6)
+#define USBPCR_TXHSXVTUNE_MASK (0x3 << 4)
+#define USBPCR_TXVREFTUNE_MASK 0xf
+
+/* bits within the USBPCR1 register */
+#define USBPCR1_REFCLKSEL_SHIFT 26
+#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
+#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
+#define USBPCR1_REFCLKDIV_SHIFT 24
+#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_19_2 (0x3 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
+#define USBPCR1_USB_SEL BIT(28)
+#define USBPCR1_WORD_IF0 BIT(19)
+#define USBPCR1_WORD_IF1 BIT(18)
+
+/* bits within the USBRDT register */
+#define USBRDT_VBFIL_LD_EN BIT(25)
+#define USBRDT_USBRDT_MASK 0x7fffff
+
+/* bits within the USBVBFIL register */
+#define USBVBFIL_IDDIGFIL_SHIFT 16
+#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT)
+#define USBVBFIL_USBVBFIL_MASK (0xffff)
+
+static struct ingenic_cgu *cgu;
+
+static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
+{
+ /* we only use CLKCORE, revisit if that ever changes */
+ return 0;
+}
+
+static int jz4780_otg_phy_set_parent(struct clk_hw *hw, u8 idx)
+{
+ unsigned long flags;
+ u32 usbpcr1;
+
+ if (idx > 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cgu->lock, flags);
+
+ usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+ usbpcr1 &= ~USBPCR1_REFCLKSEL_MASK;
+ /* we only use CLKCORE */
+ usbpcr1 |= USBPCR1_REFCLKSEL_CORE;
+ writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
+
+ spin_unlock_irqrestore(&cgu->lock, flags);
+ return 0;
+}
+
+static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ u32 usbpcr1;
+ unsigned refclk_div;
+
+ usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+ refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
+
+ switch (refclk_div) {
+ case USBPCR1_REFCLKDIV_12:
+ return 12000000;
+
+ case USBPCR1_REFCLKDIV_24:
+ return 24000000;
+
+ case USBPCR1_REFCLKDIV_48:
+ return 48000000;
+
+ case USBPCR1_REFCLKDIV_19_2:
+ return 19200000;
+ }
+
+ BUG();
+ return parent_rate;
+}
+
+static long jz4780_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *parent_rate)
+{
+ if (req_rate < 15600000)
+ return 12000000;
+
+ if (req_rate < 21600000)
+ return 19200000;
+
+ if (req_rate < 36000000)
+ return 24000000;
+
+ return 48000000;
+}
+
+static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long parent_rate)
+{
+ unsigned long flags;
+ u32 usbpcr1, div_bits;
+
+ switch (req_rate) {
+ case 12000000:
+ div_bits = USBPCR1_REFCLKDIV_12;
+ break;
+
+ case 19200000:
+ div_bits = USBPCR1_REFCLKDIV_19_2;
+ break;
+
+ case 24000000:
+ div_bits = USBPCR1_REFCLKDIV_24;
+ break;
+
+ case 48000000:
+ div_bits = USBPCR1_REFCLKDIV_48;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&cgu->lock, flags);
+
+ usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
+ usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
+ usbpcr1 |= div_bits;
+ writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
+
+ spin_unlock_irqrestore(&cgu->lock, flags);
+ return 0;
+}
+
+static struct clk_ops jz4780_otg_phy_ops = {
+ .get_parent = jz4780_otg_phy_get_parent,
+ .set_parent = jz4780_otg_phy_set_parent,
+
+ .recalc_rate = jz4780_otg_phy_recalc_rate,
+ .round_rate = jz4780_otg_phy_round_rate,
+ .set_rate = jz4780_otg_phy_set_rate,
+};
+
+static const s8 pll_od_encoding[16] = {
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+};
+
+static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4780_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
+ [JZ4780_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
+
+ /* PLLs */
+
+#define DEF_PLL(name) { \
+ .reg = CGU_REG_ ## name, \
+ .m_shift = 19, \
+ .m_bits = 13, \
+ .m_offset = 1, \
+ .n_shift = 13, \
+ .n_bits = 6, \
+ .n_offset = 1, \
+ .od_shift = 9, \
+ .od_bits = 4, \
+ .od_max = 16, \
+ .od_encoding = pll_od_encoding, \
+ .stable_bit = 6, \
+ .bypass_bit = 1, \
+ .enable_bit = 0, \
+}
+
+ [JZ4780_CLK_APLL] = {
+ "apll", CGU_CLK_PLL,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .pll = DEF_PLL(APLL),
+ },
+
+ [JZ4780_CLK_MPLL] = {
+ "mpll", CGU_CLK_PLL,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .pll = DEF_PLL(MPLL),
+ },
+
+ [JZ4780_CLK_EPLL] = {
+ "epll", CGU_CLK_PLL,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .pll = DEF_PLL(EPLL),
+ },
+
+ [JZ4780_CLK_VPLL] = {
+ "vpll", CGU_CLK_PLL,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .pll = DEF_PLL(VPLL),
+ },
+
+#undef DEF_PLL
+
+ /* Custom (SoC-specific) OTG PHY */
+
+ [JZ4780_CLK_OTGPHY] = {
+ "otg_phy", CGU_CLK_CUSTOM,
+ .parents = { -1, -1, JZ4780_CLK_EXCLK, -1 },
+ .custom = { &jz4780_otg_phy_ops },
+ },
+
+ /* Muxes & dividers */
+
+ [JZ4780_CLK_SCLKA] = {
+ "sclk_a", CGU_CLK_MUX,
+ .parents = { -1, JZ4780_CLK_APLL, JZ4780_CLK_EXCLK,
+ JZ4780_CLK_RTCLK },
+ .mux = { CGU_REG_CLOCKCONTROL, 30, 2 },
+ },
+
+ [JZ4780_CLK_CPUMUX] = {
+ "cpumux", CGU_CLK_MUX,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL },
+ .mux = { CGU_REG_CLOCKCONTROL, 28, 2 },
+ },
+
+ [JZ4780_CLK_CPU] = {
+ "cpu", CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 },
+ .div = { CGU_REG_CLOCKCONTROL, 0, 4, 22, -1, -1 },
+ },
+
+ [JZ4780_CLK_L2CACHE] = {
+ "l2cache", CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_CPUMUX, -1, -1, -1 },
+ .div = { CGU_REG_CLOCKCONTROL, 4, 4, -1, -1, -1 },
+ },
+
+ [JZ4780_CLK_AHB0] = {
+ "ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL },
+ .mux = { CGU_REG_CLOCKCONTROL, 26, 2 },
+ .div = { CGU_REG_CLOCKCONTROL, 8, 4, 21, -1, -1 },
+ },
+
+ [JZ4780_CLK_AHB2PMUX] = {
+ "ahb2_apb_mux", CGU_CLK_MUX,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_RTCLK },
+ .mux = { CGU_REG_CLOCKCONTROL, 24, 2 },
+ },
+
+ [JZ4780_CLK_AHB2] = {
+ "ahb2", CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 },
+ .div = { CGU_REG_CLOCKCONTROL, 12, 4, 20, -1, -1 },
+ },
+
+ [JZ4780_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_AHB2PMUX, -1, -1, -1 },
+ .div = { CGU_REG_CLOCKCONTROL, 16, 4, 20, -1, -1 },
+ },
+
+ [JZ4780_CLK_DDR] = {
+ "ddr", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
+ .mux = { CGU_REG_DDRCDR, 30, 2 },
+ .div = { CGU_REG_DDRCDR, 0, 4, 29, 28, 27 },
+ },
+
+ [JZ4780_CLK_VPU] = {
+ "vpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL, -1 },
+ .mux = { CGU_REG_VPUCDR, 30, 2 },
+ .div = { CGU_REG_VPUCDR, 0, 4, 29, 28, 27 },
+ .gate = { CGU_REG_CLKGR1, 2 },
+ },
+
+ [JZ4780_CLK_I2SPLL] = {
+ "i2s_pll", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_EPLL, -1, -1 },
+ .mux = { CGU_REG_I2SCDR, 30, 1 },
+ .div = { CGU_REG_I2SCDR, 0, 8, 29, 28, 27 },
+ },
+
+ [JZ4780_CLK_I2S] = {
+ "i2s", CGU_CLK_MUX,
+ .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_I2SPLL, -1, -1 },
+ .mux = { CGU_REG_I2SCDR, 31, 1 },
+ },
+
+ [JZ4780_CLK_LCD0PIXCLK] = {
+ "lcd0pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_VPLL, -1 },
+ .mux = { CGU_REG_LP0CDR, 30, 2 },
+ .div = { CGU_REG_LP0CDR, 0, 8, 28, 27, 26 },
+ },
+
+ [JZ4780_CLK_LCD1PIXCLK] = {
+ "lcd1pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_VPLL, -1 },
+ .mux = { CGU_REG_LP1CDR, 30, 2 },
+ .div = { CGU_REG_LP1CDR, 0, 8, 28, 27, 26 },
+ },
+
+ [JZ4780_CLK_MSCMUX] = {
+ "msc_mux", CGU_CLK_MUX,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 },
+ .mux = { CGU_REG_MSC0CDR, 30, 2 },
+ },
+
+ [JZ4780_CLK_MSC0] = {
+ "msc0", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
+ .div = { CGU_REG_MSC0CDR, 0, 8, 29, 28, 27 },
+ .gate = { CGU_REG_CLKGR0, 3 },
+ },
+
+ [JZ4780_CLK_MSC1] = {
+ "msc1", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
+ .div = { CGU_REG_MSC1CDR, 0, 8, 29, 28, 27 },
+ .gate = { CGU_REG_CLKGR0, 11 },
+ },
+
+ [JZ4780_CLK_MSC2] = {
+ "msc2", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_MSCMUX, -1, -1, -1 },
+ .div = { CGU_REG_MSC2CDR, 0, 8, 29, 28, 27 },
+ .gate = { CGU_REG_CLKGR0, 12 },
+ },
+
+ [JZ4780_CLK_UHC] = {
+ "uhc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL, JZ4780_CLK_OTGPHY },
+ .mux = { CGU_REG_UHCCDR, 30, 2 },
+ .div = { CGU_REG_UHCCDR, 0, 8, 29, 28, 27 },
+ .gate = { CGU_REG_CLKGR0, 24 },
+ },
+
+ [JZ4780_CLK_SSIPLL] = {
+ "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 },
+ .mux = { CGU_REG_SSICDR, 30, 1 },
+ .div = { CGU_REG_SSICDR, 0, 8, 29, 28, 27 },
+ },
+
+ [JZ4780_CLK_SSI] = {
+ "ssi", CGU_CLK_MUX,
+ .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_SSIPLL, -1, -1 },
+ .mux = { CGU_REG_SSICDR, 31, 1 },
+ },
+
+ [JZ4780_CLK_CIMMCLK] = {
+ "cim_mclk", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 },
+ .mux = { CGU_REG_CIMCDR, 31, 1 },
+ .div = { CGU_REG_CIMCDR, 0, 8, 30, 29, 28 },
+ },
+
+ [JZ4780_CLK_PCMPLL] = {
+ "pcm_pll", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL, JZ4780_CLK_VPLL },
+ .mux = { CGU_REG_PCMCDR, 29, 2 },
+ .div = { CGU_REG_PCMCDR, 0, 8, 28, 27, 26 },
+ },
+
+ [JZ4780_CLK_PCM] = {
+ "pcm", CGU_CLK_MUX | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, JZ4780_CLK_PCMPLL, -1, -1 },
+ .mux = { CGU_REG_PCMCDR, 31, 1 },
+ .gate = { CGU_REG_CLKGR1, 3 },
+ },
+
+ [JZ4780_CLK_GPU] = {
+ "gpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL },
+ .mux = { CGU_REG_GPUCDR, 30, 2 },
+ .div = { CGU_REG_GPUCDR, 0, 4, 29, 28, 27 },
+ .gate = { CGU_REG_CLKGR1, 4 },
+ },
+
+ [JZ4780_CLK_HDMI] = {
+ "hdmi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_VPLL, -1 },
+ .mux = { CGU_REG_HDMICDR, 30, 2 },
+ .div = { CGU_REG_HDMICDR, 0, 8, 29, 28, 26 },
+ .gate = { CGU_REG_CLKGR1, 9 },
+ },
+
+ [JZ4780_CLK_BCH] = {
+ "bch", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
+ JZ4780_CLK_EPLL },
+ .mux = { CGU_REG_BCHCDR, 30, 2 },
+ .div = { CGU_REG_BCHCDR, 0, 4, 29, 28, 27 },
+ .gate = { CGU_REG_CLKGR0, 1 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4780_CLK_NEMC] = {
+ "nemc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_AHB2, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 0 },
+ },
+
+ [JZ4780_CLK_OTG0] = {
+ "otg0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 2 },
+ },
+
+ [JZ4780_CLK_SSI0] = {
+ "ssi0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SSI, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 4 },
+ },
+
+ [JZ4780_CLK_SMB0] = {
+ "smb0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 5 },
+ },
+
+ [JZ4780_CLK_SMB1] = {
+ "smb1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 6 },
+ },
+
+ [JZ4780_CLK_SCC] = {
+ "scc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 7 },
+ },
+
+ [JZ4780_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 8 },
+ },
+
+ [JZ4780_CLK_TSSI0] = {
+ "tssi0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 9 },
+ },
+
+ [JZ4780_CLK_OWI] = {
+ "owi", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 10 },
+ },
+
+ [JZ4780_CLK_KBC] = {
+ "kbc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 13 },
+ },
+
+ [JZ4780_CLK_SADC] = {
+ "sadc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 14 },
+ },
+
+ [JZ4780_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 15 },
+ },
+
+ [JZ4780_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 16 },
+ },
+
+ [JZ4780_CLK_UART2] = {
+ "uart2", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 17 },
+ },
+
+ [JZ4780_CLK_UART3] = {
+ "uart3", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 18 },
+ },
+
+ [JZ4780_CLK_SSI1] = {
+ "ssi1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SSI, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 19 },
+ },
+
+ [JZ4780_CLK_SSI2] = {
+ "ssi2", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_SSI, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 20 },
+ },
+
+ [JZ4780_CLK_PDMA] = {
+ "pdma", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 21 },
+ },
+
+ [JZ4780_CLK_GPS] = {
+ "gps", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 22 },
+ },
+
+ [JZ4780_CLK_MAC] = {
+ "mac", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 23 },
+ },
+
+ [JZ4780_CLK_SMB2] = {
+ "smb2", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 24 },
+ },
+
+ [JZ4780_CLK_CIM] = {
+ "cim", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 26 },
+ },
+
+ [JZ4780_CLK_LCD] = {
+ "lcd", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 28 },
+ },
+
+ [JZ4780_CLK_TVE] = {
+ "tve", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_LCD, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 27 },
+ },
+
+ [JZ4780_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 29 },
+ },
+
+ [JZ4780_CLK_DDR0] = {
+ "ddr0", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_DDR, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 30 },
+ },
+
+ [JZ4780_CLK_DDR1] = {
+ "ddr1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_DDR, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 31 },
+ },
+
+ [JZ4780_CLK_SMB3] = {
+ "smb3", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 0 },
+ },
+
+ [JZ4780_CLK_TSSI1] = {
+ "tssi1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 1 },
+ },
+
+ [JZ4780_CLK_COMPRESS] = {
+ "compress", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 5 },
+ },
+
+ [JZ4780_CLK_AIC1] = {
+ "aic1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 6 },
+ },
+
+ [JZ4780_CLK_GPVLC] = {
+ "gpvlc", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 7 },
+ },
+
+ [JZ4780_CLK_OTG1] = {
+ "otg1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 8 },
+ },
+
+ [JZ4780_CLK_UART4] = {
+ "uart4", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 10 },
+ },
+
+ [JZ4780_CLK_AHBMON] = {
+ "ahb_mon", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 11 },
+ },
+
+ [JZ4780_CLK_SMB4] = {
+ "smb4", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 12 },
+ },
+
+ [JZ4780_CLK_DES] = {
+ "des", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 13 },
+ },
+
+ [JZ4780_CLK_X2D] = {
+ "x2d", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_EXCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 14 },
+ },
+
+ [JZ4780_CLK_CORE1] = {
+ "core1", CGU_CLK_GATE,
+ .parents = { JZ4780_CLK_CPU, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 15 },
+ },
+
+};
+
+static void __init jz4780_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4780_cgu_clocks,
+ ARRAY_SIZE(jz4780_cgu_clocks), np);
+ if (!cgu) {
+ pr_err("%s: failed to initialise CGU\n", __func__);
+ return;
+ }
+
+ retval = ingenic_cgu_register_clocks(cgu);
+ if (retval) {
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+ return;
+ }
+}
+CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);
--
2.4.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v5 30/37] clk: ingenic: add JZ4780 CGU support
2015-05-24 15:11 ` [PATCH v5 30/37] clk: ingenic: add JZ4780 CGU support Paul Burton
@ 2015-06-03 23:32 ` Michael Turquette
0 siblings, 0 replies; 8+ messages in thread
From: Michael Turquette @ 2015-06-03 23:32 UTC (permalink / raw)
To: Paul Burton, linux-mips
Cc: Paul Burton, Lars-Peter Clausen, Ralf Baechle, Stephen Boyd,
linux-clk, linux-kernel
Quoting Paul Burton (2015-05-24 08:11:40)
> Add support for the clocks provided by the CGU in the Ingenic JZ4780
> SoC, making use of the SoC-agnostic CGU code to do the heavy lifting.
> =
> Signed-off-by: Paul Burton <paul.burton@imgtec.com>
> Co-authored-by: Paul Cercueil <paul@crapouillou.net>
> Cc: Lars-Peter Clausen <lars@metafoo.de>
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: linux-clk@vger.kernel.org
> Cc: linux-mips@linux-mips.org
For patches 24-30:
Acked-by: Michael Turquette <mturquette@linaro.org>
Are you wanting to take this all through the same tree, or are you happy
for the clock patches to get picked into clk-next?
Regards,
Mike
> ---
> =
> Changes in v5:
> - Declare jz4780_otg_phy_ops static.
> - Drop setting the parent of the UHC clock during probe - USB isn't
> supported as of this patchset anyway, so it can be dealt with in
> whatever's deemed the best way later.
> =
> Changes in v4:
> - Return on ingenic_cgu_new or ingenic_cgu_register_clocks failure.
> - Initialise all unused clock parent fields to -1. Zero initialisation
> works out so long as the common clock framework only ever attempts
> to set a parent clock that was specified in the parent array (which
> is OK), and so long as the hardware state is always valid according
> to the clock description (which is hopefully OK). Initialising to -1
> makes sense for resilience should the latter ever not be the case,
> and to avoid that bit of implicit magic knowledge.
> =
> Changes in v3:
> - Rebase.
> =
> Changes in v2:
> - Remove FSF address per checkpatch (ZubairLK).
> =
> drivers/clk/ingenic/Makefile | 1 +
> drivers/clk/ingenic/jz4780-cgu.c | 733 +++++++++++++++++++++++++++++++++=
++++++
> 2 files changed, 734 insertions(+)
> create mode 100644 drivers/clk/ingenic/jz4780-cgu.c
> =
> diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
> index e6db7da..cd47b06 100644
> --- a/drivers/clk/ingenic/Makefile
> +++ b/drivers/clk/ingenic/Makefile
> @@ -1,2 +1,3 @@
> obj-y +=3D cgu.o
> obj-$(CONFIG_MACH_JZ4740) +=3D jz4740-cgu.o
> +obj-$(CONFIG_MACH_JZ4780) +=3D jz4780-cgu.o
> diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz478=
0-cgu.c
> new file mode 100644
> index 0000000..431f962
> --- /dev/null
> +++ b/drivers/clk/ingenic/jz4780-cgu.c
> @@ -0,0 +1,733 @@
> +/*
> + * Ingenic JZ4780 SoC CGU driver
> + *
> + * Copyright (c) 2013-2015 Imagination Technologies
> + * Author: Paul Burton <paul.burton@imgtec.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/of.h>
> +#include <dt-bindings/clock/jz4780-cgu.h>
> +#include "cgu.h"
> +
> +/* CGU register offsets */
> +#define CGU_REG_CLOCKCONTROL 0x00
> +#define CGU_REG_PLLCONTROL 0x0c
> +#define CGU_REG_APLL 0x10
> +#define CGU_REG_MPLL 0x14
> +#define CGU_REG_EPLL 0x18
> +#define CGU_REG_VPLL 0x1c
> +#define CGU_REG_CLKGR0 0x20
> +#define CGU_REG_OPCR 0x24
> +#define CGU_REG_CLKGR1 0x28
> +#define CGU_REG_DDRCDR 0x2c
> +#define CGU_REG_VPUCDR 0x30
> +#define CGU_REG_USBPCR 0x3c
> +#define CGU_REG_USBRDT 0x40
> +#define CGU_REG_USBVBFIL 0x44
> +#define CGU_REG_USBPCR1 0x48
> +#define CGU_REG_LP0CDR 0x54
> +#define CGU_REG_I2SCDR 0x60
> +#define CGU_REG_LP1CDR 0x64
> +#define CGU_REG_MSC0CDR 0x68
> +#define CGU_REG_UHCCDR 0x6c
> +#define CGU_REG_SSICDR 0x74
> +#define CGU_REG_CIMCDR 0x7c
> +#define CGU_REG_PCMCDR 0x84
> +#define CGU_REG_GPUCDR 0x88
> +#define CGU_REG_HDMICDR 0x8c
> +#define CGU_REG_MSC1CDR 0xa4
> +#define CGU_REG_MSC2CDR 0xa8
> +#define CGU_REG_BCHCDR 0xac
> +#define CGU_REG_CLOCKSTATUS 0xd4
> +
> +/* bits within the OPCR register */
> +#define OPCR_SPENDN0 (1 << 7)
> +#define OPCR_SPENDN1 (1 << 6)
> +
> +/* bits within the USBPCR register */
> +#define USBPCR_USB_MODE BIT(31)
> +#define USBPCR_IDPULLUP_MASK (0x3 << 28)
> +#define USBPCR_COMMONONN BIT(25)
> +#define USBPCR_VBUSVLDEXT BIT(24)
> +#define USBPCR_VBUSVLDEXTSEL BIT(23)
> +#define USBPCR_POR BIT(22)
> +#define USBPCR_OTG_DISABLE BIT(20)
> +#define USBPCR_COMPDISTUNE_MASK (0x7 << 17)
> +#define USBPCR_OTGTUNE_MASK (0x7 << 14)
> +#define USBPCR_SQRXTUNE_MASK (0x7 << 11)
> +#define USBPCR_TXFSLSTUNE_MASK (0xf << 7)
> +#define USBPCR_TXPREEMPHTUNE BIT(6)
> +#define USBPCR_TXHSXVTUNE_MASK (0x3 << 4)
> +#define USBPCR_TXVREFTUNE_MASK 0xf
> +
> +/* bits within the USBPCR1 register */
> +#define USBPCR1_REFCLKSEL_SHIFT 26
> +#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
> +#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
> +#define USBPCR1_REFCLKDIV_SHIFT 24
> +#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
> +#define USBPCR1_REFCLKDIV_19_2 (0x3 << USBPCR1_REFCLKDIV_SHIFT)
> +#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
> +#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
> +#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
> +#define USBPCR1_USB_SEL BIT(28)
> +#define USBPCR1_WORD_IF0 BIT(19)
> +#define USBPCR1_WORD_IF1 BIT(18)
> +
> +/* bits within the USBRDT register */
> +#define USBRDT_VBFIL_LD_EN BIT(25)
> +#define USBRDT_USBRDT_MASK 0x7fffff
> +
> +/* bits within the USBVBFIL register */
> +#define USBVBFIL_IDDIGFIL_SHIFT 16
> +#define USBVBFIL_IDDIGFIL_MASK (0xffff << USBVBFIL_IDDIGFIL_SHIFT)
> +#define USBVBFIL_USBVBFIL_MASK (0xffff)
> +
> +static struct ingenic_cgu *cgu;
> +
> +static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
> +{
> + /* we only use CLKCORE, revisit if that ever changes */
> + return 0;
> +}
> +
> +static int jz4780_otg_phy_set_parent(struct clk_hw *hw, u8 idx)
> +{
> + unsigned long flags;
> + u32 usbpcr1;
> +
> + if (idx > 0)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&cgu->lock, flags);
> +
> + usbpcr1 =3D readl(cgu->base + CGU_REG_USBPCR1);
> + usbpcr1 &=3D ~USBPCR1_REFCLKSEL_MASK;
> + /* we only use CLKCORE */
> + usbpcr1 |=3D USBPCR1_REFCLKSEL_CORE;
> + writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
> +
> + spin_unlock_irqrestore(&cgu->lock, flags);
> + return 0;
> +}
> +
> +static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + u32 usbpcr1;
> + unsigned refclk_div;
> +
> + usbpcr1 =3D readl(cgu->base + CGU_REG_USBPCR1);
> + refclk_div =3D usbpcr1 & USBPCR1_REFCLKDIV_MASK;
> +
> + switch (refclk_div) {
> + case USBPCR1_REFCLKDIV_12:
> + return 12000000;
> +
> + case USBPCR1_REFCLKDIV_24:
> + return 24000000;
> +
> + case USBPCR1_REFCLKDIV_48:
> + return 48000000;
> +
> + case USBPCR1_REFCLKDIV_19_2:
> + return 19200000;
> + }
> +
> + BUG();
> + return parent_rate;
> +}
> +
> +static long jz4780_otg_phy_round_rate(struct clk_hw *hw, unsigned long r=
eq_rate,
> + unsigned long *parent_rate)
> +{
> + if (req_rate < 15600000)
> + return 12000000;
> +
> + if (req_rate < 21600000)
> + return 19200000;
> +
> + if (req_rate < 36000000)
> + return 24000000;
> +
> + return 48000000;
> +}
> +
> +static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_=
rate,
> + unsigned long parent_rate)
> +{
> + unsigned long flags;
> + u32 usbpcr1, div_bits;
> +
> + switch (req_rate) {
> + case 12000000:
> + div_bits =3D USBPCR1_REFCLKDIV_12;
> + break;
> +
> + case 19200000:
> + div_bits =3D USBPCR1_REFCLKDIV_19_2;
> + break;
> +
> + case 24000000:
> + div_bits =3D USBPCR1_REFCLKDIV_24;
> + break;
> +
> + case 48000000:
> + div_bits =3D USBPCR1_REFCLKDIV_48;
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + spin_lock_irqsave(&cgu->lock, flags);
> +
> + usbpcr1 =3D readl(cgu->base + CGU_REG_USBPCR1);
> + usbpcr1 &=3D ~USBPCR1_REFCLKDIV_MASK;
> + usbpcr1 |=3D div_bits;
> + writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
> +
> + spin_unlock_irqrestore(&cgu->lock, flags);
> + return 0;
> +}
> +
> +static struct clk_ops jz4780_otg_phy_ops =3D {
> + .get_parent =3D jz4780_otg_phy_get_parent,
> + .set_parent =3D jz4780_otg_phy_set_parent,
> +
> + .recalc_rate =3D jz4780_otg_phy_recalc_rate,
> + .round_rate =3D jz4780_otg_phy_round_rate,
> + .set_rate =3D jz4780_otg_phy_set_rate,
> +};
> +
> +static const s8 pll_od_encoding[16] =3D {
> + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
> + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
> +};
> +
> +static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] =3D {
> +
> + /* External clocks */
> +
> + [JZ4780_CLK_EXCLK] =3D { "ext", CGU_CLK_EXT },
> + [JZ4780_CLK_RTCLK] =3D { "rtc", CGU_CLK_EXT },
> +
> + /* PLLs */
> +
> +#define DEF_PLL(name) { \
> + .reg =3D CGU_REG_ ## name, \
> + .m_shift =3D 19, \
> + .m_bits =3D 13, \
> + .m_offset =3D 1, \
> + .n_shift =3D 13, \
> + .n_bits =3D 6, \
> + .n_offset =3D 1, \
> + .od_shift =3D 9, \
> + .od_bits =3D 4, \
> + .od_max =3D 16, \
> + .od_encoding =3D pll_od_encoding, \
> + .stable_bit =3D 6, \
> + .bypass_bit =3D 1, \
> + .enable_bit =3D 0, \
> +}
> +
> + [JZ4780_CLK_APLL] =3D {
> + "apll", CGU_CLK_PLL,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .pll =3D DEF_PLL(APLL),
> + },
> +
> + [JZ4780_CLK_MPLL] =3D {
> + "mpll", CGU_CLK_PLL,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .pll =3D DEF_PLL(MPLL),
> + },
> +
> + [JZ4780_CLK_EPLL] =3D {
> + "epll", CGU_CLK_PLL,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .pll =3D DEF_PLL(EPLL),
> + },
> +
> + [JZ4780_CLK_VPLL] =3D {
> + "vpll", CGU_CLK_PLL,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .pll =3D DEF_PLL(VPLL),
> + },
> +
> +#undef DEF_PLL
> +
> + /* Custom (SoC-specific) OTG PHY */
> +
> + [JZ4780_CLK_OTGPHY] =3D {
> + "otg_phy", CGU_CLK_CUSTOM,
> + .parents =3D { -1, -1, JZ4780_CLK_EXCLK, -1 },
> + .custom =3D { &jz4780_otg_phy_ops },
> + },
> +
> + /* Muxes & dividers */
> +
> + [JZ4780_CLK_SCLKA] =3D {
> + "sclk_a", CGU_CLK_MUX,
> + .parents =3D { -1, JZ4780_CLK_APLL, JZ4780_CLK_EXCLK,
> + JZ4780_CLK_RTCLK },
> + .mux =3D { CGU_REG_CLOCKCONTROL, 30, 2 },
> + },
> +
> + [JZ4780_CLK_CPUMUX] =3D {
> + "cpumux", CGU_CLK_MUX,
> + .parents =3D { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_EPLL },
> + .mux =3D { CGU_REG_CLOCKCONTROL, 28, 2 },
> + },
> +
> + [JZ4780_CLK_CPU] =3D {
> + "cpu", CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_CPUMUX, -1, -1, -1 },
> + .div =3D { CGU_REG_CLOCKCONTROL, 0, 4, 22, -1, -1 },
> + },
> +
> + [JZ4780_CLK_L2CACHE] =3D {
> + "l2cache", CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_CPUMUX, -1, -1, -1 },
> + .div =3D { CGU_REG_CLOCKCONTROL, 4, 4, -1, -1, -1 },
> + },
> +
> + [JZ4780_CLK_AHB0] =3D {
> + "ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
> + .parents =3D { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_EPLL },
> + .mux =3D { CGU_REG_CLOCKCONTROL, 26, 2 },
> + .div =3D { CGU_REG_CLOCKCONTROL, 8, 4, 21, -1, -1 },
> + },
> +
> + [JZ4780_CLK_AHB2PMUX] =3D {
> + "ahb2_apb_mux", CGU_CLK_MUX,
> + .parents =3D { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_RTCLK },
> + .mux =3D { CGU_REG_CLOCKCONTROL, 24, 2 },
> + },
> +
> + [JZ4780_CLK_AHB2] =3D {
> + "ahb2", CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_AHB2PMUX, -1, -1, -1 },
> + .div =3D { CGU_REG_CLOCKCONTROL, 12, 4, 20, -1, -1 },
> + },
> +
> + [JZ4780_CLK_PCLK] =3D {
> + "pclk", CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_AHB2PMUX, -1, -1, -1 },
> + .div =3D { CGU_REG_CLOCKCONTROL, 16, 4, 20, -1, -1 },
> + },
> +
> + [JZ4780_CLK_DDR] =3D {
> + "ddr", CGU_CLK_MUX | CGU_CLK_DIV,
> + .parents =3D { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 =
},
> + .mux =3D { CGU_REG_DDRCDR, 30, 2 },
> + .div =3D { CGU_REG_DDRCDR, 0, 4, 29, 28, 27 },
> + },
> +
> + [JZ4780_CLK_VPU] =3D {
> + "vpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_EPLL, -1 },
> + .mux =3D { CGU_REG_VPUCDR, 30, 2 },
> + .div =3D { CGU_REG_VPUCDR, 0, 4, 29, 28, 27 },
> + .gate =3D { CGU_REG_CLKGR1, 2 },
> + },
> +
> + [JZ4780_CLK_I2SPLL] =3D {
> + "i2s_pll", CGU_CLK_MUX | CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_EPLL, -1, -1 =
},
> + .mux =3D { CGU_REG_I2SCDR, 30, 1 },
> + .div =3D { CGU_REG_I2SCDR, 0, 8, 29, 28, 27 },
> + },
> +
> + [JZ4780_CLK_I2S] =3D {
> + "i2s", CGU_CLK_MUX,
> + .parents =3D { JZ4780_CLK_EXCLK, JZ4780_CLK_I2SPLL, -1, -=
1 },
> + .mux =3D { CGU_REG_I2SCDR, 31, 1 },
> + },
> +
> + [JZ4780_CLK_LCD0PIXCLK] =3D {
> + "lcd0pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_VPLL, -1 },
> + .mux =3D { CGU_REG_LP0CDR, 30, 2 },
> + .div =3D { CGU_REG_LP0CDR, 0, 8, 28, 27, 26 },
> + },
> +
> + [JZ4780_CLK_LCD1PIXCLK] =3D {
> + "lcd1pixclk", CGU_CLK_MUX | CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_VPLL, -1 },
> + .mux =3D { CGU_REG_LP1CDR, 30, 2 },
> + .div =3D { CGU_REG_LP1CDR, 0, 8, 28, 27, 26 },
> + },
> +
> + [JZ4780_CLK_MSCMUX] =3D {
> + "msc_mux", CGU_CLK_MUX,
> + .parents =3D { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1 =
},
> + .mux =3D { CGU_REG_MSC0CDR, 30, 2 },
> + },
> +
> + [JZ4780_CLK_MSC0] =3D {
> + "msc0", CGU_CLK_DIV | CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_MSCMUX, -1, -1, -1 },
> + .div =3D { CGU_REG_MSC0CDR, 0, 8, 29, 28, 27 },
> + .gate =3D { CGU_REG_CLKGR0, 3 },
> + },
> +
> + [JZ4780_CLK_MSC1] =3D {
> + "msc1", CGU_CLK_DIV | CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_MSCMUX, -1, -1, -1 },
> + .div =3D { CGU_REG_MSC1CDR, 0, 8, 29, 28, 27 },
> + .gate =3D { CGU_REG_CLKGR0, 11 },
> + },
> +
> + [JZ4780_CLK_MSC2] =3D {
> + "msc2", CGU_CLK_DIV | CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_MSCMUX, -1, -1, -1 },
> + .div =3D { CGU_REG_MSC2CDR, 0, 8, 29, 28, 27 },
> + .gate =3D { CGU_REG_CLKGR0, 12 },
> + },
> +
> + [JZ4780_CLK_UHC] =3D {
> + "uhc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_EPLL, JZ4780_CLK_OTGPHY },
> + .mux =3D { CGU_REG_UHCCDR, 30, 2 },
> + .div =3D { CGU_REG_UHCCDR, 0, 8, 29, 28, 27 },
> + .gate =3D { CGU_REG_CLKGR0, 24 },
> + },
> +
> + [JZ4780_CLK_SSIPLL] =3D {
> + "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 =
},
> + .mux =3D { CGU_REG_SSICDR, 30, 1 },
> + .div =3D { CGU_REG_SSICDR, 0, 8, 29, 28, 27 },
> + },
> +
> + [JZ4780_CLK_SSI] =3D {
> + "ssi", CGU_CLK_MUX,
> + .parents =3D { JZ4780_CLK_EXCLK, JZ4780_CLK_SSIPLL, -1, -=
1 },
> + .mux =3D { CGU_REG_SSICDR, 31, 1 },
> + },
> +
> + [JZ4780_CLK_CIMMCLK] =3D {
> + "cim_mclk", CGU_CLK_MUX | CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL, -1, -1 =
},
> + .mux =3D { CGU_REG_CIMCDR, 31, 1 },
> + .div =3D { CGU_REG_CIMCDR, 0, 8, 30, 29, 28 },
> + },
> +
> + [JZ4780_CLK_PCMPLL] =3D {
> + "pcm_pll", CGU_CLK_MUX | CGU_CLK_DIV,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_EPLL, JZ4780_CLK_VPLL },
> + .mux =3D { CGU_REG_PCMCDR, 29, 2 },
> + .div =3D { CGU_REG_PCMCDR, 0, 8, 28, 27, 26 },
> + },
> +
> + [JZ4780_CLK_PCM] =3D {
> + "pcm", CGU_CLK_MUX | CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, JZ4780_CLK_PCMPLL, -1, -=
1 },
> + .mux =3D { CGU_REG_PCMCDR, 31, 1 },
> + .gate =3D { CGU_REG_CLKGR1, 3 },
> + },
> +
> + [JZ4780_CLK_GPU] =3D {
> + "gpu", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
> + .parents =3D { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_EPLL },
> + .mux =3D { CGU_REG_GPUCDR, 30, 2 },
> + .div =3D { CGU_REG_GPUCDR, 0, 4, 29, 28, 27 },
> + .gate =3D { CGU_REG_CLKGR1, 4 },
> + },
> +
> + [JZ4780_CLK_HDMI] =3D {
> + "hdmi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_VPLL, -1 },
> + .mux =3D { CGU_REG_HDMICDR, 30, 2 },
> + .div =3D { CGU_REG_HDMICDR, 0, 8, 29, 28, 26 },
> + .gate =3D { CGU_REG_CLKGR1, 9 },
> + },
> +
> + [JZ4780_CLK_BCH] =3D {
> + "bch", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
> + .parents =3D { -1, JZ4780_CLK_SCLKA, JZ4780_CLK_MPLL,
> + JZ4780_CLK_EPLL },
> + .mux =3D { CGU_REG_BCHCDR, 30, 2 },
> + .div =3D { CGU_REG_BCHCDR, 0, 4, 29, 28, 27 },
> + .gate =3D { CGU_REG_CLKGR0, 1 },
> + },
> +
> + /* Gate-only clocks */
> +
> + [JZ4780_CLK_NEMC] =3D {
> + "nemc", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_AHB2, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 0 },
> + },
> +
> + [JZ4780_CLK_OTG0] =3D {
> + "otg0", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 2 },
> + },
> +
> + [JZ4780_CLK_SSI0] =3D {
> + "ssi0", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_SSI, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 4 },
> + },
> +
> + [JZ4780_CLK_SMB0] =3D {
> + "smb0", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_PCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 5 },
> + },
> +
> + [JZ4780_CLK_SMB1] =3D {
> + "smb1", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_PCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 6 },
> + },
> +
> + [JZ4780_CLK_SCC] =3D {
> + "scc", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 7 },
> + },
> +
> + [JZ4780_CLK_AIC] =3D {
> + "aic", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 8 },
> + },
> +
> + [JZ4780_CLK_TSSI0] =3D {
> + "tssi0", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 9 },
> + },
> +
> + [JZ4780_CLK_OWI] =3D {
> + "owi", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 10 },
> + },
> +
> + [JZ4780_CLK_KBC] =3D {
> + "kbc", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 13 },
> + },
> +
> + [JZ4780_CLK_SADC] =3D {
> + "sadc", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 14 },
> + },
> +
> + [JZ4780_CLK_UART0] =3D {
> + "uart0", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 15 },
> + },
> +
> + [JZ4780_CLK_UART1] =3D {
> + "uart1", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 16 },
> + },
> +
> + [JZ4780_CLK_UART2] =3D {
> + "uart2", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 17 },
> + },
> +
> + [JZ4780_CLK_UART3] =3D {
> + "uart3", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 18 },
> + },
> +
> + [JZ4780_CLK_SSI1] =3D {
> + "ssi1", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_SSI, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 19 },
> + },
> +
> + [JZ4780_CLK_SSI2] =3D {
> + "ssi2", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_SSI, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 20 },
> + },
> +
> + [JZ4780_CLK_PDMA] =3D {
> + "pdma", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 21 },
> + },
> +
> + [JZ4780_CLK_GPS] =3D {
> + "gps", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 22 },
> + },
> +
> + [JZ4780_CLK_MAC] =3D {
> + "mac", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 23 },
> + },
> +
> + [JZ4780_CLK_SMB2] =3D {
> + "smb2", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_PCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 24 },
> + },
> +
> + [JZ4780_CLK_CIM] =3D {
> + "cim", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 26 },
> + },
> +
> + [JZ4780_CLK_LCD] =3D {
> + "lcd", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 28 },
> + },
> +
> + [JZ4780_CLK_TVE] =3D {
> + "tve", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_LCD, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 27 },
> + },
> +
> + [JZ4780_CLK_IPU] =3D {
> + "ipu", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 29 },
> + },
> +
> + [JZ4780_CLK_DDR0] =3D {
> + "ddr0", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_DDR, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 30 },
> + },
> +
> + [JZ4780_CLK_DDR1] =3D {
> + "ddr1", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_DDR, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR0, 31 },
> + },
> +
> + [JZ4780_CLK_SMB3] =3D {
> + "smb3", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_PCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 0 },
> + },
> +
> + [JZ4780_CLK_TSSI1] =3D {
> + "tssi1", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 1 },
> + },
> +
> + [JZ4780_CLK_COMPRESS] =3D {
> + "compress", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 5 },
> + },
> +
> + [JZ4780_CLK_AIC1] =3D {
> + "aic1", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 6 },
> + },
> +
> + [JZ4780_CLK_GPVLC] =3D {
> + "gpvlc", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 7 },
> + },
> +
> + [JZ4780_CLK_OTG1] =3D {
> + "otg1", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 8 },
> + },
> +
> + [JZ4780_CLK_UART4] =3D {
> + "uart4", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 10 },
> + },
> +
> + [JZ4780_CLK_AHBMON] =3D {
> + "ahb_mon", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 11 },
> + },
> +
> + [JZ4780_CLK_SMB4] =3D {
> + "smb4", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_PCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 12 },
> + },
> +
> + [JZ4780_CLK_DES] =3D {
> + "des", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 13 },
> + },
> +
> + [JZ4780_CLK_X2D] =3D {
> + "x2d", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_EXCLK, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 14 },
> + },
> +
> + [JZ4780_CLK_CORE1] =3D {
> + "core1", CGU_CLK_GATE,
> + .parents =3D { JZ4780_CLK_CPU, -1, -1, -1 },
> + .gate =3D { CGU_REG_CLKGR1, 15 },
> + },
> +
> +};
> +
> +static void __init jz4780_cgu_init(struct device_node *np)
> +{
> + int retval;
> +
> + cgu =3D ingenic_cgu_new(jz4780_cgu_clocks,
> + ARRAY_SIZE(jz4780_cgu_clocks), np);
> + if (!cgu) {
> + pr_err("%s: failed to initialise CGU\n", __func__);
> + return;
> + }
> +
> + retval =3D ingenic_cgu_register_clocks(cgu);
> + if (retval) {
> + pr_err("%s: failed to register CGU Clocks\n", __func__);
> + return;
> + }
> +}
> +CLK_OF_DECLARE(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);
> -- =
> 2.4.1
>=20
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2015-06-03 23:32 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-24 15:11 [PATCH v5 00/37] JZ4780 & CI20 support Paul Burton
2015-05-24 15:11 ` [PATCH v5 25/37] clk: ingenic: add driver for Ingenic SoC CGU clocks Paul Burton
2015-05-24 15:11 ` [PATCH v5 26/37] MIPS,clk: migrate JZ4740 to common clock framework Paul Burton
2015-05-24 15:11 ` [PATCH v5 27/37] MIPS,clk: move jz4740_clock_set_wait_mode to jz4740-cgu Paul Burton
2015-05-24 15:11 ` [PATCH v5 28/37] MIPS, clk: move jz4740 UDC auto suspend functions " Paul Burton
2015-05-24 15:11 ` [PATCH v5 29/37] MIPS, clk: move jz4740 clock suspend, resume " Paul Burton
2015-05-24 15:11 ` [PATCH v5 30/37] clk: ingenic: add JZ4780 CGU support Paul Burton
2015-06-03 23:32 ` Michael Turquette
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).