summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Calligeros <jcalligeros99@gmail.com>2026-03-01 11:05:25 +0300
committerMark Brown <broonie@kernel.org>2026-03-16 04:13:04 +0300
commit45573ee1f2badd1886eb6f4a736e60e3f76effe6 (patch)
tree4acfff8360e7d231fe1a3ef1bb3683bc66c3b2e9
parentb758d3574e88537f9089bd757a51b35cf9675179 (diff)
downloadlinux-45573ee1f2badd1886eb6f4a736e60e3f76effe6.tar.xz
ASoC: tas2764: expose SDOUT bus keeper via set_tdm_idle operation
TAS2764, and the Apple-exclusive variant SN012776, include bus keepers on the SDOUT pin that can be configured to alter the behaviour of the SDOUT pin during specified TDM slots. The chip can either leave the bus floating (default/uninitialised behaviour) or fill the specified slots with zeroes. Expose the SDOUT bus keeper and allow it to be configured using the set_tdm_idle DAI op. The mask must be cropped to only cover slots valid for the configured BCLK ratio, so introduce a set_bclk_ratio op that properly configures this. Signed-off-by: James Calligeros <jcalligeros99@gmail.com> Link: https://patch.msgid.link/20260301-tdm-idle-slots-v3-6-c6ac5351489a@gmail.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/tas2764.c95
-rw-r--r--sound/soc/codecs/tas2764.h11
2 files changed, 106 insertions, 0 deletions
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 36e25e48b354..423b7073b302 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -44,6 +44,11 @@ struct tas2764_priv {
bool dac_powered;
bool unmuted;
+
+ struct {
+ int tx_mode;
+ unsigned int tx_mask;
+ } idle_slot_config;
};
#include "tas2764-quirks.h"
@@ -509,11 +514,101 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
+static int tas2764_write_sdout_idle_mask(struct tas2764_priv *tas2764, u32 mask)
+{
+ struct snd_soc_component *component = tas2764->component;
+ int i, ret;
+
+ /* Hardware supports up to 64 slots, but we don't */
+ for (i = 0; i < 4; i++) {
+ ret = snd_soc_component_write(component,
+ TAS2764_SDOUT_HIZ_1 + i,
+ (mask >> (i * 8)) & 0xff);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tas2764_set_dai_tdm_idle(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int tx_mode, int rx_mode)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ /* We don't support setting anything on SDIN */
+ if (rx_mode)
+ return -EOPNOTSUPP;
+
+ if (tas2764->idle_slot_config.tx_mask == tx_mask &&
+ tas2764->idle_slot_config.tx_mode == tx_mode)
+ return 0;
+
+ switch (tx_mode) {
+ case SND_SOC_DAI_TDM_IDLE_ZERO:
+ if (!tx_mask)
+ return -EINVAL;
+
+ ret = tas2764_write_sdout_idle_mask(tas2764, tx_mask);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component,
+ TAS2764_SDOUT_HIZ_9,
+ TAS2764_SDOUT_HIZ_9_FORCE_0_EN,
+ TAS2764_SDOUT_HIZ_9_FORCE_0_EN);
+ if (ret < 0)
+ return ret;
+
+ tas2764->idle_slot_config.tx_mask = tx_mask;
+ tas2764->idle_slot_config.tx_mode = tx_mode;
+ break;
+ case SND_SOC_DAI_TDM_IDLE_HIZ:
+ case SND_SOC_DAI_TDM_IDLE_OFF:
+ /* HiZ mode does not support a slot mask */
+ ret = tas2764_write_sdout_idle_mask(tas2764, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component,
+ TAS2764_SDOUT_HIZ_9,
+ TAS2764_SDOUT_HIZ_9_FORCE_0_EN, 0);
+ if (ret < 0)
+ return ret;
+
+ tas2764->idle_slot_config.tx_mask = 0;
+ tas2764->idle_slot_config.tx_mode = tx_mode;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+/* The SDOUT idle slot mask must be cropped based on the BCLK ratio */
+static int tas2764_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(dai->component);
+
+ if (!tas2764->idle_slot_config.tx_mask)
+ return 0;
+
+ tas2764->idle_slot_config.tx_mask &= GENMASK((ratio / 8) - 1, 0);
+
+ return tas2764_write_sdout_idle_mask(tas2764, tas2764->idle_slot_config.tx_mask);
+}
+
static const struct snd_soc_dai_ops tas2764_dai_ops = {
.mute_stream = tas2764_mute,
.hw_params = tas2764_hw_params,
.set_fmt = tas2764_set_fmt,
+ .set_bclk_ratio = tas2764_set_bclk_ratio,
.set_tdm_slot = tas2764_set_dai_tdm_slot,
+ .set_tdm_idle = tas2764_set_dai_tdm_idle,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h
index 538290ed3d92..4494bc4889dc 100644
--- a/sound/soc/codecs/tas2764.h
+++ b/sound/soc/codecs/tas2764.h
@@ -126,4 +126,15 @@
#define TAS2764_BOP_CFG0 TAS2764_REG(0X0, 0x1d)
+#define TAS2764_SDOUT_HIZ_1 TAS2764_REG(0x1, 0x3d)
+#define TAS2764_SDOUT_HIZ_2 TAS2764_REG(0x1, 0x3e)
+#define TAS2764_SDOUT_HIZ_3 TAS2764_REG(0x1, 0x3f)
+#define TAS2764_SDOUT_HIZ_4 TAS2764_REG(0x1, 0x40)
+#define TAS2764_SDOUT_HIZ_5 TAS2764_REG(0x1, 0x41)
+#define TAS2764_SDOUT_HIZ_6 TAS2764_REG(0x1, 0x42)
+#define TAS2764_SDOUT_HIZ_7 TAS2764_REG(0x1, 0x43)
+#define TAS2764_SDOUT_HIZ_8 TAS2764_REG(0x1, 0x44)
+#define TAS2764_SDOUT_HIZ_9 TAS2764_REG(0x1, 0x45)
+#define TAS2764_SDOUT_HIZ_9_FORCE_0_EN BIT(7)
+
#endif /* __TAS2764__ */