mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-09-03 02:16:09 +02:00

Let imx-audio-rpmsg register platform device for card. So that card register and unregister can be controlled by rpmsg driver's register and unregister. Signed-off-by: Chancel Liu <chancel.liu@nxp.com> Link: https://msgid.link/r/20240311111349.723256-4-chancel.liu@nxp.com Acked-by: Shengjiu Wang <shengjiu.wang@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
183 lines
5.1 KiB
C
183 lines
5.1 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
// Copyright 2017-2020 NXP
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/rpmsg.h>
|
|
#include "imx-pcm-rpmsg.h"
|
|
|
|
/*
|
|
* struct imx_audio_rpmsg: private data
|
|
*
|
|
* @rpmsg_pdev: pointer of platform device
|
|
*/
|
|
struct imx_audio_rpmsg {
|
|
struct platform_device *rpmsg_pdev;
|
|
struct platform_device *card_pdev;
|
|
};
|
|
|
|
static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
|
|
void *priv, u32 src)
|
|
{
|
|
struct imx_audio_rpmsg *rpmsg = dev_get_drvdata(&rpdev->dev);
|
|
struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data;
|
|
struct rpmsg_info *info;
|
|
struct rpmsg_msg *msg;
|
|
unsigned long flags;
|
|
|
|
if (!rpmsg->rpmsg_pdev)
|
|
return 0;
|
|
|
|
info = platform_get_drvdata(rpmsg->rpmsg_pdev);
|
|
|
|
dev_dbg(&rpdev->dev, "get from%d: cmd:%d. %d\n",
|
|
src, r_msg->header.cmd, r_msg->param.resp);
|
|
|
|
switch (r_msg->header.type) {
|
|
case MSG_TYPE_C:
|
|
/* TYPE C is notification from M core */
|
|
switch (r_msg->header.cmd) {
|
|
case TX_PERIOD_DONE:
|
|
spin_lock_irqsave(&info->lock[TX], flags);
|
|
msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
|
|
msg->r_msg.param.buffer_tail =
|
|
r_msg->param.buffer_tail;
|
|
msg->r_msg.param.buffer_tail %= info->num_period[TX];
|
|
spin_unlock_irqrestore(&info->lock[TX], flags);
|
|
info->callback[TX](info->callback_param[TX]);
|
|
break;
|
|
case RX_PERIOD_DONE:
|
|
spin_lock_irqsave(&info->lock[RX], flags);
|
|
msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
|
|
msg->r_msg.param.buffer_tail =
|
|
r_msg->param.buffer_tail;
|
|
msg->r_msg.param.buffer_tail %= info->num_period[1];
|
|
spin_unlock_irqrestore(&info->lock[RX], flags);
|
|
info->callback[RX](info->callback_param[RX]);
|
|
break;
|
|
default:
|
|
dev_warn(&rpdev->dev, "unknown msg command\n");
|
|
break;
|
|
}
|
|
break;
|
|
case MSG_TYPE_B:
|
|
/* TYPE B is response msg */
|
|
memcpy(&info->r_msg, r_msg, sizeof(struct rpmsg_r_msg));
|
|
complete(&info->cmd_complete);
|
|
break;
|
|
default:
|
|
dev_warn(&rpdev->dev, "unknown msg type\n");
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev)
|
|
{
|
|
struct imx_audio_rpmsg *data;
|
|
struct platform_device *codec_pdev;
|
|
struct rpmsg_codec codec;
|
|
const char *model_string;
|
|
struct device_node *np;
|
|
int ret = 0;
|
|
|
|
dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
|
|
rpdev->src, rpdev->dst);
|
|
|
|
data = devm_kzalloc(&rpdev->dev, sizeof(*data), GFP_KERNEL);
|
|
if (!data)
|
|
return -ENOMEM;
|
|
|
|
dev_set_drvdata(&rpdev->dev, data);
|
|
|
|
/* Register platform driver for rpmsg routine */
|
|
data->rpmsg_pdev = platform_device_register_data(&rpdev->dev,
|
|
rpdev->id.name,
|
|
PLATFORM_DEVID_NONE,
|
|
NULL, 0);
|
|
if (IS_ERR(data->rpmsg_pdev)) {
|
|
dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
|
|
ret = PTR_ERR(data->rpmsg_pdev);
|
|
}
|
|
|
|
data->card_pdev = platform_device_register_data(&rpdev->dev,
|
|
"imx-audio-rpmsg",
|
|
PLATFORM_DEVID_AUTO,
|
|
rpdev->id.name,
|
|
strlen(rpdev->id.name) + 1);
|
|
if (IS_ERR(data->card_pdev)) {
|
|
dev_err(&rpdev->dev, "failed to register rpmsg card.\n");
|
|
ret = PTR_ERR(data->card_pdev);
|
|
}
|
|
|
|
if (!strcmp(rpdev->id.name, "rpmsg-micfil-channel"))
|
|
return ret;
|
|
np = of_find_node_by_name(NULL, "rpmsg_audio");
|
|
of_property_read_string(np, "model", &model_string);
|
|
if (np && of_device_is_compatible(np, "fsl,imx7ulp-rpmsg-audio")) {
|
|
codec.audioindex = 0;
|
|
codec.shared_lrclk = true;
|
|
codec.capless = false;
|
|
codec_pdev = platform_device_register_data(&data->rpmsg_pdev->dev,
|
|
RPMSG_CODEC_DRV_NAME_WM8960,
|
|
PLATFORM_DEVID_NONE,
|
|
&codec,
|
|
sizeof(struct rpmsg_codec));
|
|
if (IS_ERR(codec_pdev)) {
|
|
dev_err(&rpdev->dev, "failed to register rpmsg codec\n");
|
|
ret = PTR_ERR(codec_pdev);
|
|
goto fail;
|
|
}
|
|
} else if (np && of_device_is_compatible(np, "fsl,imx8mm-rpmsg-audio") &&
|
|
!strcmp("ak4497-audio", model_string)) {
|
|
codec.audioindex = 0;
|
|
codec_pdev = platform_device_register_data(&data->rpmsg_pdev->dev,
|
|
RPMSG_CODEC_DRV_NAME_AK4497,
|
|
PLATFORM_DEVID_NONE,
|
|
&codec,
|
|
sizeof(struct rpmsg_codec));
|
|
if (IS_ERR(codec_pdev)) {
|
|
dev_err(&rpdev->dev, "failed to register rpmsg codec\n");
|
|
ret = PTR_ERR(codec_pdev);
|
|
goto fail;
|
|
}
|
|
}
|
|
fail:
|
|
return ret;
|
|
}
|
|
|
|
static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
|
|
{
|
|
struct imx_audio_rpmsg *data = dev_get_drvdata(&rpdev->dev);
|
|
|
|
if (data->rpmsg_pdev)
|
|
platform_device_unregister(data->rpmsg_pdev);
|
|
|
|
if (data->card_pdev)
|
|
platform_device_unregister(data->card_pdev);
|
|
|
|
dev_info(&rpdev->dev, "audio rpmsg driver is removed\n");
|
|
}
|
|
|
|
static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
|
|
{ .name = "rpmsg-audio-channel" },
|
|
{ .name = "rpmsg-micfil-channel" },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(rpmsg, imx_audio_rpmsg_id_table);
|
|
|
|
static struct rpmsg_driver imx_audio_rpmsg_driver = {
|
|
.drv.name = "imx_audio_rpmsg",
|
|
.id_table = imx_audio_rpmsg_id_table,
|
|
.probe = imx_audio_rpmsg_probe,
|
|
.callback = imx_audio_rpmsg_cb,
|
|
.remove = imx_audio_rpmsg_remove,
|
|
};
|
|
|
|
module_rpmsg_driver(imx_audio_rpmsg_driver);
|
|
|
|
MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface");
|
|
MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
|
|
MODULE_ALIAS("rpmsg:imx_audio_rpmsg");
|
|
MODULE_LICENSE("GPL v2");
|