1
0
Fork 0

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)
5.4-rM2-2.2.x-imx-squashed
Shengjiu Wang 2019-03-07 11:01:06 +08:00 committed by Dong Aisheng
parent b3b38fea22
commit 26e4c3d80f
5 changed files with 287 additions and 138 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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);

View File

@ -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;