linux/sound/soc/fsl/imx-audio-rpmsg.c
<<
>>
Prefs
   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");
 131