]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
authorMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 21:30:57 +0000 (21:30 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 21:30:57 +0000 (21:30 +0000)
Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
sound/soc/sh/rcar/adg.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/ssi.c

index 8b8afe9fcb315891b0e321152bbf56eefd5c6e30..441dd6f29df13ba987316c5b6a4102c7bf73e636 100644 (file)
@@ -43,7 +43,7 @@ Example 1. Sampling Rate Conversion
                label = "sound-card";
                prefix = "codec";
                routing = "codec Playback", "DAI0 Playback",
-                       "codec Playback", "DAI1 Playback";
+                         "DAI0 Capture",   "codec Capture";
                convert-rate = <48000>;
 
                dais = <&cpu_port>;
@@ -79,7 +79,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
                label = "sound-card";
                prefix = "codec";
                routing = "codec Playback", "DAI0 Playback",
-                       "codec Playback", "DAI1 Playback";
+                         "codec Playback", "DAI1 Playback",
+                         "DAI0 Capture",   "codec Capture";
                convert-rate = <48000>;
 
                dais = <&cpu_port0
index e11ce5036bcfb8347d930673f8888ba414c37418..8ddb08714faabb5bc2b58716155b0ecec501db0d 100644 (file)
@@ -44,7 +44,6 @@ struct rsnd_adg {
 
 #define LRCLK_ASYNC    (1 << 0)
 #define AUDIO_OUT_48   (1 << 1)
-#define adg_mode_flags(adg)    (adg->flags)
 
 #define for_each_rsnd_clk(pos, adg, i)         \
        for (i = 0;                             \
@@ -58,6 +57,13 @@ struct rsnd_adg {
             i++)
 #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
 
+static const char * const clk_name[] = {
+       [CLKA]  = "clk_a",
+       [CLKB]  = "clk_b",
+       [CLKC]  = "clk_c",
+       [CLKI]  = "clk_i",
+};
+
 static u32 rsnd_adg_calculate_rbgx(unsigned long div)
 {
        int i, ratio;
@@ -280,6 +286,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
        struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
        struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+       struct device *dev = rsnd_priv_to_dev(priv);
        int id = rsnd_mod_id(ssi_mod);
        int shift = (id % 4) * 8;
        u32 mask = 0xFF << shift;
@@ -306,12 +313,13 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
                rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
                break;
        }
+
+       dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
 }
 
 int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
 {
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
        struct clk *clk;
        int i;
        int sel_table[] = {
@@ -321,8 +329,6 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
                [CLKI] = 0x0,
        };
 
-       dev_dbg(dev, "request clock = %d\n", rate);
-
        /*
         * find suitable clock from
         * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
@@ -366,8 +372,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
 
        rsnd_adg_set_ssi_clk(ssi_mod, data);
 
-       if (adg_mode_flags(adg) & LRCLK_ASYNC) {
-               if (adg_mode_flags(adg) & AUDIO_OUT_48)
+       if (rsnd_flags_has(adg, LRCLK_ASYNC)) {
+               if (rsnd_flags_has(adg, AUDIO_OUT_48))
                        ckr = 0x80000000;
        } else {
                if (0 == (rate % 8000))
@@ -378,9 +384,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
        rsnd_mod_write(adg_mod, BRRA,  adg->rbga);
        rsnd_mod_write(adg_mod, BRRB,  adg->rbgb);
 
-       dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
-               rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
-               data, rate);
+       dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
+               (ckr) ? 'B' : 'A',
+               (ckr) ? adg->rbgb_rate_for_48khz :
+                       adg->rbga_rate_for_441khz);
 
        return 0;
 }
@@ -409,21 +416,12 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct clk *clk;
-       static const char * const clk_name[] = {
-               [CLKA]  = "clk_a",
-               [CLKB]  = "clk_b",
-               [CLKC]  = "clk_c",
-               [CLKI]  = "clk_i",
-       };
        int i;
 
        for (i = 0; i < CLKMAX; i++) {
                clk = devm_clk_get(dev, clk_name[i]);
                adg->clk[i] = IS_ERR(clk) ? NULL : clk;
        }
-
-       for_each_rsnd_clk(clk, adg, i)
-               dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
 }
 
 static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
@@ -479,10 +477,10 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
        }
 
        if (req_rate[0] % 48000 == 0)
-               adg->flags |= AUDIO_OUT_48;
+               rsnd_flags_set(adg, AUDIO_OUT_48);
 
        if (of_get_property(np, "clkout-lr-asynchronous", NULL))
-               adg->flags |= LRCLK_ASYNC;
+               rsnd_flags_set(adg, LRCLK_ASYNC);
 
        /*
         * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
@@ -512,7 +510,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
                                adg->rbga_rate_for_441khz = rate / div;
                                ckr |= brg_table[i] << 20;
                                if (req_441kHz_rate &&
-                                   !(adg_mode_flags(adg) & AUDIO_OUT_48))
+                                   !rsnd_flags_has(adg, AUDIO_OUT_48))
                                        parent_clk_name = __clk_get_name(clk);
                        }
                }
@@ -528,7 +526,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
                                adg->rbgb_rate_for_48khz = rate / div;
                                ckr |= brg_table[i] << 16;
                                if (req_48kHz_rate &&
-                                   (adg_mode_flags(adg) & AUDIO_OUT_48))
+                                   rsnd_flags_has(adg, AUDIO_OUT_48))
                                        parent_clk_name = __clk_get_name(clk);
                        }
                }
@@ -572,12 +570,35 @@ rsnd_adg_get_clkout_end:
        adg->ckr = ckr;
        adg->rbga = rbga;
        adg->rbgb = rbgb;
+}
+
+#ifdef DEBUG
+static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       int i;
+
+       for_each_rsnd_clk(clk, adg, i)
+               dev_dbg(dev, "%s    : %p : %ld\n",
+                       clk_name[i], clk, clk_get_rate(clk));
 
-       for_each_rsnd_clkout(clk, adg, i)
-               dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk));
        dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
-               ckr, rbga, rbgb);
+               adg->ckr, adg->rbga, adg->rbgb);
+       dev_dbg(dev, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz);
+       dev_dbg(dev, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz);
+
+       /*
+        * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
+        * by BRGCKR::BRGCKR_31
+        */
+       for_each_rsnd_clkout(clk, adg, i)
+               dev_dbg(dev, "clkout %d : %p : %ld\n", i,
+                       clk, clk_get_rate(clk));
 }
+#else
+#define rsnd_adg_clk_dbg_info(priv, adg)
+#endif
 
 int rsnd_adg_probe(struct rsnd_priv *priv)
 {
@@ -596,6 +617,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
 
        rsnd_adg_get_clkin(priv, adg);
        rsnd_adg_get_clkout(priv, adg);
+       rsnd_adg_clk_dbg_info(priv, adg);
 
        priv->adg = adg;
 
index 107133297e8dd169855e3953ebcf0ca630ef336a..c70eb20978163d6952a6764381d083779dbd758b 100644 (file)
@@ -121,14 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
        }
 }
 
-char *rsnd_mod_name(struct rsnd_mod *mod)
-{
-       if (!mod || !mod->ops)
-               return "unknown";
-
-       return mod->ops->name;
-}
-
 struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
                                  struct rsnd_mod *mod)
 {
@@ -172,8 +164,7 @@ int rsnd_mod_init(struct rsnd_priv *priv,
 
 void rsnd_mod_quit(struct rsnd_mod *mod)
 {
-       if (mod->clk)
-               clk_unprepare(mod->clk);
+       clk_unprepare(mod->clk);
        mod->clk = NULL;
 }
 
@@ -200,7 +191,10 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
 int rsnd_io_is_working(struct rsnd_dai_stream *io)
 {
        /* see rsnd_dai_stream_init/quit() */
-       return !!io->substream;
+       if (io->substream)
+               return snd_pcm_running(io->substream);
+
+       return 0;
 }
 
 int rsnd_runtime_channel_original(struct rsnd_dai_stream *io)
@@ -407,11 +401,9 @@ struct rsnd_mod *rsnd_mod_next(int *iterator,
 
        for (; *iterator < max; (*iterator)++) {
                type = (array) ? array[*iterator] : *iterator;
-               mod = io->mod[type];
-               if (!mod)
-                       continue;
-
-               return mod;
+               mod = rsnd_io_to_mod(io, type);
+               if (mod)
+                       return mod;
        }
 
        return NULL;
@@ -1242,6 +1234,33 @@ struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg)
        return &cfg->cfg;
 }
 
+const char * const volume_ramp_rate[] = {
+       "128 dB/1 step",         /* 00000 */
+       "64 dB/1 step",          /* 00001 */
+       "32 dB/1 step",          /* 00010 */
+       "16 dB/1 step",          /* 00011 */
+       "8 dB/1 step",           /* 00100 */
+       "4 dB/1 step",           /* 00101 */
+       "2 dB/1 step",           /* 00110 */
+       "1 dB/1 step",           /* 00111 */
+       "0.5 dB/1 step",         /* 01000 */
+       "0.25 dB/1 step",        /* 01001 */
+       "0.125 dB/1 step",       /* 01010 = VOLUME_RAMP_MAX_MIX */
+       "0.125 dB/2 steps",      /* 01011 */
+       "0.125 dB/4 steps",      /* 01100 */
+       "0.125 dB/8 steps",      /* 01101 */
+       "0.125 dB/16 steps",     /* 01110 */
+       "0.125 dB/32 steps",     /* 01111 */
+       "0.125 dB/64 steps",     /* 10000 */
+       "0.125 dB/128 steps",    /* 10001 */
+       "0.125 dB/256 steps",    /* 10010 */
+       "0.125 dB/512 steps",    /* 10011 */
+       "0.125 dB/1024 steps",   /* 10100 */
+       "0.125 dB/2048 steps",   /* 10101 */
+       "0.125 dB/4096 steps",   /* 10110 */
+       "0.125 dB/8192 steps",   /* 10111 = VOLUME_RAMP_MAX_DVC */
+};
+
 int rsnd_kctrl_new(struct rsnd_mod *mod,
                   struct rsnd_dai_stream *io,
                   struct snd_soc_pcm_runtime *rtd,
index e7f53f44165d78b423c56a1623bbc2cfe965e0e6..d201d551866db10e3f6523d1bb30caa045df0e8a 100644 (file)
@@ -81,8 +81,11 @@ struct rsnd_ctu {
        struct rsnd_kctrl_cfg_m sv3;
        struct rsnd_kctrl_cfg_s reset;
        int channels;
+       u32 flags;
 };
 
+#define KCTRL_INITIALIZED      (1 << 0)
+
 #define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
 #define for_each_rsnd_ctu(pos, priv, i)                                        \
        for ((i) = 0;                                                   \
@@ -130,7 +133,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
        int i;
 
        for (i = 0; i < RSND_MAX_CHANNELS; i++) {
-               u32 val = ctu->pass.val[i];
+               u32 val = rsnd_kctrl_valm(ctu->pass, i);
 
                cpmdr |= val << (28 - (i * 4));
 
@@ -147,44 +150,44 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
        rsnd_mod_write(mod, CTU_SCMDR, scmdr);
 
        if (scmdr > 0) {
-               rsnd_mod_write(mod, CTU_SV00R, ctu->sv0.val[0]);
-               rsnd_mod_write(mod, CTU_SV01R, ctu->sv0.val[1]);
-               rsnd_mod_write(mod, CTU_SV02R, ctu->sv0.val[2]);
-               rsnd_mod_write(mod, CTU_SV03R, ctu->sv0.val[3]);
-               rsnd_mod_write(mod, CTU_SV04R, ctu->sv0.val[4]);
-               rsnd_mod_write(mod, CTU_SV05R, ctu->sv0.val[5]);
-               rsnd_mod_write(mod, CTU_SV06R, ctu->sv0.val[6]);
-               rsnd_mod_write(mod, CTU_SV07R, ctu->sv0.val[7]);
+               rsnd_mod_write(mod, CTU_SV00R, rsnd_kctrl_valm(ctu->sv0, 0));
+               rsnd_mod_write(mod, CTU_SV01R, rsnd_kctrl_valm(ctu->sv0, 1));
+               rsnd_mod_write(mod, CTU_SV02R, rsnd_kctrl_valm(ctu->sv0, 2));
+               rsnd_mod_write(mod, CTU_SV03R, rsnd_kctrl_valm(ctu->sv0, 3));
+               rsnd_mod_write(mod, CTU_SV04R, rsnd_kctrl_valm(ctu->sv0, 4));
+               rsnd_mod_write(mod, CTU_SV05R, rsnd_kctrl_valm(ctu->sv0, 5));
+               rsnd_mod_write(mod, CTU_SV06R, rsnd_kctrl_valm(ctu->sv0, 6));
+               rsnd_mod_write(mod, CTU_SV07R, rsnd_kctrl_valm(ctu->sv0, 7));
        }
        if (scmdr > 1) {
-               rsnd_mod_write(mod, CTU_SV10R, ctu->sv1.val[0]);
-               rsnd_mod_write(mod, CTU_SV11R, ctu->sv1.val[1]);
-               rsnd_mod_write(mod, CTU_SV12R, ctu->sv1.val[2]);
-               rsnd_mod_write(mod, CTU_SV13R, ctu->sv1.val[3]);
-               rsnd_mod_write(mod, CTU_SV14R, ctu->sv1.val[4]);
-               rsnd_mod_write(mod, CTU_SV15R, ctu->sv1.val[5]);
-               rsnd_mod_write(mod, CTU_SV16R, ctu->sv1.val[6]);
-               rsnd_mod_write(mod, CTU_SV17R, ctu->sv1.val[7]);
+               rsnd_mod_write(mod, CTU_SV10R, rsnd_kctrl_valm(ctu->sv1, 0));
+               rsnd_mod_write(mod, CTU_SV11R, rsnd_kctrl_valm(ctu->sv1, 1));
+               rsnd_mod_write(mod, CTU_SV12R, rsnd_kctrl_valm(ctu->sv1, 2));
+               rsnd_mod_write(mod, CTU_SV13R, rsnd_kctrl_valm(ctu->sv1, 3));
+               rsnd_mod_write(mod, CTU_SV14R, rsnd_kctrl_valm(ctu->sv1, 4));
+               rsnd_mod_write(mod, CTU_SV15R, rsnd_kctrl_valm(ctu->sv1, 5));
+               rsnd_mod_write(mod, CTU_SV16R, rsnd_kctrl_valm(ctu->sv1, 6));
+               rsnd_mod_write(mod, CTU_SV17R, rsnd_kctrl_valm(ctu->sv1, 7));
        }
        if (scmdr > 2) {
-               rsnd_mod_write(mod, CTU_SV20R, ctu->sv2.val[0]);
-               rsnd_mod_write(mod, CTU_SV21R, ctu->sv2.val[1]);
-               rsnd_mod_write(mod, CTU_SV22R, ctu->sv2.val[2]);
-               rsnd_mod_write(mod, CTU_SV23R, ctu->sv2.val[3]);
-               rsnd_mod_write(mod, CTU_SV24R, ctu->sv2.val[4]);
-               rsnd_mod_write(mod, CTU_SV25R, ctu->sv2.val[5]);
-               rsnd_mod_write(mod, CTU_SV26R, ctu->sv2.val[6]);
-               rsnd_mod_write(mod, CTU_SV27R, ctu->sv2.val[7]);
+               rsnd_mod_write(mod, CTU_SV20R, rsnd_kctrl_valm(ctu->sv2, 0));
+               rsnd_mod_write(mod, CTU_SV21R, rsnd_kctrl_valm(ctu->sv2, 1));
+               rsnd_mod_write(mod, CTU_SV22R, rsnd_kctrl_valm(ctu->sv2, 2));
+               rsnd_mod_write(mod, CTU_SV23R, rsnd_kctrl_valm(ctu->sv2, 3));
+               rsnd_mod_write(mod, CTU_SV24R, rsnd_kctrl_valm(ctu->sv2, 4));
+               rsnd_mod_write(mod, CTU_SV25R, rsnd_kctrl_valm(ctu->sv2, 5));
+               rsnd_mod_write(mod, CTU_SV26R, rsnd_kctrl_valm(ctu->sv2, 6));
+               rsnd_mod_write(mod, CTU_SV27R, rsnd_kctrl_valm(ctu->sv2, 7));
        }
        if (scmdr > 3) {
-               rsnd_mod_write(mod, CTU_SV30R, ctu->sv3.val[0]);
-               rsnd_mod_write(mod, CTU_SV31R, ctu->sv3.val[1]);
-               rsnd_mod_write(mod, CTU_SV32R, ctu->sv3.val[2]);
-               rsnd_mod_write(mod, CTU_SV33R, ctu->sv3.val[3]);
-               rsnd_mod_write(mod, CTU_SV34R, ctu->sv3.val[4]);
-               rsnd_mod_write(mod, CTU_SV35R, ctu->sv3.val[5]);
-               rsnd_mod_write(mod, CTU_SV36R, ctu->sv3.val[6]);
-               rsnd_mod_write(mod, CTU_SV37R, ctu->sv3.val[7]);
+               rsnd_mod_write(mod, CTU_SV30R, rsnd_kctrl_valm(ctu->sv3, 0));
+               rsnd_mod_write(mod, CTU_SV31R, rsnd_kctrl_valm(ctu->sv3, 1));
+               rsnd_mod_write(mod, CTU_SV32R, rsnd_kctrl_valm(ctu->sv3, 2));
+               rsnd_mod_write(mod, CTU_SV33R, rsnd_kctrl_valm(ctu->sv3, 3));
+               rsnd_mod_write(mod, CTU_SV34R, rsnd_kctrl_valm(ctu->sv3, 4));
+               rsnd_mod_write(mod, CTU_SV35R, rsnd_kctrl_valm(ctu->sv3, 5));
+               rsnd_mod_write(mod, CTU_SV36R, rsnd_kctrl_valm(ctu->sv3, 6));
+               rsnd_mod_write(mod, CTU_SV37R, rsnd_kctrl_valm(ctu->sv3, 7));
        }
 
        rsnd_mod_write(mod, CTU_CTUIR, 0);
@@ -196,17 +199,17 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
        struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
        int i;
 
-       if (!ctu->reset.val)
+       if (!rsnd_kctrl_vals(ctu->reset))
                return;
 
        for (i = 0; i < RSND_MAX_CHANNELS; i++) {
-               ctu->pass.val[i] = 0;
-               ctu->sv0.val[i] = 0;
-               ctu->sv1.val[i] = 0;
-               ctu->sv2.val[i] = 0;
-               ctu->sv3.val[i] = 0;
+               rsnd_kctrl_valm(ctu->pass, i) = 0;
+               rsnd_kctrl_valm(ctu->sv0,  i) = 0;
+               rsnd_kctrl_valm(ctu->sv1,  i) = 0;
+               rsnd_kctrl_valm(ctu->sv2,  i) = 0;
+               rsnd_kctrl_valm(ctu->sv3,  i) = 0;
        }
-       ctu->reset.val = 0;
+       rsnd_kctrl_vals(ctu->reset) = 0;
 }
 
 static int rsnd_ctu_init(struct rsnd_mod *mod,
@@ -277,6 +280,9 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
        struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
        int ret;
 
+       if (rsnd_flags_has(ctu, KCTRL_INITIALIZED))
+               return 0;
+
        /* CTU Pass */
        ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
                               rsnd_kctrl_accept_anytime,
@@ -326,6 +332,8 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
                               rsnd_ctu_value_reset,
                               &ctu->reset, 1);
 
+       rsnd_flags_set(ctu, KCTRL_INITIALIZED);
+
        return ret;
 }
 
index 041ec1080d52fa2429096c394459828552d47db2..fd557abfe390a1ea6c6800e9e9836d039bdbcee3 100644 (file)
@@ -60,6 +60,14 @@ struct rsnd_dma_ctrl {
 #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
 #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
 
+/* for DEBUG */
+static struct rsnd_mod_ops mem_ops = {
+       .name = "mem",
+};
+
+static struct rsnd_mod mem = {
+};
+
 /*
  *             Audio DMAC
  */
@@ -211,11 +219,9 @@ static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod,
                                                 dma->mod_from,
                                                 dma->mod_to);
        if (IS_ERR_OR_NULL(dmaen->chan)) {
-               int ret = PTR_ERR(dmaen->chan);
-
                dmaen->chan = NULL;
                dev_err(dev, "can't get dma channel\n");
-               return ret;
+               return -EIO;
        }
 
        return 0;
@@ -747,20 +753,22 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
                rsnd_mod_name(this), rsnd_mod_id(this));
        for (i = 0; i <= idx; i++) {
                dev_dbg(dev, "  %s[%d]%s\n",
-                      rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
-                      (mod[i] == *mod_from) ? " from" :
-                      (mod[i] == *mod_to)   ? " to" : "");
+                       rsnd_mod_name(mod[i] ? mod[i] : &mem),
+                       rsnd_mod_id  (mod[i] ? mod[i] : &mem),
+                       (mod[i] == *mod_from) ? " from" :
+                       (mod[i] == *mod_to)   ? " to" : "");
        }
 }
 
