In the last cycle, the patches support Whale2 sc9860 mobile chip have been
merged. This patchset adds clock driver which is used on almost all
Spreadtrum SoCs.
This is a rewrite of Spreadtrum's original clock driver[1] according to the
comments[2] from Stephen Boyd.
This series also adds Spreadtrum clock binding documentation and devicetree
data.
Any comments would be greatly appreciated.
Thanks,
Chunyan
[1] https://lwn.net/Articles/722739/
[2] https://www.spinics.net/lists/arm-kernel/msg582017.html
Chunyan Zhang (9):
dt-bindings: Add Spreadtrum CCU binding documentation
clk: sprd: Add common infrastructure
clk: sprd: add gate clock support
clk: sprd: add mux clock support
clk: sprd: add divider clock support
clk: sprd: add composite clock support
clk: sprd: add adjustable pll support
clk: sprd: add clock support for SC9860
arm64: dts: add ccu for SC9860
.../devicetree/bindings/clock/sprd-ccu.txt | 46 +
arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi | 67 +
arch/arm64/boot/dts/sprd/sc9860.dtsi | 2 +
arch/arm64/boot/dts/sprd/whale2.dtsi | 8 -
drivers/clk/Makefile | 1 +
drivers/clk/sprd/Makefile | 4 +
drivers/clk/sprd/ccu-sc9860.c | 1742 ++++++++++++++++++++
drivers/clk/sprd/ccu-sc9860.h | 379 +++++
drivers/clk/sprd/ccu_common.c | 78 +
drivers/clk/sprd/ccu_common.h | 90 +
drivers/clk/sprd/ccu_composite.c | 62 +
drivers/clk/sprd/ccu_composite.h | 47 +
drivers/clk/sprd/ccu_div.c | 93 ++
drivers/clk/sprd/ccu_div.h | 77 +
drivers/clk/sprd/ccu_gate.c | 102 ++
drivers/clk/sprd/ccu_gate.h | 73 +
drivers/clk/sprd/ccu_mux.c | 82 +
drivers/clk/sprd/ccu_mux.h | 63 +
drivers/clk/sprd/ccu_pll.c | 241 +++
drivers/clk/sprd/ccu_pll.h | 123 ++
include/dt-bindings/clock/sc9860-ccu.h | 19 +
21 files changed, 3391 insertions(+), 8 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/sprd-ccu.txt
create mode 100644 arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi
create mode 100644 drivers/clk/sprd/Makefile
create mode 100644 drivers/clk/sprd/ccu-sc9860.c
create mode 100644 drivers/clk/sprd/ccu-sc9860.h
create mode 100644 drivers/clk/sprd/ccu_common.c
create mode 100644 drivers/clk/sprd/ccu_common.h
create mode 100644 drivers/clk/sprd/ccu_composite.c
create mode 100644 drivers/clk/sprd/ccu_composite.h
create mode 100644 drivers/clk/sprd/ccu_div.c
create mode 100644 drivers/clk/sprd/ccu_div.h
create mode 100644 drivers/clk/sprd/ccu_gate.c
create mode 100644 drivers/clk/sprd/ccu_gate.h
create mode 100644 drivers/clk/sprd/ccu_mux.c
create mode 100644 drivers/clk/sprd/ccu_mux.h
create mode 100644 drivers/clk/sprd/ccu_pll.c
create mode 100644 drivers/clk/sprd/ccu_pll.h
create mode 100644 include/dt-bindings/clock/sc9860-ccu.h
--
2.7.4
Introduce a new binding with its documentation for Spreadtrum clock
sub-framework.
Signed-off-by: Chunyan Zhang <[email protected]>
---
.../devicetree/bindings/clock/sprd-ccu.txt | 46 ++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/sprd-ccu.txt
diff --git a/Documentation/devicetree/bindings/clock/sprd-ccu.txt b/Documentation/devicetree/bindings/clock/sprd-ccu.txt
new file mode 100644
index 0000000..7a1aa4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sprd-ccu.txt
@@ -0,0 +1,46 @@
+Spreadtrum Clock Control Unit Binding
+------------------------------------
+
+This binding uses the common clock binding[1].
+
+Required properties:
+- compatible: must contain the following compatible:
+ - "sprd,sc9860-ccu" (only support SC9860 for the time being)
+
+- reg: Must contain the registers base address and length.
+ Clocks on most of Spreadtrum's SoCs were designed to locate in a few
+ different address areas, so there would be more than one items under
+ this property.
+
+- clock-names: Must contain the following clock names:
+ - "ext-26m", "ext-rco-100m", "ext-32k"
+- #clock-cells: must be 1
+
+Example:
+
+ccu: clk {
+ compatible = "sprd,sc9860-ccu";
+ #clock-cells = <1>;
+ reg = <0 0x20000000 0 0x400>,
+ <0 0x20210000 0 0x3000>,
+ <0 0x402b0000 0 0x4000>,
+ <0 0x402d0000 0 0x400>,
+ <0 0x402e0000 0 0x4000>,
+ <0 0x40400000 0 0x400>,
+ <0 0x40880000 0 0x400>,
+ <0 0x415e0000 0 0x400>,
+ <0 0x60200000 0 0x400>,
+ <0 0x61000000 0 0x400>,
+ <0 0x61100000 0 0x3000>,
+ <0 0x62000000 0 0x4000>,
+ <0 0x62100000 0 0x4000>,
+ <0 0x63000000 0 0x400>,
+ <0 0x63100000 0 0x3000>,
+ <0 0x70b00000 0 0x3000>;
+ clocks = <&ext_26m>, <&ext_rco_100m>, <&ext_32k>;
+ clock-names = "ext-26m", "ext-rco-100m", "ext-32k";
+};
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+
--
2.7.4
Added Spreadtrum's clock driver common structure and registration code.
Signed-off-by: Chunyan Zhang <[email protected]>
---
drivers/clk/Makefile | 1 +
drivers/clk/sprd/Makefile | 3 ++
drivers/clk/sprd/ccu_common.c | 78 +++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/ccu_common.h | 90 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 172 insertions(+)
create mode 100644 drivers/clk/sprd/Makefile
create mode 100644 drivers/clk/sprd/ccu_common.c
create mode 100644 drivers/clk/sprd/ccu_common.h
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c19983a..1d62721 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
+obj-$(CONFIG_ARCH_SPRD) += sprd/
obj-$(CONFIG_ARCH_STI) += st/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
new file mode 100644
index 0000000..8f802b2
--- /dev/null
+++ b/drivers/clk/sprd/Makefile
@@ -0,0 +1,3 @@
+ifneq ($(CONFIG_OF),)
+obj-y += ccu_common.o
+endif
diff --git a/drivers/clk/sprd/ccu_common.c b/drivers/clk/sprd/ccu_common.c
new file mode 100644
index 0000000..911f4ba
--- /dev/null
+++ b/drivers/clk/sprd/ccu_common.c
@@ -0,0 +1,78 @@
+/*
+ * Spreadtrum clock infrastructure
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include "ccu_common.h"
+
+static inline void __iomem *ccu_find_base(struct ccu_addr_map *maps,
+ unsigned int num, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ if ((reg & 0xffff0000) == maps[i].phy)
+ return maps[i].virt;
+
+ return 0;
+}
+
+int sprd_ccu_probe(struct device_node *node, struct ccu_addr_map *maps,
+ unsigned int count, const struct sprd_ccu_desc *desc)
+{
+ int i, ret = 0;
+ struct ccu_common *cclk;
+ struct clk_hw *hw;
+
+ for (i = 0; i < desc->num_ccu_clks; i++) {
+ cclk = desc->ccu_clks[i];
+ if (!cclk)
+ continue;
+
+ cclk->base = ccu_find_base(maps, count, cclk->reg);
+ if (!cclk->base) {
+ pr_err("%s: No mapped address found for clock(0x%x)\n",
+ __func__, cclk->reg);
+ return -EINVAL;
+ }
+ cclk->reg = cclk->reg & 0xffff;
+ }
+
+ for (i = 0; i < desc->hw_clks->num; i++) {
+
+ hw = desc->hw_clks->hws[i];
+
+ if (!hw)
+ continue;
+
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ pr_err("Couldn't register clock %d - %s\n",
+ i, hw->init->name);
+ goto err_clk_unreg;
+ }
+ }
+
+ ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+ desc->hw_clks);
+ if (ret) {
+ pr_err("Failed to add clock provider.\n");
+ goto err_clk_unreg;
+ }
+
+ return 0;
+
+err_clk_unreg:
+ while (--i >= 0) {
+ hw = desc->hw_clks->hws[i];
+ if (!hw)
+ continue;
+
+ clk_hw_unregister(hw);
+ }
+
+ return ret;
+}
diff --git a/drivers/clk/sprd/ccu_common.h b/drivers/clk/sprd/ccu_common.h
new file mode 100644
index 0000000..ff07772
--- /dev/null
+++ b/drivers/clk/sprd/ccu_common.h
@@ -0,0 +1,90 @@
+/*
+ * Spreadtrum clock infrastructure
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _CCU_COMMON_H_
+#define _CCU_COMMON_H_
+
+#include <linux/clk-provider.h>
+
+struct device_node;
+
+#define CLK_HW_INIT_NO_PARENT(_name, _ops, _flags) \
+ (&(struct clk_init_data) { \
+ .flags = _flags, \
+ .name = _name, \
+ .parent_names = NULL, \
+ .num_parents = 0, \
+ .ops = _ops, \
+ })
+
+#define CLK_HW_INIT(_name, _parent, _ops, _flags) \
+ (&(struct clk_init_data) { \
+ .flags = _flags, \
+ .name = _name, \
+ .parent_names = (const char *[]) { _parent }, \
+ .num_parents = 1, \
+ .ops = _ops, \
+ })
+
+#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \
+ (&(struct clk_init_data) { \
+ .flags = _flags, \
+ .name = _name, \
+ .parent_names = _parents, \
+ .num_parents = ARRAY_SIZE(_parents), \
+ .ops = _ops, \
+ })
+
+#define CLK_FIXED_FACTOR(_struct, _name, _parent, \
+ _div, _mult, _flags) \
+ struct clk_fixed_factor _struct = { \
+ .div = _div, \
+ .mult = _mult, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &clk_fixed_factor_ops, \
+ _flags), \
+ }
+
+struct ccu_common {
+ void __iomem *base;
+ u32 reg;
+ spinlock_t *lock;
+ struct clk_hw hw;
+};
+
+struct ccu_addr_map {
+ phys_addr_t phy;
+ void __iomem *virt;
+};
+
+static inline u32 ccu_readl(struct ccu_common *common)
+{
+ return readl(common->base + common->reg);
+}
+
+static inline void ccu_writel(u32 val, struct ccu_common *common)
+{
+ writel(val, common->base + common->reg);
+}
+
+static inline struct ccu_common *hw_to_ccu_common(struct clk_hw *hw)
+{
+ return container_of(hw, struct ccu_common, hw);
+}
+
+struct sprd_ccu_desc {
+ struct ccu_common **ccu_clks;
+ unsigned long num_ccu_clks;
+ struct clk_hw_onecell_data *hw_clks;
+};
+
+int sprd_ccu_probe(struct device_node *node, struct ccu_addr_map *maps,
+ unsigned int count, const struct sprd_ccu_desc *desc);
+
+#endif /* _CCU_COMMON_H_ */
--
2.7.4
This is a feature that can also be found in sprd composite clocks,
provide two helpers that can be reused later on.
Original-by: Xiaolong Zhang <[email protected]>
Signed-off-by: Chunyan Zhang <[email protected]>
---
drivers/clk/sprd/Makefile | 2 +-
drivers/clk/sprd/ccu_mux.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/ccu_mux.h | 63 +++++++++++++++++++++++++++++++++++
3 files changed, 146 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/sprd/ccu_mux.c
create mode 100644 drivers/clk/sprd/ccu_mux.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index 333e2b2..dc89790 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -1,3 +1,3 @@
ifneq ($(CONFIG_OF),)
-obj-y += ccu_common.o ccu_gate.o
+obj-y += ccu_common.o ccu_gate.o ccu_mux.o
endif
diff --git a/drivers/clk/sprd/ccu_mux.c b/drivers/clk/sprd/ccu_mux.c
new file mode 100644
index 0000000..51c744e
--- /dev/null
+++ b/drivers/clk/sprd/ccu_mux.c
@@ -0,0 +1,82 @@
+/*
+ * Spreadtrum multiplexer clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#include "ccu_mux.h"
+
+DEFINE_SPINLOCK(mux_lock);
+
+u8 ccu_mux_helper_get_parent(struct ccu_common *common,
+ struct ccu_mux_internal *mux)
+{
+ u32 reg;
+ u8 parent;
+ int num_parents;
+ int i;
+
+ reg = ccu_readl(common);
+ parent = reg >> mux->shift;
+ parent &= (1 << mux->width) - 1;
+
+ if (mux->table) {
+ num_parents = clk_hw_get_num_parents(&common->hw);
+
+ for (i = 0; i < num_parents; i++)
+ if (parent == mux->table[i] ||
+ (i < (num_parents - 1) && parent > mux->table[i] &&
+ parent < mux->table[i + 1]))
+ return i;
+ if (i == num_parents)
+ return i - 1;
+ }
+
+ return parent;
+}
+
+static u8 ccu_mux_get_parent(struct clk_hw *hw)
+{
+ struct ccu_mux *cm = hw_to_ccu_mux(hw);
+
+ return ccu_mux_helper_get_parent(&cm->common, &cm->mux);
+}
+
+int ccu_mux_helper_set_parent(struct ccu_common *common,
+ struct ccu_mux_internal *mux,
+ u8 index)
+{
+ unsigned long flags = 0;
+ u32 reg;
+
+ if (mux->table)
+ index = mux->table[index];
+
+ spin_lock_irqsave(common->lock, flags);
+
+ reg = ccu_readl(common);
+ reg &= ~GENMASK(mux->width + mux->shift - 1, mux->shift);
+ ccu_writel(reg | (index << mux->shift), common);
+
+ spin_unlock_irqrestore(common->lock, flags);
+
+ return 0;
+}
+
+static int ccu_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct ccu_mux *cm = hw_to_ccu_mux(hw);
+
+ return ccu_mux_helper_set_parent(&cm->common, &cm->mux, index);
+}
+
+const struct clk_ops ccu_mux_ops = {
+ .get_parent = ccu_mux_get_parent,
+ .set_parent = ccu_mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate,
+};
diff --git a/drivers/clk/sprd/ccu_mux.h b/drivers/clk/sprd/ccu_mux.h
new file mode 100644
index 0000000..f3e3fb4
--- /dev/null
+++ b/drivers/clk/sprd/ccu_mux.h
@@ -0,0 +1,63 @@
+/*
+ * Spreadtrum multiplexer clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _CCU_MUX_H_
+#define _CCU_MUX_H_
+
+#include "ccu_common.h"
+
+struct ccu_mux_internal {
+ u8 shift;
+ u8 width;
+ const u8 *table;
+};
+
+struct ccu_mux {
+ struct ccu_mux_internal mux;
+ struct ccu_common common;
+};
+
+#define _SPRD_CCU_MUX(_shift, _width, _table) \
+ { \
+ .shift = _shift, \
+ .width = _width, \
+ .table = _table, \
+ }
+
+#define SPRD_CCU_MUX(_struct, _name, _parents, _table, \
+ _reg, _shift, _width, \
+ _flags) \
+ struct ccu_mux _struct = { \
+ .mux = _SPRD_CCU_MUX(_shift, _width, _table), \
+ .common = { \
+ .reg = _reg, \
+ .lock = &mux_lock, \
+ .hw.init = CLK_HW_INIT_PARENTS(_name, \
+ _parents, \
+ &ccu_mux_ops,\
+ _flags), \
+ } \
+ }
+
+static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)
+{
+ struct ccu_common *common = hw_to_ccu_common(hw);
+
+ return container_of(common, struct ccu_mux, common);
+}
+
+extern const struct clk_ops ccu_mux_ops;
+extern spinlock_t mux_lock;
+
+u8 ccu_mux_helper_get_parent(struct ccu_common *common,
+ struct ccu_mux_internal *mux);
+int ccu_mux_helper_set_parent(struct ccu_common *common,
+ struct ccu_mux_internal *mux,
+ u8 index);
+
+#endif /* _CCU_MUX_H_ */
--
2.7.4
Some clocks on the Spreadtrum's SoCs are just simple gates. Add
support for those clocks.
Also, some gate clocks are orphan, so this patch also added
registration code for those.
Signed-off-by: Chunyan Zhang <[email protected]>
---
drivers/clk/sprd/Makefile | 2 +-
drivers/clk/sprd/ccu_gate.c | 102 ++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/ccu_gate.h | 73 +++++++++++++++++++++++++++++++
3 files changed, 176 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/sprd/ccu_gate.c
create mode 100644 drivers/clk/sprd/ccu_gate.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index 8f802b2..333e2b2 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -1,3 +1,3 @@
ifneq ($(CONFIG_OF),)
-obj-y += ccu_common.o
+obj-y += ccu_common.o ccu_gate.o
endif
diff --git a/drivers/clk/sprd/ccu_gate.c b/drivers/clk/sprd/ccu_gate.c
new file mode 100644
index 0000000..3d27615
--- /dev/null
+++ b/drivers/clk/sprd/ccu_gate.c
@@ -0,0 +1,102 @@
+/*
+ * Spreadtrum gate clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/clk-provider.h>
+
+#include "ccu_gate.h"
+
+DEFINE_SPINLOCK(gate_lock);
+
+static void ccu_gate_endisable(struct ccu_gate *cg, u32 en)
+{
+ struct ccu_common *common = &cg->common;
+ unsigned long flags = 0;
+ u32 reg;
+ int set = cg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
+
+ set ^= en;
+
+ spin_lock_irqsave(common->lock, flags);
+
+ reg = ccu_readl(common);
+
+ if (set)
+ reg |= cg->op_bit;
+ else
+ reg &= ~cg->op_bit;
+
+ ccu_writel(reg, common);
+
+ spin_unlock_irqrestore(common->lock, flags);
+}
+
+static void ccu_sc_gate_endisable(struct ccu_gate *cg, u32 en)
+{
+ struct ccu_common *common = &cg->common;
+ unsigned long flags = 0;
+ int set = cg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
+ u32 offset;
+
+ set ^= en;
+
+ /*
+ * Each set/clear gate clock has three registers:
+ * common->reg - base register
+ * common->reg + offset - set register
+ * common->reg + 2 * offset - clear register
+ */
+ offset = set ? cg->sc_offset : cg->sc_offset * 2;
+
+ spin_lock_irqsave(common->lock, flags);
+ ccu_writel_offset(cg->op_bit, common, offset);
+ spin_unlock_irqrestore(common->lock, flags);
+}
+
+static void ccu_gate_disable(struct clk_hw *hw)
+{
+ struct ccu_gate *cg = hw_to_ccu_gate(hw);
+
+ if (cg->sc_offset)
+ ccu_sc_gate_endisable(cg, 0);
+ else
+ ccu_gate_endisable(cg, 0);
+}
+
+static int ccu_gate_enable(struct clk_hw *hw)
+{
+ struct ccu_gate *cg = hw_to_ccu_gate(hw);
+
+ if (cg->sc_offset)
+ ccu_sc_gate_endisable(cg, 1);
+ else
+ ccu_gate_endisable(cg, 1);
+
+ return 0;
+}
+
+static int ccu_gate_is_enabled(struct clk_hw *hw)
+{
+ struct ccu_gate *cg = hw_to_ccu_gate(hw);
+ struct ccu_common *common = &cg->common;
+ u32 reg;
+
+ reg = ccu_readl(common);
+
+ if (cg->flags & CLK_GATE_SET_TO_DISABLE)
+ reg ^= cg->op_bit;
+
+ reg &= cg->op_bit;
+
+ return reg ? 1 : 0;
+}
+
+const struct clk_ops ccu_gate_ops = {
+ .disable = ccu_gate_disable,
+ .enable = ccu_gate_enable,
+ .is_enabled = ccu_gate_is_enabled,
+};
diff --git a/drivers/clk/sprd/ccu_gate.h b/drivers/clk/sprd/ccu_gate.h
new file mode 100644
index 0000000..bc40169
--- /dev/null
+++ b/drivers/clk/sprd/ccu_gate.h
@@ -0,0 +1,73 @@
+/*
+ * Spreadtrum gate clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _CCU_GATE_H_
+#define _CCU_GATE_H_
+
+#include "ccu_common.h"
+
+struct ccu_gate {
+ u32 op_bit;
+ u16 flags;
+ u16 sc_offset;
+
+ struct ccu_common common;
+};
+
+#define SPRD_CCU_GATE(_struct, _name, _parent, _reg, _sc_offset, \
+ _op_bit, _flags, _gate_flags) \
+ struct ccu_gate _struct = { \
+ .op_bit = _op_bit, \
+ .sc_offset = _sc_offset, \
+ .flags = _gate_flags, \
+ .common = { \
+ .reg = _reg, \
+ .lock = &gate_lock, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &ccu_gate_ops, \
+ _flags), \
+ } \
+ }
+
+#define SPRD_CCU_GATE_NO_PARENT(_struct, _name, _reg, _sc_offset, \
+ _op_bit, _flags, _gate_flags) \
+ struct ccu_gate _struct = { \
+ .op_bit = _op_bit, \
+ .sc_offset = _sc_offset, \
+ .flags = _gate_flags, \
+ .common = { \
+ .reg = _reg, \
+ .lock = &gate_lock, \
+ .hw.init = CLK_HW_INIT_NO_PARENT(_name, \
+ &ccu_gate_ops, \
+ _flags), \
+ } \
+ }
+
+static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)
+{
+ struct ccu_common *common = hw_to_ccu_common(hw);
+
+ return container_of(common, struct ccu_gate, common);
+}
+
+static inline void ccu_writel_offset(u32 val,
+ struct ccu_common *common, u32 offset)
+{
+ writel(val, common->base + common->reg + offset);
+}
+
+void ccu_gate_helper_disable(struct ccu_common *common, u32 gate);
+int ccu_gate_helper_enable(struct ccu_common *common, u32 gate);
+int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate);
+
+extern const struct clk_ops ccu_gate_ops;
+extern spinlock_t gate_lock;
+
+#endif /* _CCU_GATE_H_ */
--
2.7.4
This patch introduced composite driver whose functions are simply
consisted of divider and mux clocks.
Original-by: Xiaolong Zhang <[email protected]>
Signed-off-by: Chunyan Zhang <[email protected]>
---
drivers/clk/sprd/Makefile | 2 +-
drivers/clk/sprd/ccu_composite.c | 62 ++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/ccu_composite.h | 47 ++++++++++++++++++++++++++++++
3 files changed, 110 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/sprd/ccu_composite.c
create mode 100644 drivers/clk/sprd/ccu_composite.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index d129c0a8..83232e5 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -1,3 +1,3 @@
ifneq ($(CONFIG_OF),)
-obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o
+obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o
endif
diff --git a/drivers/clk/sprd/ccu_composite.c b/drivers/clk/sprd/ccu_composite.c
new file mode 100644
index 0000000..6a64fb1
--- /dev/null
+++ b/drivers/clk/sprd/ccu_composite.c
@@ -0,0 +1,62 @@
+/*
+ * Spreadtrum composite clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/clk-provider.h>
+
+#include "ccu_composite.h"
+
+DEFINE_SPINLOCK(comp_lock);
+
+static long ccu_comp_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct ccu_comp *cc = hw_to_ccu_comp(hw);
+
+ return ccu_div_helper_round_rate(&cc->common, &cc->div,
+ rate, parent_rate);
+}
+
+static unsigned long ccu_comp_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ccu_comp *cc = hw_to_ccu_comp(hw);
+
+ return ccu_div_helper_recalc_rate(&cc->common, &cc->div, parent_rate);
+}
+
+static int ccu_comp_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct ccu_comp *cc = hw_to_ccu_comp(hw);
+
+ return ccu_div_helper_set_rate(&cc->common, &cc->div,
+ rate, parent_rate);
+}
+
+static u8 ccu_comp_get_parent(struct clk_hw *hw)
+{
+ struct ccu_comp *cc = hw_to_ccu_comp(hw);
+
+ return ccu_mux_helper_get_parent(&cc->common, &cc->mux);
+}
+
+static int ccu_comp_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct ccu_comp *cc = hw_to_ccu_comp(hw);
+
+ return ccu_mux_helper_set_parent(&cc->common, &cc->mux, index);
+}
+
+const struct clk_ops ccu_comp_ops = {
+ .get_parent = ccu_comp_get_parent,
+ .set_parent = ccu_comp_set_parent,
+
+ .round_rate = ccu_comp_round_rate,
+ .recalc_rate = ccu_comp_recalc_rate,
+ .set_rate = ccu_comp_set_rate,
+};
diff --git a/drivers/clk/sprd/ccu_composite.h b/drivers/clk/sprd/ccu_composite.h
new file mode 100644
index 0000000..c99c919
--- /dev/null
+++ b/drivers/clk/sprd/ccu_composite.h
@@ -0,0 +1,47 @@
+/*
+ * Spreadtrum composite clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _CCU_COMPOSITE_H_
+#define _CCU_COMPOSITE_H_
+
+#include "ccu_common.h"
+#include "ccu_mux.h"
+#include "ccu_div.h"
+
+struct ccu_comp {
+ struct ccu_mux_internal mux;
+ struct ccu_div_internal div;
+ struct ccu_common common;
+};
+
+#define SPRD_CCU_COMP(_struct, _name, _parent, _reg, _table, \
+ _mshift, _mwidth, _dshift, _dwidth, _flags) \
+ struct ccu_comp _struct = { \
+ .mux = _SPRD_CCU_MUX(_mshift, _mwidth, _table), \
+ .div = _SPRD_CCU_DIV(_dshift, _dwidth), \
+ .common = { \
+ .reg = _reg, \
+ .lock = &comp_lock, \
+ .hw.init = CLK_HW_INIT_PARENTS(_name, \
+ _parent, \
+ &ccu_comp_ops, \
+ _flags), \
+ } \
+ }
+
+static inline struct ccu_comp *hw_to_ccu_comp(struct clk_hw *hw)
+{
+ struct ccu_common *common = hw_to_ccu_common(hw);
+
+ return container_of(common, struct ccu_comp, common);
+}
+
+extern const struct clk_ops ccu_comp_ops;
+extern spinlock_t comp_lock;
+
+#endif /* _CCU_COMPOSITE_H_ */
--
2.7.4
Introduced a common adjustable pll clock driver for Spreadtrum SoCs.
Original-by: Xiaolong Zhang <[email protected]>
Signed-off-by: Chunyan Zhang <[email protected]>
---
drivers/clk/sprd/Makefile | 2 +-
drivers/clk/sprd/ccu_pll.c | 241 +++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/ccu_pll.h | 123 +++++++++++++++++++++++
3 files changed, 365 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/sprd/ccu_pll.c
create mode 100644 drivers/clk/sprd/ccu_pll.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index 83232e5..c593a93 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -1,3 +1,3 @@
ifneq ($(CONFIG_OF),)
-obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o
+obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o ccu_pll.o
endif
diff --git a/drivers/clk/sprd/ccu_pll.c b/drivers/clk/sprd/ccu_pll.c
new file mode 100644
index 0000000..6c908e4
--- /dev/null
+++ b/drivers/clk/sprd/ccu_pll.c
@@ -0,0 +1,241 @@
+/*
+ * Spreadtrum pll clock driver
+ *
+ * Copyright (C) 2015~2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "ccu_pll.h"
+
+#define CCU_PLL_1M 1000000
+#define CCU_PLL_10M (CCU_PLL_1M * 10)
+
+#define pindex(pll, member) \
+ (pll->factors[member].shift / (8 * sizeof(pll->regs[0])))
+
+#define pshift(pll, member) \
+ (pll->factors[member].shift % (8 * sizeof(pll->regs[0])))
+
+#define pwidth(pll, member) \
+ pll->factors[member].width
+
+#define pmask(pll, member) \
+ ((pwidth(pll, member)) ? \
+ GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
+ pshift(pll, member)) : 0)
+
+#define pinternal(pll, cfg, member) \
+ (cfg[pindex(pll, member)] & pmask(pll, member))
+
+#define pinternal_val(pll, cfg, member) \
+ (pinternal(pll, cfg, member) >> pshift(pll, member))
+
+static unsigned long pll_get_refin_rate(struct ccu_pll *pll)
+{
+ u8 shift, index, refin_id = 3;
+ u32 mask;
+ const unsigned long refin[4] = { 2, 4, 13, 26 };
+
+ if (pwidth(pll, PLL_REFIN)) {
+ index = pindex(pll, PLL_REFIN);
+ shift = pshift(pll, PLL_REFIN);
+ mask = pmask(pll, PLL_REFIN);
+ refin_id = (ccu_pll_readl(pll, index) & mask) >> shift;
+ if (refin_id > 3)
+ refin_id = 3;
+ }
+
+ return refin[refin_id];
+}
+
+static u8 pll_get_ibias(unsigned long rate, const u64 *table)
+{
+ u64 i;
+ u8 num = table[0];
+
+ for (i = 0; i < num; i++)
+ if (rate <= table[i + 1])
+ break;
+
+ return i == num ? num - 1 : i;
+}
+
+static unsigned long ccu_pll_helper_recalc_rate(struct ccu_pll *pll,
+ unsigned long parent_rate)
+{
+ unsigned long rate, refin, k1, k2;
+ unsigned long kint = 0, nint;
+ u32 reg_num = pll->regs[0];
+ u32 *cfg;
+ u32 i;
+ u32 mask;
+
+ cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ for (i = 0; i < reg_num; i++)
+ cfg[i] = ccu_pll_readl(pll, i);
+
+ refin = pll_get_refin_rate(pll);
+
+ if (pinternal(pll, cfg, PLL_PREDIV))
+ refin = refin * 2;
+
+ if (pwidth(pll, PLL_POSTDIV) &&
+ ((pll->fflag == 1 && pinternal(pll, cfg, PLL_POSTDIV)) ||
+ (!pll->fflag && !pinternal(pll, cfg, PLL_POSTDIV))))
+ refin = refin / 2;
+
+ if (!pinternal(pll, cfg, PLL_DIV_S))
+ rate = refin * pinternal_val(pll, cfg, PLL_N) * CCU_PLL_10M;
+ else {
+ nint = pinternal_val(pll, cfg, PLL_NINT);
+ if (pinternal(pll, cfg, PLL_SDM_EN))
+ kint = pinternal_val(pll, cfg, PLL_KINT);
+
+ mask = pmask(pll, PLL_KINT);
+#ifdef CONFIG_64BIT
+ k1 = 1000;
+ k2 = 1000;
+ rate = DIV_ROUND_CLOSEST(refin * kint * k1,
+ ((mask >> __ffs(mask)) + 1)) *
+ k2 + refin * nint * CCU_PLL_1M;
+#else
+ k1 = 100;
+ k2 = 10000;
+ i = pwidth(pll, PLL_KINT);
+ i = i < 21 ? 0 : i - 21;
+ rate = DIV_ROUND_CLOSEST(refin * (kint >> i) * k1,
+ ((mask >> (__ffs(mask) + i)) + 1)) *
+ k2 + refin * nint * CCU_PLL_1M;
+#endif
+ }
+
+ return rate;
+}
+
+static int ccu_pll_helper_set_rate(struct ccu_pll *pll,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ u32 mask, shift, width, ibias_val, index, kint, nint;
+ u32 reg_num = pll->regs[0], i = 0;
+ unsigned long refin, fvco = rate;
+ struct reg_cfg *cfg;
+
+ cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ refin = pll_get_refin_rate(pll);
+
+ mask = pmask(pll, PLL_PREDIV);
+ index = pindex(pll, PLL_PREDIV);
+ width = pwidth(pll, PLL_PREDIV);
+ if (width && (ccu_pll_readl(pll, index) & mask))
+ refin = refin * 2;
+
+ mask = pmask(pll, PLL_POSTDIV);
+ index = pindex(pll, PLL_POSTDIV);
+ width = pwidth(pll, PLL_POSTDIV);
+ cfg[index].msk = mask;
+ if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
+ (pll->fflag == 0 && fvco > pll->fvco)))
+ cfg[index].val |= mask;
+
+ if (width && fvco <= pll->fvco)
+ fvco = fvco * 2;
+
+ mask = pmask(pll, PLL_DIV_S);
+ index = pindex(pll, PLL_DIV_S);
+ cfg[index].val |= mask;
+ cfg[index].msk |= mask;
+
+ mask = pmask(pll, PLL_SDM_EN);
+ index = pindex(pll, PLL_SDM_EN);
+ cfg[index].val |= mask;
+ cfg[index].msk |= mask;
+
+ nint = fvco/(refin * CCU_PLL_1M);
+
+ mask = pmask(pll, PLL_NINT);
+ index = pindex(pll, PLL_NINT);
+ shift = pshift(pll, PLL_NINT);
+ cfg[index].val |= (nint << shift) & mask;
+ cfg[index].msk |= mask;
+
+ mask = pmask(pll, PLL_KINT);
+ index = pindex(pll, PLL_KINT);
+ width = pwidth(pll, PLL_KINT);
+ shift = pshift(pll, PLL_KINT);
+#ifndef CONFIG_64BIT
+ i = width < 21 ? 0 : i - 21;
+#endif
+ kint = DIV_ROUND_CLOSEST(((fvco - refin * nint * CCU_PLL_1M)/10000) *
+ ((mask >> (shift + i)) + 1), refin * 100) << i;
+ cfg[index].val |= (kint << shift) & mask;
+ cfg[index].msk |= mask;
+
+ ibias_val = pll_get_ibias(fvco, pll->itable);
+
+ mask = pmask(pll, PLL_IBIAS);
+ index = pindex(pll, PLL_IBIAS);
+ shift = pshift(pll, PLL_IBIAS);
+ cfg[index].val |= ibias_val << shift & mask;
+ cfg[index].msk |= mask;
+
+ for (i = 0; i < reg_num; i++) {
+ if (cfg[i].msk)
+ ccu_pll_writel(pll, i, cfg[i].val, cfg[i].msk);
+ }
+
+ udelay(pll->udelay);
+
+ return 0;
+}
+
+static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ccu_pll *pll = hw_to_ccu_pll(hw);
+
+ return ccu_pll_helper_recalc_rate(pll, parent_rate);
+}
+
+static int ccu_pll_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct ccu_pll *pll = hw_to_ccu_pll(hw);
+
+ return ccu_pll_helper_set_rate(pll, rate, parent_rate);
+}
+
+static int ccu_pll_clk_prepare(struct clk_hw *hw)
+{
+ struct ccu_pll *pll = hw_to_ccu_pll(hw);
+
+ udelay(pll->udelay);
+
+ return 0;
+}
+
+static long ccu_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ return rate;
+}
+
+const struct clk_ops ccu_pll_ops = {
+ .prepare = ccu_pll_clk_prepare,
+ .recalc_rate = ccu_pll_recalc_rate,
+ .round_rate = ccu_pll_round_rate,
+ .set_rate = ccu_pll_set_rate,
+};
diff --git a/drivers/clk/sprd/ccu_pll.h b/drivers/clk/sprd/ccu_pll.h
new file mode 100644
index 0000000..66fe5d1
--- /dev/null
+++ b/drivers/clk/sprd/ccu_pll.h
@@ -0,0 +1,123 @@
+/*
+ * Spreadtrum clock pll configurations
+ *
+ * Copyright (C) 2015~2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _CCU_PLL_H_
+#define _CCU_PLL_H_
+
+#include "ccu_common.h"
+
+struct reg_cfg {
+ u32 val;
+ u32 msk;
+};
+
+struct ccu_bit_field {
+ u8 shift;
+ u8 width;
+};
+
+enum {
+ PLL_LOCK_DONE = 0,
+ PLL_DIV_S,
+ PLL_MOD_EN,
+ PLL_SDM_EN,
+ PLL_REFIN,
+ PLL_IBIAS,
+ PLL_N,
+ PLL_NINT,
+ PLL_KINT,
+ PLL_PREDIV,
+ PLL_POSTDIV,
+
+ PLL_FACT_MAX
+};
+
+/*
+ * struct ccu_pll - defination of adjustable pll clock
+ *
+ * @reg: registers used to set the configuration of pll clock,
+ * reg[0] shows how many registers this pll clock uses.
+ * @itable: pll ibias table, itable[0] means how many items this
+ * table includes
+ * @udelay delay time after setting rate
+ * @factors used to calculate the pll clock rate
+ * @fvco: fvco threshold rate
+ * @fflag: fvco flag
+ */
+struct ccu_pll {
+ const u32 *regs;
+ const u64 *itable;
+ u16 udelay;
+ const struct ccu_bit_field *factors;
+ u64 fvco;
+ u16 fflag;
+
+ struct ccu_common common;
+};
+
+#define SPRD_CCU_PLL_WITH_ITABLE_FVCO(_struct, _name, _parent, _reg, \
+ _regs, _itable, _udelay, \
+ _factors, _fvco, _fflag) \
+ struct ccu_pll _struct = { \
+ .regs = _regs, \
+ .itable = _itable, \
+ .udelay = _udelay, \
+ .factors = _factors, \
+ .fvco = _fvco, \
+ .fflag = _fflag, \
+ .common = { \
+ .reg = _reg, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &ccu_pll_ops, \
+ CLK_IGNORE_UNUSED), \
+ }, \
+ }
+
+#define SPRD_CCU_PLL_WITH_ITABLE(_struct, _name, _parent, _reg, \
+ _regs, _itable, _udelay, \
+ _factors) \
+ SPRD_CCU_PLL_WITH_ITABLE_FVCO(_struct, _name, _parent, _reg, \
+ _regs, _itable, _udelay, \
+ _factors, 0, 0)
+
+static inline struct ccu_pll *hw_to_ccu_pll(struct clk_hw *hw)
+{
+ struct ccu_common *common = hw_to_ccu_common(hw);
+
+ return container_of(common, struct ccu_pll, common);
+}
+
+static inline u32 ccu_pll_readl(struct ccu_pll *pll, u8 index)
+{
+ struct ccu_common *common = &pll->common;
+
+ if (WARN_ON(index >= pll->regs[0]))
+ return 0;
+
+ return readl(common->base + pll->regs[index + 1]);
+}
+
+static inline void ccu_pll_writel(struct ccu_pll *pll, u8 index,
+ u32 val, u32 msk)
+{
+ struct ccu_common *common = &pll->common;
+ void __iomem *addr;
+ u32 reg;
+
+ if (WARN_ON(index >= pll->regs[0]))
+ return;
+
+ addr = common->base + pll->regs[index + 1];
+ reg = readl(addr);
+ writel((reg & ~msk) | val, addr);
+}
+
+extern const struct clk_ops ccu_pll_ops;
+
+#endif /* _CCU_PLL_H_ */
--
2.7.4
This is a feature that can also be found in sprd composite clocks,
provide a bunch of helpers that can be reused later on.
Original-by: Xiaolong Zhang <[email protected]>
Signed-off-by: Chunyan Zhang <[email protected]>
---
drivers/clk/sprd/Makefile | 2 +-
drivers/clk/sprd/ccu_div.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/ccu_div.h | 77 ++++++++++++++++++++++++++++++++++++++
3 files changed, 171 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/sprd/ccu_div.c
create mode 100644 drivers/clk/sprd/ccu_div.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index dc89790..d129c0a8 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -1,3 +1,3 @@
ifneq ($(CONFIG_OF),)
-obj-y += ccu_common.o ccu_gate.o ccu_mux.o
+obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o
endif
diff --git a/drivers/clk/sprd/ccu_div.c b/drivers/clk/sprd/ccu_div.c
new file mode 100644
index 0000000..0d0f1e9
--- /dev/null
+++ b/drivers/clk/sprd/ccu_div.c
@@ -0,0 +1,93 @@
+/*
+ * Spreadtrum divider clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/clk-provider.h>
+
+#include "ccu_div.h"
+
+DEFINE_SPINLOCK(div_lock);
+
+long ccu_div_helper_round_rate(struct ccu_common *common,
+ struct ccu_div_internal *div,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return divider_round_rate(&common->hw, rate, parent_rate,
+ NULL, div->width, 0);
+}
+
+static long ccu_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct ccu_div *cd = hw_to_ccu_div(hw);
+
+ return ccu_div_helper_round_rate(&cd->common, &cd->div,
+ rate, parent_rate);
+}
+
+unsigned long ccu_div_helper_recalc_rate(struct ccu_common *common,
+ struct ccu_div_internal *div,
+ unsigned long parent_rate)
+{
+ unsigned long val;
+ u32 reg;
+
+ reg = ccu_readl(common);
+ val = reg >> div->shift;
+ val &= (1 << div->width) - 1;
+
+ return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0);
+}
+
+static unsigned long ccu_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ccu_div *cd = hw_to_ccu_div(hw);
+
+ return ccu_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate);
+}
+
+int ccu_div_helper_set_rate(struct ccu_common *common,
+ struct ccu_div_internal *div,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned long flags;
+ unsigned long val;
+ u32 reg;
+
+ val = divider_get_val(rate, parent_rate, NULL,
+ div->width, 0);
+
+ spin_lock_irqsave(common->lock, flags);
+
+ reg = ccu_readl(common);
+ reg &= ~GENMASK(div->width + div->shift - 1, div->shift);
+
+ ccu_writel(reg | (val << div->shift), common);
+
+ spin_unlock_irqrestore(common->lock, flags);
+
+ return 0;
+
+}
+
+static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct ccu_div *cd = hw_to_ccu_div(hw);
+
+ return ccu_div_helper_set_rate(&cd->common, &cd->div,
+ rate, parent_rate);
+}
+
+const struct clk_ops ccu_div_ops = {
+ .recalc_rate = ccu_div_recalc_rate,
+ .round_rate = ccu_div_round_rate,
+ .set_rate = ccu_div_set_rate,
+};
diff --git a/drivers/clk/sprd/ccu_div.h b/drivers/clk/sprd/ccu_div.h
new file mode 100644
index 0000000..cb13ed7
--- /dev/null
+++ b/drivers/clk/sprd/ccu_div.h
@@ -0,0 +1,77 @@
+/*
+ * Spreadtrum divider clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _CCU_DIV_H_
+#define _CCU_DIV_H_
+
+#include "ccu_common.h"
+
+/**
+ * struct ccu_div_internal - Internal divider description
+ * @shift: Bit offset of the divider in its register
+ * @width: Width of the divider field in its register
+ *
+ * That structure represents a single divider, and is meant to be
+ * embedded in other structures representing the various clock
+ * classes.
+ */
+struct ccu_div_internal {
+ u8 shift;
+ u8 width;
+};
+
+#define _SPRD_CCU_DIV(_shift, _width) \
+ { \
+ .shift = _shift, \
+ .width = _width, \
+ }
+
+struct ccu_div {
+ struct ccu_div_internal div;
+ struct ccu_common common;
+};
+
+#define SPRD_CCU_DIV(_struct, _name, _parent, _reg, \
+ _shift, _width, _flags) \
+ struct ccu_div _struct = { \
+ .div = _SPRD_CCU_DIV(_shift, _width), \
+ .common = { \
+ .reg = _reg, \
+ .lock = &div_lock, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &ccu_div_ops, \
+ _flags), \
+ } \
+ }
+
+static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw)
+{
+ struct ccu_common *common = hw_to_ccu_common(hw);
+
+ return container_of(common, struct ccu_div, common);
+}
+
+long ccu_div_helper_round_rate(struct ccu_common *common,
+ struct ccu_div_internal *div,
+ unsigned long rate,
+ unsigned long *parent_rate);
+
+unsigned long ccu_div_helper_recalc_rate(struct ccu_common *common,
+ struct ccu_div_internal *div,
+ unsigned long parent_rate);
+
+int ccu_div_helper_set_rate(struct ccu_common *common,
+ struct ccu_div_internal *div,
+ unsigned long rate,
+ unsigned long parent_rate);
+
+extern const struct clk_ops ccu_div_ops;
+extern spinlock_t div_lock;
+
+#endif /* _CCU_DIV_H_ */
--
2.7.4
Add the list of clocks in SC9860 CCU.
Original-by: Xiaolong Zhang <[email protected]>
Signed-off-by: Chunyan Zhang <[email protected]>
---
drivers/clk/sprd/Makefile | 1 +
drivers/clk/sprd/ccu-sc9860.c | 1742 ++++++++++++++++++++++++++++++++
drivers/clk/sprd/ccu-sc9860.h | 379 +++++++
include/dt-bindings/clock/sc9860-ccu.h | 19 +
4 files changed, 2141 insertions(+)
create mode 100644 drivers/clk/sprd/ccu-sc9860.c
create mode 100644 drivers/clk/sprd/ccu-sc9860.h
create mode 100644 include/dt-bindings/clock/sc9860-ccu.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index c593a93..0d90b40 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -1,3 +1,4 @@
ifneq ($(CONFIG_OF),)
obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o ccu_pll.o
+obj-y += ccu-sc9860.o
endif
diff --git a/drivers/clk/sprd/ccu-sc9860.c b/drivers/clk/sprd/ccu-sc9860.c
new file mode 100644
index 0000000..6cd4dc5
--- /dev/null
+++ b/drivers/clk/sprd/ccu-sc9860.c
@@ -0,0 +1,1742 @@
+/*
+ * Spreatrum SC9860 clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "ccu_composite.h"
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_mux.h"
+#include "ccu_pll.h"
+
+#include "ccu-sc9860.h"
+
+static CLK_FIXED_FACTOR(fac_4m, "fac-4m", "ext-26m",
+ 6, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_2m, "fac-2m", "ext-26m",
+ 13, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_1m, "fac-1m", "ext-26m",
+ 26, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_250k, "fac-250k", "ext-26m",
+ 104, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_rpll0_26m, "rpll0-26m", "ext-26m",
+ 1, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_rpll1_26m, "rpll1-26m", "ext-26m",
+ 1, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_rco_25m, "rco-25m", "ext-rc0-100m",
+ 4, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_rco_4m, "rco-4m", "ext-rc0-100m",
+ 25, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_rco_2m, "rco-2m", "ext-rc0-100m",
+ 50, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_3k2, "fac-3k2", "ext-32k",
+ 10, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(fac_1k, "fac-1k", "ext-32k",
+ 32, 1, CLK_IS_BASIC);
+
+#define SC9860_GATE_FLAGS (CLK_IGNORE_UNUSED | CLK_IS_BASIC)
+static SPRD_CCU_GATE(rpll0_gate, "rpll0-gate", "ext-26m", 0x402b016c,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(rpll1_gate, "rpll1-gate", "ext-26m", 0x402b016c,
+ 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mpll0_gate, "mpll0-gate", "ext-26m", 0x402b00b0,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mpll1_gate, "mpll1-gate", "ext-26m", 0x402b00b0,
+ 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dpll0_gate, "dpll0-gate", "ext-26m", 0x402b00b4,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dpll1_gate, "dpll1-gate", "ext-26m", 0x402b00b4,
+ 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gpll_gate, "gpll-gate", "ext-26m", 0x402b032c,
+ 0x1000, BIT(0), SC9860_GATE_FLAGS,
+ CLK_GATE_SET_TO_DISABLE);
+static SPRD_CCU_GATE(cppll_gate, "cppll-gate", "ext-26m", 0x402b02b4,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ltepll0_gate, "ltepll0-gate", "ext-26m", 0x402b00b8,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ltepll1_gate, "ltepll1-gate", "ext-26m", 0x402b010c,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(twpll_gate, "twpll-gate", "ext-26m", 0x402b00bc,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(sdio0_2x_en, "sdio0-2x-en", 0x402e013c,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(sdio0_1x_en, "sdio0-1x-en", 0x402e013c,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(sdio1_2x_en, "sdio1-2x-en", 0x402e013c,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(sdio1_1x_en, "sdio1-1x-en", 0x402e013c,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(sdio2_2x_en, "sdio2-2x-en", 0x402e013c,
+ 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(sdio2_1x_en, "sdio2-1x-en", 0x402e013c,
+ 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(emmc_1x_en, "emmc-1x-en", 0x402e013c,
+ 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(emmc_2x_en, "emmc-2x-en", 0x402e013c,
+ 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
+
+/* GPLL/LPLL/DPLL/RPLL/CPLL */
+static const u64 const itable1[4] = {3, 780000000, 988000000, 1196000000};
+
+/* TWPLL/MPLL0/MPLL1 */
+static const u64 itable2[4] = {3, 1638000000, 2080000000, 2600000000UL};
+
+static const struct ccu_bit_field const f_rpll[PLL_FACT_MAX] = {
+ { .shift = 0, .width = 1 }, /* lock_done */
+ { .shift = 3, .width = 1 }, /* div_s */
+ { .shift = 80, .width = 1 }, /* mod_en */
+ { .shift = 81, .width = 1 }, /* sdm_en */
+ { .shift = 0, .width = 0 }, /* refin */
+ { .shift = 14, .width = 2 }, /* ibias */
+ { .shift = 16, .width = 7 }, /* n */
+ { .shift = 4, .width = 7 }, /* nint */
+ { .shift = 32, .width = 23}, /* kint */
+ { .shift = 0, .width = 0 }, /* prediv */
+ { .shift = 0, .width = 0 }, /* postdiv */
+};
+static const u32 const regs_rpll0[4] = { 3, 0x44, 0x48, 0x4c };
+static SPRD_CCU_PLL_WITH_ITABLE(rpll0_clk, "rpll0", "rpll0-gate", 0x40400044,
+ regs_rpll0, itable1, 200, f_rpll);
+
+static const u32 const regs_rpll1[4] = { 3, 0x50, 0x54, 0x58 };
+static SPRD_CCU_PLL_WITH_ITABLE(rpll1_clk, "rpll1", "rpll1-gate", 0x40400050,
+ regs_rpll1, itable1, 200, f_rpll);
+
+static const struct ccu_bit_field const f_mpll0[PLL_FACT_MAX] = {
+ { .shift = 20, .width = 1 }, /* lock_done */
+ { .shift = 19, .width = 1 }, /* div_s */
+ { .shift = 18, .width = 1 }, /* mod_en */
+ { .shift = 17, .width = 1 }, /* sdm_en */
+ { .shift = 0, .width = 0 }, /* refin */
+ { .shift = 11, .width = 2 }, /* ibias */
+ { .shift = 0, .width = 7 }, /* n */
+ { .shift = 57, .width = 7 }, /* nint */
+ { .shift = 32, .width = 23}, /* kint */
+ { .shift = 0, .width = 0 }, /* prediv */
+ { .shift = 56, .width = 1 }, /* postdiv */
+};
+static const u32 const regs_mpll0[3] = { 2, 0x24, 0x28 };
+static SPRD_CCU_PLL_WITH_ITABLE_FVCO(mpll0_clk, "mpll0", "mpll0-gate",
+ 0x40400024, regs_mpll0, itable2,
+ 200, f_mpll0, 1300000000, 1);
+
+static const struct ccu_bit_field const f_mpll1[PLL_FACT_MAX] = {
+ { .shift = 20, .width = 1 }, /* lock_done */
+ { .shift = 19, .width = 1 }, /* div_s */
+ { .shift = 18, .width = 1 }, /* mod_en */
+ { .shift = 17, .width = 1 }, /* sdm_en */
+ { .shift = 0, .width = 0 }, /* refin */
+ { .shift = 11, .width = 2 }, /* ibias */
+ { .shift = 0, .width = 7 }, /* n */
+ { .shift = 57, .width = 7 }, /* nint */
+ { .shift = 32, .width = 23}, /* kint */
+ { .shift = 56, .width = 1 }, /* prediv */
+ { .shift = 0, .width = 0 }, /* postdiv */
+};
+static const u32 const regs_mpll1[3] = { 2, 0x2c, 0x30 };
+static SPRD_CCU_PLL_WITH_ITABLE(mpll1_clk, "mpll1", "mpll1-gate", 0x4040002c,
+ regs_mpll1, itable2, 200, f_mpll1);
+
+static const struct ccu_bit_field const f_dpll[PLL_FACT_MAX] = {
+ { .shift = 16, .width = 1 }, /* lock_done */
+ { .shift = 15, .width = 1 }, /* div_s */
+ { .shift = 14, .width = 1 }, /* mod_en */
+ { .shift = 13, .width = 1 }, /* sdm_en */
+ { .shift = 0, .width = 0 }, /* refin */
+ { .shift = 8, .width = 2 }, /* ibias */
+ { .shift = 0, .width = 7 }, /* n */
+ { .shift = 57, .width = 7 }, /* nint */
+ { .shift = 32, .width = 23}, /* kint */
+ { .shift = 0, .width = 0 }, /* prediv */
+ { .shift = 0, .width = 0 }, /* postdiv */
+};
+static const u32 const regs_dpll0[3] = { 2, 0x34, 0x38 };
+static SPRD_CCU_PLL_WITH_ITABLE(dpll0_clk, "dpll0", "dpll0-gate", 0x40400034,
+ regs_dpll0, itable1, 200, f_dpll);
+
+static const u32 const regs_dpll1[3] = { 2, 0x3c, 0x40 };
+static SPRD_CCU_PLL_WITH_ITABLE(dpll1_clk, "dpll1", "dpll1-gate", 0x4040003c,
+ regs_dpll1, itable1, 200, f_dpll);
+
+static const struct ccu_bit_field const f_gpll[PLL_FACT_MAX] = {
+ { .shift = 18, .width = 1 }, /* lock_done */
+ { .shift = 15, .width = 1 }, /* div_s */
+ { .shift = 14, .width = 1 }, /* mod_en */
+ { .shift = 13, .width = 1 }, /* sdm_en */
+ { .shift = 0, .width = 0 }, /* refin */
+ { .shift = 8, .width = 2 }, /* ibias */
+ { .shift = 0, .width = 7 }, /* n */
+ { .shift = 57, .width = 7 }, /* nint */
+ { .shift = 32, .width = 23}, /* kint */
+ { .shift = 0, .width = 0 }, /* prediv */
+ { .shift = 17, .width = 1 }, /* postdiv */
+};
+static const u32 const regs_gpll[3] = { 2, 0x9c, 0xa0 };
+static SPRD_CCU_PLL_WITH_ITABLE_FVCO(gpll_clk, "gpll", "gpll-gate",
+ 0x4040009c, regs_gpll, itable1,
+ 200, f_gpll, 600000000, 1);
+
+static const struct ccu_bit_field const f_cppll[PLL_FACT_MAX] = {
+ { .shift = 17, .width = 1 }, /* lock_done */
+ { .shift = 15, .width = 1 }, /* div_s */
+ { .shift = 14, .width = 1 }, /* mod_en */
+ { .shift = 13, .width = 1 }, /* sdm_en */
+ { .shift = 0, .width = 0 }, /* refin */
+ { .shift = 8, .width = 2 }, /* ibias */
+ { .shift = 0, .width = 7 }, /* n */
+ { .shift = 57, .width = 7 }, /* nint */
+ { .shift = 32, .width = 23}, /* kint */
+ { .shift = 0, .width = 0 }, /* prediv */
+ { .shift = 0, .width = 0 }, /* postdiv */
+};
+static const u32 const regs_cppll[3] = { 2, 0xc4, 0xc8 };
+static SPRD_CCU_PLL_WITH_ITABLE(cppll_clk, "cppll", "cppll-gate", 0x404000c4,
+ regs_cppll, itable1, 200, f_cppll);
+
+static const struct ccu_bit_field const f_ltepll[PLL_FACT_MAX] = {
+ { .shift = 31, .width = 1 }, /* lock_done */
+ { .shift = 27, .width = 1 }, /* div_s */
+ { .shift = 26, .width = 1 }, /* mod_en */
+ { .shift = 25, .width = 1 }, /* sdm_en */
+ { .shift = 0, .width = 0 }, /* refin */
+ { .shift = 20, .width = 2 }, /* ibias */
+ { .shift = 0, .width = 7 }, /* n */
+ { .shift = 57, .width = 7 }, /* nint */
+ { .shift = 32, .width = 23}, /* kint */
+ { .shift = 0, .width = 0 }, /* prediv */
+ { .shift = 0, .width = 0 }, /* postdiv */
+};
+static const u32 const regs_ltepll0[3] = { 2, 0x64, 0x68 };
+static SPRD_CCU_PLL_WITH_ITABLE(ltepll0_clk, "ltepll0", "ltepll0-gate",
+ 0x40400064, regs_ltepll0,
+ itable1, 200, f_ltepll);
+static const u32 const regs_ltepll1[3] = { 2, 0x6c, 0x70 };
+static SPRD_CCU_PLL_WITH_ITABLE(ltepll1_clk, "ltepll1", "ltepll1-gate",
+ 0x4040006c, regs_ltepll1, itable1,
+ 200, f_ltepll);
+
+static const struct ccu_bit_field const f_twpll[PLL_FACT_MAX] = {
+ { .shift = 21, .width = 1 }, /* lock_done */
+ { .shift = 20, .width = 1 }, /* div_s */
+ { .shift = 19, .width = 1 }, /* mod_en */
+ { .shift = 18, .width = 1 }, /* sdm_en */
+ { .shift = 0, .width = 0 }, /* refin */
+ { .shift = 13, .width = 2 }, /* ibias */
+ { .shift = 0, .width = 7 }, /* n */
+ { .shift = 57, .width = 7 }, /* nint */
+ { .shift = 32, .width = 23}, /* kint */
+ { .shift = 0, .width = 0 }, /* prediv */
+ { .shift = 0, .width = 0 }, /* postdiv */
+};
+static const u32 const regs_twpll[3] = { 2, 0x5c, 0x60 };
+static SPRD_CCU_PLL_WITH_ITABLE(twpll_clk, "twpll", "twpll-gate", 0x4040005c,
+ regs_twpll, itable2, 200, f_twpll);
+
+static CLK_FIXED_FACTOR(gpll_42m5, "gpll-42m5", "gpll", 20, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_768m, "twpll-768m", "twpll", 2, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_384m, "twpll-384m", "twpll", 4, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_192m, "twpll-192m", "twpll", 8, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_96m, "twpll-96m", "twpll", 16, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_48m, "twpll-48m", "twpll", 32, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_24m, "twpll-24m", "twpll", 64, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_12m, "twpll-12m", "twpll", 128, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_512m, "twpll-512m", "twpll", 3, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_256m, "twpll-256m", "twpll", 6, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_128m, "twpll-128m", "twpll", 12, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_64m, "twpll-64m", "twpll", 24, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_307m2, "twpll-307m2", "twpll",
+ 5, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_153m6, "twpll-153m6", "twpll",
+ 10, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_76m8, "twpll-76m8", "twpll", 20, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_51m2, "twpll-51m2", "twpll", 30, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_38m4, "twpll-38m4", "twpll", 40, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(twpll_19m2, "twpll-19m2", "twpll", 80, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(l0_614m4, "l0-614m4", "ltepll0", 2, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(l0_409m6, "l0-409m6", "ltepll0", 3, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(l0_38m, "l0-38m", "ltepll0", 32, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(l1_38m, "l1-38m", "ltepll1", 32, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(rpll0_192m, "rpll0-192m", "rpll0", 6, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(rpll0_96m, "rpll0-96m", "rpll0", 12, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(rpll0_48m, "rpll0-48m", "rpll0", 24, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(rpll1_468m, "rpll1-468m", "rpll1", 2, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(rpll1_192m, "rpll1-192m", "rpll1", 6, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(rpll1_96m, "rpll1-96m", "rpll1", 12, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(rpll1_64m, "rpll1-64m", "rpll1", 18, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(rpll1_48m, "rpll1-48m", "rpll1", 24, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(dpll0_50m, "dpll0-50m", "dpll0", 16, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(dpll1_50m, "dpll1-50m", "dpll1", 16, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(cppll_50m, "cppll-50m", "cppll", 18, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(m0_39m, "m0-39m", "mpll0", 32, 1, CLK_IS_BASIC);
+static CLK_FIXED_FACTOR(m1_63m, "m1-63m", "mpll1", 32, 1, CLK_IS_BASIC);
+
+#define SC9860_COMP_FLAGS (CLK_IGNORE_UNUSED | CLK_IS_BASIC)
+
+static const char * const aon_apb_parents[] = { "rco-25m", "ext-26m",
+ "ext-rco-100m", "twpll-96m",
+ "twpll-128m",
+ "twpll-153m6" };
+static SPRD_CCU_COMP(aon_apb, "aon-apb", aon_apb_parents, 0x402d0230,
+ 0, 0, 3, 8, 2, SC9860_COMP_FLAGS);
+
+static const char * const aux_parents[] = { "ext-32k", "rpll0-26m",
+ "rpll1-26m", "ext-26m",
+ "cppll-50m", "rco-25m",
+ "dpll0-50m", "dpll1-50m",
+ "gpll-42m5", "twpll-48m",
+ "m0-39m", "m1-63m",
+ "l0-38m", "l1-38m" };
+
+static SPRD_CCU_COMP(aux0_clk, "aux0", aux_parents, 0x402d0238,
+ 0, 0, 5, 8, 4, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(aux1_clk, "aux1", aux_parents, 0x402d023c,
+ 0, 0, 5, 8, 4, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(aux2_clk, "aux2", aux_parents, 0x402d0240,
+ 0, 0, 5, 8, 4, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(probe_clk, "probe", aux_parents, 0x402d0244,
+ 0, 0, 5, 8, 4, SC9860_COMP_FLAGS);
+
+static const char * const sp_ahb_parents[] = { "rco-4m", "ext-26m",
+ "ext-rco-100m", "twpll-96m",
+ "twpll-128m",
+ "twpll-153m6" };
+static SPRD_CCU_COMP(sp_ahb, "sp-ahb", sp_ahb_parents, 0x402d02d0,
+ 0, 0, 3, 8, 2, SC9860_COMP_FLAGS);
+
+static const char * const cci_parents[] = { "ext-26m", "twpll-384m",
+ "l0-614m4", "twpll-768m" };
+static SPRD_CCU_COMP(cci_clk, "cci", cci_parents, 0x402d0304,
+ 0, 0, 2, 8, 2, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(gic_clk, "gic", cci_parents, 0x402d0304,
+ 0, 0, 2, 8, 2, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(cssys_clk, "cssys", cci_parents, 0x402d0310,
+ 0, 0, 2, 8, 2, SC9860_COMP_FLAGS);
+
+static const char * const sdio_2x_parents[] = { "fac-1m", "ext-26m",
+ "twpll-307m2", "twpll-384m",
+ "l0-409m6" };
+static SPRD_CCU_COMP(sdio0_2x, "sdio0-2x", sdio_2x_parents, 0x402d0328,
+ 0, 0, 3, 8, 4, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(sdio1_2x, "sdio1-2x", sdio_2x_parents, 0x402d0330,
+ 0, 0, 3, 8, 4, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(sdio2_2x, "sdio2-2x", sdio_2x_parents, 0x402d0338,
+ 0, 0, 3, 8, 4, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(emmc_2x, "emmc-2x", sdio_2x_parents, 0x402d0340,
+ 0, 0, 3, 8, 4, SC9860_COMP_FLAGS);
+
+static const char * const uart_parents[] = { "ext-26m", "twpll-48m",
+ "twpll-51m2", "twpll-96m" };
+static SPRD_CCU_COMP(uart0_clk, "uart0", uart_parents, 0x20000030,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(uart1_clk, "uart1", uart_parents, 0x20000034,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(uart2_clk, "uart2", uart_parents, 0x20000038,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(uart3_clk, "uart3", uart_parents, 0x2000003c,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(uart4_clk, "uart4", uart_parents, 0x20000040,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+
+static const char * const i2c_parents[] = { "ext-26m", "twpll-48m",
+ "twpll-51m2", "twpll-153m6" };
+static SPRD_CCU_COMP(i2c0_clk, "i2c0", i2c_parents, 0x20000044,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(i2c1_clk, "i2c1", i2c_parents, 0x20000048,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(i2c2_clk, "i2c2", i2c_parents, 0x2000004c,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(i2c3_clk, "i2c3", i2c_parents, 0x20000050,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(i2c4_clk, "i2c4", i2c_parents, 0x20000054,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(i2c5_clk, "i2c5", i2c_parents, 0x20000058,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+
+static const char * const spi_parents[] = { "ext-26m", "twpll-128m",
+ "twpll-153m6", "twpll-192m" };
+static SPRD_CCU_COMP(spi0_clk, "spi0", spi_parents, 0x2000005c,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(spi1_clk, "spi1", spi_parents, 0x20000060,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(spi2_clk, "spi2", spi_parents, 0x20000064,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(spi3_clk, "spi3", spi_parents, 0x20000068,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+
+static const char * const iis_parents[] = { "ext-26m",
+ "twpll-128m",
+ "twpll-153m6" };
+static SPRD_CCU_COMP(iis0_clk, "iis0", iis_parents, 0x2000006c,
+ 0, 0, 2, 8, 6, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(iis1_clk, "iis1", iis_parents, 0x20000070,
+ 0, 0, 2, 8, 6, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(iis2_clk, "iis2", iis_parents, 0x20000074,
+ 0, 0, 2, 8, 6, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(iis3_clk, "iis3", iis_parents, 0x20000078,
+ 0, 0, 2, 8, 6, SC9860_COMP_FLAGS);
+
+static const u8 mcu_table[] = { 0, 1, 2, 3, 4, 8 };
+static const char * const lit_mcu_parents[] = { "ext-26m", "twpll-512m",
+ "twpll-768m", "ltepll0",
+ "twpll", "mpll0" };
+static SPRD_CCU_COMP(lit_mcu, "lit-mcu", lit_mcu_parents, 0x40880020,
+ mcu_table, 0, 4, 4, 3, SC9860_COMP_FLAGS);
+
+static const char * const big_mcu_parents[] = { "ext-26m", "twpll-512m",
+ "twpll-768m", "ltepll0",
+ "twpll", "mpll1" };
+static SPRD_CCU_COMP(big_mcu, "big-mcu", big_mcu_parents, 0x40880024,
+ mcu_table, 0, 4, 4, 3, SC9860_COMP_FLAGS);
+
+static const char * const gpu_parents[] = { "twpll-512m",
+ "twpll-768m",
+ "gpll" };
+static SPRD_CCU_COMP(gpu_clk, "gpu", gpu_parents, 0x60200020,
+ 0, 0, 2, 8, 4, SC9860_COMP_FLAGS);
+
+static const char * const vsp_parents[] = { "twpll-76m8", "twpll-128m",
+ "twpll-256m", "twpll-307m2",
+ "twpll-384m" };
+static SPRD_CCU_COMP(vsp_clk, "vsp", vsp_parents, 0x61000024,
+ 0, 0, 3, 8, 2, SC9860_COMP_FLAGS);
+
+static const char * const dispc_parents[] = { "twpll-76m8", "twpll-128m",
+ "twpll-256m", "twpll-307m2" };
+static SPRD_CCU_COMP(vsp_enc, "vsp-enc", dispc_parents, 0x61000028,
+ 0, 0, 2, 8, 2, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(dispc0_dpi, "dispc0-dpi", dispc_parents, 0x63000034,
+ 0, 0, 2, 8, 2, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(dispc1_dpi, "dispc1-dpi", dispc_parents, 0x63000040,
+ 0, 0, 2, 8, 2, SC9860_COMP_FLAGS);
+
+static const char * const sensor_parents[] = { "ext-26m", "twpll-48m",
+ "twpll-76m8", "twpll-96m" };
+static SPRD_CCU_COMP(sensor0_clk, "sensor0", sensor_parents, 0x62000024,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(sensor1_clk, "sensor1", sensor_parents, 0x62000028,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+static SPRD_CCU_COMP(sensor2_clk, "sensor2", sensor_parents, 0x6200002c,
+ 0, 0, 2, 8, 3, SC9860_COMP_FLAGS);
+
+static SPRD_CCU_DIV(sdio0_1x, "sdio0-1x", "sdio0-2x", 0x402d032c,
+ 8, 1, CLK_IS_BASIC);
+static SPRD_CCU_DIV(sdio1_1x, "sdio1-1x", "sdio1-2x", 0x402d0334,
+ 8, 1, CLK_IS_BASIC);
+static SPRD_CCU_DIV(sdio2_1x, "sdio2-1x", "sdio2-2x", 0x402d033c,
+ 8, 1, CLK_IS_BASIC);
+static SPRD_CCU_DIV(emmc_1x, "emmc-1x", "emmc-2x", 0x402d0344,
+ 8, 1, CLK_IS_BASIC);
+
+#define SC9860_MUX_FLAG \
+ (CLK_IS_BASIC | CLK_GET_RATE_NOCACHE | CLK_SET_RATE_NO_REPARENT)
+
+static const char * const adi_parents[] = { "rco-4m", "ext-26m",
+ "rco-25m", "twpll-38m4",
+ "twpll-51m2" };
+static SPRD_CCU_MUX(adi_clk, "adi", adi_parents, NULL, 0x402d0234,
+ 0, 3, SC9860_MUX_FLAG);
+
+static const char * const pwm_parents[] = { "ext-32k", "ext-26m",
+ "rco-4m", "rco-25m",
+ "twpll-48m" };
+static SPRD_CCU_MUX(pwm0_clk, "pwm0", pwm_parents, NULL, 0x402d0248,
+ 0, 3, SC9860_MUX_FLAG);
+static SPRD_CCU_MUX(pwm1_clk, "pwm1", pwm_parents, NULL, 0x402d024c,
+ 0, 3, SC9860_MUX_FLAG);
+static SPRD_CCU_MUX(pwm2_clk, "pwm2", pwm_parents, NULL, 0x402d0250,
+ 0, 3, SC9860_MUX_FLAG);
+static SPRD_CCU_MUX(pwm3_clk, "pwm3", pwm_parents, NULL, 0x402d0254,
+ 0, 3, SC9860_MUX_FLAG);
+
+static const char * const efuse_parents[] = { "rco-25m", "ext-26m" };
+static SPRD_CCU_MUX(efuse_clk, "efuse", efuse_parents, NULL, 0x402d0258,
+ 0, 1, SC9860_MUX_FLAG);
+
+static const char * const cm3_uart_parents[] = { "rco-4m", "ext-26m",
+ "rco-100m", "twpll-48m",
+ "twpll-51m2", "twpll-96m",
+ "twpll-128m" };
+static SPRD_CCU_MUX(cm3_uart0, "cm3-uart0", cm3_uart_parents, NULL, 0x402d025c,
+ 0, 3, SC9860_MUX_FLAG);
+static SPRD_CCU_MUX(cm3_uart1, "cm3-uart1", cm3_uart_parents, NULL, 0x402d0260,
+ 0, 3, SC9860_MUX_FLAG);
+
+static const char * const thm_parents[] = { "ext-32k", "fac-250k" };
+static SPRD_CCU_MUX(thm_clk, "thm", thm_parents, NULL, 0x402d0270,
+ 0, 1, SC9860_MUX_FLAG);
+
+static const char * const cm3_i2c_parents[] = { "rco-4m",
+ "ext-26m",
+ "rco-100m",
+ "twpll-48m",
+ "twpll-51m2",
+ "twpll-153m6" };
+static SPRD_CCU_MUX(cm3_i2c0, "cm3-i2c0", cm3_i2c_parents, NULL, 0x402d0274,
+ 0, 3, SC9860_MUX_FLAG);
+static SPRD_CCU_MUX(cm3_i2c1, "cm3-i2c1", cm3_i2c_parents, NULL, 0x402d0278,
+ 0, 3, SC9860_MUX_FLAG);
+static SPRD_CCU_MUX(aon_i2c, "aon-i2c", cm3_i2c_parents, NULL, 0x402d0280,
+ 0, 3, SC9860_MUX_FLAG);
+
+static const char * const cm4_spi_parents[] = { "ext-26m", "twpll-96m",
+ "rco-100m", "twpll-128m",
+ "twpll-153m6", "twpll-192m" };
+static SPRD_CCU_MUX(cm4_spi, "cm4-spi", cm4_spi_parents, NULL, 0x402d027c,
+ 0, 3, SC9860_MUX_FLAG);
+
+static SPRD_CCU_MUX(avs_clk, "avs", uart_parents, NULL, 0x402d0284,
+ 0, 2, SC9860_MUX_FLAG);
+
+static const char * const ca53_dap_parents[] = { "ext-26m", "rco-4m",
+ "rco-100m", "twpll-76m8",
+ "twpll-128m", "twpll-153m6" };
+static SPRD_CCU_MUX(ca53_dap, "ca53-dap", ca53_dap_parents, NULL, 0x402d0288,
+ 0, 3, SC9860_MUX_FLAG);
+
+static const char * const ca53_ts_parents[] = { "ext-32k", "ext-26m",
+ "clk-twpll-128m",
+ "clk-twpll-153m6" };
+static SPRD_CCU_MUX(ca53_ts, "ca53-ts", ca53_ts_parents, NULL, 0x402d0290,
+ 0, 2, SC9860_MUX_FLAG);
+
+static const char * const djtag_tck_parents[] = { "rco-4m", "ext-26m" };
+static SPRD_CCU_MUX(djtag_tck, "djtag-tck", djtag_tck_parents, NULL,
+ 0x402d02c8, 0, 1, SC9860_MUX_FLAG);
+
+static const char * const pmu_parents[] = { "ext-32k", "rco-4m", "clk-4m" };
+static SPRD_CCU_MUX(pmu_clk, "pmu", pmu_parents, NULL, 0x402d02e0,
+ 0, 2, SC9860_MUX_FLAG);
+
+static const char * const pmu_26m_parents[] = { "rco-25m", "ext-26m" };
+static SPRD_CCU_MUX(pmu_26m, "pmu-26m", pmu_26m_parents, NULL,
+ 0x402d02e4, 0, 1, SC9860_MUX_FLAG);
+
+static const char * const debounce_parents[] = { "ext-32k", "rco-4m",
+ "rco-25m", "ext-26m" };
+static SPRD_CCU_MUX(debounce_clk, "debounce", debounce_parents, NULL,
+ 0x402d02e8, 0, 2, SC9860_MUX_FLAG);
+
+static const char * const otg2_ref_parents[] = { "twpll-12m", "twpll-24m" };
+static SPRD_CCU_MUX(otg2_ref, "otg2-ref", otg2_ref_parents, NULL,
+ 0x402d02f4, 0, 1, SC9860_MUX_FLAG);
+
+static const char * const usb3_ref_parents[] = { "twpll-24m", "twpll-19m2",
+ "twpll-48m" };
+static SPRD_CCU_MUX(usb3_ref, "usb3-ref", usb3_ref_parents, NULL,
+ 0x402d02f8, 0, 2, SC9860_MUX_FLAG);
+
+static const char * const ap_axi_parents[] = { "ext-26m", "twpll-76m8",
+ "twpll-128m", "twpll-256m" };
+static SPRD_CCU_MUX(ap_axi, "ap-axi", ap_axi_parents, NULL,
+ 0x402d0324, 0, 2, SC9860_MUX_FLAG);
+
+static const char * const ap_apb_parents[] = { "ext-26m", "twpll-64m",
+ "twpll-96m", "twpll-128m" };
+static SPRD_CCU_MUX(ap_apb, "ap-apb", ap_apb_parents, NULL,
+ 0x20000020, 0, 1, SC9860_MUX_FLAG);
+
+static const char * const ahb_parents[] = { "ext-26m", "twpll-96m",
+ "twpll-128m", "twpll-153m6" };
+static SPRD_CCU_MUX(ahb_vsp, "ahb-vsp", ahb_parents, NULL,
+ 0x61000020, 0, 2, SC9860_MUX_FLAG);
+static SPRD_CCU_MUX(ahb_disp, "ahb-disp", ahb_parents, NULL,
+ 0x63000020, 0, 2, SC9860_MUX_FLAG);
+static SPRD_CCU_MUX(ahb_cam, "ahb-cam", ahb_parents, NULL,
+ 0x62000020, 0, 2, SC9860_MUX_FLAG);
+
+static SPRD_CCU_GATE(mipi_csi0_eb, "mipi-csi0-eb", "ahb-cam", 0x6200004c,
+ 0, BIT(16), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mipi_csi1_eb, "mipi-csi1-eb", "ahb-cam", 0x62000050,
+ 0, BIT(16), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(usb3_eb, "usb3-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(usb3_suspend, "usb3-suspend", "ap-axi", 0x20210000,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(usb3_ref_eb, "usb3-ref-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dma_eb, "dma-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(sdio0_eb, "sdio0-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(sdio1_eb, "sdio1-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(sdio2_eb, "sdio2-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(emmc_eb, "emmc-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(rom_eb, "rom-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(12), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(busmon_eb, "busmon-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(cc63s_eb, "cc63s-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(22), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(cc63p_eb, "cc63p-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(23), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ce0_eb, "ce0-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(24), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ce1_eb, "ce1-eb", "ap-axi", 0x20210000,
+ 0x1000, BIT(25), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(avs_lit_eb, "avs-lit-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(avs_big_eb, "avs-big-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_intc5_eb, "ap-intc5-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gpio_eb, "gpio-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(pwm0_eb, "pwm0-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(pwm1_eb, "pwm1-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(pwm2_eb, "pwm2-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(pwm3_eb, "pwm3-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(kpd_eb, "kpd-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(aon_sys_eb, "aon-sys-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_sys_eb, "ap-sys-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(aon_tmr_eb, "aon-tmr-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(11), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_tmr0_eb, "ap-tmr0-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(12), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(efuse_eb, "efuse-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(eic_eb, "eic-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(14), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(pub1_reg_eb, "pub1-reg-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(15), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(adi_eb, "adi-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(16), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_intc0_eb, "ap-intc0-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(17), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_intc1_eb, "ap-intc1-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_intc2_eb, "ap-intc2-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(19), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_intc3_eb, "ap-intc3-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(20), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_intc4_eb, "ap-intc4-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(21), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(splk_eb, "splk-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(22), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mspi_eb, "mspi-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(23), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(pub0_reg_eb, "pub0-reg-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(24), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(pin_eb, "pin-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(25), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(aon_ckg_eb, "aon-ckg-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(26), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gpu_eb, "gpu-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(27), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(apcpu_ts0_eb, "apcpu-ts0-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(28), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(apcpu_ts1_eb, "apcpu-ts1-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(29), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dap_eb, "dap-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(30), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(i2c_eb, "i2c-eb", "aon-apb", 0x402e0000,
+ 0x1000, BIT(31), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(pmu_eb, "pmu-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(thm_eb, "thm-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(aux0_eb, "aux0-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(aux1_eb, "aux1-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(aux2_eb, "aux2-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(probe_eb, "probe-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gpu0_avs_eb, "gpu0-avs-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gpu1_avs_eb, "gpu1-avs-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(apcpu_wdg_eb, "apcpu-wdg-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_tmr1_eb, "ap-tmr1-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_tmr2_eb, "ap-tmr2-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(disp_emc_eb, "disp-emc-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(11), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(zip_emc_eb, "zip-emc-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(12), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp_emc_eb, "gsp-emc-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(osc_aon_eb, "osc-aon-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(14), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(lvds_trx_eb, "lvds-trx-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(15), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(lvds_tcxo_eb, "lvds-tcxo-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(16), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mdar_eb, "mdar-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(17), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(rtc4m0_cal_eb, "rtc4m0-cal-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(rct100m_cal_eb, "rct100m-cal-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(19), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(djtag_eb, "djtag-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(20), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mbox_eb, "mbox-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(21), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(aon_dma_eb, "aon-dma-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(22), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dbg_emc_eb, "dbg-emc-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(23), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(lvds_pll_div_en, "lvds-pll-div-en", "aon-apb", 0x402e0004,
+ 0x1000, BIT(24), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(def_eb, "def-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(25), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(aon_apb_rsv0, "aon-apb-rsv0", "aon-apb", 0x402e0004,
+ 0x1000, BIT(26), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(orp_jtag_eb, "orp-jtag-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(27), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vsp_eb, "vsp-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(28), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(cam_eb, "cam-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(29), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(disp_eb, "disp-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(30), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dbg_axi_if_eb, "dbg-axi-if-eb", "aon-apb", 0x402e0004,
+ 0x1000, BIT(31), SC9860_GATE_FLAGS, 0);
+
+static SPRD_CCU_GATE_NO_PARENT(agcp_iis0_eb, "agcp-iis0-eb", 0x415e0000,
+ 0x100, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_iis1_eb, "agcp-iis1-eb", 0x415e0000,
+ 0x100, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_iis2_eb, "agcp-iis2-eb", 0x415e0000,
+ 0x100, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_iis3_eb, "agcp-iis3-eb", 0x415e0000,
+ 0x100, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_uart_eb, "agcp-uart-eb", 0x415e0000,
+ 0x100, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_dmacp_eb, "agcp-dmacp-eb", 0x415e0000,
+ 0x100, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_dmaap_eb, "agcp-dmaap-eb", 0x415e0000,
+ 0x100, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_arc48k_eb, "agcp-arc48k-eb", 0x415e0000,
+ 0x100, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_src44p1k_eb, "agcp-src44p1k-eb", 0x415e0000,
+ 0x100, BIT(11), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_mcdt_eb, "agcp-mcdt-eb", 0x415e0000,
+ 0x100, BIT(12), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_vbcifd_eb, "agcp-vbcifd-eb", 0x415e0000,
+ 0x100, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_vbc_eb, "agcp-vbc-eb", 0x415e0000,
+ 0x100, BIT(14), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_spinlock_eb, "agcp-spinlock-eb", 0x415e0000,
+ 0x100, BIT(15), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_icu_eb, "agcp-icu-eb", 0x415e0000,
+ 0x100, BIT(16), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_ap_ashb_eb, "agcp-ap-ashb-eb", 0x415e0000,
+ 0x100, BIT(17), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_cp_ashb_eb, "agcp-cp-ashb-eb", 0x415e0000,
+ 0x100, BIT(18), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_aud_eb, "agcp-aud-eb", 0x415e0000,
+ 0x100, BIT(19), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE_NO_PARENT(agcp_audif_eb, "agcp-audif-eb", 0x415e0000,
+ 0x100, BIT(20), SC9860_GATE_FLAGS, 0);
+
+static SPRD_CCU_GATE(vsp_dec_eb, "vsp-dec-eb", "ahb_vsp", 0x61100000,
+ 0x1000, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vsp_ckg_eb, "vsp-ckg-eb", "ahb_vsp", 0x61100000,
+ 0x1000, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vsp_mmu_eb, "vsp-mmu-eb", "ahb_vsp", 0x61100000,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vsp_enc_eb, "vsp-enc-eb", "ahb_vsp", 0x61100000,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vpp_eb, "vpp-eb", "ahb_vsp", 0x61100000,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vsp_26m_eb, "vsp-26m-eb", "ahb_vsp", 0x61100000,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+
+static SPRD_CCU_GATE(vsp_axi_gate, "vsp-axi-gate", "ahb_vsp", 0x61100008,
+ 0, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vsp_enc_gate, "vsp-enc-gate", "ahb_vsp", 0x61100008,
+ 0, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vpp_axi_gate, "vpp-axi-gate", "ahb_vsp", 0x61100008,
+ 0, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vsp_bm_gate, "vsp-bm-gate", "ahb_vsp", 0x61100008,
+ 0, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vsp_enc_bm_gate, "vsp-enc-bm-gate", "ahb_vsp", 0x61100008,
+ 0, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(vpp_bm_gate, "vpp-bm-gate", "ahb_vsp", 0x61100008,
+ 0, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dcam0_eb, "dcam0-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dcam1_eb, "dcam1-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp0_eb, "isp0-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(csi0_eb, "csi0-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(csi1_eb, "csi1-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(jpg0_eb, "jpg0-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(jpg1_eb, "jpg1-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(cam_ckg_eb, "cam-ckg-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(cam_mmu_eb, "cam-mmu-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp1_eb, "isp1-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(cpp_eb, "cpp-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mmu_pf_eb, "mmu-pf-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(11), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp2_eb, "isp2-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(12), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dcam2isp_if_eb, "dcam2isp-if-eb", "ahb_cam", 0x62100000,
+ 0x1000, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp2dcam_if_eb, "isp2dcam-if-eb", "ahb_cam", 0x62100000,
+ 0x1000, BIT(14), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp_lclk_eb, "isp-lclk-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(15), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp_iclk_eb, "isp-iclk-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(16), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp_mclk_eb, "isp-mclk-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(17), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp_pclk_eb, "isp-pclk-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp_isp2dcam_eb, "isp-isp2dcam-eb", "ahb_cam", 0x62100000,
+ 0x1000, BIT(19), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dcam0_if_eb, "dcam0-if-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(20), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(clk26m_if_eb, "clk26m-if-eb", "ahb-cam", 0x62100000,
+ 0x1000, BIT(21), SC9860_GATE_FLAGS, 0);
+
+static SPRD_CCU_GATE(cphy0_gate, "cphy0-gate", "ahb-cam", 0x62100008,
+ 0, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mipi_csi0_gate, "mipi-csi0-gate", "ahb_cam", 0x62100008,
+ 0, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(cphy1_gate, "cphy1-gate", "ahb-cam", 0x62100008,
+ 0, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(mipi_csi1, "mipi-csi1", "ahb-cam", 0x62100008,
+ 0, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dcam0_axi_gate, "dcam0-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dcam1_axi_gate, "dcam1-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(sensor0_gate, "sensor0-gate", "ahb-cam", 0x62100008,
+ 0, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(sensor1_gate, "sensor1-gate", "ahb-cam", 0x62100008,
+ 0, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(jpg0_axi_gate, "jpg0-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gpg1_axi_gate, "gpg1-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp0_axi_gate, "isp0-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp1_axi_gate, "isp1-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(11), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(isp2_axi_gate, "isp2-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(12), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(cpp_axi_gate, "cpp-axi-gate", "ahb-cam", 0x62100008,
+ 0, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d0_if_axi_gate, "d0-if-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(14), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d2i_if_axi_gate, "d2i-if-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(15), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(i2d_if_axi_gate, "i2d-if-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(16), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(spare_axi_gate, "spare-axi-gate", "ahb_cam", 0x62100008,
+ 0, BIT(17), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(sensor2_gate, "sensor2-gate", "ahb-cam", 0x62100008,
+ 0, BIT(18), SC9860_GATE_FLAGS, 0);
+
+static SPRD_CCU_GATE(d0if_in_d_en, "d0if-in-d-en", "ahb-cam", 0x62100028,
+ 0x1000, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d1if_in_d_en, "d1if-in-d-en", "ahb-cam", 0x62100028,
+ 0x1000, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d0if_in_d2i_en, "d0if-in-d2i-en", "ahb_cam", 0x62100028,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d1if_in_d2i_en, "d1if-in-d2i-en", "ahb_cam", 0x62100028,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ia_in_d2i_en, "ia-in-d2i-en", "ahb-cam", 0x62100028,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ib_in_d2i_en, "ib-in-d2i-en", "ahb-cam", 0x62100028,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ic_in_d2i_en, "ic-in-d2i-en", "ahb-cam", 0x62100028,
+ 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ia_in_i_en, "ia-in-i-en", "ahb-cam", 0x62100028,
+ 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ib_in_i_en, "ib-in-i-en", "ahb-cam", 0x62100028,
+ 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ic_in_i_en, "ic-in-i-en", "ahb-cam", 0x62100028,
+ 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
+
+static SPRD_CCU_GATE(dispc0_eb, "dispc0-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dispc1_eb, "dispc1-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dispc_mmu_eb, "dispc-mmu-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp0_eb, "gsp0-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp1_eb, "gsp1-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp0_mmu_eb, "gsp0-mmu-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp1_mmu_eb, "gsp1-mmu-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dsi0_eb, "dsi0-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dsi1_eb, "dsi1-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(disp_ckg_eb, "disp-ckg-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(disp_gpu_eb, "disp-gpu-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gpu_mtx_eb, "gpu-mtx-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp_mtx_eb, "gsp-mtx-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(14), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(tmc_mtx_eb, "tmc-mtx-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(15), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dispc_mtx_eb, "dispc-mtx-eb", "ahb-disp", 0x63100000,
+ 0x1000, BIT(16), SC9860_GATE_FLAGS, 0);
+
+static SPRD_CCU_GATE(dphy0_gate, "dphy0-gate", "ahb-disp", 0x63100008,
+ 0, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dphy1_gate, "dphy1-gate", "ahb-disp", 0x63100008,
+ 0, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp0_a_gate, "gsp0-a-gate", "ahb-disp", 0x63100008,
+ 0, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp1_a_gate, "gsp1-a-gate", "ahb-disp", 0x63100008,
+ 0, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp0_f_gate, "gsp0-f-gate", "ahb-disp", 0x63100008,
+ 0, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp1_f_gate, "gsp1-f-gate", "ahb-disp", 0x63100008,
+ 0, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d_mtx_f_gate, "d-mtx-f-gate", "ahb-disp", 0x63100008,
+ 0, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d_mtx_a_gate, "d-mtx-a-gate", "ahb-disp", 0x63100008,
+ 0, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d_noc_f_gate, "d-noc-f-gate", "ahb-disp", 0x63100008,
+ 0, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(d_noc_a_gate, "d-noc-a-gate", "ahb-disp", 0x63100008,
+ 0, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp_mtx_f_gate, "gsp-mtx-f-gate", "ahb-disp", 0x63100008,
+ 0, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp_mtx_a_gate, "gsp-mtx-a-gate", "ahb-disp", 0x63100008,
+ 0, BIT(11), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp_noc_f_gate, "gsp-noc-f-gate", "ahb-disp", 0x63100008,
+ 0, BIT(12), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gsp_noc_a_gate, "gsp-noc-a-gate", "ahb-disp", 0x63100008,
+ 0, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(dispm0idle_gate, "dispm0idle-gate", "ahb-disp", 0x63100008,
+ 0, BIT(14), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(gspm0idle_gate, "gspm0idle-gate", "ahb-disp", 0x63100008,
+ 0, BIT(15), SC9860_GATE_FLAGS, 0);
+
+static SPRD_CCU_GATE(sim0_eb, "sim0-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(0), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(iis0_eb, "iis0-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(1), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(iis1_eb, "iis1-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(iis2_eb, "iis2-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(iis3_eb, "iis3-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(spi0_eb, "spi0-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(spi1_eb, "spi1-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(spi2_eb, "spi2-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(i2c0_eb, "i2c0-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(i2c1_eb, "i2c1-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(i2c2_eb, "i2c2-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(10), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(i2c3_eb, "i2c3-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(11), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(i2c4_eb, "i2c4-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(12), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(i2c5_eb, "i2c5-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(13), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(uart0_eb, "uart0-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(14), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(uart1_eb, "uart1-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(15), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(uart2_eb, "uart2-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(16), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(uart3_eb, "uart3-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(17), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(uart4_eb, "uart4-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(ap_ckg_eb, "ap-ckg-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(19), SC9860_GATE_FLAGS, 0);
+static SPRD_CCU_GATE(spi3_eb, "spi3-eb", "ap_apb", 0x70b00000,
+ 0x1000, BIT(20), SC9860_GATE_FLAGS, 0);
+
+static struct ccu_common *sc9860_ccu_clks[] = {
+ &rpll0_gate.common,
+ &rpll1_gate.common,
+ &mpll0_gate.common,
+ &mpll1_gate.common,
+ &dpll0_gate.common,
+ &dpll1_gate.common,
+ &gpll_gate.common,
+ &cppll_gate.common,
+ <epll0_gate.common,
+ <epll1_gate.common,
+ &twpll_gate.common,
+ &sdio0_2x_en.common,
+ &sdio0_1x_en.common,
+ &sdio1_2x_en.common,
+ &sdio1_1x_en.common,
+ &sdio2_2x_en.common,
+ &sdio2_1x_en.common,
+ &emmc_1x_en.common,
+ &emmc_2x_en.common,
+ &rpll0_clk.common,
+ &rpll1_clk.common,
+ &mpll0_clk.common,
+ &mpll1_clk.common,
+ &dpll0_clk.common,
+ &dpll1_clk.common,
+ &gpll_clk.common,
+ &cppll_clk.common,
+ <epll0_clk.common,
+ <epll1_clk.common,
+ &twpll_clk.common,
+ &aon_apb.common,
+ &aux0_clk.common,
+ &aux1_clk.common,
+ &aux2_clk.common,
+ &probe_clk.common,
+ &sp_ahb.common,
+ &cci_clk.common,
+ &gic_clk.common,
+ &cssys_clk.common,
+ &sdio0_2x.common,
+ &sdio1_2x.common,
+ &sdio2_2x.common,
+ &emmc_2x.common,
+ &uart0_clk.common,
+ &uart1_clk.common,
+ &uart2_clk.common,
+ &uart3_clk.common,
+ &uart4_clk.common,
+ &i2c0_clk.common,
+ &i2c1_clk.common,
+ &i2c2_clk.common,
+ &i2c3_clk.common,
+ &i2c4_clk.common,
+ &i2c5_clk.common,
+ &spi0_clk.common,
+ &spi1_clk.common,
+ &spi2_clk.common,
+ &spi3_clk.common,
+ &iis0_clk.common,
+ &iis1_clk.common,
+ &iis2_clk.common,
+ &iis3_clk.common,
+ &lit_mcu.common,
+ &big_mcu.common,
+ &gpu_clk.common,
+ &vsp_clk.common,
+ &vsp_enc.common,
+ &dispc0_dpi.common,
+ &dispc1_dpi.common,
+ &sensor0_clk.common,
+ &sensor1_clk.common,
+ &sensor2_clk.common,
+ &sdio0_1x.common,
+ &sdio1_1x.common,
+ &sdio2_1x.common,
+ &emmc_1x.common,
+ &adi_clk.common,
+ &pwm0_clk.common,
+ &pwm1_clk.common,
+ &pwm2_clk.common,
+ &pwm3_clk.common,
+ &efuse_clk.common,
+ &cm3_uart0.common,
+ &cm3_uart1.common,
+ &thm_clk.common,
+ &cm3_i2c0.common,
+ &cm3_i2c1.common,
+ &cm4_spi.common,
+ &aon_i2c.common,
+ &avs_clk.common,
+ &ca53_dap.common,
+ &ca53_ts.common,
+ &djtag_tck.common,
+ &pmu_clk.common,
+ &pmu_26m.common,
+ &debounce_clk.common,
+ &otg2_ref.common,
+ &usb3_ref.common,
+ &ap_axi.common,
+ &ap_apb.common,
+ &ahb_vsp.common,
+ &ahb_disp.common,
+ &ahb_cam.common,
+ &mipi_csi0_eb.common,
+ &mipi_csi1_eb.common,
+ &usb3_eb.common,
+ &usb3_suspend.common,
+ &usb3_ref_eb.common,
+ &dma_eb.common,
+ &sdio0_eb.common,
+ &sdio1_eb.common,
+ &sdio2_eb.common,
+ &emmc_eb.common,
+ &rom_eb.common,
+ &busmon_eb.common,
+ &cc63s_eb.common,
+ &cc63p_eb.common,
+ &ce0_eb.common,
+ &ce1_eb.common,
+ &avs_lit_eb.common,
+ &avs_big_eb.common,
+ &ap_intc5_eb.common,
+ &gpio_eb.common,
+ &pwm0_eb.common,
+ &pwm1_eb.common,
+ &pwm2_eb.common,
+ &pwm3_eb.common,
+ &kpd_eb.common,
+ &aon_sys_eb.common,
+ &ap_sys_eb.common,
+ &aon_tmr_eb.common,
+ &ap_tmr0_eb.common,
+ &efuse_eb.common,
+ &eic_eb.common,
+ &pub1_reg_eb.common,
+ &adi_eb.common,
+ &ap_intc0_eb.common,
+ &ap_intc1_eb.common,
+ &ap_intc2_eb.common,
+ &ap_intc3_eb.common,
+ &ap_intc4_eb.common,
+ &splk_eb.common,
+ &mspi_eb.common,
+ &pub0_reg_eb.common,
+ &pin_eb.common,
+ &aon_ckg_eb.common,
+ &gpu_eb.common,
+ &apcpu_ts0_eb.common,
+ &apcpu_ts1_eb.common,
+ &dap_eb.common,
+ &i2c_eb.common,
+ &pmu_eb.common,
+ &thm_eb.common,
+ &aux0_eb.common,
+ &aux1_eb.common,
+ &aux2_eb.common,
+ &probe_eb.common,
+ &gpu0_avs_eb.common,
+ &gpu1_avs_eb.common,
+ &apcpu_wdg_eb.common,
+ &ap_tmr1_eb.common,
+ &ap_tmr2_eb.common,
+ &disp_emc_eb.common,
+ &zip_emc_eb.common,
+ &gsp_emc_eb.common,
+ &osc_aon_eb.common,
+ &lvds_trx_eb.common,
+ &lvds_tcxo_eb.common,
+ &mdar_eb.common,
+ &rtc4m0_cal_eb.common,
+ &rct100m_cal_eb.common,
+ &djtag_eb.common,
+ &mbox_eb.common,
+ &aon_dma_eb.common,
+ &dbg_emc_eb.common,
+ &lvds_pll_div_en.common,
+ &def_eb.common,
+ &aon_apb_rsv0.common,
+ &orp_jtag_eb.common,
+ &vsp_eb.common,
+ &cam_eb.common,
+ &disp_eb.common,
+ &dbg_axi_if_eb.common,
+ &agcp_iis0_eb.common,
+ &agcp_iis1_eb.common,
+ &agcp_iis2_eb.common,
+ &agcp_iis3_eb.common,
+ &agcp_uart_eb.common,
+ &agcp_dmacp_eb.common,
+ &agcp_dmaap_eb.common,
+ &agcp_arc48k_eb.common,
+ &agcp_src44p1k_eb.common,
+ &agcp_mcdt_eb.common,
+ &agcp_vbcifd_eb.common,
+ &agcp_vbc_eb.common,
+ &agcp_spinlock_eb.common,
+ &agcp_icu_eb.common,
+ &agcp_ap_ashb_eb.common,
+ &agcp_cp_ashb_eb.common,
+ &agcp_aud_eb.common,
+ &agcp_audif_eb.common,
+ &vsp_dec_eb.common,
+ &vsp_ckg_eb.common,
+ &vsp_mmu_eb.common,
+ &vsp_enc_eb.common,
+ &vpp_eb.common,
+ &vsp_26m_eb.common,
+ &vsp_axi_gate.common,
+ &vsp_enc_gate.common,
+ &vpp_axi_gate.common,
+ &vsp_bm_gate.common,
+ &vsp_enc_bm_gate.common,
+ &vpp_bm_gate.common,
+ &dcam0_eb.common,
+ &dcam1_eb.common,
+ &isp0_eb.common,
+ &csi0_eb.common,
+ &csi1_eb.common,
+ &jpg0_eb.common,
+ &jpg1_eb.common,
+ &cam_ckg_eb.common,
+ &cam_mmu_eb.common,
+ &isp1_eb.common,
+ &cpp_eb.common,
+ &mmu_pf_eb.common,
+ &isp2_eb.common,
+ &dcam2isp_if_eb.common,
+ &isp2dcam_if_eb.common,
+ &isp_lclk_eb.common,
+ &isp_iclk_eb.common,
+ &isp_mclk_eb.common,
+ &isp_pclk_eb.common,
+ &isp_isp2dcam_eb.common,
+ &dcam0_if_eb.common,
+ &clk26m_if_eb.common,
+ &cphy0_gate.common,
+ &mipi_csi0_gate.common,
+ &cphy1_gate.common,
+ &mipi_csi1.common,
+ &dcam0_axi_gate.common,
+ &dcam1_axi_gate.common,
+ &sensor0_gate.common,
+ &sensor1_gate.common,
+ &jpg0_axi_gate.common,
+ &gpg1_axi_gate.common,
+ &isp0_axi_gate.common,
+ &isp1_axi_gate.common,
+ &isp2_axi_gate.common,
+ &cpp_axi_gate.common,
+ &d0_if_axi_gate.common,
+ &d2i_if_axi_gate.common,
+ &i2d_if_axi_gate.common,
+ &spare_axi_gate.common,
+ &sensor2_gate.common,
+ &d0if_in_d_en.common,
+ &d1if_in_d_en.common,
+ &d0if_in_d2i_en.common,
+ &d1if_in_d2i_en.common,
+ &ia_in_d2i_en.common,
+ &ib_in_d2i_en.common,
+ &ic_in_d2i_en.common,
+ &ia_in_i_en.common,
+ &ib_in_i_en.common,
+ &ic_in_i_en.common,
+ &dispc0_eb.common,
+ &dispc1_eb.common,
+ &dispc_mmu_eb.common,
+ &gsp0_eb.common,
+ &gsp1_eb.common,
+ &gsp0_mmu_eb.common,
+ &gsp1_mmu_eb.common,
+ &dsi0_eb.common,
+ &dsi1_eb.common,
+ &disp_ckg_eb.common,
+ &disp_gpu_eb.common,
+ &gpu_mtx_eb.common,
+ &gsp_mtx_eb.common,
+ &tmc_mtx_eb.common,
+ &dispc_mtx_eb.common,
+ &dphy0_gate.common,
+ &dphy1_gate.common,
+ &gsp0_a_gate.common,
+ &gsp1_a_gate.common,
+ &gsp0_f_gate.common,
+ &gsp1_f_gate.common,
+ &d_mtx_f_gate.common,
+ &d_mtx_a_gate.common,
+ &d_noc_f_gate.common,
+ &d_noc_a_gate.common,
+ &gsp_mtx_f_gate.common,
+ &gsp_mtx_a_gate.common,
+ &gsp_noc_f_gate.common,
+ &gsp_noc_a_gate.common,
+ &dispm0idle_gate.common,
+ &gspm0idle_gate.common,
+ &sim0_eb.common,
+ &iis0_eb.common,
+ &iis1_eb.common,
+ &iis2_eb.common,
+ &iis3_eb.common,
+ &spi0_eb.common,
+ &spi1_eb.common,
+ &spi2_eb.common,
+ &i2c0_eb.common,
+ &i2c1_eb.common,
+ &i2c2_eb.common,
+ &i2c3_eb.common,
+ &i2c4_eb.common,
+ &i2c5_eb.common,
+ &uart0_eb.common,
+ &uart1_eb.common,
+ &uart2_eb.common,
+ &uart3_eb.common,
+ &uart4_eb.common,
+ &ap_ckg_eb.common,
+ &spi3_eb.common,
+};
+
+static struct clk_hw_onecell_data sc9860_hw_clks = {
+ .hws = {
+ [CLK_FAC_4M] = &fac_4m.hw,
+ [CLK_FAC_2M] = &fac_2m.hw,
+ [CLK_FAC_1M] = &fac_1m.hw,
+ [CLK_FAC_250K] = &fac_250k.hw,
+ [CLK_FAC_RPLL0_26M] = &fac_rpll0_26m.hw,
+ [CLK_FAC_RPLL1_26M] = &fac_rpll1_26m.hw,
+ [CLK_FAC_RCO25M] = &fac_rco_25m.hw,
+ [CLK_FAC_RCO4M] = &fac_rco_4m.hw,
+ [CLK_FAC_RCO2M] = &fac_rco_2m.hw,
+ [CLK_FAC_3K2] = &fac_3k2.hw,
+ [CLK_FAC_1K] = &fac_1k.hw,
+ [CLK_RPLL0_GATE] = &rpll0_gate.common.hw,
+ [CLK_RPLL1_GATE] = &rpll1_gate.common.hw,
+ [CLK_MPLL0_GATE] = &mpll0_gate.common.hw,
+ [CLK_MPLL1_GATE] = &mpll1_gate.common.hw,
+ [CLK_DPLL0_GATE] = &dpll0_gate.common.hw,
+ [CLK_DPLL1_GATE] = &dpll1_gate.common.hw,
+ [CLK_GPLL_GATE] = &gpll_gate.common.hw,
+ [CLK_CPPLL_GATE] = &cppll_gate.common.hw,
+ [CLK_LTEPLL0_GATE] = <epll0_gate.common.hw,
+ [CLK_LTEPLL1_GATE] = <epll1_gate.common.hw,
+ [CLK_TWPLL_GATE] = &twpll_gate.common.hw,
+ [CLK_SDIO0_2X_EN] = &sdio0_2x_en.common.hw,
+ [CLK_SDIO0_1X_EN] = &sdio0_1x_en.common.hw,
+ [CLK_SDIO1_2X_EN] = &sdio1_2x_en.common.hw,
+ [CLK_SDIO1_1X_EN] = &sdio1_1x_en.common.hw,
+ [CLK_SDIO2_2X_EN] = &sdio2_2x_en.common.hw,
+ [CLK_SDIO2_1X_EN] = &sdio2_1x_en.common.hw,
+ [CLK_EMMC_1X_EN] = &emmc_1x_en.common.hw,
+ [CLK_EMMC_2X_EN] = &emmc_2x_en.common.hw,
+ [CLK_RPLL0] = &rpll0_clk.common.hw,
+ [CLK_RPLL1] = &rpll1_clk.common.hw,
+ [CLK_MPLL0] = &mpll0_clk.common.hw,
+ [CLK_MPLL1] = &mpll1_clk.common.hw,
+ [CLK_DPLL0] = &dpll0_clk.common.hw,
+ [CLK_DPLL1] = &dpll1_clk.common.hw,
+ [CLK_GPLL] = &gpll_clk.common.hw,
+ [CLK_CPPLL] = &cppll_clk.common.hw,
+ [CLK_LTEPLL0] = <epll0_clk.common.hw,
+ [CLK_LTEPLL1] = <epll1_clk.common.hw,
+ [CLK_TWPLL] = &twpll_clk.common.hw,
+ [CLK_GPLL_42M5] = &gpll_42m5.hw,
+ [CLK_TWPLL_768M] = &twpll_768m.hw,
+ [CLK_TWPLL_384M] = &twpll_384m.hw,
+ [CLK_TWPLL_192M] = &twpll_192m.hw,
+ [CLK_TWPLL_96M] = &twpll_96m.hw,
+ [CLK_TWPLL_48M] = &twpll_48m.hw,
+ [CLK_TWPLL_24M] = &twpll_24m.hw,
+ [CLK_TWPLL_12M] = &twpll_12m.hw,
+ [CLK_TWPLL_512M] = &twpll_512m.hw,
+ [CLK_TWPLL_256M] = &twpll_256m.hw,
+ [CLK_TWPLL_128M] = &twpll_128m.hw,
+ [CLK_TWPLL_64M] = &twpll_64m.hw,
+ [CLK_TWPLL_307M2] = &twpll_307m2.hw,
+ [CLK_TWPLL_153M6] = &twpll_153m6.hw,
+ [CLK_TWPLL_76M8] = &twpll_76m8.hw,
+ [CLK_TWPLL_51M2] = &twpll_51m2.hw,
+ [CLK_TWPLL_38M4] = &twpll_38m4.hw,
+ [CLK_TWPLL_19M2] = &twpll_19m2.hw,
+ [CLK_L0_614M4] = &l0_614m4.hw,
+ [CLK_L0_409M6] = &l0_409m6.hw,
+ [CLK_L0_38M] = &l0_38m.hw,
+ [CLK_L1_38M] = &l1_38m.hw,
+ [CLK_RPLL0_192M] = &rpll0_192m.hw,
+ [CLK_RPLL0_96M] = &rpll0_96m.hw,
+ [CLK_RPLL0_48M] = &rpll0_48m.hw,
+ [CLK_RPLL1_468M] = &rpll1_468m.hw,
+ [CLK_RPLL1_192M] = &rpll1_192m.hw,
+ [CLK_RPLL1_96M] = &rpll1_96m.hw,
+ [CLK_RPLL1_64M] = &rpll1_64m.hw,
+ [CLK_RPLL1_48M] = &rpll1_48m.hw,
+ [CLK_DPLL0_50M] = &dpll0_50m.hw,
+ [CLK_DPLL1_50M] = &dpll1_50m.hw,
+ [CLK_CPPLL_50M] = &cppll_50m.hw,
+ [CLK_M0_39M] = &m0_39m.hw,
+ [CLK_M1_63M] = &m1_63m.hw,
+ [CLK_AON_APB] = &aon_apb.common.hw,
+ [CLK_AUX0] = &aux0_clk.common.hw,
+ [CLK_AUX1] = &aux1_clk.common.hw,
+ [CLK_AUX2] = &aux2_clk.common.hw,
+ [CLK_PROBE] = &probe_clk.common.hw,
+ [CLK_SP_AHB] = &sp_ahb.common.hw,
+ [CLK_CCI] = &cci_clk.common.hw,
+ [CLK_GIC] = &gic_clk.common.hw,
+ [CLK_CSSYS] = &cssys_clk.common.hw,
+ [CLK_SDIO0_2X] = &sdio0_2x.common.hw,
+ [CLK_SDIO1_2X] = &sdio1_2x.common.hw,
+ [CLK_SDIO2_2X] = &sdio2_2x.common.hw,
+ [CLK_EMMC_2X] = &emmc_2x.common.hw,
+ [CLK_UART0] = &uart0_clk.common.hw,
+ [CLK_UART1] = &uart1_clk.common.hw,
+ [CLK_UART2] = &uart2_clk.common.hw,
+ [CLK_UART3] = &uart3_clk.common.hw,
+ [CLK_UART4] = &uart4_clk.common.hw,
+ [CLK_I2C0] = &i2c0_clk.common.hw,
+ [CLK_I2C1] = &i2c1_clk.common.hw,
+ [CLK_I2C2] = &i2c2_clk.common.hw,
+ [CLK_I2C3] = &i2c3_clk.common.hw,
+ [CLK_I2C4] = &i2c4_clk.common.hw,
+ [CLK_I2C5] = &i2c5_clk.common.hw,
+ [CLK_SPI0] = &spi0_clk.common.hw,
+ [CLK_SPI1] = &spi1_clk.common.hw,
+ [CLK_SPI2] = &spi2_clk.common.hw,
+ [CLK_SPI3] = &spi3_clk.common.hw,
+ [CLK_IIS0] = &iis0_clk.common.hw,
+ [CLK_IIS1] = &iis1_clk.common.hw,
+ [CLK_IIS2] = &iis2_clk.common.hw,
+ [CLK_IIS3] = &iis3_clk.common.hw,
+ [CLK_LIT_MCU] = &lit_mcu.common.hw,
+ [CLK_BIG_MCU] = &big_mcu.common.hw,
+ [CLK_GPU] = &gpu_clk.common.hw,
+ [CLK_VSP] = &vsp_clk.common.hw,
+ [CLK_VSP_ENC] = &vsp_enc.common.hw,
+ [CLK_DISPC0_DPI] = &dispc0_dpi.common.hw,
+ [CLK_DISPC1_DPI] = &dispc1_dpi.common.hw,
+ [CLK_SENSOR0] = &sensor0_clk.common.hw,
+ [CLK_SENSOR1] = &sensor1_clk.common.hw,
+ [CLK_SENSOR2] = &sensor2_clk.common.hw,
+ [CLK_SDIO0_1X] = &sdio0_1x.common.hw,
+ [CLK_SDIO1_1X] = &sdio1_1x.common.hw,
+ [CLK_SDIO2_1X] = &sdio2_1x.common.hw,
+ [CLK_EMMC_1X] = &emmc_1x.common.hw,
+ [CLK_ADI] = &adi_clk.common.hw,
+ [CLK_PWM0] = &pwm0_clk.common.hw,
+ [CLK_PWM1] = &pwm1_clk.common.hw,
+ [CLK_PWM2] = &pwm2_clk.common.hw,
+ [CLK_PWM3] = &pwm3_clk.common.hw,
+ [CLK_EFUSE] = &efuse_clk.common.hw,
+ [CLK_CM3_UART0] = &cm3_uart0.common.hw,
+ [CLK_CM3_UART1] = &cm3_uart1.common.hw,
+ [CLK_THM] = &thm_clk.common.hw,
+ [CLK_CM3_I2C0] = &cm3_i2c0.common.hw,
+ [CLK_CM3_I2C1] = &cm3_i2c1.common.hw,
+ [CLK_CM4_SPI] = &cm4_spi.common.hw,
+ [CLK_AON_I2C] = &aon_i2c.common.hw,
+ [CLK_AVS] = &avs_clk.common.hw,
+ [CLK_CA53_DAP] = &ca53_dap.common.hw,
+ [CLK_CA53_TS] = &ca53_ts.common.hw,
+ [CLK_DJTAG_TCK] = &djtag_tck.common.hw,
+ [CLK_PMU] = &pmu_clk.common.hw,
+ [CLK_PMU_26M] = &pmu_26m.common.hw,
+ [CLK_DEBOUNCE] = &debounce_clk.common.hw,
+ [CLK_OTG2_REF] = &otg2_ref.common.hw,
+ [CLK_USB3_REF] = &usb3_ref.common.hw,
+ [CLK_AP_AXI] = &ap_axi.common.hw,
+ [CLK_AP_APB] = &ap_apb.common.hw,
+ [CLK_AHB_VSP] = &ahb_vsp.common.hw,
+ [CLK_AHB_DISP] = &ahb_disp.common.hw,
+ [CLK_AHB_CAM] = &ahb_cam.common.hw,
+ [CLK_MIPI_CSI0_EB] = &mipi_csi0_eb.common.hw,
+ [CLK_MIPI_CSI1_EB] = &mipi_csi1_eb.common.hw,
+ [CLK_USB3_EB] = &usb3_eb.common.hw,
+ [CLK_USB3_SUSPEND_EB] = &usb3_suspend.common.hw,
+ [CLK_USB3_REF_EB] = &usb3_ref_eb.common.hw,
+ [CLK_DMA_EB] = &dma_eb.common.hw,
+ [CLK_SDIO0_EB] = &sdio0_eb.common.hw,
+ [CLK_SDIO1_EB] = &sdio1_eb.common.hw,
+ [CLK_SDIO2_EB] = &sdio2_eb.common.hw,
+ [CLK_EMMC_EB] = &emmc_eb.common.hw,
+ [CLK_ROM_EB] = &rom_eb.common.hw,
+ [CLK_BUSMON_EB] = &busmon_eb.common.hw,
+ [CLK_CC63S_EB] = &cc63s_eb.common.hw,
+ [CLK_CC63P_EB] = &cc63p_eb.common.hw,
+ [CLK_CE0_EB] = &ce0_eb.common.hw,
+ [CLK_CE1_EB] = &ce1_eb.common.hw,
+ [CLK_AVS_LIT_EB] = &avs_lit_eb.common.hw,
+ [CLK_AVS_BIG_EB] = &avs_big_eb.common.hw,
+ [CLK_AP_INTC5_EB] = &ap_intc5_eb.common.hw,
+ [CLK_GPIO_EB] = &gpio_eb.common.hw,
+ [CLK_PWM0_EB] = &pwm0_eb.common.hw,
+ [CLK_PWM1_EB] = &pwm1_eb.common.hw,
+ [CLK_PWM2_EB] = &pwm2_eb.common.hw,
+ [CLK_PWM3_EB] = &pwm3_eb.common.hw,
+ [CLK_KPD_EB] = &kpd_eb.common.hw,
+ [CLK_AON_SYS_EB] = &aon_sys_eb.common.hw,
+ [CLK_AP_SYS_EB] = &ap_sys_eb.common.hw,
+ [CLK_AON_TMR_EB] = &aon_tmr_eb.common.hw,
+ [CLK_AP_TMR0_EB] = &ap_tmr0_eb.common.hw,
+ [CLK_EFUSE_EB] = &efuse_eb.common.hw,
+ [CLK_EIC_EB] = &eic_eb.common.hw,
+ [CLK_PUB1_REG_EB] = &pub1_reg_eb.common.hw,
+ [CLK_ADI_EB] = &adi_eb.common.hw,
+ [CLK_AP_INTC0_EB] = &ap_intc0_eb.common.hw,
+ [CLK_AP_INTC1_EB] = &ap_intc1_eb.common.hw,
+ [CLK_AP_INTC2_EB] = &ap_intc2_eb.common.hw,
+ [CLK_AP_INTC3_EB] = &ap_intc3_eb.common.hw,
+ [CLK_AP_INTC4_EB] = &ap_intc4_eb.common.hw,
+ [CLK_SPLK_EB] = &splk_eb.common.hw,
+ [CLK_MSPI_EB] = &mspi_eb.common.hw,
+ [CLK_PUB0_REG_EB] = &pub0_reg_eb.common.hw,
+ [CLK_PIN_EB] = &pin_eb.common.hw,
+ [CLK_AON_CKG_EB] = &aon_ckg_eb.common.hw,
+ [CLK_GPU_EB] = &gpu_eb.common.hw,
+ [CLK_APCPU_TS0_EB] = &apcpu_ts0_eb.common.hw,
+ [CLK_APCPU_TS1_EB] = &apcpu_ts1_eb.common.hw,
+ [CLK_DAP_EB] = &dap_eb.common.hw,
+ [CLK_I2C_EB] = &i2c_eb.common.hw,
+ [CLK_PMU_EB] = &pmu_eb.common.hw,
+ [CLK_THM_EB] = &thm_eb.common.hw,
+ [CLK_AUX0_EB] = &aux0_eb.common.hw,
+ [CLK_AUX1_EB] = &aux1_eb.common.hw,
+ [CLK_AUX2_EB] = &aux2_eb.common.hw,
+ [CLK_PROBE_EB] = &probe_eb.common.hw,
+ [CLK_GPU0_AVS_EB] = &gpu0_avs_eb.common.hw,
+ [CLK_GPU1_AVS_EB] = &gpu1_avs_eb.common.hw,
+ [CLK_APCPU_WDG_EB] = &apcpu_wdg_eb.common.hw,
+ [CLK_AP_TMR1_EB] = &ap_tmr1_eb.common.hw,
+ [CLK_AP_TMR2_EB] = &ap_tmr2_eb.common.hw,
+ [CLK_DISP_EMC_EB] = &disp_emc_eb.common.hw,
+ [CLK_ZIP_EMC_EB] = &zip_emc_eb.common.hw,
+ [CLK_GSP_EMC_EB] = &gsp_emc_eb.common.hw,
+ [CLK_OSC_AON_EB] = &osc_aon_eb.common.hw,
+ [CLK_LVDS_TRX_EB] = &lvds_trx_eb.common.hw,
+ [CLK_LVDS_TCXO_EB] = &lvds_tcxo_eb.common.hw,
+ [CLK_MDAR_EB] = &mdar_eb.common.hw,
+ [CLK_RTC4M0_CAL_EB] = &rtc4m0_cal_eb.common.hw,
+ [CLK_RCT100M_CAL_EB] = &rct100m_cal_eb.common.hw,
+ [CLK_DJTAG_EB] = &djtag_eb.common.hw,
+ [CLK_MBOX_EB] = &mbox_eb.common.hw,
+ [CLK_AON_DMA_EB] = &aon_dma_eb.common.hw,
+ [CLK_DBG_EMC_EB] = &dbg_emc_eb.common.hw,
+ [CLK_LVDS_PLL_DIV_EN] = &lvds_pll_div_en.common.hw,
+ [CLK_DEF_EB] = &def_eb.common.hw,
+ [CLK_AON_APB_RSV0] = &aon_apb_rsv0.common.hw,
+ [CLK_ORP_JTAG_EB] = &orp_jtag_eb.common.hw,
+ [CLK_VSP_EB] = &vsp_eb.common.hw,
+ [CLK_CAM_EB] = &cam_eb.common.hw,
+ [CLK_DISP_EB] = &disp_eb.common.hw,
+ [CLK_DBG_AXI_IF_EB] = &dbg_axi_if_eb.common.hw,
+ [CLK_AGCP_IIS0_EB] = &agcp_iis0_eb.common.hw,
+ [CLK_AGCP_IIS1_EB] = &agcp_iis1_eb.common.hw,
+ [CLK_AGCP_IIS2_EB] = &agcp_iis2_eb.common.hw,
+ [CLK_AGCP_IIS3_EB] = &agcp_iis3_eb.common.hw,
+ [CLK_AGCP_UART_EB] = &agcp_uart_eb.common.hw,
+ [CLK_AGCP_DMACP_EB] = &agcp_dmacp_eb.common.hw,
+ [CLK_AGCP_DMAAP_EB] = &agcp_dmaap_eb.common.hw,
+ [CLK_AGCP_ARC48K_EB] = &agcp_arc48k_eb.common.hw,
+ [CLK_AGCP_SRC44P1K_EB] = &agcp_src44p1k_eb.common.hw,
+ [CLK_AGCP_MCDT_EB] = &agcp_mcdt_eb.common.hw,
+ [CLK_AGCP_VBCIFD_EB] = &agcp_vbcifd_eb.common.hw,
+ [CLK_AGCP_VBC_EB] = &agcp_vbc_eb.common.hw,
+ [CLK_AGCP_SPINLOCK_EB] = &agcp_spinlock_eb.common.hw,
+ [CLK_AGCP_ICU_EB] = &agcp_icu_eb.common.hw,
+ [CLK_AGCP_AP_ASHB_EB] = &agcp_ap_ashb_eb.common.hw,
+ [CLK_AGCP_CP_ASHB_EB] = &agcp_cp_ashb_eb.common.hw,
+ [CLK_AGCP_AUD_EB] = &agcp_aud_eb.common.hw,
+ [CLK_AGCP_AUDIF_EB] = &agcp_audif_eb.common.hw,
+ [CLK_VSP_DEC_EB] = &vsp_dec_eb.common.hw,
+ [CLK_VSP_CKG_EB] = &vsp_ckg_eb.common.hw,
+ [CLK_VSP_MMU_EB] = &vsp_mmu_eb.common.hw,
+ [CLK_VSP_ENC_EB] = &vsp_enc_eb.common.hw,
+ [CLK_VPP_EB] = &vpp_eb.common.hw,
+ [CLK_VSP_26M_EB] = &vsp_26m_eb.common.hw,
+ [CLK_VSP_AXI_GATE] = &vsp_axi_gate.common.hw,
+ [CLK_VSP_ENC_GATE] = &vsp_enc_gate.common.hw,
+ [CLK_VPP_AXI_GATE] = &vpp_axi_gate.common.hw,
+ [CLK_VSP_BM_GATE] = &vsp_bm_gate.common.hw,
+ [CLK_VSP_ENC_BM_GATE] = &vsp_enc_bm_gate.common.hw,
+ [CLK_VPP_BM_GATE] = &vpp_bm_gate.common.hw,
+ [CLK_DCAM0_EB] = &dcam0_eb.common.hw,
+ [CLK_DCAM1_EB] = &dcam1_eb.common.hw,
+ [CLK_ISP0_EB] = &isp0_eb.common.hw,
+ [CLK_CSI0_EB] = &csi0_eb.common.hw,
+ [CLK_CSI1_EB] = &csi1_eb.common.hw,
+ [CLK_JPG0_EB] = &jpg0_eb.common.hw,
+ [CLK_JPG1_EB] = &jpg1_eb.common.hw,
+ [CLK_CAM_CKG_EB] = &cam_ckg_eb.common.hw,
+ [CLK_CAM_MMU_EB] = &cam_mmu_eb.common.hw,
+ [CLK_ISP1_EB] = &isp1_eb.common.hw,
+ [CLK_CPP_EB] = &cpp_eb.common.hw,
+ [CLK_MMU_PF_EB] = &mmu_pf_eb.common.hw,
+ [CLK_ISP2_EB] = &isp2_eb.common.hw,
+ [CLK_DCAM2ISP_IF_EB] = &dcam2isp_if_eb.common.hw,
+ [CLK_ISP2DCAM_IF_EB] = &isp2dcam_if_eb.common.hw,
+ [CLK_ISP_LCLK_EB] = &isp_lclk_eb.common.hw,
+ [CLK_ISP_ICLK_EB] = &isp_iclk_eb.common.hw,
+ [CLK_ISP_MCLK_EB] = &isp_mclk_eb.common.hw,
+ [CLK_ISP_PCLK_EB] = &isp_pclk_eb.common.hw,
+ [CLK_ISP_ISP2DCAM_EB] = &isp_isp2dcam_eb.common.hw,
+ [CLK_DCAM0_IF_EB] = &dcam0_if_eb.common.hw,
+ [CLK_CLK26M_IF_EB] = &clk26m_if_eb.common.hw,
+ [CLK_CPHY0_GATE] = &cphy0_gate.common.hw,
+ [CLK_MIPI_CSI0_GATE] = &mipi_csi0_gate.common.hw,
+ [CLK_CPHY1_GATE] = &cphy1_gate.common.hw,
+ [CLK_MIPI_CSI1] = &mipi_csi1.common.hw,
+ [CLK_DCAM0_AXI_GATE] = &dcam0_axi_gate.common.hw,
+ [CLK_DCAM1_AXI_GATE] = &dcam1_axi_gate.common.hw,
+ [CLK_SENSOR0_GATE] = &sensor0_gate.common.hw,
+ [CLK_SENSOR1_GATE] = &sensor1_gate.common.hw,
+ [CLK_JPG0_AXI_GATE] = &jpg0_axi_gate.common.hw,
+ [CLK_GPG1_AXI_GATE] = &gpg1_axi_gate.common.hw,
+ [CLK_ISP0_AXI_GATE] = &isp0_axi_gate.common.hw,
+ [CLK_ISP1_AXI_GATE] = &isp1_axi_gate.common.hw,
+ [CLK_ISP2_AXI_GATE] = &isp2_axi_gate.common.hw,
+ [CLK_CPP_AXI_GATE] = &cpp_axi_gate.common.hw,
+ [CLK_D0_IF_AXI_GATE] = &d0_if_axi_gate.common.hw,
+ [CLK_D2I_IF_AXI_GATE] = &d2i_if_axi_gate.common.hw,
+ [CLK_I2D_IF_AXI_GATE] = &i2d_if_axi_gate.common.hw,
+ [CLK_SPARE_AXI_GATE] = &spare_axi_gate.common.hw,
+ [CLK_SENSOR2_GATE] = &sensor2_gate.common.hw,
+ [CLK_D0IF_IN_D_EN] = &d0if_in_d_en.common.hw,
+ [CLK_D1IF_IN_D_EN] = &d1if_in_d_en.common.hw,
+ [CLK_D0IF_IN_D2I_EN] = &d0if_in_d2i_en.common.hw,
+ [CLK_D1IF_IN_D2I_EN] = &d1if_in_d2i_en.common.hw,
+ [CLK_IA_IN_D2I_EN] = &ia_in_d2i_en.common.hw,
+ [CLK_IB_IN_D2I_EN] = &ib_in_d2i_en.common.hw,
+ [CLK_IC_IN_D2I_EN] = &ic_in_d2i_en.common.hw,
+ [CLK_IA_IN_I_EN] = &ia_in_i_en.common.hw,
+ [CLK_IB_IN_I_EN] = &ib_in_i_en.common.hw,
+ [CLK_IC_IN_I_EN] = &ic_in_i_en.common.hw,
+ [CLK_DISPC0_EB] = &dispc0_eb.common.hw,
+ [CLK_DISPC1_EB] = &dispc1_eb.common.hw,
+ [CLK_DISPC_MMU_EB] = &dispc_mmu_eb.common.hw,
+ [CLK_GSP0_EB] = &gsp0_eb.common.hw,
+ [CLK_GSP1_EB] = &gsp1_eb.common.hw,
+ [CLK_GSP0_MMU_EB] = &gsp0_mmu_eb.common.hw,
+ [CLK_GSP1_MMU_EB] = &gsp1_mmu_eb.common.hw,
+ [CLK_DSI0_EB] = &dsi0_eb.common.hw,
+ [CLK_DSI1_EB] = &dsi1_eb.common.hw,
+ [CLK_DISP_CKG_EB] = &disp_ckg_eb.common.hw,
+ [CLK_DISP_GPU_EB] = &disp_gpu_eb.common.hw,
+ [CLK_GPU_MTX_EB] = &gpu_mtx_eb.common.hw,
+ [CLK_GSP_MTX_EB] = &gsp_mtx_eb.common.hw,
+ [CLK_TMC_MTX_EB] = &tmc_mtx_eb.common.hw,
+ [CLK_DISPC_MTX_EB] = &dispc_mtx_eb.common.hw,
+ [CLK_DPHY0_GATE] = &dphy0_gate.common.hw,
+ [CLK_DPHY1_GATE] = &dphy1_gate.common.hw,
+ [CLK_GSP0_A_GATE] = &gsp0_a_gate.common.hw,
+ [CLK_GSP1_A_GATE] = &gsp1_a_gate.common.hw,
+ [CLK_GSP0_F_GATE] = &gsp0_f_gate.common.hw,
+ [CLK_GSP1_F_GATE] = &gsp1_f_gate.common.hw,
+ [CLK_D_MTX_F_GATE] = &d_mtx_f_gate.common.hw,
+ [CLK_D_MTX_A_GATE] = &d_mtx_a_gate.common.hw,
+ [CLK_D_NOC_F_GATE] = &d_noc_f_gate.common.hw,
+ [CLK_D_NOC_A_GATE] = &d_noc_a_gate.common.hw,
+ [CLK_GSP_MTX_F_GATE] = &gsp_mtx_f_gate.common.hw,
+ [CLK_GSP_MTX_A_GATE] = &gsp_mtx_a_gate.common.hw,
+ [CLK_GSP_NOC_F_GATE] = &gsp_noc_f_gate.common.hw,
+ [CLK_GSP_NOC_A_GATE] = &gsp_noc_a_gate.common.hw,
+ [CLK_DISPM0IDLE_GATE] = &dispm0idle_gate.common.hw,
+ [CLK_GSPM0IDLE_GATE] = &gspm0idle_gate.common.hw,
+ [CLK_SIM0_EB] = &sim0_eb.common.hw,
+ [CLK_IIS0_EB] = &iis0_eb.common.hw,
+ [CLK_IIS1_EB] = &iis1_eb.common.hw,
+ [CLK_IIS2_EB] = &iis2_eb.common.hw,
+ [CLK_IIS3_EB] = &iis3_eb.common.hw,
+ [CLK_SPI0_EB] = &spi0_eb.common.hw,
+ [CLK_SPI1_EB] = &spi1_eb.common.hw,
+ [CLK_SPI2_EB] = &spi2_eb.common.hw,
+ [CLK_I2C0_EB] = &i2c0_eb.common.hw,
+ [CLK_I2C1_EB] = &i2c1_eb.common.hw,
+ [CLK_I2C2_EB] = &i2c2_eb.common.hw,
+ [CLK_I2C3_EB] = &i2c3_eb.common.hw,
+ [CLK_I2C4_EB] = &i2c4_eb.common.hw,
+ [CLK_I2C5_EB] = &i2c5_eb.common.hw,
+ [CLK_UART0_EB] = &uart0_eb.common.hw,
+ [CLK_UART1_EB] = &uart1_eb.common.hw,
+ [CLK_UART2_EB] = &uart2_eb.common.hw,
+ [CLK_UART3_EB] = &uart3_eb.common.hw,
+ [CLK_UART4_EB] = &uart4_eb.common.hw,
+ [CLK_AP_CKG_EB] = &ap_ckg_eb.common.hw,
+ [CLK_SPI3_EB] = &spi3_eb.common.hw,
+ },
+ .num = CLK_NUMBER_SC9860,
+};
+
+static const struct sprd_ccu_desc sc9860_ccu_desc = {
+ .ccu_clks = sc9860_ccu_clks,
+ .num_ccu_clks = ARRAY_SIZE(sc9860_ccu_clks),
+
+ .hw_clks = &sc9860_hw_clks,
+};
+
+static void __init sc9860_ccu_init(struct device_node *node,
+ const struct sprd_ccu_desc *desc)
+{
+ void __iomem *base;
+ int i, count;
+ struct resource res;
+ struct ccu_addr_map *sc9860_maps;
+
+ count = of_property_count_u64_elems(node, "reg");
+ if (count <= 0) {
+ pr_err("%s: no reg properties found for %s\n",
+ __func__, of_node_full_name(node));
+ return;
+ }
+ count = count / 2;
+
+ sc9860_maps = kcalloc(count, sizeof(*sc9860_maps), GFP_KERNEL);
+ if (!sc9860_maps)
+ return;
+
+ for (i = 0; i < count; i++) {
+ if (of_address_to_resource(node, i, &res)) {
+ pr_err("%s: wrong reg[%d] found for %s\n",
+ __func__, i, of_node_full_name(node));
+ goto unmap_maps;
+ }
+
+ base = ioremap(res.start, resource_size(&res));
+ if (IS_ERR(base)) {
+ pr_err("%s: clock[%s] ioremap failed!\n",
+ __func__, node->full_name);
+ goto unmap_maps;
+ }
+
+ sc9860_maps[i].phy = res.start & 0xffff0000;
+ sc9860_maps[i].virt = base;
+ }
+
+ if (sprd_ccu_probe(node, sc9860_maps, count, desc))
+ goto unmap_maps;
+
+
+ kfree(sc9860_maps);
+ pr_info("%u SC9860 clocks have been registered now.\n",
+ CLK_NUMBER_SC9860);
+ return;
+
+unmap_maps:
+ while (--i >= 0)
+ iounmap(sc9860_maps[i].virt);
+ kfree(sc9860_maps);
+}
+
+static void __init sc9860_ccu_setup(struct device_node *node)
+{
+ sc9860_ccu_init(node, &sc9860_ccu_desc);
+}
+CLK_OF_DECLARE(sc9860_ccu, "sprd,sc9860-ccu", sc9860_ccu_setup);
diff --git a/drivers/clk/sprd/ccu-sc9860.h b/drivers/clk/sprd/ccu-sc9860.h
new file mode 100644
index 0000000..643b0d6
--- /dev/null
+++ b/drivers/clk/sprd/ccu-sc9860.h
@@ -0,0 +1,379 @@
+/*
+ * Spreatrum clock pll driver head file
+ *
+ * Copyright (C) 2015~2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _CCU_SC9860_H_
+#define _CCU_SC9860_H_
+
+enum ccu_index {
+ CLK_FAC_4M = 0,
+ CLK_FAC_2M,
+ CLK_FAC_1M,
+ CLK_FAC_250K = 3,
+ CLK_FAC_RPLL0_26M,
+ CLK_FAC_RPLL1_26M,
+ CLK_FAC_RCO25M,
+ CLK_FAC_RCO4M,
+ CLK_FAC_RCO2M,
+ CLK_FAC_3K2,
+ CLK_FAC_1K,
+ CLK_RPLL0_GATE, /* GATE clock */
+ CLK_RPLL1_GATE,
+ CLK_MPLL0_GATE,
+ CLK_MPLL1_GATE,
+ CLK_DPLL0_GATE,
+ CLK_DPLL1_GATE,
+ CLK_GPLL_GATE,
+ CLK_CPPLL_GATE,
+ CLK_LTEPLL0_GATE,
+ CLK_LTEPLL1_GATE,
+ CLK_TWPLL_GATE,
+ CLK_SDIO0_2X_EN,
+ CLK_SDIO0_1X_EN,
+ CLK_SDIO1_2X_EN,
+ CLK_SDIO1_1X_EN,
+ CLK_SDIO2_2X_EN,
+ CLK_SDIO2_1X_EN,
+ CLK_EMMC_1X_EN,
+ CLK_EMMC_2X_EN,
+ CLK_RPLL0, /* PLL clock */
+ CLK_RPLL1,
+ CLK_MPLL0,
+ CLK_MPLL1,
+ CLK_DPLL0,
+ CLK_DPLL1,
+ CLK_GPLL,
+ CLK_CPPLL,
+ CLK_LTEPLL0,
+ CLK_LTEPLL1,
+ CLK_TWPLL,
+ CLK_GPLL_42M5, /* PLL fix factor clock */
+ CLK_TWPLL_768M,
+ CLK_TWPLL_384M,
+ CLK_TWPLL_192M,
+ CLK_TWPLL_96M,
+ CLK_TWPLL_48M,
+ CLK_TWPLL_24M,
+ CLK_TWPLL_12M,
+ CLK_TWPLL_512M,
+ CLK_TWPLL_256M,
+ CLK_TWPLL_128M,
+ CLK_TWPLL_64M,
+ CLK_TWPLL_307M2,
+ CLK_TWPLL_153M6,
+ CLK_TWPLL_76M8,
+ CLK_TWPLL_51M2,
+ CLK_TWPLL_38M4,
+ CLK_TWPLL_19M2,
+ CLK_L0_614M4,
+ CLK_L0_409M6, /* 60 */
+ CLK_L0_38M,
+ CLK_L1_38M,
+ CLK_RPLL0_192M,
+ CLK_RPLL0_96M,
+ CLK_RPLL0_48M,
+ CLK_RPLL1_468M,
+ CLK_RPLL1_192M,
+ CLK_RPLL1_96M,
+ CLK_RPLL1_64M,
+ CLK_RPLL1_48M,
+ CLK_DPLL0_50M,
+ CLK_DPLL1_50M,
+ CLK_CPPLL_50M,
+ CLK_M0_39M,
+ CLK_M1_63M,
+ CLK_AON_APB,
+ CLK_AUX0,
+ CLK_AUX1,
+ CLK_AUX2,
+ CLK_PROBE,
+ CLK_SP_AHB,
+ CLK_CCI,
+ CLK_GIC,
+ CLK_CSSYS,
+ CLK_SDIO0_2X,
+ CLK_SDIO1_2X,
+ CLK_SDIO2_2X,
+ CLK_EMMC_2X,
+ CLK_UART0,
+ CLK_UART1,
+ CLK_UART2,
+ CLK_UART3,
+ CLK_UART4,
+ CLK_I2C0,
+ CLK_I2C1,
+ CLK_I2C2,
+ CLK_I2C3,
+ CLK_I2C4,
+ CLK_I2C5,
+ CLK_SPI0,
+ CLK_SPI1,
+ CLK_SPI2,
+ CLK_SPI3,
+ CLK_IIS0,
+ CLK_IIS1,
+ CLK_IIS2,
+ CLK_IIS3,
+ CLK_LIT_MCU,
+ CLK_BIG_MCU,
+ CLK_GPU,
+ CLK_VSP,
+ CLK_VSP_ENC,
+ CLK_DISPC0_DPI,
+ CLK_DISPC1_DPI,
+ CLK_SENSOR0,
+ CLK_SENSOR1,
+ CLK_SENSOR2,
+ CLK_SDIO0_1X,
+ CLK_SDIO1_1X,
+ CLK_SDIO2_1X,
+ CLK_EMMC_1X,
+ CLK_ADI, /* MUX clock */
+ CLK_PWM0,
+ CLK_PWM1,
+ CLK_PWM2,
+ CLK_PWM3,
+ CLK_EFUSE,
+ CLK_CM3_UART0,
+ CLK_CM3_UART1,
+ CLK_THM,
+ CLK_CM3_I2C0,
+ CLK_CM3_I2C1,
+ CLK_CM4_SPI,
+ CLK_AON_I2C,
+ CLK_AVS,
+ CLK_CA53_DAP,
+ CLK_CA53_TS,
+ CLK_DJTAG_TCK,
+ CLK_PMU,
+ CLK_PMU_26M,
+ CLK_DEBOUNCE,
+ CLK_OTG2_REF,
+ CLK_USB3_REF,
+ CLK_AP_AXI,
+ CLK_AP_APB,
+ CLK_AHB_VSP,
+ CLK_AHB_DISP,
+ CLK_AHB_CAM,
+ CLK_MIPI_CSI0_EB,
+ CLK_MIPI_CSI1_EB,
+ CLK_USB3_EB,
+ CLK_USB3_SUSPEND_EB,
+ CLK_USB3_REF_EB,
+ CLK_DMA_EB,
+ CLK_SDIO0_EB,
+ CLK_SDIO1_EB,
+ CLK_SDIO2_EB,
+ CLK_EMMC_EB,
+ CLK_ROM_EB,
+ CLK_BUSMON_EB,
+ CLK_CC63S_EB,
+ CLK_CC63P_EB,
+ CLK_CE0_EB,
+ CLK_CE1_EB,
+ CLK_AVS_LIT_EB,
+ CLK_AVS_BIG_EB,
+ CLK_AP_INTC5_EB,
+ CLK_GPIO_EB,
+ CLK_PWM0_EB,
+ CLK_PWM1_EB,
+ CLK_PWM2_EB,
+ CLK_PWM3_EB,
+ CLK_KPD_EB,
+ CLK_AON_SYS_EB,
+ CLK_AP_SYS_EB,
+ CLK_AON_TMR_EB,
+ CLK_AP_TMR0_EB,
+ CLK_EFUSE_EB,
+ CLK_EIC_EB,
+ CLK_PUB1_REG_EB,
+ CLK_ADI_EB,
+ CLK_AP_INTC0_EB,
+ CLK_AP_INTC1_EB,
+ CLK_AP_INTC2_EB,
+ CLK_AP_INTC3_EB,
+ CLK_AP_INTC4_EB,
+ CLK_SPLK_EB,
+ CLK_MSPI_EB,
+ CLK_PUB0_REG_EB,
+ CLK_PIN_EB,
+ CLK_AON_CKG_EB,
+ CLK_GPU_EB,
+ CLK_APCPU_TS0_EB,
+ CLK_APCPU_TS1_EB,
+ CLK_DAP_EB,
+ CLK_I2C_EB,
+ CLK_PMU_EB,
+ CLK_THM_EB,
+ CLK_AUX0_EB,
+ CLK_AUX1_EB,
+ CLK_AUX2_EB,
+ CLK_PROBE_EB,
+ CLK_GPU0_AVS_EB,
+ CLK_GPU1_AVS_EB,
+ CLK_APCPU_WDG_EB,
+ CLK_AP_TMR1_EB,
+ CLK_AP_TMR2_EB,
+ CLK_DISP_EMC_EB,
+ CLK_ZIP_EMC_EB,
+ CLK_GSP_EMC_EB,
+ CLK_OSC_AON_EB,
+ CLK_LVDS_TRX_EB,
+ CLK_LVDS_TCXO_EB,
+ CLK_MDAR_EB,
+ CLK_RTC4M0_CAL_EB,
+ CLK_RCT100M_CAL_EB,
+ CLK_DJTAG_EB,
+ CLK_MBOX_EB,
+ CLK_AON_DMA_EB,
+ CLK_DBG_EMC_EB,
+ CLK_LVDS_PLL_DIV_EN,
+ CLK_DEF_EB,
+ CLK_AON_APB_RSV0,
+ CLK_ORP_JTAG_EB,
+ CLK_VSP_EB,
+ CLK_CAM_EB,
+ CLK_DISP_EB,
+ CLK_DBG_AXI_IF_EB,
+ CLK_AGCP_IIS0_EB,
+ CLK_AGCP_IIS1_EB,
+ CLK_AGCP_IIS2_EB,
+ CLK_AGCP_IIS3_EB,
+ CLK_AGCP_UART_EB,
+ CLK_AGCP_DMACP_EB,
+ CLK_AGCP_DMAAP_EB,
+ CLK_AGCP_ARC48K_EB,
+ CLK_AGCP_SRC44P1K_EB,
+ CLK_AGCP_MCDT_EB,
+ CLK_AGCP_VBCIFD_EB,
+ CLK_AGCP_VBC_EB,
+ CLK_AGCP_SPINLOCK_EB,
+ CLK_AGCP_ICU_EB,
+ CLK_AGCP_AP_ASHB_EB,
+ CLK_AGCP_CP_ASHB_EB,
+ CLK_AGCP_AUD_EB,
+ CLK_AGCP_AUDIF_EB,
+ CLK_VSP_DEC_EB,
+ CLK_VSP_CKG_EB,
+ CLK_VSP_MMU_EB,
+ CLK_VSP_ENC_EB,
+ CLK_VPP_EB,
+ CLK_VSP_26M_EB,
+ CLK_VSP_AXI_GATE,
+ CLK_VSP_ENC_GATE,
+ CLK_VPP_AXI_GATE,
+ CLK_VSP_BM_GATE,
+ CLK_VSP_ENC_BM_GATE,
+ CLK_VPP_BM_GATE,
+ CLK_DCAM0_EB,
+ CLK_DCAM1_EB,
+ CLK_ISP0_EB,
+ CLK_CSI0_EB,
+ CLK_CSI1_EB,
+ CLK_JPG0_EB,
+ CLK_JPG1_EB,
+ CLK_CAM_CKG_EB,
+ CLK_CAM_MMU_EB,
+ CLK_ISP1_EB,
+ CLK_CPP_EB,
+ CLK_MMU_PF_EB,
+ CLK_ISP2_EB,
+ CLK_DCAM2ISP_IF_EB,
+ CLK_ISP2DCAM_IF_EB,
+ CLK_ISP_LCLK_EB,
+ CLK_ISP_ICLK_EB,
+ CLK_ISP_MCLK_EB,
+ CLK_ISP_PCLK_EB,
+ CLK_ISP_ISP2DCAM_EB,
+ CLK_DCAM0_IF_EB,
+ CLK_CLK26M_IF_EB,
+ CLK_CPHY0_GATE,
+ CLK_MIPI_CSI0_GATE,
+ CLK_CPHY1_GATE,
+ CLK_MIPI_CSI1,
+ CLK_DCAM0_AXI_GATE,
+ CLK_DCAM1_AXI_GATE,
+ CLK_SENSOR0_GATE,
+ CLK_SENSOR1_GATE,
+ CLK_JPG0_AXI_GATE,
+ CLK_GPG1_AXI_GATE,
+ CLK_ISP0_AXI_GATE,
+ CLK_ISP1_AXI_GATE,
+ CLK_ISP2_AXI_GATE,
+ CLK_CPP_AXI_GATE,
+ CLK_D0_IF_AXI_GATE,
+ CLK_D2I_IF_AXI_GATE,
+ CLK_I2D_IF_AXI_GATE,
+ CLK_SPARE_AXI_GATE,
+ CLK_SENSOR2_GATE,
+ CLK_D0IF_IN_D_EN,
+ CLK_D1IF_IN_D_EN,
+ CLK_D0IF_IN_D2I_EN,
+ CLK_D1IF_IN_D2I_EN,
+ CLK_IA_IN_D2I_EN,
+ CLK_IB_IN_D2I_EN,
+ CLK_IC_IN_D2I_EN,
+ CLK_IA_IN_I_EN,
+ CLK_IB_IN_I_EN,
+ CLK_IC_IN_I_EN,
+ CLK_DISPC0_EB,
+ CLK_DISPC1_EB,
+ CLK_DISPC_MMU_EB,
+ CLK_GSP0_EB,
+ CLK_GSP1_EB,
+ CLK_GSP0_MMU_EB,
+ CLK_GSP1_MMU_EB,
+ CLK_DSI0_EB,
+ CLK_DSI1_EB,
+ CLK_DISP_CKG_EB,
+ CLK_DISP_GPU_EB,
+ CLK_GPU_MTX_EB,
+ CLK_GSP_MTX_EB,
+ CLK_TMC_MTX_EB,
+ CLK_DISPC_MTX_EB,
+ CLK_DPHY0_GATE,
+ CLK_DPHY1_GATE,
+ CLK_GSP0_A_GATE,
+ CLK_GSP1_A_GATE,
+ CLK_GSP0_F_GATE,
+ CLK_GSP1_F_GATE,
+ CLK_D_MTX_F_GATE,
+ CLK_D_MTX_A_GATE,
+ CLK_D_NOC_F_GATE,
+ CLK_D_NOC_A_GATE,
+ CLK_GSP_MTX_F_GATE,
+ CLK_GSP_MTX_A_GATE,
+ CLK_GSP_NOC_F_GATE,
+ CLK_GSP_NOC_A_GATE,
+ CLK_DISPM0IDLE_GATE,
+ CLK_GSPM0IDLE_GATE,
+ CLK_SIM0_EB,
+ CLK_IIS0_EB,
+ CLK_IIS1_EB,
+ CLK_IIS2_EB,
+ CLK_IIS3_EB,
+ CLK_SPI0_EB,
+ CLK_SPI1_EB,
+ CLK_SPI2_EB,
+ CLK_I2C0_EB,
+ CLK_I2C1_EB,
+ CLK_I2C2_EB,
+ CLK_I2C3_EB,
+ CLK_I2C4_EB,
+ CLK_I2C5_EB,
+ CLK_UART0_EB,
+ CLK_UART1_EB,
+ CLK_UART2_EB,
+ CLK_UART3_EB,
+ CLK_UART4_EB,
+ CLK_AP_CKG_EB,
+ CLK_SPI3_EB,
+
+ CLK_NUMBER_SC9860,
+};
+
+#endif
diff --git a/include/dt-bindings/clock/sc9860-ccu.h b/include/dt-bindings/clock/sc9860-ccu.h
new file mode 100644
index 0000000..dd7ccf9
--- /dev/null
+++ b/include/dt-bindings/clock/sc9860-ccu.h
@@ -0,0 +1,19 @@
+/*
+ * Spreadtrum SC9860 platform clocks
+ *
+ * Copyright (C) 2017, Spreadtrum Communications Inc.
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ */
+
+#ifndef _DT_BINDINGS_CLK_SC9860_CCU_H_
+#define _DT_BINDINGS_CLK_SC9860_CCU_H_
+
+#define CLK_FAC_1M 2
+#define CLK_EMMC_2X_EN 29
+#define CLK_L0_409M6 60
+#define CLK_EMMC_2X 88
+#define CLK_EMMC_EB 158
+
+
+#endif /* _DT_BINDINGS_CLK_SC9860_CCU_H_ */
--
2.7.4
Now we have clock driver, so add clock dt for SC9860 platform.
This patch also removed "ext-26m" from whale2.dtsi since it
is described in sc9860-ccu.dtsi.
Signed-off-by: Chunyan Zhang <[email protected]>
---
arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi | 67 ++++++++++++++++++++++++++++++++
arch/arm64/boot/dts/sprd/sc9860.dtsi | 2 +
arch/arm64/boot/dts/sprd/whale2.dtsi | 8 ----
3 files changed, 69 insertions(+), 8 deletions(-)
create mode 100644 arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi
diff --git a/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi b/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi
new file mode 100644
index 0000000..e15bf2d
--- /dev/null
+++ b/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi
@@ -0,0 +1,67 @@
+/*
+ * Spreadtrum SC9860 SoC CCU
+ *
+ * Copyright (C) 2017, Spreadtrum Communications Inc.
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ */
+
+&soc {
+ ext_26m: ext-26m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <26000000>;
+ clock-output-names = "ext-26m";
+ };
+
+ ext_32m_sine0: ext-32m-sine0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32000000>;
+ clock-output-names = "ext-32m-sine0";
+ };
+
+ ext_32m_sine1: ext-32m-sine1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32000000>;
+ clock-output-names = "ext-32m-sine1";
+ };
+
+ ext_rco_100m: ext-rco-100m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "ext-rco-100m";
+ };
+
+ ext_32k: ext-32k {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "ext-32k";
+ };
+
+ ccu: clk {
+ compatible = "sprd,sc9860-ccu";
+ #clock-cells = <1>;
+ reg = <0 0x20000000 0 0x400>,
+ <0 0x20210000 0 0x3000>,
+ <0 0x402b0000 0 0x4000>,
+ <0 0x402d0000 0 0x400>,
+ <0 0x402e0000 0 0x4000>,
+ <0 0x40400000 0 0x400>,
+ <0 0x40880000 0 0x400>,
+ <0 0x415e0000 0 0x400>,
+ <0 0x60200000 0 0x400>,
+ <0 0x61000000 0 0x400>,
+ <0 0x61100000 0 0x3000>,
+ <0 0x62000000 0 0x4000>,
+ <0 0x62100000 0 0x4000>,
+ <0 0x63000000 0 0x400>,
+ <0 0x63100000 0 0x3000>,
+ <0 0x70b00000 0 0x3000>;
+ clocks = <&ext_26m>, <&ext_rco_100m>, <&ext_32k>;
+ clock-names = "ext-26m", "ext-rco-100m", "ext-32k";
+ };
+};
diff --git a/arch/arm64/boot/dts/sprd/sc9860.dtsi b/arch/arm64/boot/dts/sprd/sc9860.dtsi
index 7b7d8ce..10ff7c6 100644
--- a/arch/arm64/boot/dts/sprd/sc9860.dtsi
+++ b/arch/arm64/boot/dts/sprd/sc9860.dtsi
@@ -7,7 +7,9 @@
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sc9860-ccu.h>
#include "whale2.dtsi"
+#include "sc9860-ccu.dtsi"
/ {
cpus {
diff --git a/arch/arm64/boot/dts/sprd/whale2.dtsi b/arch/arm64/boot/dts/sprd/whale2.dtsi
index 7c217c5..9d69b84 100644
--- a/arch/arm64/boot/dts/sprd/whale2.dtsi
+++ b/arch/arm64/boot/dts/sprd/whale2.dtsi
@@ -59,13 +59,5 @@
status = "disabled";
};
};
-
- };
-
- ext_26m: ext-26m {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <26000000>;
- clock-output-names = "ext_26m";
};
};
--
2.7.4
Hi Chunyan,
[auto build test ERROR on clk/clk-next]
[also build test ERROR on v4.12-rc5 next-20170616]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Chunyan-Zhang/add-clock-driver-for-Spreadtrum-platforms/20170619-031614
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64
All errors (new ones prefixed by >>):
>> drivers/clk/sunxi-ng/built-in.o:(.rodata+0x16080): multiple definition of `ccu_gate_ops'
drivers/clk/sprd/built-in.o:(.rodata+0x160): first defined here
drivers/clk/sunxi-ng/built-in.o: In function `ccu_mux_helper_set_parent':
>> ccu_frac.c:(.text+0x2ac8): multiple definition of `ccu_mux_helper_set_parent'
drivers/clk/sprd/built-in.o:ccu_composite.c:(.text+0x810): first defined here
>> drivers/clk/sunxi-ng/built-in.o:(.rodata+0x162c0): multiple definition of `ccu_mux_ops'
drivers/clk/sprd/built-in.o:(.rodata+0x260): first defined here
drivers/clk/sunxi-ng/built-in.o: In function `ccu_mux_helper_get_parent':
>> ccu_frac.c:(.text+0x2950): multiple definition of `ccu_mux_helper_get_parent'
drivers/clk/sprd/built-in.o:ccu_composite.c:(.text+0x650): first defined here
>> drivers/clk/sunxi-ng/built-in.o:(.rodata+0x15fc0): multiple definition of `ccu_div_ops'
drivers/clk/sprd/built-in.o:(.rodata+0x360): first defined here
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
On 06/18, Chunyan Zhang wrote:
> diff --git a/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi b/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi
> new file mode 100644
> index 0000000..e15bf2d
> --- /dev/null
> +++ b/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi
> @@ -0,0 +1,67 @@
> +/*
> + * Spreadtrum SC9860 SoC CCU
> + *
> + * Copyright (C) 2017, Spreadtrum Communications Inc.
> + *
> + * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> + */
> +
> +&soc {
> + ext_26m: ext-26m {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <26000000>;
> + clock-output-names = "ext-26m";
> + };
> +
> + ext_32m_sine0: ext-32m-sine0 {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <32000000>;
> + clock-output-names = "ext-32m-sine0";
> + };
> +
> + ext_32m_sine1: ext-32m-sine1 {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <32000000>;
> + clock-output-names = "ext-32m-sine1";
> + };
> +
> + ext_rco_100m: ext-rco-100m {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <100000000>;
> + clock-output-names = "ext-rco-100m";
> + };
> +
> + ext_32k: ext-32k {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <32768>;
> + clock-output-names = "ext-32k";
> + };
These should all be outside of the soc node as they're probably
on the board and not the SoC? The hint is that they don't have a
reg property.
> +
> + ccu: clk {
clock-controller is a more standard node name.
> + compatible = "sprd,sc9860-ccu";
> + #clock-cells = <1>;
> + reg = <0 0x20000000 0 0x400>,
> + <0 0x20210000 0 0x3000>,
> + <0 0x402b0000 0 0x4000>,
> + <0 0x402d0000 0 0x400>,
> + <0 0x402e0000 0 0x4000>,
> + <0 0x40400000 0 0x400>,
> + <0 0x40880000 0 0x400>,
> + <0 0x415e0000 0 0x400>,
> + <0 0x60200000 0 0x400>,
> + <0 0x61000000 0 0x400>,
> + <0 0x61100000 0 0x3000>,
> + <0 0x62000000 0 0x4000>,
> + <0 0x62100000 0 0x4000>,
> + <0 0x63000000 0 0x400>,
> + <0 0x63100000 0 0x3000>,
> + <0 0x70b00000 0 0x3000>;
There are a lot of reg properties here. Perhaps there needs to be
different nodes for the different clock controllers in this SoC?
> + clocks = <&ext_26m>, <&ext_rco_100m>, <&ext_32k>;
> + clock-names = "ext-26m", "ext-rco-100m", "ext-32k";
> + };
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/18, Chunyan Zhang wrote:
> In the last cycle, the patches support Whale2 sc9860 mobile chip have been
> merged. This patchset adds clock driver which is used on almost all
> Spreadtrum SoCs.
>
> This is a rewrite of Spreadtrum's original clock driver[1] according to the
> comments[2] from Stephen Boyd.
>
> This series also adds Spreadtrum clock binding documentation and devicetree
> data.
>
> Any comments would be greatly appreciated.
Overall it seems to copy quite a bit of code from sunxi-ng, which
is OK, but if that's just copy/paste + replace some names then
perhaps we should consolidate the two implementations into one
that both SoCs can use.
Also, is there any reason why we can't use a platform device
driver for this instead of the DT probing mechanism? That is more
preferred method of probing clk controllers.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/18, Chunyan Zhang wrote:
> Added Spreadtrum's clock driver common structure and registration code.
>
> Signed-off-by: Chunyan Zhang <[email protected]>
> ---
> drivers/clk/Makefile | 1 +
> drivers/clk/sprd/Makefile | 3 ++
> drivers/clk/sprd/ccu_common.c | 78 +++++++++++++++++++++++++++++++++++++
> drivers/clk/sprd/ccu_common.h | 90 +++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 172 insertions(+)
> create mode 100644 drivers/clk/sprd/Makefile
> create mode 100644 drivers/clk/sprd/ccu_common.c
> create mode 100644 drivers/clk/sprd/ccu_common.h
>
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index c19983a..1d62721 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -81,6 +81,7 @@ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
> obj-$(CONFIG_ARCH_SIRF) += sirf/
> obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
> obj-$(CONFIG_PLAT_SPEAR) += spear/
> +obj-$(CONFIG_ARCH_SPRD) += sprd/
> obj-$(CONFIG_ARCH_STI) += st/
> obj-$(CONFIG_ARCH_SUNXI) += sunxi/
> obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/
> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
> new file mode 100644
> index 0000000..8f802b2
> --- /dev/null
> +++ b/drivers/clk/sprd/Makefile
> @@ -0,0 +1,3 @@
> +ifneq ($(CONFIG_OF),)
> +obj-y += ccu_common.o
> +endif
I'd prefer a Kconfig for SPRD clk drivers instead of this
CONFIG_OF check. Then we can compile test the sprd code in
configurations that don't have CONFIG_ARCH_SPRD set too.
> diff --git a/drivers/clk/sprd/ccu_common.c b/drivers/clk/sprd/ccu_common.c
> new file mode 100644
> index 0000000..911f4ba
> --- /dev/null
> +++ b/drivers/clk/sprd/ccu_common.c
> @@ -0,0 +1,78 @@
> +/*
> + * Spreadtrum clock infrastructure
> + *
> + * Copyright (C) 2017 Spreadtrum, Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#include "ccu_common.h"
> +
> +static inline void __iomem *ccu_find_base(struct ccu_addr_map *maps,
> + unsigned int num, unsigned int reg)
> +{
> + int i;
> +
> + for (i = 0; i < num; i++)
> + if ((reg & 0xffff0000) == maps[i].phy)
What is this?
> + return maps[i].virt;
> +
> + return 0;
> +}
> +
> +int sprd_ccu_probe(struct device_node *node, struct ccu_addr_map *maps,
> + unsigned int count, const struct sprd_ccu_desc *desc)
> +{
> + int i, ret = 0;
> + struct ccu_common *cclk;
> + struct clk_hw *hw;
> +
> + for (i = 0; i < desc->num_ccu_clks; i++) {
> + cclk = desc->ccu_clks[i];
> + if (!cclk)
> + continue;
> +
> + cclk->base = ccu_find_base(maps, count, cclk->reg);
> + if (!cclk->base) {
> + pr_err("%s: No mapped address found for clock(0x%x)\n",
> + __func__, cclk->reg);
> + return -EINVAL;
> + }
> + cclk->reg = cclk->reg & 0xffff;
> + }
> +
> + for (i = 0; i < desc->hw_clks->num; i++) {
> +
> + hw = desc->hw_clks->hws[i];
> +
> + if (!hw)
> + continue;
> +
> + ret = clk_hw_register(NULL, hw);
> + if (ret) {
> + pr_err("Couldn't register clock %d - %s\n",
> + i, hw->init->name);
> + goto err_clk_unreg;
> + }
> + }
> +
> + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
> + desc->hw_clks);
> + if (ret) {
> + pr_err("Failed to add clock provider.\n");
> + goto err_clk_unreg;
> + }
> +
> + return 0;
> +
> +err_clk_unreg:
> + while (--i >= 0) {
> + hw = desc->hw_clks->hws[i];
> + if (!hw)
> + continue;
> +
> + clk_hw_unregister(hw);
> + }
> +
> + return ret;
> +}
> diff --git a/drivers/clk/sprd/ccu_common.h b/drivers/clk/sprd/ccu_common.h
> new file mode 100644
> index 0000000..ff07772
> --- /dev/null
> +++ b/drivers/clk/sprd/ccu_common.h
> @@ -0,0 +1,90 @@
> +/*
> + * Spreadtrum clock infrastructure
> + *
> + * Copyright (C) 2017 Spreadtrum, Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#ifndef _CCU_COMMON_H_
> +#define _CCU_COMMON_H_
> +
> +#include <linux/clk-provider.h>
> +
> +struct device_node;
> +
> +#define CLK_HW_INIT_NO_PARENT(_name, _ops, _flags) \
> + (&(struct clk_init_data) { \
> + .flags = _flags, \
> + .name = _name, \
> + .parent_names = NULL, \
> + .num_parents = 0, \
> + .ops = _ops, \
> + })
> +
> +#define CLK_HW_INIT(_name, _parent, _ops, _flags) \
> + (&(struct clk_init_data) { \
> + .flags = _flags, \
> + .name = _name, \
> + .parent_names = (const char *[]) { _parent }, \
> + .num_parents = 1, \
> + .ops = _ops, \
> + })
> +
> +#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \
> + (&(struct clk_init_data) { \
> + .flags = _flags, \
> + .name = _name, \
> + .parent_names = _parents, \
> + .num_parents = ARRAY_SIZE(_parents), \
> + .ops = _ops, \
> + })
> +
> +#define CLK_FIXED_FACTOR(_struct, _name, _parent, \
> + _div, _mult, _flags) \
> + struct clk_fixed_factor _struct = { \
> + .div = _div, \
> + .mult = _mult, \
> + .hw.init = CLK_HW_INIT(_name, \
> + _parent, \
> + &clk_fixed_factor_ops, \
> + _flags), \
> + }
> +
> +struct ccu_common {
> + void __iomem *base;
> + u32 reg;
> + spinlock_t *lock;
> + struct clk_hw hw;
> +};
> +
> +struct ccu_addr_map {
> + phys_addr_t phy;
> + void __iomem *virt;
> +};
> +
> +static inline u32 ccu_readl(struct ccu_common *common)
> +{
> + return readl(common->base + common->reg);
> +}
> +
> +static inline void ccu_writel(u32 val, struct ccu_common *common)
> +{
> + writel(val, common->base + common->reg);
> +}
> +
> +static inline struct ccu_common *hw_to_ccu_common(struct clk_hw *hw)
> +{
> + return container_of(hw, struct ccu_common, hw);
> +}
> +
> +struct sprd_ccu_desc {
> + struct ccu_common **ccu_clks;
> + unsigned long num_ccu_clks;
> + struct clk_hw_onecell_data *hw_clks;
> +};
> +
> +int sprd_ccu_probe(struct device_node *node, struct ccu_addr_map *maps,
> + unsigned int count, const struct sprd_ccu_desc *desc);
> +
> +#endif /* _CCU_COMMON_H_ */
Do you call them CCUs internally? I thought CCU was a sunxi
thing, so it may make more sense to call it whatever you call the
clock controller on your hardware.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/18, Chunyan Zhang wrote:
> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
> index 8f802b2..333e2b2 100644
> --- a/drivers/clk/sprd/Makefile
> +++ b/drivers/clk/sprd/Makefile
> @@ -1,3 +1,3 @@
> ifneq ($(CONFIG_OF),)
> -obj-y += ccu_common.o
> +obj-y += ccu_common.o ccu_gate.o
Can this be built as a module?
> endif
> diff --git a/drivers/clk/sprd/ccu_gate.c b/drivers/clk/sprd/ccu_gate.c
> new file mode 100644
> index 0000000..3d27615
> --- /dev/null
> +++ b/drivers/clk/sprd/ccu_gate.c
> @@ -0,0 +1,102 @@
> +/*
> + * Spreadtrum gate clock driver
> + *
> + * Copyright (C) 2017 Spreadtrum, Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#include <linux/clk-provider.h>
> +
> +#include "ccu_gate.h"
> +
> +DEFINE_SPINLOCK(gate_lock);
This variable name is not very unique for debugging lockdep
reports. Probably needs 'sprd' in the name.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/18, Chunyan Zhang wrote:
> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
> index 83232e5..c593a93 100644
> --- a/drivers/clk/sprd/Makefile
> +++ b/drivers/clk/sprd/Makefile
> @@ -1,3 +1,3 @@
> ifneq ($(CONFIG_OF),)
> -obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o
> +obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o ccu_pll.o
> endif
> diff --git a/drivers/clk/sprd/ccu_pll.c b/drivers/clk/sprd/ccu_pll.c
> new file mode 100644
> index 0000000..6c908e4
> --- /dev/null
> +++ b/drivers/clk/sprd/ccu_pll.c
> @@ -0,0 +1,241 @@
> +/*
> + * Spreadtrum pll clock driver
> + *
> + * Copyright (C) 2015~2017 Spreadtrum, Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/clk.h>
Is this include used? Should be clk-provider?
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +
> +#include "ccu_pll.h"
> +
> +#define CCU_PLL_1M 1000000
> +#define CCU_PLL_10M (CCU_PLL_1M * 10)
> +
> +#define pindex(pll, member) \
> + (pll->factors[member].shift / (8 * sizeof(pll->regs[0])))
> +
> +#define pshift(pll, member) \
> + (pll->factors[member].shift % (8 * sizeof(pll->regs[0])))
> +
> +#define pwidth(pll, member) \
> + pll->factors[member].width
> +
> +#define pmask(pll, member) \
> + ((pwidth(pll, member)) ? \
> + GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
> + pshift(pll, member)) : 0)
> +
> +#define pinternal(pll, cfg, member) \
> + (cfg[pindex(pll, member)] & pmask(pll, member))
> +
> +#define pinternal_val(pll, cfg, member) \
> + (pinternal(pll, cfg, member) >> pshift(pll, member))
> +
> +static unsigned long pll_get_refin_rate(struct ccu_pll *pll)
pll could be const?
> +{
> + u8 shift, index, refin_id = 3;
> + u32 mask;
> + const unsigned long refin[4] = { 2, 4, 13, 26 };
> +
> + if (pwidth(pll, PLL_REFIN)) {
> + index = pindex(pll, PLL_REFIN);
> + shift = pshift(pll, PLL_REFIN);
> + mask = pmask(pll, PLL_REFIN);
> + refin_id = (ccu_pll_readl(pll, index) & mask) >> shift;
> + if (refin_id > 3)
> + refin_id = 3;
> + }
> +
> + return refin[refin_id];
> +}
> +
> +static u8 pll_get_ibias(unsigned long rate, const u64 *table)
> +{
> + u64 i;
> + u8 num = table[0];
> +
> + for (i = 0; i < num; i++)
> + if (rate <= table[i + 1])
> + break;
> +
> + return i == num ? num - 1 : i;
> +}
> +
> +static unsigned long ccu_pll_helper_recalc_rate(struct ccu_pll *pll,
> + unsigned long parent_rate)
> +{
> + unsigned long rate, refin, k1, k2;
> + unsigned long kint = 0, nint;
> + u32 reg_num = pll->regs[0];
> + u32 *cfg;
> + u32 i;
> + u32 mask;
> +
> + cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
> + if (!cfg)
> + return -ENOMEM;
> +
> + for (i = 0; i < reg_num; i++)
> + cfg[i] = ccu_pll_readl(pll, i);
> +
> + refin = pll_get_refin_rate(pll);
> +
> + if (pinternal(pll, cfg, PLL_PREDIV))
> + refin = refin * 2;
> +
> + if (pwidth(pll, PLL_POSTDIV) &&
> + ((pll->fflag == 1 && pinternal(pll, cfg, PLL_POSTDIV)) ||
> + (!pll->fflag && !pinternal(pll, cfg, PLL_POSTDIV))))
> + refin = refin / 2;
> +
> + if (!pinternal(pll, cfg, PLL_DIV_S))
> + rate = refin * pinternal_val(pll, cfg, PLL_N) * CCU_PLL_10M;
> + else {
Please include braces on the if as well when another branch has them.
> + nint = pinternal_val(pll, cfg, PLL_NINT);
> + if (pinternal(pll, cfg, PLL_SDM_EN))
> + kint = pinternal_val(pll, cfg, PLL_KINT);
> +
> + mask = pmask(pll, PLL_KINT);
> +#ifdef CONFIG_64BIT
> + k1 = 1000;
> + k2 = 1000;
> + rate = DIV_ROUND_CLOSEST(refin * kint * k1,
> + ((mask >> __ffs(mask)) + 1)) *
> + k2 + refin * nint * CCU_PLL_1M;
> +#else
> + k1 = 100;
> + k2 = 10000;
> + i = pwidth(pll, PLL_KINT);
> + i = i < 21 ? 0 : i - 21;
> + rate = DIV_ROUND_CLOSEST(refin * (kint >> i) * k1,
> + ((mask >> (__ffs(mask) + i)) + 1)) *
> + k2 + refin * nint * CCU_PLL_1M;
> +#endif
> + }
> +
> + return rate;
> +}
> +
> +static int ccu_pll_helper_set_rate(struct ccu_pll *pll,
> + unsigned long rate,
> + unsigned long parent_rate)
> +{
> + u32 mask, shift, width, ibias_val, index, kint, nint;
> + u32 reg_num = pll->regs[0], i = 0;
> + unsigned long refin, fvco = rate;
> + struct reg_cfg *cfg;
> +
> + cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
> + if (!cfg)
> + return -ENOMEM;
> +
> + refin = pll_get_refin_rate(pll);
> +
> + mask = pmask(pll, PLL_PREDIV);
> + index = pindex(pll, PLL_PREDIV);
> + width = pwidth(pll, PLL_PREDIV);
> + if (width && (ccu_pll_readl(pll, index) & mask))
> + refin = refin * 2;
> +
> + mask = pmask(pll, PLL_POSTDIV);
> + index = pindex(pll, PLL_POSTDIV);
> + width = pwidth(pll, PLL_POSTDIV);
> + cfg[index].msk = mask;
> + if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
> + (pll->fflag == 0 && fvco > pll->fvco)))
> + cfg[index].val |= mask;
> +
> + if (width && fvco <= pll->fvco)
> + fvco = fvco * 2;
> +
> + mask = pmask(pll, PLL_DIV_S);
> + index = pindex(pll, PLL_DIV_S);
> + cfg[index].val |= mask;
> + cfg[index].msk |= mask;
> +
> + mask = pmask(pll, PLL_SDM_EN);
> + index = pindex(pll, PLL_SDM_EN);
> + cfg[index].val |= mask;
> + cfg[index].msk |= mask;
> +
> + nint = fvco/(refin * CCU_PLL_1M);
> +
> + mask = pmask(pll, PLL_NINT);
> + index = pindex(pll, PLL_NINT);
> + shift = pshift(pll, PLL_NINT);
> + cfg[index].val |= (nint << shift) & mask;
> + cfg[index].msk |= mask;
> +
> + mask = pmask(pll, PLL_KINT);
> + index = pindex(pll, PLL_KINT);
> + width = pwidth(pll, PLL_KINT);
> + shift = pshift(pll, PLL_KINT);
> +#ifndef CONFIG_64BIT
> + i = width < 21 ? 0 : i - 21;
> +#endif
What's this? Why do we depend on CONFIG_64BIT?
> + kint = DIV_ROUND_CLOSEST(((fvco - refin * nint * CCU_PLL_1M)/10000) *
> + ((mask >> (shift + i)) + 1), refin * 100) << i;
> + cfg[index].val |= (kint << shift) & mask;
> + cfg[index].msk |= mask;
> +
> + ibias_val = pll_get_ibias(fvco, pll->itable);
> +
> + mask = pmask(pll, PLL_IBIAS);
> + index = pindex(pll, PLL_IBIAS);
> + shift = pshift(pll, PLL_IBIAS);
> + cfg[index].val |= ibias_val << shift & mask;
> + cfg[index].msk |= mask;
> +
> + for (i = 0; i < reg_num; i++) {
> + if (cfg[i].msk)
> + ccu_pll_writel(pll, i, cfg[i].val, cfg[i].msk);
> + }
> +
Are we waiting for the writel() to go through above? If so we
need a readl() of the same register to make sure the write has
completed before delaying.
> + udelay(pll->udelay);
> +
> + return 0;
> +}
> +
> +static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct ccu_pll *pll = hw_to_ccu_pll(hw);
> +
> + return ccu_pll_helper_recalc_rate(pll, parent_rate);
> +}
> +
> +static int ccu_pll_set_rate(struct clk_hw *hw,
> + unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct ccu_pll *pll = hw_to_ccu_pll(hw);
> +
> + return ccu_pll_helper_set_rate(pll, rate, parent_rate);
> +}
> +
> +static int ccu_pll_clk_prepare(struct clk_hw *hw)
> +{
> + struct ccu_pll *pll = hw_to_ccu_pll(hw);
> +
> + udelay(pll->udelay);
> +
> + return 0;
> +}
> +
> +static long ccu_pll_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + return rate;
> +}
> +
> +const struct clk_ops ccu_pll_ops = {
> + .prepare = ccu_pll_clk_prepare,
> + .recalc_rate = ccu_pll_recalc_rate,
> + .round_rate = ccu_pll_round_rate,
> + .set_rate = ccu_pll_set_rate,
> +};
> diff --git a/drivers/clk/sprd/ccu_pll.h b/drivers/clk/sprd/ccu_pll.h
> new file mode 100644
> index 0000000..66fe5d1
> --- /dev/null
> +++ b/drivers/clk/sprd/ccu_pll.h
> @@ -0,0 +1,123 @@
> +/*
> + * Spreadtrum clock pll configurations
> + *
> + * Copyright (C) 2015~2017 Spreadtrum, Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> +
> +#ifndef _CCU_PLL_H_
> +#define _CCU_PLL_H_
> +
> +#include "ccu_common.h"
> +
> +struct reg_cfg {
> + u32 val;
> + u32 msk;
> +};
> +
> +struct ccu_bit_field {
> + u8 shift;
> + u8 width;
> +};
> +
> +enum {
> + PLL_LOCK_DONE = 0,
Drop the = 0 please unless it's needed for something?
> + PLL_DIV_S,
> + PLL_MOD_EN,
> + PLL_SDM_EN,
> + PLL_REFIN,
> + PLL_IBIAS,
> + PLL_N,
> + PLL_NINT,
> + PLL_KINT,
> + PLL_PREDIV,
> + PLL_POSTDIV,
> +
> + PLL_FACT_MAX
> +};
> +
> +/*
> + * struct ccu_pll - defination of adjustable pll clock
s/defination/definition/
> + *
> + * @reg: registers used to set the configuration of pll clock,
> + * reg[0] shows how many registers this pll clock uses.
> + * @itable: pll ibias table, itable[0] means how many items this
> + * table includes
> + * @udelay delay time after setting rate
> + * @factors used to calculate the pll clock rate
> + * @fvco: fvco threshold rate
> + * @fflag: fvco flag
> + */
> +struct ccu_pll {
> + const u32 *regs;
> + const u64 *itable;
> + u16 udelay;
> + const struct ccu_bit_field *factors;
Does this change across the different PLLs? Would be nice to not
need the bit field thing.
> + u64 fvco;
> + u16 fflag;
> +
> + struct ccu_common common;
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/18, Chunyan Zhang wrote:
> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
> index c593a93..0d90b40 100644
> --- a/drivers/clk/sprd/Makefile
> +++ b/drivers/clk/sprd/Makefile
> @@ -1,3 +1,4 @@
> ifneq ($(CONFIG_OF),)
> obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o ccu_pll.o
> +obj-y += ccu-sc9860.o
And a Kconfig for this SoC specific driver.
> endif
> diff --git a/drivers/clk/sprd/ccu-sc9860.c b/drivers/clk/sprd/ccu-sc9860.c
> new file mode 100644
> index 0000000..6cd4dc5
> --- /dev/null
> +++ b/drivers/clk/sprd/ccu-sc9860.c
> +
> +static CLK_FIXED_FACTOR(fac_4m, "fac-4m", "ext-26m",
> + 6, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_2m, "fac-2m", "ext-26m",
> + 13, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_1m, "fac-1m", "ext-26m",
> + 26, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_250k, "fac-250k", "ext-26m",
> + 104, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_rpll0_26m, "rpll0-26m", "ext-26m",
> + 1, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_rpll1_26m, "rpll1-26m", "ext-26m",
> + 1, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_rco_25m, "rco-25m", "ext-rc0-100m",
> + 4, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_rco_4m, "rco-4m", "ext-rc0-100m",
> + 25, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_rco_2m, "rco-2m", "ext-rc0-100m",
> + 50, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_3k2, "fac-3k2", "ext-32k",
> + 10, 1, CLK_IS_BASIC);
> +static CLK_FIXED_FACTOR(fac_1k, "fac-1k", "ext-32k",
> + 32, 1, CLK_IS_BASIC);
> +
> +#define SC9860_GATE_FLAGS (CLK_IGNORE_UNUSED | CLK_IS_BASIC)
No CLK_IS_BASIC. Why is everything marked as CLK_IGNORE_UNUSED?
> +static SPRD_CCU_GATE(rpll0_gate, "rpll0-gate", "ext-26m", 0x402b016c,
> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(rpll1_gate, "rpll1-gate", "ext-26m", 0x402b016c,
> + 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(mpll0_gate, "mpll0-gate", "ext-26m", 0x402b00b0,
> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(mpll1_gate, "mpll1-gate", "ext-26m", 0x402b00b0,
> + 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(dpll0_gate, "dpll0-gate", "ext-26m", 0x402b00b4,
> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(dpll1_gate, "dpll1-gate", "ext-26m", 0x402b00b4,
> + 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(gpll_gate, "gpll-gate", "ext-26m", 0x402b032c,
> + 0x1000, BIT(0), SC9860_GATE_FLAGS,
> + CLK_GATE_SET_TO_DISABLE);
> +static SPRD_CCU_GATE(cppll_gate, "cppll-gate", "ext-26m", 0x402b02b4,
> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(ltepll0_gate, "ltepll0-gate", "ext-26m", 0x402b00b8,
> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(ltepll1_gate, "ltepll1-gate", "ext-26m", 0x402b010c,
> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE(twpll_gate, "twpll-gate", "ext-26m", 0x402b00bc,
> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE_NO_PARENT(sdio0_2x_en, "sdio0-2x-en", 0x402e013c,
> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE_NO_PARENT(sdio0_1x_en, "sdio0-1x-en", 0x402e013c,
> + 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE_NO_PARENT(sdio1_2x_en, "sdio1-2x-en", 0x402e013c,
> + 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE_NO_PARENT(sdio1_1x_en, "sdio1-1x-en", 0x402e013c,
> + 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE_NO_PARENT(sdio2_2x_en, "sdio2-2x-en", 0x402e013c,
> + 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE_NO_PARENT(sdio2_1x_en, "sdio2-1x-en", 0x402e013c,
> + 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE_NO_PARENT(emmc_1x_en, "emmc-1x-en", 0x402e013c,
> + 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
> +static SPRD_CCU_GATE_NO_PARENT(emmc_2x_en, "emmc-2x-en", 0x402e013c,
> + 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
> +
> +/* GPLL/LPLL/DPLL/RPLL/CPLL */
> +static const u64 const itable1[4] = {3, 780000000, 988000000, 1196000000};
> +
> +/* TWPLL/MPLL0/MPLL1 */
> +static const u64 itable2[4] = {3, 1638000000, 2080000000, 2600000000UL};
> +
> +static const struct ccu_bit_field const f_rpll[PLL_FACT_MAX] = {
> + { .shift = 0, .width = 1 }, /* lock_done */
> + { .shift = 3, .width = 1 }, /* div_s */
> + { .shift = 80, .width = 1 }, /* mod_en */
Are they even shifts? Or offsets from some base? I have to go
back and read the other patch.
> + { .shift = 81, .width = 1 }, /* sdm_en */
> + { .shift = 0, .width = 0 }, /* refin */
> + { .shift = 14, .width = 2 }, /* ibias */
> + { .shift = 16, .width = 7 }, /* n */
> + { .shift = 4, .width = 7 }, /* nint */
> + { .shift = 32, .width = 23}, /* kint */
> + { .shift = 0, .width = 0 }, /* prediv */
> + { .shift = 0, .width = 0 }, /* postdiv */
> +};
> +static const u32 const regs_rpll0[4] = { 3, 0x44, 0x48, 0x4c };
> +static SPRD_CCU_PLL_WITH_ITABLE(rpll0_clk, "rpll0", "rpll0-gate", 0x40400044,
> + regs_rpll0, itable1, 200, f_rpll);
> +
> +static const u32 const regs_rpll1[4] = { 3, 0x50, 0x54, 0x58 };
> +static SPRD_CCU_PLL_WITH_ITABLE(rpll1_clk, "rpll1", "rpll1-gate", 0x40400050,
> + regs_rpll1, itable1, 200, f_rpll);
> +
> +static const struct ccu_bit_field const f_mpll0[PLL_FACT_MAX] = {
[...]
> diff --git a/include/dt-bindings/clock/sc9860-ccu.h b/include/dt-bindings/clock/sc9860-ccu.h
> new file mode 100644
> index 0000000..dd7ccf9
> --- /dev/null
> +++ b/include/dt-bindings/clock/sc9860-ccu.h
> @@ -0,0 +1,19 @@
> +/*
> + * Spreadtrum SC9860 platform clocks
> + *
> + * Copyright (C) 2017, Spreadtrum Communications Inc.
> + *
> + * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_SC9860_CCU_H_
> +#define _DT_BINDINGS_CLK_SC9860_CCU_H_
> +
> +#define CLK_FAC_1M 2
> +#define CLK_EMMC_2X_EN 29
> +#define CLK_L0_409M6 60
> +#define CLK_EMMC_2X 88
> +#define CLK_EMMC_EB 158
Why are only a handful exposed in the header file? Not exposing
everything is mostly a maintenance nightmare right now.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
Hi Stephen,
On 20 June 2017 at 09:25, Stephen Boyd <[email protected]> wrote:
> On 06/18, Chunyan Zhang wrote:
>> In the last cycle, the patches support Whale2 sc9860 mobile chip have been
>> merged. This patchset adds clock driver which is used on almost all
>> Spreadtrum SoCs.
>>
>> This is a rewrite of Spreadtrum's original clock driver[1] according to the
>> comments[2] from Stephen Boyd.
>>
>> This series also adds Spreadtrum clock binding documentation and devicetree
>> data.
>>
>> Any comments would be greatly appreciated.
>
> Overall it seems to copy quite a bit of code from sunxi-ng, which
> is OK, but if that's just copy/paste + replace some names then
> perhaps we should consolidate the two implementations into one
> that both SoCs can use.
>
OK, will try.
> Also, is there any reason why we can't use a platform device
> driver for this instead of the DT probing mechanism? That is more
> preferred method of probing clk controllers.
>From what I have known on ARM platforms, device drivers cannot
recognize out which SoC the driver is running on, assume that the
device on different SoC has some differences. To make one only kernel
Image can be used on all SoCs of Spreadtrum, we selected the way of
loading different dtb for each SoC.
Actually, I haven't understood the merits of moving more clk things to
driver from DT, could you please introduce more about that?
Many appreciated,
Chunyan
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
On 20 June 2017 at 09:29, Stephen Boyd <[email protected]> wrote:
> On 06/18, Chunyan Zhang wrote:
>> Added Spreadtrum's clock driver common structure and registration code.
>>
>> Signed-off-by: Chunyan Zhang <[email protected]>
>> ---
>> drivers/clk/Makefile | 1 +
>> drivers/clk/sprd/Makefile | 3 ++
>> drivers/clk/sprd/ccu_common.c | 78 +++++++++++++++++++++++++++++++++++++
>> drivers/clk/sprd/ccu_common.h | 90 +++++++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 172 insertions(+)
>> create mode 100644 drivers/clk/sprd/Makefile
>> create mode 100644 drivers/clk/sprd/ccu_common.c
>> create mode 100644 drivers/clk/sprd/ccu_common.h
>>
>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>> index c19983a..1d62721 100644
>> --- a/drivers/clk/Makefile
>> +++ b/drivers/clk/Makefile
>> @@ -81,6 +81,7 @@ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
>> obj-$(CONFIG_ARCH_SIRF) += sirf/
>> obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
>> obj-$(CONFIG_PLAT_SPEAR) += spear/
>> +obj-$(CONFIG_ARCH_SPRD) += sprd/
>> obj-$(CONFIG_ARCH_STI) += st/
>> obj-$(CONFIG_ARCH_SUNXI) += sunxi/
>> obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/
>> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
>> new file mode 100644
>> index 0000000..8f802b2
>> --- /dev/null
>> +++ b/drivers/clk/sprd/Makefile
>> @@ -0,0 +1,3 @@
>> +ifneq ($(CONFIG_OF),)
>> +obj-y += ccu_common.o
>> +endif
>
> I'd prefer a Kconfig for SPRD clk drivers instead of this
> CONFIG_OF check. Then we can compile test the sprd code in
> configurations that don't have CONFIG_ARCH_SPRD set too.
Ok, make sense, will address this in the next version.
>
>> diff --git a/drivers/clk/sprd/ccu_common.c b/drivers/clk/sprd/ccu_common.c
>> new file mode 100644
>> index 0000000..911f4ba
>> --- /dev/null
>> +++ b/drivers/clk/sprd/ccu_common.c
>> @@ -0,0 +1,78 @@
>> +/*
>> + * Spreadtrum clock infrastructure
>> + *
>> + * Copyright (C) 2017 Spreadtrum, Inc.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0
>> + */
>> +
>> +#include "ccu_common.h"
>> +
>> +static inline void __iomem *ccu_find_base(struct ccu_addr_map *maps,
>> + unsigned int num, unsigned int reg)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < num; i++)
>> + if ((reg & 0xffff0000) == maps[i].phy)
>
> What is this?
You can look at ccu-sc9860.c, different from sunxi-ng, we specify the
whole register address rather than register offset when initializing
Spreadtrum clocks, the high 16 bits is the base address which is
configured in DT, and is mapped in the board clock files like
ccu-sc9860.c, I will write more in commit message to explain this when
cooking next version of the patchset.
>
>> + return maps[i].virt;
>> +
>> + return 0;
>> +}
>> +
>> +int sprd_ccu_probe(struct device_node *node, struct ccu_addr_map *maps,
>> + unsigned int count, const struct sprd_ccu_desc *desc)
>> +{
>> + int i, ret = 0;
>> + struct ccu_common *cclk;
>> + struct clk_hw *hw;
>> +
>> + for (i = 0; i < desc->num_ccu_clks; i++) {
>> + cclk = desc->ccu_clks[i];
>> + if (!cclk)
>> + continue;
>> +
>> + cclk->base = ccu_find_base(maps, count, cclk->reg);
>> + if (!cclk->base) {
>> + pr_err("%s: No mapped address found for clock(0x%x)\n",
>> + __func__, cclk->reg);
>> + return -EINVAL;
>> + }
>> + cclk->reg = cclk->reg & 0xffff;
>> + }
>> +
>> + for (i = 0; i < desc->hw_clks->num; i++) {
>> +
>> + hw = desc->hw_clks->hws[i];
>> +
>> + if (!hw)
>> + continue;
>> +
>> + ret = clk_hw_register(NULL, hw);
>> + if (ret) {
>> + pr_err("Couldn't register clock %d - %s\n",
>> + i, hw->init->name);
>> + goto err_clk_unreg;
>> + }
>> + }
>> +
>> + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
>> + desc->hw_clks);
>> + if (ret) {
>> + pr_err("Failed to add clock provider.\n");
>> + goto err_clk_unreg;
>> + }
>> +
>> + return 0;
>> +
>> +err_clk_unreg:
>> + while (--i >= 0) {
>> + hw = desc->hw_clks->hws[i];
>> + if (!hw)
>> + continue;
>> +
>> + clk_hw_unregister(hw);
>> + }
>> +
>> + return ret;
>> +}
>> diff --git a/drivers/clk/sprd/ccu_common.h b/drivers/clk/sprd/ccu_common.h
>> new file mode 100644
>> index 0000000..ff07772
>> --- /dev/null
>> +++ b/drivers/clk/sprd/ccu_common.h
>> @@ -0,0 +1,90 @@
>> +/*
>> + * Spreadtrum clock infrastructure
>> + *
>> + * Copyright (C) 2017 Spreadtrum, Inc.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0
>> + */
>> +
>> +#ifndef _CCU_COMMON_H_
>> +#define _CCU_COMMON_H_
>> +
>> +#include <linux/clk-provider.h>
>> +
>> +struct device_node;
>> +
>> +#define CLK_HW_INIT_NO_PARENT(_name, _ops, _flags) \
>> + (&(struct clk_init_data) { \
>> + .flags = _flags, \
>> + .name = _name, \
>> + .parent_names = NULL, \
>> + .num_parents = 0, \
>> + .ops = _ops, \
>> + })
>> +
>> +#define CLK_HW_INIT(_name, _parent, _ops, _flags) \
>> + (&(struct clk_init_data) { \
>> + .flags = _flags, \
>> + .name = _name, \
>> + .parent_names = (const char *[]) { _parent }, \
>> + .num_parents = 1, \
>> + .ops = _ops, \
>> + })
>> +
>> +#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \
>> + (&(struct clk_init_data) { \
>> + .flags = _flags, \
>> + .name = _name, \
>> + .parent_names = _parents, \
>> + .num_parents = ARRAY_SIZE(_parents), \
>> + .ops = _ops, \
>> + })
>> +
>> +#define CLK_FIXED_FACTOR(_struct, _name, _parent, \
>> + _div, _mult, _flags) \
>> + struct clk_fixed_factor _struct = { \
>> + .div = _div, \
>> + .mult = _mult, \
>> + .hw.init = CLK_HW_INIT(_name, \
>> + _parent, \
>> + &clk_fixed_factor_ops, \
>> + _flags), \
>> + }
>> +
>> +struct ccu_common {
>> + void __iomem *base;
>> + u32 reg;
>> + spinlock_t *lock;
>> + struct clk_hw hw;
>> +};
>> +
>> +struct ccu_addr_map {
>> + phys_addr_t phy;
>> + void __iomem *virt;
>> +};
>> +
>> +static inline u32 ccu_readl(struct ccu_common *common)
>> +{
>> + return readl(common->base + common->reg);
>> +}
>> +
>> +static inline void ccu_writel(u32 val, struct ccu_common *common)
>> +{
>> + writel(val, common->base + common->reg);
>> +}
>> +
>> +static inline struct ccu_common *hw_to_ccu_common(struct clk_hw *hw)
>> +{
>> + return container_of(hw, struct ccu_common, hw);
>> +}
>> +
>> +struct sprd_ccu_desc {
>> + struct ccu_common **ccu_clks;
>> + unsigned long num_ccu_clks;
>> + struct clk_hw_onecell_data *hw_clks;
>> +};
>> +
>> +int sprd_ccu_probe(struct device_node *node, struct ccu_addr_map *maps,
>> + unsigned int count, const struct sprd_ccu_desc *desc);
>> +
>> +#endif /* _CCU_COMMON_H_ */
>
> Do you call them CCUs internally? I thought CCU was a sunxi
> thing, so it may make more sense to call it whatever you call the
> clock controller on your hardware.
OK, will address that.
Thanks,
Chunyan
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
On 20 June 2017 at 09:31, Stephen Boyd <[email protected]> wrote:
> On 06/18, Chunyan Zhang wrote:
>> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
>> index 8f802b2..333e2b2 100644
>> --- a/drivers/clk/sprd/Makefile
>> +++ b/drivers/clk/sprd/Makefile
>> @@ -1,3 +1,3 @@
>> ifneq ($(CONFIG_OF),)
>> -obj-y += ccu_common.o
>> +obj-y += ccu_common.o ccu_gate.o
>
> Can this be built as a module?
Since most of all Spreadtrum device drivers would depend on if clocks
have been initialized, so we'd prefer to build this into the kernel
image.
>
>> endif
>> diff --git a/drivers/clk/sprd/ccu_gate.c b/drivers/clk/sprd/ccu_gate.c
>> new file mode 100644
>> index 0000000..3d27615
>> --- /dev/null
>> +++ b/drivers/clk/sprd/ccu_gate.c
>> @@ -0,0 +1,102 @@
>> +/*
>> + * Spreadtrum gate clock driver
>> + *
>> + * Copyright (C) 2017 Spreadtrum, Inc.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +
>> +#include "ccu_gate.h"
>> +
>> +DEFINE_SPINLOCK(gate_lock);
>
> This variable name is not very unique for debugging lockdep
> reports. Probably needs 'sprd' in the name.
Ok.
Thank you for your comments,
Chunyan
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
On 20 June 2017 at 09:37, Stephen Boyd <[email protected]> wrote:
> On 06/18, Chunyan Zhang wrote:
>> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
>> index 83232e5..c593a93 100644
>> --- a/drivers/clk/sprd/Makefile
>> +++ b/drivers/clk/sprd/Makefile
>> @@ -1,3 +1,3 @@
>> ifneq ($(CONFIG_OF),)
>> -obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o
>> +obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o ccu_pll.o
>> endif
>> diff --git a/drivers/clk/sprd/ccu_pll.c b/drivers/clk/sprd/ccu_pll.c
>> new file mode 100644
>> index 0000000..6c908e4
>> --- /dev/null
>> +++ b/drivers/clk/sprd/ccu_pll.c
>> @@ -0,0 +1,241 @@
>> +/*
>> + * Spreadtrum pll clock driver
>> + *
>> + * Copyright (C) 2015~2017 Spreadtrum, Inc.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/clk.h>
>
> Is this include used? Should be clk-provider?
Right, will remove it.
>
>> +#include <linux/err.h>
>> +#include <linux/slab.h>
>> +
>> +#include "ccu_pll.h"
>> +
>> +#define CCU_PLL_1M 1000000
>> +#define CCU_PLL_10M (CCU_PLL_1M * 10)
>> +
>> +#define pindex(pll, member) \
>> + (pll->factors[member].shift / (8 * sizeof(pll->regs[0])))
>> +
>> +#define pshift(pll, member) \
>> + (pll->factors[member].shift % (8 * sizeof(pll->regs[0])))
>> +
>> +#define pwidth(pll, member) \
>> + pll->factors[member].width
>> +
>> +#define pmask(pll, member) \
>> + ((pwidth(pll, member)) ? \
>> + GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
>> + pshift(pll, member)) : 0)
>> +
>> +#define pinternal(pll, cfg, member) \
>> + (cfg[pindex(pll, member)] & pmask(pll, member))
>> +
>> +#define pinternal_val(pll, cfg, member) \
>> + (pinternal(pll, cfg, member) >> pshift(pll, member))
>> +
>> +static unsigned long pll_get_refin_rate(struct ccu_pll *pll)
>
> pll could be const?
What this function returns is a factor used to calculate the pll rate
later, I will rename this function in the next iterator.
>
>> +{
>> + u8 shift, index, refin_id = 3;
>> + u32 mask;
>> + const unsigned long refin[4] = { 2, 4, 13, 26 };
>> +
>> + if (pwidth(pll, PLL_REFIN)) {
>> + index = pindex(pll, PLL_REFIN);
>> + shift = pshift(pll, PLL_REFIN);
>> + mask = pmask(pll, PLL_REFIN);
>> + refin_id = (ccu_pll_readl(pll, index) & mask) >> shift;
>> + if (refin_id > 3)
>> + refin_id = 3;
>> + }
>> +
>> + return refin[refin_id];
>> +}
>> +
>> +static u8 pll_get_ibias(unsigned long rate, const u64 *table)
>> +{
>> + u64 i;
>> + u8 num = table[0];
>> +
>> + for (i = 0; i < num; i++)
>> + if (rate <= table[i + 1])
>> + break;
>> +
>> + return i == num ? num - 1 : i;
>> +}
>> +
>> +static unsigned long ccu_pll_helper_recalc_rate(struct ccu_pll *pll,
>> + unsigned long parent_rate)
>> +{
>> + unsigned long rate, refin, k1, k2;
>> + unsigned long kint = 0, nint;
>> + u32 reg_num = pll->regs[0];
>> + u32 *cfg;
>> + u32 i;
>> + u32 mask;
>> +
>> + cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
>> + if (!cfg)
>> + return -ENOMEM;
>> +
>> + for (i = 0; i < reg_num; i++)
>> + cfg[i] = ccu_pll_readl(pll, i);
>> +
>> + refin = pll_get_refin_rate(pll);
>> +
>> + if (pinternal(pll, cfg, PLL_PREDIV))
>> + refin = refin * 2;
>> +
>> + if (pwidth(pll, PLL_POSTDIV) &&
>> + ((pll->fflag == 1 && pinternal(pll, cfg, PLL_POSTDIV)) ||
>> + (!pll->fflag && !pinternal(pll, cfg, PLL_POSTDIV))))
>> + refin = refin / 2;
>> +
>> + if (!pinternal(pll, cfg, PLL_DIV_S))
>> + rate = refin * pinternal_val(pll, cfg, PLL_N) * CCU_PLL_10M;
>> + else {
>
> Please include braces on the if as well when another branch has them.
Sure.
>
>> + nint = pinternal_val(pll, cfg, PLL_NINT);
>> + if (pinternal(pll, cfg, PLL_SDM_EN))
>> + kint = pinternal_val(pll, cfg, PLL_KINT);
>> +
>> + mask = pmask(pll, PLL_KINT);
>> +#ifdef CONFIG_64BIT
>> + k1 = 1000;
>> + k2 = 1000;
>> + rate = DIV_ROUND_CLOSEST(refin * kint * k1,
>> + ((mask >> __ffs(mask)) + 1)) *
>> + k2 + refin * nint * CCU_PLL_1M;
>> +#else
>> + k1 = 100;
>> + k2 = 10000;
>> + i = pwidth(pll, PLL_KINT);
>> + i = i < 21 ? 0 : i - 21;
>> + rate = DIV_ROUND_CLOSEST(refin * (kint >> i) * k1,
>> + ((mask >> (__ffs(mask) + i)) + 1)) *
>> + k2 + refin * nint * CCU_PLL_1M;
>> +#endif
>> + }
>> +
>> + return rate;
>> +}
>> +
>> +static int ccu_pll_helper_set_rate(struct ccu_pll *pll,
>> + unsigned long rate,
>> + unsigned long parent_rate)
>> +{
>> + u32 mask, shift, width, ibias_val, index, kint, nint;
>> + u32 reg_num = pll->regs[0], i = 0;
>> + unsigned long refin, fvco = rate;
>> + struct reg_cfg *cfg;
>> +
>> + cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
>> + if (!cfg)
>> + return -ENOMEM;
>> +
>> + refin = pll_get_refin_rate(pll);
>> +
>> + mask = pmask(pll, PLL_PREDIV);
>> + index = pindex(pll, PLL_PREDIV);
>> + width = pwidth(pll, PLL_PREDIV);
>> + if (width && (ccu_pll_readl(pll, index) & mask))
>> + refin = refin * 2;
>> +
>> + mask = pmask(pll, PLL_POSTDIV);
>> + index = pindex(pll, PLL_POSTDIV);
>> + width = pwidth(pll, PLL_POSTDIV);
>> + cfg[index].msk = mask;
>> + if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
>> + (pll->fflag == 0 && fvco > pll->fvco)))
>> + cfg[index].val |= mask;
>> +
>> + if (width && fvco <= pll->fvco)
>> + fvco = fvco * 2;
>> +
>> + mask = pmask(pll, PLL_DIV_S);
>> + index = pindex(pll, PLL_DIV_S);
>> + cfg[index].val |= mask;
>> + cfg[index].msk |= mask;
>> +
>> + mask = pmask(pll, PLL_SDM_EN);
>> + index = pindex(pll, PLL_SDM_EN);
>> + cfg[index].val |= mask;
>> + cfg[index].msk |= mask;
>> +
>> + nint = fvco/(refin * CCU_PLL_1M);
>> +
>> + mask = pmask(pll, PLL_NINT);
>> + index = pindex(pll, PLL_NINT);
>> + shift = pshift(pll, PLL_NINT);
>> + cfg[index].val |= (nint << shift) & mask;
>> + cfg[index].msk |= mask;
>> +
>> + mask = pmask(pll, PLL_KINT);
>> + index = pindex(pll, PLL_KINT);
>> + width = pwidth(pll, PLL_KINT);
>> + shift = pshift(pll, PLL_KINT);
>> +#ifndef CONFIG_64BIT
>> + i = width < 21 ? 0 : i - 21;
>> +#endif
>
> What's this? Why do we depend on CONFIG_64BIT?
On 32-bit SoCs, the largest width we can support is limited due to the
limitation of calculation precision.
>
>> + kint = DIV_ROUND_CLOSEST(((fvco - refin * nint * CCU_PLL_1M)/10000) *
>> + ((mask >> (shift + i)) + 1), refin * 100) << i;
>> + cfg[index].val |= (kint << shift) & mask;
>> + cfg[index].msk |= mask;
>> +
>> + ibias_val = pll_get_ibias(fvco, pll->itable);
>> +
>> + mask = pmask(pll, PLL_IBIAS);
>> + index = pindex(pll, PLL_IBIAS);
>> + shift = pshift(pll, PLL_IBIAS);
>> + cfg[index].val |= ibias_val << shift & mask;
>> + cfg[index].msk |= mask;
>> +
>> + for (i = 0; i < reg_num; i++) {
>> + if (cfg[i].msk)
>> + ccu_pll_writel(pll, i, cfg[i].val, cfg[i].msk);
>> + }
>> +
>
> Are we waiting for the writel() to go through above? If so we
> need a readl() of the same register to make sure the write has
> completed before delaying.
After writing these configuration registers, we have to wait a certain
time to make sure the pll has worked as we configured. This depends
on other circuit part, so we use udelay rather than reading the same
register.
>
>> + udelay(pll->udelay);
>> +
>> + return 0;
>> +}
>> +
>> +static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw,
>> + unsigned long parent_rate)
>> +{
>> + struct ccu_pll *pll = hw_to_ccu_pll(hw);
>> +
>> + return ccu_pll_helper_recalc_rate(pll, parent_rate);
>> +}
>> +
>> +static int ccu_pll_set_rate(struct clk_hw *hw,
>> + unsigned long rate,
>> + unsigned long parent_rate)
>> +{
>> + struct ccu_pll *pll = hw_to_ccu_pll(hw);
>> +
>> + return ccu_pll_helper_set_rate(pll, rate, parent_rate);
>> +}
>> +
>> +static int ccu_pll_clk_prepare(struct clk_hw *hw)
>> +{
>> + struct ccu_pll *pll = hw_to_ccu_pll(hw);
>> +
>> + udelay(pll->udelay);
>> +
>> + return 0;
>> +}
>> +
>> +static long ccu_pll_round_rate(struct clk_hw *hw, unsigned long rate,
>> + unsigned long *prate)
>> +{
>> + return rate;
>> +}
>> +
>> +const struct clk_ops ccu_pll_ops = {
>> + .prepare = ccu_pll_clk_prepare,
>> + .recalc_rate = ccu_pll_recalc_rate,
>> + .round_rate = ccu_pll_round_rate,
>> + .set_rate = ccu_pll_set_rate,
>> +};
>> diff --git a/drivers/clk/sprd/ccu_pll.h b/drivers/clk/sprd/ccu_pll.h
>> new file mode 100644
>> index 0000000..66fe5d1
>> --- /dev/null
>> +++ b/drivers/clk/sprd/ccu_pll.h
>> @@ -0,0 +1,123 @@
>> +/*
>> + * Spreadtrum clock pll configurations
>> + *
>> + * Copyright (C) 2015~2017 Spreadtrum, Inc.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0
>> + */
>> +
>> +#ifndef _CCU_PLL_H_
>> +#define _CCU_PLL_H_
>> +
>> +#include "ccu_common.h"
>> +
>> +struct reg_cfg {
>> + u32 val;
>> + u32 msk;
>> +};
>> +
>> +struct ccu_bit_field {
>> + u8 shift;
>> + u8 width;
>> +};
>> +
>> +enum {
>> + PLL_LOCK_DONE = 0,
>
> Drop the = 0 please unless it's needed for something?
OK.
>
>> + PLL_DIV_S,
>> + PLL_MOD_EN,
>> + PLL_SDM_EN,
>> + PLL_REFIN,
>> + PLL_IBIAS,
>> + PLL_N,
>> + PLL_NINT,
>> + PLL_KINT,
>> + PLL_PREDIV,
>> + PLL_POSTDIV,
>> +
>> + PLL_FACT_MAX
>> +};
>> +
>> +/*
>> + * struct ccu_pll - defination of adjustable pll clock
>
> s/defination/definition/
>
>> + *
>> + * @reg: registers used to set the configuration of pll clock,
>> + * reg[0] shows how many registers this pll clock uses.
>> + * @itable: pll ibias table, itable[0] means how many items this
>> + * table includes
>> + * @udelay delay time after setting rate
>> + * @factors used to calculate the pll clock rate
>> + * @fvco: fvco threshold rate
>> + * @fflag: fvco flag
>> + */
>> +struct ccu_pll {
>> + const u32 *regs;
>> + const u64 *itable;
>> + u16 udelay;
>> + const struct ccu_bit_field *factors;
>
> Does this change across the different PLLs? Would be nice to not
Yes, different PLL has diferent bit field arragement, even on the same SoC.
Thanks for your review,
Chunyan
> need the bit field thing.
>
>> + u64 fvco;
>> + u16 fflag;
>> +
>> + struct ccu_common common;
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
Hi Stephen,
On 20 June 2017 at 09:41, Stephen Boyd <[email protected]> wrote:
> On 06/18, Chunyan Zhang wrote:
>> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
>> index c593a93..0d90b40 100644
>> --- a/drivers/clk/sprd/Makefile
>> +++ b/drivers/clk/sprd/Makefile
>> @@ -1,3 +1,4 @@
>> ifneq ($(CONFIG_OF),)
>> obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o ccu_pll.o
>> +obj-y += ccu-sc9860.o
>
> And a Kconfig for this SoC specific driver.
Ok.
>
>> endif
>> diff --git a/drivers/clk/sprd/ccu-sc9860.c b/drivers/clk/sprd/ccu-sc9860.c
>> new file mode 100644
>> index 0000000..6cd4dc5
>> --- /dev/null
>> +++ b/drivers/clk/sprd/ccu-sc9860.c
>> +
>> +static CLK_FIXED_FACTOR(fac_4m, "fac-4m", "ext-26m",
>> + 6, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_2m, "fac-2m", "ext-26m",
>> + 13, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_1m, "fac-1m", "ext-26m",
>> + 26, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_250k, "fac-250k", "ext-26m",
>> + 104, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_rpll0_26m, "rpll0-26m", "ext-26m",
>> + 1, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_rpll1_26m, "rpll1-26m", "ext-26m",
>> + 1, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_rco_25m, "rco-25m", "ext-rc0-100m",
>> + 4, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_rco_4m, "rco-4m", "ext-rc0-100m",
>> + 25, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_rco_2m, "rco-2m", "ext-rc0-100m",
>> + 50, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_3k2, "fac-3k2", "ext-32k",
>> + 10, 1, CLK_IS_BASIC);
>> +static CLK_FIXED_FACTOR(fac_1k, "fac-1k", "ext-32k",
>> + 32, 1, CLK_IS_BASIC);
>> +
>> +#define SC9860_GATE_FLAGS (CLK_IGNORE_UNUSED | CLK_IS_BASIC)
>
> No CLK_IS_BASIC. Why is everything marked as CLK_IGNORE_UNUSED?
Copied from the original implementation :)
But I will do a double check, there'are indeed some clocks which
shouldn't be marked as CLK_IGNORE_UNUSED.
>
>> +static SPRD_CCU_GATE(rpll0_gate, "rpll0-gate", "ext-26m", 0x402b016c,
>> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(rpll1_gate, "rpll1-gate", "ext-26m", 0x402b016c,
>> + 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(mpll0_gate, "mpll0-gate", "ext-26m", 0x402b00b0,
>> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(mpll1_gate, "mpll1-gate", "ext-26m", 0x402b00b0,
>> + 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(dpll0_gate, "dpll0-gate", "ext-26m", 0x402b00b4,
>> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(dpll1_gate, "dpll1-gate", "ext-26m", 0x402b00b4,
>> + 0x1000, BIT(18), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(gpll_gate, "gpll-gate", "ext-26m", 0x402b032c,
>> + 0x1000, BIT(0), SC9860_GATE_FLAGS,
>> + CLK_GATE_SET_TO_DISABLE);
>> +static SPRD_CCU_GATE(cppll_gate, "cppll-gate", "ext-26m", 0x402b02b4,
>> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(ltepll0_gate, "ltepll0-gate", "ext-26m", 0x402b00b8,
>> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(ltepll1_gate, "ltepll1-gate", "ext-26m", 0x402b010c,
>> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE(twpll_gate, "twpll-gate", "ext-26m", 0x402b00bc,
>> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE_NO_PARENT(sdio0_2x_en, "sdio0-2x-en", 0x402e013c,
>> + 0x1000, BIT(2), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE_NO_PARENT(sdio0_1x_en, "sdio0-1x-en", 0x402e013c,
>> + 0x1000, BIT(3), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE_NO_PARENT(sdio1_2x_en, "sdio1-2x-en", 0x402e013c,
>> + 0x1000, BIT(4), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE_NO_PARENT(sdio1_1x_en, "sdio1-1x-en", 0x402e013c,
>> + 0x1000, BIT(5), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE_NO_PARENT(sdio2_2x_en, "sdio2-2x-en", 0x402e013c,
>> + 0x1000, BIT(6), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE_NO_PARENT(sdio2_1x_en, "sdio2-1x-en", 0x402e013c,
>> + 0x1000, BIT(7), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE_NO_PARENT(emmc_1x_en, "emmc-1x-en", 0x402e013c,
>> + 0x1000, BIT(8), SC9860_GATE_FLAGS, 0);
>> +static SPRD_CCU_GATE_NO_PARENT(emmc_2x_en, "emmc-2x-en", 0x402e013c,
>> + 0x1000, BIT(9), SC9860_GATE_FLAGS, 0);
>> +
>> +/* GPLL/LPLL/DPLL/RPLL/CPLL */
>> +static const u64 const itable1[4] = {3, 780000000, 988000000, 1196000000};
>> +
>> +/* TWPLL/MPLL0/MPLL1 */
>> +static const u64 itable2[4] = {3, 1638000000, 2080000000, 2600000000UL};
>> +
>> +static const struct ccu_bit_field const f_rpll[PLL_FACT_MAX] = {
>> + { .shift = 0, .width = 1 }, /* lock_done */
>> + { .shift = 3, .width = 1 }, /* div_s */
>> + { .shift = 80, .width = 1 }, /* mod_en */
>
> Are they even shifts? Or offsets from some base? I have to go
> back and read the other patch.
You must've noticed that each PLL has a structure of "ccu_bit_field
*factors", each pair of shift - width represents a bit field in
registers, each bit field stores a factor used to calculate PLL clock
rate, but different PLL clock has different bit fields arrangement due
to hardware design.
>
>> + { .shift = 81, .width = 1 }, /* sdm_en */
>> + { .shift = 0, .width = 0 }, /* refin */
>> + { .shift = 14, .width = 2 }, /* ibias */
>> + { .shift = 16, .width = 7 }, /* n */
>> + { .shift = 4, .width = 7 }, /* nint */
>> + { .shift = 32, .width = 23}, /* kint */
>> + { .shift = 0, .width = 0 }, /* prediv */
>> + { .shift = 0, .width = 0 }, /* postdiv */
>> +};
>> +static const u32 const regs_rpll0[4] = { 3, 0x44, 0x48, 0x4c };
>> +static SPRD_CCU_PLL_WITH_ITABLE(rpll0_clk, "rpll0", "rpll0-gate", 0x40400044,
>> + regs_rpll0, itable1, 200, f_rpll);
>> +
>> +static const u32 const regs_rpll1[4] = { 3, 0x50, 0x54, 0x58 };
>> +static SPRD_CCU_PLL_WITH_ITABLE(rpll1_clk, "rpll1", "rpll1-gate", 0x40400050,
>> + regs_rpll1, itable1, 200, f_rpll);
>> +
>> +static const struct ccu_bit_field const f_mpll0[PLL_FACT_MAX] = {
> [...]
>> diff --git a/include/dt-bindings/clock/sc9860-ccu.h b/include/dt-bindings/clock/sc9860-ccu.h
>> new file mode 100644
>> index 0000000..dd7ccf9
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/sc9860-ccu.h
>> @@ -0,0 +1,19 @@
>> +/*
>> + * Spreadtrum SC9860 platform clocks
>> + *
>> + * Copyright (C) 2017, Spreadtrum Communications Inc.
>> + *
>> + * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> + */
>> +
>> +#ifndef _DT_BINDINGS_CLK_SC9860_CCU_H_
>> +#define _DT_BINDINGS_CLK_SC9860_CCU_H_
>> +
>> +#define CLK_FAC_1M 2
>> +#define CLK_EMMC_2X_EN 29
>> +#define CLK_L0_409M6 60
>> +#define CLK_EMMC_2X 88
>> +#define CLK_EMMC_EB 158
>
> Why are only a handful exposed in the header file? Not exposing
> everything is mostly a maintenance nightmare right now.
No special reason here, my thought simply was that there's no much
Spreadtrum's device driver in mainline at present, so most of the
clocks wouldn't be needed for now, I planned to expose only those when
the device driver they provide clock to, that's saying when we add a
new device driver we'll expose the clocks this device needs.
Another reason is, I'm not sure if there are still some clocks I
haven't listed for SC9860 , so if we need to add a clock in the
feature, the value of these macros defined in
"include/dt-bindings/clock/sc9860-ccu.h" may be changed, that means I
need to change the index of all clocks following the clock inserted
into.
But why will not exposing everything bring trouble to maintenance? :)
Thank you for your review,
Chunyan
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
Hi Stephen,
On 20 June 2017 at 09:24, Stephen Boyd <[email protected]> wrote:
> On 06/18, Chunyan Zhang wrote:
>> diff --git a/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi b/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi
>> new file mode 100644
>> index 0000000..e15bf2d
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/sprd/sc9860-ccu.dtsi
>> @@ -0,0 +1,67 @@
>> +/*
>> + * Spreadtrum SC9860 SoC CCU
>> + *
>> + * Copyright (C) 2017, Spreadtrum Communications Inc.
>> + *
>> + * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> + */
>> +
>> +&soc {
>> + ext_26m: ext-26m {
>> + compatible = "fixed-clock";
>> + #clock-cells = <0>;
>> + clock-frequency = <26000000>;
>> + clock-output-names = "ext-26m";
>> + };
>> +
>> + ext_32m_sine0: ext-32m-sine0 {
>> + compatible = "fixed-clock";
>> + #clock-cells = <0>;
>> + clock-frequency = <32000000>;
>> + clock-output-names = "ext-32m-sine0";
>> + };
>> +
>> + ext_32m_sine1: ext-32m-sine1 {
>> + compatible = "fixed-clock";
>> + #clock-cells = <0>;
>> + clock-frequency = <32000000>;
>> + clock-output-names = "ext-32m-sine1";
>> + };
>> +
>> + ext_rco_100m: ext-rco-100m {
>> + compatible = "fixed-clock";
>> + #clock-cells = <0>;
>> + clock-frequency = <100000000>;
>> + clock-output-names = "ext-rco-100m";
>> + };
>> +
>> + ext_32k: ext-32k {
>> + compatible = "fixed-clock";
>> + #clock-cells = <0>;
>> + clock-frequency = <32768>;
>> + clock-output-names = "ext-32k";
>> + };
>
> These should all be outside of the soc node as they're probably
> on the board and not the SoC? The hint is that they don't have a
> reg property.
>
>> +
>> + ccu: clk {
>
> clock-controller is a more standard node name.
OK, will address.
>
>> + compatible = "sprd,sc9860-ccu";
>> + #clock-cells = <1>;
>> + reg = <0 0x20000000 0 0x400>,
>> + <0 0x20210000 0 0x3000>,
>> + <0 0x402b0000 0 0x4000>,
>> + <0 0x402d0000 0 0x400>,
>> + <0 0x402e0000 0 0x4000>,
>> + <0 0x40400000 0 0x400>,
>> + <0 0x40880000 0 0x400>,
>> + <0 0x415e0000 0 0x400>,
>> + <0 0x60200000 0 0x400>,
>> + <0 0x61000000 0 0x400>,
>> + <0 0x61100000 0 0x3000>,
>> + <0 0x62000000 0 0x4000>,
>> + <0 0x62100000 0 0x4000>,
>> + <0 0x63000000 0 0x400>,
>> + <0 0x63100000 0 0x3000>,
>> + <0 0x70b00000 0 0x3000>;
>
> There are a lot of reg properties here. Perhaps there needs to be
> different nodes for the different clock controllers in this SoC?
>
On Spreadtrum's platform, clocks are basically located in a few
address areas due to some hardware design issue, that says there're
more than one kinds of clocks in one address range, and one kind of
clocks have more than one physical address bases, except ccu_pll and
ccu_div in this patchset.
We're planning to map the whole device area at one time before
initializing each of them, once that has been done and upstreamed, I
will remove these lists of addressed.
Thanks for your review,
Chunyan
>> + clocks = <&ext_26m>, <&ext_rco_100m>, <&ext_32k>;
>> + clock-names = "ext-26m", "ext-rco-100m", "ext-32k";
>> + };
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
On Thu, Jun 22, 2017 at 12:17 PM, Chunyan Zhang <[email protected]> wrote:
> On 20 June 2017 at 09:37, Stephen Boyd <[email protected]> wrote:
>> On 06/18, Chunyan Zhang wrote:
>>> + kint = DIV_ROUND_CLOSEST(((fvco - refin * nint * CCU_PLL_1M)/10000) *
>>> + ((mask >> (shift + i)) + 1), refin * 100) << i;
>>> + cfg[index].val |= (kint << shift) & mask;
>>> + cfg[index].msk |= mask;
>>> +
>>> + ibias_val = pll_get_ibias(fvco, pll->itable);
>>> +
>>> + mask = pmask(pll, PLL_IBIAS);
>>> + index = pindex(pll, PLL_IBIAS);
>>> + shift = pshift(pll, PLL_IBIAS);
>>> + cfg[index].val |= ibias_val << shift & mask;
>>> + cfg[index].msk |= mask;
>>> +
>>> + for (i = 0; i < reg_num; i++) {
>>> + if (cfg[i].msk)
>>> + ccu_pll_writel(pll, i, cfg[i].val, cfg[i].msk);
>>> + }
>>> +
>>
>> Are we waiting for the writel() to go through above? If so we
>> need a readl() of the same register to make sure the write has
>> completed before delaying.
>
> After writing these configuration registers, we have to wait a certain
> time to make sure the pll has worked as we configured. This depends
> on other circuit part, so we use udelay rather than reading the same
> register.
I think you have to do both: normally the writel() is not guaranteed
to arrive at the device until you read back from an address in the
same device, so the delay must happen after the readl(), or you won't
know how long to wait for.
Arnd
Hi Arnd,
On 22 June 2017 at 19:15, Arnd Bergmann <[email protected]> wrote:
> On Thu, Jun 22, 2017 at 12:17 PM, Chunyan Zhang <[email protected]> wrote:
>> On 20 June 2017 at 09:37, Stephen Boyd <[email protected]> wrote:
>>> On 06/18, Chunyan Zhang wrote:
>
>>>> + kint = DIV_ROUND_CLOSEST(((fvco - refin * nint * CCU_PLL_1M)/10000) *
>>>> + ((mask >> (shift + i)) + 1), refin * 100) << i;
>>>> + cfg[index].val |= (kint << shift) & mask;
>>>> + cfg[index].msk |= mask;
>>>> +
>>>> + ibias_val = pll_get_ibias(fvco, pll->itable);
>>>> +
>>>> + mask = pmask(pll, PLL_IBIAS);
>>>> + index = pindex(pll, PLL_IBIAS);
>>>> + shift = pshift(pll, PLL_IBIAS);
>>>> + cfg[index].val |= ibias_val << shift & mask;
>>>> + cfg[index].msk |= mask;
>>>> +
>>>> + for (i = 0; i < reg_num; i++) {
>>>> + if (cfg[i].msk)
>>>> + ccu_pll_writel(pll, i, cfg[i].val, cfg[i].msk);
>>>> + }
>>>> +
>>>
>>> Are we waiting for the writel() to go through above? If so we
>>> need a readl() of the same register to make sure the write has
>>> completed before delaying.
>>
>> After writing these configuration registers, we have to wait a certain
>> time to make sure the pll has worked as we configured. This depends
>> on other circuit part, so we use udelay rather than reading the same
>> register.
>
> I think you have to do both: normally the writel() is not guaranteed
> to arrive at the device until you read back from an address in the
> same device, so the delay must happen after the readl(), or you won't
> know how long to wait for.
I got it, will add the readl() in the next iterator.
Thanks,
Chunyan
>
> Arnd
On Sun, Jun 18, 2017 at 09:58:47AM +0800, Chunyan Zhang wrote:
> Introduce a new binding with its documentation for Spreadtrum clock
> sub-framework.
>
> Signed-off-by: Chunyan Zhang <[email protected]>
> ---
> .../devicetree/bindings/clock/sprd-ccu.txt | 46 ++++++++++++++++++++++
> 1 file changed, 46 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/sprd-ccu.txt
Acked-by: Rob Herring <[email protected]>
On 06/22, Chunyan Zhang wrote:
> Hi Stephen,
>
> On 20 June 2017 at 09:25, Stephen Boyd <[email protected]> wrote:
> > On 06/18, Chunyan Zhang wrote:
> >> In the last cycle, the patches support Whale2 sc9860 mobile chip have been
> >> merged. This patchset adds clock driver which is used on almost all
> >> Spreadtrum SoCs.
> >>
> >> This is a rewrite of Spreadtrum's original clock driver[1] according to the
> >> comments[2] from Stephen Boyd.
> >>
> >> This series also adds Spreadtrum clock binding documentation and devicetree
> >> data.
> >>
> >> Any comments would be greatly appreciated.
> >
> > Overall it seems to copy quite a bit of code from sunxi-ng, which
> > is OK, but if that's just copy/paste + replace some names then
> > perhaps we should consolidate the two implementations into one
> > that both SoCs can use.
> >
>
> OK, will try.
Ok. Please don't spend too much time on it though.
>
> > Also, is there any reason why we can't use a platform device
> > driver for this instead of the DT probing mechanism? That is more
> > preferred method of probing clk controllers.
>
> From what I have known on ARM platforms, device drivers cannot
> recognize out which SoC the driver is running on, assume that the
> device on different SoC has some differences. To make one only kernel
> Image can be used on all SoCs of Spreadtrum, we selected the way of
> loading different dtb for each SoC.
Device drivers can figure out what device the driver is bound to
based on the compatible string of the node. Typically, the clk
driver binds to a device node with a compatible indicating the
clock controller it is, like spd,soc-name-clk-controller-name.
Then that can be used to determine what sort of associated data
there is.
>
> Actually, I haven't understood the merits of moving more clk things to
> driver from DT, could you please introduce more about that?
>
>
Some mailing list digging may be helpful, but I admit I need to
have some sort of canned response here that I can just repeat
each time this comes up. Here it goes.
We really only need CLK_OF_DECLARE() if a clk needs to be
available for timers or interrupt controllers. Otherwise, its
possible to put the rest of the clk tree registration in the
normal device driver path.
Reasons (in no particular order):
1. We get a dev pointer to use with clk_hw_register()
2. We can handle probe defer if some resource is not available
3. Using device model gets us a hook into power management frameworks
like runtime PM and system PM for things like suspend and hibernate
4. It encourages a single DT node clk controller style binding
instead of a single node per clk style binding
5. We can use non-DT specific functions like devm_ioremap_resource() to map
registers and acquire other resources, leading to more portable and
generic code
6. We may be able to make the device driver a module, which will
make distros happy if we don't have to compile in all
these clk drivers to the resulting vmlinux
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/22, Chunyan Zhang wrote:
> Hi Stephen,
>
> On 20 June 2017 at 09:24, Stephen Boyd <[email protected]> wrote:
> > On 06/18, Chunyan Zhang wrote:
>
> >
> >> + compatible = "sprd,sc9860-ccu";
> >> + #clock-cells = <1>;
> >> + reg = <0 0x20000000 0 0x400>,
> >> + <0 0x20210000 0 0x3000>,
> >> + <0 0x402b0000 0 0x4000>,
> >> + <0 0x402d0000 0 0x400>,
> >> + <0 0x402e0000 0 0x4000>,
> >> + <0 0x40400000 0 0x400>,
> >> + <0 0x40880000 0 0x400>,
> >> + <0 0x415e0000 0 0x400>,
> >> + <0 0x60200000 0 0x400>,
> >> + <0 0x61000000 0 0x400>,
> >> + <0 0x61100000 0 0x3000>,
> >> + <0 0x62000000 0 0x4000>,
> >> + <0 0x62100000 0 0x4000>,
> >> + <0 0x63000000 0 0x400>,
> >> + <0 0x63100000 0 0x3000>,
> >> + <0 0x70b00000 0 0x3000>;
> >
> > There are a lot of reg properties here. Perhaps there needs to be
> > different nodes for the different clock controllers in this SoC?
> >
>
> On Spreadtrum's platform, clocks are basically located in a few
> address areas due to some hardware design issue, that says there're
> more than one kinds of clocks in one address range, and one kind of
> clocks have more than one physical address bases, except ccu_pll and
> ccu_div in this patchset.
>
> We're planning to map the whole device area at one time before
> initializing each of them, once that has been done and upstreamed, I
> will remove these lists of addressed.
Ok. Does this mean we need to wait for those patches to be sent
out for review? Is it more like certain clks are embedded inside
other devices like display controllers, i2c controllers, etc? Is
there any more information I can get on this SoC?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/22, Chunyan Zhang wrote:
> Hi Stephen,
>
> On 20 June 2017 at 09:41, Stephen Boyd <[email protected]> wrote:
> > On 06/18, Chunyan Zhang wrote:
> >> +++ b/include/dt-bindings/clock/sc9860-ccu.h
> >> @@ -0,0 +1,19 @@
> >> +/*
> >> + * Spreadtrum SC9860 platform clocks
> >> + *
> >> + * Copyright (C) 2017, Spreadtrum Communications Inc.
> >> + *
> >> + * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> >> + */
> >> +
> >> +#ifndef _DT_BINDINGS_CLK_SC9860_CCU_H_
> >> +#define _DT_BINDINGS_CLK_SC9860_CCU_H_
> >> +
> >> +#define CLK_FAC_1M 2
> >> +#define CLK_EMMC_2X_EN 29
> >> +#define CLK_L0_409M6 60
> >> +#define CLK_EMMC_2X 88
> >> +#define CLK_EMMC_EB 158
> >
> > Why are only a handful exposed in the header file? Not exposing
> > everything is mostly a maintenance nightmare right now.
>
> No special reason here, my thought simply was that there's no much
> Spreadtrum's device driver in mainline at present, so most of the
> clocks wouldn't be needed for now, I planned to expose only those when
> the device driver they provide clock to, that's saying when we add a
> new device driver we'll expose the clocks this device needs.
Please no. I don't want to get the one-off patch in my inbox to
add more and more ids here "just because" nobody was using the
numbers before. I really don't care that someone has added the
driver for some random device on their SoC now and so they need
to expose the number into a header file. I know some people are
doing this, and it's really not meaningful. I'm much happier if
we're exposing every single clk number to DT and reducing churn
in the include/dt-bindings/ directory. And really, the raw number
could be used in dt, so the enforcement of any sort of ABI needs
to be in the clk driver anyway.
Now if a clk was left out of the clk driver implementation, then
the number could be left out of the header file, but even then it
doesn't really need to be. The clk driver could be implemented in
a way to return an error if the number doesn't map to a clk_hw
structure in the driver. In the future, the clk could be added to
the driver, and then DT wouldn't need to change and consumer
drivers would start to work when various branches are merged
together.
Also, sometimes clk driver authors don't know about all the clks
that they have on their hardware (I doubt this includes you
because you work at the company making the SoC here). In this
case, it's OK to leave out the ids that aren't known to the
binding author because we can't expect more from these people.
And if you know for a fact that a certain clk will never need to
be exposed in the binding, like some random internal clk that
nobody will care to use, then it's also OK to leave that out from
the binding.
>
> Another reason is, I'm not sure if there are still some clocks I
> haven't listed for SC9860 , so if we need to add a clock in the
> feature, the value of these macros defined in
> "include/dt-bindings/clock/sc9860-ccu.h" may be changed, that means I
> need to change the index of all clocks following the clock inserted
> into.
When modifying a dt-bindings header file to add more clk ids you
should _never_ modify existing numbers. That would be a backwards
incompatible change of the DT binding. If anything, just keep
adding more numbers to the end of the number space. If something
needs to be removed, make that number map to an error or some
no-op clk_hw structure in the clk driver.
>
> But why will not exposing everything bring trouble to maintenance? :)
>
Mostly it's because I spend too much time worrying about these
include/dt-bindings files and how they're going to land in Linus'
tree and not enough time reviewing driver and core framework
patches. I'm trying to reduce the time spent worrying about these
header files to a manageable amount.
Hopefully that's helpful. Sorry for the long email.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/22, Chunyan Zhang wrote:
> On 20 June 2017 at 09:31, Stephen Boyd <[email protected]> wrote:
> > On 06/18, Chunyan Zhang wrote:
> >> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
> >> index 8f802b2..333e2b2 100644
> >> --- a/drivers/clk/sprd/Makefile
> >> +++ b/drivers/clk/sprd/Makefile
> >> @@ -1,3 +1,3 @@
> >> ifneq ($(CONFIG_OF),)
> >> -obj-y += ccu_common.o
> >> +obj-y += ccu_common.o ccu_gate.o
> >
> > Can this be built as a module?
>
> Since most of all Spreadtrum device drivers would depend on if clocks
> have been initialized, so we'd prefer to build this into the kernel
> image.
This isn't really a good reason, but OK. Hopefully nobody wants
to make a module for every driver on the system and jam the ones
needed to access the rootfs into a ramdisk. Don't worry, you
don't need to support modules here.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 06/22, Chunyan Zhang wrote:
> On 20 June 2017 at 09:37, Stephen Boyd <[email protected]> wrote:
> > On 06/18, Chunyan Zhang wrote:
> >> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
> >> index 83232e5..c593a93 100644
> >> --- a/drivers/clk/sprd/Makefile
> >> +++ b/drivers/clk/sprd/Makefile
> >> @@ -1,3 +1,3 @@
> >> ifneq ($(CONFIG_OF),)
> >> -obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o
> >> +obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o ccu_pll.o
> >> endif
> >> diff --git a/drivers/clk/sprd/ccu_pll.c b/drivers/clk/sprd/ccu_pll.c
> >> new file mode 100644
> >> index 0000000..6c908e4
> >> --- /dev/null
> >> +++ b/drivers/clk/sprd/ccu_pll.c
> >> @@ -0,0 +1,241 @@
> >> +/*
> >> + * Spreadtrum pll clock driver
> >> + *
> >> + * Copyright (C) 2015~2017 Spreadtrum, Inc.
> >> + *
> >> + * SPDX-License-Identifier: GPL-2.0
> >> + */
> >> +
> >> +#include <linux/delay.h>
> >> +#include <linux/clk.h>
> >
> > Is this include used? Should be clk-provider?
>
> Right, will remove it.
>
> >
> >> +#include <linux/err.h>
> >> +#include <linux/slab.h>
> >> +
> >> +#include "ccu_pll.h"
> >> +
> >> +#define CCU_PLL_1M 1000000
> >> +#define CCU_PLL_10M (CCU_PLL_1M * 10)
> >> +
> >> +#define pindex(pll, member) \
> >> + (pll->factors[member].shift / (8 * sizeof(pll->regs[0])))
> >> +
> >> +#define pshift(pll, member) \
> >> + (pll->factors[member].shift % (8 * sizeof(pll->regs[0])))
> >> +
> >> +#define pwidth(pll, member) \
> >> + pll->factors[member].width
> >> +
> >> +#define pmask(pll, member) \
> >> + ((pwidth(pll, member)) ? \
> >> + GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
> >> + pshift(pll, member)) : 0)
> >> +
> >> +#define pinternal(pll, cfg, member) \
> >> + (cfg[pindex(pll, member)] & pmask(pll, member))
> >> +
> >> +#define pinternal_val(pll, cfg, member) \
> >> + (pinternal(pll, cfg, member) >> pshift(pll, member))
> >> +
> >> +static unsigned long pll_get_refin_rate(struct ccu_pll *pll)
> >
> > pll could be const?
>
> What this function returns is a factor used to calculate the pll rate
> later, I will rename this function in the next iterator.
>
Rename is fine, but pll can still be marked const?
>
> >
> >> + nint = pinternal_val(pll, cfg, PLL_NINT);
> >> + if (pinternal(pll, cfg, PLL_SDM_EN))
> >> + kint = pinternal_val(pll, cfg, PLL_KINT);
> >> +
> >> + mask = pmask(pll, PLL_KINT);
> >> +#ifdef CONFIG_64BIT
> >> + k1 = 1000;
> >> + k2 = 1000;
> >> + rate = DIV_ROUND_CLOSEST(refin * kint * k1,
> >> + ((mask >> __ffs(mask)) + 1)) *
> >> + k2 + refin * nint * CCU_PLL_1M;
> >> +#else
> >> + k1 = 100;
> >> + k2 = 10000;
> >> + i = pwidth(pll, PLL_KINT);
> >> + i = i < 21 ? 0 : i - 21;
> >> + rate = DIV_ROUND_CLOSEST(refin * (kint >> i) * k1,
> >> + ((mask >> (__ffs(mask) + i)) + 1)) *
> >> + k2 + refin * nint * CCU_PLL_1M;
> >> +#endif
> >> + }
> >> +
> >> + return rate;
> >> +}
> >> +
> >> +static int ccu_pll_helper_set_rate(struct ccu_pll *pll,
> >> + unsigned long rate,
> >> + unsigned long parent_rate)
> >> +{
> >> + u32 mask, shift, width, ibias_val, index, kint, nint;
> >> + u32 reg_num = pll->regs[0], i = 0;
> >> + unsigned long refin, fvco = rate;
> >> + struct reg_cfg *cfg;
> >> +
> >> + cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
> >> + if (!cfg)
> >> + return -ENOMEM;
> >> +
> >> + refin = pll_get_refin_rate(pll);
> >> +
> >> + mask = pmask(pll, PLL_PREDIV);
> >> + index = pindex(pll, PLL_PREDIV);
> >> + width = pwidth(pll, PLL_PREDIV);
> >> + if (width && (ccu_pll_readl(pll, index) & mask))
> >> + refin = refin * 2;
> >> +
> >> + mask = pmask(pll, PLL_POSTDIV);
> >> + index = pindex(pll, PLL_POSTDIV);
> >> + width = pwidth(pll, PLL_POSTDIV);
> >> + cfg[index].msk = mask;
> >> + if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
> >> + (pll->fflag == 0 && fvco > pll->fvco)))
> >> + cfg[index].val |= mask;
> >> +
> >> + if (width && fvco <= pll->fvco)
> >> + fvco = fvco * 2;
> >> +
> >> + mask = pmask(pll, PLL_DIV_S);
> >> + index = pindex(pll, PLL_DIV_S);
> >> + cfg[index].val |= mask;
> >> + cfg[index].msk |= mask;
> >> +
> >> + mask = pmask(pll, PLL_SDM_EN);
> >> + index = pindex(pll, PLL_SDM_EN);
> >> + cfg[index].val |= mask;
> >> + cfg[index].msk |= mask;
> >> +
> >> + nint = fvco/(refin * CCU_PLL_1M);
> >> +
> >> + mask = pmask(pll, PLL_NINT);
> >> + index = pindex(pll, PLL_NINT);
> >> + shift = pshift(pll, PLL_NINT);
> >> + cfg[index].val |= (nint << shift) & mask;
> >> + cfg[index].msk |= mask;
> >> +
> >> + mask = pmask(pll, PLL_KINT);
> >> + index = pindex(pll, PLL_KINT);
> >> + width = pwidth(pll, PLL_KINT);
> >> + shift = pshift(pll, PLL_KINT);
> >> +#ifndef CONFIG_64BIT
> >> + i = width < 21 ? 0 : i - 21;
> >> +#endif
> >
> > What's this? Why do we depend on CONFIG_64BIT?
>
> On 32-bit SoCs, the largest width we can support is limited due to the
> limitation of calculation precision.
Does the hardware width change? Still not clear to me what's
going on here.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
Hi Stephen,
Thanks for your every so clear and detailed answer, thank you.
On 30 June 2017 at 08:57, Stephen Boyd <[email protected]> wrote:
> On 06/22, Chunyan Zhang wrote:
>> Hi Stephen,
>>
>> On 20 June 2017 at 09:24, Stephen Boyd <[email protected]> wrote:
>> > On 06/18, Chunyan Zhang wrote:
>>
>> >
>> >> + compatible = "sprd,sc9860-ccu";
>> >> + #clock-cells = <1>;
>> >> + reg = <0 0x20000000 0 0x400>,
>> >> + <0 0x20210000 0 0x3000>,
>> >> + <0 0x402b0000 0 0x4000>,
>> >> + <0 0x402d0000 0 0x400>,
>> >> + <0 0x402e0000 0 0x4000>,
>> >> + <0 0x40400000 0 0x400>,
>> >> + <0 0x40880000 0 0x400>,
>> >> + <0 0x415e0000 0 0x400>,
>> >> + <0 0x60200000 0 0x400>,
>> >> + <0 0x61000000 0 0x400>,
>> >> + <0 0x61100000 0 0x3000>,
>> >> + <0 0x62000000 0 0x4000>,
>> >> + <0 0x62100000 0 0x4000>,
>> >> + <0 0x63000000 0 0x400>,
>> >> + <0 0x63100000 0 0x3000>,
>> >> + <0 0x70b00000 0 0x3000>;
>> >
>> > There are a lot of reg properties here. Perhaps there needs to be
>> > different nodes for the different clock controllers in this SoC?
>> >
>>
>> On Spreadtrum's platform, clocks are basically located in a few
>> address areas due to some hardware design issue, that says there're
>> more than one kinds of clocks in one address range, and one kind of
>> clocks have more than one physical address bases, except ccu_pll and
>> ccu_div in this patchset.
>>
>> We're planning to map the whole device area at one time before
>> initializing each of them, once that has been done and upstreamed, I
>> will remove these lists of addressed.
>
> Ok. Does this mean we need to wait for those patches to be sent
I don't think that would come out for review in the near future, so I
have to keep these ranges of the address listed here for the time
being.
> out for review? Is it more like certain clks are embedded inside
> other devices like display controllers, i2c controllers, etc? Is
>From what I understand, that's just something like you said.
> there any more information I can get on this SoC?
I think you may get more information from our dts files [1], if you
would like to :)
Thanks again,
Chunyan
[1] https://github.com/sprdlinux/kernel/blob/sp9860g-1h10/arch/arm64/boot/dts/sprd/whale.dtsi
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
Hi Stephen,
On 30 June 2017 at 09:44, Stephen Boyd <[email protected]> wrote:
> On 06/22, Chunyan Zhang wrote:
>> On 20 June 2017 at 09:37, Stephen Boyd <[email protected]> wrote:
>> > On 06/18, Chunyan Zhang wrote:
>> >> diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
>> >> index 83232e5..c593a93 100644
>> >> --- a/drivers/clk/sprd/Makefile
>> >> +++ b/drivers/clk/sprd/Makefile
>> >> @@ -1,3 +1,3 @@
>> >> ifneq ($(CONFIG_OF),)
>> >> -obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o
>> >> +obj-y += ccu_common.o ccu_gate.o ccu_mux.o ccu_div.o ccu_composite.o ccu_pll.o
>> >> endif
>> >> diff --git a/drivers/clk/sprd/ccu_pll.c b/drivers/clk/sprd/ccu_pll.c
>> >> new file mode 100644
>> >> index 0000000..6c908e4
>> >> --- /dev/null
>> >> +++ b/drivers/clk/sprd/ccu_pll.c
>> >> @@ -0,0 +1,241 @@
>> >> +/*
>> >> + * Spreadtrum pll clock driver
>> >> + *
>> >> + * Copyright (C) 2015~2017 Spreadtrum, Inc.
>> >> + *
>> >> + * SPDX-License-Identifier: GPL-2.0
>> >> + */
>> >> +
>> >> +#include <linux/delay.h>
>> >> +#include <linux/clk.h>
>> >
>> > Is this include used? Should be clk-provider?
>>
>> Right, will remove it.
>>
>> >
>> >> +#include <linux/err.h>
>> >> +#include <linux/slab.h>
>> >> +
>> >> +#include "ccu_pll.h"
>> >> +
>> >> +#define CCU_PLL_1M 1000000
>> >> +#define CCU_PLL_10M (CCU_PLL_1M * 10)
>> >> +
>> >> +#define pindex(pll, member) \
>> >> + (pll->factors[member].shift / (8 * sizeof(pll->regs[0])))
>> >> +
>> >> +#define pshift(pll, member) \
>> >> + (pll->factors[member].shift % (8 * sizeof(pll->regs[0])))
>> >> +
>> >> +#define pwidth(pll, member) \
>> >> + pll->factors[member].width
>> >> +
>> >> +#define pmask(pll, member) \
>> >> + ((pwidth(pll, member)) ? \
>> >> + GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
>> >> + pshift(pll, member)) : 0)
>> >> +
>> >> +#define pinternal(pll, cfg, member) \
>> >> + (cfg[pindex(pll, member)] & pmask(pll, member))
>> >> +
>> >> +#define pinternal_val(pll, cfg, member) \
>> >> + (pinternal(pll, cfg, member) >> pshift(pll, member))
>> >> +
>> >> +static unsigned long pll_get_refin_rate(struct ccu_pll *pll)
>> >
>> > pll could be const?
>>
>> What this function returns is a factor used to calculate the pll rate
>> later, I will rename this function in the next iterator.
>>
>
> Rename is fine, but pll can still be marked const?
Oh, sorry I misunderstood :)
You mean mark the input parameter "pll" const, right?
>>
>> >
>> >> + nint = pinternal_val(pll, cfg, PLL_NINT);
>> >> + if (pinternal(pll, cfg, PLL_SDM_EN))
>> >> + kint = pinternal_val(pll, cfg, PLL_KINT);
>> >> +
>> >> + mask = pmask(pll, PLL_KINT);
>> >> +#ifdef CONFIG_64BIT
>> >> + k1 = 1000;
>> >> + k2 = 1000;
>> >> + rate = DIV_ROUND_CLOSEST(refin * kint * k1,
>> >> + ((mask >> __ffs(mask)) + 1)) *
>> >> + k2 + refin * nint * CCU_PLL_1M;
>> >> +#else
>> >> + k1 = 100;
>> >> + k2 = 10000;
>> >> + i = pwidth(pll, PLL_KINT);
>> >> + i = i < 21 ? 0 : i - 21;
>> >> + rate = DIV_ROUND_CLOSEST(refin * (kint >> i) * k1,
>> >> + ((mask >> (__ffs(mask) + i)) + 1)) *
>> >> + k2 + refin * nint * CCU_PLL_1M;
>> >> +#endif
>> >> + }
>> >> +
>> >> + return rate;
>> >> +}
>> >> +
>> >> +static int ccu_pll_helper_set_rate(struct ccu_pll *pll,
>> >> + unsigned long rate,
>> >> + unsigned long parent_rate)
>> >> +{
>> >> + u32 mask, shift, width, ibias_val, index, kint, nint;
>> >> + u32 reg_num = pll->regs[0], i = 0;
>> >> + unsigned long refin, fvco = rate;
>> >> + struct reg_cfg *cfg;
>> >> +
>> >> + cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
>> >> + if (!cfg)
>> >> + return -ENOMEM;
>> >> +
>> >> + refin = pll_get_refin_rate(pll);
>> >> +
>> >> + mask = pmask(pll, PLL_PREDIV);
>> >> + index = pindex(pll, PLL_PREDIV);
>> >> + width = pwidth(pll, PLL_PREDIV);
>> >> + if (width && (ccu_pll_readl(pll, index) & mask))
>> >> + refin = refin * 2;
>> >> +
>> >> + mask = pmask(pll, PLL_POSTDIV);
>> >> + index = pindex(pll, PLL_POSTDIV);
>> >> + width = pwidth(pll, PLL_POSTDIV);
>> >> + cfg[index].msk = mask;
>> >> + if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
>> >> + (pll->fflag == 0 && fvco > pll->fvco)))
>> >> + cfg[index].val |= mask;
>> >> +
>> >> + if (width && fvco <= pll->fvco)
>> >> + fvco = fvco * 2;
>> >> +
>> >> + mask = pmask(pll, PLL_DIV_S);
>> >> + index = pindex(pll, PLL_DIV_S);
>> >> + cfg[index].val |= mask;
>> >> + cfg[index].msk |= mask;
>> >> +
>> >> + mask = pmask(pll, PLL_SDM_EN);
>> >> + index = pindex(pll, PLL_SDM_EN);
>> >> + cfg[index].val |= mask;
>> >> + cfg[index].msk |= mask;
>> >> +
>> >> + nint = fvco/(refin * CCU_PLL_1M);
>> >> +
>> >> + mask = pmask(pll, PLL_NINT);
>> >> + index = pindex(pll, PLL_NINT);
>> >> + shift = pshift(pll, PLL_NINT);
>> >> + cfg[index].val |= (nint << shift) & mask;
>> >> + cfg[index].msk |= mask;
>> >> +
>> >> + mask = pmask(pll, PLL_KINT);
>> >> + index = pindex(pll, PLL_KINT);
>> >> + width = pwidth(pll, PLL_KINT);
>> >> + shift = pshift(pll, PLL_KINT);
>> >> +#ifndef CONFIG_64BIT
>> >> + i = width < 21 ? 0 : i - 21;
>> >> +#endif
>> >
>> > What's this? Why do we depend on CONFIG_64BIT?
>>
>> On 32-bit SoCs, the largest width we can support is limited due to the
>> limitation of calculation precision.
>
> Does the hardware width change? Still not clear to me what's
> going on here.
I heard from my colleague, that because the calculation precision on
Spreadtrum's 32-bit SoCs is different from on 64-bit SoCs, when the
width of the value of PLL_KINT is larger than 21, the value is too
large to be multiplied on 32-bit Spreadtrum's SoCs.
i = width < 21 ? 0 : i - 21;
Here ' i ' is used to adjust 'shift' rather than 'width' like below (
wrote the code back for convenience of understanding)
+ kint = DIV_ROUND_CLOSEST(((fvco - refin * nint * CCU_PLL_1M)/10000) *
+ ((mask >> (shift + i)) + 1), refin * 100) << i;
Thanks for your review,
Chunyan
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
On 06/30, Chunyan Zhang wrote:
> Hi Stephen,
>
> On 30 June 2017 at 09:44, Stephen Boyd <[email protected]> wrote:
> > On 06/22, Chunyan Zhang wrote:
> >> On 20 June 2017 at 09:37, Stephen Boyd <[email protected]> wrote:
> >> > On 06/18, Chunyan Zhang wrote:
> >> >> + pll->factors[member].width
> >> >> +
> >> >> +#define pmask(pll, member) \
> >> >> + ((pwidth(pll, member)) ? \
> >> >> + GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
> >> >> + pshift(pll, member)) : 0)
> >> >> +
> >> >> +#define pinternal(pll, cfg, member) \
> >> >> + (cfg[pindex(pll, member)] & pmask(pll, member))
> >> >> +
> >> >> +#define pinternal_val(pll, cfg, member) \
> >> >> + (pinternal(pll, cfg, member) >> pshift(pll, member))
> >> >> +
> >> >> +static unsigned long pll_get_refin_rate(struct ccu_pll *pll)
> >> >
> >> > pll could be const?
> >>
> >> What this function returns is a factor used to calculate the pll rate
> >> later, I will rename this function in the next iterator.
> >>
> >
> > Rename is fine, but pll can still be marked const?
>
> Oh, sorry I misunderstood :)
> You mean mark the input parameter "pll" const, right?
Yes.
> >> >> +
> >> >> +static int ccu_pll_helper_set_rate(struct ccu_pll *pll,
> >> >> + unsigned long rate,
> >> >> + unsigned long parent_rate)
> >> >> +{
> >> >> + u32 mask, shift, width, ibias_val, index, kint, nint;
> >> >> + u32 reg_num = pll->regs[0], i = 0;
> >> >> + unsigned long refin, fvco = rate;
> >> >> + struct reg_cfg *cfg;
> >> >> +
> >> >> + cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
> >> >> + if (!cfg)
> >> >> + return -ENOMEM;
> >> >> +
> >> >> + refin = pll_get_refin_rate(pll);
> >> >> +
> >> >> + mask = pmask(pll, PLL_PREDIV);
> >> >> + index = pindex(pll, PLL_PREDIV);
> >> >> + width = pwidth(pll, PLL_PREDIV);
> >> >> + if (width && (ccu_pll_readl(pll, index) & mask))
> >> >> + refin = refin * 2;
> >> >> +
> >> >> + mask = pmask(pll, PLL_POSTDIV);
> >> >> + index = pindex(pll, PLL_POSTDIV);
> >> >> + width = pwidth(pll, PLL_POSTDIV);
> >> >> + cfg[index].msk = mask;
> >> >> + if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
> >> >> + (pll->fflag == 0 && fvco > pll->fvco)))
> >> >> + cfg[index].val |= mask;
> >> >> +
> >> >> + if (width && fvco <= pll->fvco)
> >> >> + fvco = fvco * 2;
> >> >> +
> >> >> + mask = pmask(pll, PLL_DIV_S);
> >> >> + index = pindex(pll, PLL_DIV_S);
> >> >> + cfg[index].val |= mask;
> >> >> + cfg[index].msk |= mask;
> >> >> +
> >> >> + mask = pmask(pll, PLL_SDM_EN);
> >> >> + index = pindex(pll, PLL_SDM_EN);
> >> >> + cfg[index].val |= mask;
> >> >> + cfg[index].msk |= mask;
> >> >> +
> >> >> + nint = fvco/(refin * CCU_PLL_1M);
> >> >> +
> >> >> + mask = pmask(pll, PLL_NINT);
> >> >> + index = pindex(pll, PLL_NINT);
> >> >> + shift = pshift(pll, PLL_NINT);
> >> >> + cfg[index].val |= (nint << shift) & mask;
> >> >> + cfg[index].msk |= mask;
> >> >> +
> >> >> + mask = pmask(pll, PLL_KINT);
> >> >> + index = pindex(pll, PLL_KINT);
> >> >> + width = pwidth(pll, PLL_KINT);
> >> >> + shift = pshift(pll, PLL_KINT);
> >> >> +#ifndef CONFIG_64BIT
> >> >> + i = width < 21 ? 0 : i - 21;
> >> >> +#endif
> >> >
> >> > What's this? Why do we depend on CONFIG_64BIT?
> >>
> >> On 32-bit SoCs, the largest width we can support is limited due to the
> >> limitation of calculation precision.
> >
> > Does the hardware width change? Still not clear to me what's
> > going on here.
>
> I heard from my colleague, that because the calculation precision on
> Spreadtrum's 32-bit SoCs is different from on 64-bit SoCs, when the
> width of the value of PLL_KINT is larger than 21, the value is too
> large to be multiplied on 32-bit Spreadtrum's SoCs.
It sounds like you're saying that the clk hardware is not
changing, but the sizeof(long) is different on 64-bit and 32-bit
CPUs so you've added this ifndef here for that.
>
> i = width < 21 ? 0 : i - 21;
>
> Here ' i ' is used to adjust 'shift' rather than 'width' like below (
> wrote the code back for convenience of understanding)
>
> + kint = DIV_ROUND_CLOSEST(((fvco - refin * nint * CCU_PLL_1M)/10000) *
> + ((mask >> (shift + i)) + 1), refin * 100) << i;
>
Having the types for all these variables would also be helpful.
u32 mask, shift, width, kint, nint;
unsigned long refin, fvco;
Why don't we do 64-bit math here instead of 32-bit math? And use
DIV_ROUND_CLOSEST_ULL?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 1 July 2017 at 03:22, Stephen Boyd <[email protected]> wrote:
> On 06/30, Chunyan Zhang wrote:
>> Hi Stephen,
>>
>> On 30 June 2017 at 09:44, Stephen Boyd <[email protected]> wrote:
>> > On 06/22, Chunyan Zhang wrote:
>> >> On 20 June 2017 at 09:37, Stephen Boyd <[email protected]> wrote:
>> >> > On 06/18, Chunyan Zhang wrote:
>> >> >> + pll->factors[member].width
>> >> >> +
>> >> >> +#define pmask(pll, member) \
>> >> >> + ((pwidth(pll, member)) ? \
>> >> >> + GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
>> >> >> + pshift(pll, member)) : 0)
>> >> >> +
>> >> >> +#define pinternal(pll, cfg, member) \
>> >> >> + (cfg[pindex(pll, member)] & pmask(pll, member))
>> >> >> +
>> >> >> +#define pinternal_val(pll, cfg, member) \
>> >> >> + (pinternal(pll, cfg, member) >> pshift(pll, member))
>> >> >> +
>> >> >> +static unsigned long pll_get_refin_rate(struct ccu_pll *pll)
>> >> >
>> >> > pll could be const?
>> >>
>> >> What this function returns is a factor used to calculate the pll rate
>> >> later, I will rename this function in the next iterator.
>> >>
>> >
>> > Rename is fine, but pll can still be marked const?
>>
>> Oh, sorry I misunderstood :)
>> You mean mark the input parameter "pll" const, right?
>
> Yes.
>
>> >> >> +
>> >> >> +static int ccu_pll_helper_set_rate(struct ccu_pll *pll,
>> >> >> + unsigned long rate,
>> >> >> + unsigned long parent_rate)
>> >> >> +{
>> >> >> + u32 mask, shift, width, ibias_val, index, kint, nint;
>> >> >> + u32 reg_num = pll->regs[0], i = 0;
>> >> >> + unsigned long refin, fvco = rate;
>> >> >> + struct reg_cfg *cfg;
>> >> >> +
>> >> >> + cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
>> >> >> + if (!cfg)
>> >> >> + return -ENOMEM;
>> >> >> +
>> >> >> + refin = pll_get_refin_rate(pll);
>> >> >> +
>> >> >> + mask = pmask(pll, PLL_PREDIV);
>> >> >> + index = pindex(pll, PLL_PREDIV);
>> >> >> + width = pwidth(pll, PLL_PREDIV);
>> >> >> + if (width && (ccu_pll_readl(pll, index) & mask))
>> >> >> + refin = refin * 2;
>> >> >> +
>> >> >> + mask = pmask(pll, PLL_POSTDIV);
>> >> >> + index = pindex(pll, PLL_POSTDIV);
>> >> >> + width = pwidth(pll, PLL_POSTDIV);
>> >> >> + cfg[index].msk = mask;
>> >> >> + if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
>> >> >> + (pll->fflag == 0 && fvco > pll->fvco)))
>> >> >> + cfg[index].val |= mask;
>> >> >> +
>> >> >> + if (width && fvco <= pll->fvco)
>> >> >> + fvco = fvco * 2;
>> >> >> +
>> >> >> + mask = pmask(pll, PLL_DIV_S);
>> >> >> + index = pindex(pll, PLL_DIV_S);
>> >> >> + cfg[index].val |= mask;
>> >> >> + cfg[index].msk |= mask;
>> >> >> +
>> >> >> + mask = pmask(pll, PLL_SDM_EN);
>> >> >> + index = pindex(pll, PLL_SDM_EN);
>> >> >> + cfg[index].val |= mask;
>> >> >> + cfg[index].msk |= mask;
>> >> >> +
>> >> >> + nint = fvco/(refin * CCU_PLL_1M);
>> >> >> +
>> >> >> + mask = pmask(pll, PLL_NINT);
>> >> >> + index = pindex(pll, PLL_NINT);
>> >> >> + shift = pshift(pll, PLL_NINT);
>> >> >> + cfg[index].val |= (nint << shift) & mask;
>> >> >> + cfg[index].msk |= mask;
>> >> >> +
>> >> >> + mask = pmask(pll, PLL_KINT);
>> >> >> + index = pindex(pll, PLL_KINT);
>> >> >> + width = pwidth(pll, PLL_KINT);
>> >> >> + shift = pshift(pll, PLL_KINT);
>> >> >> +#ifndef CONFIG_64BIT
>> >> >> + i = width < 21 ? 0 : i - 21;
>> >> >> +#endif
>> >> >
>> >> > What's this? Why do we depend on CONFIG_64BIT?
>> >>
>> >> On 32-bit SoCs, the largest width we can support is limited due to the
>> >> limitation of calculation precision.
>> >
>> > Does the hardware width change? Still not clear to me what's
>> > going on here.
>>
>> I heard from my colleague, that because the calculation precision on
>> Spreadtrum's 32-bit SoCs is different from on 64-bit SoCs, when the
>> width of the value of PLL_KINT is larger than 21, the value is too
>> large to be multiplied on 32-bit Spreadtrum's SoCs.
>
> It sounds like you're saying that the clk hardware is not
> changing, but the sizeof(long) is different on 64-bit and 32-bit
> CPUs so you've added this ifndef here for that.
>
I finally figure out that this #ifndef is indeed not needed, thanks to
your querying :)
They told me that on Spreadtrum's 32-bit SoCs, only 20-bit of PLL_KINT
is used and 3-bit is reserved in order to keep in line with the PLLs
on 64-bit SoC.
And we can get the same effect only if we define PLL with the specific
'width' and 'shift' for PLL_KINT.
I'll remove this statement and 'i' from here and
sprd_pll_helper_recalc_rate() function.
>>
>> i = width < 21 ? 0 : i - 20;
>>
>> Here ' i ' is used to adjust 'shift' rather than 'width' like below (
>> wrote the code back for convenience of understanding)
>>
>> + kint = DIV_ROUND_CLOSEST(((fvco - refin * nint * CCU_PLL_1M)/10000) *
>> + ((mask >> (shift + i)) + 1), refin * 100) << i;
>>
>
> Having the types for all these variables would also be helpful.
>
> u32 mask, shift, width, kint, nint;
> unsigned long refin, fvco;
>
> Why don't we do 64-bit math here instead of 32-bit math? And use
> DIV_ROUND_CLOSEST_ULL?
Agree, we should use 64-bit math, will address this.
Thanks,
Chunyan
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project