Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/fsl/fsl_qmc_audio.c
26428 views
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 <[email protected]>
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
prtd->buffer_ended = 0;
254
prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
255
256
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
257
for (i = 0; i < prtd->channels; i++)
258
prtd->qmc_dai->chans[i].prtd_tx = prtd;
259
260
/* Submit first chunk ... */
261
ret = qmc_audio_pcm_write_submit(prtd);
262
if (ret)
263
return ret;
264
265
/* ... prepare next one ... */
266
prtd->ch_dma_addr_current += prtd->ch_dma_size;
267
if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
268
prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
269
270
/* ... and send it */
271
ret = qmc_audio_pcm_write_submit(prtd);
272
if (ret)
273
return ret;
274
} else {
275
for (i = 0; i < prtd->channels; i++)
276
prtd->qmc_dai->chans[i].prtd_rx = prtd;
277
278
/* Submit first chunk ... */
279
ret = qmc_audio_pcm_read_submit(prtd);
280
if (ret)
281
return ret;
282
283
/* ... prepare next one ... */
284
prtd->ch_dma_addr_current += prtd->ch_dma_size;
285
if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
286
prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
287
288
/* ... and send it */
289
ret = qmc_audio_pcm_read_submit(prtd);
290
if (ret)
291
return ret;
292
}
293
break;
294
295
case SNDRV_PCM_TRIGGER_RESUME:
296
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
297
break;
298
299
case SNDRV_PCM_TRIGGER_STOP:
300
case SNDRV_PCM_TRIGGER_SUSPEND:
301
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
302
break;
303
304
default:
305
return -EINVAL;
306
}
307
308
return 0;
309
}
310
311
static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *component,
312
struct snd_pcm_substream *substream)
313
{
314
struct qmc_dai_prtd *prtd = substream->runtime->private_data;
315
316
return prtd->buffer_ended;
317
}
318
319
static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,
320
const struct of_phandle_args *args,
321
const char **dai_name)
322
{
323
struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);
324
struct snd_soc_dai_driver *dai_driver;
325
int id = args->args[0];
326
int i;
327
328
for (i = 0; i < qmc_audio->num_dais; i++) {
329
dai_driver = qmc_audio->dai_drivers + i;
330
if (dai_driver->id == id) {
331
*dai_name = dai_driver->name;
332
return 0;
333
}
334
}
335
336
return -EINVAL;
337
}
338
339
static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {
340
.info = SNDRV_PCM_INFO_MMAP |
341
SNDRV_PCM_INFO_MMAP_VALID |
342
SNDRV_PCM_INFO_INTERLEAVED |
343
SNDRV_PCM_INFO_NONINTERLEAVED |
344
SNDRV_PCM_INFO_PAUSE,
345
.period_bytes_min = 32,
346
.period_bytes_max = 64 * 1024,
347
.periods_min = 2,
348
.periods_max = 2 * 1024,
349
.buffer_bytes_max = 64 * 1024,
350
};
351
352
static int qmc_audio_pcm_open(struct snd_soc_component *component,
353
struct snd_pcm_substream *substream)
354
{
355
struct snd_pcm_runtime *runtime = substream->runtime;
356
struct qmc_dai_prtd *prtd;
357
int ret;
358
359
snd_soc_set_runtime_hwparams(substream, &qmc_audio_pcm_hardware);
360
361
/* ensure that buffer size is a multiple of period size */
362
ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
363
if (ret < 0)
364
return ret;
365
366
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
367
if (!prtd)
368
return -ENOMEM;
369
370
runtime->private_data = prtd;
371
372
return 0;
373
}
374
375
static int qmc_audio_pcm_close(struct snd_soc_component *component,
376
struct snd_pcm_substream *substream)
377
{
378
struct qmc_dai_prtd *prtd = substream->runtime->private_data;
379
380
kfree(prtd);
381
return 0;
382
}
383
384
static const struct snd_soc_component_driver qmc_audio_soc_platform = {
385
.open = qmc_audio_pcm_open,
386
.close = qmc_audio_pcm_close,
387
.hw_params = qmc_audio_pcm_hw_params,
388
.trigger = qmc_audio_pcm_trigger,
389
.pointer = qmc_audio_pcm_pointer,
390
.pcm_construct = qmc_audio_pcm_construct,
391
.of_xlate_dai_name = qmc_audio_of_xlate_dai_name,
392
};
393
394
static unsigned int qmc_dai_get_index(struct snd_soc_dai *dai)
395
{
396
struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
397
398
return dai->driver - qmc_audio->dai_drivers;
399
}
400
401
static struct qmc_dai *qmc_dai_get_data(struct snd_soc_dai *dai)
402
{
403
struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
404
unsigned int index;
405
406
index = qmc_dai_get_index(dai);
407
if (index > qmc_audio->num_dais)
408
return NULL;
409
410
return qmc_audio->dais + index;
411
}
412
413
/*
414
* The constraints for format/channel is to match with the number of 8bit
415
* time-slots available.
416
*/
417
static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_dai,
418
struct snd_pcm_hw_params *params,
419
unsigned int nb_ts)
420
{
421
struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
422
snd_pcm_format_t format = params_format(params);
423
struct snd_interval ch = {0};
424
425
switch (snd_pcm_format_physical_width(format)) {
426
case 8:
427
ch.max = nb_ts;
428
break;
429
case 16:
430
ch.max = nb_ts / 2;
431
break;
432
case 32:
433
ch.max = nb_ts / 4;
434
break;
435
case 64:
436
ch.max = nb_ts / 8;
437
break;
438
default:
439
dev_err(qmc_dai->dev, "format physical width %u not supported\n",
440
snd_pcm_format_physical_width(format));
441
return -EINVAL;
442
}
443
444
ch.min = ch.max ? 1 : 0;
445
446
return snd_interval_refine(c, &ch);
447
}
448
449
static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
450
struct snd_pcm_hw_rule *rule)
451
{
452
struct qmc_dai *qmc_dai = rule->private;
453
454
return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);
455
}
456
457
static int qmc_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,
458
struct snd_pcm_hw_rule *rule)
459
{
460
struct qmc_dai *qmc_dai = rule->private;
461
462
return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_rx_ts);
463
}
464
465
static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
466
struct snd_pcm_hw_params *params,
467
unsigned int nb_ts)
468
{
469
struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
470
unsigned int channels = params_channels(params);
471
unsigned int slot_width;
472
snd_pcm_format_t format;
473
struct snd_mask f_new;
474
475
if (!channels || channels > nb_ts) {
476
dev_err(qmc_dai->dev, "channels %u not supported\n",
477
nb_ts);
478
return -EINVAL;
479
}
480
481
slot_width = (nb_ts / channels) * 8;
482
483
snd_mask_none(&f_new);
484
pcm_for_each_format(format) {
485
if (snd_mask_test_format(f_old, format)) {
486
if (snd_pcm_format_physical_width(format) <= slot_width)
487
snd_mask_set_format(&f_new, format);
488
}
489
}
490
491
return snd_mask_refine(f_old, &f_new);
492
}
493
494
static int qmc_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,
495
struct snd_pcm_hw_rule *rule)
496
{
497
struct qmc_dai *qmc_dai = rule->private;
498
499
return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);
500
}
501
502
static int qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,
503
struct snd_pcm_hw_rule *rule)
504
{
505
struct qmc_dai *qmc_dai = rule->private;
506
507
return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);
508
}
509
510
static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream,
511
struct qmc_dai *qmc_dai)
512
{
513
snd_pcm_hw_rule_func_t hw_rule_channels_by_format;
514
snd_pcm_hw_rule_func_t hw_rule_format_by_channels;
515
unsigned int frame_bits;
516
u64 access;
517
int ret;
518
519
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
520
hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;
521
hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;
522
frame_bits = qmc_dai->nb_rx_ts * 8;
523
} else {
524
hw_rule_channels_by_format = qmc_dai_hw_rule_playback_channels_by_format;
525
hw_rule_format_by_channels = qmc_dai_hw_rule_playback_format_by_channels;
526
frame_bits = qmc_dai->nb_tx_ts * 8;
527
}
528
529
ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
530
hw_rule_channels_by_format, qmc_dai,
531
SNDRV_PCM_HW_PARAM_FORMAT, -1);
532
if (ret) {
533
dev_err(qmc_dai->dev, "Failed to add channels rule (%d)\n", ret);
534
return ret;
535
}
536
537
ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
538
hw_rule_format_by_channels, qmc_dai,
539
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
540
if (ret) {
541
dev_err(qmc_dai->dev, "Failed to add format rule (%d)\n", ret);
542
return ret;
543
}
544
545
ret = snd_pcm_hw_constraint_single(substream->runtime,
546
SNDRV_PCM_HW_PARAM_FRAME_BITS,
547
frame_bits);
548
if (ret < 0) {
549
dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
550
return ret;
551
}
552
553
access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |
554
1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED;
555
ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
556
access);
557
if (ret) {
558
dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);
559
return ret;
560
}
561
562
return 0;
563
}
564
565
static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substream,
566
struct qmc_dai *qmc_dai)
567
{
568
unsigned int frame_bits;
569
u64 access;
570
int ret;
571
572
frame_bits = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ?
573
qmc_dai->nb_rx_ts * 8 : qmc_dai->nb_tx_ts * 8;
574
ret = snd_pcm_hw_constraint_single(substream->runtime,
575
SNDRV_PCM_HW_PARAM_FRAME_BITS,
576
frame_bits);
577
if (ret < 0) {
578
dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
579
return ret;
580
}
581
582
access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |
583
1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
584
ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
585
access);
586
if (ret) {
587
dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);
588
return ret;
589
}
590
591
return 0;
592
}
593
594
static int qmc_dai_startup(struct snd_pcm_substream *substream,
595
struct snd_soc_dai *dai)
596
{
597
struct qmc_dai_prtd *prtd = substream->runtime->private_data;
598
struct qmc_dai *qmc_dai;
599
600
qmc_dai = qmc_dai_get_data(dai);
601
if (!qmc_dai) {
602
dev_err(dai->dev, "Invalid dai\n");
603
return -EINVAL;
604
}
605
606
prtd->qmc_dai = qmc_dai;
607
608
return qmc_dai->nb_chans_avail > 1 ?
609
qmc_dai_constraints_noninterleaved(substream, qmc_dai) :
610
qmc_dai_constraints_interleaved(substream, qmc_dai);
611
}
612
613
static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
614
struct snd_pcm_hw_params *params,
615
struct snd_soc_dai *dai)
616
{
617
struct qmc_chan_param chan_param = {0};
618
unsigned int nb_chans_used;
619
struct qmc_dai *qmc_dai;
620
unsigned int i;
621
int ret;
622
623
qmc_dai = qmc_dai_get_data(dai);
624
if (!qmc_dai) {
625
dev_err(dai->dev, "Invalid dai\n");
626
return -EINVAL;
627
}
628
629
/*
630
* In interleaved mode, the driver uses one QMC channel for all audio
631
* channels whereas in non-interleaved mode, it uses one QMC channel per
632
* audio channel.
633
*/
634
nb_chans_used = qmc_audio_access_is_interleaved(params_access(params)) ?
635
1 : params_channels(params);
636
637
if (nb_chans_used > qmc_dai->nb_chans_avail) {
638
dev_err(dai->dev, "Not enough qmc_chans. Need %u, avail %u\n",
639
nb_chans_used, qmc_dai->nb_chans_avail);
640
return -EINVAL;
641
}
642
643
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
644
chan_param.mode = QMC_TRANSPARENT;
645
chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;
646
for (i = 0; i < nb_chans_used; i++) {
647
ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param);
648
if (ret) {
649
dev_err(dai->dev, "chans[%u], set param failed %d\n",
650
i, ret);
651
return ret;
652
}
653
}
654
qmc_dai->nb_chans_used_rx = nb_chans_used;
655
} else {
656
qmc_dai->nb_chans_used_tx = nb_chans_used;
657
}
658
659
return 0;
660
}
661
662
static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
663
struct snd_soc_dai *dai)
664
{
665
unsigned int nb_chans_used;
666
struct qmc_dai *qmc_dai;
667
unsigned int i;
668
int direction;
669
int ret = 0;
670
int ret_tmp;
671
672
qmc_dai = qmc_dai_get_data(dai);
673
if (!qmc_dai) {
674
dev_err(dai->dev, "Invalid dai\n");
675
return -EINVAL;
676
}
677
678
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
679
direction = QMC_CHAN_WRITE;
680
nb_chans_used = qmc_dai->nb_chans_used_tx;
681
} else {
682
direction = QMC_CHAN_READ;
683
nb_chans_used = qmc_dai->nb_chans_used_rx;
684
}
685
686
switch (cmd) {
687
case SNDRV_PCM_TRIGGER_START:
688
case SNDRV_PCM_TRIGGER_RESUME:
689
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
690
for (i = 0; i < nb_chans_used; i++) {
691
ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction);
692
if (ret)
693
goto err_stop;
694
}
695
break;
696
697
case SNDRV_PCM_TRIGGER_STOP:
698
/* Stop and reset all QMC channels and return the first error encountered */
699
for (i = 0; i < nb_chans_used; i++) {
700
ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
701
if (!ret)
702
ret = ret_tmp;
703
if (ret_tmp)
704
continue;
705
706
ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);
707
if (!ret)
708
ret = ret_tmp;
709
}
710
if (ret)
711
return ret;
712
break;
713
714
case SNDRV_PCM_TRIGGER_SUSPEND:
715
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
716
/* Stop all QMC channels and return the first error encountered */
717
for (i = 0; i < nb_chans_used; i++) {
718
ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
719
if (!ret)
720
ret = ret_tmp;
721
}
722
if (ret)
723
return ret;
724
break;
725
726
default:
727
return -EINVAL;
728
}
729
730
return 0;
731
732
err_stop:
733
while (i--) {
734
qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);
735
qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);
736
}
737
return ret;
738
}
739
740
static const struct snd_soc_dai_ops qmc_dai_ops = {
741
.startup = qmc_dai_startup,
742
.trigger = qmc_dai_trigger,
743
.hw_params = qmc_dai_hw_params,
744
};
745
746
static u64 qmc_audio_formats(u8 nb_ts, bool is_noninterleaved)
747
{
748
unsigned int format_width;
749
unsigned int chan_width;
750
snd_pcm_format_t format;
751
u64 formats_mask;
752
753
if (!nb_ts)
754
return 0;
755
756
formats_mask = 0;
757
chan_width = nb_ts * 8;
758
pcm_for_each_format(format) {
759
/*
760
* Support format other than little-endian (ie big-endian or
761
* without endianness such as 8bit formats)
762
*/
763
if (snd_pcm_format_little_endian(format) == 1)
764
continue;
765
766
/* Support physical width multiple of 8bit */
767
format_width = snd_pcm_format_physical_width(format);
768
if (format_width == 0 || format_width % 8)
769
continue;
770
771
/*
772
* And support physical width that can fit N times in the
773
* channel
774
*/
775
if (format_width > chan_width || chan_width % format_width)
776
continue;
777
778
/*
779
* In non interleaved mode, we can only support formats that
780
* can fit only 1 time in the channel
781
*/
782
if (is_noninterleaved && format_width != chan_width)
783
continue;
784
785
formats_mask |= pcm_format_to_bits(format);
786
}
787
return formats_mask;
788
}
789
790
static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
791
struct qmc_dai *qmc_dai,
792
struct snd_soc_dai_driver *qmc_soc_dai_driver)
793
{
794
struct qmc_chan_info info;
795
unsigned long rx_fs_rate;
796
unsigned long tx_fs_rate;
797
unsigned int nb_tx_ts;
798
unsigned int nb_rx_ts;
799
unsigned int i;
800
int count;
801
u32 val;
802
int ret;
803
804
qmc_dai->dev = qmc_audio->dev;
805
806
ret = of_property_read_u32(np, "reg", &val);
807
if (ret) {
808
dev_err(qmc_audio->dev, "%pOF: failed to read reg\n", np);
809
return ret;
810
}
811
qmc_dai->id = val;
812
813
qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",
814
np->parent->name, qmc_dai->id);
815
if (!qmc_dai->name)
816
return -ENOMEM;
817
818
count = qmc_chan_count_phandles(np, "fsl,qmc-chan");
819
if (count < 0)
820
return dev_err_probe(qmc_audio->dev, count,
821
"dai %d get number of QMC channel failed\n", qmc_dai->id);
822
if (!count)
823
return dev_err_probe(qmc_audio->dev, -EINVAL,
824
"dai %d no QMC channel defined\n", qmc_dai->id);
825
826
qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL);
827
if (!qmc_dai->chans)
828
return -ENOMEM;
829
830
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),
835
"dai %d get QMC channel %d failed\n", qmc_dai->id, i);
836
}
837
838
ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info);
839
if (ret) {
840
dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",
841
qmc_dai->id, i, ret);
842
return ret;
843
}
844
845
if (info.mode != QMC_TRANSPARENT) {
846
dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n",
847
qmc_dai->id, i, info.mode);
848
return -EINVAL;
849
}
850
851
/*
852
* All channels must have the same number of Tx slots and the
853
* same numbers of Rx slots.
854
*/
855
if (i == 0) {
856
nb_tx_ts = info.nb_tx_ts;
857
nb_rx_ts = info.nb_rx_ts;
858
tx_fs_rate = info.tx_fs_rate;
859
rx_fs_rate = info.rx_fs_rate;
860
} else {
861
if (nb_tx_ts != info.nb_tx_ts) {
862
dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Tx timeslots (%u instead of %u)\n",
863
qmc_dai->id, i, info.nb_tx_ts, nb_tx_ts);
864
return -EINVAL;
865
}
866
if (nb_rx_ts != info.nb_rx_ts) {
867
dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Rx timeslots (%u instead of %u)\n",
868
qmc_dai->id, i, info.nb_rx_ts, nb_rx_ts);
869
return -EINVAL;
870
}
871
if (tx_fs_rate != info.tx_fs_rate) {
872
dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Tx frame sample rate (%lu instead of %lu)\n",
873
qmc_dai->id, i, info.tx_fs_rate, tx_fs_rate);
874
return -EINVAL;
875
}
876
if (rx_fs_rate != info.rx_fs_rate) {
877
dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Rx frame sample rate (%lu instead of %lu)\n",
878
qmc_dai->id, i, info.rx_fs_rate, rx_fs_rate);
879
return -EINVAL;
880
}
881
}
882
}
883
884
qmc_dai->nb_chans_avail = count;
885
qmc_dai->nb_tx_ts = nb_tx_ts * count;
886
qmc_dai->nb_rx_ts = nb_rx_ts * count;
887
888
qmc_soc_dai_driver->id = qmc_dai->id;
889
qmc_soc_dai_driver->name = qmc_dai->name;
890
891
qmc_soc_dai_driver->playback.channels_min = 0;
892
qmc_soc_dai_driver->playback.channels_max = 0;
893
if (nb_tx_ts) {
894
qmc_soc_dai_driver->playback.channels_min = 1;
895
qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts;
896
}
897
qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts,
898
count > 1);
899
900
qmc_soc_dai_driver->capture.channels_min = 0;
901
qmc_soc_dai_driver->capture.channels_max = 0;
902
if (nb_rx_ts) {
903
qmc_soc_dai_driver->capture.channels_min = 1;
904
qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts;
905
}
906
qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts,
907
count > 1);
908
909
qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate);
910
qmc_soc_dai_driver->playback.rate_min = tx_fs_rate;
911
qmc_soc_dai_driver->playback.rate_max = tx_fs_rate;
912
qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(rx_fs_rate);
913
qmc_soc_dai_driver->capture.rate_min = rx_fs_rate;
914
qmc_soc_dai_driver->capture.rate_max = rx_fs_rate;
915
916
qmc_soc_dai_driver->ops = &qmc_dai_ops;
917
918
return 0;
919
}
920
921
static int qmc_audio_probe(struct platform_device *pdev)
922
{
923
struct device_node *np = pdev->dev.of_node;
924
struct qmc_audio *qmc_audio;
925
struct device_node *child;
926
unsigned int i;
927
int ret;
928
929
qmc_audio = devm_kzalloc(&pdev->dev, sizeof(*qmc_audio), GFP_KERNEL);
930
if (!qmc_audio)
931
return -ENOMEM;
932
933
qmc_audio->dev = &pdev->dev;
934
935
qmc_audio->num_dais = of_get_available_child_count(np);
936
if (qmc_audio->num_dais) {
937
qmc_audio->dais = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
938
sizeof(*qmc_audio->dais),
939
GFP_KERNEL);
940
if (!qmc_audio->dais)
941
return -ENOMEM;
942
943
qmc_audio->dai_drivers = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
944
sizeof(*qmc_audio->dai_drivers),
945
GFP_KERNEL);
946
if (!qmc_audio->dai_drivers)
947
return -ENOMEM;
948
}
949
950
i = 0;
951
for_each_available_child_of_node(np, child) {
952
ret = qmc_audio_dai_parse(qmc_audio, child,
953
qmc_audio->dais + i,
954
qmc_audio->dai_drivers + i);
955
if (ret) {
956
of_node_put(child);
957
return ret;
958
}
959
i++;
960
}
961
962
platform_set_drvdata(pdev, qmc_audio);
963
964
ret = devm_snd_soc_register_component(qmc_audio->dev,
965
&qmc_audio_soc_platform,
966
qmc_audio->dai_drivers,
967
qmc_audio->num_dais);
968
if (ret)
969
return ret;
970
971
return 0;
972
}
973
974
static const struct of_device_id qmc_audio_id_table[] = {
975
{ .compatible = "fsl,qmc-audio" },
976
{} /* sentinel */
977
};
978
MODULE_DEVICE_TABLE(of, qmc_audio_id_table);
979
980
static struct platform_driver qmc_audio_driver = {
981
.driver = {
982
.name = "fsl-qmc-audio",
983
.of_match_table = of_match_ptr(qmc_audio_id_table),
984
},
985
.probe = qmc_audio_probe,
986
};
987
module_platform_driver(qmc_audio_driver);
988
989
MODULE_AUTHOR("Herve Codina <[email protected]>");
990
MODULE_DESCRIPTION("CPM/QE QMC audio driver");
991
MODULE_LICENSE("GPL");
992
993