-int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
-                   struct rsnd_mod **dma_mod)
+static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+                         struct rsnd_mod **dma_mod)
 {
        struct rsnd_mod *mod_from = NULL;
        struct rsnd_mod *mod_to = NULL;
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_dma *dma;
        struct rsnd_mod_ops *ops;
        enum rsnd_mod_type type;
        int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma,
@@ -800,40 +808,47 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
                type    = RSND_MOD_AUDMA;
        }
 
-       if (!(*dma_mod)) {
-               struct rsnd_dma *dma;
+       dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+       if (!dma)
+               return -ENOMEM;
 
-               dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
-               if (!dma)
-                       return -ENOMEM;
+       *dma_mod = rsnd_mod_get(dma);
 
-               *dma_mod = rsnd_mod_get(dma);
+       ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
+                           rsnd_mod_get_status, type, dma_id);
+       if (ret < 0)
+               return ret;
 
-               ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
-                                   rsnd_mod_get_status, type, dma_id);
-               if (ret < 0)
-                       return ret;
+       dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
+               rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
+               rsnd_mod_name(mod_from ? mod_from : &mem),
+               rsnd_mod_id  (mod_from ? mod_from : &mem),
+               rsnd_mod_name(mod_to   ? mod_to   : &mem),
+               rsnd_mod_id  (mod_to   ? mod_to   : &mem));
 
