mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 04:06:22 +00:00
ASoC: sh: FSI: Add capture support
Signed-off-by: Kuninori Morimoto <morimoto.kuninori@renesas.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
9ddc9aa910
commit
07102f3cef
1 changed files with 86 additions and 7 deletions
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue