991 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ALSA SoC using the QUICC Multichannel Controller (QMC)4 *5 * Copyright 2022 CS GROUP France6 *7 * Author: Herve Codina <herve.codina@bootlin.com>8 */9 10#include <linux/dma-mapping.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/of_platform.h>14#include <linux/platform_device.h>15#include <linux/slab.h>16#include <soc/fsl/qe/qmc.h>17#include <sound/pcm_params.h>18#include <sound/soc.h>19 20struct qmc_dai_chan {21 struct qmc_dai_prtd *prtd_tx;22 struct qmc_dai_prtd *prtd_rx;23 struct qmc_chan *qmc_chan;24};25 26struct qmc_dai {27 char *name;28 int id;29 struct device *dev;30 unsigned int nb_tx_ts;31 unsigned int nb_rx_ts;32 33 unsigned int nb_chans_avail;34 unsigned int nb_chans_used_tx;35 unsigned int nb_chans_used_rx;36 struct qmc_dai_chan *chans;37};38 39struct qmc_audio {40 struct device *dev;41 unsigned int num_dais;42 struct qmc_dai *dais;43 struct snd_soc_dai_driver *dai_drivers;44};45 46struct qmc_dai_prtd {47 struct qmc_dai *qmc_dai;48 49 snd_pcm_uframes_t buffer_ended;50 snd_pcm_uframes_t buffer_size;51 snd_pcm_uframes_t period_size;52 53 dma_addr_t ch_dma_addr_start;54 dma_addr_t ch_dma_addr_current;55 dma_addr_t ch_dma_addr_end;56 size_t ch_dma_size;57 size_t ch_dma_offset;58 59 unsigned int channels;60 DECLARE_BITMAP(chans_pending, 64);61 struct snd_pcm_substream *substream;62};63 64static int qmc_audio_pcm_construct(struct snd_soc_component *component,65 struct snd_soc_pcm_runtime *rtd)66{67 struct snd_card *card = rtd->card->snd_card;68 int ret;69 70 ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));71 if (ret)72 return ret;73 74 snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,75 64 * 1024, 64 * 1024);76 return 0;77}78 79static bool qmc_audio_access_is_interleaved(snd_pcm_access_t access)80{81 switch (access) {82 case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:83 case SNDRV_PCM_ACCESS_RW_INTERLEAVED:84 return true;85 default:86 break;87 }88 return false;89}90 91static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,92 struct snd_pcm_substream *substream,93 struct snd_pcm_hw_params *params)94{95 struct snd_pcm_runtime *runtime = substream->runtime;96 struct qmc_dai_prtd *prtd = substream->runtime->private_data;97 98 /*99 * In interleaved mode, the driver uses one QMC channel for all audio100 * channels whereas in non-interleaved mode, it uses one QMC channel per101 * audio channel.102 */103 prtd->channels = qmc_audio_access_is_interleaved(params_access(params)) ?104 1 : params_channels(params);105 106 prtd->substream = substream;107 108 prtd->buffer_ended = 0;109 prtd->buffer_size = params_buffer_size(params);110 prtd->period_size = params_period_size(params);111 112 prtd->ch_dma_addr_start = runtime->dma_addr;113 prtd->ch_dma_offset = params_buffer_bytes(params) / prtd->channels;114 prtd->ch_dma_addr_end = runtime->dma_addr + prtd->ch_dma_offset;115 prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;116 prtd->ch_dma_size = params_period_bytes(params) / prtd->channels;117 118 return 0;119}120 121static void qmc_audio_pcm_write_complete(void *context);122 123static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)124{125 unsigned int i;126 int ret;127 128 for (i = 0; i < prtd->channels; i++) {129 bitmap_set(prtd->chans_pending, i, 1);130 131 ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan,132 prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,133 prtd->ch_dma_size,134 qmc_audio_pcm_write_complete,135 &prtd->qmc_dai->chans[i]);136 if (ret) {137 dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",138 i, ret);139 bitmap_clear(prtd->chans_pending, i, 1);140 return ret;141 }142 }143 144 return 0;145}146 147static void qmc_audio_pcm_write_complete(void *context)148{149 struct qmc_dai_chan *chan = context;150 struct qmc_dai_prtd *prtd;151 152 prtd = chan->prtd_tx;153 154 /* Mark the current channel as completed */155 bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);156 157 /*158 * All QMC channels involved must have completed their transfer before159 * submitting a new one.160 */161 if (!bitmap_empty(prtd->chans_pending, 64))162 return;163 164 prtd->buffer_ended += prtd->period_size;165 if (prtd->buffer_ended >= prtd->buffer_size)166 prtd->buffer_ended = 0;167 168 prtd->ch_dma_addr_current += prtd->ch_dma_size;169 if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)170 prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;171 172 qmc_audio_pcm_write_submit(prtd);173 174 snd_pcm_period_elapsed(prtd->substream);175}176 177static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags);178 179static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)180{181 unsigned int i;182 int ret;183 184 for (i = 0; i < prtd->channels; i++) {185 bitmap_set(prtd->chans_pending, i, 1);186 187 ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan,188 prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,189 prtd->ch_dma_size,190 qmc_audio_pcm_read_complete,191 &prtd->qmc_dai->chans[i]);192 if (ret) {193 dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",194 i, ret);195 bitmap_clear(prtd->chans_pending, i, 1);196 return ret;197 }198 }199 200 return 0;201}202 203static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)204{205 struct qmc_dai_chan *chan = context;206 struct qmc_dai_prtd *prtd;207 208 prtd = chan->prtd_rx;209 210 /* Mark the current channel as completed */211 bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);212 213 if (length != prtd->ch_dma_size) {214 dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",215 length, prtd->ch_dma_size);216 }217 218 /*219 * All QMC channels involved must have completed their transfer before220 * submitting a new one.221 */222 if (!bitmap_empty(prtd->chans_pending, 64))223 return;224 225 prtd->buffer_ended += prtd->period_size;226 if (prtd->buffer_ended >= prtd->buffer_size)227 prtd->buffer_ended = 0;228 229 prtd->ch_dma_addr_current += prtd->ch_dma_size;230 if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)231 prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;232 233 qmc_audio_pcm_read_submit(prtd);234 235 snd_pcm_period_elapsed(prtd->substream);236}237 238static int qmc_audio_pcm_trigger(struct snd_soc_component *component,239 struct snd_pcm_substream *substream, int cmd)240{241 struct qmc_dai_prtd *prtd = substream->runtime->private_data;242 unsigned int i;243 int ret;244 245 if (!prtd->qmc_dai) {246 dev_err(component->dev, "qmc_dai is not set\n");247 return -EINVAL;248 }249 250 switch (cmd) {251 case SNDRV_PCM_TRIGGER_START:252 bitmap_zero(prtd->chans_pending, 64);253 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {254 for (i = 0; i < prtd->channels; i++)255 prtd->qmc_dai->chans[i].prtd_tx = prtd;256 257 /* Submit first chunk ... */258 ret = qmc_audio_pcm_write_submit(prtd);259 if (ret)260 return ret;261 262 /* ... prepare next one ... */263 prtd->ch_dma_addr_current += prtd->ch_dma_size;264 if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)265 prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;266 267 /* ... and send it */268 ret = qmc_audio_pcm_write_submit(prtd);269 if (ret)270 return ret;271 } else {272 for (i = 0; i < prtd->channels; i++)273 prtd->qmc_dai->chans[i].prtd_rx = prtd;274 275 /* Submit first chunk ... */276 ret = qmc_audio_pcm_read_submit(prtd);277 if (ret)278 return ret;279 280 /* ... prepare next one ... */281 prtd->ch_dma_addr_current += prtd->ch_dma_size;282 if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)283 prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;284 285 /* ... and send it */286 ret = qmc_audio_pcm_read_submit(prtd);287 if (ret)288 return ret;289 }290 break;291 292 case SNDRV_PCM_TRIGGER_RESUME:293 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:294 break;295 296 case SNDRV_PCM_TRIGGER_STOP:297 case SNDRV_PCM_TRIGGER_SUSPEND:298 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:299 break;300 301 default:302 return -EINVAL;303 }304 305 return 0;306}307 308static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *component,309 struct snd_pcm_substream *substream)310{311 struct qmc_dai_prtd *prtd = substream->runtime->private_data;312 313 return prtd->buffer_ended;314}315 316static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,317 const struct of_phandle_args *args,318 const char **dai_name)319{320 struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);321 struct snd_soc_dai_driver *dai_driver;322 int id = args->args[0];323 int i;324 325 for (i = 0; i < qmc_audio->num_dais; i++) {326 dai_driver = qmc_audio->dai_drivers + i;327 if (dai_driver->id == id) {328 *dai_name = dai_driver->name;329 return 0;330 }331 }332 333 return -EINVAL;334}335 336static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {337 .info = SNDRV_PCM_INFO_MMAP |338 SNDRV_PCM_INFO_MMAP_VALID |339 SNDRV_PCM_INFO_INTERLEAVED |340 SNDRV_PCM_INFO_NONINTERLEAVED |341 SNDRV_PCM_INFO_PAUSE,342 .period_bytes_min = 32,343 .period_bytes_max = 64 * 1024,344 .periods_min = 2,345 .periods_max = 2 * 1024,346 .buffer_bytes_max = 64 * 1024,347};348 349static int qmc_audio_pcm_open(struct snd_soc_component *component,350 struct snd_pcm_substream *substream)351{352 struct snd_pcm_runtime *runtime = substream->runtime;353 struct qmc_dai_prtd *prtd;354 int ret;355 356 snd_soc_set_runtime_hwparams(substream, &qmc_audio_pcm_hardware);357 358 /* ensure that buffer size is a multiple of period size */359 ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);360 if (ret < 0)361 return ret;362 363 prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);364 if (!prtd)365 return -ENOMEM;366 367 runtime->private_data = prtd;368 369 return 0;370}371 372static int qmc_audio_pcm_close(struct snd_soc_component *component,373 struct snd_pcm_substream *substream)374{375 struct qmc_dai_prtd *prtd = substream->runtime->private_data;376 377 kfree(prtd);378 return 0;379}380 381static const struct snd_soc_component_driver qmc_audio_soc_platform = {382 .open = qmc_audio_pcm_open,383 .close = qmc_audio_pcm_close,384 .hw_params = qmc_audio_pcm_hw_params,385 .trigger = qmc_audio_pcm_trigger,386 .pointer = qmc_audio_pcm_pointer,387 .pcm_construct = qmc_audio_pcm_construct,388 .of_xlate_dai_name = qmc_audio_of_xlate_dai_name,389};390 391static unsigned int qmc_dai_get_index(struct snd_soc_dai *dai)392{393 struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);394 395 return dai->driver - qmc_audio->dai_drivers;396}397 398static struct qmc_dai *qmc_dai_get_data(struct snd_soc_dai *dai)399{400 struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);401 unsigned int index;402 403 index = qmc_dai_get_index(dai);404 if (index > qmc_audio->num_dais)405 return NULL;406 407 return qmc_audio->dais + index;408}409 410/*411 * The constraints for format/channel is to match with the number of 8bit412 * time-slots available.413 */414static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_dai,415 struct snd_pcm_hw_params *params,416 unsigned int nb_ts)417{418 struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);419 snd_pcm_format_t format = params_format(params);420 struct snd_interval ch = {0};421 422 switch (snd_pcm_format_physical_width(format)) {423 case 8:424 ch.max = nb_ts;425 break;426 case 16:427 ch.max = nb_ts / 2;428 break;429 case 32:430 ch.max = nb_ts / 4;431 break;432 case 64:433 ch.max = nb_ts / 8;434 break;435 default:436 dev_err(qmc_dai->dev, "format physical width %u not supported\n",437 snd_pcm_format_physical_width(format));438 return -EINVAL;439 }440 441 ch.min = ch.max ? 1 : 0;442 443 return snd_interval_refine(c, &ch);444}445 446static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,447 struct snd_pcm_hw_rule *rule)448{449 struct qmc_dai *qmc_dai = rule->private;450 451 return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);452}453 454static int qmc_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,455 struct snd_pcm_hw_rule *rule)456{457 struct qmc_dai *qmc_dai = rule->private;458 459 return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_rx_ts);460}461 462static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,463 struct snd_pcm_hw_params *params,464 unsigned int nb_ts)465{466 struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);467 unsigned int channels = params_channels(params);468 unsigned int slot_width;469 snd_pcm_format_t format;470 struct snd_mask f_new;471 472 if (!channels || channels > nb_ts) {473 dev_err(qmc_dai->dev, "channels %u not supported\n",474 nb_ts);475 return -EINVAL;476 }477 478 slot_width = (nb_ts / channels) * 8;479 480 snd_mask_none(&f_new);481 pcm_for_each_format(format) {482 if (snd_mask_test_format(f_old, format)) {483 if (snd_pcm_format_physical_width(format) <= slot_width)484 snd_mask_set_format(&f_new, format);485 }486 }487 488 return snd_mask_refine(f_old, &f_new);489}490 491static int qmc_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,492 struct snd_pcm_hw_rule *rule)493{494 struct qmc_dai *qmc_dai = rule->private;495 496 return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);497}498 499static int qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,500 struct snd_pcm_hw_rule *rule)501{502 struct qmc_dai *qmc_dai = rule->private;503 504 return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);505}506 507static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream,508 struct qmc_dai *qmc_dai)509{510 snd_pcm_hw_rule_func_t hw_rule_channels_by_format;511 snd_pcm_hw_rule_func_t hw_rule_format_by_channels;512 unsigned int frame_bits;513 u64 access;514 int ret;515 516 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {517 hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;518 hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;519 frame_bits = qmc_dai->nb_rx_ts * 8;520 } else {521 hw_rule_channels_by_format = qmc_dai_hw_rule_playback_channels_by_format;522 hw_rule_format_by_channels = qmc_dai_hw_rule_playback_format_by_channels;523 frame_bits = qmc_dai->nb_tx_ts * 8;524 }525 526 ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,527 hw_rule_channels_by_format, qmc_dai,528 SNDRV_PCM_HW_PARAM_FORMAT, -1);529 if (ret) {530 dev_err(qmc_dai->dev, "Failed to add channels rule (%d)\n", ret);531 return ret;532 }533 534 ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,535 hw_rule_format_by_channels, qmc_dai,536 SNDRV_PCM_HW_PARAM_CHANNELS, -1);537 if (ret) {538 dev_err(qmc_dai->dev, "Failed to add format rule (%d)\n", ret);539 return ret;540 }541 542 ret = snd_pcm_hw_constraint_single(substream->runtime,543 SNDRV_PCM_HW_PARAM_FRAME_BITS,544 frame_bits);545 if (ret < 0) {546 dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);547 return ret;548 }549 550 access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |551 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED;552 ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,553 access);554 if (ret) {555 dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);556 return ret;557 }558 559 return 0;560}561 562static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substream,563 struct qmc_dai *qmc_dai)564{565 unsigned int frame_bits;566 u64 access;567 int ret;568 569 frame_bits = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ?570 qmc_dai->nb_rx_ts * 8 : qmc_dai->nb_tx_ts * 8;571 ret = snd_pcm_hw_constraint_single(substream->runtime,572 SNDRV_PCM_HW_PARAM_FRAME_BITS,573 frame_bits);574 if (ret < 0) {575 dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);576 return ret;577 }578 579 access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |580 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;581 ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,582 access);583 if (ret) {584 dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);585 return ret;586 }587 588 return 0;589}590 591static int qmc_dai_startup(struct snd_pcm_substream *substream,592 struct snd_soc_dai *dai)593{594 struct qmc_dai_prtd *prtd = substream->runtime->private_data;595 struct qmc_dai *qmc_dai;596 597 qmc_dai = qmc_dai_get_data(dai);598 if (!qmc_dai) {599 dev_err(dai->dev, "Invalid dai\n");600 return -EINVAL;601 }602 603 prtd->qmc_dai = qmc_dai;604 605 return qmc_dai->nb_chans_avail > 1 ?606 qmc_dai_constraints_noninterleaved(substream, qmc_dai) :607 qmc_dai_constraints_interleaved(substream, qmc_dai);608}609 610static int qmc_dai_hw_params(struct snd_pcm_substream *substream,611 struct snd_pcm_hw_params *params,612 struct snd_soc_dai *dai)613{614 struct qmc_chan_param chan_param = {0};615 unsigned int nb_chans_used;616 struct qmc_dai *qmc_dai;617 unsigned int i;618 int ret;619 620 qmc_dai = qmc_dai_get_data(dai);621 if (!qmc_dai) {622 dev_err(dai->dev, "Invalid dai\n");623 return -EINVAL;624 }625 626 /*627 * In interleaved mode, the driver uses one QMC channel for all audio628 * channels whereas in non-interleaved mode, it uses one QMC channel per629 * audio channel.630 */631 nb_chans_used = qmc_audio_access_is_interleaved(params_access(params)) ?632 1 : params_channels(params);633 634 if (nb_chans_used > qmc_dai->nb_chans_avail) {635 dev_err(dai->dev, "Not enough qmc_chans. Need %u, avail %u\n",636 nb_chans_used, qmc_dai->nb_chans_avail);637 return -EINVAL;638 }639 640 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {641 chan_param.mode = QMC_TRANSPARENT;642 chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;643 for (i = 0; i < nb_chans_used; i++) {644 ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param);645 if (ret) {646 dev_err(dai->dev, "chans[%u], set param failed %d\n",647 i, ret);648 return ret;649 }650 }651 qmc_dai->nb_chans_used_rx = nb_chans_used;652 } else {653 qmc_dai->nb_chans_used_tx = nb_chans_used;654 }655 656 return 0;657}658 659static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,660 struct snd_soc_dai *dai)661{662 unsigned int nb_chans_used;663 struct qmc_dai *qmc_dai;664 unsigned int i;665 int direction;666 int ret = 0;667 int ret_tmp;668 669 qmc_dai = qmc_dai_get_data(dai);670 if (!qmc_dai) {671 dev_err(dai->dev, "Invalid dai\n");672 return -EINVAL;673 }674 675 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {676 direction = QMC_CHAN_WRITE;677 nb_chans_used = qmc_dai->nb_chans_used_tx;678 } else {679 direction = QMC_CHAN_READ;680 nb_chans_used = qmc_dai->nb_chans_used_rx;681 }682 683 switch (cmd) {684 case SNDRV_PCM_TRIGGER_START:685 case SNDRV_PCM_TRIGGER_RESUME:686 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:687 for (i = 0; i < nb_chans_used; i++) {688 ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction);689 if (ret)690 goto err_stop;691 }692 break;693 694 case SNDRV_PCM_TRIGGER_STOP:695 /* Stop and reset all QMC channels and return the first error encountered */696 for (i = 0; i < nb_chans_used; i++) {697 ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);698 if (!ret)699 ret = ret_tmp;700 if (ret_tmp)701 continue;702 703 ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);704 if (!ret)705 ret = ret_tmp;706 }707 if (ret)708 return ret;709 break;710 711 case SNDRV_PCM_TRIGGER_SUSPEND:712 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:713 /* Stop all QMC channels and return the first error encountered */714 for (i = 0; i < nb_chans_used; i++) {715 ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);716 if (!ret)717 ret = ret_tmp;718 }719 if (ret)720 return ret;721 break;722 723 default:724 return -EINVAL;725 }726 727 return 0;728 729err_stop:730 while (i--) {731 qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);732 qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);733 }734 return ret;735}736 737static const struct snd_soc_dai_ops qmc_dai_ops = {738 .startup = qmc_dai_startup,739 .trigger = qmc_dai_trigger,740 .hw_params = qmc_dai_hw_params,741};742 743static u64 qmc_audio_formats(u8 nb_ts, bool is_noninterleaved)744{745 unsigned int format_width;746 unsigned int chan_width;747 snd_pcm_format_t format;748 u64 formats_mask;749 750 if (!nb_ts)751 return 0;752 753 formats_mask = 0;754 chan_width = nb_ts * 8;755 pcm_for_each_format(format) {756 /*757 * Support format other than little-endian (ie big-endian or758 * without endianness such as 8bit formats)759 */760 if (snd_pcm_format_little_endian(format) == 1)761 continue;762 763 /* Support physical width multiple of 8bit */764 format_width = snd_pcm_format_physical_width(format);765 if (format_width == 0 || format_width % 8)766 continue;767 768 /*769 * And support physical width that can fit N times in the770 * channel771 */772 if (format_width > chan_width || chan_width % format_width)773 continue;774 775 /*776 * In non interleaved mode, we can only support formats that777 * can fit only 1 time in the channel778 */779 if (is_noninterleaved && format_width != chan_width)780 continue;781 782 formats_mask |= pcm_format_to_bits(format);783 }784 return formats_mask;785}786 787static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,788 struct qmc_dai *qmc_dai,789 struct snd_soc_dai_driver *qmc_soc_dai_driver)790{791 struct qmc_chan_info info;792 unsigned long rx_fs_rate;793 unsigned long tx_fs_rate;794 unsigned int nb_tx_ts;795 unsigned int nb_rx_ts;796 unsigned int i;797 int count;798 u32 val;799 int ret;800 801 qmc_dai->dev = qmc_audio->dev;802 803 ret = of_property_read_u32(np, "reg", &val);804 if (ret) {805 dev_err(qmc_audio->dev, "%pOF: failed to read reg\n", np);806 return ret;807 }808 qmc_dai->id = val;809 810 qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",811 np->parent->name, qmc_dai->id);812 if (!qmc_dai->name)813 return -ENOMEM;814 815 count = qmc_chan_count_phandles(np, "fsl,qmc-chan");816 if (count < 0)817 return dev_err_probe(qmc_audio->dev, count,818 "dai %d get number of QMC channel failed\n", qmc_dai->id);819 if (!count)820 return dev_err_probe(qmc_audio->dev, -EINVAL,821 "dai %d no QMC channel defined\n", qmc_dai->id);822 823 qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL);824 if (!qmc_dai->chans)825 return -ENOMEM;826 827 for (i = 0; i < count; i++) {828 qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,829 "fsl,qmc-chan", i);830 if (IS_ERR(qmc_dai->chans[i].qmc_chan)) {831 return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan),832 "dai %d get QMC channel %d failed\n", qmc_dai->id, i);833 }834 835 ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info);836 if (ret) {837 dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",838 qmc_dai->id, i, ret);839 return ret;840 }841 dev_info(qmc_audio->dev, "dai %d QMC channel %d mode %d, nb_tx_ts %u, nb_rx_ts %u\n",842 qmc_dai->id, i, info.mode, info.nb_tx_ts, info.nb_rx_ts);843 844 if (info.mode != QMC_TRANSPARENT) {845 dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n",846 qmc_dai->id, i, info.mode);847 return -EINVAL;848 }849 850 /*851 * All channels must have the same number of Tx slots and the852 * same numbers of Rx slots.853 */854 if (i == 0) {855 nb_tx_ts = info.nb_tx_ts;856 nb_rx_ts = info.nb_rx_ts;857 tx_fs_rate = info.tx_fs_rate;858 rx_fs_rate = info.rx_fs_rate;859 } else {860 if (nb_tx_ts != info.nb_tx_ts) {861 dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Tx timeslots (%u instead of %u)\n",862 qmc_dai->id, i, info.nb_tx_ts, nb_tx_ts);863 return -EINVAL;864 }865 if (nb_rx_ts != info.nb_rx_ts) {866 dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Rx timeslots (%u instead of %u)\n",867 qmc_dai->id, i, info.nb_rx_ts, nb_rx_ts);868 return -EINVAL;869 }870 if (tx_fs_rate != info.tx_fs_rate) {871 dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Tx frame sample rate (%lu instead of %lu)\n",872 qmc_dai->id, i, info.tx_fs_rate, tx_fs_rate);873 return -EINVAL;874 }875 if (rx_fs_rate != info.rx_fs_rate) {876 dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Rx frame sample rate (%lu instead of %lu)\n",877 qmc_dai->id, i, info.rx_fs_rate, rx_fs_rate);878 return -EINVAL;879 }880 }881 }882 883 qmc_dai->nb_chans_avail = count;884 qmc_dai->nb_tx_ts = nb_tx_ts * count;885 qmc_dai->nb_rx_ts = nb_rx_ts * count;886 887 qmc_soc_dai_driver->id = qmc_dai->id;888 qmc_soc_dai_driver->name = qmc_dai->name;889 890 qmc_soc_dai_driver->playback.channels_min = 0;891 qmc_soc_dai_driver->playback.channels_max = 0;892 if (nb_tx_ts) {893 qmc_soc_dai_driver->playback.channels_min = 1;894 qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts;895 }896 qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts,897 count > 1 ? true : false);898 899 qmc_soc_dai_driver->capture.channels_min = 0;900 qmc_soc_dai_driver->capture.channels_max = 0;901 if (nb_rx_ts) {902 qmc_soc_dai_driver->capture.channels_min = 1;903 qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts;904 }905 qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts,906 count > 1 ? true : false);907 908 qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate);909 qmc_soc_dai_driver->playback.rate_min = tx_fs_rate;910 qmc_soc_dai_driver->playback.rate_max = tx_fs_rate;911 qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(rx_fs_rate);912 qmc_soc_dai_driver->capture.rate_min = rx_fs_rate;913 qmc_soc_dai_driver->capture.rate_max = rx_fs_rate;914 915 qmc_soc_dai_driver->ops = &qmc_dai_ops;916 917 return 0;918}919 920static int qmc_audio_probe(struct platform_device *pdev)921{922 struct device_node *np = pdev->dev.of_node;923 struct qmc_audio *qmc_audio;924 struct device_node *child;925 unsigned int i;926 int ret;927 928 qmc_audio = devm_kzalloc(&pdev->dev, sizeof(*qmc_audio), GFP_KERNEL);929 if (!qmc_audio)930 return -ENOMEM;931 932 qmc_audio->dev = &pdev->dev;933 934 qmc_audio->num_dais = of_get_available_child_count(np);935 if (qmc_audio->num_dais) {936 qmc_audio->dais = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,937 sizeof(*qmc_audio->dais),938 GFP_KERNEL);939 if (!qmc_audio->dais)940 return -ENOMEM;941 942 qmc_audio->dai_drivers = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,943 sizeof(*qmc_audio->dai_drivers),944 GFP_KERNEL);945 if (!qmc_audio->dai_drivers)946 return -ENOMEM;947 }948 949 i = 0;950 for_each_available_child_of_node(np, child) {951 ret = qmc_audio_dai_parse(qmc_audio, child,952 qmc_audio->dais + i,953 qmc_audio->dai_drivers + i);954 if (ret) {955 of_node_put(child);956 return ret;957 }958 i++;959 }960 961 platform_set_drvdata(pdev, qmc_audio);962 963 ret = devm_snd_soc_register_component(qmc_audio->dev,964 &qmc_audio_soc_platform,965 qmc_audio->dai_drivers,966 qmc_audio->num_dais);967 if (ret)968 return ret;969 970 return 0;971}972 973static const struct of_device_id qmc_audio_id_table[] = {974 { .compatible = "fsl,qmc-audio" },975 {} /* sentinel */976};977MODULE_DEVICE_TABLE(of, qmc_audio_id_table);978 979static struct platform_driver qmc_audio_driver = {980 .driver = {981 .name = "fsl-qmc-audio",982 .of_match_table = of_match_ptr(qmc_audio_id_table),983 },984 .probe = qmc_audio_probe,985};986module_platform_driver(qmc_audio_driver);987 988MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");989MODULE_DESCRIPTION("CPM/QE QMC audio driver");990MODULE_LICENSE("GPL");991