All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] clk: zx: reform pll config info to ease code extension
@ 2016-07-18  9:41 Jun Nie
  2016-07-18  9:41 ` [PATCH 2/3] clk: zx: Add clk helper and zx296718 clk method Jun Nie
  2016-07-18  9:41 ` [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework Jun Nie
  0 siblings, 2 replies; 8+ messages in thread
From: Jun Nie @ 2016-07-18  9:41 UTC (permalink / raw)
  To: sboyd, mturquette, linux-clk; +Cc: Jun Nie

Add power down bit and pll lock bit in pll config structure
to ease new SoC support.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
 drivers/clk/zte/clk.c | 18 ++++++++++--------
 drivers/clk/zte/clk.h |  2 ++
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c
index 7c73c53..10d532d 100644
--- a/drivers/clk/zte/clk.c
+++ b/drivers/clk/zte/clk.c
@@ -21,8 +21,8 @@
 #define to_clk_zx_audio(_hw) container_of(_hw, struct clk_zx_audio, hw)
 
 #define CFG0_CFG1_OFFSET 4
-#define LOCK_FLAG BIT(30)
-#define POWER_DOWN BIT(31)
+#define LOCK_FLAG 30
+#define POWER_DOWN 31
 
 static int rate_to_idx(struct clk_zx_pll *zx_pll, unsigned long rate)
 {
@@ -50,8 +50,8 @@ static int hw_to_idx(struct clk_zx_pll *zx_pll)
 	hw_cfg1 = readl_relaxed(zx_pll->reg_base + CFG0_CFG1_OFFSET);
 
 	/* For matching the value in lookup table */
-	hw_cfg0 &= ~LOCK_FLAG;
-	hw_cfg0 |= POWER_DOWN;
+	hw_cfg0 &= ~BIT(zx_pll->lock_bit);
+	hw_cfg0 |= BIT(zx_pll->pd_bit);
 
 	for (i = 0; i < zx_pll->count; i++) {
 		if (hw_cfg0 == config[i].cfg0 && hw_cfg1 == config[i].cfg1)
@@ -108,10 +108,10 @@ static int zx_pll_enable(struct clk_hw *hw)
 	u32 reg;
 
 	reg = readl_relaxed(zx_pll->reg_base);
-	writel_relaxed(reg & ~POWER_DOWN, zx_pll->reg_base);
+	writel_relaxed(reg & ~BIT(zx_pll->pd_bit), zx_pll->reg_base);
 
 	return readl_relaxed_poll_timeout(zx_pll->reg_base, reg,
-					  reg & LOCK_FLAG, 0, 100);
+					  reg & BIT(zx_pll->lock_bit), 0, 100);
 }
 
 static void zx_pll_disable(struct clk_hw *hw)
@@ -120,7 +120,7 @@ static void zx_pll_disable(struct clk_hw *hw)
 	u32 reg;
 
 	reg = readl_relaxed(zx_pll->reg_base);
-	writel_relaxed(reg | POWER_DOWN, zx_pll->reg_base);
+	writel_relaxed(reg | BIT(zx_pll->pd_bit), zx_pll->reg_base);
 }
 
 static int zx_pll_is_enabled(struct clk_hw *hw)
@@ -130,7 +130,7 @@ static int zx_pll_is_enabled(struct clk_hw *hw)
 
 	reg = readl_relaxed(zx_pll->reg_base);
 
-	return !(reg & POWER_DOWN);
+	return !(reg & BIT(zx_pll->pd_bit));
 }
 
 static const struct clk_ops zx_pll_ops = {
@@ -164,6 +164,8 @@ struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
 	zx_pll->reg_base = reg_base;
 	zx_pll->lookup_table = lookup_table;
 	zx_pll->count = count;
+	zx_pll->lock_bit = LOCK_FLAG;
+	zx_pll->pd_bit = POWER_DOWN;
 	zx_pll->lock = lock;
 	zx_pll->hw.init = &init;
 
diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h
index 65ae08b..8277a0a 100644
--- a/drivers/clk/zte/clk.h
+++ b/drivers/clk/zte/clk.h
@@ -24,6 +24,8 @@ struct clk_zx_pll {
 	const struct zx_pll_config *lookup_table; /* order by rate asc */
 	int count;
 	spinlock_t *lock;
+	u8 pd_bit;		/* power down bit */
+	u8 lock_bit;		/* pll lock flag bit */
 };
 
 struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] clk: zx: Add clk helper and zx296718 clk method
  2016-07-18  9:41 [PATCH 1/3] clk: zx: reform pll config info to ease code extension Jun Nie
