Skip to content

Commit d470279

Browse files
marcanjannau
authored andcommitted
ASoC: tas2770: Support setting the PDM TX slot
We don't actually support configuring the PDM input right now. Rather, this is useful as a hack. On Apple Silicon machines, amps are split between two I2S buses which are logically ANDed internally at the SoC. Odd and even slot groups are driven by amps on either bus respectively. Since the signals are ANDed, unused slot groups must be driven as zero to avoid corrupting the data from the other side. On most recent machines (TAS2764-based), this is accomplished using the "SDOUT zero mask" feature of that chip. Unfortunately, TAS2770 does not support this. It does support zeroing out *all* unused slots, which works well for machines with a single amp per I2S bus. That is all, except one. The 13" M1 MacBook Pro is the only machine using TAS2764 and two amps per I2S bus: L Bus: SPK0I SPK0V Hi-Z Hi-Z SPK2I SPK2V Hi-Z Hi-Z R Bus: Hi-Z Hi-Z SPK1I SPK2V Hi-Z Hi-Z SPK3I SPK3V To ensure uncorrupted data, we need to force all the Hi-Z periods to zero. We cannot use the "force all zero" feature, as that would cause a bus conflict between both amps. We can use the pull-down feature, but that leaves a few bits of garbage on the trailing edge of the speaker data, since the pull-down is weak. This is where the PDM transmit feature comes in. With PDM grounded and disabled (the default state), the PDM slot is transmitted as all zeroes. We can use that to force a zero 16-bit slot after the voltage data for each speaker, cleaning it up. Then the pull-down ensures the line stays low for the subsequent slot: L Bus: SPK0I SPK0V PDM0 PulDn SPK2I SPK2V PDM0 PulDn R Bus: PDM0 PulDn SPK1I SPK2V PDM0 PulDn SPK3I SPK3V Yes, this is a horrible hack, but it beats adding dummy slots that would be visible to the userspace capture side. There may be some other way to fix the logical AND behavior on the MCA side... that would make this unnecessary. ("How does Apple deal with this"? - they don't, macOS does not use IVSENSE on TAS2764 machines even though it's physically wired up, but we want to do so on Linux.) Signed-off-by: Hector Martin <marcan@marcan.st>
1 parent 6d6a7c8 commit d470279

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

sound/soc/codecs/tas2770.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,19 @@ static int tas2770_set_ivsense_transmit(struct tas2770_priv *tas2770,
251251
return 0;
252252
}
253253

254+
static int tas2770_set_pdm_transmit(struct tas2770_priv *tas2770, int slot)
255+
{
256+
struct snd_soc_component *component = tas2770->component;
257+
int ret;
258+
259+
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG7,
260+
TAS2770_TDM_CFG_REG7_PDM_MASK |
261+
TAS2770_TDM_CFG_REG7_50_MASK,
262+
TAS2770_TDM_CFG_REG7_PDM_ENABLE |
263+
slot);
264+
return ret;
265+
}
266+
254267
static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)
255268
{
256269
int ret;
@@ -602,6 +615,13 @@ static int tas2770_codec_probe(struct snd_soc_component *component)
602615
return ret;
603616
}
604617

618+
if (tas2770->pdm_slot != -1) {
619+
ret = tas2770_set_pdm_transmit(tas2770, tas2770->pdm_slot);
620+
621+
if (ret < 0)
622+
return ret;
623+
}
624+
605625
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG4,
606626
TAS2770_TDM_CFG_REG4_TX_FILL,
607627
tas2770->sdout_zfill ? 0 :
@@ -769,6 +789,12 @@ static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770)
769789
tas2770->v_sense_slot = -1;
770790
}
771791

792+
rc = fwnode_property_read_u32(dev->fwnode, "ti,pdm-slot-no",
793+
&tas2770->pdm_slot);
794+
if (rc) {
795+
tas2770->pdm_slot = -1;
796+
}
797+
772798
tas2770->sdout_pd = fwnode_property_read_bool(dev->fwnode, "ti,sdout-pull-down");
773799
tas2770->sdout_zfill = fwnode_property_read_bool(dev->fwnode, "ti,sdout-zero-fill");
774800

sound/soc/codecs/tas2770.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@
8585
#define TAS2770_TDM_CFG_REG6_ISNS_MASK BIT(6)
8686
#define TAS2770_TDM_CFG_REG6_ISNS_ENABLE BIT(6)
8787
#define TAS2770_TDM_CFG_REG6_50_MASK GENMASK(5, 0)
88+
/* TDM Configuration Reg10 */
89+
#define TAS2770_TDM_CFG_REG7 TAS2770_REG(0X0, 0x11)
90+
#define TAS2770_TDM_CFG_REG7_PDM_MASK BIT(6)
91+
#define TAS2770_TDM_CFG_REG7_PDM_ENABLE BIT(6)
92+
#define TAS2770_TDM_CFG_REG7_50_MASK GENMASK(5, 0)
8893
/* Brown Out Prevention Reg0 */
8994
#define TAS2770_BO_PRV_REG0 TAS2770_REG(0X0, 0x1B)
9095
/* Interrupt MASK Reg0 */
@@ -150,6 +155,7 @@ struct tas2770_priv {
150155
struct device *dev;
151156
int v_sense_slot;
152157
int i_sense_slot;
158+
int pdm_slot;
153159
bool sdout_pd;
154160
bool sdout_zfill;
155161
bool dac_powered;

0 commit comments

Comments
 (0)