[alsa-devel] [PATCH] ASoC: sh: FSI: Add capture support

Kuninori Morimoto morimoto.kuninori at renesas.com
Fri Oct 30 04:02:44 CET 2009


Signed-off-by: Kuninori Morimoto <morimoto.kuninori at renesas.com>
---
 sound/soc/sh/fsi.c |   93 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 9742a28..e1a3d1a 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)
 	return 0;
 }
 
+static int fsi_data_pop(struct fsi_priv *fsi)
+{
+	struct snd_pcm_runtime *runtime;
+	struct snd_pcm_substream *substream = NULL;
+	int free;
+	int fifo_fill;
+	int width;
+	u8 *start;
+	int i;
+
+	if (!fsi			||
+	    !fsi->substream		||
+	    !fsi->substream->runtime)
+		return -EINVAL;
+
+	runtime = fsi->substream->runtime;
+
+	/* FSI FIFO has limit.
+	 * So, this driver can not send periods data at a time
+	 */
+	if (fsi->byte_offset >=
+	    fsi->period_len * (fsi->periods + 1)) {
+
+		substream = fsi->substream;
+		fsi->periods = (fsi->periods + 1) % runtime->periods;
+
+		if (0 == fsi->periods)
+			fsi->byte_offset = 0;
+	}
+
+	/* get 1 channel data width */
+	width = frames_to_bytes(runtime, 1) / fsi->chan;
+
+	/* get free space for alsa */
+	free = (fsi->buffer_len - fsi->byte_offset) / width;
+
+	/* get recv size */
+	fifo_fill = fsi_get_fifo_residue(fsi, 0);
+
+	if (free < fifo_fill)
+		fifo_fill = free;
+
+	start = runtime->dma_area;
+	start += fsi->byte_offset;
+
+	switch (width) {
+	case 2:
+		for (i = 0; i < fifo_fill; i++)
+			*((u16 *)start + i) =
+				(u16)(fsi_reg_read(fsi, DIDT) >> 8);
+		break;
+	case 4:
+		for (i = 0; i < fifo_fill; i++)
+			*((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fsi->byte_offset += fifo_fill * width;
+
+	fsi_irq_enable(fsi, 0);
+
+	if (substream)
+		snd_pcm_period_elapsed(substream);
+
+	return 0;
+}
+
 static irqreturn_t fsi_interrupt(int irq, void *data)
 {
 	u32 status = fsi_master_read(SOFT_RST) & ~0x00000010;
@@ -460,6 +529,10 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
 		fsi_data_push(&master->fsia);
 	if (int_st & INT_B_OUT)
 		fsi_data_push(&master->fsib);
+	if (int_st & INT_A_IN)
+		fsi_data_pop(&master->fsia);
+	if (int_st & INT_B_IN)
+		fsi_data_pop(&master->fsib);
 
 	fsi_master_write(INT_ST, 0x0000000);
 
@@ -612,16 +685,12 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 	int ret = 0;
 
-	/* capture not supported */
-	if (!is_play)
-		return -ENODEV;
-
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		fsi_stream_push(fsi, substream,
 				frames_to_bytes(runtime, runtime->buffer_size),
 				frames_to_bytes(runtime, runtime->period_size));
-		ret = fsi_data_push(fsi);
+		ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		fsi_irq_disable(fsi, is_play);
@@ -757,7 +826,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
 			.channels_min	= 1,
 			.channels_max	= 8,
 		},
-		/* capture not supported */
+		.capture = {
+			.rates		= FSI_RATES,
+			.formats	= FSI_FMTS,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
 		.ops = &fsi_dai_ops,
 	},
 	{
@@ -769,7 +843,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
 			.channels_min	= 1,
 			.channels_max	= 8,
 		},
-		/* capture not supported */
+		.capture = {
+			.rates		= FSI_RATES,
+			.formats	= FSI_FMTS,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
 		.ops = &fsi_dai_ops,
 	},
 };
-- 
1.6.0.4



More information about the Alsa-devel mailing list