Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 // Copyright 2017-2020 NXP
0003 
0004 #include <linux/module.h>
0005 #include <linux/rpmsg.h>
0006 #include "imx-pcm-rpmsg.h"
0007 
0008 /*
0009  * struct imx_audio_rpmsg: private data
0010  *
0011  * @rpmsg_pdev: pointer of platform device
0012  */
0013 struct imx_audio_rpmsg {
0014     struct platform_device *rpmsg_pdev;
0015 };
0016 
0017 static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
0018                   void *priv, u32 src)
0019 {
0020     struct imx_audio_rpmsg *rpmsg = dev_get_drvdata(&rpdev->dev);
0021     struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data;
0022     struct rpmsg_info *info;
0023     struct rpmsg_msg *msg;
0024     unsigned long flags;
0025 
0026     if (!rpmsg->rpmsg_pdev)
0027         return 0;
0028 
0029     info = platform_get_drvdata(rpmsg->rpmsg_pdev);
0030 
0031     dev_dbg(&rpdev->dev, "get from%d: cmd:%d. %d\n",
0032         src, r_msg->header.cmd, r_msg->param.resp);
0033 
0034     switch (r_msg->header.type) {
0035     case MSG_TYPE_C:
0036         /* TYPE C is notification from M core */
0037         switch (r_msg->header.cmd) {
0038         case TX_PERIOD_DONE:
0039             spin_lock_irqsave(&info->lock[TX], flags);
0040             msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
0041             msg->r_msg.param.buffer_tail =
0042                         r_msg->param.buffer_tail;
0043             msg->r_msg.param.buffer_tail %= info->num_period[TX];
0044             spin_unlock_irqrestore(&info->lock[TX], flags);
0045             info->callback[TX](info->callback_param[TX]);
0046             break;
0047         case RX_PERIOD_DONE:
0048             spin_lock_irqsave(&info->lock[RX], flags);
0049             msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
0050             msg->r_msg.param.buffer_tail =
0051                         r_msg->param.buffer_tail;
0052             msg->r_msg.param.buffer_tail %= info->num_period[1];
0053             spin_unlock_irqrestore(&info->lock[RX], flags);
0054             info->callback[RX](info->callback_param[RX]);
0055             break;
0056         default:
0057             dev_warn(&rpdev->dev, "unknown msg command\n");
0058             break;
0059         }
0060         break;
0061     case MSG_TYPE_B:
0062         /* TYPE B is response msg */
0063         memcpy(&info->r_msg, r_msg, sizeof(struct rpmsg_r_msg));
0064         complete(&info->cmd_complete);
0065         break;
0066     default:
0067         dev_warn(&rpdev->dev, "unknown msg type\n");
0068         break;
0069     }
0070 
0071     return 0;
0072 }
0073 
0074 static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev)
0075 {
0076     struct imx_audio_rpmsg *data;
0077     int ret = 0;
0078 
0079     dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
0080          rpdev->src, rpdev->dst);
0081 
0082     data = devm_kzalloc(&rpdev->dev, sizeof(*data), GFP_KERNEL);
0083     if (!data)
0084         return -ENOMEM;
0085 
0086     dev_set_drvdata(&rpdev->dev, data);
0087 
0088     /* Register platform driver for rpmsg routine */
0089     data->rpmsg_pdev = platform_device_register_data(&rpdev->dev,
0090                              IMX_PCM_DRV_NAME,
0091                              PLATFORM_DEVID_NONE,
0092                              NULL, 0);
0093     if (IS_ERR(data->rpmsg_pdev)) {
0094         dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
0095         ret = PTR_ERR(data->rpmsg_pdev);
0096     }
0097 
0098     return ret;
0099 }
0100 
0101 static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
0102 {
0103     struct imx_audio_rpmsg *data = dev_get_drvdata(&rpdev->dev);
0104 
0105     if (data->rpmsg_pdev)
0106         platform_device_unregister(data->rpmsg_pdev);
0107 
0108     dev_info(&rpdev->dev, "audio rpmsg driver is removed\n");
0109 }
0110 
0111 static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
0112     { .name = "rpmsg-audio-channel" },
0113     { },
0114 };
0115 
0116 static struct rpmsg_driver imx_audio_rpmsg_driver = {
0117     .drv.name   = "imx_audio_rpmsg",
0118     .drv.owner  = THIS_MODULE,
0119     .id_table   = imx_audio_rpmsg_id_table,
0120     .probe      = imx_audio_rpmsg_probe,
0121     .callback   = imx_audio_rpmsg_cb,
0122     .remove     = imx_audio_rpmsg_remove,
0123 };
0124 
0125 module_rpmsg_driver(imx_audio_rpmsg_driver);
0126 
0127 MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface");
0128 MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
0129 MODULE_ALIAS("platform:imx_audio_rpmsg");
0130 MODULE_LICENSE("GPL v2");