Loading...
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 */
13struct imx_audio_rpmsg {
14 struct platform_device *rpmsg_pdev;
15 struct platform_device *card_pdev;
16};
17
18static 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
75static 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
112static 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
125static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
126 { .name = "rpmsg-audio-channel" },
127 { .name = "rpmsg-micfil-channel" },
128 { },
129};
130MODULE_DEVICE_TABLE(rpmsg, imx_audio_rpmsg_id_table);
131
132static 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
140module_rpmsg_driver(imx_audio_rpmsg_driver);
141
142MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface");
143MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
144MODULE_ALIAS("rpmsg:imx_audio_rpmsg");
145MODULE_LICENSE("GPL v2");
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 */
13struct imx_audio_rpmsg {
14 struct platform_device *rpmsg_pdev;
15};
16
17static 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
74static 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
101static 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
111static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
112 { .name = "rpmsg-audio-channel" },
113 { },
114};
115
116static 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
125module_rpmsg_driver(imx_audio_rpmsg_driver);
126
127MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface");
128MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
129MODULE_ALIAS("platform:imx_audio_rpmsg");
130MODULE_LICENSE("GPL v2");