Linux Audio

Check our new training course

Loading...
v6.13.7
  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");
v5.14.15
  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");