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 19f5509f908deef2a401558b01a00806eafe6b90..d74e1ccc0f8f736828ec8172a633700419cc3f7e 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 4b2d50d9a68617dfe796f006a80d6e8a06b56af8..abb5eaac854a9b9c47027e278cd5204c18aceace 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 ed0918967defabf26fc9c9da1f76666d18a7d05c..b460d714d088a8d5f027a676545f8c9303a91be1 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 d53a225d19e9b724b2b326a32f5746c822e3c4b8..109930a2040109bee693bdf7673177414b7af56e 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 418e6fdd06a338b1aac03d585e1a353bd21bfc26..d1cb3c1775729612932308117dacd881467113f5 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 d45ffe496397f84b4f68adc3377699f2e94e2308..302c193f674d26fe6e5e4e23d00944525310c58c 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 65542b6a89e9e3452b312369035983c98b70077d..e0e337ad4206a7a114f7ab3d4caca96ccf923e5d 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 c7b2ba0daf2a8814f3c0d02e9366d228ec2220ed..28602607cf5ee2f6947ad2ce9dcdd20147b42b47 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 b438538a0a69e727b6c9b8365d1d44efdbcab75b..516b0c05451c1ff2e72324d00948c0a315350b76 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 df3ab74adf3eccea4ed0146aee7e44b40865ce44..e68f3a1c9cb499f65271ee62e39cf35d8606a47d 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 06d72828e5bcdc210ceb1234880abd4d7a50186b..11e55889b40105c24e9a41b7e5eb3d64d7e0cd20 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;
        }