Skip to content

Commit b6b5bba

Browse files
committed
ASoC: renesas: msiof: tidyup to remove each errors
Merge series from Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>: Current Renesas MSIOF driver might get some errors. This patch-set try to reduce/remove them.
2 parents 27fa1a8 + e26387e commit b6b5bba

1 file changed

Lines changed: 131 additions & 30 deletions

File tree

sound/soc/renesas/rcar/msiof.c

Lines changed: 131 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//
88

99
/*
10-
* [NOTE]
10+
* [NOTE-CLOCK-MODE]
1111
*
1212
* This driver doesn't support Clock/Frame Provider Mode
1313
*
@@ -24,12 +24,64 @@
2424
* Clock/Frame Consumer Mode.
2525
*/
2626

27+
/*
28+
* [NOTE-RESET]
29+
*
30+
* MSIOF has TXRST/RXRST to reset FIFO, but it shouldn't be used during SYNC signal was asserted,
31+
* because it will be cause of HW issue.
32+
*
33+
* When MSIOF is used as Sound driver, this driver is assuming it is used as clock consumer mode
34+
* (= Codec is clock provider). This means, it can't control SYNC signal by itself.
35+
*
36+
* We need to use SW reset (= reset_control_xxx()) instead of TXRST/RXRST.
37+
*/
38+
39+
/*
40+
* [NOTE-BOTH-SETTING]
41+
*
42+
* SITMDRn / SIRMDRn and some other registers should not be updated during working even though it
43+
* was not related the target direction (for example, do TX settings during RX is working),
44+
* otherwise it cause a FSERR.
45+
*
46+
* Setup both direction (Playback/Capture) in the same time.
47+
*/
48+
49+
/*
50+
* [NOTE-R/L]
51+
*
52+
* The data of Captured might be R/L opposite.
53+
*
54+
* This driver is assuming MSIOF is used as Clock/Frame Consumer Mode, and there is a case that some
55+
* Codec (= Clock/Frame Provider) might output Clock/Frame before setup MSIOF. It depends on Codec
56+
* driver implementation.
57+
*
58+
* MSIOF will capture data without checking SYNC signal Hi/Low (= R/L).
59+
*
60+
* This means, if MSIOF RXE bit was set as 1 in case of SYNC signal was Hi (= R) timing, it will
61+
* start capture data since next SYNC low singla (= L). Because Linux assumes sound data is lined
62+
* up as R->L->R->L->..., the data R/L will be opposite.
63+
*
64+
* The only solution in this case is start CLK/SYNC *after* MSIOF settings, but it depends when and
65+
* how Codec driver start it.
66+
*/
67+
68+
/*
69+
* [NOTE-FSERR]
70+
*
71+
* We can't remove all FSERR.
72+
*
73+
* Renesas have tried to minimize the occurrence of FSERR errors as much as possible, but
74+
* unfortunately we cannot remove them completely, because MSIOF might setup its register during
75+
* CLK/SYNC are inputed. It can be happen because MSIOF is working as Clock/Frame Consumer.
76+
*/
77+
2778
#include <linux/module.h>
2879
#include <linux/of.h>
2980
#include <linux/of_dma.h>
3081
#include <linux/of_graph.h>
3182
#include <linux/platform_device.h>
3283
#include <linux/pm_runtime.h>
84+
#include <linux/reset.h>
3385
#include <linux/spi/sh_msiof.h>
3486
#include <sound/dmaengine_pcm.h>
3587
#include <sound/soc.h>
@@ -60,10 +112,13 @@
60112
struct msiof_priv {
61113
struct device *dev;
62114
struct snd_pcm_substream *substream[SNDRV_PCM_STREAM_LAST + 1];
115+
struct reset_control *reset;
63116
spinlock_t lock;
64117
void __iomem *base;
65118
resource_size_t phy_addr;
66119

120+
int count;
121+
67122
/* for error */
68123
int err_syc[SNDRV_PCM_STREAM_LAST + 1];
69124
int err_ovf[SNDRV_PCM_STREAM_LAST + 1];
@@ -121,7 +176,7 @@ static int msiof_hw_start(struct snd_soc_component *component,
121176

122177
/*
123178
* see
124-
* [NOTE] on top of this driver
179+
* [NOTE-CLOCK-MODE] on top of this driver
125180
*/
126181
/*
127182
* see
@@ -131,42 +186,63 @@ static int msiof_hw_start(struct snd_soc_component *component,
131186
* RX: Fig 109.15
132187
*/
133188

134-
/* reset errors */
135-
priv->err_syc[substream->stream] =
189+
/*
190+
* Use reset_control_xx() instead of TXRST/RXRST.
191+
* see
192+
* [NOTE-RESET]
193+
*/
194+
if (!priv->count)
195+
reset_control_deassert(priv->reset);
196+
197+
priv->count++;
198+
199+
/*
200+
* Reset errors. ignore 1st FSERR
201+
*
202+
* see
203+
* [NOTE-FSERR]
204+
*/
205+
priv->err_syc[substream->stream] = -1;
136206
priv->err_ovf[substream->stream] =
137207
priv->err_udf[substream->stream] = 0;
138208

139209
/* Start DMAC */
140210
snd_dmaengine_pcm_trigger(substream, cmd);
141211

212+
/*
213+
* setup both direction (Playback/Capture) in the same time.
214+
* see
215+
* above [NOTE-BOTH-SETTING]
216+
*/
217+
142218
/* SITMDRx */
143-
if (is_play) {
144-
val = SITMDR1_PCON |
145-
FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR) |
146-
SIMDR1_SYNCAC | SIMDR1_XXSTP;
147-
if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
148-
val |= FIELD_PREP(SIMDR1_DTDL, 1);
219+
val = SITMDR1_PCON | SIMDR1_SYNCAC | SIMDR1_XXSTP |
220+
FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR);
221+
if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
222+
val |= FIELD_PREP(SIMDR1_DTDL, 1);
149223

150-
msiof_write(priv, SITMDR1, val);
224+
msiof_write(priv, SITMDR1, val);
151225

152-
val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
153-
msiof_write(priv, SITMDR2, val | FIELD_PREP(SIMDR2_GRP, 1));
154-
msiof_write(priv, SITMDR3, val);
226+
val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
227+
msiof_write(priv, SITMDR2, val | FIELD_PREP(SIMDR2_GRP, 1));
228+
msiof_write(priv, SITMDR3, val);
155229

156-
}
157230
/* SIRMDRx */
158-
else {
159-
val = FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR) |
160-
SIMDR1_SYNCAC;
161-
if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
162-
val |= FIELD_PREP(SIMDR1_DTDL, 1);
231+
val = SIMDR1_SYNCAC |
232+
FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR);
233+
if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
234+
val |= FIELD_PREP(SIMDR1_DTDL, 1);
163235

