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
Unified · Split
| @@ -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 | 462 | ctrl = qmc_read16(&bd->cbd_sc); |
| 463 | 463 | if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) { |
| 464 | − /* We are full ... */ | |
| 465 | − ret = -EBUSY; | |
| 466 | − goto end; | |
| 464 | + if (!(ctrl & (QMC_BD_TX_R | QMC_BD_TX_I)) && bd == chan->txbd_done) { | |
| 465 | + if (ctrl & QMC_BD_TX_W) | |
| 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 | 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 | 483 | /* Activate the descriptor */ |
| 477 | 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 | 489 | wmb(); /* Be sure to flush the descriptor before control update */ |
| 479 | 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 | 581 | ctrl = qmc_read16(&bd->cbd_sc); |
| 571 | 582 | if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) { |
| 572 | − /* We are full ... */ | |
| 573 | − ret = -EBUSY; | |
| 574 | − goto end; | |
| 583 | + if (!(ctrl & (QMC_BD_RX_E | QMC_BD_RX_I)) && bd == chan->rxbd_done) { | |
| 584 | + if (ctrl & QMC_BD_RX_W) | |
| 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 | 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 | 606 | /* Activate the descriptor */ |
| 589 | 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 | 612 | wmb(); /* Be sure to flush data before descriptor activation */ |
| 591 | 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 | 1505 | /* Init Rx BDs and set Wrap bit on last descriptor */ |
| 1484 | 1506 | BUILD_BUG_ON(QMC_NB_RXBDS == 0); |
| 1485 | − val = QMC_BD_RX_I; | |
| 1486 | 1507 | for (i = 0; i < QMC_NB_RXBDS; i++) { |
| 1487 | 1508 | bd = chan->rxbds + i; |
| 1488 | − qmc_write16(&bd->cbd_sc, val); | |
| 1509 | + qmc_write16(&bd->cbd_sc, 0); | |
| 1489 | 1510 | } |
| 1490 | 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 | 1514 | /* Init Tx BDs and set Wrap bit on last descriptor */ |
| 1494 | 1515 | BUILD_BUG_ON(QMC_NB_TXBDS == 0); |
| 1495 | − val = QMC_BD_TX_I; | |
| 1496 | 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 | 1520 | for (i = 0; i < QMC_NB_TXBDS; i++) { |
| 1499 | 1521 | bd = chan->txbds + i; |
| 1500 | 1522 | qmc_write16(&bd->cbd_sc, val); |
| @@ -17,12 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <sound/pcm_params.h> |
| 18 | 18 | #include <sound/soc.h> |
| 19 | 19 | |
| 20 | −struct 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 | − | |
| 26 | 20 | struct qmc_dai { |
| 27 | 21 | char *name; |
| 28 | 22 | int id; |
| @@ -33,7 +27,7 @@ struct qmc_dai { · 4 unmodified lines | ||
| 33 | 27 | unsigned int nb_chans_avail; |
| 34 | 28 | unsigned int nb_chans_used_tx; |
| 35 | 29 | unsigned int nb_chans_used_rx; |
| 36 | − struct qmc_dai_chan *chans; | |
| 30 | + struct qmc_chan **qmc_chans; | |
| 37 | 31 | }; |
| 38 | 32 | |
| 39 | 33 | struct qmc_audio { |
| @@ -57,7 +51,6 @@ struct qmc_dai_prtd { · 17 unmodified lines | ||
| 57 | 51 | size_t ch_dma_offset; |
| 58 | 52 | |
| 59 | 53 | unsigned int channels; |
| 60 | − DECLARE_BITMAP(chans_pending, 64); | |
| 61 | 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 | 119 | int ret; |
| 127 | 120 | |
| 128 | 121 | 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, | |
| 122 | + ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chans[i], | |
| 132 | 123 | prtd->ch_dma_addr_current + i * prtd->ch_dma_offset, |
| 133 | 124 | prtd->ch_dma_size, |
| 134 | − qmc_audio_pcm_write_complete, | |
| 135 | − &prtd->qmc_dai->chans[i]); | |
| 125 | + i == prtd->channels - 1 ? qmc_audio_pcm_write_complete : | |
| 126 | + NULL, prtd); | |
| 136 | 127 | if (ret) { |
| 137 | 128 | dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n", |
| 138 | 129 | i, ret); |
| 139 | − bitmap_clear(prtd->chans_pending, i, 1); | |
| 140 | 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 | |
| 147 | 137 | static void qmc_audio_pcm_write_complete(void *context) |
| 148 | 138 | { |
| 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 before | |
| 159 | − * submitting a new one. | |
| 160 | − */ | |
| 161 | − if (!bitmap_empty(prtd->chans_pending, 64)) | |
| 162 | − return; | |
| 139 | + struct qmc_dai_prtd *prtd = context; | |
| 163 | 140 | |
| 164 | 141 | prtd->buffer_ended += prtd->period_size; |
| 165 | 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 | 159 | int ret; |
| 183 | 160 | |
| 184 | 161 | 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, | |
| 162 | + ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chans[i], | |
| 188 | 163 | prtd->ch_dma_addr_current + i * prtd->ch_dma_offset, |
| 189 | 164 | prtd->ch_dma_size, |
| 190 | − qmc_audio_pcm_read_complete, | |
| 191 | − &prtd->qmc_dai->chans[i]); | |
| 165 | + i == prtd->channels - 1 ? qmc_audio_pcm_read_complete : | |
| 166 | + NULL, prtd); | |
| 192 | 167 | if (ret) { |
| 193 | 168 | dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n", |
| 194 | 169 | i, ret); |
| 195 | − bitmap_clear(prtd->chans_pending, i, 1); | |
| 196 | 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 | |
| 203 | 177 | static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags) |
| 204 | 178 | { |
| 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); | |
| 179 | + struct qmc_dai_prtd *prtd = context; | |
| 212 | 180 | |
| 213 | 181 | if (length != prtd->ch_dma_size) { |
| 214 | 182 | dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n", |
| 215 | 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 | 186 | prtd->buffer_ended += prtd->period_size; |
| 226 | 187 | if (prtd->buffer_ended >= prtd->buffer_size) |
| 227 | 188 | prtd->buffer_ended = 0; |
| @@ -239,7 +200,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, · 11 unmodified lines | ||
| 239 | 200 | struct snd_pcm_substream *substream, int cmd) |
| 240 | 201 | { |
| 241 | 202 | struct qmc_dai_prtd *prtd = substream->runtime->private_data; |
| 242 | − unsigned int i; | |
| 243 | 203 | int ret; |
| 244 | 204 | |
| 245 | 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 | 210 | switch (cmd) { |
| 251 | 211 | case SNDRV_PCM_TRIGGER_START: |
| 252 | − bitmap_zero(prtd->chans_pending, 64); | |
| 253 | 212 | prtd->buffer_ended = 0; |
| 254 | 213 | prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; |
| 255 | 214 | |
| 256 | 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 | 216 | /* Submit first chunk ... */ |
| 261 | 217 | ret = qmc_audio_pcm_write_submit(prtd); |
| 262 | 218 | if (ret) |
| @@ -272,9 +228,6 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, · 9 unmodified lines | ||
| 272 | 228 | if (ret) |
| 273 | 229 | return ret; |
| 274 | 230 | } else { |
| 275 | − for (i = 0; i < prtd->channels; i++) | |
| 276 | − prtd->qmc_dai->chans[i].prtd_rx = prtd; | |
| 277 | − | |
| 278 | 231 | /* Submit first chunk ... */ |
| 279 | 232 | ret = qmc_audio_pcm_read_submit(prtd); |
| 280 | 233 | if (ret) |
| @@ -644,9 +597,9 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream, · 363 unmodified lines | ||
| 644 | 597 | chan_param.mode = QMC_TRANSPARENT; |
| 645 | 598 | chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used; |
| 646 | 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 | 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 | 603 | i, ret); |
| 651 | 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 | 641 | case SNDRV_PCM_TRIGGER_RESUME: |
| 689 | 642 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
| 690 | 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 | 645 | if (ret) |
| 693 | 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 | 650 | case SNDRV_PCM_TRIGGER_STOP: |
| 698 | 651 | /* Stop and reset all QMC channels and return the first error encountered */ |
| 699 | 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 | 654 | if (!ret) |
| 702 | 655 | ret = ret_tmp; |
| 703 | 656 | if (ret_tmp) |
| 704 | 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 | 660 | if (!ret) |
| 708 | 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 | 668 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
| 716 | 669 | /* Stop all QMC channels and return the first error encountered */ |
| 717 | 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 | 672 | if (!ret) |
| 720 | 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 | |
| 732 | 685 | err_stop: |
| 733 | 686 | while (i--) { |
| 734 | − qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction); | |
| 735 | − qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction); | |
| 687 | + qmc_chan_stop(qmc_dai->qmc_chans[i], direction); | |
| 688 | + qmc_chan_reset(qmc_dai->qmc_chans[i], direction); | |
| 736 | 689 | } |
| 737 | 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 | 744 | struct qmc_dai *qmc_dai, |
| 792 | 745 | struct snd_soc_dai_driver *qmc_soc_dai_driver) |
| 793 | 746 | { |
| 747 | + struct qmc_chan_ts_info ts_info; | |
| 794 | 748 | struct qmc_chan_info info; |
| 795 | 749 | unsigned long rx_fs_rate; |
| 796 | 750 | unsigned long tx_fs_rate; |
| 751 | + int prev_last_rx_ts = 0; | |
| 752 | + int prev_last_tx_ts = 0; | |
| 797 | 753 | unsigned int nb_tx_ts; |
| 798 | 754 | unsigned int nb_rx_ts; |
| 799 | 755 | unsigned int i; |
| 756 | + int last_rx_ts; | |
| 757 | + int last_tx_ts; | |
| 800 | 758 | int count; |
| 801 | 759 | u32 val; |
| 802 | 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 | 781 | return dev_err_probe(qmc_audio->dev, -EINVAL, |
| 824 | 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); | |
| 827 | − if (!qmc_dai->chans) | |
| 784 | + qmc_dai->qmc_chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->qmc_chans), | |
| 785 | + GFP_KERNEL); | |
| 786 | + if (!qmc_dai->qmc_chans) | |
| 828 | 787 | return -ENOMEM; |
| 829 | 788 | |
| 830 | 789 | for (i = 0; i < count; i++) { |
| 831 | − qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np, | |
| 832 | − "fsl,qmc-chan", i); | |
| 833 | − if (IS_ERR(qmc_dai->chans[i].qmc_chan)) { | |
| 834 | − return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan), | |
| 790 | + qmc_dai->qmc_chans[i] = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np, | |
| 791 | + "fsl,qmc-chan", i); | |
| 792 | + if (IS_ERR(qmc_dai->qmc_chans[i])) { | |
| 793 | + return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->qmc_chans[i]), | |
| 835 | 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 | 798 | if (ret) { |
| 840 | 799 | dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n", |
| 841 | 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 | 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 | 867 | qmc_dai->nb_chans_avail = count; |