]> www.infradead.org Git - users/hch/misc.git/commitdiff
ASoC: fsl: fsl_qmc_audio: Ensure audio channels are ordered in TDM bus
authorChristophe Leroy <christophe.leroy@csgroup.eu>
Thu, 18 Sep 2025 15:34:09 +0000 (17:34 +0200)
committerMark Brown <broonie@kernel.org>
Thu, 18 Sep 2025 21:50:46 +0000 (22:50 +0100)
To reduce complexity of interrupt handling in following patch, ensure
audio channels are configured in the same order as timeslots on the
TDM bus. If we need a given ordering of audio sources in the audio
frame, it is possible to re-order codecs on the TDM bus, no need to
mix up timeslots in channels.

Acked-by: Herve Codina <herve.codina@bootlin.com>
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Link: https://patch.msgid.link/4ff40afdf3d032b05dd4af6c0f777d4d4b445a76.1758209158.git.christophe.leroy@csgroup.eu
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/fsl/fsl_qmc_audio.c

index 5614a8b909edf8d4b7857b9c4f8841fab7ec9635..c0c7ef0a151190e0fe80e476c005c4ae66a5f964 100644 (file)
@@ -791,12 +791,17 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
                               struct qmc_dai *qmc_dai,
                               struct snd_soc_dai_driver *qmc_soc_dai_driver)
 {
+       struct qmc_chan_ts_info ts_info;
        struct qmc_chan_info info;
        unsigned long rx_fs_rate;
        unsigned long tx_fs_rate;
+       int prev_last_rx_ts = 0;
+       int prev_last_tx_ts = 0;
        unsigned int nb_tx_ts;
        unsigned int nb_rx_ts;
        unsigned int i;
+       int last_rx_ts;
+       int last_tx_ts;
        int count;
        u32 val;
        int ret;
@@ -879,6 +884,30 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
                                return -EINVAL;
                        }
                }
+
+               ret = qmc_chan_get_ts_info(qmc_dai->chans[i].qmc_chan, &ts_info);
+               if (ret) {
+                       dev_err(qmc_audio->dev, "dai %d get QMC %d channel TS info failed %d\n",
+                               qmc_dai->id, i, ret);
+                       return ret;
+               }
+
+               last_rx_ts = fls64(ts_info.rx_ts_mask);
+               last_tx_ts = fls64(ts_info.tx_ts_mask);
+
+               if (prev_last_rx_ts > last_rx_ts) {
+                       dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %d before %d)\n",
+                               qmc_dai->id, i, prev_last_rx_ts, last_rx_ts);
+                       return -EINVAL;
+               }
+               if (prev_last_tx_ts > last_tx_ts) {
+                       dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (TX timeslot %d before %d)\n",
+                               qmc_dai->id, i, prev_last_tx_ts, last_tx_ts);
+                       return -EINVAL;
+               }
+
+               prev_last_rx_ts = last_rx_ts;
+               prev_last_tx_ts = last_tx_ts;
        }
 
        qmc_dai->nb_chans_avail = count;