2017-02-14 20:28:36 -07:00
|
|
|
/*
|
|
|
|
* Freescale ALSA SoC rpmsg i2s driver.
|
|
|
|
*
|
|
|
|
* Copyright 2017 NXP
|
|
|
|
*
|
|
|
|
* This program is free software, you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation, either version 2 of the License, or(at your
|
|
|
|
* option) any later version.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/dmaengine.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/of_device.h>
|
|
|
|
#include <linux/of_address.h>
|
|
|
|
#include <linux/pm_runtime.h>
|
|
|
|
#include <linux/rpmsg.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
|
|
#include <sound/core.h>
|
|
|
|
#include <sound/dmaengine_pcm.h>
|
|
|
|
#include <sound/pcm_params.h>
|
|
|
|
|
|
|
|
#include "fsl_rpmsg_i2s.h"
|
|
|
|
#include "imx-pcm.h"
|
|
|
|
|
2017-02-16 19:11:35 -07:00
|
|
|
#define FSL_RPMSG_I2S_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
|
|
|
|
SNDRV_PCM_RATE_48000)
|
2017-02-14 20:28:36 -07:00
|
|
|
#define FSL_RPMSG_I2S_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
static int i2s_send_message(struct i2s_rpmsg *msg,
|
2017-02-14 20:28:36 -07:00
|
|
|
struct i2s_info *info)
|
|
|
|
{
|
2018-07-24 23:42:50 -06:00
|
|
|
int err = 0;
|
2017-02-14 20:28:36 -07:00
|
|
|
|
2017-12-14 05:03:51 -07:00
|
|
|
mutex_lock(&info->tx_lock);
|
2017-02-14 20:28:36 -07:00
|
|
|
if (!info->rpdev) {
|
2018-03-05 21:45:22 -07:00
|
|
|
dev_err(info->dev, "rpmsg channel not ready, m4 image ready?\n");
|
2017-12-14 05:03:51 -07:00
|
|
|
mutex_unlock(&info->tx_lock);
|
2017-02-14 20:28:36 -07:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
dev_dbg(&info->rpdev->dev, "send cmd %d\n", msg->send_msg.header.cmd);
|
2017-02-14 20:28:36 -07:00
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
if (!(msg->send_msg.header.type == I2S_TYPE_C))
|
|
|
|
reinit_completion(&info->cmd_complete);
|
|
|
|
|
|
|
|
err = rpmsg_send(info->rpdev->ept, (void *)&msg->send_msg,
|
2017-02-14 20:28:36 -07:00
|
|
|
sizeof(struct i2s_rpmsg_s));
|
|
|
|
if (err) {
|
|
|
|
dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
|
2017-12-12 05:07:34 -07:00
|
|
|
mutex_unlock(&info->tx_lock);
|
2017-02-14 20:28:36 -07:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
if (!(msg->send_msg.header.type == I2S_TYPE_C)) {
|
|
|
|
/* wait response from rpmsg */
|
|
|
|
err = wait_for_completion_timeout(&info->cmd_complete,
|
2017-02-14 20:28:36 -07:00
|
|
|
msecs_to_jiffies(RPMSG_TIMEOUT));
|
2018-07-24 23:42:50 -06:00
|
|
|
if (!err) {
|
|
|
|
dev_err(&info->rpdev->dev,
|
|
|
|
"rpmsg_send cmd %d timeout!\n",
|
|
|
|
msg->send_msg.header.cmd);
|
|
|
|
mutex_unlock(&info->tx_lock);
|
|
|
|
return -ETIMEDOUT;
|
|
|
|
}
|
|
|
|
memcpy(&msg->recv_msg, &info->recv_msg,
|
|
|
|
sizeof(struct i2s_rpmsg_r));
|
|
|
|
memcpy(&info->rpmsg[msg->recv_msg.header.cmd].recv_msg,
|
|
|
|
&msg->recv_msg, sizeof(struct i2s_rpmsg_r));
|
2019-03-06 20:01:06 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
2017-02-14 20:28:36 -07:00
|
|
|
}
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
dev_dbg(&info->rpdev->dev, "cmd:%d, resp %d\n",
|
|
|
|
msg->send_msg.header.cmd,
|
2017-02-14 20:28:36 -07:00
|
|
|
info->recv_msg.param.resp);
|
|
|
|
mutex_unlock(&info->tx_lock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-13 23:15:27 -06:00
|
|
|
static const unsigned int fsl_rpmsg_rates[] = {
|
2018-11-20 23:20:36 -07:00
|
|
|
8000, 11025, 16000, 22050, 44100,
|
2018-09-13 23:15:27 -06:00
|
|
|
32000, 48000, 96000, 88200, 176400, 192000,
|
|
|
|
352800, 384000, 705600, 768000, 1411200, 2822400,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct snd_pcm_hw_constraint_list fsl_rpmsg_rate_constraints = {
|
|
|
|
.count = ARRAY_SIZE(fsl_rpmsg_rates),
|
|
|
|
.list = fsl_rpmsg_rates,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int fsl_rpmsg_startup(struct snd_pcm_substream *substream,
|
|
|
|
struct snd_soc_dai *cpu_dai)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
|
|
|
|
SNDRV_PCM_HW_PARAM_RATE, &fsl_rpmsg_rate_constraints);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct snd_soc_dai_ops fsl_rpmsg_dai_ops = {
|
|
|
|
.startup = fsl_rpmsg_startup,
|
|
|
|
};
|
|
|
|
|
2017-02-14 20:28:36 -07:00
|
|
|
static struct snd_soc_dai_driver fsl_rpmsg_i2s_dai = {
|
|
|
|
.playback = {
|
|
|
|
.stream_name = "CPU-Playback",
|
2017-02-20 00:44:40 -07:00
|
|
|
.channels_min = 2,
|
2017-02-14 20:28:36 -07:00
|
|
|
.channels_max = 2,
|
2018-09-13 23:15:27 -06:00
|
|
|
.rates = SNDRV_PCM_RATE_KNOT,
|
2017-02-14 20:28:36 -07:00
|
|
|
.formats = FSL_RPMSG_I2S_FORMATS,
|
|
|
|
},
|
|
|
|
.capture = {
|
|
|
|
.stream_name = "CPU-Capture",
|
2017-02-20 00:44:40 -07:00
|
|
|
.channels_min = 2,
|
2017-02-14 20:28:36 -07:00
|
|
|
.channels_max = 2,
|
2018-09-13 23:15:27 -06:00
|
|
|
.rates = SNDRV_PCM_RATE_KNOT,
|
2017-02-14 20:28:36 -07:00
|
|
|
.formats = FSL_RPMSG_I2S_FORMATS,
|
|
|
|
},
|
|
|
|
.symmetric_rates = 1,
|
|
|
|
.symmetric_channels = 1,
|
|
|
|
.symmetric_samplebits = 1,
|
2018-09-13 23:15:27 -06:00
|
|
|
.ops = &fsl_rpmsg_dai_ops,
|
2017-02-14 20:28:36 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct snd_soc_component_driver fsl_component = {
|
|
|
|
.name = "fsl-rpmsg-i2s",
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct of_device_id fsl_rpmsg_i2s_ids[] = {
|
|
|
|
{ .compatible = "fsl,imx7ulp-rpmsg-i2s"},
|
2018-07-24 23:42:50 -06:00
|
|
|
{ .compatible = "fsl,imx8mq-rpmsg-i2s"},
|
2018-08-08 01:07:43 -06:00
|
|
|
{ .compatible = "fsl,imx8qxp-rpmsg-i2s"},
|
2018-09-12 23:07:47 -06:00
|
|
|
{ .compatible = "fsl,imx8qm-rpmsg-i2s"},
|
2019-03-06 20:01:06 -07:00
|
|
|
{ .compatible = "fsl,imx8mn-rpmsg-i2s"},
|
2020-03-29 23:57:34 -06:00
|
|
|
{ .compatible = "fsl,imx8mp-rpmsg-i2s"},
|
2017-02-14 20:28:36 -07:00
|
|
|
{ /* sentinel */ }
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(of, fsl_rpmsg_i2s_ids);
|
|
|
|
|
|
|
|
static void rpmsg_i2s_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct work_of_rpmsg *work_of_rpmsg;
|
|
|
|
struct i2s_info *i2s_info;
|
2019-03-06 20:01:06 -07:00
|
|
|
bool is_period_done = false;
|
|
|
|
unsigned long flags;
|
|
|
|
struct i2s_rpmsg msg;
|
2017-02-14 20:28:36 -07:00
|
|
|
|
|
|
|
work_of_rpmsg = container_of(work, struct work_of_rpmsg, work);
|
|
|
|
i2s_info = work_of_rpmsg->i2s_info;
|
|
|
|
|
2019-03-06 20:01:06 -07:00
|
|
|
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);
|
2017-02-14 20:28:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int fsl_rpmsg_i2s_probe(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct device_node *np = pdev->dev.of_node;
|
|
|
|
struct fsl_rpmsg_i2s *rpmsg_i2s;
|
|
|
|
struct i2s_info *i2s_info;
|
|
|
|
int audioindex = 0;
|
|
|
|
int ret;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
rpmsg_i2s = devm_kzalloc(&pdev->dev, sizeof(struct fsl_rpmsg_i2s),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!rpmsg_i2s)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
rpmsg_i2s->pdev = pdev;
|
|
|
|
i2s_info = &rpmsg_i2s->i2s_info;
|
|
|
|
|
|
|
|
ret = of_property_read_u32(np, "fsl,audioindex", &audioindex);
|
|
|
|
if (ret)
|
|
|
|
audioindex = 0;
|
|
|
|
|
|
|
|
/* Setup work queue */
|
2019-11-28 21:03:04 -07:00
|
|
|
i2s_info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_i2s", WQ_HIGHPRI | WQ_UNBOUND | WQ_FREEZABLE);
|
2017-02-14 20:28:36 -07:00
|
|
|
if (i2s_info->rpmsg_wq == NULL) {
|
|
|
|
dev_err(&pdev->dev, "workqueue create failed\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2019-03-06 20:01:06 -07:00
|
|
|
i2s_info->work_write_index = 1;
|
2017-02-14 20:28:36 -07:00
|
|
|
i2s_info->send_message = i2s_send_message;
|
|
|
|
|
|
|
|
for (i = 0; i < WORK_MAX_NUM; i++) {
|
|
|
|
INIT_WORK(&i2s_info->work_list[i].work, rpmsg_i2s_work);
|
|
|
|
i2s_info->work_list[i].i2s_info = i2s_info;
|
|
|
|
}
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
for (i = 0; i < I2S_CMD_MAX_NUM ; i++) {
|
|
|
|
i2s_info->rpmsg[i].send_msg.header.cate = IMX_RPMSG_AUDIO;
|
|
|
|
i2s_info->rpmsg[i].send_msg.header.major = IMX_RMPSG_MAJOR;
|
|
|
|
i2s_info->rpmsg[i].send_msg.header.minor = IMX_RMPSG_MINOR;
|
|
|
|
i2s_info->rpmsg[i].send_msg.header.type = I2S_TYPE_A;
|
|
|
|
i2s_info->rpmsg[i].send_msg.param.audioindex = audioindex;
|
2017-02-14 20:28:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mutex_init(&i2s_info->tx_lock);
|
2018-03-05 21:45:22 -07:00
|
|
|
mutex_init(&i2s_info->i2c_lock);
|
2019-04-11 05:39:47 -06:00
|
|
|
spin_lock_init(&i2s_info->lock[0]);
|
|
|
|
spin_lock_init(&i2s_info->lock[1]);
|
2019-03-06 20:01:06 -07:00
|
|
|
spin_lock_init(&i2s_info->wq_lock);
|
2017-02-14 20:28:36 -07:00
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
if (of_device_is_compatible(pdev->dev.of_node,
|
|
|
|
"fsl,imx7ulp-rpmsg-i2s")) {
|
2018-08-08 01:07:43 -06:00
|
|
|
rpmsg_i2s->codec_wm8960 = 1;
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_i2s->version = 1;
|
|
|
|
rpmsg_i2s->rates = SNDRV_PCM_RATE_8000 |
|
|
|
|
SNDRV_PCM_RATE_16000 |
|
|
|
|
SNDRV_PCM_RATE_48000;
|
|
|
|
rpmsg_i2s->formats = SNDRV_PCM_FMTBIT_S16_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;
|
|
|
|
}
|
|
|
|
|
2018-08-08 01:07:43 -06:00
|
|
|
if (of_device_is_compatible(pdev->dev.of_node,
|
|
|
|
"fsl,imx8qxp-rpmsg-i2s")) {
|
|
|
|
rpmsg_i2s->codec_wm8960 = 1 + (1 << 16);
|
|
|
|
rpmsg_i2s->version = 1;
|
|
|
|
rpmsg_i2s->codec_cs42888 = 1 + (2 << 16);
|
|
|
|
}
|
|
|
|
|
2018-09-12 23:07:47 -06:00
|
|
|
if (of_device_is_compatible(pdev->dev.of_node,
|
|
|
|
"fsl,imx8qm-rpmsg-i2s")) {
|
|
|
|
rpmsg_i2s->codec_wm8960 = 0;
|
|
|
|
rpmsg_i2s->version = 1;
|
|
|
|
rpmsg_i2s->codec_cs42888 = 1 + (0 << 16);
|
|
|
|
}
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
if (of_device_is_compatible(pdev->dev.of_node,
|
|
|
|
"fsl,imx8mq-rpmsg-i2s")) {
|
2018-09-13 23:15:27 -06:00
|
|
|
rpmsg_i2s->codec_dummy = 0;
|
|
|
|
rpmsg_i2s->codec_ak4497 = 1;
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_i2s->version = 2;
|
2018-09-13 23:15:27 -06:00
|
|
|
rpmsg_i2s->rates = SNDRV_PCM_RATE_KNOT;
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_i2s->formats = SNDRV_PCM_FMTBIT_S16_LE |
|
|
|
|
SNDRV_PCM_FMTBIT_S24_LE |
|
2018-09-13 23:15:27 -06:00
|
|
|
SNDRV_PCM_FMTBIT_S32_LE |
|
|
|
|
SNDRV_PCM_FMTBIT_DSD_U8 |
|
|
|
|
SNDRV_PCM_FMTBIT_DSD_U16_LE |
|
|
|
|
SNDRV_PCM_FMTBIT_DSD_U32_LE;
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
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;
|
2019-03-06 20:01:06 -07:00
|
|
|
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;
|
2019-12-10 22:28:03 -07:00
|
|
|
rpmsg_i2s->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
|
|
|
|
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
|
|
|
|
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
|
|
|
|
SNDRV_PCM_RATE_192000;
|
2019-03-06 20:01:06 -07:00
|
|
|
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;
|
2020-03-29 23:57:34 -06:00
|
|
|
fsl_rpmsg_i2s_dai.capture.rates = rpmsg_i2s->rates;
|
|
|
|
fsl_rpmsg_i2s_dai.capture.formats = rpmsg_i2s->formats;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (of_device_is_compatible(pdev->dev.of_node,
|
|
|
|
"fsl,imx8mp-rpmsg-i2s")) {
|
|
|
|
rpmsg_i2s->codec_wm8960 = 1;
|
|
|
|
rpmsg_i2s->codec_in_dt = 1;
|
|
|
|
rpmsg_i2s->version = 2;
|
|
|
|
rpmsg_i2s->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
|
|
|
|
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
|
|
|
|
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
|
|
|
|
SNDRV_PCM_RATE_192000;
|
|
|
|
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;
|
2019-03-06 20:01:06 -07:00
|
|
|
fsl_rpmsg_i2s_dai.capture.rates = rpmsg_i2s->rates;
|
2018-07-24 23:42:50 -06:00
|
|
|
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;
|
|
|
|
|
|
|
|
if (of_property_read_u32(np, "fsl,dma-buffer-size",
|
|
|
|
&i2s_info->prealloc_buffer_size))
|
|
|
|
i2s_info->prealloc_buffer_size = IMX_DEFAULT_DMABUF_SIZE;
|
|
|
|
|
2017-02-14 20:28:36 -07:00
|
|
|
platform_set_drvdata(pdev, rpmsg_i2s);
|
|
|
|
pm_runtime_enable(&pdev->dev);
|
|
|
|
|
|
|
|
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
|
|
|
|
&fsl_rpmsg_i2s_dai, 1);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return imx_rpmsg_platform_register(&pdev->dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fsl_rpmsg_i2s_remove(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct fsl_rpmsg_i2s *rpmsg_i2s = platform_get_drvdata(pdev);
|
|
|
|
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
|
|
|
|
|
|
|
|
if (i2s_info->rpmsg_wq)
|
|
|
|
destroy_workqueue(i2s_info->rpmsg_wq);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
static int fsl_rpmsg_i2s_runtime_resume(struct device *dev)
|
|
|
|
{
|
2017-05-30 21:04:52 -06:00
|
|
|
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(dev);
|
|
|
|
|
|
|
|
pm_qos_add_request(&rpmsg_i2s->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0);
|
2017-02-14 20:28:36 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fsl_rpmsg_i2s_runtime_suspend(struct device *dev)
|
|
|
|
{
|
2017-05-30 21:04:52 -06:00
|
|
|
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(dev);
|
|
|
|
|
|
|
|
pm_qos_remove_request(&rpmsg_i2s->pm_qos_req);
|
2017-02-14 20:28:36 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
|
static int fsl_rpmsg_i2s_suspend(struct device *dev)
|
|
|
|
{
|
|
|
|
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(dev);
|
|
|
|
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
|
2018-07-24 23:42:50 -06:00
|
|
|
struct i2s_rpmsg *rpmsg_tx;
|
|
|
|
struct i2s_rpmsg *rpmsg_rx;
|
2017-02-14 20:28:36 -07:00
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_tx = &i2s_info->rpmsg[I2S_TX_SUSPEND];
|
|
|
|
rpmsg_rx = &i2s_info->rpmsg[I2S_RX_SUSPEND];
|
2017-02-14 20:28:36 -07:00
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_tx->send_msg.header.cmd = I2S_TX_SUSPEND;
|
2017-02-14 20:28:36 -07:00
|
|
|
i2s_send_message(rpmsg_tx, i2s_info);
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_rx->send_msg.header.cmd = I2S_RX_SUSPEND;
|
2017-02-14 20:28:36 -07:00
|
|
|
i2s_send_message(rpmsg_rx, i2s_info);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fsl_rpmsg_i2s_resume(struct device *dev)
|
|
|
|
{
|
|
|
|
struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(dev);
|
|
|
|
struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info;
|
2018-07-24 23:42:50 -06:00
|
|
|
struct i2s_rpmsg *rpmsg_tx;
|
|
|
|
struct i2s_rpmsg *rpmsg_rx;
|
2017-02-14 20:28:36 -07:00
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_tx = &i2s_info->rpmsg[I2S_TX_RESUME];
|
|
|
|
rpmsg_rx = &i2s_info->rpmsg[I2S_RX_RESUME];
|
2017-02-14 20:28:36 -07:00
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_tx->send_msg.header.cmd = I2S_TX_RESUME;
|
2017-02-14 20:28:36 -07:00
|
|
|
i2s_send_message(rpmsg_tx, i2s_info);
|
|
|
|
|
2018-07-24 23:42:50 -06:00
|
|
|
rpmsg_rx->send_msg.header.cmd = I2S_RX_RESUME;
|
2017-02-14 20:28:36 -07:00
|
|
|
i2s_send_message(rpmsg_rx, i2s_info);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_PM_SLEEP */
|
|
|
|
|
|
|
|
static const struct dev_pm_ops fsl_rpmsg_i2s_pm_ops = {
|
|
|
|
SET_RUNTIME_PM_OPS(fsl_rpmsg_i2s_runtime_suspend,
|
|
|
|
fsl_rpmsg_i2s_runtime_resume,
|
|
|
|
NULL)
|
|
|
|
SET_SYSTEM_SLEEP_PM_OPS(fsl_rpmsg_i2s_suspend, fsl_rpmsg_i2s_resume)
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct platform_driver fsl_rpmsg_i2s_driver = {
|
|
|
|
.probe = fsl_rpmsg_i2s_probe,
|
|
|
|
.remove = fsl_rpmsg_i2s_remove,
|
|
|
|
.driver = {
|
|
|
|
.name = "fsl-rpmsg-i2s",
|
|
|
|
.pm = &fsl_rpmsg_i2s_pm_ops,
|
|
|
|
.of_match_table = fsl_rpmsg_i2s_ids,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
module_platform_driver(fsl_rpmsg_i2s_driver);
|
|
|
|
|
|
|
|
MODULE_DESCRIPTION("Freescale Soc rpmsg_i2s Interface");
|
|
|
|
MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@freescale.com>");
|
|
|
|
MODULE_ALIAS("platform:fsl-rpmsg_i2s");
|
|
|
|
MODULE_LICENSE("GPL");
|