905c3a07130056713915cf904e9da22857dfb9cb
[sfrench/cifs-2.6.git] / sound / soc / fsl / imx-audio-rpmsg.c
1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2017-2020 NXP
3
4 #include <linux/module.h>
5 #include <linux/rpmsg.h>
6 #include "imx-pcm-rpmsg.h"
7
8 /*
9  * struct imx_audio_rpmsg: private data
10  *
11  * @rpmsg_pdev: pointer of platform device
12  */
13 struct imx_audio_rpmsg {
14         struct platform_device *rpmsg_pdev;
15 };
16
17 static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
18                               void *priv, u32 src)
19 {
20         struct imx_audio_rpmsg *rpmsg = dev_get_drvdata(&rpdev->dev);
21         struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data;
22         struct rpmsg_info *info;
23         struct rpmsg_msg *msg;
24         unsigned long flags;
25
26         if (!rpmsg->rpmsg_pdev)
27                 return 0;
28
29         info = platform_get_drvdata(rpmsg->rpmsg_pdev);
30
31         dev_dbg(&rpdev->dev, "get from%d: cmd:%d. %d\n",
32                 src, r_msg->header.cmd, r_msg->param.resp);
33
34         switch (r_msg->header.type) {
35         case MSG_TYPE_C:
36                 /* TYPE C is notification from M core */
37                 switch (r_msg->header.cmd) {
38                 case TX_PERIOD_DONE:
39                         spin_lock_irqsave(&info->lock[TX], flags);
40                         msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
41                         msg->r_msg.param.buffer_tail =
42                                                 r_msg->param.buffer_tail;
43                         msg->r_msg.param.buffer_tail %= info->num_period[TX];
44                         spin_unlock_irqrestore(&info->lock[TX], flags);
45                         info->callback[TX](info->callback_param[TX]);
46                         break;
47                 case RX_PERIOD_DONE:
48                         spin_lock_irqsave(&info->lock[RX], flags);
49                         msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
50                         msg->r_msg.param.buffer_tail =
51                                                 r_msg->param.buffer_tail;
52                         msg->r_msg.param.buffer_tail %= info->num_period[1];
53                         spin_unlock_irqrestore(&info->lock[RX], flags);
54                         info->callback[RX](info->callback_param[RX]);
55                         break;
56                 default:
57                         dev_warn(&rpdev->dev, "unknown msg command\n");
58                         break;
59                 }
60                 break;
61         case MSG_TYPE_B:
62                 /* TYPE B is response msg */
63                 memcpy(&info->r_msg, r_msg, sizeof(struct rpmsg_r_msg));
64                 complete(&info->cmd_complete);
65                 break;
66         default:
67                 dev_warn(&rpdev->dev, "unknown msg type\n");
68                 break;
69         }
70
71         return 0;
72 }
73
74 static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev)
75 {
76         struct imx_audio_rpmsg *data;
77         int ret = 0;
78
79         dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
80                  rpdev->src, rpdev->dst);
81
82         data = devm_kzalloc(&rpdev->dev, sizeof(*data), GFP_KERNEL);
83         if (!data)
84                 return -ENOMEM;
85
86         dev_set_drvdata(&rpdev->dev, data);
87
88         /* Register platform driver for rpmsg routine */
89         data->rpmsg_pdev = platform_device_register_data(&rpdev->dev,
90                                                          IMX_PCM_DRV_NAME,
91                                                          PLATFORM_DEVID_NONE,
92                                                          NULL, 0);
93         if (IS_ERR(data->rpmsg_pdev)) {
94                 dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
95                 ret = PTR_ERR(data->rpmsg_pdev);
96         }
97
98         return ret;
99 }
100
101 static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
102 {
103         struct imx_audio_rpmsg *data = dev_get_drvdata(&rpdev->dev);
104
105         if (data->rpmsg_pdev)
106                 platform_device_unregister(data->rpmsg_pdev);
107
108         dev_info(&rpdev->dev, "audio rpmsg driver is removed\n");
109 }
110
111 static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
112         { .name = "rpmsg-audio-channel" },
113         { },
114 };
115
116 static struct rpmsg_driver imx_audio_rpmsg_driver = {
117         .drv.name       = "imx_audio_rpmsg",
118         .drv.owner      = THIS_MODULE,
119         .id_table       = imx_audio_rpmsg_id_table,
120         .probe          = imx_audio_rpmsg_probe,
121         .callback       = imx_audio_rpmsg_cb,
122         .remove         = imx_audio_rpmsg_remove,
123 };
124
125 module_rpmsg_driver(imx_audio_rpmsg_driver);
126
127 MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface");
128 MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
129 MODULE_ALIAS("platform:imx_audio_rpmsg");
130 MODULE_LICENSE("GPL v2");