ASoC: uniphier: add support for multichannel output
authorKatsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Fri, 27 Jul 2018 02:37:28 +0000 (11:37 +0900)
committerMark Brown <broonie@kernel.org>
Mon, 30 Jul 2018 11:02:31 +0000 (12:02 +0100)
This patch adds multichannel PCM output support for LD11/LD20.
Currently driver tested and supported only 2ch, 6ch, and 8ch.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/uniphier/aio-core.c
sound/soc/uniphier/aio-ld11.c
sound/soc/uniphier/aio-reg.h
sound/soc/uniphier/aio.h

index 638cb3fc5f7b1dee22367c52ec3c7c0622459111..8b09bbb0f8d0848cf63b5b7a56d5539961c1c285 100644 (file)
@@ -264,6 +264,57 @@ void aio_port_reset(struct uniphier_aio_sub *sub)
        }
 }
 
+/**
+ * aio_port_set_ch - set channels of LPCM
+ * @sub: the AIO substream pointer, PCM substream only
+ * @ch : count of channels
+ *
+ * Set suitable slot selecting to input/output port block of AIO.
+ *
+ * This function may return error if non-PCM substream.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+static int aio_port_set_ch(struct uniphier_aio_sub *sub)
+{
+       struct regmap *r = sub->aio->chip->regmap;
+       u32 slotsel_2ch[] = {
+               0, 0, 0, 0, 0,
+       };
+       u32 slotsel_multi[] = {
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
+               OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
+       };
+       u32 mode, *slotsel;
+       int i;
+
+       switch (params_channels(&sub->params)) {
+       case 8:
+       case 6:
+               mode = OPORTMXTYSLOTCTR_MODE;
+               slotsel = slotsel_multi;
+               break;
+       case 2:
+               mode = 0;
+               slotsel = slotsel_2ch;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < AUD_MAX_SLOTSEL; i++) {
+               regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
+                                  OPORTMXTYSLOTCTR_MODE, mode);
+               regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
+                                  OPORTMXTYSLOTCTR_SLOTSEL_MASK, slotsel[i]);
+       }
+
+       return 0;
+}
+
 /**
  * aio_port_set_rate - set sampling rate of LPCM
  * @sub: the AIO substream pointer, PCM substream only
@@ -575,6 +626,10 @@ int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
                        rate = params_rate(params);
                }
 
+               ret = aio_port_set_ch(sub);
+               if (ret)
+                       return ret;
+
                ret = aio_port_set_rate(sub, rate);
                if (ret)
                        return ret;
@@ -731,15 +786,28 @@ void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
 int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
 {
        struct regmap *r = sub->aio->chip->regmap;
-       u32 v;
+       u32 memfmt, v;
 
        if (sub->swm->dir == PORT_DIR_OUTPUT) {
-               if (pass_through)
+               if (pass_through) {
                        v = PBOUTMXCTR0_ENDIAN_0123 |
                                PBOUTMXCTR0_MEMFMT_STREAM;
-               else
-                       v = PBOUTMXCTR0_ENDIAN_3210 |
-                               PBOUTMXCTR0_MEMFMT_2CH;
+               } else {
+                       switch (params_channels(&sub->params)) {
+                       case 2:
+                               memfmt = PBOUTMXCTR0_MEMFMT_2CH;
+                               break;
+                       case 6:
+                               memfmt = PBOUTMXCTR0_MEMFMT_6CH;
+                               break;
+                       case 8:
+                               memfmt = PBOUTMXCTR0_MEMFMT_8CH;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       v = PBOUTMXCTR0_ENDIAN_3210 | memfmt;
+               }
 
                regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
                regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
index ab04d3331be94313748938e5c3f87133b1952eae..de962df245baa450872d5ec9cc87f90d88b3f665 100644 (file)
@@ -286,7 +286,7 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
                        .rates       = SNDRV_PCM_RATE_48000,
                        .channels_min = 2,
-                       .channels_max = 2,
+                       .channels_max = 8,
                },
                .ops = &uniphier_aio_i2s_ops,
        },
index 45fdc6ae358af5dfe5d1022d376d160b53b7a15c..734395dbcffbd22348a62c8435ddc01d1a3be563 100644 (file)
 #define OPORTMXTYVOLGAINSTATUS(n, m)     (0x42108 + 0x400 * (n) + 0x20 * (m))
 #define   OPORTMXTYVOLGAINSTATUS_CUR_MASK  GENMASK(15, 0)
 #define OPORTMXTYSLOTCTR(n, m)           (0x42114 + 0x400 * (n) + 0x20 * (m))
+#define   OPORTMXTYSLOTCTR_MODE            BIT(15)
 #define   OPORTMXTYSLOTCTR_SLOTSEL_MASK    GENMASK(11, 8)
 #define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT0   (0x8 << 8)
 #define   OPORTMXTYSLOTCTR_SLOTSEL_SLOT1   (0x9 << 8)
index aa89c2f6fa24014569306a3c63228e27d216d859..23a5c3c68658495f77e480f5492c76a770e5bf95 100644 (file)
@@ -141,6 +141,9 @@ enum IEC61937_PC {
 #define AUD_MIN_FRAGMENT_SIZE    (4 * 1024)
 #define AUD_MAX_FRAGMENT_SIZE    (16 * 1024)
 
+/* max 5 slots, 10 channels, 2 channel in 1 slot */
+#define AUD_MAX_SLOTSEL    5
+
 /*
  * This is a selector for virtual register map of AIO.
  *