-               dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
-                       rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
-                       rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
-                       rsnd_mod_name(mod_to),   rsnd_mod_id(mod_to));
+       ret = attach(io, dma, mod_from, mod_to);
+       if (ret < 0)
+               return ret;
+
+       dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
+       dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
+       dma->mod_from = mod_from;
+       dma->mod_to   = mod_to;
+
+       return 0;
+}
+
+int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+                   struct rsnd_mod **dma_mod)
+{
+       if (!(*dma_mod)) {
+               int ret = rsnd_dma_alloc(io, mod, dma_mod);
 
-               ret = attach(io, dma, mod_from, mod_to);
                if (ret < 0)
                        return ret;
-
-               dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
-               dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
-               dma->mod_from = mod_from;
-               dma->mod_to   = mod_to;
        }
 
-       ret = rsnd_dai_connect(*dma_mod, io, type);
-       if (ret < 0)
-               return ret;
-
-       return 0;
+       return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type);
 }
 
 int rsnd_dma_probe(struct rsnd_priv *priv)
@@ -866,5 +881,6 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
 
        priv->dma = dmac;
 
-       return 0;
+       /* dummy mem mod for debug */
+       return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0);
 }
index 1743ade3cc55563c04204b37b70d57254f41cae8..dbe54f024d68824fa0b3bd81122891989adb9faf 100644 (file)
@@ -44,8 +44,11 @@ struct rsnd_dvc {
        struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
        struct rsnd_kctrl_cfg_s rup;    /* Ramp Rate Up */
        struct rsnd_kctrl_cfg_s rdown;  /* Ramp Rate Down */
+       u32 flags;
 };
 
