Merge tag 'char-misc-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[deliverable/linux.git] / sound / soc / sh / rcar / src.c
index 81c182b4bad531c8afe3a071da4c9ad41c4d868f..3beb32eb412a103db4135a20e96948f4a1c88c80 100644 (file)
 struct rsnd_src {
        struct rsnd_src_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
+       struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
+       struct rsnd_kctrl_cfg_s sync; /* sync convert */
+       u32 convert_rate; /* sampling rate convert */
        int err;
 };
 
 #define RSND_SRC_NAME_SIZE 16
 
-#define rsnd_src_convert_rate(p) ((p)->info->convert_rate)
+#define rsnd_enable_sync_convert(src) ((src)->sen.val)
+#define rsnd_src_of_node(priv) \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
+
 #define rsnd_mod_to_src(_mod)                          \
        container_of((_mod), struct rsnd_src, mod)
-#define rsnd_src_dma_available(src) \
-       rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod))
 
 #define for_each_rsnd_src(pos, priv, i)                                \
        for ((i) = 0;                                           \
@@ -113,6 +117,17 @@ struct rsnd_src {
 /*
  *             Gen1/Gen2 common functions
  */
+static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       int is_play = rsnd_io_is_play(io);
+
+       return rsnd_dma_request_channel(rsnd_src_of_node(priv),
+                                       mod,
+                                       is_play ? "rx" : "tx");
+}
+
 int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
                        int use_busif)
 {
@@ -220,6 +235,30 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
        return 0;
 }
 
+static u32 rsnd_src_convert_rate(struct rsnd_src *src)
+{
+       struct rsnd_mod *mod = &src->mod;
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       u32 convert_rate;
+
+       if (!runtime)
+               return 0;
+
+       if (!rsnd_enable_sync_convert(src))
+               return src->convert_rate;
+
+       convert_rate = src->sync.val;
+
+       if (!convert_rate)
+               convert_rate = src->convert_rate;
+
+       if (!convert_rate)
+               convert_rate = runtime->rate;
+
+       return convert_rate;
+}
+
 unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
                                   struct rsnd_dai_stream *io,
                                   struct snd_pcm_runtime *runtime)
@@ -276,7 +315,43 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod)
        return 0;
 }
 
-static int rsnd_src_init(struct rsnd_mod *mod)
+static int rsnd_src_hw_params(struct rsnd_mod *mod,
+                             struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *fe_params)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+
+       /* default value (mainly for non-DT) */
+       src->convert_rate = src->info->convert_rate;
+
+       /*
+        * SRC assumes that it is used under DPCM if user want to use
+        * sampling rate convert. Then, SRC 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()
+        */
+       if (fe->dai_link->dynamic) {
+               int stream = substream->stream;
+               struct snd_soc_dpcm *dpcm;
+               struct snd_pcm_hw_params *be_params;
+
+               list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+                       be_params = &dpcm->hw_params;
+
+                       if (params_rate(fe_params) != params_rate(be_params))
+                               src->convert_rate = params_rate(be_params);
+               }
+       }
+
+       return 0;
+}
+
+static int rsnd_src_init(struct rsnd_mod *mod,
+                        struct rsnd_priv *priv)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
 
@@ -284,6 +359,9 @@ static int rsnd_src_init(struct rsnd_mod *mod)
 
        src->err = 0;
 
+       /* reset sync convert_rate */
+       src->sync.val = 0;
+
        /*
         * Initialize the operation of the SRC internal circuits
         * see rsnd_src_start()
@@ -305,6 +383,11 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
                dev_warn(dev, "%s[%d] under/over flow err = %d\n",
                         rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
 
+       src->convert_rate = 0;
+
+       /* reset sync convert_rate */
+       src->sync.val = 0;
+
        return 0;
 }
 
@@ -448,23 +531,12 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod)
        return 0;
 }
 
-static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
-                              struct rsnd_priv *priv)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       dev_dbg(dev, "%s[%d] (Gen1) is probed\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod));
-
-       return 0;
-}
-
 static int rsnd_src_init_gen1(struct rsnd_mod *mod,
                              struct rsnd_priv *priv)
 {
        int ret;
 
-       ret = rsnd_src_init(mod);
+       ret = rsnd_src_init(mod, priv);
        if (ret < 0)
                return ret;
 
@@ -505,11 +577,12 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
 
 static struct rsnd_mod_ops rsnd_src_gen1_ops = {
        .name   = SRC_NAME,
-       .probe  = rsnd_src_probe_gen1,
+       .dma_req = rsnd_src_dma_req,
        .init   = rsnd_src_init_gen1,
        .quit   = rsnd_src_quit,
        .start  = rsnd_src_start_gen1,
        .stop   = rsnd_src_stop_gen1,
+       .hw_params = rsnd_src_hw_params,
 };
 
 /*
@@ -607,13 +680,17 @@ static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
 
        if (rsnd_src_error_record_gen2(mod)) {
                struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+               struct rsnd_src *src = rsnd_mod_to_src(mod);
                struct device *dev = rsnd_priv_to_dev(priv);
 
-               _rsnd_src_stop_gen2(mod);
-               _rsnd_src_start_gen2(mod);
-
                dev_dbg(dev, "%s[%d] restart\n",
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+               _rsnd_src_stop_gen2(mod);
+               if (src->err < 1024)
+                       _rsnd_src_start_gen2(mod);
+               else
+                       dev_warn(dev, "no more SRC restart\n");
        }
 
        return IRQ_HANDLED;
@@ -627,6 +704,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 cr, route;
        uint ratio;
        int ret;
 
@@ -647,13 +725,21 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
        if (ret < 0)
                return ret;
 
-       rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
-
+       cr      = 0x00011110;
+       route   = 0x0;
        if (convert_rate) {
-               /* Gen1/Gen2 are not compatible */
-               rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+               route   = 0x1;
+
+               if (rsnd_enable_sync_convert(src)) {
+                       cr |= 0x1;
+                       route |= rsnd_io_is_play(io) ?
+                               (0x1 << 24) : (0x1 << 25);
+               }
        }
 
