aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorJarkko Nikula <jhnikula@gmail.com>2009-08-07 02:59:47 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-08-07 05:57:42 -0400
commitc12abc012e18b362204345c323536f228d65c4db (patch)
tree105552bd558076eb3206ce5f4026af60921dc27f /arch/arm
parent06c71282a90470184a78f7f0ab0f7ce0fc1f69c8 (diff)
ARM: OMAP: McBSP: Fix ASoC on OMAP1510 by fixing API of omap_mcbsp_start/stop
Simultaneous audio playback and capture on OMAP1510 can cause that second stream is stalled if there is enough delay between startup of the audio streams. Current implementation of the omap_mcbsp_start is starting both transmitter and receiver at the same time and it is called only for firstly started audio stream from the OMAP McBSP based ASoC DAI driver. Since DMA request lines on OMAP1510 are edge sensitive, the DMA request is missed if there is no DMA transfer set up at that time when the first word after McBSP startup is transmitted. The problem hasn't noted before since later OMAPs are using level sensitive DMA request lines. Fix the problem by changing API of omap_mcbsp_start and omap_mcbsp_stop by allowing to start and stop individually McBSP transmitter and receiver logics. Then call those functions individually for both audio playback and capture streams. This ensures that DMA transfer is setup before transmitter or receiver is started. Thanks to Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> for detailed problem analysis and Peter Ujfalusi <peter.ujfalusi@nokia.com> for info about DMA request line behavior differences between the OMAP generations. Reported-and-tested-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Acked-by: Tony Lindgren <tony@atomide.com> Acked-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/plat-omap/include/mach/mcbsp.h4
-rw-r--r--arch/arm/plat-omap/mcbsp.c50
2 files changed, 34 insertions, 20 deletions
diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h
index bb154ea76769..57249bb1e9bc 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/mach/mcbsp.h
@@ -387,8 +387,8 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
387void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config); 387void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config);
388int omap_mcbsp_request(unsigned int id); 388int omap_mcbsp_request(unsigned int id);
389void omap_mcbsp_free(unsigned int id); 389void omap_mcbsp_free(unsigned int id);
390void omap_mcbsp_start(unsigned int id); 390void omap_mcbsp_start(unsigned int id, int tx, int rx);
391void omap_mcbsp_stop(unsigned int id); 391void omap_mcbsp_stop(unsigned int id, int tx, int rx);
392void omap_mcbsp_xmit_word(unsigned int id, u32 word); 392void omap_mcbsp_xmit_word(unsigned int id, u32 word);
393u32 omap_mcbsp_recv_word(unsigned int id); 393u32 omap_mcbsp_recv_word(unsigned int id);
394 394
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index efa0e0111f38..a3d2313460b3 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -328,14 +328,15 @@ void omap_mcbsp_free(unsigned int id)
328EXPORT_SYMBOL(omap_mcbsp_free); 328EXPORT_SYMBOL(omap_mcbsp_free);
329 329
330/* 330/*
331 * Here we start the McBSP, by enabling the sample 331 * Here we start the McBSP, by enabling transmitter, receiver or both.
332 * generator, both transmitter and receivers, 332 * If no transmitter or receiver is active prior calling, then sample-rate
333 * and the frame sync. 333 * generator and frame sync are started.
334 */ 334 */
335void omap_mcbsp_start(unsigned int id) 335void omap_mcbsp_start(unsigned int id, int tx, int rx)
336{ 336{
337 struct omap_mcbsp *mcbsp; 337 struct omap_mcbsp *mcbsp;
338 void __iomem *io_base; 338 void __iomem *io_base;
339 int idle;
339 u16 w; 340 u16 w;
340 341
341 if (!omap_mcbsp_check_valid_id(id)) { 342 if (!omap_mcbsp_check_valid_id(id)) {
@@ -348,32 +349,40 @@ void omap_mcbsp_start(unsigned int id)
348 mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7; 349 mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
349 mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7; 350 mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
350 351
351 /* Start the sample generator */ 352 idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
352 w = OMAP_MCBSP_READ(io_base, SPCR2); 353 OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
353 OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); 354
355 if (idle) {
356 /* Start the sample generator */
357 w = OMAP_MCBSP_READ(io_base, SPCR2);
358 OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
359 }
354 360
355 /* Enable transmitter and receiver */ 361 /* Enable transmitter and receiver */
356 w = OMAP_MCBSP_READ(io_base, SPCR2); 362 w = OMAP_MCBSP_READ(io_base, SPCR2);
357 OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1); 363 OMAP_MCBSP_WRITE(io_base, SPCR2, w | (tx & 1));
358 364
359 w = OMAP_MCBSP_READ(io_base, SPCR1); 365 w = OMAP_MCBSP_READ(io_base, SPCR1);
360 OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1); 366 OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1));
361 367
362 udelay(100); 368 udelay(100);
363 369
364 /* Start frame sync */ 370 if (idle) {
365 w = OMAP_MCBSP_READ(io_base, SPCR2); 371 /* Start frame sync */
366 OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); 372 w = OMAP_MCBSP_READ(io_base, SPCR2);
373 OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
374 }
367 375
368 /* Dump McBSP Regs */ 376 /* Dump McBSP Regs */
369 omap_mcbsp_dump_reg(id); 377 omap_mcbsp_dump_reg(id);
370} 378}
371EXPORT_SYMBOL(omap_mcbsp_start); 379EXPORT_SYMBOL(omap_mcbsp_start);
372 380
373void omap_mcbsp_stop(unsigned int id) 381void omap_mcbsp_stop(unsigned int id, int tx, int rx)
374{ 382{
375 struct omap_mcbsp *mcbsp; 383 struct omap_mcbsp *mcbsp;
376 void __iomem *io_base; 384 void __iomem *io_base;
385 int idle;
377 u16 w; 386 u16 w;
378 387
379 if (!omap_mcbsp_check_valid_id(id)) { 388 if (!omap_mcbsp_check_valid_id(id)) {
@@ -386,15 +395,20 @@ void omap_mcbsp_stop(unsigned int id)
386 395
387 /* Reset transmitter */ 396 /* Reset transmitter */
388 w = OMAP_MCBSP_READ(io_base, SPCR2); 397 w = OMAP_MCBSP_READ(io_base, SPCR2);
389 OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1)); 398 OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(tx & 1));
390 399
391 /* Reset receiver */ 400 /* Reset receiver */
392 w = OMAP_MCBSP_READ(io_base, SPCR1); 401 w = OMAP_MCBSP_READ(io_base, SPCR1);
393 OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1)); 402 OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(rx & 1));
394 403
395 /* Reset the sample rate generator */ 404 idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
396 w = OMAP_MCBSP_READ(io_base, SPCR2); 405 OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
397 OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); 406
407 if (idle) {
408 /* Reset the sample rate generator */
409 w = OMAP_MCBSP_READ(io_base, SPCR2);
410 OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
411 }
398} 412}
399EXPORT_SYMBOL(omap_mcbsp_stop); 413EXPORT_SYMBOL(omap_mcbsp_stop);
400 414