]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.19.35/asoc-fsl_esai-fix-channel-swap-issue-when-stream-starts.patch
Linux 4.14.112
[thirdparty/kernel/stable-queue.git] / releases / 4.19.35 / asoc-fsl_esai-fix-channel-swap-issue-when-stream-starts.patch
1 From 0ff4e8c61b794a4bf6c854ab071a1abaaa80f358 Mon Sep 17 00:00:00 2001
2 From: "S.j. Wang" <shengjiu.wang@nxp.com>
3 Date: Wed, 27 Feb 2019 06:31:12 +0000
4 Subject: ASoC: fsl_esai: fix channel swap issue when stream starts
5
6 From: S.j. Wang <shengjiu.wang@nxp.com>
7
8 commit 0ff4e8c61b794a4bf6c854ab071a1abaaa80f358 upstream.
9
10 There is very low possibility ( < 0.1% ) that channel swap happened
11 in beginning when multi output/input pin is enabled. The issue is
12 that hardware can't send data to correct pin in the beginning with
13 the normal enable flow.
14
15 This is hardware issue, but there is no errata, the workaround flow
16 is that: Each time playback/recording, firstly clear the xSMA/xSMB,
17 then enable TE/RE, then enable xSMB and xSMA (xSMB must be enabled
18 before xSMA). Which is to use the xSMA as the trigger start register,
19 previously the xCR_TE or xCR_RE is the bit for starting.
20
21 Fixes commit 43d24e76b698 ("ASoC: fsl_esai: Add ESAI CPU DAI driver")
22 Cc: <stable@vger.kernel.org>
23 Reviewed-by: Fabio Estevam <festevam@gmail.com>
24 Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
25 Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
26 Signed-off-by: Mark Brown <broonie@kernel.org>
27 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
28
29 ---
30 sound/soc/fsl/fsl_esai.c | 47 +++++++++++++++++++++++++++++++++++++----------
31 1 file changed, 37 insertions(+), 10 deletions(-)
32
33 --- a/sound/soc/fsl/fsl_esai.c
34 +++ b/sound/soc/fsl/fsl_esai.c
35 @@ -54,6 +54,8 @@ struct fsl_esai {
36 u32 fifo_depth;
37 u32 slot_width;
38 u32 slots;
39 + u32 tx_mask;
40 + u32 rx_mask;
41 u32 hck_rate[2];
42 u32 sck_rate[2];
43 bool hck_dir[2];
44 @@ -361,21 +363,13 @@ static int fsl_esai_set_dai_tdm_slot(str
45 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
46 ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
47
48 - regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
49 - ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
50 - regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
51 - ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask));
52 -
53 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
54 ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
55
56 - regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
57 - ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
58 - regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
59 - ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
60 -
61 esai_priv->slot_width = slot_width;
62 esai_priv->slots = slots;
63 + esai_priv->tx_mask = tx_mask;
64 + esai_priv->rx_mask = rx_mask;
65
66 return 0;
67 }
68 @@ -596,6 +590,7 @@ static int fsl_esai_trigger(struct snd_p
69 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
70 u8 i, channels = substream->runtime->channels;
71 u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
72 + u32 mask;
73
74 switch (cmd) {
75 case SNDRV_PCM_TRIGGER_START:
76 @@ -608,15 +603,38 @@ static int fsl_esai_trigger(struct snd_p
77 for (i = 0; tx && i < channels; i++)
78 regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
79
80 + /*
81 + * When set the TE/RE in the end of enablement flow, there
82 + * will be channel swap issue for multi data line case.
83 + * In order to workaround this issue, we switch the bit
84 + * enablement sequence to below sequence
85 + * 1) clear the xSMB & xSMA: which is done in probe and
86 + * stop state.
87 + * 2) set TE/RE
88 + * 3) set xSMB
89 + * 4) set xSMA: xSMA is the last one in this flow, which
90 + * will trigger esai to start.
91 + */
92 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
93 tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
94 tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins));
95 + mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask;
96 +
97 + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx),
98 + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask));
99 + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx),
100 + ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask));
101 +
102 break;
103 case SNDRV_PCM_TRIGGER_SUSPEND:
104 case SNDRV_PCM_TRIGGER_STOP:
105 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
106 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
107 tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
108 + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx),
109 + ESAI_xSMA_xS_MASK, 0);
110 + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx),
111 + ESAI_xSMB_xS_MASK, 0);
112
113 /* Disable and reset FIFO */
114 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
115 @@ -906,6 +924,15 @@ static int fsl_esai_probe(struct platfor
116 return ret;
117 }
118
119 + esai_priv->tx_mask = 0xFFFFFFFF;
120 + esai_priv->rx_mask = 0xFFFFFFFF;
121 +
122 + /* Clear the TSMA, TSMB, RSMA, RSMB */
123 + regmap_write(esai_priv->regmap, REG_ESAI_TSMA, 0);
124 + regmap_write(esai_priv->regmap, REG_ESAI_TSMB, 0);
125 + regmap_write(esai_priv->regmap, REG_ESAI_RSMA, 0);
126 + regmap_write(esai_priv->regmap, REG_ESAI_RSMB, 0);
127 +
128 ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component,
129 &fsl_esai_dai, 1);
130 if (ret) {