ASoC: rsnd: each mod has status again for CTU/MUX support
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Thu, 21 Jan 2016 01:58:07 +0000 (01:58 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 22 Jan 2016 17:12:25 +0000 (17:12 +0000)
SSI will be used as normal SSI or as clock parent SSI. Therefor,
rsnd driver wants to control SSI and parent SSI separately. Otherwise it
can't use Playback/Capture in the same time.
And it has been done by c2dc47d5cf("ASoC: rsnd: rsnd_dai_stream has each
mod's status insted of rsnd_mod") before.

OTOH, rsnd driver doesn't want to control CTU/MUX/DVC/SSIU/SSI in
separately. Otherwise, these will be re-initialized during playing if
MUX merges 2 sounds.
Because of these picky reasons, this patch re-defines status on each mod,
and add new parent_ssi_status on rsnd_dai_stream.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/cmd.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/mix.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssiu.c

index 19f5509..d74e1cc 100644 (file)
@@ -519,7 +519,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
        }
 
        rsnd_mod_init(priv, &adg->mod, &adg_ops,
-                     NULL, 0, 0);
+                     NULL, NULL, 0, 0);
 
        rsnd_adg_get_clkin(priv, adg);
        rsnd_adg_get_clkout(priv, adg);
index 4b2d50d..abb5eaa 100644 (file)
@@ -157,7 +157,8 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
 
        for_each_rsnd_cmd(cmd, priv, i) {
                ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
-                                   &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i);
+                                   &rsnd_cmd_ops, NULL,
+                                   rsnd_mod_get_status, RSND_MOD_CMD, i);
                if (ret)
                        return ret;
        }
index ed09189..b460d71 100644 (file)
@@ -138,12 +138,22 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
        return mod->ops->dma_req(io, mod);
 }
 
+u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
+                        struct rsnd_mod *mod,
+                        enum rsnd_mod_type type)
+{
+       return &mod->status;
+}
+
 int rsnd_mod_init(struct rsnd_priv *priv,
                  struct rsnd_mod *mod,
-                  struct rsnd_mod_ops *ops,
-                  struct clk *clk,
-                  enum rsnd_mod_type type,
-                  int id)
+                 struct rsnd_mod_ops *ops,
+                 struct clk *clk,
+                 u32* (*get_status)(struct rsnd_dai_stream *io,
+                                    struct rsnd_mod *mod,
+                                    enum rsnd_mod_type type),
+                 enum rsnd_mod_type type,
+                 int id)
 {
        int ret = clk_prepare(clk);
 
@@ -155,6 +165,7 @@ int rsnd_mod_init(struct rsnd_priv *priv,
        mod->type       = type;
        mod->clk        = clk;
        mod->priv       = priv;
+       mod->get_status = get_status;
 
        return ret;
 }
@@ -325,7 +336,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
        struct rsnd_mod *mod = (io)->mod[idx];                  \
        struct device *dev = rsnd_priv_to_dev(priv);            \
-       u32 *status = (io)->mod_status + idx;                   \
+       u32 *status = mod->get_status(io, mod, idx);                    \
        u32 mask = 0xF << __rsnd_mod_shift_##func;                      \
        u8 val  = (*status >> __rsnd_mod_shift_##func) & 0xF;           \
        u8 add  = ((val + __rsnd_mod_add_##func) & 0xF);                \
index d53a225..109930a 100644 (file)
@@ -129,7 +129,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
-                                   clk, RSND_MOD_CTU, i);
+                                   clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
                if (ret)
                        goto rsnd_ctu_probe_done;
 
index 418e6fd..d1cb3c1 100644 (file)
@@ -681,7 +681,7 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
        dma_mod = rsnd_mod_get(dma);
 
        ret = rsnd_mod_init(priv, dma_mod,
-                           ops, NULL, type, dma_id);
+                           ops, NULL, rsnd_mod_get_status, type, dma_id);
        if (ret < 0)
                return ERR_PTR(ret);
 
index d45ffe4..302c193 100644 (file)
@@ -373,7 +373,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
-                             clk, RSND_MOD_DVC, i);
+                                   clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
                if (ret)
                        goto rsnd_dvc_probe_done;
 
index 65542b6..e0e337a 100644 (file)
@@ -172,7 +172,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
-                                   clk, RSND_MOD_MIX, i);
+                                   clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
                if (ret)
                        goto rsnd_mix_probe_done;
 