+       rsnd_mod_write(mod, SRC_SRCCR, cr);
+       rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+
        switch (rsnd_mod_id(mod)) {
        case 5:
        case 6:
@@ -708,24 +794,12 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
                                       IRQF_SHARED,
                                       dev_name(dev), mod);
                if (ret)
-                       goto rsnd_src_probe_gen2_fail;
+                       return ret;
        }
 
        ret = rsnd_dma_init(priv,
                            rsnd_mod_to_dma(mod),
-                           rsnd_info_is_playback(priv, src),
                            src->info->dma_id);
-       if (ret)
-               goto rsnd_src_probe_gen2_fail;
-
-       dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod));
-
-       return ret;
-
-rsnd_src_probe_gen2_fail:
-       dev_err(dev, "%s[%d] (Gen2) failed\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod));
 
        return ret;
 }
@@ -733,7 +807,7 @@ rsnd_src_probe_gen2_fail:
 static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
                                struct rsnd_priv *priv)
 {
-       rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
+       rsnd_dma_quit(rsnd_mod_to_dma(mod));
 
        return 0;
 }
@@ -743,7 +817,7 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod,
 {
        int ret;
 
-       ret = rsnd_src_init(mod);
+       ret = rsnd_src_init(mod, priv);
        if (ret < 0)
                return ret;
 
@@ -778,14 +852,91 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
        return ret;
 }
 
+static void rsnd_src_reconvert_update(struct rsnd_mod *mod)
+{
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 fsrate;
+
+       if (!runtime)
+               return;
+
+       if (!convert_rate)
+               convert_rate = runtime->rate;
+
+       fsrate = 0x0400000 / convert_rate * runtime->rate;
+
+       /* update IFS */
+       rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+}
+
+static int rsnd_src_pcm_new(struct rsnd_mod *mod,
+                           struct snd_soc_pcm_runtime *rtd)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       int ret;
+
+       /*
+        * enable SRC sync convert if possible
+        */
+
+       /*
+        * Gen1 is not supported
+        */
+       if (rsnd_is_gen1(priv))
+               return 0;
+
+       /*
+        * SRC sync convert needs clock master
+        */
+       if (!rsnd_rdai_is_clk_master(rdai))
+               return 0;
+
+       /*
+        * We can't use SRC sync convert
+        * if it has DVC
+        */
+       if (rsnd_io_to_mod_dvc(io))
+               return 0;
+
+       /*
+        * enable sync convert
+        */
+       ret = rsnd_kctrl_new_s(mod, rtd,
+                              rsnd_io_is_play(io) ?
+                              "SRC Out Rate Switch" :
+                              "SRC In Rate Switch",
+                              rsnd_src_reconvert_update,
+                              &src->sen, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_kctrl_new_s(mod, rtd,
+                              rsnd_io_is_play(io) ?
+                              "SRC Out Rate" :
+                              "SRC In Rate",
+                              rsnd_src_reconvert_update,
+                              &src->sync, 192000);
+
+       return ret;
+}
+
 static struct rsnd_mod_ops rsnd_src_gen2_ops = {
        .name   = SRC_NAME,
+       .dma_req = rsnd_src_dma_req,
        .probe  = rsnd_src_probe_gen2,
        .remove = rsnd_src_remove_gen2,
        .init   = rsnd_src_init_gen2,
        .quit   = rsnd_src_quit,
        .start  = rsnd_src_start_gen2,
        .stop   = rsnd_src_stop_gen2,
+       .hw_params = rsnd_src_hw_params,
+       .pcm_new = rsnd_src_pcm_new,
 };
 
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -810,7 +961,7 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
        if (!of_data)
                return;
 
-       src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+       src_node = rsnd_src_of_node(priv);
        if (!src_node)
                return;
 
@@ -850,7 +1001,7 @@ int rsnd_src_probe(struct platform_device *pdev,
        struct rsnd_mod_ops *ops;
        struct clk *clk;
        char name[RSND_SRC_NAME_SIZE];
-       int i, nr;
+       int i, nr, ret;
 
        ops = NULL;
        if (rsnd_is_gen1(priv))
@@ -890,10 +1041,21 @@ int rsnd_src_probe(struct platform_device *pdev,
 
                src->info = &info->src_info[i];
 
-               rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
-
-               dev_dbg(dev, "SRC%d probed\n", i);
+               ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
+               if (ret)
+                       return ret;
        }
 
        return 0;
 }
+
+void rsnd_src_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_src *src;
+       int i;
+
+       for_each_rsnd_src(src, priv, i) {
+               rsnd_mod_quit(&src->mod);
+       }
+}
This page took 0.031889 seconds and 5 git commands to generate.