164-
msiof_write(priv, SIRMDR1, val);
236+
msiof_write(priv, SIRMDR1, val);
165237

166-
val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
167-
msiof_write(priv, SIRMDR2, val | FIELD_PREP(SIMDR2_GRP, 1));
168-
msiof_write(priv, SIRMDR3, val);
169-
}
238+
val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
239+
msiof_write(priv, SIRMDR2, val | FIELD_PREP(SIMDR2_GRP, 1));
240+
msiof_write(priv, SIRMDR3, val);
241+
242+
/* SIFCTR */
243+
msiof_write(priv, SIFCTR,
244+
FIELD_PREP(SIFCTR_TFWM, SIFCTR_TFWM_1) |
245+
FIELD_PREP(SIFCTR_RFWM, SIFCTR_RFWM_1));
170246

171247
/* SIIER */
172248
if (is_play)
@@ -183,10 +259,11 @@ static int msiof_hw_start(struct snd_soc_component *component,
183259
msiof_update(priv, SISTR, val, val);
184260

185261
/* SICTR */
262+
val = SICTR_TEDG | SICTR_REDG;
186263
if (is_play)
187-
val = SICTR_TXE | SICTR_TEDG;
264+
val |= SICTR_TXE;
188265
else
189-
val = SICTR_RXE | SICTR_REDG;
266+
val |= SICTR_RXE;
190267
msiof_update_and_wait(priv, SICTR, val, val, val);
191268

192269
return 0;
@@ -207,16 +284,25 @@ static int msiof_hw_stop(struct snd_soc_component *component,
207284
val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX;
208285
msiof_update(priv, SIIER, val, 0);
209286

210-
/* Stop DMAC */
211-
snd_dmaengine_pcm_trigger(substream, cmd);
212-
213287
/* SICTR */
214288
if (is_play)
215289
val = SICTR_TXE;
216290
else
217291
val = SICTR_RXE;
218292
msiof_update_and_wait(priv, SICTR, val, 0, 0);
219293

294+
/* Stop DMAC */
295+
snd_dmaengine_pcm_trigger(substream, cmd);
296+
297+
/*
298+
* Ignore 1st FSERR
299+
*
300+
* see
301+
* [NOTE-FSERR]
302+
*/
303+
if (priv->err_syc[substream->stream] < 0)
304+
priv->err_syc[substream->stream] = 0;
305+
220306
/* indicate error status if exist */
221307
if (priv->err_syc[substream->stream] ||
222308
priv->err_ovf[substream->stream] ||
@@ -227,6 +313,11 @@ static int msiof_hw_stop(struct snd_soc_component *component,
227313
priv->err_ovf[substream->stream],
228314
priv->err_udf[substream->stream]);
229315

316+
priv->count--;
317+
318+
if (!priv->count)
319+
reset_control_assert(priv->reset);
320+
230321
return 0;
231322
}
232323

@@ -302,6 +393,9 @@ static struct snd_soc_dai_driver msiof_dai_driver = {
302393
.channels_max = 2,
303394
},
304395
.ops = &msiof_dai_ops,
396+
.symmetric_rate = 1,
397+
.symmetric_channels = 1,
398+
.symmetric_sample_bits = 1,
305399
};
306400

307401
static struct snd_pcm_hardware msiof_pcm_hardware = {
@@ -490,12 +584,19 @@ static int msiof_probe(struct platform_device *pdev)
490584
if (IS_ERR(priv->base))
491585
return PTR_ERR(priv->base);
492586

587+
priv->reset = devm_reset_control_get_exclusive(dev, NULL);
588+
if (IS_ERR(priv->reset))
589+
return PTR_ERR(priv->reset);
590+
591+
reset_control_assert(priv->reset);
592+
493593
ret = devm_request_irq(dev, irq, msiof_interrupt, 0, dev_name(dev), priv);
494594
if (ret)
495595
return ret;
496596

497597
priv->dev = dev;
498598
priv->phy_addr = res->start;
599+
priv->count = 0;
499600

500601
spin_lock_init(&priv->lock);
501602
platform_set_drvdata(pdev, priv);

0 commit comments

Comments
 (0)