imx-audio-rpmsg.c 3.8 KB

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