ASoC: rsnd: make sure SSI parent/child uses same number of sound channel.
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Fri, 10 Apr 2015 08:50:30 +0000 (08:50 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 27 Apr 2015 19:57:38 +0000 (20:57 +0100)
SSI parent/child need to use same number of sound data channel
if these are sharing clock/ws pin. this patch makes it sure.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sh/rcar/ssi.c

index 2ef48a4..5b89723 100644 (file)
@@ -66,6 +66,7 @@ struct rsnd_ssi {
 
        u32 cr_own;
        u32 cr_clk;
+       int chan;
        int err;
        unsigned int usrcnt;
 };
@@ -264,6 +265,8 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi)
                }
 
                rsnd_mod_hw_stop(&ssi->mod);
+
+               ssi->chan = 0;
        }
 
        dev_dbg(dev, "%s[%d] hw stopped\n",
@@ -340,6 +343,35 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
        return 0;
 }
 
+static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
+                             struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
+       int chan = params_channels(params);
+
+       /*
+        * Already working.
+        * It will happen if SSI has parent/child connection.
+        */
+       if (ssi->usrcnt) {
+               /*
+                * it is error if child <-> parent SSI uses
+                * different channels.
+                */
+               if (ssi->chan != chan)
+                       return -EIO;
+       }
+
+       /* It will be removed on rsnd_ssi_hw_stop */
+       ssi->chan = chan;
+       if (ssi_parent)
+               return rsnd_ssi_hw_params(&ssi_parent->mod, substream, params);
+
+       return 0;
+}
+
 static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
 {
        /* under/over flow error */
@@ -460,6 +492,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
        .quit   = rsnd_ssi_quit,
        .start  = rsnd_ssi_start,
        .stop   = rsnd_ssi_stop,
+       .hw_params = rsnd_ssi_hw_params,
 };
 
 static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
@@ -569,6 +602,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
        .start  = rsnd_ssi_dma_start,
        .stop   = rsnd_ssi_dma_stop,
        .fallback = rsnd_ssi_fallback,
+       .hw_params = rsnd_ssi_hw_params,
 };
 
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)