Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07102f3c authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown
Browse files

ASoC: sh: FSI: Add capture support

parent 9ddc9aa9
Loading
Loading
Loading
Loading
+86 −7
Original line number Original line Diff line number Diff line
@@ -447,6 +447,75 @@ static int fsi_data_push(struct fsi_priv *fsi)
	return 0;
	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)
static irqreturn_t fsi_interrupt(int irq, void *data)
{
{
	u32 status = fsi_master_read(SOFT_RST) & ~0x00000010;
	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);
		fsi_data_push(&master->fsia);
	if (int_st & INT_B_OUT)
	if (int_st & INT_B_OUT)
		fsi_data_push(&master->fsib);
		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);
	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 is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
	int ret = 0;
	int ret = 0;


	/* capture not supported */
	if (!is_play)
		return -ENODEV;

	switch (cmd) {
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_START:
		fsi_stream_push(fsi, substream,
		fsi_stream_push(fsi, substream,
				frames_to_bytes(runtime, runtime->buffer_size),
				frames_to_bytes(runtime, runtime->buffer_size),
				frames_to_bytes(runtime, runtime->period_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;
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_STOP:
		fsi_irq_disable(fsi, is_play);
		fsi_irq_disable(fsi, is_play);
@@ -757,7 +826,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
			.channels_min	= 1,
			.channels_min	= 1,
			.channels_max	= 8,
			.channels_max	= 8,
		},
		},
		/* capture not supported */
		.capture = {
			.rates		= FSI_RATES,
			.formats	= FSI_FMTS,
			.channels_min	= 1,
			.channels_max	= 8,
		},
		.ops = &fsi_dai_ops,
		.ops = &fsi_dai_ops,
	},
	},
	{
	{
@@ -769,7 +843,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
			.channels_min	= 1,
			.channels_min	= 1,
			.channels_max	= 8,
			.channels_max	= 8,
		},
		},
		/* capture not supported */
		.capture = {
			.rates		= FSI_RATES,
			.formats	= FSI_FMTS,
			.channels_min	= 1,
			.channels_max	= 8,
		},
		.ops = &fsi_dai_ops,
		.ops = &fsi_dai_ops,
	},
	},
};
};