123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- // 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;
- };
- 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,
- IMX_PCM_DRV_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);
- }
- 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);
- dev_info(&rpdev->dev, "audio rpmsg driver is removed\n");
- }
- static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
- { .name = "rpmsg-audio-channel" },
- { },
- };
- static struct rpmsg_driver imx_audio_rpmsg_driver = {
- .drv.name = "imx_audio_rpmsg",
- .drv.owner = THIS_MODULE,
- .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 <[email protected]>");
- MODULE_ALIAS("platform:imx_audio_rpmsg");
- MODULE_LICENSE("GPL v2");
|