diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2013-07-21 21:36:03 -0700 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-07-28 19:34:09 +0100 |
commit | cdaa3cdfb4a710545a53740b1780a683b043618a (patch) | |
tree | 48118dbc5149323d18366203d22cf62d9c1446f2 /sound/soc/sh | |
parent | 1536a968892aa9095aada4b6d2ed326432cd71c8 (diff) | |
download | kernel_goldelico_gta04-cdaa3cdfb4a710545a53740b1780a683b043618a.zip kernel_goldelico_gta04-cdaa3cdfb4a710545a53740b1780a683b043618a.tar.gz kernel_goldelico_gta04-cdaa3cdfb4a710545a53740b1780a683b043618a.tar.bz2 |
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>
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/rcar/core.c | 80 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 46 |
2 files changed, 126 insertions, 0 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 13b5d50..a47fda2 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 8d04fd0..65d3835 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) |