History

ASoC: fsl: fsl_qmc_audio: Reduce amount of

Merge series from Christophe Leroy <christophe.leroy@csgroup.eu>: This is a RESEND of v3 sent one month ago, see: https://lore.kernel.org/all/cover.1754993232.git.christophe.leroy@csgroup.eu/ This series reduces significantly the amount of interrupts on fsl_qmc_audio device. Patches 1 and 2 are preparatory patches. Patch 3 is the main change Patch 4 is a cleanup which is enabled by previous patch

Mark Brown committed 1 year ago

Commit 5998f0d2 parents 309e94a 2c618f32 files · +87 −82Browse files

Unified · Split

2 files
  1. drivers/soc/fsl/qe/qmc.c +33 −11
  2. sound/soc/fsl/fsl_qmc_audio.c +54 −71
drivers/soc/fsl/qe/qmc.c+33−11
@@ -461,9 +461,16 @@ int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, · 460 unmodified lines
461 461
462 ctrl = qmc_read16(&bd->cbd_sc);462 ctrl = qmc_read16(&bd->cbd_sc);
463 if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {463 if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
464 /* We are full ... */464 if (!(ctrl & (QMC_BD_TX_R | QMC_BD_TX_I)) && bd == chan->txbd_done) {
465 ret = -EBUSY;465 if (ctrl & QMC_BD_TX_W)
466 goto end;466 chan->txbd_done = chan->txbds;
467 else
468 chan->txbd_done++;
469 } else {
470 /* We are full ... */
471 ret = -EBUSY;
472 goto end;
473 }
467 }474 }
468 475
469 qmc_write16(&bd->cbd_datlen, length);476 qmc_write16(&bd->cbd_datlen, length);
@@ -475,6 +482,10 @@ int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, · 5 unmodified lines
475 482
476 /* Activate the descriptor */483 /* Activate the descriptor */
477 ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);484 ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
485 if (complete)
486 ctrl |= QMC_BD_TX_I;
487 else
488 ctrl &= ~QMC_BD_TX_I;
478 wmb(); /* Be sure to flush the descriptor before control update */489 wmb(); /* Be sure to flush the descriptor before control update */
479 qmc_write16(&bd->cbd_sc, ctrl);490 qmc_write16(&bd->cbd_sc, ctrl);
480 491
@@ -569,9 +580,16 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, · 88 unmodified lines
569 580
570 ctrl = qmc_read16(&bd->cbd_sc);581 ctrl = qmc_read16(&bd->cbd_sc);
571 if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {582 if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
572 /* We are full ... */583 if (!(ctrl & (QMC_BD_RX_E | QMC_BD_RX_I)) && bd == chan->rxbd_done) {
573 ret = -EBUSY;584 if (ctrl & QMC_BD_RX_W)
574 goto end;585 chan->rxbd_done = chan->rxbds;
586 else
587 chan->rxbd_done++;
588 } else {
589 /* We are full ... */
590 ret = -EBUSY;
591 goto end;
592 }
575 }593 }
576 594
577 qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */595 qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
@@ -587,6 +605,10 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, · 9 unmodified lines
587 605
588 /* Activate the descriptor */606 /* Activate the descriptor */
589 ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);607 ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
608 if (complete)
609 ctrl |= QMC_BD_RX_I;
610 else
611 ctrl &= ~QMC_BD_RX_I;
590 wmb(); /* Be sure to flush data before descriptor activation */612 wmb(); /* Be sure to flush data before descriptor activation */
591 qmc_write16(&bd->cbd_sc, ctrl);613 qmc_write16(&bd->cbd_sc, ctrl);
592 614
@@ -1482,19 +1504,19 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) · 889 unmodified lines
1482 1504
1483 /* Init Rx BDs and set Wrap bit on last descriptor */1505 /* Init Rx BDs and set Wrap bit on last descriptor */
1484 BUILD_BUG_ON(QMC_NB_RXBDS == 0);1506 BUILD_BUG_ON(QMC_NB_RXBDS == 0);
1485 val = QMC_BD_RX_I;
1486 for (i = 0; i < QMC_NB_RXBDS; i++) {1507 for (i = 0; i < QMC_NB_RXBDS; i++) {
1487 bd = chan->rxbds + i;1508 bd = chan->rxbds + i;
1488 qmc_write16(&bd->cbd_sc, val);1509 qmc_write16(&bd->cbd_sc, 0);
1489 }1510 }
1490 bd = chan->rxbds + QMC_NB_RXBDS - 1;1511 bd = chan->rxbds + QMC_NB_RXBDS - 1;
1491 qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);1512 qmc_write16(&bd->cbd_sc, QMC_BD_RX_W);
1492 1513
1493 /* Init Tx BDs and set Wrap bit on last descriptor */1514 /* Init Tx BDs and set Wrap bit on last descriptor */
1494 BUILD_BUG_ON(QMC_NB_TXBDS == 0);1515 BUILD_BUG_ON(QMC_NB_TXBDS == 0);
1495 val = QMC_BD_TX_I;
1496 if (chan->mode == QMC_HDLC)1516 if (chan->mode == QMC_HDLC)
1497 val |= QMC_BD_TX_L | QMC_BD_TX_TC;1517 val = QMC_BD_TX_L | QMC_BD_TX_TC;
1518 else
1519 val = 0;
1498 for (i = 0; i < QMC_NB_TXBDS; i++) {1520 for (i = 0; i < QMC_NB_TXBDS; i++) {
1499 bd = chan->txbds + i;1521 bd = chan->txbds + i;
1500 qmc_write16(&bd->cbd_sc, val);1522 qmc_write16(&bd->cbd_sc, val);
sound/soc/fsl/fsl_qmc_audio.c+54−71
@@ -17,12 +17,6 @@ · 16 unmodified lines
17#include <sound/pcm_params.h>17#include <sound/pcm_params.h>
18#include <sound/soc.h>18#include <sound/soc.h>
19 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 {20struct qmc_dai {
27 char *name;21 char *name;
28 int id;22 int id;
@@ -33,7 +27,7 @@ struct qmc_dai { · 4 unmodified lines
33 unsigned int nb_chans_avail;27 unsigned int nb_chans_avail;
34 unsigned int nb_chans_used_tx;28 unsigned int nb_chans_used_tx;
35 unsigned int nb_chans_used_rx;29 unsigned int nb_chans_used_rx;
36 struct qmc_dai_chan *chans;30 struct qmc_chan **qmc_chans;
37};31};
38 32
39struct qmc_audio {33struct qmc_audio {
@@ -57,7 +51,6 @@ struct qmc_dai_prtd { · 17 unmodified lines
57 size_t ch_dma_offset;51 size_t ch_dma_offset;
58 52
59 unsigned int channels;53 unsigned int channels;
60 DECLARE_BITMAP(chans_pending, 64);
61 struct snd_pcm_substream *substream;54 struct snd_pcm_substream *substream;
62};55};
63 56
@@ -126,17 +119,14 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd) · 62 unmodified lines
126 int ret;119 int ret;
127 120
128 for (i = 0; i < prtd->channels; i++) {121 for (i = 0; i < prtd->channels; i++) {
129 bitmap_set(prtd->chans_pending, i, 1);122 ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chans[i],
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,123 prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
133 prtd->ch_dma_size,124 prtd->ch_dma_size,
134 qmc_audio_pcm_write_complete,125 i == prtd->channels - 1 ? qmc_audio_pcm_write_complete :
135 &prtd->qmc_dai->chans[i]);126 NULL, prtd);
136 if (ret) {127 if (ret) {
137 dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",128 dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",
138 i, ret);129 i, ret);
139 bitmap_clear(prtd->chans_pending, i, 1);
140 return ret;130 return ret;
141 }131 }
142 }132 }
@@ -146,20 +136,7 @@ static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd) · 3 unmodified lines
146 136
147static void qmc_audio_pcm_write_complete(void *context)137static void qmc_audio_pcm_write_complete(void *context)
148{138{
149 struct qmc_dai_chan *chan = context;139 struct qmc_dai_prtd *prtd = 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 before
159 * submitting a new one.
160 */
161 if (!bitmap_empty(prtd->chans_pending, 64))
162 return;
163 140
164 prtd->buffer_ended += prtd->period_size;141 prtd->buffer_ended += prtd->period_size;
165 if (prtd->buffer_ended >= prtd->buffer_size)142 if (prtd->buffer_ended >= prtd->buffer_size)
@@ -182,17 +159,14 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd) · 16 unmodified lines
182 int ret;159 int ret;
183 160
184 for (i = 0; i < prtd->channels; i++) {161 for (i = 0; i < prtd->channels; i++) {
185 bitmap_set(prtd->chans_pending, i, 1);162 ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chans[i],
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,163 prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
189 prtd->ch_dma_size,164 prtd->ch_dma_size,
190 qmc_audio_pcm_read_complete,165 i == prtd->channels - 1 ? qmc_audio_pcm_read_complete :
191 &prtd->qmc_dai->chans[i]);166 NULL, prtd);
192 if (ret) {167 if (ret) {
193 dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",168 dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",
194 i, ret);169 i, ret);
195 bitmap_clear(prtd->chans_pending, i, 1);
196 return ret;170 return ret;
197 }171 }
198 }172 }
@@ -202,26 +176,13 @@ static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd) · 3 unmodified lines
202 176
203static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)177static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)
204{178{
205 struct qmc_dai_chan *chan = context;179 struct qmc_dai_prtd *prtd = 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 180
213 if (length != prtd->ch_dma_size) {181 if (length != prtd->ch_dma_size) {
214 dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",182 dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
215 length, prtd->ch_dma_size);183 length, prtd->ch_dma_size);
216 }184 }
217 185
218 /*
219 * All QMC channels involved must have completed their transfer before
220 * submitting a new one.
221 */
222 if (!bitmap_empty(prtd->chans_pending, 64))
223 return;
224
225 prtd->buffer_ended += prtd->period_size;186 prtd->buffer_ended += prtd->period_size;
226 if (prtd->buffer_ended >= prtd->buffer_size)187 if (prtd->buffer_ended >= prtd->buffer_size)
227 prtd->buffer_ended = 0;188 prtd->buffer_ended = 0;
@@ -239,7 +200,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, · 11 unmodified lines
239 struct snd_pcm_substream *substream, int cmd)200 struct snd_pcm_substream *substream, int cmd)
240{201{
241 struct qmc_dai_prtd *prtd = substream->runtime->private_data;202 struct qmc_dai_prtd *prtd = substream->runtime->private_data;
242 unsigned int i;
243 int ret;203 int ret;
244 204
245 if (!prtd->qmc_dai) {205 if (!prtd->qmc_dai) {
@@ -249,14 +209,10 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, · 3 unmodified lines
249 209
250 switch (cmd) {210 switch (cmd) {
251 case SNDRV_PCM_TRIGGER_START:211 case SNDRV_PCM_TRIGGER_START:
252 bitmap_zero(prtd->chans_pending, 64);
253 prtd->buffer_ended = 0;212 prtd->buffer_ended = 0;
254 prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;213 prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
255 214
256 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {215 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
257 for (i = 0; i < prtd->channels; i++)
258 prtd->qmc_dai->chans[i].prtd_tx = prtd;
259
260 /* Submit first chunk ... */216 /* Submit first chunk ... */
261 ret = qmc_audio_pcm_write_submit(prtd);217 ret = qmc_audio_pcm_write_submit(prtd);
262 if (ret)218 if (ret)
@@ -272,9 +228,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, · 9 unmodified lines
272 if (ret)228 if (ret)
273 return ret;229 return ret;
274 } else {230 } else {
275 for (i = 0; i < prtd->channels; i++)
276 prtd->qmc_dai->chans[i].prtd_rx = prtd;
277
278 /* Submit first chunk ... */231 /* Submit first chunk ... */
279 ret = qmc_audio_pcm_read_submit(prtd);232 ret = qmc_audio_pcm_read_submit(prtd);
280 if (ret)233 if (ret)
@@ -644,9 +597,9 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream, · 363 unmodified lines
644 chan_param.mode = QMC_TRANSPARENT;597 chan_param.mode = QMC_TRANSPARENT;
645 chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;598 chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;
646 for (i = 0; i < nb_chans_used; i++) {599 for (i = 0; i < nb_chans_used; i++) {
647 ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param);600 ret = qmc_chan_set_param(qmc_dai->qmc_chans[i], &chan_param);
648 if (ret) {601 if (ret) {
649 dev_err(dai->dev, "chans[%u], set param failed %d\n",602 dev_err(dai->dev, "qmc_chans[%u], set param failed %d\n",
650 i, ret);603 i, ret);
651 return ret;604 return ret;
652 }605 }
@@ -688,7 +641,7 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, · 35 unmodified lines
688 case SNDRV_PCM_TRIGGER_RESUME:641 case SNDRV_PCM_TRIGGER_RESUME:
689 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:642 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
690 for (i = 0; i < nb_chans_used; i++) {643 for (i = 0; i < nb_chans_used; i++) {
691 ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction);644 ret = qmc_chan_start(qmc_dai->qmc_chans[i], direction);
692 if (ret)645 if (ret)
693 goto err_stop;646 goto err_stop;
694 }647 }
@@ -697,13 +650,13 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, · 2 unmodified lines
697 case SNDRV_PCM_TRIGGER_STOP:650 case SNDRV_PCM_TRIGGER_STOP:
698 /* Stop and reset all QMC channels and return the first error encountered */651 /* Stop and reset all QMC channels and return the first error encountered */
699 for (i = 0; i < nb_chans_used; i++) {652 for (i = 0; i < nb_chans_used; i++) {
700 ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);653 ret_tmp = qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
701 if (!ret)654 if (!ret)
702 ret = ret_tmp;655 ret = ret_tmp;
703 if (ret_tmp)656 if (ret_tmp)
704 continue;657 continue;
705 658
706 ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);659 ret_tmp = qmc_chan_reset(qmc_dai->qmc_chans[i], direction);
707 if (!ret)660 if (!ret)
708 ret = ret_tmp;661 ret = ret_tmp;
709 }662 }
@@ -715,7 +668,7 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, · 5 unmodified lines
715 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:668 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
716 /* Stop all QMC channels and return the first error encountered */669 /* Stop all QMC channels and return the first error encountered */
717 for (i = 0; i < nb_chans_used; i++) {670 for (i = 0; i < nb_chans_used; i++) {
718 ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);671 ret_tmp = qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
719 if (!ret)672 if (!ret)
720 ret = ret_tmp;673 ret = ret_tmp;
721 }674 }
@@ -731,8 +684,8 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, · 9 unmodified lines
731 684
732err_stop:685err_stop:
733 while (i--) {686 while (i--) {
734 qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);687 qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
735 qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);688 qmc_chan_reset(qmc_dai->qmc_chans[i], direction);
736 }689 }
737 return ret;690 return ret;
738}691}
@@ -791,12 +744,17 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * · 52 unmodified lines
791 struct qmc_dai *qmc_dai,744 struct qmc_dai *qmc_dai,
792 struct snd_soc_dai_driver *qmc_soc_dai_driver)745 struct snd_soc_dai_driver *qmc_soc_dai_driver)
793{746{
747 struct qmc_chan_ts_info ts_info;
794 struct qmc_chan_info info;748 struct qmc_chan_info info;
795 unsigned long rx_fs_rate;749 unsigned long rx_fs_rate;
796 unsigned long tx_fs_rate;750 unsigned long tx_fs_rate;
751 int prev_last_rx_ts = 0;
752 int prev_last_tx_ts = 0;
797 unsigned int nb_tx_ts;753 unsigned int nb_tx_ts;
798 unsigned int nb_rx_ts;754 unsigned int nb_rx_ts;
799 unsigned int i;755 unsigned int i;
756 int last_rx_ts;
757 int last_tx_ts;
800 int count;758 int count;
801 u32 val;759 u32 val;
802 int ret;760 int ret;
@@ -823,19 +781,20 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * · 20 unmodified lines
823 return dev_err_probe(qmc_audio->dev, -EINVAL,781 return dev_err_probe(qmc_audio->dev, -EINVAL,
824 "dai %d no QMC channel defined\n", qmc_dai->id);782 "dai %d no QMC channel defined\n", qmc_dai->id);
825 783
826 qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL);784 qmc_dai->qmc_chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->qmc_chans),
827 if (!qmc_dai->chans)785 GFP_KERNEL);
786 if (!qmc_dai->qmc_chans)
828 return -ENOMEM;787 return -ENOMEM;
829 788
830 for (i = 0; i < count; i++) {789 for (i = 0; i < count; i++) {
831 qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,790 qmc_dai->qmc_chans[i] = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,
832 "fsl,qmc-chan", i);791 "fsl,qmc-chan", i);
833 if (IS_ERR(qmc_dai->chans[i].qmc_chan)) {792 if (IS_ERR(qmc_dai->qmc_chans[i])) {
834 return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan),793 return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->qmc_chans[i]),
835 "dai %d get QMC channel %d failed\n", qmc_dai->id, i);794 "dai %d get QMC channel %d failed\n", qmc_dai->id, i);
836 }795 }
837 796
838 ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info);797 ret = qmc_chan_get_info(qmc_dai->qmc_chans[i], &info);
839 if (ret) {798 if (ret) {
840 dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",799 dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",
841 qmc_dai->id, i, ret);800 qmc_dai->id, i, ret);
@@ -879,6 +838,30 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * · 37 unmodified lines
879 return -EINVAL;838 return -EINVAL;
880 }839 }
881 }840 }
841
842 ret = qmc_chan_get_ts_info(qmc_dai->qmc_chans[i], &ts_info);
843 if (ret) {
844 dev_err(qmc_audio->dev, "dai %d get QMC %d channel TS info failed %d\n",
845 qmc_dai->id, i, ret);
846 return ret;
847 }
848
849 last_rx_ts = fls64(ts_info.rx_ts_mask);
850 last_tx_ts = fls64(ts_info.tx_ts_mask);
851
852 if (prev_last_rx_ts > last_rx_ts) {
853 dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %d before %d)\n",
854 qmc_dai->id, i, prev_last_rx_ts, last_rx_ts);
855 return -EINVAL;
856 }
857 if (prev_last_tx_ts > last_tx_ts) {
858 dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (TX timeslot %d before %d)\n",
859 qmc_dai->id, i, prev_last_tx_ts, last_tx_ts);
860 return -EINVAL;
861 }
862
863 prev_last_rx_ts = last_rx_ts;
864 prev_last_tx_ts = last_tx_ts;
882 }865 }
883 866
884 qmc_dai->nb_chans_avail = count;867 qmc_dai->nb_chans_avail = count;