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
parent
b3b38fea22
commit
26e4c3d80f
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue