Message ID | 20181203112427.18324-1-jiada_wang@mentor.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | clk: renesas: adg: add AVB Clock | expand |
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 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
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 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 > 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
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,