Skip to content

Commit

Permalink
ASoC: apple: mca: Fix SERDES reset sequence
Browse files Browse the repository at this point in the history
Fix the reset sequence of reads and writes that we invoke from within
the early trigger. It looks like there never was a SERDES_CONF_SOME_RST
bit that should be involved in the reset sequence, and its presence in
the driver code is a mistake from earlier.

Instead, the reset sequence should go as follows: We should switch the
the SERDES unit's SYNC_SEL mux to the value of 7 (so outside the range
of 1...6 representing cluster's SYNCGEN units), then raise the RST bit
in SERDES_STATUS and wait for it to clear.

Properly resetting the SERDES unit fixes frame desynchronization hazard
in case of long frames (longer than 4 used slots). The desynchronization
manifests itself by rotating the PCM channels.

Fixes: 3df5d0d ("ASoC: apple: mca: Start new platform driver")
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Link: https://lore.kernel.org/r/20230224153302.45365-2-povik+lin@cutebit.org
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Martin Povišer authored and Mark Brown committed Feb 24, 2023
1 parent aaf5f0d commit d8b3e39
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions sound/soc/apple/mca.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@
#define SERDES_CONF_UNK3 BIT(14)
#define SERDES_CONF_NO_DATA_FEEDBACK BIT(15)
#define SERDES_CONF_SYNC_SEL GENMASK(18, 16)
#define SERDES_CONF_SOME_RST BIT(19)
#define REG_TX_SERDES_BITSTART 0x08
#define REG_RX_SERDES_BITSTART 0x0c
#define REG_TX_SERDES_SLOTMASK 0x0c
Expand Down Expand Up @@ -203,15 +202,24 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, 7));
mca_modify(cl, serdes_unit + REG_SERDES_STATUS,
SERDES_STATUS_EN | SERDES_STATUS_RST,
SERDES_STATUS_RST);
mca_modify(cl, serdes_conf, SERDES_CONF_SOME_RST,
SERDES_CONF_SOME_RST);
readl_relaxed(cl->base + serdes_conf);
mca_modify(cl, serdes_conf, SERDES_STATUS_RST, 0);
/*
* Experiments suggest that it takes at most ~1 us
* for the bit to clear, so wait 2 us for good measure.
*/
udelay(2);
WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) &
SERDES_STATUS_RST);
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1));
break;
default:
break;
Expand Down

0 comments on commit d8b3e39

Please sign in to comment.