+#define KCTRL_INITIALIZED      (1 << 0)
+
 #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
 #define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
 
@@ -58,33 +61,6 @@ struct rsnd_dvc {
             ((pos) = (struct rsnd_dvc *)(priv)->dvc + i);      \
             i++)
 
-static const char * const dvc_ramp_rate[] = {
-       "128 dB/1 step",         /* 00000 */
-       "64 dB/1 step",          /* 00001 */
-       "32 dB/1 step",          /* 00010 */
-       "16 dB/1 step",          /* 00011 */
-       "8 dB/1 step",           /* 00100 */
-       "4 dB/1 step",           /* 00101 */
-       "2 dB/1 step",           /* 00110 */
-       "1 dB/1 step",           /* 00111 */
-       "0.5 dB/1 step",         /* 01000 */
-       "0.25 dB/1 step",        /* 01001 */
-       "0.125 dB/1 step",       /* 01010 */
-       "0.125 dB/2 steps",      /* 01011 */
-       "0.125 dB/4 steps",      /* 01100 */
-       "0.125 dB/8 steps",      /* 01101 */
-       "0.125 dB/16 steps",     /* 01110 */
-       "0.125 dB/32 steps",     /* 01111 */
-       "0.125 dB/64 steps",     /* 10000 */
-       "0.125 dB/128 steps",    /* 10001 */
-       "0.125 dB/256 steps",    /* 10010 */
-       "0.125 dB/512 steps",    /* 10011 */
-       "0.125 dB/1024 steps",   /* 10100 */
-       "0.125 dB/2048 steps",   /* 10101 */
-       "0.125 dB/4096 steps",   /* 10110 */
-       "0.125 dB/8192 steps",   /* 10111 */
-};
-
 static void rsnd_dvc_activation(struct rsnd_mod *mod)
 {
        rsnd_mod_write(mod, DVC_SWRSR, 0);
@@ -97,8 +73,9 @@ static void rsnd_dvc_halt(struct rsnd_mod *mod)
        rsnd_mod_write(mod, DVC_SWRSR, 0);
 }
 
