0001
0002
0003
0004 #include <linux/dma-mapping.h>
0005 #include <linux/slab.h>
0006 #include <linux/module.h>
0007 #include <linux/delay.h>
0008 #include <linux/rpmsg.h>
0009 #include <sound/core.h>
0010 #include <sound/pcm.h>
0011 #include <sound/pcm_params.h>
0012 #include <sound/dmaengine_pcm.h>
0013 #include <sound/soc.h>
0014
0015 #include "imx-pcm.h"
0016 #include "fsl_rpmsg.h"
0017 #include "imx-pcm-rpmsg.h"
0018
0019 static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
0020 .info = SNDRV_PCM_INFO_INTERLEAVED |
0021 SNDRV_PCM_INFO_BLOCK_TRANSFER |
0022 SNDRV_PCM_INFO_MMAP |
0023 SNDRV_PCM_INFO_MMAP_VALID |
0024 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
0025 SNDRV_PCM_INFO_PAUSE |
0026 SNDRV_PCM_INFO_RESUME,
0027 .buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE,
0028 .period_bytes_min = 512,
0029 .period_bytes_max = 65536,
0030 .periods_min = 2,
0031 .periods_max = 6000,
0032 .fifo_size = 0,
0033 };
0034
0035 static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
0036 struct rpmsg_info *info)
0037 {
0038 struct rpmsg_device *rpdev = info->rpdev;
0039 int ret = 0;
0040
0041 mutex_lock(&info->msg_lock);
0042 if (!rpdev) {
0043 dev_err(info->dev, "rpmsg channel not ready\n");
0044 mutex_unlock(&info->msg_lock);
0045 return -EINVAL;
0046 }
0047
0048 dev_dbg(&rpdev->dev, "send cmd %d\n", msg->s_msg.header.cmd);
0049
0050 if (!(msg->s_msg.header.type == MSG_TYPE_C))
0051 reinit_completion(&info->cmd_complete);
0052
0053 ret = rpmsg_send(rpdev->ept, (void *)&msg->s_msg,
0054 sizeof(struct rpmsg_s_msg));
0055 if (ret) {
0056 dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
0057 mutex_unlock(&info->msg_lock);
0058 return ret;
0059 }
0060
0061
0062 if (msg->s_msg.header.type == MSG_TYPE_C) {
0063 mutex_unlock(&info->msg_lock);
0064 return 0;
0065 }
0066
0067
0068 ret = wait_for_completion_timeout(&info->cmd_complete,
0069 msecs_to_jiffies(RPMSG_TIMEOUT));
0070 if (!ret) {
0071 dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n",
0072 msg->s_msg.header.cmd);
0073 mutex_unlock(&info->msg_lock);
0074 return -ETIMEDOUT;
0075 }
0076
0077 memcpy(&msg->r_msg, &info->r_msg, sizeof(struct rpmsg_r_msg));
0078 memcpy(&info->msg[msg->r_msg.header.cmd].r_msg,
0079 &msg->r_msg, sizeof(struct rpmsg_r_msg));
0080
0081
0082
0083
0084
0085
0086
0087
0088 switch (msg->s_msg.header.cmd) {
0089 case TX_TERMINATE:
0090 info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
0091 break;
0092 case RX_TERMINATE:
0093 info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
0094 break;
0095 default:
0096 break;
0097 }
0098
0099 dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd,
0100 info->r_msg.param.resp);
0101
0102 mutex_unlock(&info->msg_lock);
0103
0104 return 0;
0105 }
0106
0107 static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
0108 struct rpmsg_msg *msg,
0109 struct rpmsg_info *info)
0110 {
0111 unsigned long flags;
0112 int ret = 0;
0113
0114
0115
0116
0117
0118 spin_lock_irqsave(&info->wq_lock, flags);
0119 if (info->work_write_index != info->work_read_index) {
0120 int index = info->work_write_index;
0121
0122 memcpy(&info->work_list[index].msg, msg,
0123 sizeof(struct rpmsg_s_msg));
0124
0125 queue_work(info->rpmsg_wq, &info->work_list[index].work);
0126 info->work_write_index++;
0127 info->work_write_index %= WORK_MAX_NUM;
0128 } else {
0129 info->msg_drop_count[substream->stream]++;
0130 ret = -EPIPE;
0131 }
0132 spin_unlock_irqrestore(&info->wq_lock, flags);
0133
0134 return ret;
0135 }
0136
0137 static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
0138 struct snd_pcm_substream *substream,
0139 struct snd_pcm_hw_params *params)
0140 {
0141 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0142 struct rpmsg_msg *msg;
0143 int ret = 0;
0144
0145 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0146 msg = &info->msg[TX_HW_PARAM];
0147 msg->s_msg.header.cmd = TX_HW_PARAM;
0148 } else {
0149 msg = &info->msg[RX_HW_PARAM];
0150 msg->s_msg.header.cmd = RX_HW_PARAM;
0151 }
0152
0153 msg->s_msg.param.rate = params_rate(params);
0154
0155 switch (params_format(params)) {
0156 case SNDRV_PCM_FORMAT_S16_LE:
0157 msg->s_msg.param.format = RPMSG_S16_LE;
0158 break;
0159 case SNDRV_PCM_FORMAT_S24_LE:
0160 msg->s_msg.param.format = RPMSG_S24_LE;
0161 break;
0162 case SNDRV_PCM_FORMAT_DSD_U16_LE:
0163 msg->s_msg.param.format = RPMSG_DSD_U16_LE;
0164 break;
0165 case SNDRV_PCM_FORMAT_DSD_U32_LE:
0166 msg->s_msg.param.format = RPMSG_DSD_U32_LE;
0167 break;
0168 default:
0169 msg->s_msg.param.format = RPMSG_S32_LE;
0170 break;
0171 }
0172
0173 switch (params_channels(params)) {
0174 case 1:
0175 msg->s_msg.param.channels = RPMSG_CH_LEFT;
0176 break;
0177 case 2:
0178 msg->s_msg.param.channels = RPMSG_CH_STEREO;
0179 break;
0180 default:
0181 ret = -EINVAL;
0182 break;
0183 }
0184
0185 info->send_message(msg, info);
0186
0187 return ret;
0188 }
0189
0190 static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *component,
0191 struct snd_pcm_substream *substream)
0192 {
0193 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0194 struct rpmsg_msg *msg;
0195 unsigned int pos = 0;
0196 int buffer_tail = 0;
0197
0198 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0199 msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
0200 else
0201 msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
0202
0203 buffer_tail = msg->r_msg.param.buffer_tail;
0204 pos = buffer_tail * snd_pcm_lib_period_bytes(substream);
0205
0206 return bytes_to_frames(substream->runtime, pos);
0207 }
0208
0209 static void imx_rpmsg_timer_callback(struct timer_list *t)
0210 {
0211 struct stream_timer *stream_timer =
0212 from_timer(stream_timer, t, timer);
0213 struct snd_pcm_substream *substream = stream_timer->substream;
0214 struct rpmsg_info *info = stream_timer->info;
0215 struct rpmsg_msg *msg;
0216
0217 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0218 msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
0219 msg->s_msg.header.cmd = TX_PERIOD_DONE;
0220 } else {
0221 msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
0222 msg->s_msg.header.cmd = RX_PERIOD_DONE;
0223 }
0224
0225 imx_rpmsg_insert_workqueue(substream, msg, info);
0226 }
0227
0228 static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
0229 struct snd_pcm_substream *substream)
0230 {
0231 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0232 struct rpmsg_msg *msg;
0233 int ret = 0;
0234 int cmd;
0235
0236 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0237 msg = &info->msg[TX_OPEN];
0238 msg->s_msg.header.cmd = TX_OPEN;
0239
0240
0241 cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM;
0242 info->msg[cmd].s_msg.param.buffer_tail = 0;
0243 info->msg[cmd].r_msg.param.buffer_tail = 0;
0244 info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
0245
0246 } else {
0247 msg = &info->msg[RX_OPEN];
0248 msg->s_msg.header.cmd = RX_OPEN;
0249
0250
0251 cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM;
0252 info->msg[cmd].s_msg.param.buffer_tail = 0;
0253 info->msg[cmd].r_msg.param.buffer_tail = 0;
0254 info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
0255 }
0256
0257 info->send_message(msg, info);
0258
0259 imx_rpmsg_pcm_hardware.period_bytes_max =
0260 imx_rpmsg_pcm_hardware.buffer_bytes_max / 2;
0261
0262 snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware);
0263
0264 ret = snd_pcm_hw_constraint_integer(substream->runtime,
0265 SNDRV_PCM_HW_PARAM_PERIODS);
0266 if (ret < 0)
0267 return ret;
0268
0269 info->msg_drop_count[substream->stream] = 0;
0270
0271
0272 info->stream_timer[substream->stream].info = info;
0273 info->stream_timer[substream->stream].substream = substream;
0274 timer_setup(&info->stream_timer[substream->stream].timer,
0275 imx_rpmsg_timer_callback, 0);
0276 return ret;
0277 }
0278
0279 static int imx_rpmsg_pcm_close(struct snd_soc_component *component,
0280 struct snd_pcm_substream *substream)
0281 {
0282 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0283 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0284 struct rpmsg_msg *msg;
0285 int ret = 0;
0286
0287
0288 flush_workqueue(info->rpmsg_wq);
0289
0290 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0291 msg = &info->msg[TX_CLOSE];
0292 msg->s_msg.header.cmd = TX_CLOSE;
0293 } else {
0294 msg = &info->msg[RX_CLOSE];
0295 msg->s_msg.header.cmd = RX_CLOSE;
0296 }
0297
0298 info->send_message(msg, info);
0299
0300 del_timer(&info->stream_timer[substream->stream].timer);
0301
0302 rtd->dai_link->ignore_suspend = 0;
0303
0304 if (info->msg_drop_count[substream->stream])
0305 dev_warn(rtd->dev, "Msg is dropped!, number is %d\n",
0306 info->msg_drop_count[substream->stream]);
0307
0308 return ret;
0309 }
0310
0311 static int imx_rpmsg_pcm_prepare(struct snd_soc_component *component,
0312 struct snd_pcm_substream *substream)
0313 {
0314 struct snd_pcm_runtime *runtime = substream->runtime;
0315 struct snd_soc_pcm_runtime *rtd = substream->private_data;
0316 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0317 struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
0318
0319
0320
0321
0322
0323 if ((runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
0324 runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) &&
0325 rpmsg->enable_lpa) {
0326
0327
0328
0329
0330 rtd->dai_link->ignore_suspend = 1;
0331 rpmsg->force_lpa = 1;
0332 } else {
0333 rpmsg->force_lpa = 0;
0334 }
0335
0336 return 0;
0337 }
0338
0339 static void imx_rpmsg_pcm_dma_complete(void *arg)
0340 {
0341 struct snd_pcm_substream *substream = arg;
0342
0343 snd_pcm_period_elapsed(substream);
0344 }
0345
0346 static int imx_rpmsg_prepare_and_submit(struct snd_soc_component *component,
0347 struct snd_pcm_substream *substream)
0348 {
0349 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0350 struct rpmsg_msg *msg;
0351
0352 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0353 msg = &info->msg[TX_BUFFER];
0354 msg->s_msg.header.cmd = TX_BUFFER;
0355 } else {
0356 msg = &info->msg[RX_BUFFER];
0357 msg->s_msg.header.cmd = RX_BUFFER;
0358 }
0359
0360
0361 msg->s_msg.param.buffer_addr = substream->runtime->dma_addr;
0362 msg->s_msg.param.buffer_size = snd_pcm_lib_buffer_bytes(substream);
0363 msg->s_msg.param.period_size = snd_pcm_lib_period_bytes(substream);
0364 msg->s_msg.param.buffer_tail = 0;
0365
0366 info->num_period[substream->stream] = msg->s_msg.param.buffer_size /
0367 msg->s_msg.param.period_size;
0368
0369 info->callback[substream->stream] = imx_rpmsg_pcm_dma_complete;
0370 info->callback_param[substream->stream] = substream;
0371
0372 return imx_rpmsg_insert_workqueue(substream, msg, info);
0373 }
0374
0375 static int imx_rpmsg_async_issue_pending(struct snd_soc_component *component,
0376 struct snd_pcm_substream *substream)
0377 {
0378 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0379 struct rpmsg_msg *msg;
0380
0381 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0382 msg = &info->msg[TX_START];
0383 msg->s_msg.header.cmd = TX_START;
0384 } else {
0385 msg = &info->msg[RX_START];
0386 msg->s_msg.header.cmd = RX_START;
0387 }
0388
0389 return imx_rpmsg_insert_workqueue(substream, msg, info);
0390 }
0391
0392 static int imx_rpmsg_restart(struct snd_soc_component *component,
0393 struct snd_pcm_substream *substream)
0394 {
0395 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0396 struct rpmsg_msg *msg;
0397
0398 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0399 msg = &info->msg[TX_RESTART];
0400 msg->s_msg.header.cmd = TX_RESTART;
0401 } else {
0402 msg = &info->msg[RX_RESTART];
0403 msg->s_msg.header.cmd = RX_RESTART;
0404 }
0405
0406 return imx_rpmsg_insert_workqueue(substream, msg, info);
0407 }
0408
0409 static int imx_rpmsg_pause(struct snd_soc_component *component,
0410 struct snd_pcm_substream *substream)
0411 {
0412 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0413 struct rpmsg_msg *msg;
0414
0415 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0416 msg = &info->msg[TX_PAUSE];
0417 msg->s_msg.header.cmd = TX_PAUSE;
0418 } else {
0419 msg = &info->msg[RX_PAUSE];
0420 msg->s_msg.header.cmd = RX_PAUSE;
0421 }
0422
0423 return imx_rpmsg_insert_workqueue(substream, msg, info);
0424 }
0425
0426 static int imx_rpmsg_terminate_all(struct snd_soc_component *component,
0427 struct snd_pcm_substream *substream)
0428 {
0429 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0430 struct rpmsg_msg *msg;
0431 int cmd;
0432
0433 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0434 msg = &info->msg[TX_TERMINATE];
0435 msg->s_msg.header.cmd = TX_TERMINATE;
0436
0437 cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM;
0438 info->msg[cmd].s_msg.param.buffer_tail = 0;
0439 info->msg[cmd].r_msg.param.buffer_tail = 0;
0440 info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
0441 } else {
0442 msg = &info->msg[RX_TERMINATE];
0443 msg->s_msg.header.cmd = RX_TERMINATE;
0444
0445 cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM;
0446 info->msg[cmd].s_msg.param.buffer_tail = 0;
0447 info->msg[cmd].r_msg.param.buffer_tail = 0;
0448 info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
0449 }
0450
0451 del_timer(&info->stream_timer[substream->stream].timer);
0452
0453 return imx_rpmsg_insert_workqueue(substream, msg, info);
0454 }
0455
0456 static int imx_rpmsg_pcm_trigger(struct snd_soc_component *component,
0457 struct snd_pcm_substream *substream, int cmd)
0458 {
0459 struct snd_pcm_runtime *runtime = substream->runtime;
0460 struct snd_soc_pcm_runtime *rtd = substream->private_data;
0461 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0462 struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
0463 int ret = 0;
0464
0465 switch (cmd) {
0466 case SNDRV_PCM_TRIGGER_START:
0467 ret = imx_rpmsg_prepare_and_submit(component, substream);
0468 if (ret)
0469 return ret;
0470 ret = imx_rpmsg_async_issue_pending(component, substream);
0471 break;
0472 case SNDRV_PCM_TRIGGER_RESUME:
0473 if (rpmsg->force_lpa)
0474 break;
0475 fallthrough;
0476 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0477 ret = imx_rpmsg_restart(component, substream);
0478 break;
0479 case SNDRV_PCM_TRIGGER_SUSPEND:
0480 if (!rpmsg->force_lpa) {
0481 if (runtime->info & SNDRV_PCM_INFO_PAUSE)
0482 ret = imx_rpmsg_pause(component, substream);
0483 else
0484 ret = imx_rpmsg_terminate_all(component, substream);
0485 }
0486 break;
0487 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0488 ret = imx_rpmsg_pause(component, substream);
0489 break;
0490 case SNDRV_PCM_TRIGGER_STOP:
0491 ret = imx_rpmsg_terminate_all(component, substream);
0492 break;
0493 default:
0494 return -EINVAL;
0495 }
0496
0497 if (ret)
0498 return ret;
0499
0500 return 0;
0501 }
0502
0503
0504
0505
0506
0507
0508
0509
0510 static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
0511 struct snd_pcm_substream *substream)
0512 {
0513 struct snd_pcm_runtime *runtime = substream->runtime;
0514 struct snd_soc_pcm_runtime *rtd = substream->private_data;
0515 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0516 struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
0517 struct rpmsg_info *info = dev_get_drvdata(component->dev);
0518 snd_pcm_uframes_t period_size = runtime->period_size;
0519 snd_pcm_sframes_t avail;
0520 struct timer_list *timer;
0521 struct rpmsg_msg *msg;
0522 unsigned long flags;
0523 int buffer_tail = 0;
0524 int written_num;
0525
0526 if (!rpmsg->force_lpa)
0527 return 0;
0528
0529 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0530 msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
0531 msg->s_msg.header.cmd = TX_PERIOD_DONE;
0532 } else {
0533 msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
0534 msg->s_msg.header.cmd = RX_PERIOD_DONE;
0535 }
0536
0537 msg->s_msg.header.type = MSG_TYPE_C;
0538
0539 buffer_tail = (frames_to_bytes(runtime, runtime->control->appl_ptr) %
0540 snd_pcm_lib_buffer_bytes(substream));
0541 buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream);
0542
0543
0544 if (buffer_tail != msg->s_msg.param.buffer_tail) {
0545 written_num = buffer_tail - msg->s_msg.param.buffer_tail;
0546 if (written_num < 0)
0547 written_num += runtime->periods;
0548
0549 msg->s_msg.param.buffer_tail = buffer_tail;
0550
0551
0552 spin_lock_irqsave(&info->lock[substream->stream], flags);
0553 memcpy(&info->notify[substream->stream], msg,
0554 sizeof(struct rpmsg_s_msg));
0555 info->notify_updated[substream->stream] = true;
0556 spin_unlock_irqrestore(&info->lock[substream->stream], flags);
0557
0558 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0559 avail = snd_pcm_playback_hw_avail(runtime);
0560 else
0561 avail = snd_pcm_capture_hw_avail(runtime);
0562
0563 timer = &info->stream_timer[substream->stream].timer;
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 if ((avail - written_num * period_size) <= period_size) {
0577 imx_rpmsg_insert_workqueue(substream, msg, info);
0578 } else if (rpmsg->force_lpa && !timer_pending(timer)) {
0579 int time_msec;
0580
0581 time_msec = (int)(runtime->period_size * 1000 / runtime->rate);
0582 mod_timer(timer, jiffies + msecs_to_jiffies(time_msec));
0583 }
0584 }
0585
0586 return 0;
0587 }
0588
0589 static int imx_rpmsg_pcm_new(struct snd_soc_component *component,
0590 struct snd_soc_pcm_runtime *rtd)
0591 {
0592 struct snd_card *card = rtd->card->snd_card;
0593 struct snd_pcm *pcm = rtd->pcm;
0594 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0595 struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
0596 int ret;
0597
0598 ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
0599 if (ret)
0600 return ret;
0601
0602 imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
0603 return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
0604 pcm->card->dev, rpmsg->buffer_size);
0605 }
0606
0607 static const struct snd_soc_component_driver imx_rpmsg_soc_component = {
0608 .name = IMX_PCM_DRV_NAME,
0609 .pcm_construct = imx_rpmsg_pcm_new,
0610 .open = imx_rpmsg_pcm_open,
0611 .close = imx_rpmsg_pcm_close,
0612 .hw_params = imx_rpmsg_pcm_hw_params,
0613 .trigger = imx_rpmsg_pcm_trigger,
0614 .pointer = imx_rpmsg_pcm_pointer,
0615 .ack = imx_rpmsg_pcm_ack,
0616 .prepare = imx_rpmsg_pcm_prepare,
0617 };
0618
0619 static void imx_rpmsg_pcm_work(struct work_struct *work)
0620 {
0621 struct work_of_rpmsg *work_of_rpmsg;
0622 bool is_notification = false;
0623 struct rpmsg_info *info;
0624 struct rpmsg_msg msg;
0625 unsigned long flags;
0626
0627 work_of_rpmsg = container_of(work, struct work_of_rpmsg, work);
0628 info = work_of_rpmsg->info;
0629
0630
0631
0632
0633
0634
0635
0636 spin_lock_irqsave(&info->lock[TX], flags);
0637 if (info->notify_updated[TX]) {
0638 memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
0639 info->notify_updated[TX] = false;
0640 spin_unlock_irqrestore(&info->lock[TX], flags);
0641 info->send_message(&msg, info);
0642 } else {
0643 spin_unlock_irqrestore(&info->lock[TX], flags);
0644 }
0645
0646 spin_lock_irqsave(&info->lock[RX], flags);
0647 if (info->notify_updated[RX]) {
0648 memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
0649 info->notify_updated[RX] = false;
0650 spin_unlock_irqrestore(&info->lock[RX], flags);
0651 info->send_message(&msg, info);
0652 } else {
0653 spin_unlock_irqrestore(&info->lock[RX], flags);
0654 }
0655
0656
0657 if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C &&
0658 (work_of_rpmsg->msg.s_msg.header.cmd == TX_PERIOD_DONE ||
0659 work_of_rpmsg->msg.s_msg.header.cmd == RX_PERIOD_DONE))
0660 is_notification = true;
0661
0662 if (!is_notification)
0663 info->send_message(&work_of_rpmsg->msg, info);
0664
0665
0666 spin_lock_irqsave(&info->wq_lock, flags);
0667 info->work_read_index++;
0668 info->work_read_index %= WORK_MAX_NUM;
0669 spin_unlock_irqrestore(&info->wq_lock, flags);
0670 }
0671
0672 static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
0673 {
0674 struct snd_soc_component *component;
0675 struct rpmsg_info *info;
0676 int ret, i;
0677
0678 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
0679 if (!info)
0680 return -ENOMEM;
0681
0682 platform_set_drvdata(pdev, info);
0683
0684 info->rpdev = container_of(pdev->dev.parent, struct rpmsg_device, dev);
0685 info->dev = &pdev->dev;
0686
0687 info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_audio",
0688 WQ_HIGHPRI |
0689 WQ_UNBOUND |
0690 WQ_FREEZABLE);
0691 if (!info->rpmsg_wq) {
0692 dev_err(&pdev->dev, "workqueue create failed\n");
0693 return -ENOMEM;
0694 }
0695
0696
0697 info->work_write_index = 1;
0698 info->send_message = imx_rpmsg_pcm_send_message;
0699
0700 for (i = 0; i < WORK_MAX_NUM; i++) {
0701 INIT_WORK(&info->work_list[i].work, imx_rpmsg_pcm_work);
0702 info->work_list[i].info = info;
0703 }
0704
0705
0706 for (i = 0; i < MSG_MAX_NUM; i++) {
0707 info->msg[i].s_msg.header.cate = IMX_RPMSG_AUDIO;
0708 info->msg[i].s_msg.header.major = IMX_RMPSG_MAJOR;
0709 info->msg[i].s_msg.header.minor = IMX_RMPSG_MINOR;
0710 info->msg[i].s_msg.header.type = MSG_TYPE_A;
0711 info->msg[i].s_msg.param.audioindex = 0;
0712 }
0713
0714 init_completion(&info->cmd_complete);
0715 mutex_init(&info->msg_lock);
0716 spin_lock_init(&info->lock[TX]);
0717 spin_lock_init(&info->lock[RX]);
0718 spin_lock_init(&info->wq_lock);
0719
0720 ret = devm_snd_soc_register_component(&pdev->dev,
0721 &imx_rpmsg_soc_component,
0722 NULL, 0);
0723 if (ret)
0724 goto fail;
0725
0726 component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME);
0727 if (!component) {
0728 ret = -EINVAL;
0729 goto fail;
0730 }
0731 #ifdef CONFIG_DEBUG_FS
0732 component->debugfs_prefix = "rpmsg";
0733 #endif
0734
0735 return 0;
0736
0737 fail:
0738 if (info->rpmsg_wq)
0739 destroy_workqueue(info->rpmsg_wq);
0740
0741 return ret;
0742 }
0743
0744 static int imx_rpmsg_pcm_remove(struct platform_device *pdev)
0745 {
0746 struct rpmsg_info *info = platform_get_drvdata(pdev);
0747
0748 if (info->rpmsg_wq)
0749 destroy_workqueue(info->rpmsg_wq);
0750
0751 return 0;
0752 }
0753
0754 #ifdef CONFIG_PM
0755 static int imx_rpmsg_pcm_runtime_resume(struct device *dev)
0756 {
0757 struct rpmsg_info *info = dev_get_drvdata(dev);
0758
0759 cpu_latency_qos_add_request(&info->pm_qos_req, 0);
0760
0761 return 0;
0762 }
0763
0764 static int imx_rpmsg_pcm_runtime_suspend(struct device *dev)
0765 {
0766 struct rpmsg_info *info = dev_get_drvdata(dev);
0767
0768 cpu_latency_qos_remove_request(&info->pm_qos_req);
0769
0770 return 0;
0771 }
0772 #endif
0773
0774 #ifdef CONFIG_PM_SLEEP
0775 static int imx_rpmsg_pcm_suspend(struct device *dev)
0776 {
0777 struct rpmsg_info *info = dev_get_drvdata(dev);
0778 struct rpmsg_msg *rpmsg_tx;
0779 struct rpmsg_msg *rpmsg_rx;
0780
0781 rpmsg_tx = &info->msg[TX_SUSPEND];
0782 rpmsg_rx = &info->msg[RX_SUSPEND];
0783
0784 rpmsg_tx->s_msg.header.cmd = TX_SUSPEND;
0785 info->send_message(rpmsg_tx, info);
0786
0787 rpmsg_rx->s_msg.header.cmd = RX_SUSPEND;
0788 info->send_message(rpmsg_rx, info);
0789
0790 return 0;
0791 }
0792
0793 static int imx_rpmsg_pcm_resume(struct device *dev)
0794 {
0795 struct rpmsg_info *info = dev_get_drvdata(dev);
0796 struct rpmsg_msg *rpmsg_tx;
0797 struct rpmsg_msg *rpmsg_rx;
0798
0799 rpmsg_tx = &info->msg[TX_RESUME];
0800 rpmsg_rx = &info->msg[RX_RESUME];
0801
0802 rpmsg_tx->s_msg.header.cmd = TX_RESUME;
0803 info->send_message(rpmsg_tx, info);
0804
0805 rpmsg_rx->s_msg.header.cmd = RX_RESUME;
0806 info->send_message(rpmsg_rx, info);
0807
0808 return 0;
0809 }
0810 #endif
0811
0812 static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = {
0813 SET_RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend,
0814 imx_rpmsg_pcm_runtime_resume,
0815 NULL)
0816 SET_SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend,
0817 imx_rpmsg_pcm_resume)
0818 };
0819
0820 static struct platform_driver imx_pcm_rpmsg_driver = {
0821 .probe = imx_rpmsg_pcm_probe,
0822 .remove = imx_rpmsg_pcm_remove,
0823 .driver = {
0824 .name = IMX_PCM_DRV_NAME,
0825 .pm = &imx_rpmsg_pcm_pm_ops,
0826 },
0827 };
0828 module_platform_driver(imx_pcm_rpmsg_driver);
0829
0830 MODULE_DESCRIPTION("Freescale SoC Audio RPMSG PCM interface");
0831 MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
0832 MODULE_ALIAS("platform:" IMX_PCM_DRV_NAME);
0833 MODULE_LICENSE("GPL v2");