* [PATCH 1/2] dt-bindings: zx296718-clk: add compatible for audio clock controller
@ 2016-12-08 9:25 Shawn Guo
[not found] ` <1481189157-8995-1-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2016-12-12 17:10 ` [PATCH 1/2] dt-bindings: zx296718-clk: add compatible for audio clock controller Rob Herring
0 siblings, 2 replies; 6+ messages in thread
From: Shawn Guo @ 2016-12-08 9:25 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd
Cc: Rob Herring, Mark Rutland, Baoyou Xie, Jun Nie, linux-clk,
devicetree, linux-arm-kernel, Shawn Guo, Shawn Guo
From: Shawn Guo <shawn.guo@linaro.org>
It adds the compatible string for zx296718 audio clock controller.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
Documentation/devicetree/bindings/clock/zx296718-clk.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/zx296718-clk.txt b/Documentation/devicetree/bindings/clock/zx296718-clk.txt
index 8c18b7b237bf..4ad703808407 100644
--- a/Documentation/devicetree/bindings/clock/zx296718-clk.txt
+++ b/Documentation/devicetree/bindings/clock/zx296718-clk.txt
@@ -13,6 +13,9 @@ Required properties:
"zte,zx296718-lsp1crm":
zx296718 device level clock selection and gating
+ "zte,zx296718-audiocrm":
+ zx296718 audio clock selection, divider and gating
+
- reg: Address and length of the register set
The clock consumer should specify the desired clock by having the clock
--
1.9.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/2] clk: zte: add audio clocks for zx296718
[not found] ` <1481189157-8995-1-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
@ 2016-12-08 9:25 ` Shawn Guo
2016-12-08 14:55 ` Jun Nie
[not found] ` <1481189157-8995-2-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
0 siblings, 2 replies; 6+ messages in thread
From: Shawn Guo @ 2016-12-08 9:25 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd
Cc: Rob Herring, Mark Rutland, Baoyou Xie, Jun Nie,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Shawn Guo,
Shawn Guo
From: Jun Nie <jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
The audio related clock support is missing from the existing zx296718
clock driver. Let's add it, so that the upstream ZX SPDIF driver can
work for HDMI audio support.
Signed-off-by: Jun Nie <jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/clk/zte/clk-zx296718.c | 150 +++++++++++++++++++++++++++++++++++++++++
drivers/clk/zte/clk.c | 149 ++++++++++++++++++++++++++++++++++++++++
drivers/clk/zte/clk.h | 28 ++++++++
3 files changed, 327 insertions(+)
diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c
index 707d62956e9b..eed8581b1b25 100644
--- a/drivers/clk/zte/clk-zx296718.c
+++ b/drivers/clk/zte/clk-zx296718.c
@@ -888,10 +888,160 @@ static int __init lsp1_clocks_init(struct device_node *np)
return 0;
}
+PNAME(audio_wclk_common_p) = {
+ "audio_99m",
+ "audio_24m",
+};
+
+PNAME(audio_timer_p) = {
+ "audio_24m",
+ "audio_32k",
+};
+
+static struct zx_clk_mux audio_mux_clk[] = {
+ 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 clk_zx_audio_divider audio_adiv_clk[] = {
+ AUDIO_DIV(0, "i2s0_wclk_div", "i2s0_wclk_mux", AUDIO_I2S0_DIV_CFG1, i2s_wclk_div_table),
+ AUDIO_DIV(0, "i2s1_wclk_div", "i2s1_wclk_mux", AUDIO_I2S1_DIV_CFG1, i2s_wclk_div_table),
+ AUDIO_DIV(0, "i2s2_wclk_div", "i2s2_wclk_mux", AUDIO_I2S2_DIV_CFG1, i2s_wclk_div_table),
+ AUDIO_DIV(0, "i2s3_wclk_div", "i2s3_wclk_mux", AUDIO_I2S3_DIV_CFG1, i2s_wclk_div_table),
+ AUDIO_DIV(0, "spdif0_wclk_div", "spdif0_wclk_mux", AUDIO_SPDIF0_DIV_CFG1, spdif_wclk_div_table),
+ AUDIO_DIV(0, "spdif1_wclk_div", "spdif1_wclk_mux", AUDIO_SPDIF1_DIV_CFG1, spdif_wclk_div_table),
+};
+
+struct zx_clk_div audio_div_clk[] = {
+ DIV_T(0, "tdm_wclk_div", "audio_16m384", AUDIO_TDM_CLK, 8, 4, 0, common_div_table),
+};
+
+struct zx_clk_gate audio_gate_clk[] = {
+ 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 struct clk_hw_onecell_data audio_hw_onecell_data = {
+ .num = AUDIO_NR_CLKS,
+ .hws = {
+ [AUDIO_NR_CLKS - 1] = NULL,
+ },
+};
+
+static int __init audio_clocks_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+ int i, ret;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: Unable to map audio clk base\n", __func__);
+ return -ENXIO;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(audio_mux_clk); i++) {
+ if (audio_mux_clk[i].id)
+ audio_hw_onecell_data.hws[audio_mux_clk[i].id] =
+ &audio_mux_clk[i].mux.hw;
+
+ audio_mux_clk[i].mux.reg += (u64)reg_base;
+ ret = clk_hw_register(NULL, &audio_mux_clk[i].mux.hw);
+ if (ret) {
+ pr_warn("audio clk %s init error!\n",
+ audio_mux_clk[i].mux.hw.init->name);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(audio_adiv_clk); i++) {
+ if (audio_adiv_clk[i].id)
+ audio_hw_onecell_data.hws[audio_adiv_clk[i].id] =
+ &audio_adiv_clk[i].hw;
+
+ audio_adiv_clk[i].reg_base += (u64)reg_base;
+ ret = clk_hw_register(NULL, &audio_adiv_clk[i].hw);
+ if (ret) {
+ pr_warn("audio clk %s init error!\n",
+ audio_adiv_clk[i].hw.init->name);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(audio_div_clk); i++) {
+ if (audio_div_clk[i].id)
+ audio_hw_onecell_data.hws[audio_div_clk[i].id] =
+ &audio_div_clk[i].div.hw;
+
+ audio_div_clk[i].div.reg += (u64)reg_base;
+ ret = clk_hw_register(NULL, &audio_div_clk[i].div.hw);
+ if (ret) {
+ pr_warn("audio clk %s init error!\n",
+ audio_div_clk[i].div.hw.init->name);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(audio_gate_clk); i++) {
+ if (audio_gate_clk[i].id)
+ audio_hw_onecell_data.hws[audio_gate_clk[i].id] =
+ &audio_gate_clk[i].gate.hw;
+
+ audio_gate_clk[i].gate.reg += (u64)reg_base;
+ ret = clk_hw_register(NULL, &audio_gate_clk[i].gate.hw);
+ if (ret) {
+ pr_warn("audio clk %s init error!\n",
+ audio_gate_clk[i].gate.hw.init->name);
+ }
+ }
+
+ if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &audio_hw_onecell_data))
+ panic("could not register clk provider\n");
+ pr_info("audio-clk init over, nr:%d\n", AUDIO_NR_CLKS);
+
+ return 0;
+}
+
static const struct of_device_id zx_clkc_match_table[] = {
{ .compatible = "zte,zx296718-topcrm", .data = &top_clocks_init },
{ .compatible = "zte,zx296718-lsp0crm", .data = &lsp0_clocks_init },
{ .compatible = "zte,zx296718-lsp1crm", .data = &lsp1_clocks_init },
+ { .compatible = "zte,zx296718-audiocrm", .data = &audio_clocks_init },
{ }
};
diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c
index c4c1251bc1e7..ea97024b37aa 100644
--- a/drivers/clk/zte/clk.c
+++ b/drivers/clk/zte/clk.c
@@ -9,6 +9,7 @@
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/gcd.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
@@ -310,3 +311,151 @@ struct clk *clk_register_zx_audio(const char *name,
return clk;
}
+
+#define CLK_AUDIO_DIV_FRAC BIT(0)
+#define CLK_AUDIO_DIV_INT BIT(1)
+#define CLK_AUDIO_DIV_UNCOMMON BIT(1)
+
+#define CLK_AUDIO_DIV_FRAC_NSHIFT 16
+#define CLK_AUDIO_DIV_INT_FRAC_RE BIT(16)
+#define CLK_AUDIO_DIV_INT_FRAC_MAX (0xffff)
+#define CLK_AUDIO_DIV_INT_FRAC_MIN (0x2)
+#define CLK_AUDIO_DIV_INT_INT_SHIFT 24
+#define CLK_AUDIO_DIV_INT_INT_WIDTH 4
+
+#define to_clk_zx_audio_div(_hw) container_of(_hw, struct clk_zx_audio_divider, hw)
+
+static unsigned long audio_calc_rate(struct clk_zx_audio_divider *audio_div,
+ u32 reg_frac, u32 reg_int,
+ unsigned long parent_rate)
+{
+ unsigned long rate, m, n;
+
+ if (audio_div->table) {
+ const struct zx_clk_audio_div_table *divt = audio_div->table;
+
+ for (; divt->rate; divt++) {
+ if ((divt->int_reg == reg_int) && (divt->frac_reg == reg_frac))
+ return divt->rate;
+ }
+ }
+ if (audio_div->table)
+ pr_warn("cannot found the config(int_reg:0x%x, frac_reg:0x%x) in table, we will caculate it\n",
+ reg_int, reg_frac);
+
+ m = reg_frac & 0xffff;
+ n = (reg_frac >> 16) & 0xffff;
+
+ m = (reg_int & 0xffff) * n + m;
+ rate = (parent_rate * n) / m;
+
+ return rate;
+}
+
+static void audio_calc_reg(struct clk_zx_audio_divider *audio_div,
+ struct zx_clk_audio_div_table *div_table,
+ unsigned long rate, unsigned long parent_rate)
+{
+ unsigned int reg_int, reg_frac;
+ unsigned long m, n, div;
+
+ if (audio_div->table) {
+ const struct zx_clk_audio_div_table *divt = audio_div->table;
+
+ for (; divt->rate; divt++) {
+ if (divt->rate == rate) {
+ div_table->rate = divt->rate;
+ div_table->int_reg = divt->int_reg;
+ div_table->frac_reg = divt->frac_reg;
+ return;
+ }
+ }
+ }
+ if (audio_div->table)
+ pr_warn("cannot found the rate(%ld) in table, we will caculate the config\n",
+ rate);
+
+ reg_int = parent_rate / rate;
+
+ if (reg_int > CLK_AUDIO_DIV_INT_FRAC_MAX)
+ reg_int = CLK_AUDIO_DIV_INT_FRAC_MAX;
+ else if (reg_int < CLK_AUDIO_DIV_INT_FRAC_MIN)
+ reg_int = 0;
+ m = parent_rate - rate * reg_int;
+ n = rate;
+
+ div = gcd(m, n);
+ m = m / div;
+ n = n / div;
+
+ if ((m >> 16) || (n >> 16)) {
+ if (m > n) {
+ n = n * 0xffff / m;
+ m = 0xffff;
+ } else {
+ m = m * 0xffff / n;
+ n = 0xffff;
+ }
+ }
+ reg_frac = m | (n << 16);
+
+ div_table->rate = (ulong)(parent_rate * n) / ((ulong)reg_int * n + m);
+ div_table->int_reg = reg_int;
+ div_table->frac_reg = reg_frac;
+}
+
+static unsigned long zx_audio_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
+ u32 reg_frac, reg_int;
+
+ reg_frac = readl_relaxed(zx_audio_div->reg_base);
+ reg_int = readl_relaxed(zx_audio_div->reg_base + 0x4);
+
+ return audio_calc_rate(zx_audio_div, reg_frac, reg_int, parent_rate);
+}
+
+static long zx_audio_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
+ struct zx_clk_audio_div_table divt;
+
+ audio_calc_reg(zx_audio_div, &divt, rate, *prate);
+
+ return audio_calc_rate(zx_audio_div, divt.frac_reg, divt.int_reg, *prate);
+}
+
+static int zx_audio_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
+ struct zx_clk_audio_div_table divt;
+ unsigned int val;
+
+ audio_calc_reg(zx_audio_div, &divt, rate, parent_rate);
+ if (divt.rate != rate)
+ pr_info("the real rate is:%ld", divt.rate);
+
+ writel_relaxed(divt.frac_reg, zx_audio_div->reg_base);
+
+ val = readl_relaxed(zx_audio_div->reg_base + 0x4);
+ val &= ~0xffff;
+ val |= divt.int_reg | CLK_AUDIO_DIV_INT_FRAC_RE;
+ writel_relaxed(val, zx_audio_div->reg_base + 0x4);
+
+ mdelay(1);
+
+ val = readl_relaxed(zx_audio_div->reg_base + 0x4);
+ val &= ~CLK_AUDIO_DIV_INT_FRAC_RE;
+ writel_relaxed(val, zx_audio_div->reg_base + 0x4);
+
+ return 0;
+}
+
+const struct clk_ops zx_audio_div_ops = {
+ .recalc_rate = zx_audio_div_recalc_rate,
+ .round_rate = zx_audio_div_round_rate,
+ .set_rate = zx_audio_div_set_rate,
+};
diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h
index 0df3474b2cf3..6e7ccb752c24 100644
--- a/drivers/clk/zte/clk.h
+++ b/drivers/clk/zte/clk.h
@@ -153,6 +153,32 @@ struct zx_clk_div {
.id = _id, \
}
+struct zx_clk_audio_div_table {
+ unsigned long rate;
+ unsigned int int_reg;
+ unsigned int frac_reg;
+};
+
+struct clk_zx_audio_divider {
+ struct clk_hw hw;
+ void __iomem *reg_base;
+ const struct zx_clk_audio_div_table *table;
+ unsigned int rate_count;
+ spinlock_t *lock;
+ u16 id;
+};
+
+#define AUDIO_DIV(_id, _name, _parent, _reg, _table) \
+{ \
+ .reg_base = (void __iomem *) _reg, \
+ .lock = &clk_lock, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &zx_audio_div_ops, \
+ 0), \
+ .id = _id, \
+}
+
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);
@@ -167,4 +193,6 @@ struct clk *clk_register_zx_audio(const char *name,
unsigned long flags, void __iomem *reg_base);
extern const struct clk_ops zx_pll_ops;
+extern const struct clk_ops zx_audio_div_ops;
+
#endif
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] clk: zte: add audio clocks for zx296718
2016-12-08 9:25 ` [PATCH 2/2] clk: zte: add audio clocks for zx296718 Shawn Guo
@ 2016-12-08 14:55 ` Jun Nie
[not found] ` <1481189157-8995-2-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
1 sibling, 0 replies; 6+ messages in thread
From: Jun Nie @ 2016-12-08 14:55 UTC (permalink / raw)
To: Shawn Guo
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
Baoyou Xie, linux-clk, devicetree, linux-arm-kernel, Shawn Guo
2016-12-08 17:25 GMT+08:00 Shawn Guo <shawnguo@kernel.org>:
> From: Jun Nie <jun.nie@linaro.org>
>
> The audio related clock support is missing from the existing zx296718
> clock driver. Let's add it, so that the upstream ZX SPDIF driver can
> work for HDMI audio support.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
> drivers/clk/zte/clk-zx296718.c | 150 +++++++++++++++++++++++++++++++++++++++++
> drivers/clk/zte/clk.c | 149 ++++++++++++++++++++++++++++++++++++++++
> drivers/clk/zte/clk.h | 28 ++++++++
> 3 files changed, 327 insertions(+)
>
> diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c
> index 707d62956e9b..eed8581b1b25 100644
> --- a/drivers/clk/zte/clk-zx296718.c
> +++ b/drivers/clk/zte/clk-zx296718.c
> @@ -888,10 +888,160 @@ static int __init lsp1_clocks_init(struct device_node *np)
> return 0;
> }
>
> +PNAME(audio_wclk_common_p) = {
> + "audio_99m",
> + "audio_24m",
> +};
> +
> +PNAME(audio_timer_p) = {
> + "audio_24m",
> + "audio_32k",
> +};
> +
> +static struct zx_clk_mux audio_mux_clk[] = {
> + 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},
> +};
You can remove these two tables and table pointer member as I already
removed table pointer assignment in macro AUDIO_DIV in this code. I am
sorry for not cleaning code properly.
> +
> +struct clk_zx_audio_divider audio_adiv_clk[] = {
> + AUDIO_DIV(0, "i2s0_wclk_div", "i2s0_wclk_mux", AUDIO_I2S0_DIV_CFG1, i2s_wclk_div_table),
> + AUDIO_DIV(0, "i2s1_wclk_div", "i2s1_wclk_mux", AUDIO_I2S1_DIV_CFG1, i2s_wclk_div_table),
> + AUDIO_DIV(0, "i2s2_wclk_div", "i2s2_wclk_mux", AUDIO_I2S2_DIV_CFG1, i2s_wclk_div_table),
> + AUDIO_DIV(0, "i2s3_wclk_div", "i2s3_wclk_mux", AUDIO_I2S3_DIV_CFG1, i2s_wclk_div_table),
> + AUDIO_DIV(0, "spdif0_wclk_div", "spdif0_wclk_mux", AUDIO_SPDIF0_DIV_CFG1, spdif_wclk_div_table),
> + AUDIO_DIV(0, "spdif1_wclk_div", "spdif1_wclk_mux", AUDIO_SPDIF1_DIV_CFG1, spdif_wclk_div_table),
> +};
> +
> +struct zx_clk_div audio_div_clk[] = {
> + DIV_T(0, "tdm_wclk_div", "audio_16m384", AUDIO_TDM_CLK, 8, 4, 0, common_div_table),
> +};
> +
> +struct zx_clk_gate audio_gate_clk[] = {
> + 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 struct clk_hw_onecell_data audio_hw_onecell_data = {
> + .num = AUDIO_NR_CLKS,
> + .hws = {
> + [AUDIO_NR_CLKS - 1] = NULL,
> + },
> +};
> +
> +static int __init audio_clocks_init(struct device_node *np)
> +{
> + void __iomem *reg_base;
> + int i, ret;
> +
> + reg_base = of_iomap(np, 0);
> + if (!reg_base) {
> + pr_err("%s: Unable to map audio clk base\n", __func__);
> + return -ENXIO;
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(audio_mux_clk); i++) {
> + if (audio_mux_clk[i].id)
> + audio_hw_onecell_data.hws[audio_mux_clk[i].id] =
> + &audio_mux_clk[i].mux.hw;
> +
> + audio_mux_clk[i].mux.reg += (u64)reg_base;
Fix build test failure on 32bit system.
audio_mux_clk[i].mux.reg += (uintptr_t)reg_base;
> + ret = clk_hw_register(NULL, &audio_mux_clk[i].mux.hw);
> + if (ret) {
> + pr_warn("audio clk %s init error!\n",
> + audio_mux_clk[i].mux.hw.init->name);
> + }
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(audio_adiv_clk); i++) {
> + if (audio_adiv_clk[i].id)
> + audio_hw_onecell_data.hws[audio_adiv_clk[i].id] =
> + &audio_adiv_clk[i].hw;
> +
> + audio_adiv_clk[i].reg_base += (u64)reg_base;
The same to this line and below cases.
> + ret = clk_hw_register(NULL, &audio_adiv_clk[i].hw);
> + if (ret) {
> + pr_warn("audio clk %s init error!\n",
> + audio_adiv_clk[i].hw.init->name);
> + }
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(audio_div_clk); i++) {
> + if (audio_div_clk[i].id)
> + audio_hw_onecell_data.hws[audio_div_clk[i].id] =
> + &audio_div_clk[i].div.hw;
> +
> + audio_div_clk[i].div.reg += (u64)reg_base;
> + ret = clk_hw_register(NULL, &audio_div_clk[i].div.hw);
> + if (ret) {
> + pr_warn("audio clk %s init error!\n",
> + audio_div_clk[i].div.hw.init->name);
> + }
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(audio_gate_clk); i++) {
> + if (audio_gate_clk[i].id)
> + audio_hw_onecell_data.hws[audio_gate_clk[i].id] =
> + &audio_gate_clk[i].gate.hw;
> +
> + audio_gate_clk[i].gate.reg += (u64)reg_base;
> + ret = clk_hw_register(NULL, &audio_gate_clk[i].gate.hw);
> + if (ret) {
> + pr_warn("audio clk %s init error!\n",
> + audio_gate_clk[i].gate.hw.init->name);
> + }
> + }
> +
> + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &audio_hw_onecell_data))
> + panic("could not register clk provider\n");
> + pr_info("audio-clk init over, nr:%d\n", AUDIO_NR_CLKS);
> +
> + return 0;
> +}
> +
> static const struct of_device_id zx_clkc_match_table[] = {
> { .compatible = "zte,zx296718-topcrm", .data = &top_clocks_init },
> { .compatible = "zte,zx296718-lsp0crm", .data = &lsp0_clocks_init },
> { .compatible = "zte,zx296718-lsp1crm", .data = &lsp1_clocks_init },
> + { .compatible = "zte,zx296718-audiocrm", .data = &audio_clocks_init },
> { }
> };
>
> diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c
> index c4c1251bc1e7..ea97024b37aa 100644
> --- a/drivers/clk/zte/clk.c
> +++ b/drivers/clk/zte/clk.c
> @@ -9,6 +9,7 @@
>
> #include <linux/clk-provider.h>
> #include <linux/err.h>
> +#include <linux/gcd.h>
> #include <linux/io.h>
> #include <linux/iopoll.h>
> #include <linux/slab.h>
> @@ -310,3 +311,151 @@ struct clk *clk_register_zx_audio(const char *name,
>
> return clk;
> }
> +
> +#define CLK_AUDIO_DIV_FRAC BIT(0)
> +#define CLK_AUDIO_DIV_INT BIT(1)
> +#define CLK_AUDIO_DIV_UNCOMMON BIT(1)
> +
> +#define CLK_AUDIO_DIV_FRAC_NSHIFT 16
> +#define CLK_AUDIO_DIV_INT_FRAC_RE BIT(16)
> +#define CLK_AUDIO_DIV_INT_FRAC_MAX (0xffff)
> +#define CLK_AUDIO_DIV_INT_FRAC_MIN (0x2)
> +#define CLK_AUDIO_DIV_INT_INT_SHIFT 24
> +#define CLK_AUDIO_DIV_INT_INT_WIDTH 4
> +
> +#define to_clk_zx_audio_div(_hw) container_of(_hw, struct clk_zx_audio_divider, hw)
> +
> +static unsigned long audio_calc_rate(struct clk_zx_audio_divider *audio_div,
> + u32 reg_frac, u32 reg_int,
> + unsigned long parent_rate)
> +{
> + unsigned long rate, m, n;
> +
> + if (audio_div->table) {
> + const struct zx_clk_audio_div_table *divt = audio_div->table;
> +
> + for (; divt->rate; divt++) {
> + if ((divt->int_reg == reg_int) && (divt->frac_reg == reg_frac))
> + return divt->rate;
> + }
> + }
> + if (audio_div->table)
> + pr_warn("cannot found the config(int_reg:0x%x, frac_reg:0x%x) in table, we will caculate it\n",
> + reg_int, reg_frac);
Logic of register value table can be removed now.
> +
> + m = reg_frac & 0xffff;
> + n = (reg_frac >> 16) & 0xffff;
> +
> + m = (reg_int & 0xffff) * n + m;
> + rate = (parent_rate * n) / m;
> +
> + return rate;
> +}
> +
> +static void audio_calc_reg(struct clk_zx_audio_divider *audio_div,
> + struct zx_clk_audio_div_table *div_table,
> + unsigned long rate, unsigned long parent_rate)
> +{
> + unsigned int reg_int, reg_frac;
> + unsigned long m, n, div;
> +
> + if (audio_div->table) {
> + const struct zx_clk_audio_div_table *divt = audio_div->table;
> +
> + for (; divt->rate; divt++) {
> + if (divt->rate == rate) {
> + div_table->rate = divt->rate;
> + div_table->int_reg = divt->int_reg;
> + div_table->frac_reg = divt->frac_reg;
> + return;
> + }
> + }
> + }
> + if (audio_div->table)
> + pr_warn("cannot found the rate(%ld) in table, we will caculate the config\n",
> + rate);
Table is not used here actually neither.
> +
> + reg_int = parent_rate / rate;
> +
> + if (reg_int > CLK_AUDIO_DIV_INT_FRAC_MAX)
> + reg_int = CLK_AUDIO_DIV_INT_FRAC_MAX;
> + else if (reg_int < CLK_AUDIO_DIV_INT_FRAC_MIN)
> + reg_int = 0;
> + m = parent_rate - rate * reg_int;
> + n = rate;
> +
> + div = gcd(m, n);
> + m = m / div;
> + n = n / div;
> +
> + if ((m >> 16) || (n >> 16)) {
> + if (m > n) {
> + n = n * 0xffff / m;
> + m = 0xffff;
> + } else {
> + m = m * 0xffff / n;
> + n = 0xffff;
> + }
> + }
> + reg_frac = m | (n << 16);
> +
> + div_table->rate = (ulong)(parent_rate * n) / ((ulong)reg_int * n + m);
> + div_table->int_reg = reg_int;
> + div_table->frac_reg = reg_frac;
> +}
> +
> +static unsigned long zx_audio_div_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
> + u32 reg_frac, reg_int;
> +
> + reg_frac = readl_relaxed(zx_audio_div->reg_base);
> + reg_int = readl_relaxed(zx_audio_div->reg_base + 0x4);
> +
> + return audio_calc_rate(zx_audio_div, reg_frac, reg_int, parent_rate);
> +}
> +
> +static long zx_audio_div_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
> + struct zx_clk_audio_div_table divt;
> +
> + audio_calc_reg(zx_audio_div, &divt, rate, *prate);
> +
> + return audio_calc_rate(zx_audio_div, divt.frac_reg, divt.int_reg, *prate);
> +}
> +
> +static int zx_audio_div_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
> + struct zx_clk_audio_div_table divt;
> + unsigned int val;
> +
> + audio_calc_reg(zx_audio_div, &divt, rate, parent_rate);
> + if (divt.rate != rate)
> + pr_info("the real rate is:%ld", divt.rate);
> +
> + writel_relaxed(divt.frac_reg, zx_audio_div->reg_base);
> +
> + val = readl_relaxed(zx_audio_div->reg_base + 0x4);
> + val &= ~0xffff;
> + val |= divt.int_reg | CLK_AUDIO_DIV_INT_FRAC_RE;
> + writel_relaxed(val, zx_audio_div->reg_base + 0x4);
> +
> + mdelay(1);
> +
> + val = readl_relaxed(zx_audio_div->reg_base + 0x4);
> + val &= ~CLK_AUDIO_DIV_INT_FRAC_RE;
> + writel_relaxed(val, zx_audio_div->reg_base + 0x4);
> +
> + return 0;
> +}
> +
> +const struct clk_ops zx_audio_div_ops = {
> + .recalc_rate = zx_audio_div_recalc_rate,
> + .round_rate = zx_audio_div_round_rate,
> + .set_rate = zx_audio_div_set_rate,
> +};
> diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h
> index 0df3474b2cf3..6e7ccb752c24 100644
> --- a/drivers/clk/zte/clk.h
> +++ b/drivers/clk/zte/clk.h
> @@ -153,6 +153,32 @@ struct zx_clk_div {
> .id = _id, \
> }
>
> +struct zx_clk_audio_div_table {
> + unsigned long rate;
> + unsigned int int_reg;
> + unsigned int frac_reg;
> +};
> +
> +struct clk_zx_audio_divider {
> + struct clk_hw hw;
> + void __iomem *reg_base;
> + const struct zx_clk_audio_div_table *table;
> + unsigned int rate_count;
> + spinlock_t *lock;
> + u16 id;
> +};
> +
> +#define AUDIO_DIV(_id, _name, _parent, _reg, _table) \
Remove unused table here.
> +{ \
> + .reg_base = (void __iomem *) _reg, \
> + .lock = &clk_lock, \
> + .hw.init = CLK_HW_INIT(_name, \
> + _parent, \
> + &zx_audio_div_ops, \
> + 0), \
> + .id = _id, \
> +}
> +
> 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);
> @@ -167,4 +193,6 @@ struct clk *clk_register_zx_audio(const char *name,
> unsigned long flags, void __iomem *reg_base);
>
> extern const struct clk_ops zx_pll_ops;
> +extern const struct clk_ops zx_audio_div_ops;
> +
> #endif
> --
> 1.9.1
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] clk: zte: add audio clocks for zx296718
[not found] ` <1481189157-8995-2-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
@ 2016-12-08 21:04 ` Stephen Boyd
2016-12-16 6:40 ` Shawn Guo
0 siblings, 1 reply; 6+ messages in thread
From: Stephen Boyd @ 2016-12-08 21:04 UTC (permalink / raw)
To: Shawn Guo
Cc: Michael Turquette, Rob Herring, Mark Rutland, Baoyou Xie, Jun Nie,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Shawn Guo
On 12/08, Shawn Guo wrote:
> +
> +static int __init audio_clocks_init(struct device_node *np)
> +{
> + void __iomem *reg_base;
> + int i, ret;
> +
> + reg_base = of_iomap(np, 0);
> + if (!reg_base) {
> + pr_err("%s: Unable to map audio clk base\n", __func__);
> + return -ENXIO;
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(audio_mux_clk); i++) {
> + if (audio_mux_clk[i].id)
> + audio_hw_onecell_data.hws[audio_mux_clk[i].id] =
> + &audio_mux_clk[i].mux.hw;
> +
> + audio_mux_clk[i].mux.reg += (u64)reg_base;
> + ret = clk_hw_register(NULL, &audio_mux_clk[i].mux.hw);
> + if (ret) {
> + pr_warn("audio clk %s init error!\n",
> + audio_mux_clk[i].mux.hw.init->name);
> + }
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(audio_adiv_clk); i++) {
> + if (audio_adiv_clk[i].id)
> + audio_hw_onecell_data.hws[audio_adiv_clk[i].id] =
> + &audio_adiv_clk[i].hw;
> +
> + audio_adiv_clk[i].reg_base += (u64)reg_base;
> + ret = clk_hw_register(NULL, &audio_adiv_clk[i].hw);
> + if (ret) {
> + pr_warn("audio clk %s init error!\n",
> + audio_adiv_clk[i].hw.init->name);
> + }
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(audio_div_clk); i++) {
> + if (audio_div_clk[i].id)
> + audio_hw_onecell_data.hws[audio_div_clk[i].id] =
> + &audio_div_clk[i].div.hw;
> +
> + audio_div_clk[i].div.reg += (u64)reg_base;
> + ret = clk_hw_register(NULL, &audio_div_clk[i].div.hw);
> + if (ret) {
> + pr_warn("audio clk %s init error!\n",
> + audio_div_clk[i].div.hw.init->name);
> + }
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(audio_gate_clk); i++) {
> + if (audio_gate_clk[i].id)
> + audio_hw_onecell_data.hws[audio_gate_clk[i].id] =
> + &audio_gate_clk[i].gate.hw;
> +
> + audio_gate_clk[i].gate.reg += (u64)reg_base;
> + ret = clk_hw_register(NULL, &audio_gate_clk[i].gate.hw);
> + if (ret) {
> + pr_warn("audio clk %s init error!\n",
> + audio_gate_clk[i].gate.hw.init->name);
> + }
> + }
> +
> + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &audio_hw_onecell_data))
> + panic("could not register clk provider\n");
Why don't we return error? We returned errors before if we
couldn't map the ioregion.
> + pr_info("audio-clk init over, nr:%d\n", AUDIO_NR_CLKS);
debug noise?
> +
> + return 0;
> +}
> +
> static const struct of_device_id zx_clkc_match_table[] = {
> { .compatible = "zte,zx296718-topcrm", .data = &top_clocks_init },
> { .compatible = "zte,zx296718-lsp0crm", .data = &lsp0_clocks_init },
> { .compatible = "zte,zx296718-lsp1crm", .data = &lsp1_clocks_init },
> + { .compatible = "zte,zx296718-audiocrm", .data = &audio_clocks_init },
> { }
> };
>
> diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c
> index c4c1251bc1e7..ea97024b37aa 100644
> --- a/drivers/clk/zte/clk.c
> +++ b/drivers/clk/zte/clk.c
> @@ -9,6 +9,7 @@
>
> #include <linux/clk-provider.h>
> #include <linux/err.h>
> +#include <linux/gcd.h>
> #include <linux/io.h>
> #include <linux/iopoll.h>
> #include <linux/slab.h>
> @@ -310,3 +311,151 @@ struct clk *clk_register_zx_audio(const char *name,
>
> return clk;
> }
> +
> +#define CLK_AUDIO_DIV_FRAC BIT(0)
> +#define CLK_AUDIO_DIV_INT BIT(1)
> +#define CLK_AUDIO_DIV_UNCOMMON BIT(1)
> +
> +#define CLK_AUDIO_DIV_FRAC_NSHIFT 16
> +#define CLK_AUDIO_DIV_INT_FRAC_RE BIT(16)
> +#define CLK_AUDIO_DIV_INT_FRAC_MAX (0xffff)
> +#define CLK_AUDIO_DIV_INT_FRAC_MIN (0x2)
> +#define CLK_AUDIO_DIV_INT_INT_SHIFT 24
> +#define CLK_AUDIO_DIV_INT_INT_WIDTH 4
> +
> +#define to_clk_zx_audio_div(_hw) container_of(_hw, struct clk_zx_audio_divider, hw)
> +
> +static unsigned long audio_calc_rate(struct clk_zx_audio_divider *audio_div,
> + u32 reg_frac, u32 reg_int,
> + unsigned long parent_rate)
> +{
> + unsigned long rate, m, n;
> +
> + if (audio_div->table) {
> + const struct zx_clk_audio_div_table *divt = audio_div->table;
> +
> + for (; divt->rate; divt++) {
> + if ((divt->int_reg == reg_int) && (divt->frac_reg == reg_frac))
Please remove extra parenthesis here.
> + return divt->rate;
> + }
> + }
> + if (audio_div->table)
> + pr_warn("cannot found the config(int_reg:0x%x, frac_reg:0x%x) in table, we will caculate it\n",
> + reg_int, reg_frac);
> +
> + m = reg_frac & 0xffff;
> + n = (reg_frac >> 16) & 0xffff;
> +
> + m = (reg_int & 0xffff) * n + m;
> + rate = (parent_rate * n) / m;
> +
> + return rate;
> +}
> +
> +static void audio_calc_reg(struct clk_zx_audio_divider *audio_div,
> + struct zx_clk_audio_div_table *div_table,
> + unsigned long rate, unsigned long parent_rate)
> +{
> + unsigned int reg_int, reg_frac;
> + unsigned long m, n, div;
> +
> + if (audio_div->table) {
> + const struct zx_clk_audio_div_table *divt = audio_div->table;
> +
> + for (; divt->rate; divt++) {
> + if (divt->rate == rate) {
> + div_table->rate = divt->rate;
> + div_table->int_reg = divt->int_reg;
> + div_table->frac_reg = divt->frac_reg;
> + return;
> + }
> + }
> + }
> + if (audio_div->table)
> + pr_warn("cannot found the rate(%ld) in table, we will caculate the config\n",
> + rate);
> +
> + reg_int = parent_rate / rate;
> +
> + if (reg_int > CLK_AUDIO_DIV_INT_FRAC_MAX)
> + reg_int = CLK_AUDIO_DIV_INT_FRAC_MAX;
> + else if (reg_int < CLK_AUDIO_DIV_INT_FRAC_MIN)
> + reg_int = 0;
> + m = parent_rate - rate * reg_int;
> + n = rate;
> +
> + div = gcd(m, n);
> + m = m / div;
> + n = n / div;
> +
> + if ((m >> 16) || (n >> 16)) {
> + if (m > n) {
> + n = n * 0xffff / m;
> + m = 0xffff;
> + } else {
> + m = m * 0xffff / n;
> + n = 0xffff;
> + }
> + }
> + reg_frac = m | (n << 16);
> +
> + div_table->rate = (ulong)(parent_rate * n) / ((ulong)reg_int * n + m);
Please don't use ulong, use unsigned long. Also consider using
local variables so the line isn't overly long.
> + div_table->int_reg = reg_int;
> + div_table->frac_reg = reg_frac;
> +}
[...]
> +
> +static int zx_audio_div_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
> + struct zx_clk_audio_div_table divt;
> + unsigned int val;
> +
> + audio_calc_reg(zx_audio_div, &divt, rate, parent_rate);
> + if (divt.rate != rate)
> + pr_info("the real rate is:%ld", divt.rate);
Debug noise?
> +
> + writel_relaxed(divt.frac_reg, zx_audio_div->reg_base);
> +
> + val = readl_relaxed(zx_audio_div->reg_base + 0x4);
> + val &= ~0xffff;
> + val |= divt.int_reg | CLK_AUDIO_DIV_INT_FRAC_RE;
> + writel_relaxed(val, zx_audio_div->reg_base + 0x4);
> +
> + mdelay(1);
> +
> + val = readl_relaxed(zx_audio_div->reg_base + 0x4);
> + val &= ~CLK_AUDIO_DIV_INT_FRAC_RE;
> + writel_relaxed(val, zx_audio_div->reg_base + 0x4);
> +
> + return 0;
> +}
> +
> +const struct clk_ops zx_audio_div_ops = {
> + .recalc_rate = zx_audio_div_recalc_rate,
> + .round_rate = zx_audio_div_round_rate,
> + .set_rate = zx_audio_div_set_rate,
> +};
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] dt-bindings: zx296718-clk: add compatible for audio clock controller
2016-12-08 9:25 [PATCH 1/2] dt-bindings: zx296718-clk: add compatible for audio clock controller Shawn Guo
[not found] ` <1481189157-8995-1-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
@ 2016-12-12 17:10 ` Rob Herring
1 sibling, 0 replies; 6+ messages in thread
From: Rob Herring @ 2016-12-12 17:10 UTC (permalink / raw)
To: Shawn Guo
Cc: Michael Turquette, Stephen Boyd, Mark Rutland, Baoyou Xie,
Jun Nie, linux-clk, devicetree, linux-arm-kernel, Shawn Guo
On Thu, Dec 08, 2016 at 05:25:56PM +0800, Shawn Guo wrote:
> From: Shawn Guo <shawn.guo@linaro.org>
>
> It adds the compatible string for zx296718 audio clock controller.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
> Documentation/devicetree/bindings/clock/zx296718-clk.txt | 3 +++
> 1 file changed, 3 insertions(+)
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] clk: zte: add audio clocks for zx296718
2016-12-08 21:04 ` Stephen Boyd
@ 2016-12-16 6:40 ` Shawn Guo
0 siblings, 0 replies; 6+ messages in thread
From: Shawn Guo @ 2016-12-16 6:40 UTC (permalink / raw)
To: Stephen Boyd
Cc: Michael Turquette, Rob Herring, Mark Rutland, Baoyou Xie, Jun Nie,
linux-clk, devicetree, linux-arm-kernel, Shawn Guo
On Thu, Dec 08, 2016 at 01:04:53PM -0800, Stephen Boyd wrote:
> > + if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &audio_hw_onecell_data))
> > + panic("could not register clk provider\n");
>
> Why don't we return error? We returned errors before if we
> couldn't map the ioregion.
Yes. Rather than panic, we should check return and give an error
message in case of failure.
>
> > + pr_info("audio-clk init over, nr:%d\n", AUDIO_NR_CLKS);
>
> debug noise?
Agreed. I will just clean it up.
<snip>
> > +static unsigned long audio_calc_rate(struct clk_zx_audio_divider *audio_div,
> > + u32 reg_frac, u32 reg_int,
> > + unsigned long parent_rate)
> > +{
> > + unsigned long rate, m, n;
> > +
> > + if (audio_div->table) {
> > + const struct zx_clk_audio_div_table *divt = audio_div->table;
> > +
> > + for (; divt->rate; divt++) {
> > + if ((divt->int_reg == reg_int) && (divt->frac_reg == reg_frac))
>
> Please remove extra parenthesis here.
The whole hunk of the code will be dropped, since the divider lookup
table is not actually used.
>
> > + return divt->rate;
> > + }
> > + }
> > + if (audio_div->table)
> > + pr_warn("cannot found the config(int_reg:0x%x, frac_reg:0x%x) in table, we will caculate it\n",
> > + reg_int, reg_frac);
<snip>
> > + div_table->rate = (ulong)(parent_rate * n) / ((ulong)reg_int * n + m);
>
> Please don't use ulong, use unsigned long. Also consider using
> local variables so the line isn't overly long.
It seems to me that none of the type casts is really necessary. So I
will just drop them.
>
> > + div_table->int_reg = reg_int;
> > + div_table->frac_reg = reg_frac;
> > +}
> [...]
> > +
> > +static int zx_audio_div_set_rate(struct clk_hw *hw, unsigned long rate,
> > + unsigned long parent_rate)
> > +{
> > + struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
> > + struct zx_clk_audio_div_table divt;
> > + unsigned int val;
> > +
> > + audio_calc_reg(zx_audio_div, &divt, rate, parent_rate);
> > + if (divt.rate != rate)
> > + pr_info("the real rate is:%ld", divt.rate);
>
> Debug noise?
I will change it to pr_debug.
Shawn
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2016-12-16 6:40 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-12-08 9:25 [PATCH 1/2] dt-bindings: zx296718-clk: add compatible for audio clock controller Shawn Guo
[not found] ` <1481189157-8995-1-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2016-12-08 9:25 ` [PATCH 2/2] clk: zte: add audio clocks for zx296718 Shawn Guo
2016-12-08 14:55 ` Jun Nie
[not found] ` <1481189157-8995-2-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2016-12-08 21:04 ` Stephen Boyd
2016-12-16 6:40 ` Shawn Guo
2016-12-12 17:10 ` [PATCH 1/2] dt-bindings: zx296718-clk: add compatible for audio clock controller Rob Herring
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).