-#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val)
-#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13))
+#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \
+                                rsnd_kctrl_vals(dvc->rdown))
+#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13))
 
 static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
                                              struct rsnd_mod *mod)
@@ -108,12 +85,12 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
        int i;
 
        /* Enable Ramp */
-       if (dvc->ren.val)
+       if (rsnd_kctrl_vals(dvc->ren))
                for (i = 0; i < RSND_MAX_CHANNELS; i++)
-                       val[i] = dvc->volume.cfg.max;
+                       val[i] = rsnd_kctrl_max(dvc->volume);
        else
                for (i = 0; i < RSND_MAX_CHANNELS; i++)
-                       val[i] = dvc->volume.val[i];
+                       val[i] = rsnd_kctrl_valm(dvc->volume, i);
 
        /* Enable Digital Volume */
        rsnd_mod_write(mod, DVC_VOL0R, val[0]);
@@ -143,7 +120,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
        dvucr |= 0x101;
 
        /* Enable Ramp */
-       if (dvc->ren.val) {
+       if (rsnd_kctrl_vals(dvc->ren)) {
                dvucr |= 0x10;
 
                /*
@@ -185,10 +162,10 @@ static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
        u32 vrdbr = 0;
        int i;
 
-       for (i = 0; i < dvc->mute.cfg.size; i++)
-               zcmcr |= (!!dvc->mute.cfg.val[i]) << i;
+       for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++)
+               zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i;
 
-       if (dvc->ren.val) {
+       if (rsnd_kctrl_vals(dvc->ren)) {
                vrpdr = rsnd_dvc_get_vrpdr(dvc);
                vrdbr = rsnd_dvc_get_vrdbr(dvc);
        }
@@ -254,6 +231,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
        int channels = rsnd_rdai_channels_get(rdai);
        int ret;
 
+       if (rsnd_flags_has(dvc, KCTRL_INITIALIZED))
+               return 0;
+
        /* Volume */
        ret = rsnd_kctrl_new_m(mod, io, rtd,
                        is_play ?
@@ -292,7 +272,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                        rsnd_kctrl_accept_anytime,
                        rsnd_dvc_volume_update,
                        &dvc->rup,
-                       dvc_ramp_rate);
+                       volume_ramp_rate,
+                       VOLUME_RAMP_MAX_DVC);
        if (ret < 0)
                return ret;
 
@@ -302,11 +283,14 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                        rsnd_kctrl_accept_anytime,
                        rsnd_dvc_volume_update,
                        &dvc->rdown,
-                       dvc_ramp_rate);
+                       volume_ramp_rate,
+                       VOLUME_RAMP_MAX_DVC);
 
        if (ret < 0)
                return ret;
 
