mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
ASoC: apple: mca: Fix SERDES reset sequence
[ Upstream commitd8b3e39608] 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:3df5d0d972("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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
c664c38355
commit
0c398c1c19
@@ -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
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user