]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - sound/soc/sh/rcar/core.c
Merge remote-tracking branches 'asoc/topic/omap' and 'asoc/topic/rcar' into asoc...
[karo-tx-linux.git] / sound / soc / sh / rcar / core.c
index 215b668166be6c50d01963cac2ef62598cf6f7b2..91880156e1ae0d9b33436455763cf84efcd4a127 100644 (file)
@@ -197,13 +197,12 @@ static void rsnd_dma_complete(void *data)
         * rsnd_dai_pointer_update() will be called twice,
         * ant it will breaks io->byte_pos
         */
-
-       rsnd_dai_pointer_update(io, io->byte_per_period);
-
        if (dma->submit_loop)
                rsnd_dma_continue(dma);
 
        rsnd_unlock(priv, flags);
+
+       rsnd_dai_pointer_update(io, io->byte_per_period);
 }
 
 static void __rsnd_dma_start(struct rsnd_dma *dma)
@@ -256,11 +255,81 @@ int rsnd_dma_available(struct rsnd_dma *dma)
        return !!dma->chan;
 }
 
+#define DMA_NAME_SIZE 16
+#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
+static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
+{
+       if (mod)
+               return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod));
+       else
+               return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
+
+}
+
+static void rsnd_dma_of_name(struct rsnd_dma *dma,
+                            int is_play, char *dma_name)
+{
+       struct rsnd_mod *this = rsnd_dma_to_mod(dma);
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
+       struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+       struct rsnd_mod *mod[MOD_MAX];
+       struct rsnd_mod *src_mod, *dst_mod;
+       int i, index;
+
+
+       for (i = 0; i < MOD_MAX; i++)
+               mod[i] = NULL;
+
+       /*
+        * in play case...
+        *
+        * src -> dst
+        *
+        * mem -> SSI
+        * mem -> SRC -> SSI
+        * mem -> SRC -> DVC -> SSI
+        */
+       mod[0] = NULL; /* for "mem" */
+       index = 1;
+       for (i = 1; i < MOD_MAX; i++) {
+               if (!src) {
+                       mod[i] = ssi;
+                       break;
+               } else if (!dvc) {
+                       mod[i] = src;
+                       src = NULL;
+               } else {
+                       mod[i] = dvc;
+                       dvc = NULL;
+               }
+
+               if (mod[i] == this)
+                       index = i;
+       }
+
+       if (is_play) {
+               src_mod = mod[index - 1];
+               dst_mod = mod[index];
+       } else {
+               src_mod = mod[index];
+               dst_mod = mod[index + 1];
+       }
+
+       index = 0;
+       index = _rsnd_dma_of_name(dma_name + index, src_mod);
+       *(dma_name + index++) = '_';
+       index = _rsnd_dma_of_name(dma_name + index, dst_mod);
+}
+
 int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
                  int is_play, int id)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_slave_config cfg;
+       char dma_name[DMA_NAME_SIZE];
        dma_cap_mask_t mask;
        int ret;
 
@@ -272,18 +341,23 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
+       if (dev->of_node)
+               rsnd_dma_of_name(dma, is_play, dma_name);
+       else
+               snprintf(dma_name, DMA_NAME_SIZE,
+                        is_play ? "tx" : "rx");
+
+       dev_dbg(dev, "dma name : %s\n", dma_name);
+
        dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
                                                     (void *)id, dev,
-                                                    is_play ? "tx" : "rx");
+                                                    dma_name);
        if (!dma->chan) {
                dev_err(dev, "can't get dma channel\n");
                return -EIO;
        }
 
-       cfg.slave_id    = id;
-       cfg.dst_addr    = 0; /* use default addr when playback */
-       cfg.src_addr    = 0; /* use default addr when capture */
-       cfg.direction   = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+       rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id);
 
        ret = dmaengine_slave_config(dma->chan, &cfg);
        if (ret < 0)
@@ -309,24 +383,50 @@ void  rsnd_dma_quit(struct rsnd_priv *priv,
        dma->chan = NULL;
 }
 
+/*
+ *     settting function
+ */
+u32 rsnd_get_adinr(struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 adinr = runtime->channels;
+
+       switch (runtime->sample_bits) {
+       case 16:
+               adinr |= (8 << 16);
+               break;
+       case 32:
+               adinr |= (0 << 16);
+               break;
+       default:
+               dev_warn(dev, "not supported sample bits\n");
+               return 0;
+       }
+
+       return adinr;
+}
+
 /*
  *     rsnd_dai functions
  */