+       rsnd_flags_set(dvc, KCTRL_INITIALIZED);
+
        return 0;
 }
 
index 6c4826c189a42d06eec412cf0086b9721faa28be..7998380766f6f210accaa91bc50f3b3aaeea0bd0 100644 (file)
@@ -7,6 +7,33 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+/*
+ *                 CTUn        MIXn
+ *                 +------+    +------+
+ * [SRC3 / SRC6] -> |CTU n0| ->        [MIX n0| ->
+ * [SRC4 / SRC9] -> |CTU n1| ->        [MIX n1| ->
+ * [SRC0 / SRC1] -> |CTU n2| ->        [MIX n2| ->
+ * [SRC2 / SRC5] -> |CTU n3| ->        [MIX n3| ->
+ *                 +------+    +------+
+ *
+ * ex)
+ *     DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
+ *     DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
+ *
+ * MIX Volume
+ *     amixer set "MIX",0  100%  // DAI0 Volume
+ *     amixer set "MIX",1  100%  // DAI1 Volume
+ *
+ * Volume Ramp
+ *     amixer set "MIX Ramp Up Rate"   "0.125 dB/1 step"
+ *     amixer set "MIX Ramp Down Rate" "4 dB/1 step"
+ *     amixer set "MIX Ramp" on
+ *     aplay xxx.wav &
+ *     amixer set "MIX",0  80%  // DAI0 Volume Down
+ *     amixer set "MIX",1 100%  // DAI1 Volume Up
+ */
+
 #include "rsnd.h"
 
 #define MIX_NAME_SIZE  16
 
 struct rsnd_mix {
        struct rsnd_mod mod;
+       struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
+       struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
+       struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
+       struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
+       struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
+       struct rsnd_kctrl_cfg_s rup;    /* Ramp Rate Up */
+       struct rsnd_kctrl_cfg_s rdw;    /* Ramp Rate Down */
+       u32 flags;
 };
 
+#define ONCE_KCTRL_INITIALIZED         (1 << 0)
+#define HAS_VOLA                       (1 << 1)
+#define HAS_VOLB                       (1 << 2)
+#define HAS_VOLC                       (1 << 3)
+#define HAS_VOLD                       (1 << 4)
+
+#define VOL_MAX                                0x3ff
+
+#define rsnd_mod_to_mix(_mod)  \
+       container_of((_mod), struct rsnd_mix, mod)
+
 #define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
 #define rsnd_mix_nr(priv) ((priv)->mix_nr)
 #define for_each_rsnd_mix(pos, priv, i)                                        \
@@ -36,26 +82,43 @@ static void rsnd_mix_halt(struct rsnd_mod *mod)
        rsnd_mod_write(mod, MIX_SWRSR, 0);
 }
 
