aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMisael Lopez Cruz <misael.lopez@ti.com>2014-11-12 09:38:05 -0500
committerMark Brown <broonie@kernel.org>2014-11-12 09:55:00 -0500
commita7a3324a602cd7ebabfb7f5990006ec4f3d6449f (patch)
treef77c68c09dec608db66c5e16b9010bd56359d4f4
parent18a4f55756ac945bd89d1fe63dafe36462ecba86 (diff)
ASoC: davinci-mcasp: Add overrun/underrun event handling
An underrun (playback) event occurs when the serializer transfer data from the XRBUF buffer to the XRSR shift register, but the XRBUF hasn't been filled. Similarly, the overrun (capture) event occurs when data from the XRSR shift register is transferred to the XRBUF but it hasn't been read yet. These events are handled as XRUN events that cause the pcm to stop. The stream has to be explicitly restarted by the userspace which ensures that after stopping/starting McASP the data transfer is aligned with DMA. The other possibility was to internally stop and start McASP without DMA even knowing about it. Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt2
-rw-r--r--sound/soc/davinci/davinci-mcasp.c124
-rw-r--r--sound/soc/davinci/davinci-mcasp.h11
3 files changed, 136 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
index 60ca07996458..46bc9829c71a 100644
--- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
@@ -32,7 +32,7 @@ Optional properties:
32- rx-num-evt : FIFO levels. 32- rx-num-evt : FIFO levels.
33- sram-size-playback : size of sram to be allocated during playback 33- sram-size-playback : size of sram to be allocated during playback
34- sram-size-capture : size of sram to be allocated during capture 34- sram-size-capture : size of sram to be allocated during capture
35- interrupts : Interrupt numbers for McASP, currently not used by the driver 35- interrupts : Interrupt numbers for McASP
36- interrupt-names : Known interrupt names are "tx" and "rx" 36- interrupt-names : Known interrupt names are "tx" and "rx"
37- pinctrl-0: Should specify pin control group used for this controller. 37- pinctrl-0: Should specify pin control group used for this controller.
38- pinctrl-names: Should contain only one value - "default", for more details 38- pinctrl-names: Should contain only one value - "default", for more details
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index a9822c7bbb0b..e460f97c514e 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -70,6 +70,7 @@ struct davinci_mcasp {
70 void __iomem *base; 70 void __iomem *base;
71 u32 fifo_base; 71 u32 fifo_base;
72 struct device *dev; 72 struct device *dev;
73 struct snd_pcm_substream *substreams[2];
73 74
74 /* McASP specific data */ 75 /* McASP specific data */
75 int tdm_slots; 76 int tdm_slots;
@@ -80,6 +81,7 @@ struct davinci_mcasp {
80 u8 bclk_div; 81 u8 bclk_div;
81 u16 bclk_lrclk_ratio; 82 u16 bclk_lrclk_ratio;
82 int streams; 83 int streams;
84 u32 irq_request[2];
83 85
84 int sysclk_freq; 86 int sysclk_freq;
85 bool bclk_master; 87 bool bclk_master;
@@ -185,6 +187,10 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
185 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); 187 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
186 if (mcasp_is_synchronous(mcasp)) 188 if (mcasp_is_synchronous(mcasp))
187 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); 189 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
190
191 /* enable receive IRQs */
192 mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
193 mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
188} 194}
189 195
190static void mcasp_start_tx(struct davinci_mcasp *mcasp) 196static void mcasp_start_tx(struct davinci_mcasp *mcasp)
@@ -214,6 +220,10 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
214 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); 220 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
215 /* Release Frame Sync generator */ 221 /* Release Frame Sync generator */
216 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); 222 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
223
224 /* enable transmit IRQs */
225 mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
226 mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
217} 227}
218 228
219static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) 229static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
@@ -228,6 +238,10 @@ static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
228 238
229static void mcasp_stop_rx(struct davinci_mcasp *mcasp) 239static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
230{ 240{
241 /* disable IRQ sources */
242 mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
243 mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
244
231 /* 245 /*
232 * In synchronous mode stop the TX clocks if no other stream is 246 * In synchronous mode stop the TX clocks if no other stream is
233 * running 247 * running
@@ -249,6 +263,10 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
249{ 263{
250 u32 val = 0; 264 u32 val = 0;
251 265
266 /* disable IRQ sources */
267 mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
268 mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
269
252 /* 270 /*
253 * In synchronous mode keep TX clocks running if the capture stream is 271 * In synchronous mode keep TX clocks running if the capture stream is
254 * still running. 272 * still running.
@@ -276,6 +294,76 @@ static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
276 mcasp_stop_rx(mcasp); 294 mcasp_stop_rx(mcasp);
277} 295}
278 296
297static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
298{
299 struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
300 struct snd_pcm_substream *substream;
301 u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK];
302 u32 handled_mask = 0;
303 u32 stat;
304
305 stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG);
306 if (stat & XUNDRN & irq_mask) {
307 dev_warn(mcasp->dev, "Transmit buffer underflow\n");
308 handled_mask |= XUNDRN;
309
310 substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
311 if (substream) {
312 snd_pcm_stream_lock_irq(substream);
313 if (snd_pcm_running(substream))
314 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
315 snd_pcm_stream_unlock_irq(substream);
316 }
317 }
318
319 if (!handled_mask)
320 dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n",
321 stat);
322
323 if (stat & XRERR)
324 handled_mask |= XRERR;
325
326 /* Ack the handled event only */
327 mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask);
328
329 return IRQ_RETVAL(handled_mask);
330}
331
332static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
333{
334 struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
335 struct snd_pcm_substream *substream;
336 u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE];
337 u32 handled_mask = 0;
338 u32 stat;
339
340 stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG);
341 if (stat & ROVRN & irq_mask) {
342 dev_warn(mcasp->dev, "Receive buffer overflow\n");
343 handled_mask |= ROVRN;
344
345 substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
346 if (substream) {
347 snd_pcm_stream_lock_irq(substream);
348 if (snd_pcm_running(substream))
349 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
350 snd_pcm_stream_unlock_irq(substream);
351 }
352 }
353
354 if (!handled_mask)
355 dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n",
356 stat);
357
358 if (stat & XRERR)
359 handled_mask |= XRERR;
360
361 /* Ack the handled event only */
362 mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask);
363
364 return IRQ_RETVAL(handled_mask);
365}
366
279static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, 367static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
280 unsigned int fmt) 368 unsigned int fmt)
281{ 369{
@@ -869,6 +957,8 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
869 u32 max_channels = 0; 957 u32 max_channels = 0;
870 int i, dir; 958 int i, dir;
871 959
960 mcasp->substreams[substream->stream] = substream;
961
872 if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 962 if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
873 return 0; 963 return 0;
874 964
@@ -907,6 +997,8 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
907{ 997{
908 struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 998 struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
909 999
1000 mcasp->substreams[substream->stream] = NULL;
1001
910 if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 1002 if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
911 return; 1003 return;
912 1004
@@ -1256,6 +1348,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
1256 struct resource *mem, *ioarea, *res, *dat; 1348 struct resource *mem, *ioarea, *res, *dat;
1257 struct davinci_mcasp_pdata *pdata; 1349 struct davinci_mcasp_pdata *pdata;
1258 struct davinci_mcasp *mcasp; 1350 struct davinci_mcasp *mcasp;
1351 char *irq_name;
1352 int irq;
1259 int ret; 1353 int ret;
1260 1354
1261 if (!pdev->dev.platform_data && !pdev->dev.of_node) { 1355 if (!pdev->dev.platform_data && !pdev->dev.of_node) {
@@ -1336,6 +1430,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
1336 1430
1337 mcasp->dev = &pdev->dev; 1431 mcasp->dev = &pdev->dev;
1338 1432
1433 irq = platform_get_irq_byname(pdev, "rx");
1434 if (irq >= 0) {
1435 irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n",
1436 dev_name(&pdev->dev));
1437 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
1438 davinci_mcasp_rx_irq_handler,
1439 IRQF_ONESHOT, irq_name, mcasp);
1440 if (ret) {
1441 dev_err(&pdev->dev, "RX IRQ request failed\n");
1442 goto err;
1443 }
1444
1445 mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
1446 }
1447
1448 irq = platform_get_irq_byname(pdev, "tx");
1449 if (irq >= 0) {
1450 irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n",
1451 dev_name(&pdev->dev));
1452 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
1453 davinci_mcasp_tx_irq_handler,
1454 IRQF_ONESHOT, irq_name, mcasp);
1455 if (ret) {
1456 dev_err(&pdev->dev, "TX IRQ request failed\n");
1457 goto err;
1458 }
1459
1460 mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
1461 }
1462
1339 dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); 1463 dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
1340 if (dat) 1464 if (dat)
1341 mcasp->dat_port = true; 1465 mcasp->dat_port = true;
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index 9737108f0305..79dc511180bf 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -256,6 +256,7 @@
256 * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits 256 * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits
257 * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits 257 * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits
258 */ 258 */
259#define XRERR BIT(8) /* Transmit/Receive error */
259#define XRDATA BIT(5) /* Transmit/Receive data ready */ 260#define XRDATA BIT(5) /* Transmit/Receive data ready */
260 261
261/* 262/*
@@ -285,6 +286,16 @@
285#define TXDATADMADIS BIT(0) 286#define TXDATADMADIS BIT(0)
286 287
287/* 288/*
289 * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits
290 */
291#define ROVRN BIT(0)
292
293/*
294 * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits
295 */
296#define XUNDRN BIT(0)
297
298/*
288 * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits 299 * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
289 */ 300 */
290#define FIFO_ENABLE BIT(16) 301#define FIFO_ENABLE BIT(16)