]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - sound/soc/sh/rcar/ctu.c
ASoC: rsnd: add CTU basic support
[mirror_ubuntu-bionic-kernel.git] / sound / soc / sh / rcar / ctu.c
index d53a225d19e9b724b2b326a32f5746c822e3c4b8..784515afefaffe71033b668a2d29db6c5c8f5c16 100644 (file)
@@ -14,6 +14,7 @@
 
 struct rsnd_ctu {
        struct rsnd_mod mod;
+       int channels;
 };
 
 #define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
@@ -23,12 +24,28 @@ struct rsnd_ctu {
                     ((pos) = (struct rsnd_ctu *)(priv)->ctu + i);      \
             i++)
 
+#define rsnd_mod_to_ctu(_mod)  \
+       container_of((_mod), struct rsnd_ctu, mod)
+
 #define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
-#define rsnd_ctu_initialize_lock(mod)  __rsnd_ctu_initialize_lock(mod, 1)
-#define rsnd_ctu_initialize_unlock(mod)        __rsnd_ctu_initialize_lock(mod, 0)
-static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
+
+static void rsnd_ctu_activation(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, CTU_SWRSR, 0);
+       rsnd_mod_write(mod, CTU_SWRSR, 1);
+}
+
+static void rsnd_ctu_halt(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, CTU_CTUIR, 1);
+       rsnd_mod_write(mod, CTU_SWRSR, 0);
+}
+
+int rsnd_ctu_converted_channel(struct rsnd_mod *mod)
 {
-       rsnd_mod_write(mod, CTU_CTUIR, enable);
+       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
+
+       return ctu->channels;
 }
 
 static int rsnd_ctu_probe_(struct rsnd_mod *mod,
@@ -38,17 +55,63 @@ static int rsnd_ctu_probe_(struct rsnd_mod *mod,
        return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
 }
 
+static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
+                              struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, CTU_CTUIR, 1);
+
+       rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io));
+
+       rsnd_mod_write(mod, CTU_CPMDR, 0);
+       rsnd_mod_write(mod, CTU_SCMDR, 0);
+       rsnd_mod_write(mod, CTU_SV00R, 0);
+       rsnd_mod_write(mod, CTU_SV01R, 0);
+       rsnd_mod_write(mod, CTU_SV02R, 0);
+       rsnd_mod_write(mod, CTU_SV03R, 0);
+       rsnd_mod_write(mod, CTU_SV04R, 0);
+       rsnd_mod_write(mod, CTU_SV05R, 0);
+       rsnd_mod_write(mod, CTU_SV06R, 0);
+       rsnd_mod_write(mod, CTU_SV07R, 0);
+
+       rsnd_mod_write(mod, CTU_SV10R, 0);
+       rsnd_mod_write(mod, CTU_SV11R, 0);
+       rsnd_mod_write(mod, CTU_SV12R, 0);
+       rsnd_mod_write(mod, CTU_SV13R, 0);
+       rsnd_mod_write(mod, CTU_SV14R, 0);
+       rsnd_mod_write(mod, CTU_SV15R, 0);
+       rsnd_mod_write(mod, CTU_SV16R, 0);
+       rsnd_mod_write(mod, CTU_SV17R, 0);
+
+       rsnd_mod_write(mod, CTU_SV20R, 0);
+       rsnd_mod_write(mod, CTU_SV21R, 0);
+       rsnd_mod_write(mod, CTU_SV22R, 0);
+       rsnd_mod_write(mod, CTU_SV23R, 0);
+       rsnd_mod_write(mod, CTU_SV24R, 0);
+       rsnd_mod_write(mod, CTU_SV25R, 0);
+       rsnd_mod_write(mod, CTU_SV26R, 0);
+       rsnd_mod_write(mod, CTU_SV27R, 0);
+
+       rsnd_mod_write(mod, CTU_SV30R, 0);
+       rsnd_mod_write(mod, CTU_SV31R, 0);
+       rsnd_mod_write(mod, CTU_SV32R, 0);
+       rsnd_mod_write(mod, CTU_SV33R, 0);
+       rsnd_mod_write(mod, CTU_SV34R, 0);
+       rsnd_mod_write(mod, CTU_SV35R, 0);
+       rsnd_mod_write(mod, CTU_SV36R, 0);
+       rsnd_mod_write(mod, CTU_SV37R, 0);
+
+       rsnd_mod_write(mod, CTU_CTUIR, 0);
+}
+
 static int rsnd_ctu_init(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
        rsnd_mod_power_on(mod);
 
-       rsnd_ctu_initialize_lock(mod);
-
-       rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io));
+       rsnd_ctu_activation(mod);
 
-       rsnd_ctu_initialize_unlock(mod);
+       rsnd_ctu_value_init(io, mod);
 
        return 0;
 }
@@ -57,16 +120,56 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
+       rsnd_ctu_halt(mod);
+
        rsnd_mod_power_off(mod);
 
        return 0;
 }
 
+static int rsnd_ctu_hw_params(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
+                             struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *fe_params)
+{
+       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+
+       /*
+        * CTU assumes that it is used under DPCM if user want to use
+        * channel transfer. Then, CTU should be FE.
+        * And then, this function will be called *after* BE settings.
+        * this means, each BE already has fixuped hw_params.
+        * see
+        *      dpcm_fe_dai_hw_params()
+        *      dpcm_be_dai_hw_params()
+        */
+       ctu->channels = 0;
+       if (fe->dai_link->dynamic) {
+               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+               struct device *dev = rsnd_priv_to_dev(priv);
+               struct snd_soc_dpcm *dpcm;
+               struct snd_pcm_hw_params *be_params;
+               int stream = substream->stream;
+
+               list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+                       be_params = &dpcm->hw_params;
+                       if (params_channels(fe_params) != params_channels(be_params))
+                               ctu->channels = params_channels(be_params);
+               }
+
+               dev_dbg(dev, "CTU convert channels %d\n", ctu->channels);
+       }
+
+       return 0;
+}
+
 static struct rsnd_mod_ops rsnd_ctu_ops = {
        .name           = CTU_NAME,
        .probe          = rsnd_ctu_probe_,
        .init           = rsnd_ctu_init,
        .quit           = rsnd_ctu_quit,
+       .hw_params      = rsnd_ctu_hw_params,
 };
 
 struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
@@ -129,7 +232,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;