Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Misael Lopez Cruz and committed by
Mark Brown
a7a3324a 18a4f557

+136 -1
+1 -1
Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
··· 32 32 - rx-num-evt : FIFO levels. 33 33 - sram-size-playback : size of sram to be allocated during playback 34 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 36 - interrupt-names : Known interrupt names are "tx" and "rx" 37 37 - pinctrl-0: Should specify pin control group used for this controller. 38 38 - pinctrl-names: Should contain only one value - "default", for more details
+124
sound/soc/davinci/davinci-mcasp.c
··· 70 70 void __iomem *base; 71 71 u32 fifo_base; 72 72 struct device *dev; 73 + struct snd_pcm_substream *substreams[2]; 73 74 74 75 /* McASP specific data */ 75 76 int tdm_slots; ··· 81 80 u8 bclk_div; 82 81 u16 bclk_lrclk_ratio; 83 82 int streams; 83 + u32 irq_request[2]; 84 84 85 85 int sysclk_freq; 86 86 bool bclk_master; ··· 187 185 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); 188 186 if (mcasp_is_synchronous(mcasp)) 189 187 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); 188 + 189 + /* enable receive IRQs */ 190 + mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, 191 + mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); 190 192 } 191 193 192 194 static void mcasp_start_tx(struct davinci_mcasp *mcasp) ··· 220 214 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); 221 215 /* Release Frame Sync generator */ 222 216 mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); 217 + 218 + /* enable transmit IRQs */ 219 + mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, 220 + mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); 223 221 } 224 222 225 223 static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) ··· 238 228 239 229 static void mcasp_stop_rx(struct davinci_mcasp *mcasp) 240 230 { 231 + /* disable IRQ sources */ 232 + mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, 233 + mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); 234 + 241 235 /* 242 236 * In synchronous mode stop the TX clocks if no other stream is 243 237 * running ··· 262 248 static void mcasp_stop_tx(struct davinci_mcasp *mcasp) 263 249 { 264 250 u32 val = 0; 251 + 252 + /* disable IRQ sources */ 253 + mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, 254 + mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); 265 255 266 256 /* 267 257 * In synchronous mode keep TX clocks running if the capture stream is ··· 292 274 mcasp_stop_tx(mcasp); 293 275 else 294 276 mcasp_stop_rx(mcasp); 277 + } 278 + 279 + static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data) 280 + { 281 + struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; 282 + struct snd_pcm_substream *substream; 283 + u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]; 284 + u32 handled_mask = 0; 285 + u32 stat; 286 + 287 + stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG); 288 + if (stat & XUNDRN & irq_mask) { 289 + dev_warn(mcasp->dev, "Transmit buffer underflow\n"); 290 + handled_mask |= XUNDRN; 291 + 292 + substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]; 293 + if (substream) { 294 + snd_pcm_stream_lock_irq(substream); 295 + if (snd_pcm_running(substream)) 296 + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); 297 + snd_pcm_stream_unlock_irq(substream); 298 + } 299 + } 300 + 301 + if (!handled_mask) 302 + dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n", 303 + stat); 304 + 305 + if (stat & XRERR) 306 + handled_mask |= XRERR; 307 + 308 + /* Ack the handled event only */ 309 + mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask); 310 + 311 + return IRQ_RETVAL(handled_mask); 312 + } 313 + 314 + static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data) 315 + { 316 + struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; 317 + struct snd_pcm_substream *substream; 318 + u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]; 319 + u32 handled_mask = 0; 320 + u32 stat; 321 + 322 + stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG); 323 + if (stat & ROVRN & irq_mask) { 324 + dev_warn(mcasp->dev, "Receive buffer overflow\n"); 325 + handled_mask |= ROVRN; 326 + 327 + substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]; 328 + if (substream) { 329 + snd_pcm_stream_lock_irq(substream); 330 + if (snd_pcm_running(substream)) 331 + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); 332 + snd_pcm_stream_unlock_irq(substream); 333 + } 334 + } 335 + 336 + if (!handled_mask) 337 + dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n", 338 + stat); 339 + 340 + if (stat & XRERR) 341 + handled_mask |= XRERR; 342 + 343 + /* Ack the handled event only */ 344 + mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask); 345 + 346 + return IRQ_RETVAL(handled_mask); 295 347 } 296 348 297 349 static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, ··· 957 869 u32 max_channels = 0; 958 870 int i, dir; 959 871 872 + mcasp->substreams[substream->stream] = substream; 873 + 960 874 if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 961 875 return 0; 962 876 ··· 996 906 struct snd_soc_dai *cpu_dai) 997 907 { 998 908 struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 909 + 910 + mcasp->substreams[substream->stream] = NULL; 999 911 1000 912 if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 1001 913 return; ··· 1348 1256 struct resource *mem, *ioarea, *res, *dat; 1349 1257 struct davinci_mcasp_pdata *pdata; 1350 1258 struct davinci_mcasp *mcasp; 1259 + char *irq_name; 1260 + int irq; 1351 1261 int ret; 1352 1262 1353 1263 if (!pdev->dev.platform_data && !pdev->dev.of_node) { ··· 1429 1335 mcasp->rxnumevt = pdata->rxnumevt; 1430 1336 1431 1337 mcasp->dev = &pdev->dev; 1338 + 1339 + irq = platform_get_irq_byname(pdev, "rx"); 1340 + if (irq >= 0) { 1341 + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n", 1342 + dev_name(&pdev->dev)); 1343 + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 1344 + davinci_mcasp_rx_irq_handler, 1345 + IRQF_ONESHOT, irq_name, mcasp); 1346 + if (ret) { 1347 + dev_err(&pdev->dev, "RX IRQ request failed\n"); 1348 + goto err; 1349 + } 1350 + 1351 + mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; 1352 + } 1353 + 1354 + irq = platform_get_irq_byname(pdev, "tx"); 1355 + if (irq >= 0) { 1356 + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n", 1357 + dev_name(&pdev->dev)); 1358 + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 1359 + davinci_mcasp_tx_irq_handler, 1360 + IRQF_ONESHOT, irq_name, mcasp); 1361 + if (ret) { 1362 + dev_err(&pdev->dev, "TX IRQ request failed\n"); 1363 + goto err; 1364 + } 1365 + 1366 + mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; 1367 + } 1432 1368 1433 1369 dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); 1434 1370 if (dat)
+11
sound/soc/davinci/davinci-mcasp.h
··· 256 256 * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits 257 257 * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits 258 258 */ 259 + #define XRERR BIT(8) /* Transmit/Receive error */ 259 260 #define XRDATA BIT(5) /* Transmit/Receive data ready */ 260 261 261 262 /* ··· 284 283 * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits 285 284 */ 286 285 #define TXDATADMADIS BIT(0) 286 + 287 + /* 288 + * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits 289 + */ 290 + #define ROVRN BIT(0) 291 + 292 + /* 293 + * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits 294 + */ 295 + #define XUNDRN BIT(0) 287 296 288 297 /* 289 298 * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits