[alsa-devel] [PATCH 0/6] ASoC: rcar: add Gen2 support
Hi Mark
These patches add Gen2 PIO transfer support for Renesas sound driver. DMA transfer will be supported.
Kuninori Morimoto (6): ASoC: rcar: remove unused register settings ASoC: rcar: separate regmap init common field ASoC: rcar: add rsnd_is_accessible_reg() ASoC: rcar: remove .path_init/exit from rsnd_gen_ops ASoC: rcar: remove rcar_gen_ops ASoC: rcar: add Gen2 sound support
sound/soc/sh/rcar/gen.c | 248 +++++++++++++++++++++++++++++----------------- sound/soc/sh/rcar/rsnd.h | 6 +- sound/soc/sh/rcar/ssi.c | 3 + 3 files changed, 162 insertions(+), 95 deletions(-)
Best regards --- Kuninori Morimoto
AUDIO_CLK_SEL4/5 are not used
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/gen.c | 3 --- sound/soc/sh/rcar/rsnd.h | 3 --- 2 files changed, 6 deletions(-)
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 61212ee..b94d4ce 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -208,9 +208,6 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08), RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), - RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL3, 0x18), - RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL4, 0x1c), - RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL5, 0x20),
RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40), RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 9e463e5..748d6ca 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -49,9 +49,6 @@ enum rsnd_reg { RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, RSND_REG_AUDIO_CLK_SEL2, - RSND_REG_AUDIO_CLK_SEL3, - RSND_REG_AUDIO_CLK_SEL4, - RSND_REG_AUDIO_CLK_SEL5,
/* SSI */ RSND_REG_SSICR,
The repmap initialization difference between Gen1/Gen2 is only register offset. This patch separates rsnd_gen1_regmap_init() into common part and Gen1 specific part.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/gen.c | 49 +++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 21 deletions(-)
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index b94d4ce..0ebea44 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -115,6 +115,33 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, mask, data); }
+static int rsnd_gen_regmap_init(struct rsnd_priv *priv, + struct rsnd_gen *gen, + struct reg_field *regf) +{ + int i; + struct device *dev = rsnd_priv_to_dev(priv); + struct regmap_config regc; + + memset(®c, 0, sizeof(regc)); + regc.reg_bits = 32; + regc.val_bits = 32; + + gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); + if (IS_ERR(gen->regmap)) { + dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); + return PTR_ERR(gen->regmap); + } + + for (i = 0; i < RSND_REG_MAX; i++) { + gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); + if (IS_ERR(gen->regs[i])) + return PTR_ERR(gen->regs[i]); + + } + + return 0; +} /* * Gen2 * will be filled in the future @@ -189,9 +216,6 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) { - int i; - struct device *dev = rsnd_priv_to_dev(priv); - struct regmap_config regc; struct reg_field regf[RSND_REG_MAX] = { RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00), RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08), @@ -216,24 +240,7 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), };
- memset(®c, 0, sizeof(regc)); - regc.reg_bits = 32; - regc.val_bits = 32; - - gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); - if (IS_ERR(gen->regmap)) { - dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); - return PTR_ERR(gen->regmap); - } - - for (i = 0; i < RSND_REG_MAX; i++) { - gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); - if (IS_ERR(gen->regs[i])) - return PTR_ERR(gen->regs[i]); - - } - - return 0; + return rsnd_gen_regmap_init(priv, gen, regf); }
static int rsnd_gen1_probe(struct platform_device *pdev,
Current rcar driver is supporting Gen1, and Gen2 will be supported soon. Then, some registers are used from Gen1 only, or from Gen2 only. To avoid NULL pointer access, this patch adds register accessible check function.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/gen.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 0ebea44..970439d 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -86,12 +86,28 @@ static struct regmap_bus rsnd_regmap_bus = { .val_format_endian_default = REGMAP_ENDIAN_NATIVE, };
+static int rsnd_is_accessible_reg(struct rsnd_priv *priv, + struct rsnd_gen *gen, enum rsnd_reg reg) +{ + if (!gen->regs[reg]) { + struct device *dev = rsnd_priv_to_dev(priv); + + dev_err(dev, "unsupported register access %x\n", reg); + return 0; + } + + return 1; +} + u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg) { struct rsnd_gen *gen = rsnd_priv_to_gen(priv); u32 val;
+ if (!rsnd_is_accessible_reg(priv, gen, reg)) + return 0; + regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
return val; @@ -103,6 +119,9 @@ void rsnd_write(struct rsnd_priv *priv, { struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+ if (!rsnd_is_accessible_reg(priv, gen, reg)) + return; + regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); }
@@ -111,6 +130,9 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, { struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+ if (!rsnd_is_accessible_reg(priv, gen, reg)) + return; + regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), mask, data); } @@ -134,6 +156,10 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, }
for (i = 0; i < RSND_REG_MAX; i++) { + gen->regs[i] = NULL; + if (!regf[i].reg) + continue; + gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); if (IS_ERR(gen->regs[i])) return PTR_ERR(gen->regs[i]);
rsnd_gen_ops has .path_init/exit callback function which cares SRU/SSI (if Gen1) SCU/SSIU/SSI (if Gen2) path settings. But, the differences between Gen1/Gen2 are cared in ssi.c/scu.c, and the path itself is same in Gen1/Gen2. This patch removes .path_init/exit callback.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/gen.c | 54 +++++++++++++---------------------------------- 1 file changed, 15 insertions(+), 39 deletions(-)
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 970439d..4f2eaa3 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -16,12 +16,6 @@ struct rsnd_gen_ops { struct rsnd_priv *priv); void (*remove)(struct platform_device *pdev, struct rsnd_priv *priv); - int (*path_init)(struct rsnd_priv *priv, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); - int (*path_exit)(struct rsnd_priv *priv, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io); };
struct rsnd_gen { @@ -168,17 +162,10 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
return 0; } -/* - * Gen2 - * will be filled in the future - */
-/* - * Gen1 - */ -static int rsnd_gen1_path_init(struct rsnd_priv *priv, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) +int rsnd_gen_path_init(struct rsnd_priv *priv, + struct rsnd_dai *rdai, + struct rsnd_dai_stream *io) { struct rsnd_mod *mod; int ret; @@ -216,9 +203,9 @@ static int rsnd_gen1_path_init(struct rsnd_priv *priv, return ret; }
-static int rsnd_gen1_path_exit(struct rsnd_priv *priv, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) +int rsnd_gen_path_exit(struct rsnd_priv *priv, + struct rsnd_dai *rdai, + struct rsnd_dai_stream *io) { struct rsnd_mod *mod, *n; int ret = 0; @@ -232,6 +219,15 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv, return ret; }
+/* + * Gen2 + * will be filled in the future + */ + +/* + * Gen1 + */ + /* single address mapping */ #define RSND_GEN1_S_REG(gen, reg, id, offset) \ RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9) @@ -319,31 +315,11 @@ static void rsnd_gen1_remove(struct platform_device *pdev, static struct rsnd_gen_ops rsnd_gen1_ops = { .probe = rsnd_gen1_probe, .remove = rsnd_gen1_remove, - .path_init = rsnd_gen1_path_init, - .path_exit = rsnd_gen1_path_exit, };
/* * Gen */ -int rsnd_gen_path_init(struct rsnd_priv *priv, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) -{ - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - return gen->ops->path_init(priv, rdai, io); -} - -int rsnd_gen_path_exit(struct rsnd_priv *priv, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) -{ - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - return gen->ops->path_exit(priv, rdai, io); -} - int rsnd_gen_probe(struct platform_device *pdev, struct rcar_snd_info *info, struct rsnd_priv *priv)
Current rcar driver gen.c is using rcar_gen_ops which was made with the assumption that Gen1 and Gen2 need different behavior. but it was not needed. This patch removes unnecessary complex method.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/gen.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-)
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 4f2eaa3..a29e36e 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -10,14 +10,6 @@ */ #include "rsnd.h"
-struct rsnd_gen_ops { - int (*probe)(struct platform_device *pdev, - struct rcar_snd_info *info, - struct rsnd_priv *priv); - void (*remove)(struct platform_device *pdev, - struct rsnd_priv *priv); -}; - struct rsnd_gen { void __iomem *base[RSND_BASE_MAX];
@@ -307,16 +299,6 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
}
-static void rsnd_gen1_remove(struct platform_device *pdev, - struct rsnd_priv *priv) -{ -} - -static struct rsnd_gen_ops rsnd_gen1_ops = { - .probe = rsnd_gen1_probe, - .remove = rsnd_gen1_remove, -}; - /* * Gen */ @@ -326,6 +308,7 @@ int rsnd_gen_probe(struct platform_device *pdev, { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen; + int ret;
gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); if (!gen) { @@ -333,23 +316,19 @@ int rsnd_gen_probe(struct platform_device *pdev, return -ENOMEM; }
- if (rsnd_is_gen1(priv)) - gen->ops = &rsnd_gen1_ops; + priv->gen = gen;
- if (!gen->ops) { + if (rsnd_is_gen1(priv)) { + ret = rsnd_gen1_probe(pdev, info, priv); + } else { dev_err(dev, "unknown generation R-Car sound device\n"); return -ENODEV; }
- priv->gen = gen; - - return gen->ops->probe(pdev, info, priv); + return ret; }
void rsnd_gen_remove(struct platform_device *pdev, struct rsnd_priv *priv) { - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - gen->ops->remove(pdev, priv); }
This patch adds Gen2 sound support for Renesas R-Car. But, it is supporting PIO transfer only at this point
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/gen.c | 91 +++++++++++++++++++++++++++++++++++++++++++--- sound/soc/sh/rcar/rsnd.h | 3 +- sound/soc/sh/rcar/ssi.c | 3 ++ 3 files changed, 91 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index a29e36e..bf066f7 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -213,9 +213,88 @@ int rsnd_gen_path_exit(struct rsnd_priv *priv,
/* * Gen2 - * will be filled in the future */
+/* single address mapping */ +#define RSND_GEN2_S_REG(gen, reg, id, offset) \ + RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, 0, 9) + +/* multi address mapping */ +#define RSND_GEN2_M_REG(gen, reg, id, offset, _id_offset) \ + RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, _id_offset, 9) + +static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) +{ + struct reg_field regf[RSND_REG_MAX] = { + RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), + RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), + /* FIXME: it needs SSI_MODE2/3 in the future */ + RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), + + RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), + RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), + RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), + RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), + RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), + RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), + + RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), + RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), + RSND_GEN2_M_REG(gen, SSI, SSITDR, 0x08, 0x40), + RSND_GEN2_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), + RSND_GEN2_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), + }; + + return rsnd_gen_regmap_init(priv, gen, regf); +} + +static int rsnd_gen2_probe(struct platform_device *pdev, + struct rcar_snd_info *info, + struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + struct resource *scu_res; + struct resource *adg_res; + struct resource *ssiu_res; + struct resource *ssi_res; + int ret; + + /* + * map address + */ + scu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU); + adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG); + ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU); + ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI); + + gen->base[RSND_GEN2_SCU] = devm_ioremap_resource(dev, scu_res); + gen->base[RSND_GEN2_ADG] = devm_ioremap_resource(dev, adg_res); + gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res); + gen->base[RSND_GEN2_SSI] = devm_ioremap_resource(dev, ssi_res); + if (IS_ERR(gen->base[RSND_GEN2_SCU]) || + IS_ERR(gen->base[RSND_GEN2_ADG]) || + IS_ERR(gen->base[RSND_GEN2_SSIU]) || + IS_ERR(gen->base[RSND_GEN2_SSI])) + return -ENODEV; + + ret = rsnd_gen2_regmap_init(priv, gen); + if (ret < 0) + return ret; + + dev_dbg(dev, "Gen2 device probed\n"); + dev_dbg(dev, "SRU : %08x => %p\n", scu_res->start, + gen->base[RSND_GEN2_SCU]); + dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, + gen->base[RSND_GEN2_ADG]); + dev_dbg(dev, "SSIU : %08x => %p\n", ssiu_res->start, + gen->base[RSND_GEN2_SSIU]); + dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start, + gen->base[RSND_GEN2_SSI]); + + return 0; +} + /* * Gen1 */ @@ -318,12 +397,14 @@ int rsnd_gen_probe(struct platform_device *pdev,
priv->gen = gen;
- if (rsnd_is_gen1(priv)) { + ret = -ENODEV; + if (rsnd_is_gen1(priv)) ret = rsnd_gen1_probe(pdev, info, priv); - } else { + else if (rsnd_is_gen2(priv)) + ret = rsnd_gen2_probe(pdev, info, priv); + + if (ret < 0) dev_err(dev, "unknown generation R-Car sound device\n"); - return -ENODEV; - }
return ret; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 748d6ca..4647c15 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -31,7 +31,7 @@ * see gen1/gen2 for detail */ enum rsnd_reg { - /* SRU/SCU */ + /* SRU/SCU/SSIU */ RSND_REG_SRC_ROUTE_SEL, RSND_REG_SRC_TMG_SEL0, RSND_REG_SRC_TMG_SEL1, @@ -41,6 +41,7 @@ enum rsnd_reg { RSND_REG_SSI_MODE1, RSND_REG_BUSIF_MODE, RSND_REG_BUSIF_ADINR, + RSND_REG_INT_ENABLE,
/* ADG */ RSND_REG_BRRA, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 5ac20cd..a821b14 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -457,6 +457,9 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod, /* enable PIO IRQ */ ssi->cr_etc = UIEN | OIEN | DIEN;
+ /* enable PIO interrupt */ + rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000); + rsnd_ssi_hw_start(ssi, rdai, io);
dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
participants (2)
-
Kuninori Morimoto
-
Mark Brown