summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/fsl/Kconfig6
-rw-r--r--sound/soc/fsl/fsl_rpmsg_i2s.c68
-rw-r--r--sound/soc/fsl/fsl_rpmsg_i2s.h16
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c307
-rw-r--r--sound/soc/fsl/imx-rpmsg.c28
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;