diff options
author | Shengjiu Wang <shengjiu.wang@nxp.com> | 2019-03-07 11:01:06 +0800 |
---|---|---|
committer | Dong Aisheng <aisheng.dong@nxp.com> | 2019-11-25 15:53:20 +0800 |
commit | 26e4c3d80f3ce07dbe5732009b4e6a46ec370966 (patch) | |
tree | 588fe473a6683085e52b868bf1b0fbc695be1f69 | |
parent | b3b38fea22b1a929830ffb5576d1d4a1a53b0b00 (diff) |
ASoC: fsl_rpmsg: Merge changes from imx_4.19.y
77be7d36a525 ("MLK-22400-1: ASoC: fsl_rpmsg_i2s: Add rpmsg i2s for imx8mn")
31d5dfa44c20 ("MLK-22340-5: ASoC: imx-pcm-rpmsg: enable ignore_suspend for LPA")
c5c41138d5c8 ("MLK-22340-4: ASoC: fsl_rpmsg_i2s: add lock to protect the resource")
adb4b596d2ba ("MLK-22340-3: ASoC: imx-pcm-rpmsg: refine the timer")
a5e80bf012c3 ("MLK-22340-2: ASoC: imx-pcm-rpmsg: drop the cmd I2S_TX_POINTER")
404367d9316b ("MLK-21980: ASoC: imx-pcm-rpmsg: add debugfs_prefix for platform")
971faf095246 ("MLK-21450: ASoC: fsl_rpmsg: fix timer issue for updating to 4.19")
edbbcdc07bf1 ("MLK-21461: ASoC: fsl_rpmsg_i2s: clear buffer pointer in i2s_send_message")
f5f2f38018d8 ("MLK-21447: ASoC: fsl_rpmsg_i2s: underrun in m4 for msg delayed")
d9410ace757f ("MLK-21307: ASoC: fsl_rpmsg_i2s: optimize the message sent to m4")
98633a4cd35b ("MLK-21440-1: ASoC: fsl_rpmsg_i2s: init spin lock")
7bf6d3131863 ("MLK-21107-1: ASoC: Fix timer wake up system after suspend")
eb422681ffa4 ("MLK-20661: ASoC: imx-pcm-rpmsg: remove the nonblock constraint")
e36957e97ca9 ("MLK-21002-1: ASoC: imx-pcm-rpmsg: fix data consumed faster with pause")
bc828e61693f ("MLK-19565-1: ASoC: fsl_rpmsg_i2s: support rpmsg on imx8qm")
e56bedf71ae4 ("MLK-21107-2: ASoC: Drop msg if msg queue is full")
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
(cherry picked from commit 31def064871336af7780d01a6ed8c5ed075b7e48)
-rw-r--r-- | sound/soc/fsl/Kconfig | 6 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_rpmsg_i2s.c | 68 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_rpmsg_i2s.h | 16 | ||||
-rw-r--r-- | sound/soc/fsl/imx-pcm-rpmsg.c | 307 | ||||
-rw-r--r-- | sound/soc/fsl/imx-rpmsg.c | 28 |
5 files changed, 287 insertions, 138 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 00b5db8898d3..1409bd27d7cc 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -76,7 +76,7 @@ config SND_SOC_FSL_MICFIL config SND_SOC_FSL_RPMSG_I2S tristate "I2S base on the RPMSG support" - depends on CONFIG_HAVE_IMX_RPMSG + depends on HAVE_IMX_RPMSG help Say Y if you want to add rpmsg i2s support for the Freescale CPUs. which is depends on the rpmsg. @@ -92,7 +92,7 @@ config SND_SOC_IMX_PCM_DMA config SND_SOC_IMX_PCM_RPMSG tristate - depends on CONFIG_HAVE_IMX_RPMSG + depends on HAVE_IMX_RPMSG select SND_SOC_GENERIC_DMAENGINE_PCM config SND_SOC_IMX_AUDMUX @@ -265,7 +265,7 @@ config SND_SOC_EUKREA_TLV320 config SND_SOC_IMX_RPMSG tristate "SoC Audio support for i.MX boards with rpmsg" - depends on CONFIG_HAVE_IMX_RPMSG + depends on HAVE_IMX_RPMSG select SND_SOC_IMX_PCM_RPMSG select SND_SOC_FSL_RPMSG_I2S select SND_SOC_RPMSG_WM8960 diff --git a/sound/soc/fsl/fsl_rpmsg_i2s.c b/sound/soc/fsl/fsl_rpmsg_i2s.c index c94212dfb48f..4ba151186681 100644 --- a/sound/soc/fsl/fsl_rpmsg_i2s.c +++ b/sound/soc/fsl/fsl_rpmsg_i2s.c @@ -70,6 +70,25 @@ static int i2s_send_message(struct i2s_rpmsg *msg, sizeof(struct i2s_rpmsg_r)); memcpy(&info->rpmsg[msg->recv_msg.header.cmd].recv_msg, &msg->recv_msg, sizeof(struct i2s_rpmsg_r)); + + /* + * Reset the buffer pointer to be zero, actully we have + * set the buffer pointer to be zero in imx_rpmsg_terminate_all + * But if there is timer task queued in queue, after it is + * executed the buffer pointer will be changed, so need to + * reset it again with TERMINATE command. + */ + + switch (msg->send_msg.header.cmd) { + case I2S_TX_TERMINATE: + info->rpmsg[I2S_TX_POINTER].recv_msg.param.buffer_offset = 0; + break; + case I2S_RX_TERMINATE: + info->rpmsg[I2S_RX_POINTER].recv_msg.param.buffer_offset = 0; + break; + default: + break; + } } dev_dbg(&info->rpdev->dev, "cmd:%d, resp %d\n", @@ -136,6 +155,7 @@ static const struct of_device_id fsl_rpmsg_i2s_ids[] = { { .compatible = "fsl,imx8mq-rpmsg-i2s"}, { .compatible = "fsl,imx8qxp-rpmsg-i2s"}, { .compatible = "fsl,imx8qm-rpmsg-i2s"}, + { .compatible = "fsl,imx8mn-rpmsg-i2s"}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_rpmsg_i2s_ids); @@ -144,11 +164,40 @@ static void rpmsg_i2s_work(struct work_struct *work) { struct work_of_rpmsg *work_of_rpmsg; struct i2s_info *i2s_info; + bool is_period_done = false; + unsigned long flags; + struct i2s_rpmsg msg; work_of_rpmsg = container_of(work, struct work_of_rpmsg, work); i2s_info = work_of_rpmsg->i2s_info; - i2s_send_message(&work_of_rpmsg->msg, i2s_info); + spin_lock_irqsave(&i2s_info->lock[0], flags); + if (i2s_info->period_done_msg_enabled[0]) { + memcpy(&msg, &i2s_info->period_done_msg[0], sizeof(struct i2s_rpmsg_s)); + i2s_info->period_done_msg_enabled[0] = false; + spin_unlock_irqrestore(&i2s_info->lock[0], flags); + + i2s_send_message(&msg, i2s_info); + } else + spin_unlock_irqrestore(&i2s_info->lock[0], flags); + + if (i2s_info->period_done_msg_enabled[1]) { + i2s_send_message(&i2s_info->period_done_msg[1], i2s_info); + i2s_info->period_done_msg_enabled[1] = false; + } + + if (work_of_rpmsg->msg.send_msg.header.type == I2S_TYPE_C && + (work_of_rpmsg->msg.send_msg.header.cmd == I2S_TX_PERIOD_DONE || + work_of_rpmsg->msg.send_msg.header.cmd == I2S_RX_PERIOD_DONE)) + is_period_done = true; + + if (!is_period_done) + i2s_send_message(&work_of_rpmsg->msg, i2s_info); + + spin_lock_irqsave(&i2s_info->wq_lock, flags); + i2s_info->work_read_index++; + i2s_info->work_read_index %= WORK_MAX_NUM; + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); } static int fsl_rpmsg_i2s_probe(struct platform_device *pdev) @@ -179,6 +228,7 @@ static int fsl_rpmsg_i2s_probe(struct platform_device *pdev) return -ENOMEM; } + i2s_info->work_write_index = 1; i2s_info->send_message = i2s_send_message; for (i = 0; i < WORK_MAX_NUM; i++) { @@ -198,6 +248,7 @@ static int fsl_rpmsg_i2s_probe(struct platform_device *pdev) mutex_init(&i2s_info->i2c_lock); spin_lock_init(&i2s_info->lock[0]); spin_lock_init(&i2s_info->lock[1]); + spin_lock_init(&i2s_info->wq_lock); if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx7ulp-rpmsg-i2s")) { @@ -246,6 +297,21 @@ static int fsl_rpmsg_i2s_probe(struct platform_device *pdev) fsl_rpmsg_i2s_dai.capture.formats = rpmsg_i2s->formats; } + if (of_device_is_compatible(pdev->dev.of_node, + "fsl,imx8mn-rpmsg-i2s")) { + rpmsg_i2s->codec_dummy = 1; + rpmsg_i2s->version = 2; + rpmsg_i2s->rates = SNDRV_PCM_RATE_KNOT; + rpmsg_i2s->formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE; + + fsl_rpmsg_i2s_dai.playback.rates = rpmsg_i2s->rates; + fsl_rpmsg_i2s_dai.playback.formats = rpmsg_i2s->formats; + fsl_rpmsg_i2s_dai.capture.rates = rpmsg_i2s->rates; + fsl_rpmsg_i2s_dai.capture.formats = rpmsg_i2s->formats; + } + if (of_property_read_bool(pdev->dev.of_node, "fsl,enable-lpa")) rpmsg_i2s->enable_lpa = 1; diff --git a/sound/soc/fsl/fsl_rpmsg_i2s.h b/sound/soc/fsl/fsl_rpmsg_i2s.h index 36d6c5f51360..e42986ca14ff 100644 --- a/sound/soc/fsl/fsl_rpmsg_i2s.h +++ b/sound/soc/fsl/fsl_rpmsg_i2s.h @@ -309,7 +309,7 @@ #define I2S_TYPE_A_NUM 0x18 -#define WORK_MAX_NUM 0x18 +#define WORK_MAX_NUM 0x30 #define I2S_TX_PERIOD_DONE 0x0 #define I2S_RX_PERIOD_DONE 0x1 @@ -384,6 +384,11 @@ struct work_of_rpmsg { struct work_struct work; }; +struct stream_timer { + struct timer_list timer; + struct snd_pcm_substream *substream; +}; + typedef void (*dma_callback)(void *arg); struct i2s_info { struct rpmsg_device *rpdev; @@ -394,18 +399,23 @@ struct i2s_info { struct i2s_rpmsg_r recv_msg; struct i2s_rpmsg rpmsg[I2S_CMD_MAX_NUM]; + struct i2s_rpmsg period_done_msg[2]; + bool period_done_msg_enabled[2]; struct workqueue_struct *rpmsg_wq; struct work_of_rpmsg work_list[WORK_MAX_NUM]; - int work_index; + int work_write_index; + int work_read_index; + int msg_drop_count[2]; int num_period[2]; void *callback_param[2]; int (*send_message)(struct i2s_rpmsg *msg, struct i2s_info *info); dma_callback callback[2]; spinlock_t lock[2]; + spinlock_t wq_lock; struct mutex tx_lock; struct mutex i2c_lock; - struct timer_list stream_timer[2]; + struct stream_timer stream_timer[2]; int prealloc_buffer_size; }; diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index e46b80a51411..f49205a6c41a 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -24,6 +24,8 @@ #include "fsl_rpmsg_i2s.h" #include "../../core/pcm_local.h" +#define DRV_NAME "imx_pcm_rpmsg" + struct i2s_info *i2s_info_g; static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = { @@ -107,53 +109,49 @@ static snd_pcm_uframes_t imx_rpmsg_pcm_pointer( int buffer_tail = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rpmsg = &i2s_info->rpmsg[I2S_TX_POINTER]; + rpmsg = &i2s_info->rpmsg[I2S_TX_PERIOD_DONE + I2S_TYPE_A_NUM]; else - rpmsg = &i2s_info->rpmsg[I2S_RX_POINTER]; + rpmsg = &i2s_info->rpmsg[I2S_RX_PERIOD_DONE + I2S_TYPE_A_NUM]; - buffer_tail = rpmsg->recv_msg.param.buffer_offset / - snd_pcm_lib_period_bytes(substream); + buffer_tail = rpmsg->recv_msg.param.buffer_tail; 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) +static void imx_rpmsg_timer_callback(struct timer_list *t) { - struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; - struct snd_pcm_runtime *runtime = substream->runtime; + struct stream_timer *stream_timer = + from_timer(stream_timer, t, timer); + struct snd_pcm_substream *substream = stream_timer->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 *rpmsg; - u8 index = i2s_info->work_index; - int time_msec; + unsigned long flags; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rpmsg = &i2s_info->rpmsg[I2S_TX_POINTER]; + rpmsg = &i2s_info->rpmsg[I2S_TX_PERIOD_DONE + I2S_TYPE_A_NUM]; else - rpmsg = &i2s_info->rpmsg[I2S_RX_POINTER]; + 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_POINTER; + rpmsg->send_msg.header.cmd = I2S_TX_PERIOD_DONE; else - rpmsg->send_msg.header.cmd = I2S_RX_POINTER; + rpmsg->send_msg.header.cmd = I2S_RX_PERIOD_DONE; - memcpy(&i2s_info->work_list[index].msg, rpmsg, + spin_lock_irqsave(&i2s_info->wq_lock, flags); + if (i2s_info->work_write_index != i2s_info->work_read_index) { + int index = i2s_info->work_write_index; + 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)); - } - - snd_pcm_period_elapsed(substream); + queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work); + i2s_info->work_write_index++; + i2s_info->work_write_index %= WORK_MAX_NUM; + } else + i2s_info->msg_drop_count[substream->stream]++; + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); } static int imx_rpmsg_pcm_open(struct snd_pcm_substream *substream) @@ -209,10 +207,13 @@ static int imx_rpmsg_pcm_open(struct snd_pcm_substream *substream) if (ret < 0) return ret; + i2s_info->msg_drop_count[substream->stream] = 0; /*create thread*/ - setup_timer(&i2s_info->stream_timer[substream->stream], - imx_rpmsg_timer_callback, (unsigned long)substream); + i2s_info->stream_timer[substream->stream].substream = substream; + + timer_setup(&i2s_info->stream_timer[substream->stream].timer, + imx_rpmsg_timer_callback, 0); return ret; } @@ -240,10 +241,16 @@ static int imx_rpmsg_pcm_close(struct snd_pcm_substream *substream) flush_workqueue(i2s_info->rpmsg_wq); i2s_info->send_message(rpmsg, i2s_info); - del_timer(&i2s_info->stream_timer[substream->stream]); + del_timer(&i2s_info->stream_timer[substream->stream].timer); kfree(prtd); + rtd->dai_link->ignore_suspend = 0; + + if (i2s_info->msg_drop_count[substream->stream]) + dev_warn(rtd->dev, "Msg is dropped!, number is %d\n", + i2s_info->msg_drop_count[substream->stream]); + return ret; } @@ -260,9 +267,10 @@ static int imx_rpmsg_pcm_prepare(struct snd_pcm_substream *substream) if ((runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) && rpmsg_i2s->version == 2 && - rpmsg_i2s->enable_lpa) + rpmsg_i2s->enable_lpa) { + rtd->dai_link->ignore_suspend = 1; rpmsg_i2s->force_lpa = 1; - else + } else rpmsg_i2s->force_lpa = 0; return 0; @@ -282,40 +290,7 @@ 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 snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - 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]; - } - - rpmsg->recv_msg.param.buffer_offset = - rpmsg2->recv_msg.param.buffer_tail - * snd_pcm_lib_period_bytes(substream); - /* - * With suspend state, which is not running state, M4 will trigger - * system resume with PERIOD_DONE command, at this moment, the - * snd_pcm_period_elapsed can't update the hw ptr. so change the - * state to be running and update timer - * - */ - if (!snd_pcm_running(substream) && rpmsg_i2s->force_lpa) { - int time_msec; - - substream->runtime->status->state = SNDRV_PCM_STATE_RUNNING; - 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)); - } snd_pcm_period_elapsed(substream); } @@ -326,7 +301,7 @@ static int imx_rpmsg_pcm_prepare_and_submit(struct snd_pcm_substream *substream) 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; + unsigned long flags; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) rpmsg = &i2s_info->rpmsg[I2S_TX_BUFFER]; @@ -348,27 +323,34 @@ static int imx_rpmsg_pcm_prepare_and_submit(struct snd_pcm_substream *substream) 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)); - queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work); - i2s_info->work_index++; - i2s_info->work_index %= WORK_MAX_NUM; - i2s_info->callback[substream->stream] = imx_rpmsg_pcm_dma_complete; i2s_info->callback_param[substream->stream] = substream; + + spin_lock_irqsave(&i2s_info->wq_lock, flags); + if (i2s_info->work_write_index != i2s_info->work_read_index) { + int index = i2s_info->work_write_index; + 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_write_index++; + i2s_info->work_write_index %= WORK_MAX_NUM; + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + } else { + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + return -EPIPE; + } + return 0; } -static void imx_rpmsg_async_issue_pending(struct snd_pcm_substream *substream) +static int 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 *rpmsg; - u8 index = i2s_info->work_index; - int time_msec; + unsigned long flags; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) rpmsg = &i2s_info->rpmsg[I2S_TX_START]; @@ -380,18 +362,21 @@ static void imx_rpmsg_async_issue_pending(struct snd_pcm_substream *substream) else rpmsg->send_msg.header.cmd = I2S_RX_START; - 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)); + spin_lock_irqsave(&i2s_info->wq_lock, flags); + if (i2s_info->work_write_index != i2s_info->work_read_index) { + int index = i2s_info->work_write_index; + 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_write_index++; + i2s_info->work_write_index %= WORK_MAX_NUM; + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + } else { + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + return -EPIPE; } + + return 0; } static int imx_rpmsg_restart(struct snd_pcm_substream *substream) @@ -401,7 +386,7 @@ static int imx_rpmsg_restart(struct snd_pcm_substream *substream) 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; + unsigned long flags; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) rpmsg = &i2s_info->rpmsg[I2S_TX_RESTART]; @@ -413,12 +398,19 @@ static int imx_rpmsg_restart(struct snd_pcm_substream *substream) else rpmsg->send_msg.header.cmd = I2S_RX_RESTART; - memcpy(&i2s_info->work_list[index].msg, rpmsg, + spin_lock_irqsave(&i2s_info->wq_lock, flags); + if (i2s_info->work_write_index != i2s_info->work_read_index) { + int index = i2s_info->work_write_index; + 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; - + queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work); + i2s_info->work_write_index++; + i2s_info->work_write_index %= WORK_MAX_NUM; + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + } else { + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + return -EPIPE; + } return 0; } @@ -429,7 +421,7 @@ static int imx_rpmsg_pause(struct snd_pcm_substream *substream) 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; + unsigned long flags; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) rpmsg = &i2s_info->rpmsg[I2S_TX_PAUSE]; @@ -441,11 +433,19 @@ static int imx_rpmsg_pause(struct snd_pcm_substream *substream) else rpmsg->send_msg.header.cmd = I2S_RX_PAUSE; - 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; + spin_lock_irqsave(&i2s_info->wq_lock, flags); + if (i2s_info->work_write_index != i2s_info->work_read_index) { + int index = i2s_info->work_write_index; + 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_write_index++; + i2s_info->work_write_index %= WORK_MAX_NUM; + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + } else { + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + return -EPIPE; + } return 0; } @@ -456,8 +456,8 @@ static int imx_rpmsg_terminate_all(struct snd_pcm_substream *substream) 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 cmd; + unsigned long flags; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) rpmsg = &i2s_info->rpmsg[I2S_TX_TERMINATE]; @@ -469,12 +469,6 @@ static int imx_rpmsg_terminate_all(struct snd_pcm_substream *substream) else rpmsg->send_msg.header.cmd = I2S_RX_TERMINATE; - 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 (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; @@ -487,7 +481,22 @@ static int imx_rpmsg_terminate_all(struct snd_pcm_substream *substream) i2s_info->rpmsg[I2S_RX_POINTER].recv_msg.param.buffer_offset = 0; } - del_timer(&i2s_info->stream_timer[substream->stream]); + del_timer(&i2s_info->stream_timer[substream->stream].timer); + + spin_lock_irqsave(&i2s_info->wq_lock, flags); + if (i2s_info->work_write_index != i2s_info->work_read_index) { + int index = i2s_info->work_write_index; + 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_write_index++; + i2s_info->work_write_index %= WORK_MAX_NUM; + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + } else { + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + return -EPIPE; + } + return 0; } @@ -497,41 +506,43 @@ int imx_rpmsg_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 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; - int ret; + int ret = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: ret = imx_rpmsg_pcm_prepare_and_submit(substream); if (ret) return ret; - imx_rpmsg_async_issue_pending(substream); + ret = imx_rpmsg_async_issue_pending(substream); break; case SNDRV_PCM_TRIGGER_RESUME: if (rpmsg_i2s->force_lpa) break; + /* fall through */ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - imx_rpmsg_restart(substream); + ret = imx_rpmsg_restart(substream); break; case SNDRV_PCM_TRIGGER_SUSPEND: if (!rpmsg_i2s->force_lpa) { if (runtime->info & SNDRV_PCM_INFO_PAUSE) - imx_rpmsg_pause(substream); + ret = imx_rpmsg_pause(substream); else - imx_rpmsg_terminate_all(substream); - } else - del_timer(&i2s_info->stream_timer[substream->stream]); + ret = imx_rpmsg_terminate_all(substream); + } break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - imx_rpmsg_pause(substream); + ret = imx_rpmsg_pause(substream); break; case SNDRV_PCM_TRIGGER_STOP: - imx_rpmsg_terminate_all(substream); + ret = imx_rpmsg_terminate_all(substream); break; default: return -EINVAL; } + if (ret) + return ret; + return 0; } @@ -544,8 +555,10 @@ int imx_rpmsg_pcm_ack(struct snd_pcm_substream *substream) 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; + int writen_num = 0; + snd_pcm_sframes_t avail; + unsigned long flags; if (!rpmsg_i2s->force_lpa) return 0; @@ -567,13 +580,45 @@ int imx_rpmsg_pcm_ack(struct snd_pcm_substream *substream) buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream); if (buffer_tail != rpmsg->send_msg.param.buffer_tail) { + writen_num = buffer_tail - rpmsg->send_msg.param.buffer_tail; + if (writen_num < 0) + writen_num += runtime->periods; + rpmsg->send_msg.param.buffer_tail = buffer_tail; - memcpy(&i2s_info->work_list[index].msg, rpmsg, + + spin_lock_irqsave(&i2s_info->lock[substream->stream], flags); + memcpy(&i2s_info->period_done_msg[substream->stream], rpmsg, + sizeof(struct i2s_rpmsg_s)); + + i2s_info->period_done_msg_enabled[substream->stream] = true; + spin_unlock_irqrestore(&i2s_info->lock[substream->stream], flags); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + avail = snd_pcm_playback_hw_avail(runtime); + else + avail = snd_pcm_capture_hw_avail(runtime); + + if ((avail - writen_num * runtime->period_size) <= runtime->period_size) { + spin_lock_irqsave(&i2s_info->wq_lock, flags); + if (i2s_info->work_write_index != i2s_info->work_read_index) { + int index = i2s_info->work_write_index; + memcpy(&i2s_info->work_list[index].msg, rpmsg, sizeof(struct i2s_rpmsg_s)); - queue_work(i2s_info->rpmsg_wq, + queue_work(i2s_info->rpmsg_wq, &i2s_info->work_list[index].work); - i2s_info->work_index++; - i2s_info->work_index %= WORK_MAX_NUM; + i2s_info->work_write_index++; + i2s_info->work_write_index %= WORK_MAX_NUM; + } else + i2s_info->msg_drop_count[substream->stream]++; + spin_unlock_irqrestore(&i2s_info->wq_lock, flags); + } else { + if (rpmsg_i2s->force_lpa && !timer_pending(&i2s_info->stream_timer[substream->stream].timer)) { + int time_msec; + time_msec = (int)(runtime->period_size*1000/runtime->rate); + mod_timer(&i2s_info->stream_timer[substream->stream].timer, + jiffies + msecs_to_jiffies(time_msec)); + } + } } return 0; @@ -669,7 +714,8 @@ out: return ret; } -static struct snd_soc_platform_driver imx_rpmsg_soc_platform = { +static struct snd_soc_component_driver imx_rpmsg_soc_component = { + .name = DRV_NAME, .ops = &imx_rpmsg_pcm_ops, .pcm_new = imx_rpmsg_pcm_new, .pcm_free = imx_rpmsg_pcm_free_dma_buffers, @@ -678,10 +724,25 @@ static struct snd_soc_platform_driver imx_rpmsg_soc_platform = { int imx_rpmsg_platform_register(struct device *dev) { struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(dev); + struct snd_soc_component *component; + int ret; i2s_info_g = &rpmsg_i2s->i2s_info; - return devm_snd_soc_register_platform(dev, &imx_rpmsg_soc_platform); + ret = devm_snd_soc_register_component(dev, &imx_rpmsg_soc_component, + NULL, 0); + if (ret) + return ret; + + component = snd_soc_lookup_component(dev, DRV_NAME); + if (!component) + return -EINVAL; + +#ifdef CONFIG_DEBUG_FS + component->debugfs_prefix = "dma"; +#endif + + return 0; } EXPORT_SYMBOL_GPL(imx_rpmsg_platform_register); diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index ad9e4c322de9..9db5f190bc4f 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -42,8 +42,13 @@ static int imx_rpmsg_probe(struct platform_device *pdev) struct platform_device *cpu_pdev; struct imx_rpmsg_data *data; struct fsl_rpmsg_i2s *rpmsg_i2s; + struct snd_soc_dai_link_component *dlc; int ret; + dlc = devm_kzalloc(&pdev->dev, 3 * sizeof(*dlc), GFP_KERNEL); + if (!dlc) + return -ENOMEM; + cpu_np = of_parse_phandle(pdev->dev.of_node, "cpu-dai", 0); if (!cpu_np) { dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n"); @@ -66,6 +71,13 @@ static int imx_rpmsg_probe(struct platform_device *pdev) rpmsg_i2s = platform_get_drvdata(cpu_pdev); + data->dai[0].cpus = &dlc[0]; + data->dai[0].num_cpus = 1; + data->dai[0].platforms = &dlc[1]; + data->dai[0].num_platforms = 1; + data->dai[0].codecs = &dlc[2]; + data->dai[0].num_codecs = 1; + data->dai[0].name = "rpmsg hifi"; data->dai[0].stream_name = "rpmsg hifi"; data->dai[0].dai_fmt = SND_SOC_DAIFMT_I2S | @@ -73,25 +85,25 @@ static int imx_rpmsg_probe(struct platform_device *pdev) SND_SOC_DAIFMT_CBM_CFM; if (rpmsg_i2s->codec_wm8960) { - data->dai[0].codec_dai_name = "rpmsg-wm8960-hifi"; - data->dai[0].codec_name = "rpmsg-audio-codec-wm8960"; + data->dai[0].codecs->dai_name = "rpmsg-wm8960-hifi"; + data->dai[0].codecs->name = "rpmsg-audio-codec-wm8960"; } if (rpmsg_i2s->codec_dummy) { - data->dai[0].codec_dai_name = "snd-soc-dummy-dai"; - data->dai[0].codec_name = "snd-soc-dummy"; + data->dai[0].codecs->dai_name = "snd-soc-dummy-dai"; + data->dai[0].codecs->name = "snd-soc-dummy"; } if (rpmsg_i2s->codec_ak4497) { - data->dai[0].codec_dai_name = "rpmsg-ak4497-aif"; - data->dai[0].codec_name = "rpmsg-audio-codec-ak4497"; + data->dai[0].codecs->dai_name = "rpmsg-ak4497-aif"; + data->dai[0].codecs->name = "rpmsg-audio-codec-ak4497"; data->dai[0].dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; } - data->dai[0].cpu_dai_name = dev_name(&cpu_pdev->dev); - data->dai[0].platform_of_node = cpu_np; + data->dai[0].cpus->dai_name = dev_name(&cpu_pdev->dev); + data->dai[0].platforms->of_node = cpu_np; data->dai[0].playback_only = true; data->dai[0].capture_only = true; data->card.num_links = 1; |