summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/imx-pcm-rpmsg.c
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@nxp.com>2018-07-25 13:43:05 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:53:01 +0800
commitc17407c2ddbea76a5c0e0d3a60feb0c98d159d71 (patch)
tree09142d5c76788926a9842ccc99a955bbb0bd3f0d /sound/soc/fsl/imx-pcm-rpmsg.c
parent093cb51e6f5378402280a4d0d9179d72edc1a68f (diff)
MLK-19042-2: ASoC: imx-pcm-rpmsg: support low power audio
Add ack function, which is to info M4 side how many data has been writen to buffer. Add timer, which is to get the position of hw pointer in m4. Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Reviewed-by: Viorel Suman <viorel.suman@nxp.com> (cherry picked from commit 0fd349fbab28d97f8c5501ec635bff053e3b1470)
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;