linux/sound/soc/fsl/imx-pcm-rpmsg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2// Copyright 2017-2021 NXP
   3
   4#include <linux/dma-mapping.h>
   5#include <linux/slab.h>
   6#include <linux/module.h>
   7#include <linux/delay.h>
   8#include <linux/rpmsg.h>
   9#include <sound/core.h>
  10#include <sound/pcm.h>
  11#include <sound/pcm_params.h>
  12#include <sound/dmaengine_pcm.h>
  13#include <sound/soc.h>
  14
  15#include "imx-pcm.h"
  16#include "fsl_rpmsg.h"
  17#include "imx-pcm-rpmsg.h"
  18
  19static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
  20        .info = SNDRV_PCM_INFO_INTERLEAVED |
  21                SNDRV_PCM_INFO_BLOCK_TRANSFER |
  22                SNDRV_PCM_INFO_MMAP |
  23                SNDRV_PCM_INFO_MMAP_VALID |
  24                SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
  25                SNDRV_PCM_INFO_PAUSE |
  26                SNDRV_PCM_INFO_RESUME,
  27        .buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE,
  28        .period_bytes_min = 512,
  29        .period_bytes_max = 65536,
  30        .periods_min = 2,
  31        .periods_max = 6000,
  32        .fifo_size = 0,
  33};
  34
  35static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
  36                                      struct rpmsg_info *info)
  37{
  38        struct rpmsg_device *rpdev = info->rpdev;
  39        int ret = 0;
  40
  41        mutex_lock(&info->msg_lock);
  42        if (!rpdev) {
  43                dev_err(info->dev, "rpmsg channel not ready\n");
  44                mutex_unlock(&info->msg_lock);
  45                return -EINVAL;
  46        }
  47
  48        dev_dbg(&rpdev->dev, "send cmd %d\n", msg->s_msg.header.cmd);
  49
  50        if (!(msg->s_msg.header.type == MSG_TYPE_C))
  51                reinit_completion(&info->cmd_complete);
  52
  53        ret = rpmsg_send(rpdev->ept, (void *)&msg->s_msg,
  54                         sizeof(struct rpmsg_s_msg));
  55        if (ret) {
  56                dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
  57                mutex_unlock(&info->msg_lock);
  58                return ret;
  59        }
  60
  61        /* No receive msg for TYPE_C command */
  62        if (msg->s_msg.header.type == MSG_TYPE_C) {
  63                mutex_unlock(&info->msg_lock);
  64                return 0;
  65        }
  66
  67        /* wait response from rpmsg */
  68        ret = wait_for_completion_timeout(&info->cmd_complete,
  69                                          msecs_to_jiffies(RPMSG_TIMEOUT));
  70        if (!ret) {
  71                dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n",
  72                        msg->s_msg.header.cmd);
  73                mutex_unlock(&info->msg_lock);
  74                return -ETIMEDOUT;
  75        }
  76
  77        memcpy(&msg->r_msg, &info->r_msg, sizeof(struct rpmsg_r_msg));
  78        memcpy(&info->msg[msg->r_msg.header.cmd].r_msg,
  79               &msg->r_msg, sizeof(struct rpmsg_r_msg));
  80
  81        /*
  82         * Reset the buffer pointer to be zero, actully we have
  83         * set the buffer pointer to be zero in imx_rpmsg_terminate_all
  84         * But if there is timer task queued in queue, after it is
  85         * executed the buffer pointer will be changed, so need to
  86         * reset it again with TERMINATE command.
  87         */
  88        switch (msg->s_msg.header.cmd) {
  89        case TX_TERMINATE:
  90                info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
  91                break;
  92        case RX_TERMINATE:
  93                info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
  94                break;
  95        default:
  96                break;
  97        }
  98
  99        dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd,
 100                info->r_msg.param.resp);
 101
 102        mutex_unlock(&info->msg_lock);
 103
 104        return 0;
 105}
 106
 107static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
 108                                      struct rpmsg_msg *msg,
 109                                      struct rpmsg_info *info)
 110{
 111        unsigned long flags;
 112        int ret = 0;
 113
 114        /*
 115         * Queue the work to workqueue.
 116         * If the queue is full, drop the message.
 117         */
 118        spin_lock_irqsave(&info->wq_lock, flags);
 119        if (info->work_write_index != info->work_read_index) {
 120                int index = info->work_write_index;
 121
 122                memcpy(&info->work_list[index].msg, msg,
 123                       sizeof(struct rpmsg_s_msg));
 124
 125                queue_work(info->rpmsg_wq, &info->work_list[index].work);
 126                info->work_write_index++;
 127                info->work_write_index %= WORK_MAX_NUM;
 128        } else {
 129                info->msg_drop_count[substream->stream]++;
 130                ret = -EPIPE;
 131        }
 132        spin_unlock_irqrestore(&info->wq_lock, flags);
 133
 134        return ret;
 135}
 136
 137static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
 138                                   struct snd_pcm_substream *substream,
 139                                   struct snd_pcm_hw_params *params)
 140{
 141        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 142        struct rpmsg_msg *msg;
 143        int ret = 0;
 144
 145        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 146                msg = &info->msg[TX_HW_PARAM];
 147                msg->s_msg.header.cmd = TX_HW_PARAM;
 148        } else {
 149                msg = &info->msg[RX_HW_PARAM];
 150                msg->s_msg.header.cmd = RX_HW_PARAM;
 151        }
 152
 153        msg->s_msg.param.rate = params_rate(params);
 154
 155        switch (params_format(params)) {
 156        case SNDRV_PCM_FORMAT_S16_LE:
 157                msg->s_msg.param.format   = RPMSG_S16_LE;
 158                break;
 159        case SNDRV_PCM_FORMAT_S24_LE:
 160                msg->s_msg.param.format   = RPMSG_S24_LE;
 161                break;
 162        case SNDRV_PCM_FORMAT_DSD_U16_LE:
 163                msg->s_msg.param.format   = RPMSG_DSD_U16_LE;
 164                break;
 165        case SNDRV_PCM_FORMAT_DSD_U32_LE:
 166                msg->s_msg.param.format   = RPMSG_DSD_U32_LE;
 167                break;
 168        default:
 169                msg->s_msg.param.format   = RPMSG_S32_LE;
 170                break;
 171        }
 172
 173        switch (params_channels(params)) {
 174        case 1:
 175                msg->s_msg.param.channels = RPMSG_CH_LEFT;
 176                break;
 177        case 2:
 178                msg->s_msg.param.channels = RPMSG_CH_STEREO;
 179                break;
 180        default:
 181                ret = -EINVAL;
 182                break;
 183        }
 184
 185        info->send_message(msg, info);
 186
 187        return ret;
 188}
 189
 190static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *component,
 191                                               struct snd_pcm_substream *substream)
 192{
 193        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 194        struct rpmsg_msg *msg;
 195        unsigned int pos = 0;
 196        int buffer_tail = 0;
 197
 198        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 199                msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
 200        else
 201                msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
 202
 203        buffer_tail = msg->r_msg.param.buffer_tail;
 204        pos = buffer_tail * snd_pcm_lib_period_bytes(substream);
 205
 206        return bytes_to_frames(substream->runtime, pos);
 207}
 208
 209static void imx_rpmsg_timer_callback(struct timer_list *t)
 210{
 211        struct stream_timer  *stream_timer =
 212                        from_timer(stream_timer, t, timer);
 213        struct snd_pcm_substream *substream = stream_timer->substream;
 214        struct rpmsg_info *info = stream_timer->info;
 215        struct rpmsg_msg *msg;
 216
 217        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 218                msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
 219                msg->s_msg.header.cmd = TX_PERIOD_DONE;
 220        } else {
 221                msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
 222                msg->s_msg.header.cmd = RX_PERIOD_DONE;
 223        }
 224
 225        imx_rpmsg_insert_workqueue(substream, msg, info);
 226}
 227
 228static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
 229                              struct snd_pcm_substream *substream)
 230{
 231        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 232        struct rpmsg_msg *msg;
 233        int ret = 0;
 234        int cmd;
 235
 236        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 237                msg = &info->msg[TX_OPEN];
 238                msg->s_msg.header.cmd = TX_OPEN;
 239
 240                /* reinitialize buffer counter*/
 241                cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM;
 242                info->msg[cmd].s_msg.param.buffer_tail = 0;
 243                info->msg[cmd].r_msg.param.buffer_tail = 0;
 244                info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
 245
 246        } else {
 247                msg = &info->msg[RX_OPEN];
 248                msg->s_msg.header.cmd = RX_OPEN;
 249
 250                /* reinitialize buffer counter*/
 251                cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM;
 252                info->msg[cmd].s_msg.param.buffer_tail = 0;
 253                info->msg[cmd].r_msg.param.buffer_tail = 0;
 254                info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
 255        }
 256
 257        info->send_message(msg, info);
 258
 259        imx_rpmsg_pcm_hardware.period_bytes_max =
 260                        imx_rpmsg_pcm_hardware.buffer_bytes_max / 2;
 261
 262        snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware);
 263
 264        ret = snd_pcm_hw_constraint_integer(substream->runtime,
 265                                            SNDRV_PCM_HW_PARAM_PERIODS);
 266        if (ret < 0)
 267                return ret;
 268
 269        info->msg_drop_count[substream->stream] = 0;
 270
 271        /* Create timer*/
 272        info->stream_timer[substream->stream].info = info;
 273        info->stream_timer[substream->stream].substream = substream;
 274        timer_setup(&info->stream_timer[substream->stream].timer,
 275                    imx_rpmsg_timer_callback, 0);
 276        return ret;
 277}
 278
 279static int imx_rpmsg_pcm_close(struct snd_soc_component *component,
 280                               struct snd_pcm_substream *substream)
 281{
 282        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 283        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 284        struct rpmsg_msg *msg;
 285        int ret = 0;
 286
 287        /* Flush work in workqueue to make TX_CLOSE is the last message */
 288        flush_workqueue(info->rpmsg_wq);
 289
 290        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 291                msg = &info->msg[TX_CLOSE];
 292                msg->s_msg.header.cmd = TX_CLOSE;
 293        } else {
 294                msg = &info->msg[RX_CLOSE];
 295                msg->s_msg.header.cmd = RX_CLOSE;
 296        }
 297
 298        info->send_message(msg, info);
 299
 300        del_timer(&info->stream_timer[substream->stream].timer);
 301
 302        rtd->dai_link->ignore_suspend = 0;
 303
 304        if (info->msg_drop_count[substream->stream])
 305                dev_warn(rtd->dev, "Msg is dropped!, number is %d\n",
 306                         info->msg_drop_count[substream->stream]);
 307
 308        return ret;
 309}
 310
 311static int imx_rpmsg_pcm_prepare(struct snd_soc_component *component,
 312                                 struct snd_pcm_substream *substream)
 313{
 314        struct snd_pcm_runtime *runtime = substream->runtime;
 315        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 316        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 317        struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
 318
 319        /*
 320         * NON-MMAP mode, NONBLOCK, Version 2, enable lpa in dts
 321         * four conditions to determine the lpa is enabled.
 322         */
 323        if ((runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
 324             runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) &&
 325             rpmsg->enable_lpa) {
 326                /*
 327                 * Ignore suspend operation in low power mode
 328                 * M core will continue playback music on A core suspend.
 329                 */
 330                rtd->dai_link->ignore_suspend = 1;
 331                rpmsg->force_lpa = 1;
 332        } else {
 333                rpmsg->force_lpa = 0;
 334        }
 335
 336        return 0;
 337}
 338
 339static void imx_rpmsg_pcm_dma_complete(void *arg)
 340{
 341        struct snd_pcm_substream *substream = arg;
 342
 343        snd_pcm_period_elapsed(substream);
 344}
 345
 346static int imx_rpmsg_prepare_and_submit(struct snd_soc_component *component,
 347                                        struct snd_pcm_substream *substream)
 348{
 349        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 350        struct rpmsg_msg *msg;
 351
 352        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 353                msg = &info->msg[TX_BUFFER];
 354                msg->s_msg.header.cmd = TX_BUFFER;
 355        } else {
 356                msg = &info->msg[RX_BUFFER];
 357                msg->s_msg.header.cmd = RX_BUFFER;
 358        }
 359
 360        /* Send buffer address and buffer size */
 361        msg->s_msg.param.buffer_addr = substream->runtime->dma_addr;
 362        msg->s_msg.param.buffer_size = snd_pcm_lib_buffer_bytes(substream);
 363        msg->s_msg.param.period_size = snd_pcm_lib_period_bytes(substream);
 364        msg->s_msg.param.buffer_tail = 0;
 365
 366        info->num_period[substream->stream] = msg->s_msg.param.buffer_size /
 367                                              msg->s_msg.param.period_size;
 368
 369        info->callback[substream->stream] = imx_rpmsg_pcm_dma_complete;
 370        info->callback_param[substream->stream] = substream;
 371
 372        return imx_rpmsg_insert_workqueue(substream, msg, info);
 373}
 374
 375static int imx_rpmsg_async_issue_pending(struct snd_soc_component *component,
 376                                         struct snd_pcm_substream *substream)
 377{
 378        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 379        struct rpmsg_msg *msg;
 380
 381        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 382                msg = &info->msg[TX_START];
 383                msg->s_msg.header.cmd = TX_START;
 384        } else {
 385                msg = &info->msg[RX_START];
 386                msg->s_msg.header.cmd = RX_START;
 387        }
 388
 389        return imx_rpmsg_insert_workqueue(substream, msg, info);
 390}
 391
 392static int imx_rpmsg_restart(struct snd_soc_component *component,
 393                             struct snd_pcm_substream *substream)
 394{
 395        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 396        struct rpmsg_msg *msg;
 397
 398        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 399                msg = &info->msg[TX_RESTART];
 400                msg->s_msg.header.cmd = TX_RESTART;
 401        } else {
 402                msg = &info->msg[RX_RESTART];
 403                msg->s_msg.header.cmd = RX_RESTART;
 404        }
 405
 406        return imx_rpmsg_insert_workqueue(substream, msg, info);
 407}
 408
 409static int imx_rpmsg_pause(struct snd_soc_component *component,
 410                           struct snd_pcm_substream *substream)
 411{
 412        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 413        struct rpmsg_msg *msg;
 414
 415        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 416                msg = &info->msg[TX_PAUSE];
 417                msg->s_msg.header.cmd = TX_PAUSE;
 418        } else {
 419                msg = &info->msg[RX_PAUSE];
 420                msg->s_msg.header.cmd = RX_PAUSE;
 421        }
 422
 423        return imx_rpmsg_insert_workqueue(substream, msg, info);
 424}
 425
 426static int imx_rpmsg_terminate_all(struct snd_soc_component *component,
 427                                   struct snd_pcm_substream *substream)
 428{
 429        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 430        struct rpmsg_msg *msg;
 431        int cmd;
 432
 433        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 434                msg = &info->msg[TX_TERMINATE];
 435                msg->s_msg.header.cmd = TX_TERMINATE;
 436                /* Clear buffer count*/
 437                cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM;
 438                info->msg[cmd].s_msg.param.buffer_tail = 0;
 439                info->msg[cmd].r_msg.param.buffer_tail = 0;
 440                info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
 441        } else {
 442                msg = &info->msg[RX_TERMINATE];
 443                msg->s_msg.header.cmd = RX_TERMINATE;
 444                /* Clear buffer count*/
 445                cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM;
 446                info->msg[cmd].s_msg.param.buffer_tail = 0;
 447                info->msg[cmd].r_msg.param.buffer_tail = 0;
 448                info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
 449        }
 450
 451        del_timer(&info->stream_timer[substream->stream].timer);
 452
 453        return imx_rpmsg_insert_workqueue(substream, msg, info);
 454}
 455
 456static int imx_rpmsg_pcm_trigger(struct snd_soc_component *component,
 457                                 struct snd_pcm_substream *substream, int cmd)
 458{
 459        struct snd_pcm_runtime *runtime = substream->runtime;
 460        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 461        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 462        struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
 463        int ret = 0;
 464
 465        switch (cmd) {
 466        case SNDRV_PCM_TRIGGER_START:
 467                ret = imx_rpmsg_prepare_and_submit(component, substream);
 468                if (ret)
 469                        return ret;
 470                ret = imx_rpmsg_async_issue_pending(component, substream);
 471                break;
 472        case SNDRV_PCM_TRIGGER_RESUME:
 473                if (rpmsg->force_lpa)
 474                        break;
 475                fallthrough;
 476        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 477                ret = imx_rpmsg_restart(component, substream);
 478                break;
 479        case SNDRV_PCM_TRIGGER_SUSPEND:
 480                if (!rpmsg->force_lpa) {
 481                        if (runtime->info & SNDRV_PCM_INFO_PAUSE)
 482                                ret = imx_rpmsg_pause(component, substream);
 483                        else
 484                                ret = imx_rpmsg_terminate_all(component, substream);
 485                }
 486                break;
 487        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 488                ret = imx_rpmsg_pause(component, substream);
 489                break;
 490        case SNDRV_PCM_TRIGGER_STOP:
 491                ret = imx_rpmsg_terminate_all(component, substream);
 492                break;
 493        default:
 494                return -EINVAL;
 495        }
 496
 497        if (ret)
 498                return ret;
 499
 500        return 0;
 501}
 502
 503/*
 504 * imx_rpmsg_pcm_ack
 505 *
 506 * Send the period index to M core through rpmsg, but not send
 507 * all the period index to M core, reduce some unnessesary msg
 508 * to reduce the pressure of rpmsg bandwidth.
 509 */
 510static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
 511                             struct snd_pcm_substream *substream)
 512{
 513        struct snd_pcm_runtime *runtime = substream->runtime;
 514        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 515        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 516        struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
 517        struct rpmsg_info *info = dev_get_drvdata(component->dev);
 518        snd_pcm_uframes_t period_size = runtime->period_size;
 519        snd_pcm_sframes_t avail;
 520        struct timer_list *timer;
 521        struct rpmsg_msg *msg;
 522        unsigned long flags;
 523        int buffer_tail = 0;
 524        int written_num;
 525
 526        if (!rpmsg->force_lpa)
 527                return 0;
 528
 529        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 530                msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
 531                msg->s_msg.header.cmd = TX_PERIOD_DONE;
 532        } else {
 533                msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
 534                msg->s_msg.header.cmd = RX_PERIOD_DONE;
 535        }
 536
 537        msg->s_msg.header.type = MSG_TYPE_C;
 538
 539        buffer_tail = (frames_to_bytes(runtime, runtime->control->appl_ptr) %
 540                       snd_pcm_lib_buffer_bytes(substream));
 541        buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream);
 542
 543        /* There is update for period index */
 544        if (buffer_tail != msg->s_msg.param.buffer_tail) {
 545                written_num = buffer_tail - msg->s_msg.param.buffer_tail;
 546                if (written_num < 0)
 547                        written_num += runtime->periods;
 548
 549                msg->s_msg.param.buffer_tail = buffer_tail;
 550
 551                /* The notification message is updated to latest */
 552                spin_lock_irqsave(&info->lock[substream->stream], flags);
 553                memcpy(&info->notify[substream->stream], msg,
 554                       sizeof(struct rpmsg_s_msg));
 555                info->notify_updated[substream->stream] = true;
 556                spin_unlock_irqrestore(&info->lock[substream->stream], flags);
 557
 558                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 559                        avail = snd_pcm_playback_hw_avail(runtime);
 560                else
 561                        avail = snd_pcm_capture_hw_avail(runtime);
 562
 563                timer = &info->stream_timer[substream->stream].timer;
 564                /*
 565                 * If the data in the buffer is less than one period before
 566                 * this fill, which means the data may not enough on M
 567                 * core side, we need to send message immediately to let
 568                 * M core know the pointer is updated.
 569                 * if there is more than one period data in the buffer before
 570                 * this fill, which means the data is enough on M core side,
 571                 * we can delay one period (using timer) to send the message
 572                 * for reduce the message number in workqueue, because the
 573                 * pointer may be updated by ack function later, we can
 574                 * send latest pointer to M core side.
 575                 */
 576                if ((avail - written_num * period_size) <= period_size) {
 577                        imx_rpmsg_insert_workqueue(substream, msg, info);
 578                } else if (rpmsg->force_lpa && !timer_pending(timer)) {
 579                        int time_msec;
 580
 581                        time_msec = (int)(runtime->period_size * 1000 / runtime->rate);
 582                        mod_timer(timer, jiffies + msecs_to_jiffies(time_msec));
 583                }
 584        }
 585
 586        return 0;
 587}
 588
 589static int imx_rpmsg_pcm_new(struct snd_soc_component *component,
 590                             struct snd_soc_pcm_runtime *rtd)
 591{
 592        struct snd_card *card = rtd->card->snd_card;
 593        struct snd_pcm *pcm = rtd->pcm;
 594        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 595        struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
 596        int ret;
 597
 598        ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
 599        if (ret)
 600                return ret;
 601
 602        imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
 603        return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
 604                                            pcm->card->dev, rpmsg->buffer_size);
 605}
 606
 607static const struct snd_soc_component_driver imx_rpmsg_soc_component = {
 608        .name           = IMX_PCM_DRV_NAME,
 609        .pcm_construct  = imx_rpmsg_pcm_new,
 610        .open           = imx_rpmsg_pcm_open,
 611        .close          = imx_rpmsg_pcm_close,
 612        .hw_params      = imx_rpmsg_pcm_hw_params,
 613        .trigger        = imx_rpmsg_pcm_trigger,
 614        .pointer        = imx_rpmsg_pcm_pointer,
 615        .ack            = imx_rpmsg_pcm_ack,
 616        .prepare        = imx_rpmsg_pcm_prepare,
 617};
 618
 619static void imx_rpmsg_pcm_work(struct work_struct *work)
 620{
 621        struct work_of_rpmsg *work_of_rpmsg;
 622        bool is_notification = false;
 623        struct rpmsg_info *info;
 624        struct rpmsg_msg msg;
 625        unsigned long flags;
 626
 627        work_of_rpmsg = container_of(work, struct work_of_rpmsg, work);
 628        info = work_of_rpmsg->info;
 629
 630        /*
 631         * Every work in the work queue, first we check if there
 632         * is update for period is filled, because there may be not
 633         * enough data in M core side, need to let M core know
 634         * data is updated immediately.
 635         */
 636        spin_lock_irqsave(&info->lock[TX], flags);
 637        if (info->notify_updated[TX]) {
 638                memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
 639                info->notify_updated[TX] = false;
 640                spin_unlock_irqrestore(&info->lock[TX], flags);
 641                info->send_message(&msg, info);
 642        } else {
 643                spin_unlock_irqrestore(&info->lock[TX], flags);
 644        }
 645
 646        spin_lock_irqsave(&info->lock[RX], flags);
 647        if (info->notify_updated[RX]) {
 648                memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
 649                info->notify_updated[RX] = false;
 650                spin_unlock_irqrestore(&info->lock[RX], flags);
 651                info->send_message(&msg, info);
 652        } else {
 653                spin_unlock_irqrestore(&info->lock[RX], flags);
 654        }
 655
 656        /* Skip the notification message for it has been processed above */
 657        if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C &&
 658            (work_of_rpmsg->msg.s_msg.header.cmd == TX_PERIOD_DONE ||
 659             work_of_rpmsg->msg.s_msg.header.cmd == RX_PERIOD_DONE))
 660                is_notification = true;
 661
 662        if (!is_notification)
 663                info->send_message(&work_of_rpmsg->msg, info);
 664
 665        /* update read index */
 666        spin_lock_irqsave(&info->wq_lock, flags);
 667        info->work_read_index++;
 668        info->work_read_index %= WORK_MAX_NUM;
 669        spin_unlock_irqrestore(&info->wq_lock, flags);
 670}
 671
 672static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
 673{
 674        struct snd_soc_component *component;
 675        struct rpmsg_info *info;
 676        int ret, i;
 677
 678        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 679        if (!info)
 680                return -ENOMEM;
 681
 682        platform_set_drvdata(pdev, info);
 683
 684        info->rpdev = container_of(pdev->dev.parent, struct rpmsg_device, dev);
 685        info->dev = &pdev->dev;
 686        /* Setup work queue */
 687        info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_audio",
 688                                                 WQ_HIGHPRI |
 689                                                 WQ_UNBOUND |
 690                                                 WQ_FREEZABLE);
 691        if (!info->rpmsg_wq) {
 692                dev_err(&pdev->dev, "workqueue create failed\n");
 693                return -ENOMEM;
 694        }
 695
 696        /* Write index initialize 1, make it differ with the read index */
 697        info->work_write_index = 1;
 698        info->send_message = imx_rpmsg_pcm_send_message;
 699
 700        for (i = 0; i < WORK_MAX_NUM; i++) {
 701                INIT_WORK(&info->work_list[i].work, imx_rpmsg_pcm_work);
 702                info->work_list[i].info = info;
 703        }
 704
 705        /* Initialize msg */
 706        for (i = 0; i < MSG_MAX_NUM; i++) {
 707                info->msg[i].s_msg.header.cate  = IMX_RPMSG_AUDIO;
 708                info->msg[i].s_msg.header.major = IMX_RMPSG_MAJOR;
 709                info->msg[i].s_msg.header.minor = IMX_RMPSG_MINOR;
 710                info->msg[i].s_msg.header.type  = MSG_TYPE_A;
 711                info->msg[i].s_msg.param.audioindex = 0;
 712        }
 713
 714        init_completion(&info->cmd_complete);
 715        mutex_init(&info->msg_lock);
 716        spin_lock_init(&info->lock[TX]);
 717        spin_lock_init(&info->lock[RX]);
 718        spin_lock_init(&info->wq_lock);
 719
 720        ret = devm_snd_soc_register_component(&pdev->dev,
 721                                              &imx_rpmsg_soc_component,
 722                                              NULL, 0);
 723        if (ret)
 724                goto fail;
 725
 726        component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME);
 727        if (!component) {
 728                ret = -EINVAL;
 729                goto fail;
 730        }
 731#ifdef CONFIG_DEBUG_FS
 732        component->debugfs_prefix = "rpmsg";
 733#endif
 734
 735        return 0;
 736
 737fail:
 738        if (info->rpmsg_wq)
 739                destroy_workqueue(info->rpmsg_wq);
 740
 741        return ret;
 742}
 743
 744static int imx_rpmsg_pcm_remove(struct platform_device *pdev)
 745{
 746        struct rpmsg_info *info = platform_get_drvdata(pdev);
 747
 748        if (info->rpmsg_wq)
 749                destroy_workqueue(info->rpmsg_wq);
 750
 751        return 0;
 752}
 753
 754#ifdef CONFIG_PM
 755static int imx_rpmsg_pcm_runtime_resume(struct device *dev)
 756{
 757        struct rpmsg_info *info = dev_get_drvdata(dev);
 758
 759        cpu_latency_qos_add_request(&info->pm_qos_req, 0);
 760
 761        return 0;
 762}
 763
 764static int imx_rpmsg_pcm_runtime_suspend(struct device *dev)
 765{
 766        struct rpmsg_info *info = dev_get_drvdata(dev);
 767
 768        cpu_latency_qos_remove_request(&info->pm_qos_req);
 769
 770        return 0;
 771}
 772#endif
 773
 774#ifdef CONFIG_PM_SLEEP
 775static int imx_rpmsg_pcm_suspend(struct device *dev)
 776{
 777        struct rpmsg_info *info = dev_get_drvdata(dev);
 778        struct rpmsg_msg *rpmsg_tx;
 779        struct rpmsg_msg *rpmsg_rx;
 780
 781        rpmsg_tx = &info->msg[TX_SUSPEND];
 782        rpmsg_rx = &info->msg[RX_SUSPEND];
 783
 784        rpmsg_tx->s_msg.header.cmd = TX_SUSPEND;
 785        info->send_message(rpmsg_tx, info);
 786
 787        rpmsg_rx->s_msg.header.cmd = RX_SUSPEND;
 788        info->send_message(rpmsg_rx, info);
 789
 790        return 0;
 791}
 792
 793static int imx_rpmsg_pcm_resume(struct device *dev)
 794{
 795        struct rpmsg_info *info = dev_get_drvdata(dev);
 796        struct rpmsg_msg *rpmsg_tx;
 797        struct rpmsg_msg *rpmsg_rx;
 798
 799        rpmsg_tx = &info->msg[TX_RESUME];
 800        rpmsg_rx = &info->msg[RX_RESUME];
 801
 802        rpmsg_tx->s_msg.header.cmd = TX_RESUME;
 803        info->send_message(rpmsg_tx, info);
 804
 805        rpmsg_rx->s_msg.header.cmd = RX_RESUME;
 806        info->send_message(rpmsg_rx, info);
 807
 808        return 0;
 809}
 810#endif /* CONFIG_PM_SLEEP */
 811
 812static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = {
 813        SET_RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend,
 814                           imx_rpmsg_pcm_runtime_resume,
 815                           NULL)
 816        SET_SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend,
 817                                imx_rpmsg_pcm_resume)
 818};
 819
 820static struct platform_driver imx_pcm_rpmsg_driver = {
 821        .probe  = imx_rpmsg_pcm_probe,
 822        .remove = imx_rpmsg_pcm_remove,
 823        .driver = {
 824                .name = IMX_PCM_DRV_NAME,
 825                .pm = &imx_rpmsg_pcm_pm_ops,
 826        },
 827};
 828module_platform_driver(imx_pcm_rpmsg_driver);
 829
 830MODULE_DESCRIPTION("Freescale SoC Audio RPMSG PCM interface");
 831MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
 832MODULE_ALIAS("platform:" IMX_PCM_DRV_NAME);
 833MODULE_LICENSE("GPL v2");
 834