@ 2016-07-18  9:41 ` Jun Nie
  2016-07-19  0:09   ` Michael Turquette
  2016-07-18  9:41 ` [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework Jun Nie
  1 sibling, 1 reply; 8+ messages in thread
From: Jun Nie @ 2016-07-18  9:41 UTC (permalink / raw)
  To: sboyd, mturquette, linux-clk; +Cc: Jun Nie

Add common clock framework helper functions for ZTE SoC and
ZX296718 clock method for pll/gate/mux clocks.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
 drivers/clk/zte/clk.c | 183 ++++++++++++++++++++++++++++++++++
 drivers/clk/zte/clk.h | 268 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 448 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c
index 10d532d..26557e8 100644
--- a/drivers/clk/zte/clk.c
+++ b/drivers/clk/zte/clk.c
@@ -24,6 +24,14 @@
 #define LOCK_FLAG 30
 #define POWER_DOWN 31
 
+/* add a clock instance to the clock lookup table used for dt based lookup */
+void zx_clk_add_lookup(struct zx_clk_provider *clkp, struct clk *clk,
+		       unsigned int id)
+{
+	if (clkp->clk_data.clks && id)
+		clkp->clk_data.clks[id] = clk;
+}
+
 static int rate_to_idx(struct clk_zx_pll *zx_pll, unsigned long rate)
 {
 	const struct zx_pll_config *config = zx_pll->lookup_table;
@@ -309,3 +317,178 @@ struct clk *clk_register_zx_audio(const char *name,
 
 	return clk;
 }
+
+struct zx_clk_provider * __init zx_clk_init(struct device_node *np,
+					    void __iomem *base,
+					    unsigned int nr_clks)
+{
+	struct zx_clk_provider *clkp;
+	struct clk **clk_table;
+	int i;
+
+	clkp = kzalloc(sizeof(*clkp), GFP_KERNEL);
+	if (!clkp)
+		panic("could not allocate clock provider context.\n");
+
+	clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
+	if (!clk_table)
+		panic("could not allocate clock lookup table\n");
+
+	for (i = 0; i < nr_clks; i++)
+		clk_table[i] = ERR_PTR(-ENOENT);
+
+	clkp->reg_base = base;
+	clkp->clk_data.clks = clk_table;
+	clkp->clk_data.clk_num = nr_clks;
+	spin_lock_init(&clkp->lock);
+
+	return clkp;
+}
+
+static void __init _zx296718_clk_register_pll(struct zx_clk_provider *clkp,
+					     struct zx_pll_clock *pll_clk,
+					     unsigned int nr_plls,
+					     void __iomem *base)
+{
+	struct clk_zx_pll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+	unsigned int len;
+
+	if (pll_clk->rate_table) {
+		pr_err("%s: fail to register clk %s as no config table\n",
+			__func__, pll_clk->name);
+		return;
+	}
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n",
+			__func__, pll_clk->name);
+		return;
+	}
+
+	init.name = pll_clk->name;
+	init.flags = pll_clk->flags;
+	init.parent_names = &pll_clk->parent_name;
+	init.num_parents = pll_clk->parent_name ? 1 : 0;
+	init.ops = &zx_pll_ops;
+
+	for (len = 0; pll_clk->rate_table[len].rate != 0; )
+		len++;
+
+	pll->count = len;
+	pll->lookup_table = pll_clk->rate_table;
+	pll->hw.init = &init;
+	pll->reg_base = base + pll_clk->reg_offset;
+	pll->pd_bit = pll_clk->pd_bit;
+	pll->lock_bit = LOCK_FLAG;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s : %ld\n",
+			__func__, pll_clk->name, PTR_ERR(clk));
+		kfree(pll);
+		return;
+	}
+	zx_clk_add_lookup(clkp, clk, pll_clk->id);
+}
+
+void __init zx296718_clk_register_pll(struct zx_clk_provider *clkp,
+				      struct zx_pll_clock *list,
+				      unsigned int nr_plls, void __iomem *base)
+{
+	int i;
+
+	for (i = 0; i < nr_plls; i++, list++)
+		_zx296718_clk_register_pll(clkp, list, nr_plls, base);
+}
+
+/* register mux clocks */
+void __init zx_clk_register_mux(struct zx_clk_provider *clkp,
+				struct zx_mux_clock *list,
+				unsigned int nr_clks)
+{
+	struct clk *clk;
+	unsigned int idx;
+
+	for (idx = 0; idx < nr_clks; idx++, list++) {
+		clk = clk_register_mux(NULL, list->name, list->parent_names,
+			list->num_parents, list->flags,
+			clkp->reg_base + list->offset,
+			list->shift, list->width, list->mux_flags, &clkp->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+		zx_clk_add_lookup(clkp, clk, list->id);
+	}
+}
+
+void __init zx_clk_register_gate(struct zx_clk_provider *clkp,
+				 struct zx_gate_clock *list,
+				 unsigned int nr_clks)
+{
+	struct clk *clk;
+	unsigned int idx;
+
+	for (idx = 0; idx < nr_clks; idx++, list++) {
+		clk = clk_register_gate(NULL, list->name, list->parent_name,
+				list->flags | CLK_IGNORE_UNUSED, clkp->reg_base + list->offset,
+				list->bit_idx, list->gate_flags, &clkp->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+		zx_clk_add_lookup(clkp, clk, list->id);
+	}
+}
+
+void __init zx_clk_register_div(struct zx_clk_provider *clkp,
+				struct zx_div_clock *list,
+				unsigned int nr_clks)
+{
+	struct clk *clk;
+	unsigned int idx;
+
+	for (idx = 0; idx < nr_clks; idx++, list++) {
+		if (list->table)
+			clk = clk_register_divider_table(NULL, list->name,
+				list->parent_name, list->flags,
+				clkp->reg_base + list->offset,
+				list->shift, list->width, list->div_flags,
+				list->table, &clkp->lock);
+		else
+			clk = clk_register_divider(NULL, list->name,
+				list->parent_name, list->flags,
+				clkp->reg_base + list->offset, list->shift,
+				list->width, list->div_flags, &clkp->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+		zx_clk_add_lookup(clkp, clk, list->id);
+	}
+}
+
+void __init zx_clk_register_fixed_factor(struct zx_clk_provider *clkp,
+					 struct zx_fixed_factor_clock *list,
+					 unsigned int nr_clks)
+{
+	struct clk *clk;
+	unsigned int idx;
+
+	for (idx = 0; idx < nr_clks; idx++, list++) {
+		clk = clk_register_fixed_factor(NULL, list->name,
+			list->parent_name, list->flags, list->mult, list->div);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+		zx_clk_add_lookup(clkp, clk, list->id);
+	}
+}
diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h
index 8277a0a..59993c1 100644
--- a/drivers/clk/zte/clk.h
+++ b/drivers/clk/zte/clk.h
@@ -12,12 +12,192 @@
 #include <linux/clk-provider.h>
 #include <linux/spinlock.h>
 
+/*
+ * struct zx_fixed_factor_clock: information about fixed-factor clock
+ * @id: platform specific id of the clock.
+ * @name: name of this fixed-factor clock.
+ * @parent_name: parent clock name.
+ * @mult: fixed multiplication factor.
+ * @div: fixed division factor.
+ * @flags: optional fixed-factor clock flags.
+ */
+struct zx_fixed_factor_clock {
+	unsigned int		id;
+	char			*name;
+	const char		*parent_name;
+	unsigned long		mult;
+	unsigned long		div;
+	unsigned long		flags;
+};
+
+#define FFACTOR(_id, cname, pname, m, d, f)		\
+	{						\
+		.id		= _id,			\
+		.name		= cname,		\
+		.parent_name	= pname,		\
+		.mult		= m,			\
+		.div		= d,			\
+		.flags		= f,			\
+	}
+/**
+ * struct zx_mux_clock: information about mux clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this mux clock.
+ * @parent_names: array of pointer to parent clock names.
+ * @num_parents: number of parents listed in @parent_names.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the mux.
+ * @shift: starting bit location of the mux control bit-field in @reg.
+ * @width: width of the mux control bit-field in @reg.
+ * @mux_flags: flags for mux-type clock.
+ */
+struct zx_mux_clock {
+	unsigned int		id;
+	const char		*dev_name;
+	const char		*name;
+	const char		**parent_names;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			mux_flags;
+	const char		*alias;
+};
+
+#define __MUX(_id, dname, cname, pnames, o, s, w, f, mf, a)	\
+	{							\
+		.id		= _id,				\
+		.dev_name	= dname,			\
+		.name		= cname,			\
+		.parent_names	= pnames,			\
+		.num_parents	= ARRAY_SIZE(pnames),		\
+		.flags		= f,				\
+		.offset		= o,				\
+		.shift		= s,				\
+		.width		= w,				\
+		.mux_flags	= mf,				\
+		.alias		= a,				\
+	}
+
+#define MUX(_id, cname, pnames, o, s, w)			\
+	__MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, NULL)
+
+#define MUX_A(_id, cname, pnames, o, s, w, a)			\
+	__MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, a)
+
+#define MUX_F(_id, cname, pnames, o, s, w, f, mf)		\
+	__MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL)
+
+#define MUX_FA(_id, cname, pnames, o, s, w, f, mf, a)		\
+	__MUX(_id, NULL, cname, pnames, o, s, w, f, mf, a)
+
+/**
+ * @id: platform specific id of the clock.
+ * struct zx_div_clock: information about div clock
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this div clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the div.
+ * @shift: starting bit location of the div control bit-field in @reg.
+ * @div_flags: flags for div-type clock.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct zx_div_clock {
+	unsigned int		id;
+	const char		*dev_name;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+	const char		*alias;
+	struct clk_div_table	*table;
+};
+
+#define __DIV(_id, dname, cname, pname, o, s, w, f, df, a, t)	\
+	{							\
+		.id		= _id,				\
+		.dev_name	= dname,			\
+		.name		= cname,			\
+		.parent_name	= pname,			\
+		.flags		= f,				\
+		.offset		= o,				\
+		.shift		= s,				\
+		.width		= w,				\
+		.div_flags	= df,				\
+		.alias		= a,				\
+		.table		= t,				\
+	}
+
+#define DIV(_id, cname, pname, o, s, w)				\
+	__DIV(_id, NULL, cname, pname, o, s, w, 0, 0, NULL, NULL)
+
+#define DIV_A(_id, cname, pname, o, s, w, a)			\
+	__DIV(_id, NULL, cname, pname, o, s, w, 0, 0, a, NULL)
+
+#define DIV_F(_id, cname, pname, o, s, w, f, df)		\
+	__DIV(_id, NULL, cname, pname, o, s, w, f, df, NULL, NULL)
+
+#define DIV_T(_id, cname, pname, o, s, w, f, t)			\
+	__DIV(_id, NULL, cname, pname, o, s, w, f, 0, NULL, t)
+
 struct zx_pll_config {
 	unsigned long rate;
 	u32 cfg0;
 	u32 cfg1;
 };
 
+#define PLL_RATE(_rate, _cfg0, _cfg1)		\
+	{					\
+		.rate = _rate,			\
+		.cfg0 = _cfg0,			\
+		.cfg1 = _cfg1,			\
+	}
+
+struct zx_pll_clock {
+	unsigned int			id;
+	const char			*dev_name;
+	const char			*name;
+	const char			*parent_name;
+	unsigned long			flags;
+	unsigned int			pd_bit;
+	unsigned int			reg_offset;
+	const struct zx_pll_config	*rate_table;
+	unsigned int			rate_count;
+	const char			*alias;
+};
+
+#define __PLL(_id, _dname, _name, _pname, _flags, _pflags,	\
+		_cfg, _rtable, _alias)				\
+	{							\
+		.id		= _id,				\
+		.dev_name	= _dname,			\
+		.name		= _name,			\
+		.parent_name	= _pname,			\
+		.flags		= _flags,			\
+		.pd_bit		= _pflags,			\
+		.reg_offset	= _cfg,				\
+		.rate_table	= _rtable,			\
+		.alias		= _alias,			\
+	}
+
+#define PLL(_id, _name, _pname, _cfg, _rtable)			\
+	__PLL(_id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE,	\
+		0, _cfg, _rtable, _name)
+
+#define PLL_F(_id, _name, _pname, _flags, _pflags, _cfg, _rtable)	\
+	__PLL(_id, NULL, _name, _pname, _flags, _pflags,		\
+		_cfg, _rtable, _name)
+
+#define PLL_A(_id, _name, _pname, _cfg, _alias, _rtable)	\
+	__PLL(_id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE,	\
+		0, __cfg, _rtable, _alias)
+
 struct clk_zx_pll {
 	struct clk_hw hw;
 	void __iomem *reg_base;
@@ -28,15 +208,97 @@ struct clk_zx_pll {
 	u8 lock_bit;		/* pll lock flag bit */
 };
 
-struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
-	unsigned long flags, void __iomem *reg_base,
-	const struct zx_pll_config *lookup_table, int count, spinlock_t *lock);
+/**
+ * struct samsung_gate_clock: information about gate clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this gate clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the gate.
+ * @bit_idx: bit index of the gate control bit-field in @reg.
+ * @gate_flags: flags for gate-type clock.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct zx_gate_clock {
+	unsigned int		id;
+	const char		*dev_name;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			bit_idx;
+	u8			gate_flags;
+	const char		*alias;
+};
+
+#define __GATE(_id, dname, cname, pname, o, b, f, gf, a)	\
+	{							\
+		.id		= _id,				\
+		.dev_name	= dname,			\
+		.name		= cname,			\
+		.parent_name	= pname,			\
+		.flags		= f,				\
+		.offset		= o,				\
+		.bit_idx	= b,				\
+		.gate_flags	= gf,				\
+		.alias		= a,				\
+	}
+
+#define GATE(_id, cname, pname, o, b, f, gf)			\
+	__GATE(_id, NULL, cname, pname, o, b, f, gf, NULL)
+
+#define GATE_A(_id, cname, pname, o, b, f, gf, a)		\
+	__GATE(_id, NULL, cname, pname, o, b, f, gf, a)
+
+#define GATE_D(_id, dname, cname, pname, o, b, f, gf)		\
+	__GATE(_id, dname, cname, pname, o, b, f, gf, NULL)
+
+#define GATE_DA(_id, dname, cname, pname, o, b, f, gf, a)	\
+	__GATE(_id, dname, cname, pname, o, b, f, gf, a)
+
+#define PNAME(x) static const char *x[] __initconst
+
+/**
+ * struct samsung_clk_provider: information about clock provider
+ * @reg_base: virtual address for the register base.
+ * @clk_data: holds clock related data like clk* and number of clocks.
+ * @lock: maintains exclusion between callbacks for a given clock-provider.
+ */
+struct zx_clk_provider {
+	void __iomem *reg_base;
+	struct clk_onecell_data clk_data;
+	spinlock_t lock;
+};
 
 struct clk_zx_audio {
 	struct clk_hw hw;
 	void __iomem *reg_base;
 };
 
+struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
+				unsigned long flags, void __iomem *reg_base,
+				const struct zx_pll_config *lookup_table,
+				int count, spinlock_t *lock);
+extern struct zx_clk_provider * __init zx_clk_init(struct device_node *np,
+						   void __iomem *base,
+						   unsigned int nr_clks);
+extern void __init zx296718_clk_register_pll(struct zx_clk_provider *clkp,
+					     struct zx_pll_clock *pll_list,
+					     unsigned int nr_plls,
+					     void __iomem *base);
+extern void __init zx_clk_register_mux(struct zx_clk_provider *clkp,
+				       struct zx_mux_clock *list,
+				       unsigned int nr_clks);
+extern void __init zx_clk_register_gate(struct zx_clk_provider *clkp,
+					struct zx_gate_clock *list,
+					unsigned int nr_clks);
+extern void __init zx_clk_register_div(struct zx_clk_provider *clkp,
+				       struct zx_div_clock *list,
+				       unsigned int nr_clks);
+extern void __init zx_clk_register_fixed_factor(struct zx_clk_provider *clkp,
+				       struct zx_fixed_factor_clock *list,
+				       unsigned int nr_clks);
 struct clk *clk_register_zx_audio(const char *name,
 				  const char * const parent_name,
 				  unsigned long flags, void __iomem *reg_base);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework
  2016-07-18  9:41 [PATCH 1/3] clk: zx: reform pll config info to ease code extension Jun Nie
  2016-07-18  9:41 ` [PATCH 2/3] clk: zx: Add clk helper and zx296718 clk method Jun Nie
@ 2016-07-18  9:41 ` Jun Nie
  2016-07-19  0:15   ` Michael Turquette
  1 sibling, 1 reply; 8+ messages in thread
From: Jun Nie @ 2016-07-18  9:41 UTC (permalink / raw)
  To: sboyd, mturquette, linux-clk; +Cc: Jun Nie

The ZX296718 clocks are statically listed and registered using the
ZTE specific common clock helper functions.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
 .../devicetree/bindings/clock/zx296718-clk.txt     |  35 +
 drivers/clk/zte/Makefile                           |   1 +
 drivers/clk/zte/clk-zx296718.c                     | 833 +++++++++++++++++++++
 include/dt-bindings/clock/zx296718-clock.h         | 140 ++++
 4 files changed, 1009 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/zx296718-clk.txt
 create mode 100644 drivers/clk/zte/clk-zx296718.c
 create mode 100644 include/dt-bindings/clock/zx296718-clock.h

diff --git a/Documentation/devicetree/bindings/clock/zx296718-clk.txt b/Documentation/devicetree/bindings/clock/zx296718-clk.txt
new file mode 100644
index 0000000..a6c5d86
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/zx296718-clk.txt
@@ -0,0 +1,35 @@
+Device Tree Clock bindings for ZTE zx296718
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be one of the following:
+	"zte,zx296718-topcrm":
+		zx296718 top clock selection, divider and gating
+
+	"zte,zx296718-lsp0crm" and
+	"zte,zx296718-lsp1crm":
+		zx296718 device level clock selection and gating
+
+- reg: Address and length of the register set
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell. See include/dt-bindings/clock/zx296718-clock.h
+for the full list of zx296718 clock IDs.
+
+
+topclk: topcrm@0x09800000 {
+        compatible = "zte,zx296718-topcrm-clk";
+        reg = <0x01461000 0x1000>;
+        #clock-cells = <1>;
+};
+
+usbphy0:usb-phy0{
+	compatible = "zte,zx296718-usb-phy";
+	#phy-cells = <0>;
+	clocks = <&topcrm USB20_PHY_CLK>;
+	clock-names = "phyclk";
+	status = "okay";
+};
diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile
index 74005aa..83374bf 100644
--- a/drivers/clk/zte/Makefile
+++ b/drivers/clk/zte/Makefile
@@ -1,2 +1,3 @@
 obj-y := clk.o
 obj-$(CONFIG_SOC_ZX296702) += clk-zx296702.o