+#define rsnd_mix_get_vol(mix, X) \
+       rsnd_flags_has(mix, HAS_VOL##X) ? \
+               (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
 static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
                                      struct rsnd_mod *mod)
 {
-       rsnd_mod_write(mod, MIX_MDBAR, 0);
-       rsnd_mod_write(mod, MIX_MDBBR, 0);
-       rsnd_mod_write(mod, MIX_MDBCR, 0);
-       rsnd_mod_write(mod, MIX_MDBDR, 0);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+       u32 volA = rsnd_mix_get_vol(mix, A);
+       u32 volB = rsnd_mix_get_vol(mix, B);
+       u32 volC = rsnd_mix_get_vol(mix, C);
+       u32 volD = rsnd_mix_get_vol(mix, D);
+
+       dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
+               volA, volB, volC, volD);
+
+       rsnd_mod_write(mod, MIX_MDBAR, volA);
+       rsnd_mod_write(mod, MIX_MDBBR, volB);
+       rsnd_mod_write(mod, MIX_MDBCR, volC);
+       rsnd_mod_write(mod, MIX_MDBDR, volD);
 }
 
 static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
                                 struct rsnd_mod *mod)
 {
+       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+
        rsnd_mod_write(mod, MIX_MIXIR, 1);
 
        /* General Information */
        rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
 
        /* volume step */
-       rsnd_mod_write(mod, MIX_MIXMR, 0);
-       rsnd_mod_write(mod, MIX_MVPDR, 0);
+       rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
+       rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
+                                      rsnd_kctrl_vals(mix->rdw));
 
        /* common volume parameter */
        rsnd_mix_volume_parameter(io, mod);
@@ -109,11 +172,94 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
        return 0;
 }
 
+static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct snd_soc_pcm_runtime *rtd)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+       struct rsnd_kctrl_cfg_s *volume;
+       int ret;
+
+       switch (rsnd_mod_id(src_mod)) {
+       case 3:
+       case 6: /* MDBAR */
+               volume = &mix->volumeA;
+               rsnd_flags_set(mix, HAS_VOLA);
+               break;
+       case 4:
+       case 9: /* MDBBR */
+               volume = &mix->volumeB;
+               rsnd_flags_set(mix, HAS_VOLB);
+               break;
+       case 0:
+       case 1: /* MDBCR */
+               volume = &mix->volumeC;
+               rsnd_flags_set(mix, HAS_VOLC);
+               break;
+       case 2:
+       case 5: /* MDBDR */
+               volume = &mix->volumeD;
+               rsnd_flags_set(mix, HAS_VOLD);
+               break;
+       default:
+               dev_err(dev, "unknown SRC is connected\n");
+               return -EINVAL;
+       }
+
+       /* Volume */
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
+                              "MIX Playback Volume",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_mix_volume_update,
+                              volume, VOL_MAX);
+       if (ret < 0)
+               return ret;
+       rsnd_kctrl_vals(*volume) = VOL_MAX;
+
+       if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
+               return ret;
+
+       /* Ramp */
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
+                              "MIX Ramp Switch",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_mix_volume_update,
+                              &mix->ren, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_kctrl_new_e(mod, io, rtd,
+                              "MIX Ramp Up Rate",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_mix_volume_update,
+                              &mix->rup,
+                              volume_ramp_rate,
+                              VOLUME_RAMP_MAX_MIX);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_kctrl_new_e(mod, io, rtd,
+                              "MIX Ramp Down Rate",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_mix_volume_update,
+                              &mix->rdw,
+                              volume_ramp_rate,
+                              VOLUME_RAMP_MAX_MIX);
+
+       rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);
+
+       return ret;
+}
+
 static struct rsnd_mod_ops rsnd_mix_ops = {
        .name           = MIX_NAME,
        .probe          = rsnd_mix_probe_,
        .init           = rsnd_mix_init,
        .quit           = rsnd_mix_quit,
+       .pcm_new        = rsnd_mix_pcm_new,
 };
 
 struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
index c5de71f2dc8c429b9ed3aabab509ded1651b92f9..57cd2bc773c2ab419e33a814d07b815a42af99cb 100644 (file)
@@ -355,8 +355,9 @@ struct rsnd_mod {
 #define __rsnd_mod_call_nolock_start   0
 #define __rsnd_mod_call_nolock_stop    1
 
-#define rsnd_mod_to_priv(mod) ((mod)->priv)
-#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
+#define rsnd_mod_to_priv(mod)  ((mod)->priv)
+#define rsnd_mod_name(mod)     ((mod)->ops->name)
+#define rsnd_mod_id(mod)       ((mod)->id)
 #define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
 #define rsnd_mod_power_off(mod)        clk_disable((mod)->clk)
 #define rsnd_mod_get(ip)       (&(ip)->mod)
@@ -371,7 +372,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
                  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,
                                  struct rsnd_mod *mod);
 void rsnd_mod_interrupt(struct rsnd_mod *mod,
@@ -601,6 +601,10 @@ struct rsnd_priv {
 #define rsnd_is_gen1(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
 #define rsnd_is_gen2(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
 
+#define rsnd_flags_has(p, f) ((p)->flags & (f))
+#define rsnd_flags_set(p, f) ((p)->flags |= (f))
+#define rsnd_flags_del(p, f) ((p)->flags &= ~(f))
+
 /*
  *     rsnd_kctrl
  */
@@ -627,6 +631,10 @@ struct rsnd_kctrl_cfg_s {
        struct rsnd_kctrl_cfg cfg;
        u32 val;
 };
+#define rsnd_kctrl_size(x)     ((x).cfg.size)
+#define rsnd_kctrl_max(x)      ((x).cfg.max)
+#define rsnd_kctrl_valm(x, i)  ((x).val[i])    /* = (x).cfg.val[i] */
+#define rsnd_kctrl_vals(x)     ((x).val)       /* = (x).cfg.val[0] */
 
 int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io);
 int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io);
