1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2017-2020 NXP
4 #include <linux/module.h>
5 #include <linux/rpmsg.h>
6 #include "imx-pcm-rpmsg.h"
9 * struct imx_audio_rpmsg: private data
11 * @rpmsg_pdev: pointer of platform device
13 struct imx_audio_rpmsg
{
14 struct platform_device
*rpmsg_pdev
;
15 struct platform_device
*card_pdev
;
18 static int imx_audio_rpmsg_cb(struct rpmsg_device
*rpdev
, void *data
, int len
,
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
;
27 if (!rpmsg
->rpmsg_pdev
)
30 info
= platform_get_drvdata(rpmsg
->rpmsg_pdev
);
32 dev_dbg(&rpdev
->dev
, "get from%d: cmd:%d. %d\n",
33 src
, r_msg
->header
.cmd
, r_msg
->param
.resp
);
35 switch (r_msg
->header
.type
) {
37 /* TYPE C is notification from M core */
38 switch (r_msg
->header
.cmd
) {
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
]);
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
]);
58 dev_warn(&rpdev
->dev
, "unknown msg command\n");
63 /* TYPE B is response msg */
64 memcpy(&info
->r_msg
, r_msg
, sizeof(struct rpmsg_r_msg
));
65 complete(&info
->cmd_complete
);
68 dev_warn(&rpdev
->dev
, "unknown msg type\n");
75 static int imx_audio_rpmsg_probe(struct rpmsg_device
*rpdev
)
77 struct imx_audio_rpmsg
*data
;
80 dev_info(&rpdev
->dev
, "new channel: 0x%x -> 0x%x!\n",
81 rpdev
->src
, rpdev
->dst
);
83 data
= devm_kzalloc(&rpdev
->dev
, sizeof(*data
), GFP_KERNEL
);
87 dev_set_drvdata(&rpdev
->dev
, data
);
89 /* Register platform driver for rpmsg routine */
90 data
->rpmsg_pdev
= platform_device_register_data(&rpdev
->dev
,
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
);
99 data
->card_pdev
= platform_device_register_data(&rpdev
->dev
,
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
);
112 static void imx_audio_rpmsg_remove(struct rpmsg_device
*rpdev
)
114 struct imx_audio_rpmsg
*data
= dev_get_drvdata(&rpdev
->dev
);
116 if (data
->rpmsg_pdev
)
117 platform_device_unregister(data
->rpmsg_pdev
);
120 platform_device_unregister(data
->card_pdev
);
122 dev_info(&rpdev
->dev
, "audio rpmsg driver is removed\n");
125 static struct rpmsg_device_id imx_audio_rpmsg_id_table
[] = {
126 { .name
= "rpmsg-audio-channel" },
127 { .name
= "rpmsg-micfil-channel" },
130 MODULE_DEVICE_TABLE(rpmsg
, imx_audio_rpmsg_id_table
);
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
,
140 module_rpmsg_driver(imx_audio_rpmsg_driver
);
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");