aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKuninori Morimoto <morimoto.kuninori@renesas.com>2009-10-29 23:02:44 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-10-30 06:35:30 -0400
commit07102f3cefc93aa742af91186830e282c0347e41 (patch)
tree417731c7492ecabed293bc82177dd6efbbb4eb9b
parent9ddc9aa910687a8787dbbdc53dcd48e738b197d9 (diff)
ASoC: sh: FSI: Add capture support
Signed-off-by: Kuninori Morimoto <morimoto.kuninori@renesas.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--sound/soc/sh/fsi.c93
1 files changed, 86 insertions, 7 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 9742a280ba15..e1a3d1a2b4c8 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -447,6 +447,75 @@ static int fsi_data_push(struct fsi_priv *fsi)
447 return 0; 447 return 0;
448} 448}
449 449
450static int fsi_data_pop(struct fsi_priv *fsi)
451{
452 struct snd_pcm_runtime *runtime;
453 struct snd_pcm_substream *substream = NULL;
454 int free;
455 int fifo_fill;
456 int width;
457 u8 *start;
458 int i;
459
460 if (!fsi ||
461 !fsi->substream ||
462 !fsi->substream->runtime)
463 return -EINVAL;
464
465 runtime = fsi->substream->runtime;
466
467 /* FSI FIFO has limit.
468 * So, this driver can not send periods data at a time
469 */
470 if (fsi->byte_offset >=
471 fsi->period_len * (fsi->periods + 1)) {
472
473 substream = fsi->substream;
474 fsi->periods = (fsi->periods + 1) % runtime->periods;
475
476 if (0 == fsi->periods)
477 fsi->byte_offset = 0;
478 }
479
480 /* get 1 channel data width */
481 width = frames_to_bytes(runtime, 1) / fsi->chan;
482
483 /* get free space for alsa */
484 free = (fsi->buffer_len - fsi->byte_offset) / width;
485
486 /* get recv size */
487 fifo_fill = fsi_get_fifo_residue(fsi, 0);
488
489 if (free < fifo_fill)
490 fifo_fill = free;
491
492 start = runtime->dma_area;
493 start += fsi->byte_offset;
494
495 switch (width) {
496 case 2:
497 for (i = 0; i < fifo_fill; i++)
498 *((u16 *)start + i) =
499 (u16)(fsi_reg_read(fsi, DIDT) >> 8);
500 break;
501 case 4:
502 for (i = 0; i < fifo_fill; i++)
503 *((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
504 break;
505 default:
506 return -EINVAL;
507 }
508
509 fsi->byte_offset += fifo_fill * width;
510
511 fsi_irq_enable(fsi, 0);
512
513 if (substream)
514 snd_pcm_period_elapsed(substream);
515
516 return 0;
517}
518
450static irqreturn_t fsi_interrupt(int irq, void *data) 519static irqreturn_t fsi_interrupt(int irq, void *data)
451{ 520{
452 u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; 521 u32 status = fsi_master_read(SOFT_RST) & ~0x00000010;
@@ -460,6 +529,10 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
460 fsi_data_push(&master->fsia); 529 fsi_data_push(&master->fsia);
461 if (int_st & INT_B_OUT) 530 if (int_st & INT_B_OUT)
462 fsi_data_push(&master->fsib); 531 fsi_data_push(&master->fsib);
532 if (int_st & INT_A_IN)
533 fsi_data_pop(&master->fsia);
534 if (int_st & INT_B_IN)
535 fsi_data_pop(&master->fsib);
463 536
464 fsi_master_write(INT_ST, 0x0000000); 537 fsi_master_write(INT_ST, 0x0000000);
465 538
@@ -612,16 +685,12 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
612 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 685 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
613 int ret = 0; 686 int ret = 0;
614 687
615 /* capture not supported */
616 if (!is_play)
617 return -ENODEV;
618
619 switch (cmd) { 688 switch (cmd) {
620 case SNDRV_PCM_TRIGGER_START: 689 case SNDRV_PCM_TRIGGER_START:
621 fsi_stream_push(fsi, substream, 690 fsi_stream_push(fsi, substream,
622 frames_to_bytes(runtime, runtime->buffer_size), 691 frames_to_bytes(runtime, runtime->buffer_size),
623 frames_to_bytes(runtime, runtime->period_size)); 692 frames_to_bytes(runtime, runtime->period_size));
624 ret = fsi_data_push(fsi); 693 ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
625 break; 694 break;
626 case SNDRV_PCM_TRIGGER_STOP: 695 case SNDRV_PCM_TRIGGER_STOP:
627 fsi_irq_disable(fsi, is_play); 696 fsi_irq_disable(fsi, is_play);
@@ -757,7 +826,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
757 .channels_min = 1, 826 .channels_min = 1,
758 .channels_max = 8, 827 .channels_max = 8,
759 }, 828 },
760 /* capture not supported */ 829 .capture = {
830 .rates = FSI_RATES,
831 .formats = FSI_FMTS,
832 .channels_min = 1,
833 .channels_max = 8,
834 },
761 .ops = &fsi_dai_ops, 835 .ops = &fsi_dai_ops,
762 }, 836 },
763 { 837 {
@@ -769,7 +843,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
769 .channels_min = 1, 843 .channels_min = 1,
770 .channels_max = 8, 844 .channels_max = 8,
771 }, 845 },
772 /* capture not supported */ 846 .capture = {
847 .rates = FSI_RATES,
848 .formats = FSI_FMTS,
849 .channels_min = 1,
850 .channels_max = 8,
851 },
773 .ops = &fsi_dai_ops, 852 .ops = &fsi_dai_ops,
774 }, 853 },
775}; 854};