@@ -652,9 +660,13 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
        rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
                       NULL, 1, max)
 
-#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts)       \
+#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts, size) \
        rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
-                      texts, 1, ARRAY_SIZE(texts))
+                      texts, 1, size)
+
+extern const char * const volume_ramp_rate[];
+#define VOLUME_RAMP_MAX_DVC    (0x17 + 1)
+#define VOLUME_RAMP_MAX_MIX    (0x0a + 1)
 
 /*
  *     R-Car SSI
index 03c2a1f02643b8eac6a56918a759b8fb95352f72..fece1e5f582f35ab5e558a0b66b3b558816048d6 100644 (file)
@@ -101,9 +101,6 @@ struct rsnd_ssi {
 #define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
 #define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_ssi_flags_has(p, f) ((p)->flags & f)
-#define rsnd_ssi_flags_set(p, f) ((p)->flags |= f)
-#define rsnd_ssi_flags_del(p, f) ((p)->flags = ((p)->flags & ~f))
 #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
 #define rsnd_ssi_is_multi_slave(mod, io) \
        (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod)))
@@ -116,10 +113,10 @@ int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
        struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-       if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI0))
+       if (rsnd_flags_has(ssi, RSND_SSI_HDMI0))
                return RSND_SSI_HDMI_PORT0;
 
-       if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI1))
+       if (rsnd_flags_has(ssi, RSND_SSI_HDMI1))
                return RSND_SSI_HDMI_PORT1;
 
        return 0;
@@ -134,7 +131,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
        if (!rsnd_ssi_is_dma_mode(mod))
                return 0;
 
-       if (!(rsnd_ssi_flags_has(ssi, RSND_SSI_NO_BUSIF)))
+       if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF)))
                use_busif = 1;
        if (rsnd_io_to_mod_src(io))
                use_busif = 1;
@@ -198,10 +195,15 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
 {
        struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
        struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+       u32 mods;
 
-       return rsnd_ssi_multi_slaves_runtime(io) |
-               1 << rsnd_mod_id(ssi_mod) |
-               1 << rsnd_mod_id(ssi_parent_mod);
+       mods = rsnd_ssi_multi_slaves_runtime(io) |
+               1 << rsnd_mod_id(ssi_mod);
+
+       if (ssi_parent_mod)
+               mods |= 1 << rsnd_mod_id(ssi_parent_mod);
+
+       return mods;
 }
 
 u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
@@ -601,15 +603,18 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
        if (rsnd_ssi_is_parent(mod, io))
                return 0;
 
-       /*
-        * disable all IRQ,
-        * and, wait all data was sent
-        */
        cr  =   ssi->cr_own     |
                ssi->cr_clk;
 
-       rsnd_mod_write(mod, SSICR, cr | EN);
-       rsnd_ssi_status_check(mod, DIRQ);
+       /*
+        * disable all IRQ,
+        * Playback: Wait all data was sent
+        * Capture:  It might not receave data. Do nothing
+        */
+       if (rsnd_io_is_play(io)) {
+               rsnd_mod_write(mod, SSICR, cr | EN);
+               rsnd_ssi_status_check(mod, DIRQ);
+       }
 
        /*
         * disable SSI,
@@ -793,13 +798,13 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
         * But it don't need to call request_irq() many times.
         * Let's control it by RSND_SSI_PROBED flag.
         */
-       if (!rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+       if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
                ret = request_irq(ssi->irq,
                                  rsnd_ssi_interrupt,
                                  IRQF_SHARED,
                                  dev_name(dev), mod);
 
-               rsnd_ssi_flags_set(ssi, RSND_SSI_PROBED);
+               rsnd_flags_set(ssi, RSND_SSI_PROBED);
        }
 
        return ret;
@@ -817,10 +822,10 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
                return 0;
 
        /* PIO will request IRQ again */
-       if (rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+       if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
                free_irq(ssi->irq, mod);
 
-               rsnd_ssi_flags_del(ssi, RSND_SSI_PROBED);
+               rsnd_flags_del(ssi, RSND_SSI_PROBED);
        }
 
        return 0;
@@ -1003,13 +1008,13 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
        ssi  = rsnd_mod_to_ssi(mod);
 
        if (strstr(remote_ep->full_name, "hdmi0")) {
-               rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI0);
+               rsnd_flags_set(ssi, RSND_SSI_HDMI0);
                dev_dbg(dev, "%s[%d] connected to HDMI0\n",
                         rsnd_mod_name(mod), rsnd_mod_id(mod));
        }
 
        if (strstr(remote_ep->full_name, "hdmi1")) {
-               rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI1);
+               rsnd_flags_set(ssi, RSND_SSI_HDMI1);
                dev_dbg(dev, "%s[%d] connected to HDMI1\n",
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
        }
@@ -1042,7 +1047,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-       return !!(rsnd_ssi_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE));
+       return !!(rsnd_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE));
 }
 
 static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
@@ -1128,10 +1133,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
                }
 
                if (of_get_property(np, "shared-pin", NULL))
-                       rsnd_ssi_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
+                       rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
 
                if (of_get_property(np, "no-busif", NULL))
-                       rsnd_ssi_flags_set(ssi, RSND_SSI_NO_BUSIF);
+                       rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF);
 
                ssi->irq = irq_of_parse_and_map(np, 0);
                if (!ssi->irq) {