bool dac_powered;
bool unmuted;
+
+ struct {
+ int tx_mode;
+ unsigned int tx_mask;
+ } idle_slot_config;
};
#include "tas2764-quirks.h"
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,
};
#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__ */