-#define __rsnd_mod_call(mod, func, rdai, io)                   \
+#define __rsnd_mod_call(mod, func, rdai...)                    \
 ({                                                             \
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
        struct device *dev = rsnd_priv_to_dev(priv);            \
        dev_dbg(dev, "%s [%d] %s\n",                            \
                rsnd_mod_name(mod), rsnd_mod_id(mod), #func);   \
-       (mod)->ops->func(mod, rdai, io);                        \
+       (mod)->ops->func(mod, rdai);                            \
 })
 
-#define rsnd_mod_call(mod, func, rdai, io)     \
+#define rsnd_mod_call(mod, func, rdai...)      \
        (!(mod) ? -ENODEV :                     \
         !((mod)->ops->func) ? 0 :              \
-        __rsnd_mod_call(mod, func, (rdai), (io)))
+        __rsnd_mod_call(mod, func, rdai))
 
-#define rsnd_dai_call(rdai, io, fn)                            \
+#define rsnd_dai_call(fn, io, rdai...)                         \
 ({                                                             \
        struct rsnd_mod *mod;                                   \
        int ret = 0, i;                                         \
@@ -334,7 +434,7 @@ void  rsnd_dma_quit(struct rsnd_priv *priv,
                mod = (io)->mod[i];                             \
                if (!mod)                                       \
                        continue;                               \
-               ret = rsnd_mod_call(mod, fn, (rdai), (io));     \
+               ret = rsnd_mod_call(mod, fn, rdai);             \
                if (ret < 0)                                    \
                        break;                                  \
        }                                                       \
@@ -468,10 +568,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
        struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-       struct rsnd_mod *mod = rsnd_ssi_mod_get_frm_dai(priv,
-                                               rsnd_dai_id(priv, rdai),
-                                               rsnd_dai_is_play(rdai, io));
-       int ssi_id = rsnd_mod_id(mod);
+       int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
        int ret;
        unsigned long flags;
 
@@ -487,20 +584,20 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(rdai, io, init);
+               ret = rsnd_dai_call(init, io, rdai);
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(rdai, io, start);
+               ret = rsnd_dai_call(start, io, rdai);
                if (ret < 0)
                        goto dai_trigger_end;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               ret = rsnd_dai_call(rdai, io, stop);
+               ret = rsnd_dai_call(stop, io, rdai);
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(rdai, io, quit);
+               ret = rsnd_dai_call(quit, io, rdai);
                if (ret < 0)
                        goto dai_trigger_end;
 
@@ -579,15 +676,27 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
        .set_fmt        = rsnd_soc_dai_set_fmt,
 };
 
+#define rsnd_path_parse(priv, io, type)                                \
+({                                                             \
+       struct rsnd_mod *mod;                                   \
+       int ret = 0;                                            \
+       int id = -1;                                            \
+                                                               \
+       if (rsnd_is_enable_path(io, type)) {                    \
+               id = rsnd_info_id(priv, io, type);              \
+               if (id >= 0) {                                  \
+                       mod = rsnd_##type##_mod_get(priv, id);  \
+                       ret = rsnd_dai_connect(mod, io);        \
+               }                                               \
+       }                                                       \
+       ret;                                                    \
+})
+
 static int rsnd_path_init(struct rsnd_priv *priv,
                          struct rsnd_dai *rdai,
                          struct rsnd_dai_stream *io)
 {
-       struct rsnd_mod *mod;
-       struct rsnd_dai_platform_info *dai_info = rdai->info;
        int ret;
-       int ssi_id = -1;
-       int src_id = -1;
 
        /*
         * Gen1 is created by SRU/SSI, and this SRU is base module of
@@ -599,38 +708,21 @@ static int rsnd_path_init(struct rsnd_priv *priv,
         * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
         * using fixed path.
         */
-       if (dai_info) {
-               if (rsnd_is_enable_path(io, ssi))
-                       ssi_id = rsnd_info_id(priv, io, ssi);
-               if (rsnd_is_enable_path(io, src))
-                       src_id = rsnd_info_id(priv, io, src);
-       } else {
-               /* get SSI's ID */
-               mod = rsnd_ssi_mod_get_frm_dai(priv,
-                                              rsnd_dai_id(priv, rdai),
-                                              rsnd_dai_is_play(rdai, io));
-               if (!mod)
-                       return 0;
-               ssi_id = src_id = rsnd_mod_id(mod);
-       }
-
-       ret = 0;
 
        /* SRC */
-       if (src_id >= 0) {
-               mod = rsnd_src_mod_get(priv, src_id);
-               ret = rsnd_dai_connect(mod, io);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = rsnd_path_parse(priv, io, src);
+       if (ret < 0)
+               return ret;
 
        /* SSI */
-       if (ssi_id >= 0) {
-               mod = rsnd_ssi_mod_get(priv, ssi_id);
-               ret = rsnd_dai_connect(mod, io);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = rsnd_path_parse(priv, io, ssi);
+       if (ret < 0)
+               return ret;
+
+       /* DVC */
+       ret = rsnd_path_parse(priv, io, dvc);
+       if (ret < 0)
+               return ret;
 
        return ret;
 }
@@ -726,29 +818,14 @@ static int rsnd_dai_probe(struct platform_device *pdev,
        struct snd_soc_dai_driver *drv;
        struct rcar_snd_info *info = rsnd_priv_to_info(priv);
        struct rsnd_dai *rdai;
-       struct rsnd_mod *pmod, *cmod;
+       struct rsnd_ssi_platform_info *pmod, *cmod;
        struct device *dev = rsnd_priv_to_dev(priv);
        int dai_nr;
        int i;
 
        rsnd_of_parse_dai(pdev, of_data, priv);
 
-       /*
-        * dai_nr should be set via dai_info_nr,
-        * but allow it to keeping compatible
-        */
        dai_nr = info->dai_info_nr;
-       if (!dai_nr) {
-               /* get max dai nr */
-               for (dai_nr = 0; dai_nr < 32; dai_nr++) {
-                       pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
-                       cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
-
-                       if (!pmod && !cmod)
-                               break;
-               }
-       }
-
        if (!dai_nr) {
                dev_err(dev, "no dai\n");
                return -EIO;
@@ -766,11 +843,10 @@ static int rsnd_dai_probe(struct platform_device *pdev,
        priv->rdai      = rdai;
 
        for (i = 0; i < dai_nr; i++) {
-               if (info->dai_info)
-                       rdai[i].info = &info->dai_info[i];
+               rdai[i].info = &info->dai_info[i];
 
-               pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1);
-               cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0);
+               pmod = rdai[i].info->playback.ssi;
+               cmod = rdai[i].info->capture.ssi;
 
                /*
                 *      init rsnd_dai
@@ -788,8 +864,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                        drv[i].playback.channels_min    = 2;
                        drv[i].playback.channels_max    = 2;
 
-                       if (info->dai_info)
-                               rdai[i].playback.info = &info->dai_info[i].playback;
+                       rdai[i].playback.info = &info->dai_info[i].playback;
                        rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
                }
                if (cmod) {
@@ -798,8 +873,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                        drv[i].capture.channels_min     = 2;
                        drv[i].capture.channels_max     = 2;
 
-                       if (info->dai_info)
-                               rdai[i].capture.info = &info->dai_info[i].capture;
+                       rdai[i].capture.info = &info->dai_info[i].capture;
                        rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
                }
 
@@ -874,6 +948,20 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
 
 static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct rsnd_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct rsnd_dai *rdai;
+       int i, ret;
+
+       for_each_rsnd_dai(rdai, priv, i) {
+               ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd);
+               if (ret)
+                       return ret;
+
+               ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd);
+               if (ret)
+                       return ret;
+       }
+
        return snd_pcm_lib_preallocate_pages_for_all(
                rtd->pcm,
                SNDRV_DMA_TYPE_DEV,
@@ -913,6 +1001,7 @@ static int rsnd_probe(struct platform_device *pdev)
                rsnd_gen_probe,
                rsnd_ssi_probe,
                rsnd_src_probe,
+               rsnd_dvc_probe,
                rsnd_adg_probe,
                rsnd_dai_probe,
        };
@@ -942,7 +1031,7 @@ static int rsnd_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       priv->dev       = dev;
+       priv->pdev      = pdev;
        priv->info      = info;
        spin_lock_init(&priv->lock);
 
@@ -956,11 +1045,11 @@ static int rsnd_probe(struct platform_device *pdev)
        }
 
        for_each_rsnd_dai(rdai, priv, i) {
-               ret = rsnd_dai_call(rdai, &rdai->playback, probe);
+               ret = rsnd_dai_call(probe, &rdai->playback, rdai);
                if (ret)
                        return ret;
 
-               ret = rsnd_dai_call(rdai, &rdai->capture, probe);
+               ret = rsnd_dai_call(probe, &rdai->capture, rdai);
                if (ret)
                        return ret;
        }
@@ -1003,11 +1092,11 @@ static int rsnd_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
 
        for_each_rsnd_dai(rdai, priv, i) {
-               ret = rsnd_dai_call(rdai, &rdai->playback, remove);
+               ret = rsnd_dai_call(remove, &rdai->playback, rdai);
                if (ret)
                        return ret;
 
-               ret = rsnd_dai_call(rdai, &rdai->capture, remove);
+               ret = rsnd_dai_call(remove, &rdai->capture, rdai);
                if (ret)
                        return ret;
        }