summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/fsl/fsl_ssi.c52
1 files changed, 46 insertions, 6 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 939d1b8894dc..20ef09e1a395 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -577,8 +577,54 @@ static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable)
fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx);
}
+static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi_private *ssi_private)
+{
+ struct regmap *regs = ssi_private->regs;
+
+ /* no SACC{ST,EN,DIS} regs on imx21-class SSI */
+ if (!ssi_private->soc->imx21regs) {
+ /*
+ * Note that these below aren't just normal registers.
+ * They are a way to disable or enable bits in SACCST
+ * register:
+ * - writing a '1' bit at some position in SACCEN sets the
+ * relevant bit in SACCST,
+ * - writing a '1' bit at some position in SACCDIS unsets
+ * the relevant bit in SACCST register.
+ *
+ * The two writes below first disable all channels slots,
+ * then enable just slots 3 & 4 ("PCM Playback Left Channel"
+ * and "PCM Playback Right Channel").
+ */
+ regmap_write(regs, CCSR_SSI_SACCDIS, 0xff);
+ regmap_write(regs, CCSR_SSI_SACCEN, 0x300);
+ }
+}
+
static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable)
{
+ /*
+ * Why are we setting up SACCST everytime we are starting a
+ * playback?
+ * Some CODECs (like VT1613 CODEC on UDOO board) like to
+ * (sometimes) set extra bits in their SLOTREQ requests.
+ * When a bit is set in a SLOTREQ request then SSI sets the
+ * relevant bit in SACCST automatically (it is enough if a bit was
+ * set in a SLOTREQ just once, bits in SACCST are 'sticky').
+ * If an extra slot gets enabled that's a disaster for playback
+ * because some of normal left or right channel samples are
+ * redirected instead to this extra slot.
+ *
+ * A workaround implemented in fsl-asoc-card of setting an
+ * appropriate CODEC register so that slots 3 & 4 (the normal
+ * stereo playback slots) are used for S/PDIF seems to mostly fix
+ * this issue on the UDOO board but since this CODEC is so
+ * untrustworthy let's play safe here and make sure that no extra
+ * slots are enabled every time a playback is started.
+ */
+ if (enable && fsl_ssi_is_ac97(ssi_private))
+ fsl_ssi_tx_ac97_saccst_setup(ssi_private);
+
fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx);
}
@@ -633,12 +679,6 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
regmap_write(regs, CCSR_SSI_SACNT,
CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV);
- /* no SACC{ST,EN,DIS} regs on imx21-class SSI */
- if (!ssi_private->soc->imx21regs) {
- regmap_write(regs, CCSR_SSI_SACCDIS, 0xff);
- regmap_write(regs, CCSR_SSI_SACCEN, 0x300);
- }
-
/*
* Enable SSI, Transmit and Receive. AC97 has to communicate with the
* codec before a stream is started.