+obj-$(CONFIG_ARCH_ZX) += clk-zx296718.o
diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c
new file mode 100644
index 0000000..4f17561
--- /dev/null
+++ b/drivers/clk/zte/clk-zx296718.c
@@ -0,0 +1,833 @@
+/*
+ * Copyright (C) 2015 - 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "clk-zx296718: " fmt
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <dt-bindings/clock/zx296718-clock.h>
+#include "clk.h"
+
+/* TOP CRM */
+#define TOP_CLK_MUX0	0x04
+#define TOP_CLK_MUX1	0x08
+#define TOP_CLK_MUX2	0x0c
+#define TOP_CLK_MUX3	0x10
+#define TOP_CLK_MUX4	0x14
+#define TOP_CLK_MUX5	0x18
+#define TOP_CLK_MUX6	0x1c
+#define TOP_CLK_MUX7	0x20
+#define TOP_CLK_MUX9	0x28
+
+
+#define TOP_CLK_GATE0	0x34
+#define TOP_CLK_GATE1	0x38
+#define TOP_CLK_GATE2	0x3c
+#define TOP_CLK_GATE3	0x40
+#define TOP_CLK_GATE4	0x44
+#define TOP_CLK_GATE5	0x48
+#define TOP_CLK_GATE6	0x4c
+
+#define TOP_CLK_DIV0	0x58
+
+#define PLL_CPU_REG	0x80
+#define PLL_VGA_REG	0xb0
+#define PLL_DDR_REG	0xa0
+
+/* LSP0 CRM */
+#define LSP0_TIMER3_CLK	0x4
+#define LSP0_TIMER4_CLK	0x8
+#define LSP0_TIMER5_CLK	0xc
+#define LSP0_UART3_CLK	0x10
+#define LSP0_UART1_CLK	0x14
+#define LSP0_UART2_CLK	0x18
+#define LSP0_SPIFC0_CLK	0x1c
+#define LSP0_I2C4_CLK	0x20
+#define LSP0_I2C5_CLK	0x24
+#define LSP0_SSP0_CLK	0x28
+#define LSP0_SSP1_CLK	0x2c
+#define LSP0_USIM0_CLK	0x30
+#define LSP0_GPIO_CLK	0x34
+#define LSP0_I2C3_CLK	0x38
+
+/* LSP1 CRM */
+#define LSP1_UART4_CLK	0x08
+#define LSP1_UART5_CLK	0x0c
+#define LSP1_PWM_CLK	0x10
+#define LSP1_I2C2_CLK	0x14
+#define LSP1_SSP2_CLK	0x1c
+#define LSP1_SSP3_CLK	0x20
+#define LSP1_SSP4_CLK	0x24
+#define LSP1_USIM1_CLK	0x28
+
+/* audio lsp */
+#define AUDIO_I2S0_DIV_CFG1	0x10
+#define AUDIO_I2S0_DIV_CFG2	0x14
+#define AUDIO_I2S0_CLK		0x18
+#define AUDIO_I2S1_DIV_CFG1	0x20
+#define AUDIO_I2S1_DIV_CFG2	0x24
+#define AUDIO_I2S1_CLK		0x28
+#define AUDIO_I2S2_DIV_CFG1	0x30
+#define AUDIO_I2S2_DIV_CFG2	0x34
+#define AUDIO_I2S2_CLK		0x38
+#define AUDIO_I2S3_DIV_CFG1	0x40
+#define AUDIO_I2S3_DIV_CFG2	0x44
+#define AUDIO_I2S3_CLK		0x48
+#define AUDIO_I2C0_CLK		0x50
+#define AUDIO_SPDIF0_DIV_CFG1	0x60
+#define AUDIO_SPDIF0_DIV_CFG2	0x64
+#define AUDIO_SPDIF0_CLK	0x68
+#define AUDIO_SPDIF1_DIV_CFG1	0x70
+#define AUDIO_SPDIF1_DIV_CFG2	0x74
+#define AUDIO_SPDIF1_CLK	0x78
+#define AUDIO_TIMER_CLK		0x80
+#define AUDIO_TDM_CLK		0x90
+#define AUDIO_TS_CLK		0xa0
+
+static struct zx_pll_config pll_cpu_table[] = {
+	PLL_RATE(1312000000, 0x00103621, 0x04aaaaaa),
+	PLL_RATE(1407000000, 0x00103a21, 0x04aaaaaa),
+	PLL_RATE(1503000000, 0x00103e21, 0x04aaaaaa),
+	PLL_RATE(1600000000, 0x00104221, 0x04aaaaaa),
+};
+
+PNAME(osc) = {
+	"osc24m",
+	"osc32k",
+};
+
+PNAME(dbg_wclk_p) = {
+	"clk334m",
+	"clk466m",
+	"clk396m",
+	"clk250m",
+};
+
+PNAME(a72_coreclk_p) = {
+	"osc24m",
+	"pll_mm0_1188m",
+	"pll_mm1_1296m",
+	"clk1000m",
+	"clk648m",
+	"clk1600m",
+	"pll_audio_1800m",
+	"pll_vga_1800m",
+};
+
+PNAME(cpu_periclk_p) = {
+	"osc24m",
+	"clk500m",
+	"clk594m",
+	"clk466m",
+	"clk294m",
+	"clk334m",
+	"clk250m",
+	"clk125m",
+};
+
+PNAME(a53_coreclk_p) = {
+	"osc24m",
+	"clk1000m",
+	"pll_mm0_1188m",
+	"clk648m",
+	"clk500m",
+	"clk800m",
+	"clk1600m",
+	"pll_audio_1800m",
+};
+
+PNAME(sec_wclk_p) = {
+	"osc24m",
+	"clk396m",
+	"clk334m",
+	"clk297m",
+	"clk250m",
+	"clk198m",
+	"clk148m5",
+	"clk99m",
+};
+
+PNAME(sd_nand_wclk_p) = {
+	"osc24m",
+	"clk49m5",
+	"clk99m",
+	"clk198m",
+	"clk167m",
+	"clk148m5",
+	"clk125m",
+	"clk216m",
+};
+
+PNAME(emmc_wclk_p) = {
+	"osc24m",
+	"clk198m",
+	"clk99m",
+	"clk396m",
+	"clk334m",
+	"clk297m",
+	"clk250m",
+	"clk148m5",
+};
+
+PNAME(clk32_p) = {
+	"osc32k",
+	"clk32k768",
+};
+
+PNAME(usb_ref24m_p) = {
+	"osc32k",
+	"clk32k768",
+};
+
+PNAME(sys_noc_alck_p) = {
+	"osc24m",
+	"clk250m",
+	"clk198m",
+	"clk148m5",
+	"clk108m",
+	"clk54m",
+	"clk216m",
+	"clk240m",
+};
+
+PNAME(vde_aclk_p) = {
+	"clk334m",
+	"clk594m",
+	"clk500m",
+	"clk432m",
+	"clk480m",
+	"clk297m",
+	"clk_vga",  /*600MHz*/
+	"clk294m",
+};
+
+PNAME(vce_aclk_p) = {
+	"clk334m",
+	"clk594m",
+	"clk500m",
+	"clk432m",
+	"clk396m",
+	"clk297m",
+	"clk_vga",  /*600MHz*/
+	"clk294m",
+};
+
+PNAME(hde_aclk_p) = {
+	"clk334m",
+	"clk594m",
+	"clk500m",
+	"clk432m",
+	"clk396m",
+	"clk297m",
+	"clk_vga",  /*600MHz*/
+	"clk294m",
+};
+
+PNAME(gpu_aclk_p) = {
+	"clk334m",
+	"clk648m",
+	"clk594m",
+	"clk500m",
+	"clk396m",
+	"clk297m",
+	"clk_vga",  /*600MHz*/
+	"clk294m",
+};
+
+PNAME(sappu_aclk_p) = {
+	"clk396m",
+	"clk500m",
+	"clk250m",
+	"clk148m5",
+};
+
+PNAME(sappu_wclk_p) = {
+	"clk198m",
+	"clk396m",
+	"clk334m",
+	"clk297m",
+	"clk250m",
+	"clk148m5",
+	"clk125m",
+	"clk99m",
+};
+
+PNAME(vou_aclk_p) = {
+	"clk334m",
+	"clk594m",
+	"clk500m",
+	"clk432m",
+	"clk396m",
+	"clk297m",
+	"clk_vga",  /*600MHz*/
+	"clk294m",
+};
+
+PNAME(vou_main_wclk_p) = {
+	"clk108m",
+	"clk594m",
+	"clk297m",
+	"clk148m5",
+	"clk74m25",
+	"clk54m",
+	"clk27m",
+	"clk_vga",
+};
+
+PNAME(vou_aux_wclk_p) = {
+	"clk108m",
+	"clk148m5",
+	"clk74m25",
+	"clk54m",
+	"clk27m",
+	"clk_vga",
+	"clk54m_mm0",
+	"clk"
+};
+
+PNAME(vou_ppu_wclk_p) = {
+	"clk334m",
+	"clk432m",
+	"clk396m",
+	"clk297m",
+	"clk250m",
+	"clk125m",
+	"clk198m",
+	"clk99m",
+};
+
+PNAME(vga_i2c_wclk_p) = {
+	"osc24m",
+	"clk99m",
+};
+
+PNAME(viu_m0_aclk_p) = {
+	"clk334m",
+	"clk432m",
+	"clk396m",
+	"clk297m",
+	"clk250m",
+	"clk125m",
+	"clk198m",
+	"osc24m",
+};
+
+PNAME(viu_m1_aclk_p) = {
+	"clk198m",
+	"clk250m",
+	"clk297m",
+	"clk125m",
+	"clk396m",
+	"clk334m",
+	"clk148m5",
+	"osc24m",
+};
+
+PNAME(viu_clk_p) = {
+	"clk198m",
+	"clk334m",
+	"clk297m",
+	"clk250m",
+	"clk396m",
+	"clk125m",
+	"clk99m",
+	"clk148m5",
+};
+
+PNAME(viu_jpeg_clk_p) = {
+	"clk334m",
+	"clk480m",
+	"clk432m",
+	"clk396m",
+	"clk297m",
+	"clk250m",
+	"clk125m",
+	"clk198m",
+};
+
+PNAME(ts_sys_clk_p) = {
+	"clk192m",
+	"clk167m",
+	"clk125m",
+	"clk99m",
+};
+
+PNAME(wdt_ares_p) = {
+	"osc24m",
+	"clk32k"
+};
+
+struct zx_pll_clock zx296718_pll_clk[] __initdata = {
+	PLL(0,	"pll_cpu",	"osc24m",	PLL_CPU_REG,	pll_cpu_table),
+};
+
+struct zx_fixed_factor_clock top_ffactor_clk[] = {
+	FFACTOR(0, "clk4m",		"osc24m", 1, 6,  0),
+	FFACTOR(0, "clk2m",		"osc24m", 1, 12, 0),
+	/* pll cpu */
+	FFACTOR(0, "clk1600m",		"pll_cpu", 1, 1, CLK_SET_RATE_PARENT),
+	FFACTOR(0, "clk800m",		"pll_cpu", 1, 2, CLK_SET_RATE_PARENT),
+	/* pll mac */
+	FFACTOR(0, "clk25m",		"pll_mac", 1, 40, 0),
+	FFACTOR(0, "clk125m",		"pll_mac", 1, 8, 0),
+	FFACTOR(0, "clk250m",		"pll_mac", 1, 4, 0),
+	FFACTOR(0, "clk50m",		"pll_mac", 1, 20, 0),
+	FFACTOR(0, "clk500m",		"pll_mac", 1, 2, 0),
+	FFACTOR(0, "clk1000m",		"pll_mac", 1, 1, 0),
+	FFACTOR(0, "clk334m",		"pll_mac", 1, 3, 0),
+	FFACTOR(0, "clk167m",		"pll_mac", 1, 6, 0),
+	/* pll mm */
+	FFACTOR(0, "clk54m_mm0",	"pll_mm0", 1, 22, 0),
+	FFACTOR(0, "clk74m25",		"pll_mm0", 1, 16, 0),
+	FFACTOR(0, "clk148m5",		"pll_mm0", 1, 8, 0),
+	FFACTOR(0, "clk297m",		"pll_mm0", 1, 4, 0),
+	FFACTOR(0, "clk594m",		"pll_mm0", 1, 2, 0),
+	FFACTOR(0, "pll_mm0_1188m",	"pll_mm0", 1, 1, 0),
+	FFACTOR(0, "clk396m",		"pll_mm0", 1, 3, 0),
+	FFACTOR(0, "clk198m",		"pll_mm0", 1, 6, 0),
+	FFACTOR(0, "clk99m",		"pll_mm0", 1, 12, 0),
+	FFACTOR(0, "clk49m5",		"pll_mm0", 1, 24, 0),
+	/* pll mm */
+	FFACTOR(0, "clk324m",		"pll_mm1", 1, 4, 0),
+	FFACTOR(0, "clk648m",		"pll_mm1", 1, 2, 0),
+	FFACTOR(0, "pll_mm1_1296m",	"pll_mm1", 1, 1, 0),
+	FFACTOR(0, "clk216m",		"pll_mm1", 1, 6, 0),
+	FFACTOR(0, "clk432m",		"pll_mm1", 1, 3, 0),
+	FFACTOR(0, "clk108m",		"pll_mm1", 1, 12, 0),
+	FFACTOR(0, "clk72m",		"pll_mm1", 1, 18, 0),
+	FFACTOR(0, "clk27m",		"pll_mm1", 1, 48, 0),
+	FFACTOR(0, "clk54m",		"pll_mm1", 1, 24, 0),
+	/* vga */
+	FFACTOR(0, "pll_vga_1800m",	"pll_vga", 1, 1, 0),
+	FFACTOR(0, "clk_vga",		"pll_vga", 1, 2, 0),
+	/* pll ddr */
+	FFACTOR(0, "clk466m",		"pll_ddr", 1, 2, 0),
+
+	/* pll audio */
+	FFACTOR(0, "pll_audio_1800m",	"pll_audio", 1, 1, 0),
+	FFACTOR(0, "clk32k768",		"pll_audio", 1, 27000, 0),
+	FFACTOR(0, "clk16m384",		"pll_audio", 1, 54, 0),
+	FFACTOR(0, "clk294m",		"pll_audio", 1, 3, 0),
+
+	/* pll hsic*/
+	FFACTOR(0, "clk240m",		"pll_hsic", 1, 4, 0),
+	FFACTOR(0, "clk480m",		"pll_hsic", 1, 2, 0),
+	FFACTOR(0, "clk192m",		"pll_hsic", 1, 5, 0),
+	FFACTOR(0, "clk_pll_24m",	"pll_hsic", 1, 40, 0),
+	FFACTOR(0, "emmc_mux_div2",	"emmc_mux", 1, 2, CLK_SET_RATE_PARENT),
+};
+
+static struct clk_div_table noc_div_table[] = {
+	{ .val = 1, .div = 2, },
+	{ .val = 3, .div = 4, },
+};
+struct zx_div_clock top_div_clk[] __initdata = {
+	DIV_T(0, "sys_noc_hclk", "sys_noc_aclk", TOP_CLK_DIV0, 0, 2, 0, noc_div_table),
+	DIV_T(0, "sys_noc_pclk", "sys_noc_aclk", TOP_CLK_DIV0, 4, 2, 0, noc_div_table),
+};
+
+struct zx_mux_clock top_mux_clk[] __initdata = {
+	MUX(0, "dbg_mux",	 dbg_wclk_p,	  TOP_CLK_MUX0, 12, 2),
+	MUX(0, "a72_mux",	 a72_coreclk_p,	  TOP_CLK_MUX0, 8, 3),
+	MUX(0, "cpu_peri_mux",	 cpu_periclk_p,	  TOP_CLK_MUX0, 4, 3),
+	MUX_F(0, "a53_mux",	 a53_coreclk_p,	  TOP_CLK_MUX0, 0, 3, CLK_SET_RATE_PARENT, 0),
+	MUX(0, "sys_noc_aclk",	 sys_noc_alck_p,  TOP_CLK_MUX1, 0, 3),
+	MUX(0, "sec_mux",	 sec_wclk_p,	  TOP_CLK_MUX2, 16, 3),
+	MUX(0, "sd1_mux",	 sd_nand_wclk_p,  TOP_CLK_MUX2, 12, 3),
+	MUX(0, "sd0_mux",	 sd_nand_wclk_p,  TOP_CLK_MUX2, 8, 3),
+	MUX(0, "emmc_mux",	 emmc_wclk_p,	  TOP_CLK_MUX2, 4, 3),
+	MUX(0, "nand_mux",	 sd_nand_wclk_p,  TOP_CLK_MUX2, 0, 3),
+	MUX(0, "usb_ref24m_mux", usb_ref24m_p,	  TOP_CLK_MUX9, 16, 1),
+	MUX(0, "clk32k",	 clk32_p,	  TOP_CLK_MUX9, 12, 1),
+	MUX_F(0, "wdt_mux",	 wdt_ares_p,	  TOP_CLK_MUX9, 8, 1, CLK_SET_RATE_PARENT, 0),
+	MUX(0, "timer_mux",	 osc,		  TOP_CLK_MUX9, 4, 1),
+	MUX(0, "vde_mux",	 vde_aclk_p,	  TOP_CLK_MUX4,  0, 3),
+	MUX(0, "vce_mux",	 vce_aclk_p,	  TOP_CLK_MUX4,  4, 3),
+	MUX(0, "hde_mux",	 hde_aclk_p,	  TOP_CLK_MUX4,  8, 3),
+	MUX(0, "gpu_mux",	 gpu_aclk_p,	  TOP_CLK_MUX5,  0, 3),
+	MUX(0, "sappu_a_mux",	 sappu_aclk_p,	  TOP_CLK_MUX5,  4, 2),
+	MUX(0, "sappu_w_mux",	 sappu_wclk_p,	  TOP_CLK_MUX5,  8, 3),
+	MUX(0, "vou_a_mux",	 vou_aclk_p,	  TOP_CLK_MUX7,  0, 3),
+	MUX(0, "vou_main_w_mux", vou_main_wclk_p, TOP_CLK_MUX7,  4, 3),
+	MUX(0, "vou_aux_w_mux",	 vou_aux_wclk_p,  TOP_CLK_MUX7,  8, 3),
+	MUX(0, "vou_ppu_w_mux",	 vou_ppu_wclk_p,  TOP_CLK_MUX7, 12, 3),
+	MUX(0, "vga_i2c_mux",	 vga_i2c_wclk_p,  TOP_CLK_MUX7, 16, 1),
+	MUX(0, "viu_m0_a_mux",	 viu_m0_aclk_p,	  TOP_CLK_MUX6,  0, 3),
+	MUX(0, "viu_m1_a_mux",	 viu_m1_aclk_p,	  TOP_CLK_MUX6,  4, 3),
+	MUX(0, "viu_w_mux",	 viu_clk_p,	  TOP_CLK_MUX6,  8, 3),
+	MUX(0, "viu_jpeg_w_mux", viu_jpeg_clk_p,  TOP_CLK_MUX6, 12, 3),
+	MUX(0, "ts_sys_mux",	 ts_sys_clk_p,    TOP_CLK_MUX6, 16, 2),
+};
+
+struct zx_gate_clock top_gate_clk[] __initdata = {
+	GATE(CPU_DBG_GATE,    "dbg_wclk",        "dbg_mux",        TOP_CLK_GATE0, 4, CLK_SET_RATE_PARENT, 0),
+	GATE(A72_GATE,        "a72_coreclk",     "a72_mux",        TOP_CLK_GATE0, 3, CLK_SET_RATE_PARENT, 0),
+	GATE(CPU_PERI_GATE,   "cpu_peri",        "cpu_peri_mux",   TOP_CLK_GATE0, 1, CLK_SET_RATE_PARENT, 0),
+	GATE(A53_GATE,        "a53_coreclk",     "a53_mux",        TOP_CLK_GATE0, 0, CLK_SET_RATE_PARENT, 0),
+	GATE(SD1_WCLK,        "sd1_wclk",        "sd1_mux",        TOP_CLK_GATE1, 13, CLK_SET_RATE_PARENT, 0),
+	GATE(SD0_WCLK,        "sd0_wclk",        "sd0_mux",        TOP_CLK_GATE1, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(EMMC_WCLK,       "emmc_wclk",       "emmc_mux_div2",  TOP_CLK_GATE0, 5, CLK_SET_RATE_PARENT, 0),
+	GATE(EMMC_NAND_AXI,   "emmc_nand_aclk",  "sys_noc_aclk",   TOP_CLK_GATE1, 4, CLK_SET_RATE_PARENT, 0),
+	GATE(NAND_WCLK,       "nand_wclk",       "nand_mux",       TOP_CLK_GATE0, 1, CLK_SET_RATE_PARENT, 0),
+	GATE(EMMC_NAND_AHB,   "emmc_nand_hclk",  "sys_noc_hclk",   TOP_CLK_GATE1, 0, CLK_SET_RATE_PARENT, 0),
+	GATE(0,               "lsp1_pclk",       "sys_noc_pclk",   TOP_CLK_GATE2, 31, 0,                  0),
+	GATE(LSP1_148M5,      "lsp1_148m5",      "clk148m5",       TOP_CLK_GATE2, 30, 0,                  0),
+	GATE(LSP1_99M,        "lsp1_99m",        "clk99m",         TOP_CLK_GATE2, 29, 0,                  0),
+	GATE(LSP1_24M,        "lsp1_24m",        "osc24m",         TOP_CLK_GATE2, 28, 0,                  0),
+	GATE(LSP0_74M25,      "lsp0_74m25",      "clk74m25",       TOP_CLK_GATE2, 25, 0,                  0),
+	GATE(0,               "lsp0_pclk",       "sys_noc_pclk",   TOP_CLK_GATE2, 24, 0,                  0),
+	GATE(LSP0_32K,        "lsp0_32k",        "osc32k",         TOP_CLK_GATE2, 23, 0,                  0),
+	GATE(LSP0_148M5,      "lsp0_148m5",      "clk148m5",       TOP_CLK_GATE2, 22, 0,                  0),
+	GATE(LSP0_99M,        "lsp0_99m",        "clk99m",         TOP_CLK_GATE2, 21, 0,                  0),
+	GATE(LSP0_24M,        "lsp0_24m",        "osc24m",         TOP_CLK_GATE2, 20, 0,                  0),
+	GATE(AUDIO_99M,       "audio_99m",       "clk99m",         TOP_CLK_GATE5, 27, 0,                  0),
+	GATE(AUDIO_24M,       "audio_24m",       "osc24m",         TOP_CLK_GATE5, 28, 0,                  0),
+	GATE(AUDIO_16M384,    "audio_16m384",    "clk16m384",      TOP_CLK_GATE5, 29, 0,                  0),
+	GATE(AUDIO_32K,       "audio_32k",       "clk32k",         TOP_CLK_GATE5, 30, 0,                  0),
+	GATE(WDT_WCLK,        "wdt_wclk",        "wdt_mux",        TOP_CLK_GATE6, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(TIMER_WCLK,      "timer_wclk",      "timer_mux",      TOP_CLK_GATE6, 5, CLK_SET_RATE_PARENT, 0),
+	GATE(VDE_ACLK,        "vde_aclk",        "vde_mux",        TOP_CLK_GATE3, 0,  CLK_SET_RATE_PARENT, 0),
+	GATE(VCE_ACLK,        "vce_aclk",        "vce_mux",        TOP_CLK_GATE3, 4,  CLK_SET_RATE_PARENT, 0),
+	GATE(HDE_ACLK,        "hde_aclk",        "hde_mux",        TOP_CLK_GATE3, 8,  CLK_SET_RATE_PARENT, 0),
+	GATE(GPU_ACLK,        "gpu_aclk",        "gpu_mux",        TOP_CLK_GATE3, 16, CLK_SET_RATE_PARENT, 0),
+	GATE(SAPPU_ACLK,      "sappu_aclk",      "sappu_a_mux",    TOP_CLK_GATE3, 20, CLK_SET_RATE_PARENT, 0),
+	GATE(SAPPU_WCLK,      "sappu_wclk",      "sappu_w_mux",    TOP_CLK_GATE3, 22, CLK_SET_RATE_PARENT, 0),
+	GATE(VOU_ACLK,        "vou_aclk",        "vou_a_mux",      TOP_CLK_GATE4, 16, CLK_SET_RATE_PARENT, 0),
+	GATE(VOU_MAIN_WCLK,   "vou_main_wclk",   "vou_main_w_mux", TOP_CLK_GATE4, 18, CLK_SET_RATE_PARENT, 0),
+	GATE(VOU_AUX_WCLK,    "vou_aux_wclk",    "vou_aux_w_mux",  TOP_CLK_GATE4, 19, CLK_SET_RATE_PARENT, 0),
+	GATE(VOU_PPU_WCLK,    "vou_ppu_wclk",    "vou_ppu_w_mux",  TOP_CLK_GATE4, 20, CLK_SET_RATE_PARENT, 0),
+	GATE(MIPI_CFG_CLK,    "mipi_cfg_clk",    "osc24m",         TOP_CLK_GATE4, 21, 0,                   0),
+	GATE(VGA_I2C_WCLK,    "vga_i2c_wclk",    "vga_i2c_mux",    TOP_CLK_GATE4, 23, CLK_SET_RATE_PARENT, 0),
+	GATE(MIPI_REF_CLK,    "mipi_ref_clk",    "clk27m",         TOP_CLK_GATE4, 24, 0,                   0),
+	GATE(HDMI_OSC_CEC,    "hdmi_osc_cec",    "clk2m",          TOP_CLK_GATE4, 22, 0,                   0),
+	GATE(HDMI_OSC_CLK,    "hdmi_osc_clk",    "clk240m",        TOP_CLK_GATE4, 25, 0,                   0),
+	GATE(HDMI_XCLK,       "hdmi_xclk",       "osc24m",         TOP_CLK_GATE4, 26, 0,                   0),
+	GATE(VIU_M0_ACLK,     "viu_m0_aclk",     "viu_m0_a_mux",   TOP_CLK_GATE4, 0,  CLK_SET_RATE_PARENT, 0),
+	GATE(VIU_M1_ACLK,     "viu_m1_aclk",     "viu_m1_a_mux",   TOP_CLK_GATE4, 1,  CLK_SET_RATE_PARENT, 0),
+	GATE(VIU_WCLK,        "viu_wclk",        "viu_w_mux",      TOP_CLK_GATE4, 2,  CLK_SET_RATE_PARENT, 0),
+	GATE(VIU_JPEG_WCLK,   "viu_jpeg_wclk",   "viu_jpeg_w_mux", TOP_CLK_GATE4, 3,  CLK_SET_RATE_PARENT, 0),
+	GATE(VIU_CFG_CLK,     "viu_cfg_clk",     "osc24m",         TOP_CLK_GATE4, 6,  0,                   0),
+	GATE(TS_SYS_WCLK,     "ts_sys_wclk",     "ts_sys_mux",     TOP_CLK_GATE5, 2,  CLK_SET_RATE_PARENT, 0),
+	GATE(TS_SYS_108M,     "ts_sys_108m",     "clk108m",        TOP_CLK_GATE5, 3,  0,                   0),
+	GATE(USB20_HCLK,      "usb20_hclk",      "sys_noc_hclk",   TOP_CLK_GATE2, 12, 0,                   0),
+	GATE(USB20_PHY_CLK,   "usb20_phy_clk",   "usb_ref24m_mux", TOP_CLK_GATE2, 13, 0,                   0),
+	GATE(USB21_HCLK,      "usb21_hclk",      "sys_noc_hclk",   TOP_CLK_GATE2, 14, 0,                   0),
+	GATE(USB21_PHY_CLK,   "usb21_phy_clk",   "usb_ref24m_mux", TOP_CLK_GATE2, 15, 0,                   0),
+	GATE(GMAC_RMIICLK,    "gmac_rmii_clk",   "clk50m",         TOP_CLK_GATE2, 3, 0,                    0),
+	GATE(GMAC_PCLK,       "gmac_pclk",       "clk198m",        TOP_CLK_GATE2, 1, 0,                    0),
+	GATE(GMAC_ACLK,       "gmac_aclk",       "clk49m5",        TOP_CLK_GATE2, 0, 0,                    0),
+	GATE(GMAC_RFCLK,      "gmac_refclk",     "clk25m",         TOP_CLK_GATE2, 4, 0,                    0),
+	GATE(SD1_AHB,         "sd1_hclk",        "sys_noc_hclk",   TOP_CLK_GATE1, 12,  0,                  0),
+	GATE(SD0_AHB,         "sd0_hclk",        "sys_noc_hclk",   TOP_CLK_GATE1, 8,  0,                   0),
+	GATE(TEMPSENSOR_GATE, "tempsensor_gate", "clk4m",          TOP_CLK_GATE5, 31,  0,                  0),
+};
+
+static void __init zx296718_top_clocks_init(struct device_node *np)
+{
+	struct zx_clk_provider *clkp;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	clkp = zx_clk_init(np, reg_base, TOP_NR_CLKS);
+	if (!clkp)
+		panic("%s: unable to allocate context.\n", __func__);
+	zx296718_clk_register_pll(clkp, zx296718_pll_clk, ARRAY_SIZE(zx296718_pll_clk), reg_base);
+	zx_clk_register_fixed_factor(clkp, top_ffactor_clk, ARRAY_SIZE(top_ffactor_clk));
+	zx_clk_register_mux(clkp, top_mux_clk, ARRAY_SIZE(top_mux_clk));
+	zx_clk_register_gate(clkp, top_gate_clk, ARRAY_SIZE(top_gate_clk));
+
+	if (of_clk_add_provider(np, of_clk_src_onecell_get, &clkp->clk_data))
+		panic("could not register clk provider\n");
+	pr_info("top clk init over, nr:%d\n", TOP_NR_CLKS);
+}
+CLK_OF_DECLARE(zx296718_top_clk, "zte,zx296718-topcrm", zx296718_top_clocks_init);
+
+static struct clk_div_table common_even_div_table[] = {
+	{ .val = 0, .div = 1, },
+	{ .val = 1, .div = 2, },
+	{ .val = 3, .div = 4, },
+	{ .val = 5, .div = 6, },
+	{ .val = 7, .div = 8, },
+	{ .val = 9, .div = 10, },
+	{ .val = 11, .div = 12, },
+	{ .val = 13, .div = 14, },
+	{ .val = 15, .div = 16, },
+};
+
+static struct clk_div_table common_div_table[] = {
+	{ .val = 0, .div = 1, },
+	{ .val = 1, .div = 2, },
+	{ .val = 2, .div = 3, },
+	{ .val = 3, .div = 4, },
+	{ .val = 4, .div = 5, },
+	{ .val = 5, .div = 6, },
+	{ .val = 6, .div = 7, },
+	{ .val = 7, .div = 8, },
+	{ .val = 8, .div = 9, },
+	{ .val = 9, .div = 10, },
+	{ .val = 10, .div = 11, },
+	{ .val = 11, .div = 12, },
+	{ .val = 12, .div = 13, },
+	{ .val = 13, .div = 14, },
+	{ .val = 14, .div = 15, },
+	{ .val = 15, .div = 16, },
+};
+
+PNAME(lsp0_wclk_common_p) = {
+	"lsp0_24m",
+	"lsp0_99m",
+};
+
+PNAME(lsp0_wclk_timer3_p) = {
+	"timer3_div",
+	"lsp0_32k"
+};
+
+PNAME(lsp0_wclk_timer4_p) = {
+	"timer4_div",
+	"lsp0_32k"
+};
+
+PNAME(lsp0_wclk_timer5_p) = {
+	"timer5_div",
+	"lsp0_32k"
+};
+
+PNAME(lsp0_wclk_spifc0_p) = {
+	"lsp0_148m5",
+	"lsp0_24m",
+	"lsp0_99m",
+	"lsp0_74m25"
+};
+
+PNAME(lsp0_wclk_ssp_p) = {
+	"lsp0_148m5",
+	"lsp0_99m",
+	"lsp0_24m",
+};
+
+struct zx_mux_clock lsp0_mux_clk[] __initdata = {
+	MUX(0, "timer3_wclk_mux", lsp0_wclk_timer3_p, LSP0_TIMER3_CLK, 4, 1),
+	MUX(0, "timer4_wclk_mux", lsp0_wclk_timer4_p, LSP0_TIMER4_CLK, 4, 1),
+	MUX(0, "timer5_wclk_mux", lsp0_wclk_timer5_p, LSP0_TIMER5_CLK, 4, 1),
+	MUX(0, "uart3_wclk_mux",  lsp0_wclk_common_p, LSP0_UART3_CLK,  4, 1),
+	MUX(0, "uart1_wclk_mux",  lsp0_wclk_common_p, LSP0_UART1_CLK,  4, 1),
+	MUX(0, "uart2_wclk_mux",  lsp0_wclk_common_p, LSP0_UART2_CLK,  4, 1),
+	MUX(0, "spifc0_wclk_mux", lsp0_wclk_spifc0_p, LSP0_SPIFC0_CLK, 4, 2),
+	MUX(0, "i2c4_wclk_mux",   lsp0_wclk_common_p, LSP0_I2C4_CLK,   4, 1),
+	MUX(0, "i2c5_wclk_mux",   lsp0_wclk_common_p, LSP0_I2C5_CLK,   4, 1),
+	MUX(0, "ssp0_wclk_mux",   lsp0_wclk_ssp_p,    LSP0_SSP0_CLK,   4, 1),
+	MUX(0, "ssp1_wclk_mux",   lsp0_wclk_ssp_p,    LSP0_SSP1_CLK,   4, 1),
+	MUX(0, "i2c3_wclk_mux",   lsp0_wclk_common_p, LSP0_I2C3_CLK,   4, 1),
+};
+
+struct zx_gate_clock lsp0_gate_clk[] __initdata = {
+	GATE(LSP0_TIMER3_WCLK, "timer3_wclk", "timer3_wclk_mux", LSP0_TIMER3_CLK, 1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_TIMER4_WCLK, "timer4_wclk", "timer4_wclk_mux", LSP0_TIMER4_CLK, 1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_TIMER5_WCLK, "timer5_wclk", "timer5_wclk_mux", LSP0_TIMER5_CLK, 1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_UART3_WCLK,  "uart3_wclk",  "uart3_wclk_mux",  LSP0_UART3_CLK,  1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_UART1_WCLK,  "uart1_wclk",  "uart1_wclk_mux",  LSP0_UART1_CLK,  1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_UART2_WCLK,  "uart2_wclk",  "uart2_wclk_mux",  LSP0_UART2_CLK,  1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_SPIFC0_WCLK, "spifc0_wclk", "spifc0_wclk_mux", LSP0_SPIFC0_CLK, 1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_I2C4_WCLK,   "i2c4_wclk",   "i2c4_wclk_mux",   LSP0_I2C4_CLK,   1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_I2C5_WCLK,   "i2c5_wclk",   "i2c5_wclk_mux",   LSP0_I2C5_CLK,   1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_SSP0_WCLK,   "ssp0_wclk",   "ssp0_div",        LSP0_SSP0_CLK,   1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_SSP1_WCLK,   "ssp1_wclk",   "ssp1_div",        LSP0_SSP1_CLK,   1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP0_I2C3_WCLK,   "i2c3_wclk",   "i2c3_wclk_mux",   LSP0_I2C3_CLK,   1, CLK_SET_RATE_PARENT, 0),
+};
+
+struct zx_div_clock lsp0_div_clk[] __initdata = {
+	DIV_T(0, "timer3_div", "lsp0_24m", LSP0_TIMER3_CLK,  12, 4, 0, common_even_div_table),
+	DIV_T(0, "timer4_div", "lsp0_24m", LSP0_TIMER4_CLK,  12, 4, 0, common_even_div_table),
+	DIV_T(0, "timer5_div", "lsp0_24m", LSP0_TIMER5_CLK,  12, 4, 0, common_even_div_table),
+	DIV_T(0, "ssp0_div", "ssp0_wclk_mux", LSP0_SSP0_CLK, 12, 4, 0, common_even_div_table),
+	DIV_T(0, "ssp1_div", "ssp1_wclk_mux", LSP0_SSP1_CLK, 12, 4, 0, common_even_div_table),
+};
+
+static void __init lsp0_clocks_init(struct device_node *np)
+{
+	struct zx_clk_provider *clkp;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	clkp = zx_clk_init(np, reg_base, LSP0_NR_CLKS);
+	if (!clkp)
+		panic("%s: unable to allocate context.\n", __func__);
+
+	zx_clk_register_mux(clkp, lsp0_mux_clk, ARRAY_SIZE(lsp0_mux_clk));
+	zx_clk_register_gate(clkp, lsp0_gate_clk, ARRAY_SIZE(lsp0_gate_clk));
+	zx_clk_register_div(clkp, lsp0_div_clk, ARRAY_SIZE(lsp0_div_clk));
+
+	if (of_clk_add_provider(np, of_clk_src_onecell_get, &clkp->clk_data))
+		panic("could not register clk provider\n");
+	pr_info("lsp0 init over:%d\n", LSP0_NR_CLKS);
+}
+CLK_OF_DECLARE(lsp0_clk, "zte,zx296718-lsp0crm", lsp0_clocks_init);
+
+
+PNAME(lsp1_wclk_common_p) = {
+	"lsp1_24m",
+	"lsp1_99m",
+};
+
+PNAME(lsp1_wclk_ssp_p) = {
+	"lsp1_148m5",
+	"lsp1_99m",
+	"lsp1_24m",
+};
+
+struct zx_mux_clock lsp1_mux_clk[] __initdata = {
+	MUX(0, "uart4_wclk_mux", lsp1_wclk_common_p, LSP1_UART4_CLK, 4, 1),
+	MUX(0, "uart5_wclk_mux", lsp1_wclk_common_p, LSP1_UART5_CLK, 4, 1),
+	MUX(0, "pwm_wclk_mux",   lsp1_wclk_common_p, LSP1_PWM_CLK,   4, 1),
+	MUX(0, "i2c2_wclk_mux",  lsp1_wclk_common_p, LSP1_I2C2_CLK,  4, 1),
+	MUX(0, "ssp2_wclk_mux",  lsp1_wclk_ssp_p,    LSP1_SSP2_CLK,  4, 2),
+	MUX(0, "ssp3_wclk_mux",  lsp1_wclk_ssp_p,    LSP1_SSP3_CLK,  4, 2),
+	MUX(0, "ssp4_wclk_mux",  lsp1_wclk_ssp_p,    LSP1_SSP4_CLK,  4, 2),
+	MUX(0, "usim1_wclk_mux", lsp1_wclk_common_p, LSP1_USIM1_CLK, 4, 1),
+};
+
+struct zx_div_clock lsp1_div_clk[] __initdata = {
+	DIV_T(0, "pwm_div",  "pwm_wclk_mux",  LSP1_PWM_CLK,  12, 4, CLK_SET_RATE_PARENT, common_div_table),
+	DIV_T(0, "ssp2_div", "ssp2_wclk_mux", LSP1_SSP2_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table),
+	DIV_T(0, "ssp3_div", "ssp3_wclk_mux", LSP1_SSP3_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table),
+	DIV_T(0, "ssp4_div", "ssp4_wclk_mux", LSP1_SSP4_CLK, 12, 4, CLK_SET_RATE_PARENT, common_even_div_table),
+};
+
+struct zx_gate_clock lsp1_gate_clk[] __initdata = {
+	GATE(LSP1_UART4_WCLK, "lsp1_uart4_wclk", "uart4_wclk_mux", LSP1_UART4_CLK, 1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP1_UART5_WCLK, "lsp1_uart5_wclk", "uart5_wclk_mux", LSP1_UART5_CLK, 1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP1_PWM_WCLK,   "lsp1_pwm_wclk",   "pwm_div",        LSP1_PWM_CLK,   1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP1_PWM_PCLK,   "lsp1_pwm_pclk",   "lsp1_pclk",      LSP1_PWM_CLK,   0, 0,		   0),
+	GATE(LSP1_I2C2_WCLK,  "lsp1_i2c2_wclk",  "i2c2_wclk_mux",  LSP1_I2C2_CLK,  1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP1_SSP2_WCLK,  "lsp1_ssp2_wclk",  "ssp2_div",       LSP1_SSP2_CLK,  1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP1_SSP3_WCLK,  "lsp1_ssp3_wclk",  "ssp3_div",       LSP1_SSP3_CLK,  1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP1_SSP4_WCLK,  "lsp1_ssp4_wclk",  "ssp4_div",       LSP1_SSP4_CLK,  1, CLK_SET_RATE_PARENT, 0),
+	GATE(LSP1_USIM1_WCLK, "lsp1_usim1_wclk", "usim1_wclk_mux", LSP1_USIM1_CLK, 1, CLK_SET_RATE_PARENT, 0),
+};
+
+
+static void __init lsp1_clocks_init(struct device_node *np)
+{
+	struct zx_clk_provider *clkp;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	clkp = zx_clk_init(np, reg_base, LSP1_NR_CLKS);
+	if (!clkp)
+		panic("%s: unable to allocate context.\n", __func__);
+
+	zx_clk_register_mux(clkp, lsp1_mux_clk, ARRAY_SIZE(lsp1_mux_clk));
+	zx_clk_register_gate(clkp, lsp1_gate_clk, ARRAY_SIZE(lsp1_gate_clk));
+	zx_clk_register_div(clkp, lsp1_div_clk, ARRAY_SIZE(lsp1_div_clk));
+	if (of_clk_add_provider(np, of_clk_src_onecell_get, &clkp->clk_data))
+		panic("could not register clk provider\n");
+	pr_info("lsp1-clk init over, nr:%d\n", LSP1_NR_CLKS);
+}
+CLK_OF_DECLARE(lsp1_clk, "zte,zx296718-lsp1crm", lsp1_clocks_init);
+
+
+
+#if 0
+PNAME(audio_wclk_common_p) = {
+	"audio_24m",
+	"audio_99m",
+};
+
+PNAME(audio_timer_p) = {
+	"audio_24m",
+	"audio_32k",
+};
+
+
+struct zx_mux_clock audio_mux_clk[] __initdata = {
+	MUX(0, "i2s0_wclk_mux", audio_wclk_common_p, AUDIO_I2S0_CLK, 0, 1),
+	MUX(0, "i2s1_wclk_mux", audio_wclk_common_p, AUDIO_I2S1_CLK, 0, 1),
+	MUX(0, "i2s2_wclk_mux", audio_wclk_common_p, AUDIO_I2S2_CLK, 0, 1),
+	MUX(0, "i2s3_wclk_mux", audio_wclk_common_p, AUDIO_I2S3_CLK, 0, 1),
+	MUX(0, "i2c0_wclk_mux", audio_wclk_common_p, AUDIO_I2C0_CLK, 0, 1),
+	MUX(0, "spdif0_wclk_mux", audio_wclk_common_p, AUDIO_SPDIF0_CLK, 0, 1),
+	MUX(0, "spdif1_wclk_mux", audio_wclk_common_p, AUDIO_SPDIF1_CLK, 0, 1),
+	MUX(0, "timer_wclk_mux", audio_timer_p, AUDIO_TIMER_CLK, 0, 1),
+};
+
+
+struct zx_clk_audio_div_table i2s_wclk_div_table[] = {
+	{2048000, 0x3000030, 0xffff5700},
+	{4096000, 0x3000018, 0xffff2b80},
+	{2822400, 0x3000011, 0xffff89cb},
+	{3072000, 0x3000010, 0xffff1d00},
+	{4096000, 0x300000c, 0xffff15c0},
+	{5644800, 0x3000008, 0xffffc4e5},
+	{6144000, 0x3000008, 0xffff0e80},
+	{11289600, 0x3000004, 0xffff6273},
+	{12288000, 0x3000004, 0xffff0740},
+	{22579200, 0x3000002, 0xffff3139},
+	{24576000, 0x3000002, 0xffff03a0},
+};
+
+struct zx_clk_audio_div_table spdif_wclk_div_table[] = {
+	{2822400, 0x00023, 0xffff1397},
+	{3072000, 0x00020, 0xffff3a00},
+	{4096000, 0x00018, 0xffff2b80},
+	{5644800, 0x00011, 0xffff89cb},
+	{6144000, 0x00010, 0xffff1d00},
+	{11289600, 0x00008, 0xffffc4e5},
+	{12288000, 0x00008, 0xffff0e80},
+	{22579200, 0x00004, 0xffff6273},
+	{24576000, 0x00004, 0xffff0740},
+};
+struct zx_audio_div_clock audio_adiv_clk[] __initdata = {
+	DIV_AUDIO(0, "i2s0_wclk_div", "i2s0_wclk_mux", AUDIO_I2S0_DIV_CFG1, 0, i2s_wclk_div_table),
+	DIV_AUDIO(0, "i2s1_wclk_div", "i2s1_wclk_mux", AUDIO_I2S1_DIV_CFG1, 0, i2s_wclk_div_table),
+	DIV_AUDIO(0, "i2s2_wclk_div", "i2s2_wclk_mux", AUDIO_I2S2_DIV_CFG1, 0, i2s_wclk_div_table),
+	DIV_AUDIO(0, "i2s3_wclk_div", "i2s3_wclk_mux", AUDIO_I2S3_DIV_CFG1, 0, i2s_wclk_div_table),
+	DIV_AUDIO(0, "spdif0_wclk_div", "spdif0_wclk_mux", AUDIO_SPDIF0_DIV_CFG1, 0, spdif_wclk_div_table),
+	DIV_AUDIO(0, "spdif1_wclk_div", "spdif1_wclk_mux", AUDIO_SPDIF1_DIV_CFG1, 0, spdif_wclk_div_table),
+};
+
+struct zx_div_clock audio_div_clk[] __initdata = {
+	/*DIV_T(0, "i2s0_wclk_div_int", "i2s0_wclk_div_frac", AUDIO_I2S0_DIV_CFG2, 24, 4, CLK_SET_RATE_PARENT, common_even_div_table),
+	DIV_T(0, "i2s1_wclk_div_int", "i2s1_wclk_div_frac", AUDIO_I2S1_DIV_CFG2, 24, 4, CLK_SET_RATE_PARENT, common_even_div_table),
+	DIV_T(0, "i2s2_wclk_div_int", "i2s2_wclk_div_frac", AUDIO_I2S2_DIV_CFG2, 24, 4, CLK_SET_RATE_PARENT, common_even_div_table),
+	DIV_T(0, "i2s3_wclk_div_int", "i2s3_wclk_div_frac", AUDIO_I2S3_DIV_CFG2, 24, 4, CLK_SET_RATE_PARENT, common_even_div_table),*/
+	DIV_T(0, "tdm_wclk_div", "audio_16m384", AUDIO_TDM_CLK, 8, 4, 0, common_div_table),
+};
+struct zx_gate_clock audio_gate_clk[] __initdata = {
+	GATE(AUDIO_I2S0_WCLK, "i2s0_wclk", "i2s0_wclk_div", AUDIO_I2S0_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_I2S1_WCLK, "i2s1_wclk", "i2s1_wclk_div", AUDIO_I2S1_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_I2S2_WCLK, "i2s2_wclk", "i2s2_wclk_div", AUDIO_I2S2_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_I2S3_WCLK, "i2s3_wclk", "i2s3_wclk_div", AUDIO_I2S3_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_I2C0_WCLK, "i2c0_wclk", "i2c0_wclk_mux", AUDIO_I2C0_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_SPDIF0_WCLK, "spdif0_wclk", "spdif0_wclk_div", AUDIO_SPDIF0_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_SPDIF1_WCLK, "spdif1_wclk", "spdif1_wclk_div", AUDIO_SPDIF1_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_TDM_WCLK, "tdm_wclk", "tdm_wclk_div", AUDIO_TDM_CLK, 17, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_TS_PCLK, "tempsensor_pclk", "clk49m5", AUDIO_TS_CLK, 1, 0, 0),
+};
+static void __init audio_clocks_init(struct device_node *np)
+{
+	struct zx_clk_provider *clkp;
+	void __iomem *reg_base;
+
+	reg_base = of_iomap(np, 0);
+	clkp = zx_clk_init(np, reg_base, AUDIO_NR_CLKS);
+	if (!clkp)
+		panic("%s: unable to allocate context.\n", __func__);
+
+	zx_clk_register_mux(clkp, audio_mux_clk, ARRAY_SIZE(audio_mux_clk));
+	zx_clk_register_div_audio(clkp, audio_adiv_clk, ARRAY_SIZE(audio_adiv_clk));
+	zx_clk_register_div(clkp, audio_div_clk, ARRAY_SIZE(audio_div_clk));
+	zx_clk_register_gate(clkp, audio_gate_clk, ARRAY_SIZE(audio_gate_clk));
+	if (of_clk_add_provider(np, of_clk_src_onecell_get, &clkp->clk_data))
+		panic("could not register clk provider\n");
+}
+CLK_OF_DECLARE(audio_clk, "zte,zx296718-audiocrm", audio_clocks_init);
+#endif
diff --git a/include/dt-bindings/clock/zx296718-clock.h b/include/dt-bindings/clock/zx296718-clock.h
new file mode 100644
index 0000000..97d45e2
--- /dev/null
+++ b/include/dt-bindings/clock/zx296718-clock.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 - 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __DT_BINDINGS_CLOCK_ZX296718_H
+#define __DT_BINDINGS_CLOCK_ZX296718_H
+
+/* PLL */
+#define ZX296718_OSC		0
+#define ZX296718_PLL_CPU	1
+#define ZX296718_PLL_MAC	2
+#define ZX296718_PLL_MM0	3
+#define ZX296718_PLL_MM1	4
+#define ZX296718_PLL_VGA	5
+#define ZX296718_PLL_DDR	6
+#define ZX296718_PLL_AUDIO	7
+#define ZX296718_PLL_HSIC	8
+#define CPU_DBG_GATE		9
+#define A72_GATE		10
+#define CPU_PERI_GATE		11
+#define A53_GATE		12
+#define DDR1_GATE		13
+#define DDR0_GATE		14
+#define SD1_WCLK		15
+#define SD1_AHB			16
+#define SD0_WCLK		17
+#define SD0_AHB			18
+#define EMMC_WCLK		19
+#define EMMC_NAND_AXI		20
+#define NAND_WCLK		21
+#define EMMC_NAND_AHB		22
+#define LSP1_148M5		23
+#define LSP1_99M		24
+#define LSP1_24M		25
+#define LSP0_74M25		26
+#define LSP0_32K		27
+#define LSP0_148M5		28
+#define LSP0_99M		29
+#define LSP0_24M		30
+#define DEMUX_AXI		31
+#define DEMUX_APB		32
+#define DEMUX_148M5		33
+#define DEMUX_108M		34
+#define AUDIO_APB		35
+#define AUDIO_99M		36
+#define AUDIO_24M		37
+#define AUDIO_16M384		38
+#define AUDIO_32K		39
+#define WDT_WCLK		40
+#define TIMER_WCLK		41
+#define VDE_ACLK		42
+#define VCE_ACLK		43
+#define HDE_ACLK		44
+#define GPU_ACLK		45
+#define SAPPU_ACLK		46
+#define SAPPU_WCLK		47
+#define VOU_ACLK		48
+#define VOU_MAIN_WCLK		49
+#define VOU_AUX_WCLK		50
+#define VOU_PPU_WCLK		51
+#define MIPI_CFG_CLK		52
+#define VGA_I2C_WCLK		53
+#define MIPI_REF_CLK		54
+#define HDMI_OSC_CEC		55
+#define HDMI_OSC_CLK		56
+#define HDMI_XCLK		57
+#define VIU_M0_ACLK		58
+#define VIU_M1_ACLK		59
+#define VIU_WCLK		60
+#define VIU_JPEG_WCLK		61
+#define VIU_CFG_CLK		62
+#define TS_SYS_WCLK		63
+#define TS_SYS_108M		64
+#define USB20_HCLK		65
+#define USB20_PHY_CLK		66
+#define USB21_HCLK		67
+#define USB21_PHY_CLK		68
+#define GMAC_RMIICLK		69
+#define GMAC_PCLK		70
+#define GMAC_ACLK		71
+#define GMAC_RFCLK		72
+#define TEMPSENSOR_GATE		73
+
+#define TOP_NR_CLKS		74
+
+
+#define LSP0_TIMER3_PCLK	1
+#define LSP0_TIMER3_WCLK	2
+#define LSP0_TIMER4_PCLK	3
+#define LSP0_TIMER4_WCLK	4
+#define LSP0_TIMER5_PCLK	5
+#define LSP0_TIMER5_WCLK	6
+#define LSP0_UART3_PCLK		7
+#define LSP0_UART3_WCLK		8
+#define LSP0_UART1_PCLK		9
+#define LSP0_UART1_WCLK		10
+#define LSP0_UART2_PCLK		11
+#define LSP0_UART2_WCLK		12
+#define LSP0_SPIFC0_PCLK	13
+#define LSP0_SPIFC0_WCLK	14
+#define LSP0_I2C4_PCLK		15
+#define LSP0_I2C4_WCLK		16
+#define LSP0_I2C5_PCLK		17
+#define LSP0_I2C5_WCLK		18
+#define LSP0_SSP0_PCLK		19
+#define LSP0_SSP0_WCLK		20
+#define LSP0_SSP1_PCLK		21
+#define LSP0_SSP1_WCLK		22
+#define LSP0_USIM_PCLK		23
+#define LSP0_USIM_WCLK		24
+#define LSP0_GPIO_PCLK		25
+#define LSP0_GPIO_WCLK		26
+#define LSP0_I2C3_PCLK		27
+#define LSP0_I2C3_WCLK		28
+
+#define LSP0_NR_CLKS		29
+
+
+#define LSP1_UART4_PCLK		1
+#define LSP1_UART4_WCLK		2
+#define LSP1_UART5_PCLK		3
+#define LSP1_UART5_WCLK		4
+#define LSP1_PWM_PCLK		5
+#define LSP1_PWM_WCLK		6
+#define LSP1_I2C2_PCLK		7
+#define LSP1_I2C2_WCLK		8
+#define LSP1_SSP2_PCLK		9
+#define LSP1_SSP2_WCLK		10
+#define LSP1_SSP3_PCLK		11
+#define LSP1_SSP3_WCLK		12
+#define LSP1_SSP4_PCLK		13
+#define LSP1_SSP4_WCLK		14
+#define LSP1_USIM1_PCLK		15
+#define LSP1_USIM1_WCLK		16
+
+#define LSP1_NR_CLKS		17
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] clk: zx: Add clk helper and zx296718 clk method
  2016-07-18  9:41 ` [PATCH 2/3] clk: zx: Add clk helper and zx296718 clk method Jun Nie
@ 2016-07-19  0:09   ` Michael Turquette
  0 siblings, 0 replies; 8+ messages in thread
From: Michael Turquette @ 2016-07-19  0:09 UTC (permalink / raw)
  To: Jun Nie, sboyd, linux-clk; +Cc: Jun Nie

Hi Jun Nie,

Quoting Jun Nie (2016-07-18 02:41:16)
> +/* add a clock instance to the clock lookup table used for dt based look=
up */
> +void zx_clk_add_lookup(struct zx_clk_provider *clkp, struct clk *clk,
> +                      unsigned int id)
> +{
> +       if (clkp->clk_data.clks && id)
> +               clkp->clk_data.clks[id] =3D clk;
> +}

Can you use of_clk_hw_provider and statically initialize your clock
data? For one example of this, check out drivers/clk/meson/gxbb.c

Then you won't need this function.

> +static void __init _zx296718_clk_register_pll(struct zx_clk_provider *cl=
kp,
> +                                            struct zx_pll_clock *pll_clk,
> +                                            unsigned int nr_plls,
> +                                            void __iomem *base)
> +{
> +       struct clk_zx_pll *pll;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +       unsigned int len;
> +
> +       if (pll_clk->rate_table) {
> +               pr_err("%s: fail to register clk %s as no config table\n",
> +                       __func__, pll_clk->name);
> +               return;
> +       }
> +
> +       pll =3D kzalloc(sizeof(*pll), GFP_KERNEL);
> +       if (!pll) {
> +               pr_err("%s: could not allocate pll clk %s\n",
> +                       __func__, pll_clk->name);
> +               return;
> +       }
> +
> +       init.name =3D pll_clk->name;
> +       init.flags =3D pll_clk->flags;
> +       init.parent_names =3D &pll_clk->parent_name;
> +       init.num_parents =3D pll_clk->parent_name ? 1 : 0;
> +       init.ops =3D &zx_pll_ops;
> +
> +       for (len =3D 0; pll_clk->rate_table[len].rate !=3D 0; )
> +               len++;
> +
> +       pll->count =3D len;
> +       pll->lookup_table =3D pll_clk->rate_table;
> +       pll->hw.init =3D &init;
> +       pll->reg_base =3D base + pll_clk->reg_offset;
> +       pll->pd_bit =3D pll_clk->pd_bit;
> +       pll->lock_bit =3D LOCK_FLAG;
> +
> +       clk =3D clk_register(NULL, &pll->hw);
> +       if (IS_ERR(clk)) {
> +               pr_err("%s: failed to register pll clock %s : %ld\n",
> +                       __func__, pll_clk->name, PTR_ERR(clk));
> +               kfree(pll);
> +               return;
> +       }
> +       zx_clk_add_lookup(clkp, clk, pll_clk->id);
> +}

It looks like you can get rid of all of these registration functions and
just pass your static init data into devm_clk_hw_register.

> +/*
> + * struct zx_fixed_factor_clock: information about fixed-factor clock
> + * @id: platform specific id of the clock.
> + * @name: name of this fixed-factor clock.
> + * @parent_name: parent clock name.
> + * @mult: fixed multiplication factor.
> + * @div: fixed division factor.
> + * @flags: optional fixed-factor clock flags.
> + */
> +struct zx_fixed_factor_clock {
> +       unsigned int            id;
> +       char                    *name;
> +       const char              *parent_name;
> +       unsigned long           mult;
> +       unsigned long           div;
> +       unsigned long           flags;
> +};

This sort of data type just reproduces what struct clk_fixed_factor can
already do. If you statically init the whole thing then you can store
the parent name as well. Something like:

	static struct clk_fixed_factor gxbb_fclk_div2 =3D {
		.mult =3D 1,
		.div =3D 2,
		.hw.init =3D &(struct clk_init_data){
			.name =3D "fclk_div2",
			.ops =3D &clk_fixed_factor_ops,
			.parent_names =3D (const char *[]){ "fixed_pll" },
			.num_parents =3D 1,
		},
	};

Regards,
Mike

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework
  2016-07-18  9:41 ` [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework Jun Nie
@ 2016-07-19  0:15   ` Michael Turquette
  2016-07-21  8:05     ` Jun Nie
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Turquette @ 2016-07-19  0:15 UTC (permalink / raw)
  To: Jun Nie, sboyd, linux-clk; +Cc: Jun Nie

Hi Jun Nie,

Quoting Jun Nie (2016-07-18 02:41:17)
> +Required properties:
> +- compatible : shall be one of the following:
> +       "zte,zx296718-topcrm":
> +               zx296718 top clock selection, divider and gating
> +
> +       "zte,zx296718-lsp0crm" and
> +       "zte,zx296718-lsp1crm":
> +               zx296718 device level clock selection and gating
> +
> +- reg: Address and length of the register set

clock-cells?

> +#include <linux/clk.h>

Is clk.h needed? I don't see any clock consumer api's used in this
driver.

> +struct zx_fixed_factor_clock top_ffactor_clk[] =3D {
> +       FFACTOR(0, "clk4m",             "osc24m", 1, 6,  0),
> +       FFACTOR(0, "clk2m",             "osc24m", 1, 12, 0),
> +       /* pll cpu */
> +       FFACTOR(0, "clk1600m",          "pll_cpu", 1, 1, CLK_SET_RATE_PAR=
ENT),
> +       FFACTOR(0, "clk800m",           "pll_cpu", 1, 2, CLK_SET_RATE_PAR=
ENT),

You have a lot of static data here, which is good. It can be expanded to
fill out struct clk_init_data (as showed in my reply to patch #2) and
then you can get rid of all of the registration functions.

> diff --git a/include/dt-bindings/clock/zx296718-clock.h b/include/dt-bind=
ings/clock/zx296718-clock.h
> new file mode 100644
> index 0000000..97d45e2
> --- /dev/null
> +++ b/include/dt-bindings/clock/zx296718-clock.h
> @@ -0,0 +1,140 @@
> +/*
> + * Copyright (C) 2015 - 2016 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef __DT_BINDINGS_CLOCK_ZX296718_H
> +#define __DT_BINDINGS_CLOCK_ZX296718_H
> +
> +/* PLL */
> +#define ZX296718_OSC           0
> +#define ZX296718_PLL_CPU       1
> +#define ZX296718_PLL_MAC       2
> +#define ZX296718_PLL_MM0       3
> +#define ZX296718_PLL_MM1       4
> +#define ZX296718_PLL_VGA       5
> +#define ZX296718_PLL_DDR       6
> +#define ZX296718_PLL_AUDIO     7
> +#define ZX296718_PLL_HSIC      8

For some clock controllers I suggest to split this list of numbers into
a private header that is only used by the Linux driver, and another
shared DT header that exposes only the clocks that will be consumed by
downstream drivers (usually just leaf gate clocks).

This also means that you can hide the ugly NR_CLKS stuff in the C-only
implementation and not add that Linux-specific data into the generic
binding description. It's up to you though.

Regards,
Mike

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework
  2016-07-19  0:15   ` Michael Turquette
@ 2016-07-21  8:05     ` Jun Nie
  2016-07-21 23:53       ` Michael Turquette
  0 siblings, 1 reply; 8+ messages in thread
From: Jun Nie @ 2016-07-21  8:05 UTC (permalink / raw)
  To: Michael Turquette, sboyd, linux-clk

On 2016年07月19日 08:15, Michael Turquette wrote:
> Hi Jun Nie,
>
> Quoting Jun Nie (2016-07-18 02:41:17)
>> +Required properties:
>> +- compatible : shall be one of the following:
>> +       "zte,zx296718-topcrm":
>> +               zx296718 top clock selection, divider and gating
>> +
>> +       "zte,zx296718-lsp0crm" and
>> +       "zte,zx296718-lsp1crm":
>> +               zx296718 device level clock selection and gating
>> +
>> +- reg: Address and length of the register set
>
> clock-cells?

Right, there are several clock controllers with sparse register regions. 
So separate initialization is needed.

>
>> +#include <linux/clk.h>
>
> Is clk.h needed? I don't see any clock consumer api's used in this
> driver.

I can remove that.

>
>> +struct zx_fixed_factor_clock top_ffactor_clk[] = {
>> +       FFACTOR(0, "clk4m",             "osc24m", 1, 6,  0),
>> +       FFACTOR(0, "clk2m",             "osc24m", 1, 12, 0),
>> +       /* pll cpu */
>> +       FFACTOR(0, "clk1600m",          "pll_cpu", 1, 1, CLK_SET_RATE_PARENT),
>> +       FFACTOR(0, "clk800m",           "pll_cpu", 1, 2, CLK_SET_RATE_PARENT),
>
> You have a lot of static data here, which is good. It can be expanded to
> fill out struct clk_init_data (as showed in my reply to patch #2) and
> then you can get rid of all of the registration functions.

Yes, your reply to patch #2 does save registration functions. I will try 
to follow that way. Thank you!

>
>> diff --git a/include/dt-bindings/clock/zx296718-clock.h b/include/dt-bindings/clock/zx296718-clock.h
>> new file mode 100644
>> index 0000000..97d45e2
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/zx296718-clock.h
>> @@ -0,0 +1,140 @@
>> +/*
>> + * Copyright (C) 2015 - 2016 ZTE Corporation.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +#ifndef __DT_BINDINGS_CLOCK_ZX296718_H
>> +#define __DT_BINDINGS_CLOCK_ZX296718_H
>> +
>> +/* PLL */
>> +#define ZX296718_OSC           0
>> +#define ZX296718_PLL_CPU       1
>> +#define ZX296718_PLL_MAC       2
>> +#define ZX296718_PLL_MM0       3
>> +#define ZX296718_PLL_MM1       4
>> +#define ZX296718_PLL_VGA       5
>> +#define ZX296718_PLL_DDR       6
>> +#define ZX296718_PLL_AUDIO     7
>> +#define ZX296718_PLL_HSIC      8
>
> For some clock controllers I suggest to split this list of numbers into
> a private header that is only used by the Linux driver, and another
> shared DT header that exposes only the clocks that will be consumed by
> downstream drivers (usually just leaf gate clocks).
>
> This also means that you can hide the ugly NR_CLKS stuff in the C-only
> implementation and not add that Linux-specific data into the generic
> binding description. It's up to you though.

NR_CLKS provides redundant info to drivers and generic binding 
description. Maybe that's why you think it is ugly. But move clocks from 
private header to DT binding header later will result redundant change 
history and effort. If that's all situation, I prefer to expose all 
information in DT binding header.

>
> Regards,
> Mike
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework
  2016-07-21  8:05     ` Jun Nie
@ 2016-07-21 23:53       ` Michael Turquette
  2016-07-27  9:25         ` Jun Nie
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Turquette @ 2016-07-21 23:53 UTC (permalink / raw)
  To: Jun Nie, sboyd, linux-clk

Quoting Jun Nie (2016-07-21 01:05:04)
> On 2016=E5=B9=B407=E6=9C=8819=E6=97=A5 08:15, Michael Turquette wrote:
> > Hi Jun Nie,
> >
> > Quoting Jun Nie (2016-07-18 02:41:17)
> >> +Required properties:
> >> +- compatible : shall be one of the following:
> >> +       "zte,zx296718-topcrm":
> >> +               zx296718 top clock selection, divider and gating
> >> +
> >> +       "zte,zx296718-lsp0crm" and
> >> +       "zte,zx296718-lsp1crm":
> >> +               zx296718 device level clock selection and gating
> >> +
> >> +- reg: Address and length of the register set
> >
> > clock-cells?
> =

> Right, there are several clock controllers with sparse register regions. =

> So separate initialization is needed.
> =

> >
> >> +#include <linux/clk.h>
> >
> > Is clk.h needed? I don't see any clock consumer api's used in this
> > driver.
> =

> I can remove that.
> =

> >
> >> +struct zx_fixed_factor_clock top_ffactor_clk[] =3D {
> >> +       FFACTOR(0, "clk4m",             "osc24m", 1, 6,  0),
> >> +       FFACTOR(0, "clk2m",             "osc24m", 1, 12, 0),
> >> +       /* pll cpu */
> >> +       FFACTOR(0, "clk1600m",          "pll_cpu", 1, 1, CLK_SET_RATE_=
PARENT),
> >> +       FFACTOR(0, "clk800m",           "pll_cpu", 1, 2, CLK_SET_RATE_=
PARENT),
> >
> > You have a lot of static data here, which is good. It can be expanded to
> > fill out struct clk_init_data (as showed in my reply to patch #2) and
> > then you can get rid of all of the registration functions.
> =

> Yes, your reply to patch #2 does save registration functions. I will try =

> to follow that way. Thank you!
> =

> >
> >> diff --git a/include/dt-bindings/clock/zx296718-clock.h b/include/dt-b=
indings/clock/zx296718-clock.h
> >> new file mode 100644
> >> index 0000000..97d45e2
> >> --- /dev/null
> >> +++ b/include/dt-bindings/clock/zx296718-clock.h
> >> @@ -0,0 +1,140 @@
> >> +/*
> >> + * Copyright (C) 2015 - 2016 ZTE Corporation.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modi=
fy
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + */
> >> +#ifndef __DT_BINDINGS_CLOCK_ZX296718_H
> >> +#define __DT_BINDINGS_CLOCK_ZX296718_H
> >> +
> >> +/* PLL */
> >> +#define ZX296718_OSC           0
> >> +#define ZX296718_PLL_CPU       1
> >> +#define ZX296718_PLL_MAC       2
> >> +#define ZX296718_PLL_MM0       3
> >> +#define ZX296718_PLL_MM1       4
> >> +#define ZX296718_PLL_VGA       5
> >> +#define ZX296718_PLL_DDR       6
> >> +#define ZX296718_PLL_AUDIO     7
> >> +#define ZX296718_PLL_HSIC      8
> >
> > For some clock controllers I suggest to split this list of numbers into
> > a private header that is only used by the Linux driver, and another
> > shared DT header that exposes only the clocks that will be consumed by
> > downstream drivers (usually just leaf gate clocks).
> >
> > This also means that you can hide the ugly NR_CLKS stuff in the C-only
> > implementation and not add that Linux-specific data into the generic
> > binding description. It's up to you though.
> =

> NR_CLKS provides redundant info to drivers and generic binding =

> description. Maybe that's why you think it is ugly. But move clocks from =

> private header to DT binding header later will result redundant change =

> history and effort. If that's all situation, I prefer to expose all =

> information in DT binding header.

Sure, that sounds fine to me.

Regards,
Mike

> =

> >
> > Regards,
> > Mike
> >
>=20

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework
  2016-07-21 23:53       ` Michael Turquette
@ 2016-07-27  9:25         ` Jun Nie
  0 siblings, 0 replies; 8+ messages in thread
From: Jun Nie @ 2016-07-27  9:25 UTC (permalink / raw)
  To: Michael Turquette; +Cc: Stephen Boyd, linux-clk

[-- Attachment #1: Type: text/plain, Size: 4861 bytes --]

2016-07-22 7:53 GMT+08:00 Michael Turquette <mturquette@baylibre.com>:

> Quoting Jun Nie (2016-07-21 01:05:04)
> > On 2016年07月19日 08:15, Michael Turquette wrote:
> > > Hi Jun Nie,
> > >
> > > Quoting Jun Nie (2016-07-18 02:41:17)
> > >> +Required properties:
> > >> +- compatible : shall be one of the following:
> > >> +       "zte,zx296718-topcrm":
> > >> +               zx296718 top clock selection, divider and gating
> > >> +
> > >> +       "zte,zx296718-lsp0crm" and
> > >> +       "zte,zx296718-lsp1crm":
> > >> +               zx296718 device level clock selection and gating
> > >> +
> > >> +- reg: Address and length of the register set
> > >
> > > clock-cells?
> >
> > Right, there are several clock controllers with sparse register regions.
> > So separate initialization is needed.
> >
> > >
> > >> +#include <linux/clk.h>
> > >
> > > Is clk.h needed? I don't see any clock consumer api's used in this
> > > driver.
> >
> > I can remove that.
> >
> > >
> > >> +struct zx_fixed_factor_clock top_ffactor_clk[] = {
> > >> +       FFACTOR(0, "clk4m",             "osc24m", 1, 6,  0),
> > >> +       FFACTOR(0, "clk2m",             "osc24m", 1, 12, 0),
> > >> +       /* pll cpu */
> > >> +       FFACTOR(0, "clk1600m",          "pll_cpu", 1, 1,
> CLK_SET_RATE_PARENT),
> > >> +       FFACTOR(0, "clk800m",           "pll_cpu", 1, 2,
> CLK_SET_RATE_PARENT),
> > >
> > > You have a lot of static data here, which is good. It can be expanded
> to
> > > fill out struct clk_init_data (as showed in my reply to patch #2) and
> > > then you can get rid of all of the registration functions.
>

Mike,

Are you OK if I wrap clk_gate as below? With this way, I can set id when
declaring the clk and fill the clk_provider hw pointer later with two line
of code automatically in probe function, instead of filling the provider
hw/id manually. Lots of line in driver is saved with defining clks in array
instead of separate declaration with names, long list of clk provider
contents is also saved, which also ease maintenance. Cons is that extra
memory is needed. Fixed factor, mux are in similar case.

struct zx_clk_gate {
         struct clk_gate gate;
         u16     id;
 };

static struct zx_clk_gate lsp0_gates = {
GATE(LSP0_SSP1_ID, "ssp1_wclk", "ssp1_div", LSP0_SSP1_CLK, 1,
CLK_SET_RATE_PARENT, 0),
GATE(LSP0_I2C4_ID, "i2c4_wclk", "i2c4_wclk_mux", LSP0_I2C4_CLK, 1,
CLK_SET_RATE_PARENT, 0),
...
};

struct zx_clk_gate *idx = &lsp0_gates[0];
for (i = 0; i < ARRARY_SIZE(lsp0_gates); i++) {
         if (idx->id)
                 hw_onecell_dat->hws[idx->id] = &idx->gate.hw;
}

 Jun

>
> > Yes, your reply to patch #2 does save registration functions. I will try
> > to follow that way. Thank you!
> >
> > >
> > >> diff --git a/include/dt-bindings/clock/zx296718-clock.h
> b/include/dt-bindings/clock/zx296718-clock.h
> > >> new file mode 100644
> > >> index 0000000..97d45e2
> > >> --- /dev/null
> > >> +++ b/include/dt-bindings/clock/zx296718-clock.h
> > >> @@ -0,0 +1,140 @@
> > >> +/*
> > >> + * Copyright (C) 2015 - 2016 ZTE Corporation.
> > >> + *
> > >> + * This program is free software; you can redistribute it and/or
> modify
> > >> + * it under the terms of the GNU General Public License version 2 as
> > >> + * published by the Free Software Foundation.
> > >> + */
> > >> +#ifndef __DT_BINDINGS_CLOCK_ZX296718_H
> > >> +#define __DT_BINDINGS_CLOCK_ZX296718_H
> > >> +
> > >> +/* PLL */
> > >> +#define ZX296718_OSC           0
> > >> +#define ZX296718_PLL_CPU       1
> > >> +#define ZX296718_PLL_MAC       2
> > >> +#define ZX296718_PLL_MM0       3
> > >> +#define ZX296718_PLL_MM1       4
> > >> +#define ZX296718_PLL_VGA       5
> > >> +#define ZX296718_PLL_DDR       6
> > >> +#define ZX296718_PLL_AUDIO     7
> > >> +#define ZX296718_PLL_HSIC      8
> > >
> > > For some clock controllers I suggest to split this list of numbers into
> > > a private header that is only used by the Linux driver, and another
> > > shared DT header that exposes only the clocks that will be consumed by
> > > downstream drivers (usually just leaf gate clocks).
> > >
> > > This also means that you can hide the ugly NR_CLKS stuff in the C-only
> > > implementation and not add that Linux-specific data into the generic
> > > binding description. It's up to you though.
> >
> > NR_CLKS provides redundant info to drivers and generic binding
> > description. Maybe that's why you think it is ugly. But move clocks from
> > private header to DT binding header later will result redundant change
> > history and effort. If that's all situation, I prefer to expose all
> > information in DT binding header.
>
> Sure, that sounds fine to me.
>
> Regards,
> Mike
>
> >
> > >
> > > Regards,
> > > Mike
> > >
> >
>

[-- Attachment #2: Type: text/html, Size: 6873 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-07-27  9:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-18  9:41 [PATCH 1/3] clk: zx: reform pll config info to ease code extension Jun Nie
2016-07-18  9:41 ` [PATCH 2/3] clk: zx: Add clk helper and zx296718 clk method Jun Nie
2016-07-19  0:09   ` Michael Turquette
2016-07-18  9:41 ` [PATCH 3/3] clk: zx: register ZX296718 clocks using common clock framework Jun Nie
2016-07-19  0:15   ` Michael Turquette
2016-07-21  8:05     ` Jun Nie
2016-07-21 23:53       ` Michael Turquette
2016-07-27  9:25         ` Jun Nie

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.