aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2013-07-21 21:36:03 -0700
committerMark Brown <broonie@linaro.org>2013-07-28 19:34:09 +0100
commitcdaa3cdfb4a710545a53740b1780a683b043618a (patch)
tree48118dbc5149323d18366203d22cf62d9c1446f2 /sound/soc/sh
parent1536a968892aa9095aada4b6d2ed326432cd71c8 (diff)
downloadkernel_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.c80
-rw-r--r--sound/soc/sh/rcar/rsnd.h46
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)