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