index c7b2ba0..2860260 100644 (file)
@@ -233,6 +233,10 @@ struct rsnd_mod {
        struct rsnd_mod_ops *ops;
        struct rsnd_priv *priv;
        struct clk *clk;
+       u32 *(*get_status)(struct rsnd_dai_stream *io,
+                          struct rsnd_mod *mod,
+                          enum rsnd_mod_type type);
+       u32 status;
 };
 /*
  * status
@@ -286,10 +290,13 @@ struct rsnd_mod {
 
 int rsnd_mod_init(struct rsnd_priv *priv,
                  struct rsnd_mod *mod,
-                  struct rsnd_mod_ops *ops,
-                  struct clk *clk,
-                  enum rsnd_mod_type type,
-                  int id);
+                 struct rsnd_mod_ops *ops,
+                 struct clk *clk,
+                 u32* (*get_status)(struct rsnd_dai_stream *io,
+                                    struct rsnd_mod *mod,
+                                    enum rsnd_mod_type type),
+                 enum rsnd_mod_type type,
+                 int id);
 void rsnd_mod_quit(struct rsnd_mod *mod);
 char *rsnd_mod_name(struct rsnd_mod *mod);
 struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
@@ -297,6 +304,10 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
 void rsnd_mod_interrupt(struct rsnd_mod *mod,
                        void (*callback)(struct rsnd_mod *mod,
                                         struct rsnd_dai_stream *io));
+u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
+                        struct rsnd_mod *mod,
+                        enum rsnd_mod_type type);
+
 void rsnd_parse_connect_common(struct rsnd_dai *rdai,
                struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
                struct device_node *node,
@@ -319,7 +330,7 @@ struct rsnd_dai_stream {
        struct rsnd_mod *mod[RSND_MOD_MAX];
        struct rsnd_dai_path_info *info; /* rcar_snd.h */
        struct rsnd_dai *rdai;
-       u32 mod_status[RSND_MOD_MAX];
+       u32 parent_ssi_status;
        int byte_pos;
        int period_pos;
        int byte_per_period;
index b438538..516b0c0 100644 (file)
@@ -615,7 +615,8 @@ int rsnd_src_probe(struct rsnd_priv *priv)
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(src),
-                                   &rsnd_src_ops, clk, RSND_MOD_SRC, i);
+                                   &rsnd_src_ops, clk, rsnd_mod_get_status,
+                                   RSND_MOD_SRC, i);
                if (ret)
                        goto rsnd_src_probe_done;
 
index df3ab74..e68f3a1 100644 (file)
@@ -857,6 +857,41 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
        return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
 }
 
+static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod,
+                               enum rsnd_mod_type type)
+{
+       /*
+        * SSIP (= SSI parent) needs to be special, otherwise,
+        * 2nd SSI might doesn't start. see also rsnd_mod_call()
+        *
+        * We can't include parent SSI status on SSI, because we don't know
+        * how many SSI requests parent SSI. Thus, it is localed on "io" now.
+        * ex) trouble case
+        *      Playback: SSI0
+        *      Capture : SSI1 (needs SSI0)
+        *
+        * 1) start Capture  -> SSI0/SSI1 are started.
+        * 2) start Playback -> SSI0 doesn't work, because it is already
+        *                      marked as "started" on 1)
+        *
+        * OTOH, using each mod's status is good for MUX case.
+        * It doesn't need to start in 2nd start
+        * ex)
+        *      IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
+        *                          |
+        *      IO-1: SRC1 -> CTU2 -+
+        *
+        * 1) start IO-0 ->     start SSI0
+        * 2) start IO-1 ->     SSI0 doesn't need to start, because it is
+        *                      already started on 1)
+        */
+       if (type == RSND_MOD_SSIP)
+               return &io->parent_ssi_status;
+
+       return rsnd_mod_get_status(io, mod, type);
+}
+
 int rsnd_ssi_probe(struct rsnd_priv *priv)
 {
        struct device_node *node;
@@ -919,7 +954,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
                        ops = &rsnd_ssi_dma_ops;
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
-                                   RSND_MOD_SSI, i);
+                                   rsnd_ssi_get_status, RSND_MOD_SSI, i);
                if (ret)
                        goto rsnd_ssi_probe_done;
 
index 06d7282..11e5588 100644 (file)
@@ -206,7 +206,8 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
 
        for_each_rsnd_ssiu(ssiu, priv, i) {
                ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
-                                   ops, NULL, RSND_MOD_SSIU, i);
+                                   ops, NULL, rsnd_mod_get_status,
+                                   RSND_MOD_SSIU, i);
                if (ret)
                        return ret;
        }