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 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 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 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.