~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/fsl/fsl_qmc_audio.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * ALSA SoC using the QUICC Multichannel Controller (QMC)
  4  *
  5  * Copyright 2022 CS GROUP France
  6  *
  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 
 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 struct 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 
 39 struct 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 
 46 struct 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 
 64 static 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 
 79 static 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 
 91 static 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 audio
100          * channels whereas in non-interleaved mode, it uses one QMC channel per
101          * 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 
121 static void qmc_audio_pcm_write_complete(void *context);
122 
123 static 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 
147 static 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 before
159          * 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 
177 static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags);
178 
179 static 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 
203 static 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 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;
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 
238 static 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 
308 static 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 
316 static 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 
336 static 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 
349 static 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 
372 static 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 
381 static 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 
391 static 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 
398 static 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 8bit
412  * time-slots available.
413  */
414 static 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 
446 static 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 
454 static 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 
462 static 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 
491 static 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 
499 static 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 
507 static 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 
562 static 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 
591 static 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 
610 static 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 audio
628          * channels whereas in non-interleaved mode, it uses one QMC channel per
629          * 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 
659 static 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 
729 err_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 
737 static 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 
743 static 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 or
758                  * 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 the
770                  * channel
771                  */
772                 if (format_width > chan_width || chan_width % format_width)
773                         continue;
774 
775                 /*
776                  * In non interleaved mode, we can only support formats that
777                  * can fit only 1 time in the channel
778                  */
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 
787 static 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 the
852                  * 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 
920 static 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 
973 static const struct of_device_id qmc_audio_id_table[] = {
974         { .compatible = "fsl,qmc-audio" },
975         {} /* sentinel */
976 };
977 MODULE_DEVICE_TABLE(of, qmc_audio_id_table);
978 
979 static 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 };
986 module_platform_driver(qmc_audio_driver);
987 
988 MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
989 MODULE_DESCRIPTION("CPM/QE QMC audio driver");
990 MODULE_LICENSE("GPL");
991 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php