| From 3ce69392154484a529d9951b13e3542ea7ac0ace Mon Sep 17 00:00:00 2001 |
| From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
| Date: Sun, 21 Jul 2013 21:36:03 -0700 |
| Subject: ASoC: add Renesas R-Car module feature |
| |
| Renesas R-Car series sound circuit consists of SSI and its peripheral. |
| But this peripheral circuit is different between |
| R-Car Generation1 (E1/M1/H1) and Generation2 (E2/M2/H2) |
| (Actually, there are many difference in Generation1 chips) |
| |
| Gen1 series consists of SRU/SSI/ADG, and |
| Gen2 series consists of SCU/SSIU/SSI/ADG. |
| |
| In order to control these by same method, |
| these are treated as "mod" on this driver. |
| |
| Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
| Signed-off-by: Mark Brown <broonie@linaro.org> |
| (cherry picked from commit cdaa3cdfb4a710545a53740b1780a683b043618a) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| sound/soc/sh/rcar/core.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ |
| sound/soc/sh/rcar/rsnd.h | 46 ++++++++++++++++++++++++++++ |
| 2 files changed, 126 insertions(+) |
| |
| diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c |
| index 13b5d50efd06..a47fda2aa600 100644 |
| --- a/sound/soc/sh/rcar/core.c |
| +++ b/sound/soc/sh/rcar/core.c |
| @@ -108,8 +108,73 @@ |
| |
| |
| /* |
| + * rsnd_mod functions |
| + */ |
| +char *rsnd_mod_name(struct rsnd_mod *mod) |
| +{ |
| + if (!mod || !mod->ops) |
| + return "unknown"; |
| + |
| + return mod->ops->name; |
| +} |
| + |
| +void rsnd_mod_init(struct rsnd_priv *priv, |
| + struct rsnd_mod *mod, |
| + struct rsnd_mod_ops *ops, |
| + int id) |
| +{ |
| + mod->priv = priv; |
| + mod->id = id; |
| + mod->ops = ops; |
| + INIT_LIST_HEAD(&mod->list); |
| +} |
| + |
| +/* |
| * rsnd_dai functions |
| */ |
| +#define rsnd_dai_call(rdai, io, fn) \ |
| +({ \ |
| + struct rsnd_mod *mod, *n; \ |
| + int ret = 0; \ |
| + for_each_rsnd_mod(mod, n, io) { \ |
| + ret = rsnd_mod_call(mod, fn, rdai, io); \ |
| + if (ret < 0) \ |
| + break; \ |
| + } \ |
| + ret; \ |
| +}) |
| + |
| +int rsnd_dai_connect(struct rsnd_dai *rdai, |
| + struct rsnd_mod *mod, |
| + struct rsnd_dai_stream *io) |
| +{ |
| + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| + struct device *dev = rsnd_priv_to_dev(priv); |
| + |
| + if (!mod) { |
| + dev_err(dev, "NULL mod\n"); |
| + return -EIO; |
| + } |
| + |
| + if (!list_empty(&mod->list)) { |
| + dev_err(dev, "%s%d is not empty\n", |
| + rsnd_mod_name(mod), |
| + rsnd_mod_id(mod)); |
| + return -EIO; |
| + } |
| + |
| + list_add_tail(&mod->list, &io->head); |
| + |
| + return 0; |
| +} |
| + |
| +int rsnd_dai_disconnect(struct rsnd_mod *mod) |
| +{ |
| + list_del_init(&mod->list); |
| + |
| + return 0; |
| +} |
| + |
| struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id) |
| { |
| return priv->rdai + id; |
| @@ -224,8 +289,23 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
| if (ret < 0) |
| goto dai_trigger_end; |
| |
| + ret = rsnd_dai_call(rdai, io, init); |
| + if (ret < 0) |
| + goto dai_trigger_end; |
| + |
| + ret = rsnd_dai_call(rdai, io, start); |
| + if (ret < 0) |
| + goto dai_trigger_end; |
| break; |
| case SNDRV_PCM_TRIGGER_STOP: |
| + ret = rsnd_dai_call(rdai, io, stop); |
| + if (ret < 0) |
| + goto dai_trigger_end; |
| + |
| + ret = rsnd_dai_call(rdai, io, quit); |
| + if (ret < 0) |
| + goto dai_trigger_end; |
| + |
| ret = rsnd_platform_call(priv, dai, stop, ssi_id); |
| if (ret < 0) |
| goto dai_trigger_end; |
| diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h |
| index 8d04fd0352bd..65d3835cffbc 100644 |
| --- a/sound/soc/sh/rcar/rsnd.h |
| +++ b/sound/soc/sh/rcar/rsnd.h |
| @@ -28,10 +28,53 @@ |
| * see gen1/gen2 for detail |
| */ |
| struct rsnd_priv; |
| +struct rsnd_mod; |
| struct rsnd_dai; |
| struct rsnd_dai_stream; |
| |
| /* |
| + * R-Car sound mod |
| + */ |
| + |
| +struct rsnd_mod_ops { |
| + char *name; |
| + int (*init)(struct rsnd_mod *mod, |
| + struct rsnd_dai *rdai, |
| + struct rsnd_dai_stream *io); |
| + int (*quit)(struct rsnd_mod *mod, |
| + struct rsnd_dai *rdai, |
| + struct rsnd_dai_stream *io); |
| + int (*start)(struct rsnd_mod *mod, |
| + struct rsnd_dai *rdai, |
| + struct rsnd_dai_stream *io); |
| + int (*stop)(struct rsnd_mod *mod, |
| + struct rsnd_dai *rdai, |
| + struct rsnd_dai_stream *io); |
| +}; |
| + |
| +struct rsnd_mod { |
| + int id; |
| + struct rsnd_priv *priv; |
| + struct rsnd_mod_ops *ops; |
| + struct list_head list; /* connect to rsnd_dai playback/capture */ |
| +}; |
| + |
| +#define rsnd_mod_to_priv(mod) ((mod)->priv) |
| +#define rsnd_mod_id(mod) ((mod)->id) |
| +#define for_each_rsnd_mod(pos, n, io) \ |
| + list_for_each_entry_safe(pos, n, &(io)->head, list) |
| +#define rsnd_mod_call(mod, func, rdai, io) \ |
| + (!(mod) ? -ENODEV : \ |
| + !((mod)->ops->func) ? 0 : \ |
| + (mod)->ops->func(mod, rdai, io)) |
| + |
| +void rsnd_mod_init(struct rsnd_priv *priv, |
| + struct rsnd_mod *mod, |
| + struct rsnd_mod_ops *ops, |
| + int id); |
| +char *rsnd_mod_name(struct rsnd_mod *mod); |
| + |
| +/* |
| * R-Car sound DAI |
| */ |
| #define RSND_DAI_NAME_SIZE 16 |
| @@ -64,6 +107,9 @@ struct rsnd_dai { |
| i++, (rdai) = rsnd_dai_get(priv, i)) |
| |
| struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); |
| +int rsnd_dai_disconnect(struct rsnd_mod *mod); |
| +int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod, |
| + struct rsnd_dai_stream *io); |
| int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); |
| #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) |
| |
| -- |
| 1.8.5.rc3 |
| |