From 7d8632f1ef6c8ed0b53771c16f130f18d636931e Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 1 Mar 2026 18:05:23 +1000 Subject: ASoC: soc-dai: define possible idle TDM slot modes Some audio devices, such as certain Texas Instruments codecs, include configurable bus keepers. We currently don't have a standardised way to configure such hardware, and instead rely on the hardware initialising setting itself up into a sane state. There are situations where this is insufficient, however, and some platforms require more concrete guarantees as to the state of the bus, and being able to explicitly configure bus keepers enables this. For example, some Apple Silicon machines have an odd bus topology where the SDOUT pins of all codecs are split across two data lines, which are summed via an OR gate in front of the receiving port on the SoC's I2S peripheral. Each line must transmit 0 while a codec on the other line is actively transmitting data, or the SoC will receive garbage data. To do this, one codec on each line must be configured to transmit zeroes during the other line's active TDM slots. Thus, we define seven possible bus-keeping modes that a device can be in: NONE (UB/as initialised), OFF (explicitly disabled), ZERO (actively transmit a 0), PULLDOWN, HIZ (floating), PULLUP, and DRIVE_HIGH. These will be consumed by CODEC/CPU drivers via a common DAI op, enabling the explicit configuration of bus keepers where required. Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260301-tdm-idle-slots-v3-4-c6ac5351489a@gmail.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 224396927aef..44dd06add52e 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -52,6 +52,21 @@ struct snd_compr_stream; #define SND_SOC_POSSIBLE_DAIFMT_AC97 (1 << SND_SOC_DAI_FORMAT_AC97) #define SND_SOC_POSSIBLE_DAIFMT_PDM (1 << SND_SOC_DAI_FORMAT_PDM) +/* + * DAI TDM slot idle modes + * + * Describes a CODEC/CPU's behaviour when not actively receiving or + * transmitting on a given TDM slot. NONE is undefined behaviour. + * Add new modes to the end. + */ +#define SND_SOC_DAI_TDM_IDLE_NONE 0 +#define SND_SOC_DAI_TDM_IDLE_OFF 1 +#define SND_SOC_DAI_TDM_IDLE_ZERO 2 +#define SND_SOC_DAI_TDM_IDLE_PULLDOWN 3 +#define SND_SOC_DAI_TDM_IDLE_HIZ 4 +#define SND_SOC_DAI_TDM_IDLE_PULLUP 5 +#define SND_SOC_DAI_TDM_IDLE_DRIVE_HIGH 6 + /* * DAI Clock gating. * -- cgit v1.2.3 From b758d3574e88537f9089bd757a51b35cf9675179 Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sun, 1 Mar 2026 18:05:24 +1000 Subject: ASoC: soc-dai: add common operation to set TDM idle mode Some audio devices, like certain Texas Instruments codecs, integrate configurable bus keepers that dictate the codec's behaviour during idle TDM slots. Now that we have definitions for various idle modes, add a snd_soc_dai_set_tdm_idle() operation to control this in a standardised way. This is useful on Apple Silicon laptops, where a single I2S bus is comprised of two physical lines which are ORed just before the receiving port. When a codec on one line is transmitting, we must guarantee that the other line is low. We can achieve this by configuring one codec on each line to use its bus keeper to fill its line with zeroes during the active slots of the other line. Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260301-tdm-idle-slots-v3-5-c6ac5351489a@gmail.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 44dd06add52e..6a42812bba8c 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -196,6 +196,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); +int snd_soc_dai_set_tdm_idle(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int tx_mode, int rx_mode); + int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, const unsigned int *tx_slot, unsigned int rx_num, const unsigned int *rx_slot); @@ -312,6 +316,9 @@ struct snd_soc_dai_ops { int (*set_tdm_slot)(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); + int (*set_tdm_idle)(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int tx_mode, int rx_mode); int (*set_channel_map)(struct snd_soc_dai *dai, unsigned int tx_num, const unsigned int *tx_slot, unsigned int rx_num, const unsigned int *rx_slot); -- cgit v1.2.3