* [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.