[alsa-devel] [PATCH linux-next v2 6/6] ASoC: rsnd: add avb clocks
From: Jiada Wang jiada_wang@mentor.com
There are AVB Counter Clocks in ADG, each clock has 12bits integral and 8 bits fractional dividers which operates with S0D1ϕ clock.
This patch registers 8 AVB Counter Clocks when clock-cells of rcar_sound node is 2,
Signed-off-by: Jiada Wang jiada_wang@mentor.com --- sound/soc/sh/rcar/adg.c | 306 +++++++++++++++++++++++++++++++++++++-- sound/soc/sh/rcar/gen.c | 9 ++ sound/soc/sh/rcar/rsnd.h | 9 ++ 3 files changed, 315 insertions(+), 9 deletions(-)
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 6768a66588eb..2c03d420ae76 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -5,6 +5,8 @@ // Copyright (C) 2013 Kuninori Morimoto kuninori.morimoto.gx@renesas.com
#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <dt-bindings/clock/renesas-adg.h> #include "rsnd.h"
#define CLKA 0 @@ -21,13 +23,33 @@
#define BRRx_MASK(x) (0x3FF & x)
+#define ADG_CLK_NAME "adg" +#define AVB_CLK_NAME "avb" +#define AVB_CLK_NUM 8 +#define AVB_CLK_NAME_SIZE 10 +#define AVB_MAX_RATE 25000000 +#define AVB_DIV_EN_COM BIT(31) +#define AVB_DIV_MASK 0x3ffff +#define AVB_MAX_DIV 0x3ffc0 + static struct rsnd_mod_ops adg_ops = { .name = "adg", };
+struct clk_avb { + struct clk_hw hw; + unsigned int idx; + struct rsnd_mod *mod; + /* lock reg access */ + spinlock_t *lock; +}; + +#define to_clk_avb(_hw) container_of(_hw, struct clk_avb, hw) + struct rsnd_adg { struct clk *clk[CLKMAX]; struct clk *clkout[CLKOUTMAX]; + struct clk *clkavb[AVB_CLK_NUM]; struct clk_onecell_data onecell; struct rsnd_mod mod; u32 flags; @@ -37,6 +59,7 @@ struct rsnd_adg {
int rbga_rate_for_441khz; /* RBGA */ int rbgb_rate_for_48khz; /* RBGB */ + spinlock_t avb_lock; };
#define LRCLK_ASYNC (1 << 0) @@ -408,6 +431,239 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) } }
+static struct clk *rsnd_adg_clk_src_twocell_get(struct of_phandle_args *clkspec, + void *data) +{ + unsigned int clkidx = clkspec->args[1]; + struct rsnd_adg *adg = data; + const char *type; + struct clk *clk; + + switch (clkspec->args[0]) { + case ADG_FIX: + type = "fixed"; + if (clkidx >= CLKOUTMAX) { + pr_err("Invalid %s clock index %u\n", type, + clkidx); + return ERR_PTR(-EINVAL); + } + clk = adg->clkout[clkidx]; + break; + case ADG_AVB: + type = "avb"; + if (clkidx >= AVB_CLK_NUM) { + pr_err("Invalid %s clock index %u\n", type, + clkidx); + return ERR_PTR(-EINVAL); + } + clk = adg->clkavb[clkidx]; + break; + default: + pr_err("Invalid ADG clock type %u\n", clkspec->args[0]); + return ERR_PTR(-EINVAL); + } + + return clk; +} + +static void clk_avb_div_write(struct rsnd_mod *mod, u32 data, int idx) +{ + switch (idx) { + case 0: + rsnd_mod_write(mod, AVB_CLK_DIV0, data); + break; + case 1: + rsnd_mod_write(mod, AVB_CLK_DIV1, data); + break; + case 2: + rsnd_mod_write(mod, AVB_CLK_DIV2, data); + break; + case 3: + rsnd_mod_write(mod, AVB_CLK_DIV3, data); + break; + case 4: + rsnd_mod_write(mod, AVB_CLK_DIV4, data); + break; + case 5: + rsnd_mod_write(mod, AVB_CLK_DIV5, data); + break; + case 6: + rsnd_mod_write(mod, AVB_CLK_DIV6, data); + break; + case 7: + rsnd_mod_write(mod, AVB_CLK_DIV7, data); + break; + } +} + +static u32 clk_avb_div_read(struct rsnd_mod *mod, int idx) +{ + u32 val = 0; + + switch (idx) { + case 0: + val = rsnd_mod_read(mod, AVB_CLK_DIV0); + break; + case 1: + val = rsnd_mod_read(mod, AVB_CLK_DIV1); + break; + case 2: + val = rsnd_mod_read(mod, AVB_CLK_DIV2); + break; + case 3: + val = rsnd_mod_read(mod, AVB_CLK_DIV3); + break; + case 4: + val = rsnd_mod_read(mod, AVB_CLK_DIV4); + break; + case 5: + val = rsnd_mod_read(mod, AVB_CLK_DIV5); + break; + case 6: + val = rsnd_mod_read(mod, AVB_CLK_DIV6); + break; + case 7: + val = rsnd_mod_read(mod, AVB_CLK_DIV7); + break; + } + + return val; +} + +static int clk_avb_is_enabled(struct clk_hw *hw) +{ + struct clk_avb *avb = to_clk_avb(hw); + + return rsnd_mod_read(avb->mod, AVB_CLK_CONFIG) & BIT(avb->idx); +} + +static int clk_avb_enabledisable(struct clk_hw *hw, int enable) +{ + struct clk_avb *avb = to_clk_avb(hw); + u32 val; + + spin_lock(avb->lock); + + val = rsnd_mod_read(avb->mod, AVB_CLK_CONFIG); + if (enable) + val |= BIT(avb->idx); + else + val &= ~BIT(avb->idx); + rsnd_mod_write(avb->mod, AVB_CLK_CONFIG, val); + + spin_unlock(avb->lock); + + return 0; +} + +static int clk_avb_enable(struct clk_hw *hw) +{ + return clk_avb_enabledisable(hw, 1); +} + +static void clk_avb_disable(struct clk_hw *hw) +{ + clk_avb_enabledisable(hw, 0); +} + +static unsigned long clk_avb_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_avb *avb = to_clk_avb(hw); + u32 div; + + div = clk_avb_div_read(avb->mod, avb->idx) & AVB_DIV_MASK; + if (!div) + return parent_rate; + + return parent_rate * 32 / div; +} + +static unsigned int clk_avb_calc_div(unsigned long rate, + unsigned long parent_rate) +{ + unsigned int div; + + if (!rate) + rate = 1; + + if (rate > AVB_MAX_RATE) + rate = AVB_MAX_RATE; + + div = DIV_ROUND_CLOSEST(parent_rate * 32, rate); + + if (div > AVB_MAX_DIV) + div = AVB_MAX_DIV; + + return div; +} + +static long clk_avb_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned int div = clk_avb_calc_div(rate, *parent_rate); + + return (*parent_rate * 32) / div; +} + +static int clk_avb_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_avb *avb = to_clk_avb(hw); + unsigned int div = clk_avb_calc_div(rate, parent_rate); + u32 val; + + val = clk_avb_div_read(avb->mod, avb->idx) & ~AVB_DIV_MASK; + clk_avb_div_write(avb->mod, val | div, avb->idx); + + return 0; +} + +static const struct clk_ops clk_avb_ops = { + .enable = clk_avb_enable, + .disable = clk_avb_disable, + .is_enabled = clk_avb_is_enabled, + .recalc_rate = clk_avb_recalc_rate, + .round_rate = clk_avb_round_rate, + .set_rate = clk_avb_set_rate, +}; + +static struct clk *clk_register_avb(struct device *dev, struct rsnd_mod *mod, + unsigned int id, spinlock_t *lock) +{ + struct clk_init_data init; + struct clk_avb *avb; + struct clk *clk; + char name[AVB_CLK_NAME_SIZE]; + const char *parent_name = ADG_CLK_NAME; + + avb = devm_kzalloc(dev, sizeof(*avb), GFP_KERNEL); + if (!avb) + return ERR_PTR(-ENOMEM); + + snprintf(name, AVB_CLK_NAME_SIZE, "%s%u", AVB_CLK_NAME, id); + + avb->idx = id; + avb->lock = lock; + avb->mod = mod; + + /* Register the clock. */ + init.name = name; + init.ops = &clk_avb_ops; + init.flags = CLK_IS_BASIC; + init.parent_names = &parent_name; + init.num_parents = 1; + + avb->hw.init = &init; + + /* init DIV to a valid state */ + clk_avb_div_write(avb->mod, avb->idx, AVB_MAX_DIV); + + clk = devm_clk_register(dev, &avb->hw); + + return clk; +} + static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) { @@ -436,6 +692,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, unsigned long req_48kHz_rate, req_441kHz_rate; int i, req_size; const char *parent_clk_name = NULL; + struct rsnd_mod *mod = rsnd_mod_get(adg); static const char * const clkout_name[] = { [CLKOUT] = "audio_clkout", [CLKOUT1] = "audio_clkout1", @@ -540,21 +797,23 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, */
of_property_read_u32(np, "#clock-cells", &count); - /* - * for clkout - */ - if (!count) { + + switch (count) { + case 0: + /* + * for clkout + */ clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], parent_clk_name, 0, req_rate[0]); if (!IS_ERR(clk)) { adg->clkout[CLKOUT] = clk; of_clk_add_provider(np, of_clk_src_simple_get, clk); } - } - /* - * for clkout0/1/2/3 - */ - else { + break; + case 1: + /* + * for clkout0/1/2/3 + */ for (i = 0; i < CLKOUTMAX; i++) { clk = clk_register_fixed_rate(dev, clkout_name[i], parent_clk_name, 0, @@ -566,6 +825,33 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, adg->onecell.clk_num = CLKOUTMAX; of_clk_add_provider(np, of_clk_src_onecell_get, &adg->onecell); + break; + case 2: + /* + * for clkout0/1/2/3 and avb clocks + */ + for (i = 0; i < CLKOUTMAX; i++) { + clk = clk_register_fixed_rate(dev, clkout_name[i], + parent_clk_name, 0, + req_rate[0]); + if (!IS_ERR(clk)) + adg->clkout[i] = clk; + } + + for (i = 0; i < AVB_CLK_NUM; i++) { + clk = clk_register_avb(dev, mod, i, &adg->avb_lock); + if (!IS_ERR(clk)) + adg->clkavb[i] = clk; + } + + of_clk_add_provider(np, rsnd_adg_clk_src_twocell_get, adg); + + rsnd_mod_write(mod, AVB_CLK_CONFIG, AVB_DIV_EN_COM); + + break; + default: + dev_err(dev, "Invalid clock-cell %d\n", count); + break; }
rsnd_adg_get_clkout_end: @@ -612,6 +898,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv) if (!adg) return -ENOMEM;
+ spin_lock_init(&adg->avb_lock); + ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, NULL, 0, 0); if (ret) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index ca639404f2cd..1b000d03b76e 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -355,6 +355,15 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54), RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), + RSND_GEN_S_REG(AVB_CLK_DIV0, 0x11c), + RSND_GEN_S_REG(AVB_CLK_DIV1, 0x120), + RSND_GEN_S_REG(AVB_CLK_DIV2, 0x124), + RSND_GEN_S_REG(AVB_CLK_DIV3, 0x128), + RSND_GEN_S_REG(AVB_CLK_DIV4, 0x12c), + RSND_GEN_S_REG(AVB_CLK_DIV5, 0x130), + RSND_GEN_S_REG(AVB_CLK_DIV6, 0x134), + RSND_GEN_S_REG(AVB_CLK_DIV7, 0x138), + RSND_GEN_S_REG(AVB_CLK_CONFIG, 0x13c), }; static const struct rsnd_regmap_field_conf conf_ssi[] = { RSND_GEN_M_REG(SSICR, 0x00, 0x40), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 3c57129af6d1..d31b8a65985f 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -148,6 +148,15 @@ enum rsnd_reg { RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, RSND_REG_AUDIO_CLK_SEL2, + RSND_REG_AVB_CLK_DIV0, + RSND_REG_AVB_CLK_DIV1, + RSND_REG_AVB_CLK_DIV2, + RSND_REG_AVB_CLK_DIV3, + RSND_REG_AVB_CLK_DIV4, + RSND_REG_AVB_CLK_DIV5, + RSND_REG_AVB_CLK_DIV6, + RSND_REG_AVB_CLK_DIV7, + RSND_REG_AVB_CLK_CONFIG,
/* SSIU */ RSND_REG_SSI_MODE,
Hi Jiada,
On 12/03/2018 01:24 PM, jiada_wang@mentor.com wrote:
From: Jiada Wang jiada_wang@mentor.com
There are AVB Counter Clocks in ADG, each clock has 12bits integral and 8 bits fractional dividers which operates with S0D1ϕ clock.
This patch registers 8 AVB Counter Clocks when clock-cells of rcar_sound node is 2,
Signed-off-by: Jiada Wang jiada_wang@mentor.com
sound/soc/sh/rcar/adg.c | 306 +++++++++++++++++++++++++++++++++++++-- sound/soc/sh/rcar/gen.c | 9 ++ sound/soc/sh/rcar/rsnd.h | 9 ++ 3 files changed, 315 insertions(+), 9 deletions(-)
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 6768a66588eb..2c03d420ae76 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -5,6 +5,8 @@ // Copyright (C) 2013 Kuninori Morimoto kuninori.morimoto.gx@renesas.com
#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <dt-bindings/clock/renesas-adg.h>
Drop the inclusion of the header above, see my comment to patch 5/6.
#include "rsnd.h"
#define CLKA 0 @@ -21,13 +23,33 @@
#define BRRx_MASK(x) (0x3FF & x)
+#define ADG_CLK_NAME "adg" +#define AVB_CLK_NAME "avb"
Can you please remove two macro above and replace their usage by values in clk_register_avb() function?
Also I don't think that it is good to hardcode parent clock name here, likely you should get it in runtime, see __clk_get_name().
+#define AVB_CLK_NUM 8 +#define AVB_CLK_NAME_SIZE 10
The one macro above also can be removed in my opinion.
+#define AVB_MAX_RATE 25000000 +#define AVB_DIV_EN_COM BIT(31) +#define AVB_DIV_MASK 0x3ffff +#define AVB_MAX_DIV 0x3ffc0
static struct rsnd_mod_ops adg_ops = { .name = "adg", };
+struct clk_avb {
- struct clk_hw hw;
- unsigned int idx;
- struct rsnd_mod *mod;
- /* lock reg access */
- spinlock_t *lock;
+};
+#define to_clk_avb(_hw) container_of(_hw, struct clk_avb, hw)
struct rsnd_adg { struct clk *clk[CLKMAX]; struct clk *clkout[CLKOUTMAX];
- struct clk *clkavb[AVB_CLK_NUM]; struct clk_onecell_data onecell; struct rsnd_mod mod; u32 flags;
@@ -37,6 +59,7 @@ struct rsnd_adg {
int rbga_rate_for_441khz; /* RBGA */ int rbgb_rate_for_48khz; /* RBGB */
- spinlock_t avb_lock;
};
#define LRCLK_ASYNC (1 << 0) @@ -408,6 +431,239 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) } }
+static struct clk *rsnd_adg_clk_src_twocell_get(struct of_phandle_args *clkspec,
void *data)
+{
- unsigned int clkidx = clkspec->args[1];
- struct rsnd_adg *adg = data;
- const char *type;
- struct clk *clk;
- switch (clkspec->args[0]) {
- case ADG_FIX:
type = "fixed";
Apparently you need 'type' local variable just to print an error message.
Please remove the variable and update format strings accordingly.
if (clkidx >= CLKOUTMAX) {
pr_err("Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = adg->clkout[clkidx];
break;
- case ADG_AVB:
type = "avb";
if (clkidx >= AVB_CLK_NUM) {
pr_err("Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = adg->clkavb[clkidx];
break;
- default:
pr_err("Invalid ADG clock type %u\n", clkspec->args[0]);
return ERR_PTR(-EINVAL);
- }
- return clk;
+}
+static void clk_avb_div_write(struct rsnd_mod *mod, u32 data, int idx)
unsigned int idx to match a type of 'struct clk_avb' field.
+{
- switch (idx) {
- case 0:
rsnd_mod_write(mod, AVB_CLK_DIV0, data);
break;
- case 1:
rsnd_mod_write(mod, AVB_CLK_DIV1, data);
break;
- case 2:
rsnd_mod_write(mod, AVB_CLK_DIV2, data);
break;
- case 3:
rsnd_mod_write(mod, AVB_CLK_DIV3, data);
break;
- case 4:
rsnd_mod_write(mod, AVB_CLK_DIV4, data);
break;
- case 5:
rsnd_mod_write(mod, AVB_CLK_DIV5, data);
break;
- case 6:
rsnd_mod_write(mod, AVB_CLK_DIV6, data);
break;
- case 7:
rsnd_mod_write(mod, AVB_CLK_DIV7, data);
break;
- }
+}
+static u32 clk_avb_div_read(struct rsnd_mod *mod, int idx)
unsigned int idx to match a type of 'struct clk_avb' field.
+{
- u32 val = 0;
- switch (idx) {
- case 0:
val = rsnd_mod_read(mod, AVB_CLK_DIV0);
break;
- case 1:
val = rsnd_mod_read(mod, AVB_CLK_DIV1);
break;
- case 2:
val = rsnd_mod_read(mod, AVB_CLK_DIV2);
break;
- case 3:
val = rsnd_mod_read(mod, AVB_CLK_DIV3);
break;
- case 4:
val = rsnd_mod_read(mod, AVB_CLK_DIV4);
break;
- case 5:
val = rsnd_mod_read(mod, AVB_CLK_DIV5);
break;
- case 6:
val = rsnd_mod_read(mod, AVB_CLK_DIV6);
break;
- case 7:
val = rsnd_mod_read(mod, AVB_CLK_DIV7);
break;
- }
- return val;
+}
Apparently the macro nature of rsnd_mod_read() and rsnd_mod_write() does not allow to define a helper mapping function from index into RSND_REG_AVB_CLK_DIVx, okay...
+static int clk_avb_is_enabled(struct clk_hw *hw) +{
- struct clk_avb *avb = to_clk_avb(hw);
- return rsnd_mod_read(avb->mod, AVB_CLK_CONFIG) & BIT(avb->idx);
+}
+static int clk_avb_enabledisable(struct clk_hw *hw, int enable) +{
- struct clk_avb *avb = to_clk_avb(hw);
- u32 val;
- spin_lock(avb->lock);
- val = rsnd_mod_read(avb->mod, AVB_CLK_CONFIG);
- if (enable)
val |= BIT(avb->idx);
- else
val &= ~BIT(avb->idx);
- rsnd_mod_write(avb->mod, AVB_CLK_CONFIG, val);
- spin_unlock(avb->lock);
- return 0;
+}
+static int clk_avb_enable(struct clk_hw *hw) +{
- return clk_avb_enabledisable(hw, 1);
+}
+static void clk_avb_disable(struct clk_hw *hw) +{
- clk_avb_enabledisable(hw, 0);
+}
+static unsigned long clk_avb_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct clk_avb *avb = to_clk_avb(hw);
- u32 div;
- div = clk_avb_div_read(avb->mod, avb->idx) & AVB_DIV_MASK;
- if (!div)
return parent_rate;
- return parent_rate * 32 / div;
+}
+static unsigned int clk_avb_calc_div(unsigned long rate,
unsigned long parent_rate)
+{
- unsigned int div;
- if (!rate)
rate = 1;
- if (rate > AVB_MAX_RATE)
rate = AVB_MAX_RATE;
- div = DIV_ROUND_CLOSEST(parent_rate * 32, rate);
- if (div > AVB_MAX_DIV)
div = AVB_MAX_DIV;
- return div;
+}
+static long clk_avb_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
+{
- unsigned int div = clk_avb_calc_div(rate, *parent_rate);
- return (*parent_rate * 32) / div;
+}
+static int clk_avb_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
+{
- struct clk_avb *avb = to_clk_avb(hw);
- unsigned int div = clk_avb_calc_div(rate, parent_rate);
- u32 val;
- val = clk_avb_div_read(avb->mod, avb->idx) & ~AVB_DIV_MASK;
- clk_avb_div_write(avb->mod, val | div, avb->idx);
- return 0;
+}
+static const struct clk_ops clk_avb_ops = {
- .enable = clk_avb_enable,
- .disable = clk_avb_disable,
- .is_enabled = clk_avb_is_enabled,
- .recalc_rate = clk_avb_recalc_rate,
- .round_rate = clk_avb_round_rate,
- .set_rate = clk_avb_set_rate,
+};
+static struct clk *clk_register_avb(struct device *dev, struct rsnd_mod *mod,
unsigned int id, spinlock_t *lock)
+{
- struct clk_init_data init;
- struct clk_avb *avb;
- struct clk *clk;
- char name[AVB_CLK_NAME_SIZE];
- const char *parent_name = ADG_CLK_NAME;
- avb = devm_kzalloc(dev, sizeof(*avb), GFP_KERNEL);
- if (!avb)
return ERR_PTR(-ENOMEM);
- snprintf(name, AVB_CLK_NAME_SIZE, "%s%u", AVB_CLK_NAME, id);
- avb->idx = id;
- avb->lock = lock;
- avb->mod = mod;
- /* Register the clock. */
- init.name = name;
- init.ops = &clk_avb_ops;
- init.flags = CLK_IS_BASIC;
- init.parent_names = &parent_name;
- init.num_parents = 1;
- avb->hw.init = &init;
- /* init DIV to a valid state */
- clk_avb_div_write(avb->mod, avb->idx, AVB_MAX_DIV);
- clk = devm_clk_register(dev, &avb->hw);
- return clk;
+}
static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) { @@ -436,6 +692,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, unsigned long req_48kHz_rate, req_441kHz_rate; int i, req_size; const char *parent_clk_name = NULL;
- struct rsnd_mod *mod = rsnd_mod_get(adg); static const char * const clkout_name[] = { [CLKOUT] = "audio_clkout", [CLKOUT1] = "audio_clkout1",
@@ -540,21 +797,23 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, */
of_property_read_u32(np, "#clock-cells", &count);
- /*
* for clkout
*/
- if (!count) {
- switch (count) {
- case 0:
/*
* for clkout
clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], parent_clk_name, 0, req_rate[0]); if (!IS_ERR(clk)) { adg->clkout[CLKOUT] = clk; of_clk_add_provider(np, of_clk_src_simple_get, clk); }*/
- }
- /*
* for clkout0/1/2/3
*/
- else {
break;
- case 1:
/*
* for clkout0/1/2/3
for (i = 0; i < CLKOUTMAX; i++) { clk = clk_register_fixed_rate(dev, clkout_name[i], parent_clk_name, 0,*/
@@ -566,6 +825,33 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, adg->onecell.clk_num = CLKOUTMAX; of_clk_add_provider(np, of_clk_src_onecell_get, &adg->onecell);
break;
- case 2:
/*
* for clkout0/1/2/3 and avb clocks
*/
for (i = 0; i < CLKOUTMAX; i++) {
clk = clk_register_fixed_rate(dev, clkout_name[i],
parent_clk_name, 0,
req_rate[0]);
if (!IS_ERR(clk))
adg->clkout[i] = clk;
}
for (i = 0; i < AVB_CLK_NUM; i++) {
clk = clk_register_avb(dev, mod, i, &adg->avb_lock);
if (!IS_ERR(clk))
adg->clkavb[i] = clk;
}
of_clk_add_provider(np, rsnd_adg_clk_src_twocell_get, adg);
rsnd_mod_write(mod, AVB_CLK_CONFIG, AVB_DIV_EN_COM);
break;
- default:
dev_err(dev, "Invalid clock-cell %d\n", count);
}break;
rsnd_adg_get_clkout_end: @@ -612,6 +898,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv) if (!adg) return -ENOMEM;
- spin_lock_init(&adg->avb_lock);
- ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, NULL, 0, 0); if (ret)
-- Best wishes, Vladimir
Hi Vladimir
Thanks for your comments I will address your findings in next version
Thanks, Jiada
On 2018/12/03 21:53, Vladimir Zapolskiy wrote:
Hi Jiada,
On 12/03/2018 01:24 PM, jiada_wang@mentor.com wrote:
From: Jiada Wang jiada_wang@mentor.com
There are AVB Counter Clocks in ADG, each clock has 12bits integral and 8 bits fractional dividers which operates with S0D1ϕ clock.
This patch registers 8 AVB Counter Clocks when clock-cells of rcar_sound node is 2,
Signed-off-by: Jiada Wang jiada_wang@mentor.com
sound/soc/sh/rcar/adg.c | 306 +++++++++++++++++++++++++++++++++++++-- sound/soc/sh/rcar/gen.c | 9 ++ sound/soc/sh/rcar/rsnd.h | 9 ++ 3 files changed, 315 insertions(+), 9 deletions(-)
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 6768a66588eb..2c03d420ae76 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -5,6 +5,8 @@ // Copyright (C) 2013 Kuninori Morimoto kuninori.morimoto.gx@renesas.com
#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <dt-bindings/clock/renesas-adg.h>
Drop the inclusion of the header above, see my comment to patch 5/6.
#include "rsnd.h"
#define CLKA 0 @@ -21,13 +23,33 @@
#define BRRx_MASK(x) (0x3FF & x)
+#define ADG_CLK_NAME "adg" +#define AVB_CLK_NAME "avb"
Can you please remove two macro above and replace their usage by values in clk_register_avb() function?
Also I don't think that it is good to hardcode parent clock name here, likely you should get it in runtime, see __clk_get_name().
+#define AVB_CLK_NUM 8 +#define AVB_CLK_NAME_SIZE 10
The one macro above also can be removed in my opinion.
+#define AVB_MAX_RATE 25000000 +#define AVB_DIV_EN_COM BIT(31) +#define AVB_DIV_MASK 0x3ffff +#define AVB_MAX_DIV 0x3ffc0
- static struct rsnd_mod_ops adg_ops = { .name = "adg", };
+struct clk_avb {
- struct clk_hw hw;
- unsigned int idx;
- struct rsnd_mod *mod;
- /* lock reg access */
- spinlock_t *lock;
+};
+#define to_clk_avb(_hw) container_of(_hw, struct clk_avb, hw)
- struct rsnd_adg { struct clk *clk[CLKMAX]; struct clk *clkout[CLKOUTMAX];
- struct clk *clkavb[AVB_CLK_NUM]; struct clk_onecell_data onecell; struct rsnd_mod mod; u32 flags;
@@ -37,6 +59,7 @@ struct rsnd_adg {
int rbga_rate_for_441khz; /* RBGA */ int rbgb_rate_for_48khz; /* RBGB */
spinlock_t avb_lock; };
#define LRCLK_ASYNC (1 << 0)
@@ -408,6 +431,239 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) } }
+static struct clk *rsnd_adg_clk_src_twocell_get(struct of_phandle_args *clkspec,
void *data)
+{
- unsigned int clkidx = clkspec->args[1];
- struct rsnd_adg *adg = data;
- const char *type;
- struct clk *clk;
- switch (clkspec->args[0]) {
- case ADG_FIX:
type = "fixed";
Apparently you need 'type' local variable just to print an error message.
Please remove the variable and update format strings accordingly.
if (clkidx >= CLKOUTMAX) {
pr_err("Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = adg->clkout[clkidx];
break;
- case ADG_AVB:
type = "avb";
if (clkidx >= AVB_CLK_NUM) {
pr_err("Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = adg->clkavb[clkidx];
break;
- default:
pr_err("Invalid ADG clock type %u\n", clkspec->args[0]);
return ERR_PTR(-EINVAL);
- }
- return clk;
+}
+static void clk_avb_div_write(struct rsnd_mod *mod, u32 data, int idx)
unsigned int idx to match a type of 'struct clk_avb' field.
+{
- switch (idx) {
- case 0:
rsnd_mod_write(mod, AVB_CLK_DIV0, data);
break;
- case 1:
rsnd_mod_write(mod, AVB_CLK_DIV1, data);
break;
- case 2:
rsnd_mod_write(mod, AVB_CLK_DIV2, data);
break;
- case 3:
rsnd_mod_write(mod, AVB_CLK_DIV3, data);
break;
- case 4:
rsnd_mod_write(mod, AVB_CLK_DIV4, data);
break;
- case 5:
rsnd_mod_write(mod, AVB_CLK_DIV5, data);
break;
- case 6:
rsnd_mod_write(mod, AVB_CLK_DIV6, data);
break;
- case 7:
rsnd_mod_write(mod, AVB_CLK_DIV7, data);
break;
- }
+}
+static u32 clk_avb_div_read(struct rsnd_mod *mod, int idx)
unsigned int idx to match a type of 'struct clk_avb' field.
+{
- u32 val = 0;
- switch (idx) {
- case 0:
val = rsnd_mod_read(mod, AVB_CLK_DIV0);
break;
- case 1:
val = rsnd_mod_read(mod, AVB_CLK_DIV1);
break;
- case 2:
val = rsnd_mod_read(mod, AVB_CLK_DIV2);
break;
- case 3:
val = rsnd_mod_read(mod, AVB_CLK_DIV3);
break;
- case 4:
val = rsnd_mod_read(mod, AVB_CLK_DIV4);
break;
- case 5:
val = rsnd_mod_read(mod, AVB_CLK_DIV5);
break;
- case 6:
val = rsnd_mod_read(mod, AVB_CLK_DIV6);
break;
- case 7:
val = rsnd_mod_read(mod, AVB_CLK_DIV7);
break;
- }
- return val;
+}
Apparently the macro nature of rsnd_mod_read() and rsnd_mod_write() does not allow to define a helper mapping function from index into RSND_REG_AVB_CLK_DIVx, okay...
+static int clk_avb_is_enabled(struct clk_hw *hw) +{
- struct clk_avb *avb = to_clk_avb(hw);
- return rsnd_mod_read(avb->mod, AVB_CLK_CONFIG) & BIT(avb->idx);
+}
+static int clk_avb_enabledisable(struct clk_hw *hw, int enable) +{
- struct clk_avb *avb = to_clk_avb(hw);
- u32 val;
- spin_lock(avb->lock);
- val = rsnd_mod_read(avb->mod, AVB_CLK_CONFIG);
- if (enable)
val |= BIT(avb->idx);
- else
val &= ~BIT(avb->idx);
- rsnd_mod_write(avb->mod, AVB_CLK_CONFIG, val);
- spin_unlock(avb->lock);
- return 0;
+}
+static int clk_avb_enable(struct clk_hw *hw) +{
- return clk_avb_enabledisable(hw, 1);
+}
+static void clk_avb_disable(struct clk_hw *hw) +{
- clk_avb_enabledisable(hw, 0);
+}
+static unsigned long clk_avb_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct clk_avb *avb = to_clk_avb(hw);
- u32 div;
- div = clk_avb_div_read(avb->mod, avb->idx) & AVB_DIV_MASK;
- if (!div)
return parent_rate;
- return parent_rate * 32 / div;
+}
+static unsigned int clk_avb_calc_div(unsigned long rate,
unsigned long parent_rate)
+{
- unsigned int div;
- if (!rate)
rate = 1;
- if (rate > AVB_MAX_RATE)
rate = AVB_MAX_RATE;
- div = DIV_ROUND_CLOSEST(parent_rate * 32, rate);
- if (div > AVB_MAX_DIV)
div = AVB_MAX_DIV;
- return div;
+}
+static long clk_avb_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
+{
- unsigned int div = clk_avb_calc_div(rate, *parent_rate);
- return (*parent_rate * 32) / div;
+}
+static int clk_avb_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
+{
- struct clk_avb *avb = to_clk_avb(hw);
- unsigned int div = clk_avb_calc_div(rate, parent_rate);
- u32 val;
- val = clk_avb_div_read(avb->mod, avb->idx) & ~AVB_DIV_MASK;
- clk_avb_div_write(avb->mod, val | div, avb->idx);
- return 0;
+}
+static const struct clk_ops clk_avb_ops = {
- .enable = clk_avb_enable,
- .disable = clk_avb_disable,
- .is_enabled = clk_avb_is_enabled,
- .recalc_rate = clk_avb_recalc_rate,
- .round_rate = clk_avb_round_rate,
- .set_rate = clk_avb_set_rate,
+};
+static struct clk *clk_register_avb(struct device *dev, struct rsnd_mod *mod,
unsigned int id, spinlock_t *lock)
+{
- struct clk_init_data init;
- struct clk_avb *avb;
- struct clk *clk;
- char name[AVB_CLK_NAME_SIZE];
- const char *parent_name = ADG_CLK_NAME;
- avb = devm_kzalloc(dev, sizeof(*avb), GFP_KERNEL);
- if (!avb)
return ERR_PTR(-ENOMEM);
- snprintf(name, AVB_CLK_NAME_SIZE, "%s%u", AVB_CLK_NAME, id);
- avb->idx = id;
- avb->lock = lock;
- avb->mod = mod;
- /* Register the clock. */
- init.name = name;
- init.ops = &clk_avb_ops;
- init.flags = CLK_IS_BASIC;
- init.parent_names = &parent_name;
- init.num_parents = 1;
- avb->hw.init = &init;
- /* init DIV to a valid state */
- clk_avb_div_write(avb->mod, avb->idx, AVB_MAX_DIV);
- clk = devm_clk_register(dev, &avb->hw);
- return clk;
+}
- static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) {
@@ -436,6 +692,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, unsigned long req_48kHz_rate, req_441kHz_rate; int i, req_size; const char *parent_clk_name = NULL;
- struct rsnd_mod *mod = rsnd_mod_get(adg); static const char * const clkout_name[] = { [CLKOUT] = "audio_clkout", [CLKOUT1] = "audio_clkout1",
@@ -540,21 +797,23 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, */
of_property_read_u32(np, "#clock-cells", &count);
- /*
* for clkout
*/
- if (!count) {
- switch (count) {
- case 0:
/*
* for clkout
clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], parent_clk_name, 0, req_rate[0]); if (!IS_ERR(clk)) { adg->clkout[CLKOUT] = clk; of_clk_add_provider(np, of_clk_src_simple_get, clk); }*/
- }
- /*
* for clkout0/1/2/3
*/
- else {
break;
- case 1:
/*
* for clkout0/1/2/3
for (i = 0; i < CLKOUTMAX; i++) { clk = clk_register_fixed_rate(dev, clkout_name[i], parent_clk_name, 0,*/
@@ -566,6 +825,33 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, adg->onecell.clk_num = CLKOUTMAX; of_clk_add_provider(np, of_clk_src_onecell_get, &adg->onecell);
break;
case 2:
/*
* for clkout0/1/2/3 and avb clocks
*/
for (i = 0; i < CLKOUTMAX; i++) {
clk = clk_register_fixed_rate(dev, clkout_name[i],
parent_clk_name, 0,
req_rate[0]);
if (!IS_ERR(clk))
adg->clkout[i] = clk;
}
for (i = 0; i < AVB_CLK_NUM; i++) {
clk = clk_register_avb(dev, mod, i, &adg->avb_lock);
if (!IS_ERR(clk))
adg->clkavb[i] = clk;
}
of_clk_add_provider(np, rsnd_adg_clk_src_twocell_get, adg);
rsnd_mod_write(mod, AVB_CLK_CONFIG, AVB_DIV_EN_COM);
break;
default:
dev_err(dev, "Invalid clock-cell %d\n", count);
break;
}
rsnd_adg_get_clkout_end:
@@ -612,6 +898,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv) if (!adg) return -ENOMEM;
- spin_lock_init(&adg->avb_lock);
- ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, NULL, 0, 0); if (ret)
-- Best wishes, Vladimir
Hi Jiada
There are AVB Counter Clocks in ADG, each clock has 12bits integral and 8 bits fractional dividers which operates with S0D1ϕ clock.
This patch registers 8 AVB Counter Clocks when clock-cells of rcar_sound node is 2,
Signed-off-by: Jiada Wang jiada_wang@mentor.com
(snip)
+struct clk_avb {
- struct clk_hw hw;
- unsigned int idx;
- struct rsnd_mod *mod;
- /* lock reg access */
- spinlock_t *lock;
+};
+#define to_clk_avb(_hw) container_of(_hw, struct clk_avb, hw)
I like "hw_to_avb()"
+static struct clk *rsnd_adg_clk_src_twocell_get(struct of_phandle_args *clkspec,
void *data)
+{
- unsigned int clkidx = clkspec->args[1];
- struct rsnd_adg *adg = data;
- const char *type;
- struct clk *clk;
- switch (clkspec->args[0]) {
- case ADG_FIX:
type = "fixed";
if (clkidx >= CLKOUTMAX) {
pr_err("Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = adg->clkout[clkidx];
break;
- case ADG_AVB:
type = "avb";
if (clkidx >= AVB_CLK_NUM) {
pr_err("Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = adg->clkavb[clkidx];
break;
- default:
pr_err("Invalid ADG clock type %u\n", clkspec->args[0]);
return ERR_PTR(-EINVAL);
- }
- return clk;
+}
In this function 1) I don't think you need to use "char *type". 2) If you use "clkidx = clkspec->args[1]", having same name for "clkspec->args[0]" is readable. 3) please use dev_err() instad of pr_err() I think data can be priv, and you can use rsnd_priv_to_adg(), rsnd_priv_to_dev()
+static void clk_avb_div_write(struct rsnd_mod *mod, u32 data, int idx)
(snip)
+static u32 clk_avb_div_read(struct rsnd_mod *mod, int idx)
To reduce confusion, and be more redable code, I think these function can be
clk_avb_div_write(struct rsnd_adg *adg, u32 data); clk_avb_div_read(struct rsnd_adg *adg);
+static int clk_avb_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
+{
- struct clk_avb *avb = to_clk_avb(hw);
- unsigned int div = clk_avb_calc_div(rate, parent_rate);
- u32 val;
- val = clk_avb_div_read(avb->mod, avb->idx) & ~AVB_DIV_MASK;
- clk_avb_div_write(avb->mod, val | div, avb->idx);
- return 0;
+}
Why do we need to care about ~AVB_DIV_MASK area ? These are 0 Reserved, I think.
+static const struct clk_ops clk_avb_ops = {
- .enable = clk_avb_enable,
- .disable = clk_avb_disable,
- .is_enabled = clk_avb_is_enabled,
- .recalc_rate = clk_avb_recalc_rate,
- .round_rate = clk_avb_round_rate,
- .set_rate = clk_avb_set_rate,
+};
This is not a big deal, but I like tab aligned ops
+static struct clk *clk_register_avb(struct device *dev, struct rsnd_mod *mod,
unsigned int id, spinlock_t *lock)
+{
- struct clk_init_data init;
- struct clk_avb *avb;
- struct clk *clk;
- char name[AVB_CLK_NAME_SIZE];
- const char *parent_name = ADG_CLK_NAME;
- avb = devm_kzalloc(dev, sizeof(*avb), GFP_KERNEL);
- if (!avb)
return ERR_PTR(-ENOMEM);
- snprintf(name, AVB_CLK_NAME_SIZE, "%s%u", AVB_CLK_NAME, id);
- avb->idx = id;
- avb->lock = lock;
- avb->mod = mod;
- /* Register the clock. */
- init.name = name;
- init.ops = &clk_avb_ops;
- init.flags = CLK_IS_BASIC;
- init.parent_names = &parent_name;
- init.num_parents = 1;
- avb->hw.init = &init;
- /* init DIV to a valid state */
- clk_avb_div_write(avb->mod, avb->idx, AVB_MAX_DIV);
Please check parameter, I think you want to do is
- clk_avb_div_write(avb->mod, avb->idx, AVB_MAX_DIV); + clk_avb_div_write(avb->mod, AVB_MAX_DIV, avb->idx);
Best regards --- Kuninori Morimoto
Hi Morimoto-san
Thanks for your comments, I will address your findings in next version
Thanks, Jiada
On 2018/12/04 10:52, Kuninori Morimoto wrote:
Hi Jiada
There are AVB Counter Clocks in ADG, each clock has 12bits integral and 8 bits fractional dividers which operates with S0D1ϕ clock.
This patch registers 8 AVB Counter Clocks when clock-cells of rcar_sound node is 2,
Signed-off-by: Jiada Wang jiada_wang@mentor.com
(snip)
+struct clk_avb {
- struct clk_hw hw;
- unsigned int idx;
- struct rsnd_mod *mod;
- /* lock reg access */
- spinlock_t *lock;
+};
+#define to_clk_avb(_hw) container_of(_hw, struct clk_avb, hw)
I like "hw_to_avb()"
+static struct clk *rsnd_adg_clk_src_twocell_get(struct of_phandle_args *clkspec,
void *data)
+{
- unsigned int clkidx = clkspec->args[1];
- struct rsnd_adg *adg = data;
- const char *type;
- struct clk *clk;
- switch (clkspec->args[0]) {
- case ADG_FIX:
type = "fixed";
if (clkidx >= CLKOUTMAX) {
pr_err("Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = adg->clkout[clkidx];
break;
- case ADG_AVB:
type = "avb";
if (clkidx >= AVB_CLK_NUM) {
pr_err("Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = adg->clkavb[clkidx];
break;
- default:
pr_err("Invalid ADG clock type %u\n", clkspec->args[0]);
return ERR_PTR(-EINVAL);
- }
- return clk;
+}
In this function
- I don't think you need to use "char *type".
- If you use "clkidx = clkspec->args[1]", having same name for "clkspec->args[0]" is readable.
- please use dev_err() instad of pr_err() I think data can be priv, and you can use rsnd_priv_to_adg(), rsnd_priv_to_dev()
+static void clk_avb_div_write(struct rsnd_mod *mod, u32 data, int idx)
(snip)
+static u32 clk_avb_div_read(struct rsnd_mod *mod, int idx)
To reduce confusion, and be more redable code, I think these function can be
clk_avb_div_write(struct rsnd_adg *adg, u32 data); clk_avb_div_read(struct rsnd_adg *adg);
+static int clk_avb_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
+{
- struct clk_avb *avb = to_clk_avb(hw);
- unsigned int div = clk_avb_calc_div(rate, parent_rate);
- u32 val;
- val = clk_avb_div_read(avb->mod, avb->idx) & ~AVB_DIV_MASK;
- clk_avb_div_write(avb->mod, val | div, avb->idx);
- return 0;
+}
Why do we need to care about ~AVB_DIV_MASK area ? These are 0 Reserved, I think.
+static const struct clk_ops clk_avb_ops = {
- .enable = clk_avb_enable,
- .disable = clk_avb_disable,
- .is_enabled = clk_avb_is_enabled,
- .recalc_rate = clk_avb_recalc_rate,
- .round_rate = clk_avb_round_rate,
- .set_rate = clk_avb_set_rate,
+};
This is not a big deal, but I like tab aligned ops
+static struct clk *clk_register_avb(struct device *dev, struct rsnd_mod *mod,
unsigned int id, spinlock_t *lock)
+{
- struct clk_init_data init;
- struct clk_avb *avb;
- struct clk *clk;
- char name[AVB_CLK_NAME_SIZE];
- const char *parent_name = ADG_CLK_NAME;
- avb = devm_kzalloc(dev, sizeof(*avb), GFP_KERNEL);
- if (!avb)
return ERR_PTR(-ENOMEM);
- snprintf(name, AVB_CLK_NAME_SIZE, "%s%u", AVB_CLK_NAME, id);
- avb->idx = id;
- avb->lock = lock;
- avb->mod = mod;
- /* Register the clock. */
- init.name = name;
- init.ops = &clk_avb_ops;
- init.flags = CLK_IS_BASIC;
- init.parent_names = &parent_name;
- init.num_parents = 1;
- avb->hw.init = &init;
- /* init DIV to a valid state */
- clk_avb_div_write(avb->mod, avb->idx, AVB_MAX_DIV);
Please check parameter, I think you want to do is
- clk_avb_div_write(avb->mod, avb->idx, AVB_MAX_DIV);
- clk_avb_div_write(avb->mod, AVB_MAX_DIV, avb->idx);
Best regards
Kuninori Morimoto
HI Jiada
There are AVB Counter Clocks in ADG, each clock has 12bits integral and 8 bits fractional dividers which operates with S0D1ϕ clock.
This patch registers 8 AVB Counter Clocks when clock-cells of rcar_sound node is 2,
Signed-off-by: Jiada Wang jiada_wang@mentor.com
sound/soc/sh/rcar/adg.c | 306 +++++++++++++++++++++++++++++++++++++-- sound/soc/sh/rcar/gen.c | 9 ++ sound/soc/sh/rcar/rsnd.h | 9 ++ 3 files changed, 315 insertions(+), 9 deletions(-)
Please update DT binding txt, too
Best regards --- Kuninori Morimoto
participants (4)
-
Jiada Wang
-
jiada_wang@mentor.com
-
Kuninori Morimoto
-
Vladimir Zapolskiy