ASoC: ti: davinci-mcasp: Fix DIT mode support
authorPeter Ujfalusi <peter.ujfalusi@gmail.com>
Mon, 5 Jul 2021 19:42:45 +0000 (22:42 +0300)
committerMark Brown <broonie@kernel.org>
Sun, 11 Jul 2021 22:46:38 +0000 (23:46 +0100)
The DIT mode support has not been tested due to lack of platform where it
can be tested.
To be able to use the McASP on OMAP4/5 (only supporting DIT mode) we need
to have DIT mode working in the McASP driver on a know platform.
After hacking around (on BBW, mcasp1.axr1 can be routed out for this) it
appeared that DIT mode is broken.

This patch fixes it up and 16/24 bit audio works along with passthrough,
but I have only tested with DTS example and test files.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@gmail.com>
Link: https://lore.kernel.org/r/20210705194249.2385-2-peter.ujfalusi@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/ti/davinci-mcasp.c

index 017a5a5..64ec6d4 100644 (file)
@@ -83,6 +83,8 @@ struct davinci_mcasp {
        struct snd_pcm_substream *substreams[2];
        unsigned int dai_fmt;
 
+       u32 iec958_status;
+
        /* Audio can not be enabled due to missing parameter(s) */
        bool    missing_audio_param;
 
@@ -757,6 +759,9 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+               return 0;
+
        dev_dbg(mcasp->dev,
                 "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
                 __func__, tx_mask, rx_mask, slots, slot_width);
@@ -827,6 +832,20 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
                mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
                               RXROT(7));
                mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
+       } else {
+               /*
+                * according to the TRM it should be TXROT=0, this one works:
+                * 16 bit to 23-8 (TXROT=6, rotate 24 bits)
+                * 24 bit to 23-0 (TXROT=0, rotate 0 bits)
+                *
+                * TXROT = 0 only works with 24bit samples
+                */
+               tx_rotate = (sample_width / 4 + 2) & 0x7;
+
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
+                              TXROT(7));
+               mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(15),
+                              TXSSZ(0x0F));
        }
 
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
@@ -842,10 +861,16 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
        u8 tx_ser = 0;
        u8 rx_ser = 0;
        u8 slots = mcasp->tdm_slots;
-       u8 max_active_serializers = (channels + slots - 1) / slots;
-       u8 max_rx_serializers, max_tx_serializers;
+       u8 max_active_serializers, max_rx_serializers, max_tx_serializers;
        int active_serializers, numevt;
        u32 reg;
+
+       /* In DIT mode we only allow maximum of one serializers for now */
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+               max_active_serializers = 1;
+       else
+               max_active_serializers = (channels + slots - 1) / slots;
+
        /* Default configuration */
        if (mcasp->version < MCASP_VERSION_3)
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
@@ -1031,16 +1056,18 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
 static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
                              unsigned int rate)
 {
-       u32 cs_value = 0;
-       u8 *cs_bytes = (u8*) &cs_value;
+       u8 *cs_bytes = (u8 *)&mcasp->iec958_status;
 
-       /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
-          and LSB first */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
+       if (!mcasp->dat_port)
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
+       else
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
 
        /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
 
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, 0xFFFF);
+
        /* Set the TX tdm : for all the slots */
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
 
@@ -1049,16 +1076,8 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
 
        mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
 
-       /* Only 44100 and 48000 are valid, both have the same setting */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
-
-       /* Enable the DIT */
-       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
-
        /* Set S/PDIF channel status bits */
-       cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
-       cs_bytes[1] = IEC958_AES1_CON_PCM_CODER;
-
+       cs_bytes[3] &= ~IEC958_AES3_CON_FS;
        switch (rate) {
        case 22050:
                cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
@@ -1088,12 +1107,15 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
                cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
                break;
        default:
-               printk(KERN_WARNING "unsupported sampling rate: %d\n", rate);
+               dev_err(mcasp->dev, "unsupported sampling rate: %d\n", rate);
                return -EINVAL;
        }
 
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, mcasp->iec958_status);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, mcasp->iec958_status);
+
+       /* Enable the DIT */
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
 
        return 0;
 }
@@ -1237,12 +1259,18 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                int slots = mcasp->tdm_slots;
                int rate = params_rate(params);
                int sbits = params_width(params);
+               unsigned int bclk_target;
 
                if (mcasp->slot_width)
                        sbits = mcasp->slot_width;
 
+               if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
+                       bclk_target = rate * sbits * slots;
+               else
+                       bclk_target = rate * 128;
+
                davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq,
-                                          rate * sbits * slots, true);
+                                          bclk_target, true);
        }
 
        ret = mcasp_common_hw_param(mcasp, substream->stream,
@@ -1598,6 +1626,77 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
        .set_tdm_slot   = davinci_mcasp_set_tdm_slot,
 };
 
+static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+
+       return 0;
+}
+
+static int davinci_mcasp_iec958_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *uctl)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       memcpy(uctl->value.iec958.status, &mcasp->iec958_status,
+              sizeof(mcasp->iec958_status));
+
+       return 0;
+}
+
+static int davinci_mcasp_iec958_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *uctl)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       memcpy(&mcasp->iec958_status, uctl->value.iec958.status,
+              sizeof(mcasp->iec958_status));
+
+       return 0;
+}
+
+static int davinci_mcasp_iec958_con_mask_get(struct snd_kcontrol *kcontrol,
+                                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       memset(ucontrol->value.iec958.status, 0xff, sizeof(mcasp->iec958_status));
+       return 0;
+}
+
+static const struct snd_kcontrol_new davinci_mcasp_iec958_ctls[] = {
+       {
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+               .info = davinci_mcasp_iec958_info,
+               .get = davinci_mcasp_iec958_get,
+               .put = davinci_mcasp_iec958_put,
+       }, {
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
+               .info = davinci_mcasp_iec958_info,
+               .get = davinci_mcasp_iec958_con_mask_get,
+       },
+};
+
+static void davinci_mcasp_init_iec958_status(struct davinci_mcasp *mcasp)
+{
+       unsigned char *cs = (u8 *)&mcasp->iec958_status;
+
+       cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+       cs[1] = IEC958_AES1_CON_PCM_CODER;
+       cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
+       cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
+}
+
 static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
@@ -1605,6 +1704,12 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
        dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
        dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
 
+       if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
+               davinci_mcasp_init_iec958_status(mcasp);
+               snd_soc_add_dai_controls(dai, davinci_mcasp_iec958_ctls,
+                                        ARRAY_SIZE(davinci_mcasp_iec958_ctls));
+       }
+
        return 0;
 }
 
@@ -1651,7 +1756,8 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
                        .channels_min   = 1,
                        .channels_max   = 384,
                        .rates          = DAVINCI_MCASP_RATES,
-                       .formats        = DAVINCI_MCASP_PCM_FMTS,
+                       .formats        = SNDRV_PCM_FMTBIT_S16_LE |
+                                         SNDRV_PCM_FMTBIT_S24_LE,
                },
                .ops            = &davinci_mcasp_dai_ops,
        },
@@ -1871,6 +1977,8 @@ out:
                } else {
                        mcasp->tdm_slots = pdata->tdm_slots;
                }
+       } else {
+               mcasp->tdm_slots = 32;
        }
 
        mcasp->num_serializer = pdata->num_serializer;