summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/imx-pcm-rpmsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl/imx-pcm-rpmsg.c')
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c423
1 files changed, 321 insertions, 102 deletions
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index fc48451083bc..03f184a458ec 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -25,18 +25,19 @@
struct i2s_info *i2s_info_g;
-static const struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
+static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.buffer_bytes_max = IMX_SAI_DMABUF_SIZE,
.period_bytes_min = 512,
.period_bytes_max = 65532, /* Limited by SDMA engine */
.periods_min = 2,
- .periods_max = 255,
+ .periods_max = 6000,
.fifo_size = 0,
};
@@ -49,37 +50,36 @@ static int imx_rpmsg_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg_tx = &i2s_info->send_msg[SNDRV_PCM_STREAM_PLAYBACK];
- struct i2s_rpmsg_s *rpmsg_rx = &i2s_info->send_msg[SNDRV_PCM_STREAM_CAPTURE];
-
- rpmsg_tx->param.rate = params_rate(params);
- rpmsg_rx->param.rate = params_rate(params);
- if (SNDRV_PCM_FORMAT_S16_LE == params_format(params)) {
- rpmsg_tx->param.format = RPMSG_S16_LE;
- rpmsg_rx->param.format = RPMSG_S16_LE;
- } else {
- rpmsg_tx->param.format = RPMSG_S24_LE;
- rpmsg_rx->param.format = RPMSG_S24_LE;
- }
+ struct i2s_rpmsg *rpmsg;
- if (params_channels(params) == 1) {
- rpmsg_tx->param.channels = RPMSG_CH_LEFT;
- rpmsg_rx->param.channels = RPMSG_CH_LEFT;
- } else {
- rpmsg_tx->param.channels = RPMSG_CH_STEREO;
- rpmsg_rx->param.channels = RPMSG_CH_STEREO;
- }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg = &i2s_info->rpmsg[I2S_TX_HW_PARAM];
+ else
+ rpmsg = &i2s_info->rpmsg[I2S_RX_HW_PARAM];
+
+ rpmsg->send_msg.param.rate = params_rate(params);
+
+ if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
+ rpmsg->send_msg.param.format = RPMSG_S16_LE;
+ else if (params_format(params) == SNDRV_PCM_FORMAT_S24_3LE)
+ rpmsg->send_msg.param.format = RPMSG_S24_LE;
+ else
+ rpmsg->send_msg.param.format = RPMSG_S32_LE;
+
+ if (params_channels(params) == 1)
+ rpmsg->send_msg.param.channels = RPMSG_CH_LEFT;
+ else
+ rpmsg->send_msg.param.channels = RPMSG_CH_STEREO;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = params_buffer_bytes(params);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- rpmsg_tx->header.cmd = I2S_TX_HW_PARAM;
- i2s_info->send_message(rpmsg_tx, i2s_info);
- } else {
- rpmsg_rx->header.cmd = I2S_RX_HW_PARAM;
- i2s_info->send_message(rpmsg_rx, i2s_info);
- }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_HW_PARAM;
+ else
+ rpmsg->send_msg.header.cmd = I2S_RX_HW_PARAM;
+
+ i2s_info->send_message(rpmsg, i2s_info);
return 0;
}
@@ -93,29 +93,62 @@ static int imx_rpmsg_pcm_hw_free(struct snd_pcm_substream *substream)
static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(
struct snd_pcm_substream *substream)
{
- struct dma_tx_state state;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg = &i2s_info->send_msg[substream->stream];
- unsigned int buf_size;
unsigned int pos = 0;
- unsigned long flags;
+ struct i2s_rpmsg *rpmsg;
+ int buffer_tail = 0;
- spin_lock_irqsave(&i2s_info->lock[substream->stream], flags);
- state.residue = (i2s_info->num_period[substream->stream] -
- rpmsg->param.buffer_tail)
- * rpmsg->param.period_size;
- spin_unlock_irqrestore(&i2s_info->lock[substream->stream], flags);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg = &i2s_info->rpmsg[I2S_TX_POINTER];
+ else
+ rpmsg = &i2s_info->rpmsg[I2S_RX_POINTER];
- buf_size = snd_pcm_lib_buffer_bytes(substream);
- if (state.residue > 0 && state.residue <= buf_size)
- pos = buf_size - state.residue;
+ buffer_tail = rpmsg->recv_msg.param.buffer_offset /
+ snd_pcm_lib_period_bytes(substream);
+ pos = buffer_tail * snd_pcm_lib_period_bytes(substream);
return bytes_to_frames(substream->runtime, pos);
}
+static void imx_rpmsg_timer_callback(unsigned long data)
+{
+ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
+ struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
+ struct i2s_rpmsg *rpmsg;
+ u8 index = i2s_info->work_index;
+ int time_msec;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg = &i2s_info->rpmsg[I2S_TX_POINTER];
+ else
+ rpmsg = &i2s_info->rpmsg[I2S_RX_POINTER];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_POINTER;
+ else
+ rpmsg->send_msg.header.cmd = I2S_RX_POINTER;
+
+ memcpy(&i2s_info->work_list[index].msg, rpmsg,
+ sizeof(struct i2s_rpmsg_s));
+ queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work);
+ i2s_info->work_index++;
+ i2s_info->work_index %= WORK_MAX_NUM;
+
+ if (rpmsg_i2s->force_lpa) {
+ time_msec = min(500,
+ (int)(runtime->period_size*1000/runtime->rate));
+ mod_timer(&i2s_info->stream_timer[substream->stream],
+ jiffies + msecs_to_jiffies(time_msec));
+ }
+}
+
static int imx_rpmsg_pcm_open(struct snd_pcm_substream *substream)
{
int ret = 0;
@@ -123,15 +156,39 @@ static int imx_rpmsg_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg = &i2s_info->send_msg[substream->stream];
+ struct i2s_rpmsg *rpmsg;
struct dmaengine_pcm_runtime_data *prtd;
+ int cmd;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg = &i2s_info->rpmsg[I2S_TX_OPEN];
+ else
+ rpmsg = &i2s_info->rpmsg[I2S_RX_OPEN];
+
+ imx_rpmsg_pcm_hardware.buffer_bytes_max =
+ i2s_info->prealloc_buffer_size;
+ imx_rpmsg_pcm_hardware.period_bytes_max =
+ imx_rpmsg_pcm_hardware.buffer_bytes_max / 2;
snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rpmsg->header.cmd = I2S_TX_OPEN;
+ rpmsg->send_msg.header.cmd = I2S_TX_OPEN;
else
- rpmsg->header.cmd = I2S_RX_OPEN;
+ rpmsg->send_msg.header.cmd = I2S_RX_OPEN;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cmd = I2S_TX_PERIOD_DONE + I2S_TYPE_A_NUM;
+ i2s_info->rpmsg[cmd].send_msg.param.buffer_tail = 0;
+ i2s_info->rpmsg[cmd].recv_msg.param.buffer_tail = 0;
+ i2s_info->rpmsg[I2S_TX_POINTER].recv_msg.param.buffer_offset = 0;
+ } else {
+ cmd = I2S_RX_PERIOD_DONE + I2S_TYPE_A_NUM;
+ i2s_info->rpmsg[cmd].send_msg.param.buffer_tail = 0;
+ i2s_info->rpmsg[cmd].recv_msg.param.buffer_tail = 0;
+ i2s_info->rpmsg[I2S_RX_POINTER].recv_msg.param.buffer_offset = 0;
+ }
+
i2s_info->send_message(rpmsg, i2s_info);
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
@@ -145,6 +202,11 @@ static int imx_rpmsg_pcm_open(struct snd_pcm_substream *substream)
if (ret < 0)
return ret;
+
+ /*create thread*/
+ setup_timer(&i2s_info->stream_timer[substream->stream],
+ imx_rpmsg_timer_callback, (unsigned long)substream);
+
return ret;
}
@@ -155,23 +217,51 @@ static int imx_rpmsg_pcm_close(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg = &i2s_info->send_msg[substream->stream];
+ struct i2s_rpmsg *rpmsg;
struct dmaengine_pcm_runtime_data *prtd =
substream->runtime->private_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rpmsg->header.cmd = I2S_TX_CLOSE;
+ rpmsg = &i2s_info->rpmsg[I2S_TX_CLOSE];
else
- rpmsg->header.cmd = I2S_RX_CLOSE;
+ rpmsg = &i2s_info->rpmsg[I2S_RX_CLOSE];
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_CLOSE;
+ else
+ rpmsg->send_msg.header.cmd = I2S_RX_CLOSE;
flush_workqueue(i2s_info->rpmsg_wq);
i2s_info->send_message(rpmsg, i2s_info);
+ del_timer(&i2s_info->stream_timer[substream->stream]);
+
kfree(prtd);
return ret;
}
+static int imx_rpmsg_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
+
+ /* NON-MMAP mode, NONBLOCK, Version 2, enable lpa in dts
+ * four condition to determine the lpa is enabled.
+ */
+ if ((runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
+ runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) &&
+ (substream->f_flags & O_NONBLOCK) &&
+ rpmsg_i2s->version == 2 &&
+ rpmsg_i2s->enable_lpa)
+ rpmsg_i2s->force_lpa = 1;
+ else
+ rpmsg_i2s->force_lpa = 0;
+
+ return 0;
+}
+
static int imx_rpmsg_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
@@ -186,12 +276,23 @@ static int imx_rpmsg_pcm_mmap(struct snd_pcm_substream *substream,
static void imx_rpmsg_pcm_dma_complete(void *arg)
{
struct snd_pcm_substream *substream = arg;
- struct dmaengine_pcm_runtime_data *prtd
- = substream->runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
+ struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
+ struct i2s_rpmsg *rpmsg, *rpmsg2;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ rpmsg = &i2s_info->rpmsg[I2S_TX_POINTER];
+ rpmsg2 = &i2s_info->rpmsg[I2S_TX_PERIOD_DONE + I2S_TYPE_A_NUM];
+ } else {
+ rpmsg = &i2s_info->rpmsg[I2S_RX_POINTER];
+ rpmsg2 = &i2s_info->rpmsg[I2S_RX_PERIOD_DONE + I2S_TYPE_A_NUM];
+ }
- prtd->pos += snd_pcm_lib_period_bytes(substream);
- if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
- prtd->pos = 0;
+ rpmsg->recv_msg.param.buffer_offset =
+ rpmsg2->recv_msg.param.buffer_tail
+ * snd_pcm_lib_period_bytes(substream);
snd_pcm_period_elapsed(substream);
}
@@ -202,24 +303,31 @@ static int imx_rpmsg_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg = &i2s_info->send_msg[substream->stream];
+ struct i2s_rpmsg *rpmsg;
u8 index = i2s_info->work_index;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rpmsg->header.cmd = I2S_TX_BUFFER;
+ rpmsg = &i2s_info->rpmsg[I2S_TX_BUFFER];
+ else
+ rpmsg = &i2s_info->rpmsg[I2S_RX_BUFFER];
+
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_BUFFER;
else
- rpmsg->header.cmd = I2S_RX_BUFFER;
+ rpmsg->send_msg.header.cmd = I2S_RX_BUFFER;
- rpmsg->param.buffer_addr = substream->runtime->dma_addr;
- rpmsg->param.buffer_size = snd_pcm_lib_buffer_bytes(substream);
- rpmsg->param.period_size = snd_pcm_lib_period_bytes(substream);
- rpmsg->param.buffer_tail = 0;
+ rpmsg->send_msg.param.buffer_addr = substream->runtime->dma_addr;
+ rpmsg->send_msg.param.buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ rpmsg->send_msg.param.period_size = snd_pcm_lib_period_bytes(substream);
+ rpmsg->send_msg.param.buffer_tail = 0;
i2s_info->num_period[substream->stream] =
- rpmsg->param.buffer_size/rpmsg->param.period_size;
+ rpmsg->send_msg.param.buffer_size /
+ rpmsg->send_msg.param.period_size;
memcpy(&i2s_info->work_list[index].msg, rpmsg,
- sizeof(struct i2s_rpmsg_s));
+ sizeof(struct i2s_rpmsg_s));
queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work);
i2s_info->work_index++;
i2s_info->work_index %= WORK_MAX_NUM;
@@ -231,41 +339,60 @@ static int imx_rpmsg_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
static void imx_rpmsg_async_issue_pending(struct snd_pcm_substream *substream)
{
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg = &i2s_info->send_msg[substream->stream];
+ struct i2s_rpmsg *rpmsg;
u8 index = i2s_info->work_index;
+ int time_msec;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rpmsg->header.cmd = I2S_TX_START;
+ rpmsg = &i2s_info->rpmsg[I2S_TX_START];
else
- rpmsg->header.cmd = I2S_RX_START;
+ rpmsg = &i2s_info->rpmsg[I2S_RX_START];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_START;
+ else
+ rpmsg->send_msg.header.cmd = I2S_RX_START;
memcpy(&i2s_info->work_list[index].msg, rpmsg,
- sizeof(struct i2s_rpmsg_s));
+ sizeof(struct i2s_rpmsg_s));
queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work);
i2s_info->work_index++;
i2s_info->work_index %= WORK_MAX_NUM;
+
+ if (rpmsg_i2s->force_lpa) {
+ time_msec = min(500,
+ (int)(runtime->period_size*1000/runtime->rate));
+ mod_timer(&i2s_info->stream_timer[substream->stream],
+ jiffies + msecs_to_jiffies(time_msec));
+ }
}
-static int imx_rpmsg_resume(struct snd_pcm_substream *substream)
+static int imx_rpmsg_restart(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg = &i2s_info->send_msg[substream->stream];
+ struct i2s_rpmsg *rpmsg;
u8 index = i2s_info->work_index;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rpmsg->header.cmd = I2S_TX_RESTART;
+ rpmsg = &i2s_info->rpmsg[I2S_TX_RESTART];
+ else
+ rpmsg = &i2s_info->rpmsg[I2S_RX_RESTART];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_RESTART;
else
- rpmsg->header.cmd = I2S_RX_RESTART;
+ rpmsg->send_msg.header.cmd = I2S_RX_RESTART;
memcpy(&i2s_info->work_list[index].msg, rpmsg,
- sizeof(struct i2s_rpmsg_s));
+ sizeof(struct i2s_rpmsg_s));
queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work);
i2s_info->work_index++;
i2s_info->work_index %= WORK_MAX_NUM;
@@ -279,20 +406,24 @@ static int imx_rpmsg_pause(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg = &i2s_info->send_msg[substream->stream];
+ struct i2s_rpmsg *rpmsg;
u8 index = i2s_info->work_index;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rpmsg->header.cmd = I2S_TX_PAUSE;
+ rpmsg = &i2s_info->rpmsg[I2S_TX_PAUSE];
else
- rpmsg->header.cmd = I2S_RX_PAUSE;
+ rpmsg = &i2s_info->rpmsg[I2S_RX_PAUSE];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_PAUSE;
+ else
+ rpmsg->send_msg.header.cmd = I2S_RX_PAUSE;
memcpy(&i2s_info->work_list[index].msg, rpmsg,
- sizeof(struct i2s_rpmsg_s));
+ sizeof(struct i2s_rpmsg_s));
queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work);
i2s_info->work_index++;
i2s_info->work_index %= WORK_MAX_NUM;
-
return 0;
}
@@ -302,26 +433,35 @@ static int imx_rpmsg_terminate_all(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
- struct i2s_rpmsg_s *rpmsg = &i2s_info->send_msg[substream->stream];
+ struct i2s_rpmsg *rpmsg;
u8 index = i2s_info->work_index;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rpmsg->header.cmd = I2S_TX_TERMINATE;
+ rpmsg = &i2s_info->rpmsg[I2S_TX_TERMINATE];
else
- rpmsg->header.cmd = I2S_RX_TERMINATE;
+ rpmsg = &i2s_info->rpmsg[I2S_RX_TERMINATE];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_TERMINATE;
+ else
+ rpmsg->send_msg.header.cmd = I2S_RX_TERMINATE;
memcpy(&i2s_info->work_list[index].msg, rpmsg,
- sizeof(struct i2s_rpmsg_s));
+ sizeof(struct i2s_rpmsg_s));
queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work);
i2s_info->work_index++;
i2s_info->work_index %= WORK_MAX_NUM;
+ del_timer(&i2s_info->stream_timer[substream->stream]);
return 0;
}
int imx_rpmsg_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
int ret;
switch (cmd) {
@@ -332,14 +472,18 @@ int imx_rpmsg_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
imx_rpmsg_async_issue_pending(substream);
break;
case SNDRV_PCM_TRIGGER_RESUME:
+ if (rpmsg_i2s->force_lpa)
+ break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- imx_rpmsg_resume(substream);
+ imx_rpmsg_restart(substream);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
- if (runtime->info & SNDRV_PCM_INFO_PAUSE)
- imx_rpmsg_pause(substream);
- else
- imx_rpmsg_terminate_all(substream);
+ if (!rpmsg_i2s->force_lpa) {
+ if (runtime->info & SNDRV_PCM_INFO_PAUSE)
+ imx_rpmsg_pause(substream);
+ else
+ imx_rpmsg_terminate_all(substream);
+ }
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
imx_rpmsg_pause(substream);
@@ -354,6 +498,50 @@ int imx_rpmsg_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return 0;
}
+int imx_rpmsg_pcm_ack(struct snd_pcm_substream *substream)
+{
+ /*send the hw_avail size through rpmsg*/
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
+ struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
+ struct i2s_rpmsg *rpmsg;
+ u8 index = i2s_info->work_index;
+ int buffer_tail = 0;
+
+ if (!rpmsg_i2s->force_lpa)
+ return 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg = &i2s_info->rpmsg[I2S_TX_PERIOD_DONE + I2S_TYPE_A_NUM];
+ else
+ rpmsg = &i2s_info->rpmsg[I2S_RX_PERIOD_DONE + I2S_TYPE_A_NUM];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ rpmsg->send_msg.header.cmd = I2S_TX_PERIOD_DONE;
+ else
+ rpmsg->send_msg.header.cmd = I2S_RX_PERIOD_DONE;
+
+ rpmsg->send_msg.header.type = I2S_TYPE_C;
+
+ buffer_tail = (frames_to_bytes(runtime, runtime->control->appl_ptr) %
+ snd_pcm_lib_buffer_bytes(substream));
+ buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream);
+
+ if (buffer_tail != rpmsg->send_msg.param.buffer_tail) {
+ rpmsg->send_msg.param.buffer_tail = buffer_tail;
+ memcpy(&i2s_info->work_list[index].msg, rpmsg,
+ sizeof(struct i2s_rpmsg_s));
+ queue_work(i2s_info->rpmsg_wq,
+ &i2s_info->work_list[index].work);
+ i2s_info->work_index++;
+ i2s_info->work_index %= WORK_MAX_NUM;
+ }
+
+ return 0;
+}
+
static struct snd_pcm_ops imx_rpmsg_pcm_ops = {
.open = imx_rpmsg_pcm_open,
.close = imx_rpmsg_pcm_close,
@@ -363,14 +551,15 @@ static struct snd_pcm_ops imx_rpmsg_pcm_ops = {
.trigger = imx_rpmsg_pcm_trigger,
.pointer = imx_rpmsg_pcm_pointer,
.mmap = imx_rpmsg_pcm_mmap,
+ .ack = imx_rpmsg_pcm_ack,
+ .prepare = imx_rpmsg_pcm_prepare,
};
static int imx_rpmsg_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
- int stream)
+ int stream, int size)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = imx_rpmsg_pcm_hardware.buffer_bytes_max;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
@@ -410,6 +599,9 @@ static int imx_rpmsg_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev);
+ struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
int ret;
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
@@ -418,14 +610,16 @@ static int imx_rpmsg_pcm_new(struct snd_soc_pcm_runtime *rtd)
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = imx_rpmsg_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_PLAYBACK);
+ SNDRV_PCM_STREAM_PLAYBACK,
+ i2s_info->prealloc_buffer_size);
if (ret)
goto out;
}
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = imx_rpmsg_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_CAPTURE);
+ SNDRV_PCM_STREAM_CAPTURE,
+ i2s_info->prealloc_buffer_size);
if (ret)
goto out;
}
@@ -458,24 +652,41 @@ static int i2s_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)
{
struct i2s_rpmsg_r *msg = (struct i2s_rpmsg_r *)data;
- struct i2s_rpmsg_s *rpmsg;
+ struct i2s_rpmsg *rpmsg;
unsigned long flags;
- dev_dbg(&rpdev->dev, "get from%d: cmd:%d.\n", src, msg->header.cmd);
+ dev_dbg(&rpdev->dev, "get from%d: cmd:%d. %d\n",
+ src, msg->header.cmd, msg->param.resp);
if (msg->header.type == I2S_TYPE_C) {
if (msg->header.cmd == I2S_TX_PERIOD_DONE) {
spin_lock_irqsave(&i2s_info_g->lock[0], flags);
- rpmsg = &i2s_info_g->send_msg[RPMSG_AUDIO_TX];
- rpmsg->param.buffer_tail++;
- rpmsg->param.buffer_tail %= i2s_info_g->num_period[0];
+ rpmsg = &i2s_info_g->rpmsg[I2S_TX_PERIOD_DONE + I2S_TYPE_A_NUM];
+
+ if (msg->header.major == 1 && msg->header.minor == 2)
+ rpmsg->recv_msg.param.buffer_tail =
+ msg->param.buffer_tail;
+ else
+ rpmsg->recv_msg.param.buffer_tail++;
+
+ rpmsg->recv_msg.param.buffer_tail %=
+ i2s_info_g->num_period[0];
+
spin_unlock_irqrestore(&i2s_info_g->lock[0], flags);
i2s_info_g->callback[0](i2s_info_g->callback_param[0]);
+
} else if (msg->header.cmd == I2S_RX_PERIOD_DONE) {
spin_lock_irqsave(&i2s_info_g->lock[1], flags);
- rpmsg = &i2s_info_g->send_msg[RPMSG_AUDIO_RX];
- rpmsg->param.buffer_tail++;
- rpmsg->param.buffer_tail %= i2s_info_g->num_period[1];
+ rpmsg = &i2s_info_g->rpmsg[I2S_RX_PERIOD_DONE + I2S_TYPE_A_NUM];
+
+ if (msg->header.major == 1 && msg->header.minor == 2)
+ rpmsg->recv_msg.param.buffer_tail =
+ msg->param.buffer_tail;
+ else
+ rpmsg->recv_msg.param.buffer_tail++;
+
+ rpmsg->recv_msg.param.buffer_tail %=
+ i2s_info_g->num_period[1];
spin_unlock_irqrestore(&i2s_info_g->lock[1], flags);
i2s_info_g->callback[1](i2s_info_g->callback_param[1]);
}
@@ -495,6 +706,9 @@ static int i2s_rpmsg_probe(struct rpmsg_device *rpdev)
struct fsl_rpmsg_i2s *rpmsg_i2s = NULL;
int ret;
+ if (!i2s_info_g)
+ return 0;
+
i2s_info_g->rpdev = rpdev;
init_completion(&i2s_info_g->cmd_complete);
@@ -504,13 +718,18 @@ static int i2s_rpmsg_probe(struct rpmsg_device *rpdev)
rpmsg_i2s = container_of(i2s_info_g, struct fsl_rpmsg_i2s, i2s_info);
- codec_pdev = platform_device_register_data(&rpmsg_i2s->pdev->dev,
- RPMSG_CODEC_DRV_NAME, PLATFORM_DEVID_NONE,
- NULL, 0);
- if (IS_ERR(codec_pdev)) {
- dev_err(&rpdev->dev, "failed to register rpmsg audio codec\n");
- ret = PTR_ERR(codec_pdev);
- return ret;
+ if (rpmsg_i2s->codec) {
+ codec_pdev = platform_device_register_data(
+ &rpmsg_i2s->pdev->dev,
+ RPMSG_CODEC_DRV_NAME,
+ PLATFORM_DEVID_NONE,
+ NULL, 0);
+ if (IS_ERR(codec_pdev)) {
+ dev_err(&rpdev->dev,
+ "failed to register rpmsg audio codec\n");
+ ret = PTR_ERR(codec_pdev);
+ return ret;
+ }
}
return 0;