OSDN Git Service

ASoC: rsnd: update BSDSR/BSDISR handling
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tue, 25 Dec 2018 05:05:28 +0000 (14:05 +0900)
committerMark Brown <broonie@kernel.org>
Mon, 7 Jan 2019 18:34:01 +0000 (18:34 +0000)
Current BSDSR/BSDISR are using temporary/generic settings, but it can't
handle all SRCx/SoC. It needs to handle correctry.
Otherwise, sampling rate converted sound channel will be broken if it
was TDM. One note is that it needs to overwrite settings on E3 case.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: chaoliang qin <chaoliang.qin.jg@renesas.com>
Tested-by: Yusuke Goda <yusuke.goda.sx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sh/rcar/src.c

index 50348a2..db81e06 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "rsnd.h"
+#include <linux/sys_soc.h>
 
 #define SRC_NAME "src"
 
@@ -134,20 +135,83 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
        return rate;
 }
 
+const static u32 bsdsr_table_pattern1[] = {
+       0x01800000, /* 6 - 1/6 */
+       0x01000000, /* 6 - 1/4 */
+       0x00c00000, /* 6 - 1/3 */
+       0x00800000, /* 6 - 1/2 */
+       0x00600000, /* 6 - 2/3 */
+       0x00400000, /* 6 - 1   */
+};
+
+const static u32 bsdsr_table_pattern2[] = {
+       0x02400000, /* 6 - 1/6 */
+       0x01800000, /* 6 - 1/4 */
+       0x01200000, /* 6 - 1/3 */
+       0x00c00000, /* 6 - 1/2 */
+       0x00900000, /* 6 - 2/3 */
+       0x00600000, /* 6 - 1   */
+};
+
+const static u32 bsisr_table[] = {
+       0x00100060, /* 6 - 1/6 */
+       0x00100040, /* 6 - 1/4 */
+       0x00100030, /* 6 - 1/3 */
+       0x00100020, /* 6 - 1/2 */
+       0x00100020, /* 6 - 2/3 */
+       0x00100020, /* 6 - 1   */
+};
+
+const static u32 chan288888[] = {
+       0x00000006, /* 1 to 2 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+};
+
+const static u32 chan244888[] = {
+       0x00000006, /* 1 to 2 */
+       0x0000001e, /* 1 to 4 */
+       0x0000001e, /* 1 to 4 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+};
+
+const static u32 chan222222[] = {
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+};
+
+static const struct soc_device_attribute ov_soc[] = {
+       { .soc_id = "r8a77990" }, /* E3 */
+       { /* sentinel */ }
+};
+
 static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
                                      struct rsnd_mod *mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       const struct soc_device_attribute *soc = soc_device_match(ov_soc);
        int is_play = rsnd_io_is_play(io);
        int use_src = 0;
        u32 fin, fout;
        u32 ifscr, fsrate, adinr;
        u32 cr, route;
-       u32 bsdsr, bsisr;
        u32 i_busif, o_busif, tmp;
+       const u32 *bsdsr_table;
+       const u32 *chptn;
        uint ratio;
+       int chan;
+       int idx;
 
        if (!runtime)
                return;
@@ -155,6 +219,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
        fin  = rsnd_src_get_in_rate(priv, io);
        fout = rsnd_src_get_out_rate(priv, io);
 
+       chan = rsnd_runtime_channel_original(io);
+
        /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
        if (fin == fout)
                ratio = 0;
@@ -173,8 +239,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
        /*
         * SRC_ADINR
         */
-       adinr = rsnd_get_adinr_bit(mod, io) |
-               rsnd_runtime_channel_original(io);
+       adinr = rsnd_get_adinr_bit(mod, io) | chan;
 
        /*
         * SRC_IFSCR / SRC_IFSVR
@@ -207,21 +272,56 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
 
        /*
         * SRC_BSDSR / SRC_BSISR
+        *
+        * see
+        *      Combination of Register Setting Related to
+        *      FSO/FSI Ratio and Channel, Latency
         */
        switch (rsnd_mod_id(mod)) {
+       case 0:
+               chptn           = chan288888;
+               bsdsr_table     = bsdsr_table_pattern1;
+               break;
+       case 1:
+       case 3:
+       case 4:
+               chptn           = chan244888;
+               bsdsr_table     = bsdsr_table_pattern1;
+               break;
+       case 2:
+       case 9:
+               chptn           = chan222222;
+               bsdsr_table     = bsdsr_table_pattern1;
+               break;
        case 5:
        case 6:
        case 7:
        case 8:
-               bsdsr = 0x02400000; /* 6 - 1/6 */
-               bsisr = 0x00100060; /* 6 - 1/6 */
+               chptn           = chan222222;
+               bsdsr_table     = bsdsr_table_pattern2;
                break;
        default:
-               bsdsr = 0x01800000; /* 6 - 1/6 */
-               bsisr = 0x00100060 ;/* 6 - 1/6 */
-               break;
+               goto convert_rate_err;
        }
 
+       /*
+        * E3 need to overwrite
+        */
+       if (soc)
+               switch (rsnd_mod_id(mod)) {
+               case 0:
+               case 4:
+                       chptn   = chan222222;
+               }
+
+       for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++)
+               if (chptn[idx] & (1 << chan))
+                       break;
+
+       if (chan > 8 ||
+           idx >= ARRAY_SIZE(chan222222))
+               goto convert_rate_err;
+
        /* BUSIF_MODE */
        tmp = rsnd_get_busif_shift(io, mod);
        i_busif = ( is_play ? tmp : 0) | 1;
@@ -234,8 +334,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
        rsnd_mod_write(mod, SRC_IFSCR, ifscr);
        rsnd_mod_write(mod, SRC_IFSVR, fsrate);
        rsnd_mod_write(mod, SRC_SRCCR, cr);
-       rsnd_mod_write(mod, SRC_BSDSR, bsdsr);
-       rsnd_mod_write(mod, SRC_BSISR, bsisr);
+       rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);
+       rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);
        rsnd_mod_write(mod, SRC_SRCIR, 0);      /* cancel initialize */
 
        rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif);
@@ -244,6 +344,11 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
        rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
 
        rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
+
+       return;
+
+convert_rate_err:
+       dev_err(dev, "unknown BSDSR/BSDIR settings\n");
 }
 
 static int rsnd_src_irq(struct rsnd_mod *mod,