// 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;
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);
}
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 " );
MODULE_ALIAS("rpmsg:imx_audio_rpmsg" );
MODULE_LICENSE("GPL v2" );
Messung V0.5 C=95 H=95 G=94
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland