Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add support for non-interleaved mode in qmc_audio

Merge series from Herve Codina <herve.codina@bootlin.com>:

The qmc_audio driver supports only audio in interleaved mode.
Non-interleaved mode can be easily supported using several QMC channel
per DAI. In that case, data related to ch0 are sent to (received from)
the first QMC channel, data related to ch1 use the next QMC channel and
so on up to the last channel.

In terms of constraints and settings, the interleaved and
non-interleaved modes are slightly different.

In interleaved mode:
- The sample size should fit in the number of time-slots available for
the QMC channel.
- The number of audio channels should fit in the number of time-slots
(taking into account the sample size) available for the QMC channel.

In non-interleaved mode:
- The number of audio channels is the number of available QMC
channels.
- Each QMC channel should have the same number of time-slots.
- The sample size equals the number of time-slots of one QMC channel.

This series add support for the non-interleaved mode in the qmc_audio
driver and is composed of the following parts:
- Patches 1 and 2: Fix some issues in the qmc_audio
- Patches 3 to 6: Prepare qmc_audio for the non-interleaved mode
- Patches 7 and 8: Extend the QMC driver API
- Patches 9 and 10: The support for non-interleaved mode itself

Compared to the previous iteration, this v2 series mainly improves
qmc_audio_access_is_interleaved().

+506 -185
+35 -6
Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
··· 12 12 description: | 13 13 The QMC audio is an ASoC component which uses QMC (QUICC Multichannel 14 14 Controller) channels to transfer the audio data. 15 - It provides as many DAI as the number of QMC channel used. 15 + It provides several DAIs. For each DAI, the DAI is working in interleaved mode 16 + if only one QMC channel is used by the DAI or it is working in non-interleaved 17 + mode if several QMC channels are used by the DAI. 16 18 17 19 allOf: 18 20 - $ref: dai-common.yaml# ··· 47 45 fsl,qmc-chan: 48 46 $ref: /schemas/types.yaml#/definitions/phandle-array 49 47 items: 50 - - items: 51 - - description: phandle to QMC node 52 - - description: Channel number 48 + items: 49 + - description: phandle to QMC node 50 + - description: Channel number 51 + minItems: 1 53 52 description: 54 - Should be a phandle/number pair. The phandle to QMC node and the QMC 55 - channel to use for this DAI. 53 + Should be a phandle/number pair list. The list of phandle to QMC node 54 + and the QMC channel pair to use for this DAI. 55 + If only one phandle/number pair is provided, this DAI works in 56 + interleaved mode, i.e. audio channels for this DAI are interleaved in 57 + the QMC channel. If more than one pair is provided, this DAI works 58 + in non-interleave mode. In that case the first audio channel uses the 59 + the first QMC channel, the second audio channel uses the second QMC 60 + channel, etc... 56 61 57 62 required: 58 63 - reg ··· 87 78 dai@17 { 88 79 reg = <17>; 89 80 fsl,qmc-chan = <&qmc 17>; 81 + }; 82 + dai@18 { 83 + reg = <18>; 84 + /* Non-interleaved mode */ 85 + fsl,qmc-chan = <&qmc 18>, <&qmc 19>; 90 86 }; 91 87 }; 92 88 ··· 127 113 /* TS 2, 4, 6, 8 */ 128 114 dai-tdm-slot-tx-mask = <0 0 1 0 1 0 1 0 1>; 129 115 dai-tdm-slot-rx-mask = <0 0 1 0 1 0 1 0 1>; 116 + }; 117 + }; 118 + simple-audio-card,dai-link@2 { 119 + reg = <2>; 120 + format = "dsp_b"; 121 + cpu { 122 + sound-dai = <&audio_controller 18>; 123 + }; 124 + codec { 125 + sound-dai = <&codec3>; 126 + dai-tdm-slot-num = <2>; 127 + dai-tdm-slot-width = <8>; 128 + /* TS 9, 10 */ 129 + dai-tdm-slot-tx-mask = <0 0 0 0 0 0 0 0 0 1 1>; 130 + dai-tdm-slot-rx-mask = <0 0 0 0 0 0 0 0 0 1 1>; 130 131 }; 131 132 }; 132 133 };
+24 -8
drivers/soc/fsl/qe/qmc.c
··· 1777 1777 return qmc_chan; 1778 1778 } 1779 1779 1780 - struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name) 1780 + int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name) 1781 + { 1782 + int count; 1783 + 1784 + /* phandles are fixed args phandles with one arg */ 1785 + count = of_count_phandle_with_args(np, phandles_name, NULL); 1786 + if (count < 0) 1787 + return count; 1788 + 1789 + return count / 2; 1790 + } 1791 + EXPORT_SYMBOL(qmc_chan_count_phandles); 1792 + 1793 + struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, 1794 + const char *phandles_name, 1795 + int index) 1781 1796 { 1782 1797 struct of_phandle_args out_args; 1783 1798 struct qmc_chan *qmc_chan; 1784 1799 int ret; 1785 1800 1786 - ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, 1801 + ret = of_parse_phandle_with_fixed_args(np, phandles_name, 1, index, 1787 1802 &out_args); 1788 1803 if (ret < 0) 1789 1804 return ERR_PTR(ret); ··· 1812 1797 of_node_put(out_args.np); 1813 1798 return qmc_chan; 1814 1799 } 1815 - EXPORT_SYMBOL(qmc_chan_get_byphandle); 1800 + EXPORT_SYMBOL(qmc_chan_get_byphandles_index); 1816 1801 1817 1802 struct qmc_chan *qmc_chan_get_bychild(struct device_node *np) 1818 1803 { ··· 1842 1827 qmc_chan_put(*qmc_chan); 1843 1828 } 1844 1829 1845 - struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, 1846 - struct device_node *np, 1847 - const char *phandle_name) 1830 + struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev, 1831 + struct device_node *np, 1832 + const char *phandles_name, 1833 + int index) 1848 1834 { 1849 1835 struct qmc_chan *qmc_chan; 1850 1836 struct qmc_chan **dr; ··· 1854 1838 if (!dr) 1855 1839 return ERR_PTR(-ENOMEM); 1856 1840 1857 - qmc_chan = qmc_chan_get_byphandle(np, phandle_name); 1841 + qmc_chan = qmc_chan_get_byphandles_index(np, phandles_name, index); 1858 1842 if (!IS_ERR(qmc_chan)) { 1859 1843 *dr = qmc_chan; 1860 1844 devres_add(dev, dr); ··· 1864 1848 1865 1849 return qmc_chan; 1866 1850 } 1867 - EXPORT_SYMBOL(devm_qmc_chan_get_byphandle); 1851 + EXPORT_SYMBOL(devm_qmc_chan_get_byphandles_index); 1868 1852 1869 1853 struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, 1870 1854 struct device_node *np)
+24 -3
include/soc/fsl/qe/qmc.h
··· 16 16 struct device; 17 17 struct qmc_chan; 18 18 19 - struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name); 19 + int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name); 20 + 21 + struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np, 22 + const char *phandles_name, 23 + int index); 24 + struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev, 25 + struct device_node *np, 26 + const char *phandles_name, 27 + int index); 28 + 29 + static inline struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, 30 + const char *phandle_name) 31 + { 32 + return qmc_chan_get_byphandles_index(np, phandle_name, 0); 33 + } 34 + 35 + static inline struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, 36 + struct device_node *np, 37 + const char *phandle_name) 38 + { 39 + return devm_qmc_chan_get_byphandles_index(dev, np, phandle_name, 0); 40 + } 41 + 20 42 struct qmc_chan *qmc_chan_get_bychild(struct device_node *np); 21 43 void qmc_chan_put(struct qmc_chan *chan); 22 - struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, struct device_node *np, 23 - const char *phandle_name); 44 + 24 45 struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, struct device_node *np); 25 46 26 47 enum qmc_mode {
+423 -168
sound/soc/fsl/fsl_qmc_audio.c
··· 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 + 20 26 struct qmc_dai { 21 27 char *name; 22 28 int id; 23 29 struct device *dev; 24 - struct qmc_chan *qmc_chan; 25 30 unsigned int nb_tx_ts; 26 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; 27 37 }; 28 38 29 39 struct qmc_audio { ··· 45 35 46 36 struct qmc_dai_prtd { 47 37 struct qmc_dai *qmc_dai; 48 - dma_addr_t dma_buffer_start; 49 - dma_addr_t period_ptr_submitted; 50 - dma_addr_t period_ptr_ended; 51 - dma_addr_t dma_buffer_end; 52 - size_t period_size; 38 + 39 + snd_pcm_uframes_t buffer_ended; 40 + snd_pcm_uframes_t buffer_size; 41 + snd_pcm_uframes_t period_size; 42 + 43 + dma_addr_t ch_dma_addr_start; 44 + dma_addr_t ch_dma_addr_current; 45 + dma_addr_t ch_dma_addr_end; 46 + size_t ch_dma_size; 47 + size_t ch_dma_offset; 48 + 49 + unsigned int channels; 50 + DECLARE_BITMAP(chans_pending, 64); 53 51 struct snd_pcm_substream *substream; 54 52 }; 55 53 ··· 72 54 return ret; 73 55 74 56 snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev, 75 - 64*1024, 64*1024); 57 + 64 * 1024, 64 * 1024); 76 58 return 0; 59 + } 60 + 61 + static bool qmc_audio_access_is_interleaved(snd_pcm_access_t access) 62 + { 63 + switch (access) { 64 + case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED: 65 + case SNDRV_PCM_ACCESS_RW_INTERLEAVED: 66 + return true; 67 + default: 68 + break; 69 + } 70 + return false; 77 71 } 78 72 79 73 static int qmc_audio_pcm_hw_params(struct snd_soc_component *component, ··· 95 65 struct snd_pcm_runtime *runtime = substream->runtime; 96 66 struct qmc_dai_prtd *prtd = substream->runtime->private_data; 97 67 98 - prtd->dma_buffer_start = runtime->dma_addr; 99 - prtd->dma_buffer_end = runtime->dma_addr + params_buffer_bytes(params); 100 - prtd->period_size = params_period_bytes(params); 101 - prtd->period_ptr_submitted = prtd->dma_buffer_start; 102 - prtd->period_ptr_ended = prtd->dma_buffer_start; 68 + /* 69 + * In interleaved mode, the driver uses one QMC channel for all audio 70 + * channels whereas in non-interleaved mode, it uses one QMC channel per 71 + * audio channel. 72 + */ 73 + prtd->channels = qmc_audio_access_is_interleaved(params_access(params)) ? 74 + 1 : params_channels(params); 75 + 103 76 prtd->substream = substream; 77 + 78 + prtd->buffer_ended = 0; 79 + prtd->buffer_size = params_buffer_size(params); 80 + prtd->period_size = params_period_size(params); 81 + 82 + prtd->ch_dma_addr_start = runtime->dma_addr; 83 + prtd->ch_dma_offset = params_buffer_bytes(params) / prtd->channels; 84 + prtd->ch_dma_addr_end = runtime->dma_addr + prtd->ch_dma_offset; 85 + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; 86 + prtd->ch_dma_size = params_period_bytes(params) / prtd->channels; 87 + 88 + return 0; 89 + } 90 + 91 + static void qmc_audio_pcm_write_complete(void *context); 92 + 93 + static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd) 94 + { 95 + unsigned int i; 96 + int ret; 97 + 98 + for (i = 0; i < prtd->channels; i++) { 99 + bitmap_set(prtd->chans_pending, i, 1); 100 + 101 + ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan, 102 + prtd->ch_dma_addr_current + i * prtd->ch_dma_offset, 103 + prtd->ch_dma_size, 104 + qmc_audio_pcm_write_complete, 105 + &prtd->qmc_dai->chans[i]); 106 + if (ret) { 107 + dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n", 108 + i, ret); 109 + bitmap_clear(prtd->chans_pending, i, 1); 110 + return ret; 111 + } 112 + } 104 113 105 114 return 0; 106 115 } 107 116 108 117 static void qmc_audio_pcm_write_complete(void *context) 109 118 { 110 - struct qmc_dai_prtd *prtd = context; 111 - int ret; 119 + struct qmc_dai_chan *chan = context; 120 + struct qmc_dai_prtd *prtd; 112 121 113 - prtd->period_ptr_ended += prtd->period_size; 114 - if (prtd->period_ptr_ended >= prtd->dma_buffer_end) 115 - prtd->period_ptr_ended = prtd->dma_buffer_start; 122 + prtd = chan->prtd_tx; 116 123 117 - prtd->period_ptr_submitted += prtd->period_size; 118 - if (prtd->period_ptr_submitted >= prtd->dma_buffer_end) 119 - prtd->period_ptr_submitted = prtd->dma_buffer_start; 124 + /* Mark the current channel as completed */ 125 + bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1); 120 126 121 - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, 122 - prtd->period_ptr_submitted, prtd->period_size, 123 - qmc_audio_pcm_write_complete, prtd); 124 - if (ret) { 125 - dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n", 126 - ret); 127 - } 127 + /* 128 + * All QMC channels involved must have completed their transfer before 129 + * submitting a new one. 130 + */ 131 + if (!bitmap_empty(prtd->chans_pending, 64)) 132 + return; 133 + 134 + prtd->buffer_ended += prtd->period_size; 135 + if (prtd->buffer_ended >= prtd->buffer_size) 136 + prtd->buffer_ended = 0; 137 + 138 + prtd->ch_dma_addr_current += prtd->ch_dma_size; 139 + if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) 140 + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; 141 + 142 + qmc_audio_pcm_write_submit(prtd); 128 143 129 144 snd_pcm_period_elapsed(prtd->substream); 130 145 } 131 146 132 - static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags) 147 + static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags); 148 + 149 + static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd) 133 150 { 134 - struct qmc_dai_prtd *prtd = context; 151 + unsigned int i; 135 152 int ret; 136 153 137 - if (length != prtd->period_size) { 154 + for (i = 0; i < prtd->channels; i++) { 155 + bitmap_set(prtd->chans_pending, i, 1); 156 + 157 + ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan, 158 + prtd->ch_dma_addr_current + i * prtd->ch_dma_offset, 159 + prtd->ch_dma_size, 160 + qmc_audio_pcm_read_complete, 161 + &prtd->qmc_dai->chans[i]); 162 + if (ret) { 163 + dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n", 164 + i, ret); 165 + bitmap_clear(prtd->chans_pending, i, 1); 166 + return ret; 167 + } 168 + } 169 + 170 + return 0; 171 + } 172 + 173 + static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags) 174 + { 175 + struct qmc_dai_chan *chan = context; 176 + struct qmc_dai_prtd *prtd; 177 + 178 + prtd = chan->prtd_rx; 179 + 180 + /* Mark the current channel as completed */ 181 + bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1); 182 + 183 + if (length != prtd->ch_dma_size) { 138 184 dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n", 139 - length, prtd->period_size); 185 + length, prtd->ch_dma_size); 140 186 } 141 187 142 - prtd->period_ptr_ended += prtd->period_size; 143 - if (prtd->period_ptr_ended >= prtd->dma_buffer_end) 144 - prtd->period_ptr_ended = prtd->dma_buffer_start; 188 + /* 189 + * All QMC channels involved must have completed their transfer before 190 + * submitting a new one. 191 + */ 192 + if (!bitmap_empty(prtd->chans_pending, 64)) 193 + return; 145 194 146 - prtd->period_ptr_submitted += prtd->period_size; 147 - if (prtd->period_ptr_submitted >= prtd->dma_buffer_end) 148 - prtd->period_ptr_submitted = prtd->dma_buffer_start; 195 + prtd->buffer_ended += prtd->period_size; 196 + if (prtd->buffer_ended >= prtd->buffer_size) 197 + prtd->buffer_ended = 0; 149 198 150 - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, 151 - prtd->period_ptr_submitted, prtd->period_size, 152 - qmc_audio_pcm_read_complete, prtd); 153 - if (ret) { 154 - dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n", 155 - ret); 156 - } 199 + prtd->ch_dma_addr_current += prtd->ch_dma_size; 200 + if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) 201 + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; 202 + 203 + qmc_audio_pcm_read_submit(prtd); 157 204 158 205 snd_pcm_period_elapsed(prtd->substream); 159 206 } ··· 239 132 struct snd_pcm_substream *substream, int cmd) 240 133 { 241 134 struct qmc_dai_prtd *prtd = substream->runtime->private_data; 135 + unsigned int i; 242 136 int ret; 243 137 244 138 if (!prtd->qmc_dai) { ··· 249 141 250 142 switch (cmd) { 251 143 case SNDRV_PCM_TRIGGER_START: 144 + bitmap_zero(prtd->chans_pending, 64); 252 145 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 146 + for (i = 0; i < prtd->channels; i++) 147 + prtd->qmc_dai->chans[i].prtd_tx = prtd; 148 + 253 149 /* Submit first chunk ... */ 254 - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, 255 - prtd->period_ptr_submitted, prtd->period_size, 256 - qmc_audio_pcm_write_complete, prtd); 257 - if (ret) { 258 - dev_err(component->dev, "write_submit failed %d\n", 259 - ret); 150 + ret = qmc_audio_pcm_write_submit(prtd); 151 + if (ret) 260 152 return ret; 261 - } 262 153 263 154 /* ... prepare next one ... */ 264 - prtd->period_ptr_submitted += prtd->period_size; 265 - if (prtd->period_ptr_submitted >= prtd->dma_buffer_end) 266 - prtd->period_ptr_submitted = prtd->dma_buffer_start; 155 + prtd->ch_dma_addr_current += prtd->ch_dma_size; 156 + if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) 157 + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; 267 158 268 159 /* ... and send it */ 269 - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, 270 - prtd->period_ptr_submitted, prtd->period_size, 271 - qmc_audio_pcm_write_complete, prtd); 272 - if (ret) { 273 - dev_err(component->dev, "write_submit failed %d\n", 274 - ret); 160 + ret = qmc_audio_pcm_write_submit(prtd); 161 + if (ret) 275 162 return ret; 276 - } 277 163 } else { 164 + for (i = 0; i < prtd->channels; i++) 165 + prtd->qmc_dai->chans[i].prtd_rx = prtd; 166 + 278 167 /* Submit first chunk ... */ 279 - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, 280 - prtd->period_ptr_submitted, prtd->period_size, 281 - qmc_audio_pcm_read_complete, prtd); 282 - if (ret) { 283 - dev_err(component->dev, "read_submit failed %d\n", 284 - ret); 168 + ret = qmc_audio_pcm_read_submit(prtd); 169 + if (ret) 285 170 return ret; 286 - } 287 171 288 172 /* ... prepare next one ... */ 289 - prtd->period_ptr_submitted += prtd->period_size; 290 - if (prtd->period_ptr_submitted >= prtd->dma_buffer_end) 291 - prtd->period_ptr_submitted = prtd->dma_buffer_start; 173 + prtd->ch_dma_addr_current += prtd->ch_dma_size; 174 + if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) 175 + prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; 292 176 293 177 /* ... and send it */ 294 - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, 295 - prtd->period_ptr_submitted, prtd->period_size, 296 - qmc_audio_pcm_read_complete, prtd); 297 - if (ret) { 298 - dev_err(component->dev, "write_submit failed %d\n", 299 - ret); 178 + ret = qmc_audio_pcm_read_submit(prtd); 179 + if (ret) 300 180 return ret; 301 - } 302 181 } 303 182 break; 304 183 ··· 310 215 { 311 216 struct qmc_dai_prtd *prtd = substream->runtime->private_data; 312 217 313 - return bytes_to_frames(substream->runtime, 314 - prtd->period_ptr_ended - prtd->dma_buffer_start); 218 + return prtd->buffer_ended; 315 219 } 316 220 317 221 static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component, 318 - const struct of_phandle_args *args, 319 - const char **dai_name) 222 + const struct of_phandle_args *args, 223 + const char **dai_name) 320 224 { 321 225 struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev); 322 226 struct snd_soc_dai_driver *dai_driver; ··· 337 243 .info = SNDRV_PCM_INFO_MMAP | 338 244 SNDRV_PCM_INFO_MMAP_VALID | 339 245 SNDRV_PCM_INFO_INTERLEAVED | 246 + SNDRV_PCM_INFO_NONINTERLEAVED | 340 247 SNDRV_PCM_INFO_PAUSE, 341 248 .period_bytes_min = 32, 342 - .period_bytes_max = 64*1024, 249 + .period_bytes_max = 64 * 1024, 343 250 .periods_min = 2, 344 - .periods_max = 2*1024, 345 - .buffer_bytes_max = 64*1024, 251 + .periods_max = 2 * 1024, 252 + .buffer_bytes_max = 64 * 1024, 346 253 }; 347 254 348 255 static int qmc_audio_pcm_open(struct snd_soc_component *component, ··· 361 266 return ret; 362 267 363 268 prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); 364 - if (prtd == NULL) 269 + if (!prtd) 365 270 return -ENOMEM; 366 271 367 272 runtime->private_data = prtd; ··· 424 329 ch.max = nb_ts; 425 330 break; 426 331 case 16: 427 - ch.max = nb_ts/2; 332 + ch.max = nb_ts / 2; 428 333 break; 429 334 case 32: 430 - ch.max = nb_ts/4; 335 + ch.max = nb_ts / 4; 431 336 break; 432 337 case 64: 433 - ch.max = nb_ts/8; 338 + ch.max = nb_ts / 8; 434 339 break; 435 340 default: 436 341 dev_err(qmc_dai->dev, "format physical width %u not supported\n", ··· 451 356 return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts); 452 357 } 453 358 454 - static int qmc_dai_hw_rule_capture_channels_by_format( 455 - struct snd_pcm_hw_params *params, 456 - struct snd_pcm_hw_rule *rule) 359 + static int qmc_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params, 360 + struct snd_pcm_hw_rule *rule) 457 361 { 458 362 struct qmc_dai *qmc_dai = rule->private; 459 363 ··· 488 394 return snd_mask_refine(f_old, &f_new); 489 395 } 490 396 491 - static int qmc_dai_hw_rule_playback_format_by_channels( 492 - struct snd_pcm_hw_params *params, 493 - struct snd_pcm_hw_rule *rule) 397 + static int qmc_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params, 398 + struct snd_pcm_hw_rule *rule) 494 399 { 495 400 struct qmc_dai *qmc_dai = rule->private; 496 401 497 402 return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts); 498 403 } 499 404 500 - static int qmc_dai_hw_rule_capture_format_by_channels( 501 - struct snd_pcm_hw_params *params, 502 - struct snd_pcm_hw_rule *rule) 405 + static int qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params, 406 + struct snd_pcm_hw_rule *rule) 503 407 { 504 408 struct qmc_dai *qmc_dai = rule->private; 505 409 506 410 return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts); 507 411 } 508 412 509 - static int qmc_dai_startup(struct snd_pcm_substream *substream, 510 - struct snd_soc_dai *dai) 413 + static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream, 414 + struct qmc_dai *qmc_dai) 511 415 { 512 - struct qmc_dai_prtd *prtd = substream->runtime->private_data; 513 416 snd_pcm_hw_rule_func_t hw_rule_channels_by_format; 514 417 snd_pcm_hw_rule_func_t hw_rule_format_by_channels; 515 - struct qmc_dai *qmc_dai; 516 418 unsigned int frame_bits; 419 + u64 access; 517 420 int ret; 518 - 519 - qmc_dai = qmc_dai_get_data(dai); 520 - if (!qmc_dai) { 521 - dev_err(dai->dev, "Invalid dai\n"); 522 - return -EINVAL; 523 - } 524 - 525 - prtd->qmc_dai = qmc_dai; 526 421 527 422 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 528 423 hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format; ··· 527 444 hw_rule_channels_by_format, qmc_dai, 528 445 SNDRV_PCM_HW_PARAM_FORMAT, -1); 529 446 if (ret) { 530 - dev_err(dai->dev, "Failed to add channels rule (%d)\n", ret); 447 + dev_err(qmc_dai->dev, "Failed to add channels rule (%d)\n", ret); 531 448 return ret; 532 449 } 533 450 ··· 535 452 hw_rule_format_by_channels, qmc_dai, 536 453 SNDRV_PCM_HW_PARAM_CHANNELS, -1); 537 454 if (ret) { 538 - dev_err(dai->dev, "Failed to add format rule (%d)\n", ret); 455 + dev_err(qmc_dai->dev, "Failed to add format rule (%d)\n", ret); 539 456 return ret; 540 457 } 541 458 ··· 543 460 SNDRV_PCM_HW_PARAM_FRAME_BITS, 544 461 frame_bits); 545 462 if (ret < 0) { 546 - dev_err(dai->dev, "Failed to add frame_bits constraint (%d)\n", ret); 463 + dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret); 464 + return ret; 465 + } 466 + 467 + access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED | 468 + 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED; 469 + ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS, 470 + access); 471 + if (ret) { 472 + dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret); 547 473 return ret; 548 474 } 549 475 550 476 return 0; 477 + } 478 + 479 + static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substream, 480 + struct qmc_dai *qmc_dai) 481 + { 482 + unsigned int frame_bits; 483 + u64 access; 484 + int ret; 485 + 486 + frame_bits = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ? 487 + qmc_dai->nb_rx_ts * 8 : qmc_dai->nb_tx_ts * 8; 488 + ret = snd_pcm_hw_constraint_single(substream->runtime, 489 + SNDRV_PCM_HW_PARAM_FRAME_BITS, 490 + frame_bits); 491 + if (ret < 0) { 492 + dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret); 493 + return ret; 494 + } 495 + 496 + access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED | 497 + 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; 498 + ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS, 499 + access); 500 + if (ret) { 501 + dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret); 502 + return ret; 503 + } 504 + 505 + return 0; 506 + } 507 + 508 + static int qmc_dai_startup(struct snd_pcm_substream *substream, 509 + struct snd_soc_dai *dai) 510 + { 511 + struct qmc_dai_prtd *prtd = substream->runtime->private_data; 512 + struct qmc_dai *qmc_dai; 513 + 514 + qmc_dai = qmc_dai_get_data(dai); 515 + if (!qmc_dai) { 516 + dev_err(dai->dev, "Invalid dai\n"); 517 + return -EINVAL; 518 + } 519 + 520 + prtd->qmc_dai = qmc_dai; 521 + 522 + return qmc_dai->nb_chans_avail > 1 ? 523 + qmc_dai_constraints_noninterleaved(substream, qmc_dai) : 524 + qmc_dai_constraints_interleaved(substream, qmc_dai); 551 525 } 552 526 553 527 static int qmc_dai_hw_params(struct snd_pcm_substream *substream, ··· 612 472 struct snd_soc_dai *dai) 613 473 { 614 474 struct qmc_chan_param chan_param = {0}; 475 + unsigned int nb_chans_used; 615 476 struct qmc_dai *qmc_dai; 477 + unsigned int i; 616 478 int ret; 617 479 618 480 qmc_dai = qmc_dai_get_data(dai); ··· 623 481 return -EINVAL; 624 482 } 625 483 484 + /* 485 + * In interleaved mode, the driver uses one QMC channel for all audio 486 + * channels whereas in non-interleaved mode, it uses one QMC channel per 487 + * audio channel. 488 + */ 489 + nb_chans_used = qmc_audio_access_is_interleaved(params_access(params)) ? 490 + 1 : params_channels(params); 491 + 492 + if (nb_chans_used > qmc_dai->nb_chans_avail) { 493 + dev_err(dai->dev, "Not enough qmc_chans. Need %u, avail %u\n", 494 + nb_chans_used, qmc_dai->nb_chans_avail); 495 + return -EINVAL; 496 + } 497 + 626 498 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 627 499 chan_param.mode = QMC_TRANSPARENT; 628 - chan_param.transp.max_rx_buf_size = params_period_bytes(params); 629 - ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param); 630 - if (ret) { 631 - dev_err(dai->dev, "set param failed %d\n", 632 - ret); 633 - return ret; 500 + chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used; 501 + for (i = 0; i < nb_chans_used; i++) { 502 + ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param); 503 + if (ret) { 504 + dev_err(dai->dev, "chans[%u], set param failed %d\n", 505 + i, ret); 506 + return ret; 507 + } 634 508 } 509 + qmc_dai->nb_chans_used_rx = nb_chans_used; 510 + } else { 511 + qmc_dai->nb_chans_used_tx = nb_chans_used; 635 512 } 636 513 637 514 return 0; ··· 659 498 static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, 660 499 struct snd_soc_dai *dai) 661 500 { 501 + unsigned int nb_chans_used; 662 502 struct qmc_dai *qmc_dai; 503 + unsigned int i; 663 504 int direction; 664 - int ret; 505 + int ret = 0; 506 + int ret_tmp; 665 507 666 508 qmc_dai = qmc_dai_get_data(dai); 667 509 if (!qmc_dai) { ··· 672 508 return -EINVAL; 673 509 } 674 510 675 - direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 676 - QMC_CHAN_WRITE : QMC_CHAN_READ; 511 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 512 + direction = QMC_CHAN_WRITE; 513 + nb_chans_used = qmc_dai->nb_chans_used_tx; 514 + } else { 515 + direction = QMC_CHAN_READ; 516 + nb_chans_used = qmc_dai->nb_chans_used_rx; 517 + } 677 518 678 519 switch (cmd) { 679 520 case SNDRV_PCM_TRIGGER_START: 680 521 case SNDRV_PCM_TRIGGER_RESUME: 681 522 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 682 - ret = qmc_chan_start(qmc_dai->qmc_chan, direction); 683 - if (ret) 684 - return ret; 523 + for (i = 0; i < nb_chans_used; i++) { 524 + ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction); 525 + if (ret) 526 + goto err_stop; 527 + } 685 528 break; 686 529 687 530 case SNDRV_PCM_TRIGGER_STOP: 688 - ret = qmc_chan_stop(qmc_dai->qmc_chan, direction); 689 - if (ret) 690 - return ret; 691 - ret = qmc_chan_reset(qmc_dai->qmc_chan, direction); 531 + /* Stop and reset all QMC channels and return the first error encountered */ 532 + for (i = 0; i < nb_chans_used; i++) { 533 + ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction); 534 + if (!ret) 535 + ret = ret_tmp; 536 + if (ret_tmp) 537 + continue; 538 + 539 + ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction); 540 + if (!ret) 541 + ret = ret_tmp; 542 + } 692 543 if (ret) 693 544 return ret; 694 545 break; 695 546 696 547 case SNDRV_PCM_TRIGGER_SUSPEND: 697 548 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 698 - ret = qmc_chan_stop(qmc_dai->qmc_chan, direction); 549 + /* Stop all QMC channels and return the first error encountered */ 550 + for (i = 0; i < nb_chans_used; i++) { 551 + ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction); 552 + if (!ret) 553 + ret = ret_tmp; 554 + } 699 555 if (ret) 700 556 return ret; 701 557 break; ··· 725 541 } 726 542 727 543 return 0; 544 + 545 + err_stop: 546 + while (i--) { 547 + qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction); 548 + qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction); 549 + } 550 + return ret; 728 551 } 729 552 730 553 static const struct snd_soc_dai_ops qmc_dai_ops = { ··· 740 549 .hw_params = qmc_dai_hw_params, 741 550 }; 742 551 743 - static u64 qmc_audio_formats(u8 nb_ts) 552 + static u64 qmc_audio_formats(u8 nb_ts, bool is_noninterleaved) 744 553 { 745 554 unsigned int format_width; 746 555 unsigned int chan_width; ··· 772 581 if (format_width > chan_width || chan_width % format_width) 773 582 continue; 774 583 584 + /* 585 + * In non interleaved mode, we can only support formats that 586 + * can fit only 1 time in the channel 587 + */ 588 + if (is_noninterleaved && format_width != chan_width) 589 + continue; 590 + 775 591 formats_mask |= pcm_format_to_bits(format); 776 592 } 777 593 return formats_mask; 778 594 } 779 595 780 596 static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np, 781 - struct qmc_dai *qmc_dai, struct snd_soc_dai_driver *qmc_soc_dai_driver) 597 + struct qmc_dai *qmc_dai, 598 + struct snd_soc_dai_driver *qmc_soc_dai_driver) 782 599 { 783 600 struct qmc_chan_info info; 601 + unsigned long rx_fs_rate; 602 + unsigned long tx_fs_rate; 603 + unsigned int nb_tx_ts; 604 + unsigned int nb_rx_ts; 605 + unsigned int i; 606 + int count; 784 607 u32 val; 785 608 int ret; 786 609 ··· 809 604 810 605 qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d", 811 606 np->parent->name, qmc_dai->id); 607 + if (!qmc_dai->name) 608 + return -ENOMEM; 812 609 813 - qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np, 814 - "fsl,qmc-chan"); 815 - if (IS_ERR(qmc_dai->qmc_chan)) { 816 - ret = PTR_ERR(qmc_dai->qmc_chan); 817 - return dev_err_probe(qmc_audio->dev, ret, 818 - "dai %d get QMC channel failed\n", qmc_dai->id); 610 + count = qmc_chan_count_phandles(np, "fsl,qmc-chan"); 611 + if (count < 0) 612 + return dev_err_probe(qmc_audio->dev, count, 613 + "dai %d get number of QMC channel failed\n", qmc_dai->id); 614 + if (!count) 615 + return dev_err_probe(qmc_audio->dev, -EINVAL, 616 + "dai %d no QMC channel defined\n", qmc_dai->id); 617 + 618 + qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL); 619 + if (!qmc_dai->chans) 620 + return -ENOMEM; 621 + 622 + for (i = 0; i < count; i++) { 623 + qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np, 624 + "fsl,qmc-chan", i); 625 + if (IS_ERR(qmc_dai->chans[i].qmc_chan)) { 626 + return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan), 627 + "dai %d get QMC channel %d failed\n", qmc_dai->id, i); 628 + } 629 + 630 + ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info); 631 + if (ret) { 632 + dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n", 633 + qmc_dai->id, i, ret); 634 + return ret; 635 + } 636 + dev_info(qmc_audio->dev, "dai %d QMC channel %d mode %d, nb_tx_ts %u, nb_rx_ts %u\n", 637 + qmc_dai->id, i, info.mode, info.nb_tx_ts, info.nb_rx_ts); 638 + 639 + if (info.mode != QMC_TRANSPARENT) { 640 + dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n", 641 + qmc_dai->id, i, info.mode); 642 + return -EINVAL; 643 + } 644 + 645 + /* 646 + * All channels must have the same number of Tx slots and the 647 + * same numbers of Rx slots. 648 + */ 649 + if (i == 0) { 650 + nb_tx_ts = info.nb_tx_ts; 651 + nb_rx_ts = info.nb_rx_ts; 652 + tx_fs_rate = info.tx_fs_rate; 653 + rx_fs_rate = info.rx_fs_rate; 654 + } else { 655 + if (nb_tx_ts != info.nb_tx_ts) { 656 + dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Tx timeslots (%u instead of %u)\n", 657 + qmc_dai->id, i, info.nb_tx_ts, nb_tx_ts); 658 + return -EINVAL; 659 + } 660 + if (nb_rx_ts != info.nb_rx_ts) { 661 + dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Rx timeslots (%u instead of %u)\n", 662 + qmc_dai->id, i, info.nb_rx_ts, nb_rx_ts); 663 + return -EINVAL; 664 + } 665 + if (tx_fs_rate != info.tx_fs_rate) { 666 + dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Tx frame sample rate (%lu instead of %lu)\n", 667 + qmc_dai->id, i, info.tx_fs_rate, tx_fs_rate); 668 + return -EINVAL; 669 + } 670 + if (rx_fs_rate != info.rx_fs_rate) { 671 + dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Rx frame sample rate (%lu instead of %lu)\n", 672 + qmc_dai->id, i, info.rx_fs_rate, rx_fs_rate); 673 + return -EINVAL; 674 + } 675 + } 819 676 } 677 + 678 + qmc_dai->nb_chans_avail = count; 679 + qmc_dai->nb_tx_ts = nb_tx_ts * count; 680 + qmc_dai->nb_rx_ts = nb_rx_ts * count; 820 681 821 682 qmc_soc_dai_driver->id = qmc_dai->id; 822 683 qmc_soc_dai_driver->name = qmc_dai->name; 823 684 824 - ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info); 825 - if (ret) { 826 - dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n", 827 - qmc_dai->id, ret); 828 - return ret; 829 - } 830 - dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n", 831 - qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts); 832 - 833 - if (info.mode != QMC_TRANSPARENT) { 834 - dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n", 835 - qmc_dai->id, info.mode); 836 - return -EINVAL; 837 - } 838 - qmc_dai->nb_tx_ts = info.nb_tx_ts; 839 - qmc_dai->nb_rx_ts = info.nb_rx_ts; 840 - 841 685 qmc_soc_dai_driver->playback.channels_min = 0; 842 686 qmc_soc_dai_driver->playback.channels_max = 0; 843 - if (qmc_dai->nb_tx_ts) { 687 + if (nb_tx_ts) { 844 688 qmc_soc_dai_driver->playback.channels_min = 1; 845 - qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts; 689 + qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts; 846 690 } 847 - qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts); 691 + qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts, 692 + count > 1 ? true : false); 848 693 849 694 qmc_soc_dai_driver->capture.channels_min = 0; 850 695 qmc_soc_dai_driver->capture.channels_max = 0; 851 - if (qmc_dai->nb_rx_ts) { 696 + if (nb_rx_ts) { 852 697 qmc_soc_dai_driver->capture.channels_min = 1; 853 - qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts; 698 + qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts; 854 699 } 855 - qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts); 700 + qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts, 701 + count > 1 ? true : false); 856 702 857 - qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate); 858 - qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate; 859 - qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate; 860 - qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate); 861 - qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate; 862 - qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate; 703 + qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate); 704 + qmc_soc_dai_driver->playback.rate_min = tx_fs_rate; 705 + qmc_soc_dai_driver->playback.rate_max = tx_fs_rate; 706 + qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(rx_fs_rate); 707 + qmc_soc_dai_driver->capture.rate_min = rx_fs_rate; 708 + qmc_soc_dai_driver->capture.rate_max = rx_fs_rate; 863 709 864 710 qmc_soc_dai_driver->ops = &qmc_dai_ops; 865 711 ··· 957 701 } 958 702 i++; 959 703 } 960 - 961 704 962 705 platform_set_drvdata(pdev, qmc_audio); 963 706