Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/qcom/qdsp6/q6asm-dai.c
53517 views
1
// SPDX-License-Identifier: GPL-2.0
2
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
3
// Copyright (c) 2018, Linaro Limited
4
5
#include <dt-bindings/sound/qcom,q6asm.h>
6
#include <linux/init.h>
7
#include <linux/err.h>
8
#include <linux/module.h>
9
#include <linux/of.h>
10
#include <linux/platform_device.h>
11
#include <linux/slab.h>
12
#include <sound/soc.h>
13
#include <sound/soc-dapm.h>
14
#include <sound/pcm.h>
15
#include <linux/spinlock.h>
16
#include <sound/compress_driver.h>
17
#include <asm/div64.h>
18
#include <asm/dma.h>
19
#include <linux/dma-mapping.h>
20
#include <sound/pcm_params.h>
21
#include "q6asm.h"
22
#include "q6routing.h"
23
#include "q6dsp-errno.h"
24
25
#define DRV_NAME "q6asm-fe-dai"
26
27
#define PLAYBACK_MIN_NUM_PERIODS 2
28
#define PLAYBACK_MAX_NUM_PERIODS 8
29
#define PLAYBACK_MAX_PERIOD_SIZE 65536
30
#define PLAYBACK_MIN_PERIOD_SIZE 128
31
#define CAPTURE_MIN_NUM_PERIODS 2
32
#define CAPTURE_MAX_NUM_PERIODS 8
33
#define CAPTURE_MAX_PERIOD_SIZE 4096
34
#define CAPTURE_MIN_PERIOD_SIZE 320
35
#define SID_MASK_DEFAULT 0xF
36
37
/* Default values used if user space does not set */
38
#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
39
#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
40
#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
41
#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
42
43
#define ALAC_CH_LAYOUT_MONO ((101 << 16) | 1)
44
#define ALAC_CH_LAYOUT_STEREO ((101 << 16) | 2)
45
46
enum stream_state {
47
Q6ASM_STREAM_IDLE = 0,
48
Q6ASM_STREAM_STOPPED,
49
Q6ASM_STREAM_RUNNING,
50
};
51
52
struct q6asm_dai_rtd {
53
struct snd_pcm_substream *substream;
54
struct snd_compr_stream *cstream;
55
struct snd_codec codec;
56
struct snd_dma_buffer dma_buffer;
57
spinlock_t lock;
58
phys_addr_t phys;
59
unsigned int pcm_size;
60
unsigned int pcm_count;
61
unsigned int periods;
62
uint64_t bytes_sent;
63
uint64_t bytes_received;
64
uint64_t copied_total;
65
uint16_t bits_per_sample;
66
snd_pcm_uframes_t queue_ptr;
67
uint16_t source; /* Encoding source bit mask */
68
struct audio_client *audio_client;
69
uint32_t next_track_stream_id;
70
bool next_track;
71
uint32_t stream_id;
72
uint16_t session_id;
73
enum stream_state state;
74
uint32_t initial_samples_drop;
75
uint32_t trailing_samples_drop;
76
bool notify_on_drain;
77
};
78
79
struct q6asm_dai_data {
80
struct snd_soc_dai_driver *dais;
81
int num_dais;
82
long long int sid;
83
};
84
85
static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
86
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
87
SNDRV_PCM_INFO_BLOCK_TRANSFER |
88
SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR |
89
SNDRV_PCM_INFO_MMAP_VALID |
90
SNDRV_PCM_INFO_INTERLEAVED |
91
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
92
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
93
SNDRV_PCM_FMTBIT_S24_LE),
94
.rates = SNDRV_PCM_RATE_8000_48000,
95
.rate_min = 8000,
96
.rate_max = 48000,
97
.channels_min = 1,
98
.channels_max = 4,
99
.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
100
CAPTURE_MAX_PERIOD_SIZE,
101
.period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
102
.period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
103
.periods_min = CAPTURE_MIN_NUM_PERIODS,
104
.periods_max = CAPTURE_MAX_NUM_PERIODS,
105
.fifo_size = 0,
106
};
107
108
static const struct snd_pcm_hardware q6asm_dai_hardware_playback = {
109
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
110
SNDRV_PCM_INFO_BLOCK_TRANSFER |
111
SNDRV_PCM_INFO_MMAP_VALID |
112
SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR |
113
SNDRV_PCM_INFO_INTERLEAVED |
114
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
115
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
116
SNDRV_PCM_FMTBIT_S24_LE),
117
.rates = SNDRV_PCM_RATE_8000_192000,
118
.rate_min = 8000,
119
.rate_max = 192000,
120
.channels_min = 1,
121
.channels_max = 8,
122
.buffer_bytes_max = (PLAYBACK_MAX_NUM_PERIODS *
123
PLAYBACK_MAX_PERIOD_SIZE),
124
.period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
125
.period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
126
.periods_min = PLAYBACK_MIN_NUM_PERIODS,
127
.periods_max = PLAYBACK_MAX_NUM_PERIODS,
128
.fifo_size = 0,
129
};
130
131
#define Q6ASM_FEDAI_DRIVER(num) { \
132
.playback = { \
133
.stream_name = "MultiMedia"#num" Playback", \
134
.rates = (SNDRV_PCM_RATE_8000_48000 | \
135
SNDRV_PCM_RATE_12000 | \
136
SNDRV_PCM_RATE_24000 | \
137
SNDRV_PCM_RATE_88200 | \
138
SNDRV_PCM_RATE_96000 | \
139
SNDRV_PCM_RATE_176400 | \
140
SNDRV_PCM_RATE_192000), \
141
.formats = (SNDRV_PCM_FMTBIT_S16_LE | \
142
SNDRV_PCM_FMTBIT_S24_LE), \
143
.channels_min = 1, \
144
.channels_max = 8, \
145
.rate_min = 8000, \
146
.rate_max = 192000, \
147
}, \
148
.capture = { \
149
.stream_name = "MultiMedia"#num" Capture", \
150
.rates = (SNDRV_PCM_RATE_8000_48000 | \
151
SNDRV_PCM_RATE_12000 | \
152
SNDRV_PCM_RATE_24000), \
153
.formats = (SNDRV_PCM_FMTBIT_S16_LE | \
154
SNDRV_PCM_FMTBIT_S24_LE), \
155
.channels_min = 1, \
156
.channels_max = 4, \
157
.rate_min = 8000, \
158
.rate_max = 48000, \
159
}, \
160
.name = "MultiMedia"#num, \
161
.id = MSM_FRONTEND_DAI_MULTIMEDIA##num, \
162
}
163
164
static const struct snd_compr_codec_caps q6asm_compr_caps = {
165
.num_descriptors = 1,
166
.descriptor[0].max_ch = 2,
167
.descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
168
24000, 32000, 44100, 48000, 88200,
169
96000, 176400, 192000 },
170
.descriptor[0].num_sample_rates = 13,
171
.descriptor[0].bit_rate[0] = 320,
172
.descriptor[0].bit_rate[1] = 128,
173
.descriptor[0].num_bitrates = 2,
174
.descriptor[0].profiles = 0,
175
.descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
176
.descriptor[0].formats = 0,
177
};
178
179
static void event_handler(uint32_t opcode, uint32_t token,
180
void *payload, void *priv)
181
{
182
struct q6asm_dai_rtd *prtd = priv;
183
struct snd_pcm_substream *substream = prtd->substream;
184
185
switch (opcode) {
186
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
187
break;
188
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
189
prtd->state = Q6ASM_STREAM_STOPPED;
190
break;
191
case ASM_CLIENT_EVENT_DATA_WRITE_DONE: {
192
snd_pcm_period_elapsed(substream);
193
break;
194
}
195
case ASM_CLIENT_EVENT_DATA_READ_DONE:
196
snd_pcm_period_elapsed(substream);
197
if (prtd->state == Q6ASM_STREAM_RUNNING)
198
q6asm_read(prtd->audio_client, prtd->stream_id);
199
200
break;
201
default:
202
break;
203
}
204
}
205
206
static int q6asm_dai_prepare(struct snd_soc_component *component,
207
struct snd_pcm_substream *substream)
208
{
209
struct snd_pcm_runtime *runtime = substream->runtime;
210
struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
211
struct q6asm_dai_rtd *prtd = runtime->private_data;
212
struct q6asm_dai_data *pdata;
213
struct device *dev = component->dev;
214
int ret, i;
215
216
pdata = snd_soc_component_get_drvdata(component);
217
if (!pdata)
218
return -EINVAL;
219
220
if (!prtd || !prtd->audio_client) {
221
dev_err(dev, "%s: private data null or audio client freed\n",
222
__func__);
223
return -EINVAL;
224
}
225
226
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
227
/* rate and channels are sent to audio driver */
228
if (prtd->state == Q6ASM_STREAM_RUNNING) {
229
/* clear the previous setup if any */
230
q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
231
q6asm_unmap_memory_regions(substream->stream,
232
prtd->audio_client);
233
q6routing_stream_close(soc_prtd->dai_link->id,
234
substream->stream);
235
prtd->state = Q6ASM_STREAM_STOPPED;
236
}
237
238
ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client,
239
prtd->phys,
240
(prtd->pcm_size / prtd->periods),
241
prtd->periods);
242
243
if (ret < 0) {
244
dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n",
245
ret);
246
return -ENOMEM;
247
}
248
249
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
250
ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
251
FORMAT_LINEAR_PCM,
252
0, prtd->bits_per_sample, false);
253
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
254
ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
255
FORMAT_LINEAR_PCM,
256
prtd->bits_per_sample);
257
}
258
259
if (ret < 0) {
260
dev_err(dev, "%s: q6asm_open_write failed\n", __func__);
261
goto open_err;
262
}
263
264
prtd->session_id = q6asm_get_session_id(prtd->audio_client);
265
ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
266
prtd->session_id, substream->stream);
267
if (ret) {
268
dev_err(dev, "%s: stream reg failed ret:%d\n", __func__, ret);
269
goto routing_err;
270
}
271
272
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
273
ret = q6asm_media_format_block_multi_ch_pcm(
274
prtd->audio_client, prtd->stream_id,
275
runtime->rate, runtime->channels, NULL,
276
prtd->bits_per_sample);
277
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
278
ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
279
prtd->stream_id,
280
runtime->rate,
281
runtime->channels,
282
prtd->bits_per_sample);
283
284
/* Queue the buffers */
285
for (i = 0; i < runtime->periods; i++)
286
q6asm_read(prtd->audio_client, prtd->stream_id);
287
288
}
289
if (ret < 0)
290
dev_info(dev, "%s: CMD Format block failed\n", __func__);
291
else
292
prtd->state = Q6ASM_STREAM_RUNNING;
293
294
return ret;
295
296
routing_err:
297
q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
298
open_err:
299
q6asm_unmap_memory_regions(substream->stream, prtd->audio_client);
300
q6asm_audio_client_free(prtd->audio_client);
301
prtd->audio_client = NULL;
302
303
return ret;
304
}
305
306
static int q6asm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream)
307
{
308
struct snd_pcm_runtime *runtime = substream->runtime;
309
struct q6asm_dai_rtd *prtd = runtime->private_data;
310
int i, ret = 0, avail_periods;
311
312
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && prtd->state == Q6ASM_STREAM_RUNNING) {
313
avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size;
314
for (i = 0; i < avail_periods; i++) {
315
ret = q6asm_write_async(prtd->audio_client, prtd->stream_id,
316
prtd->pcm_count, 0, 0, 0);
317
318
if (ret < 0) {
319
dev_err(component->dev, "Error queuing playback buffer %d\n", ret);
320
return ret;
321
}
322
prtd->queue_ptr += runtime->period_size;
323
}
324
}
325
326
return ret;
327
}
328
329
static int q6asm_dai_trigger(struct snd_soc_component *component,
330
struct snd_pcm_substream *substream, int cmd)
331
{
332
int ret = 0;
333
struct snd_pcm_runtime *runtime = substream->runtime;
334
struct q6asm_dai_rtd *prtd = runtime->private_data;
335
336
switch (cmd) {
337
case SNDRV_PCM_TRIGGER_START:
338
case SNDRV_PCM_TRIGGER_RESUME:
339
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
340
ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
341
0, 0, 0);
342
break;
343
case SNDRV_PCM_TRIGGER_STOP:
344
prtd->state = Q6ASM_STREAM_STOPPED;
345
ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
346
CMD_EOS);
347
break;
348
case SNDRV_PCM_TRIGGER_SUSPEND:
349
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
350
ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
351
CMD_PAUSE);
352
break;
353
default:
354
ret = -EINVAL;
355
break;
356
}
357
358
return ret;
359
}
360
361
static int q6asm_dai_open(struct snd_soc_component *component,
362
struct snd_pcm_substream *substream)
363
{
364
struct snd_pcm_runtime *runtime = substream->runtime;
365
struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
366
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0);
367
struct q6asm_dai_rtd *prtd;
368
struct q6asm_dai_data *pdata;
369
struct device *dev = component->dev;
370
int ret = 0;
371
int stream_id;
372
373
stream_id = cpu_dai->driver->id;
374
375
pdata = snd_soc_component_get_drvdata(component);
376
if (!pdata) {
377
dev_err(dev, "Drv data not found ..\n");
378
return -EINVAL;
379
}
380
381
prtd = kzalloc(sizeof(struct q6asm_dai_rtd), GFP_KERNEL);
382
if (prtd == NULL)
383
return -ENOMEM;
384
385
prtd->substream = substream;
386
prtd->audio_client = q6asm_audio_client_alloc(dev,
387
(q6asm_cb)event_handler, prtd, stream_id,
388
LEGACY_PCM_MODE);
389
if (IS_ERR(prtd->audio_client)) {
390
dev_info(dev, "%s: Could not allocate memory\n", __func__);
391
ret = PTR_ERR(prtd->audio_client);
392
kfree(prtd);
393
return ret;
394
}
395
396
/* DSP expects stream id from 1 */
397
prtd->stream_id = 1;
398
399
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
400
runtime->hw = q6asm_dai_hardware_playback;
401
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
402
runtime->hw = q6asm_dai_hardware_capture;
403
404
/* Ensure that buffer size is a multiple of period size */
405
ret = snd_pcm_hw_constraint_integer(runtime,
406
SNDRV_PCM_HW_PARAM_PERIODS);
407
if (ret < 0)
408
dev_info(dev, "snd_pcm_hw_constraint_integer failed\n");
409
410
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
411
ret = snd_pcm_hw_constraint_minmax(runtime,
412
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
413
PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
414
PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
415
if (ret < 0) {
416
dev_err(dev, "constraint for buffer bytes min max ret = %d\n",
417
ret);
418
}
419
}
420
421
ret = snd_pcm_hw_constraint_step(runtime, 0,
422
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480);
423
if (ret < 0) {
424
dev_err(dev, "constraint for period bytes step ret = %d\n",
425
ret);
426
}
427
ret = snd_pcm_hw_constraint_step(runtime, 0,
428
SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480);
429
if (ret < 0) {
430
dev_err(dev, "constraint for buffer bytes step ret = %d\n",
431
ret);
432
}
433
434
runtime->private_data = prtd;
435
436
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
437
snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
438
runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
439
} else {
440
snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_capture);
441
runtime->dma_bytes = q6asm_dai_hardware_capture.buffer_bytes_max;
442
}
443
444
if (pdata->sid < 0)
445
prtd->phys = substream->dma_buffer.addr;
446
else
447
prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
448
449
return 0;
450
}
451
452
static int q6asm_dai_close(struct snd_soc_component *component,
453
struct snd_pcm_substream *substream)
454
{
455
struct snd_pcm_runtime *runtime = substream->runtime;
456
struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
457
struct q6asm_dai_rtd *prtd = runtime->private_data;
458
459
if (prtd->audio_client) {
460
if (prtd->state)
461
q6asm_cmd(prtd->audio_client, prtd->stream_id,
462
CMD_CLOSE);
463
464
q6asm_unmap_memory_regions(substream->stream,
465
prtd->audio_client);
466
q6asm_audio_client_free(prtd->audio_client);
467
prtd->audio_client = NULL;
468
}
469
q6routing_stream_close(soc_prtd->dai_link->id,
470
substream->stream);
471
kfree(prtd);
472
return 0;
473
}
474
475
static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component,
476
struct snd_pcm_substream *substream)
477
{
478
479
struct snd_pcm_runtime *runtime = substream->runtime;
480
struct q6asm_dai_rtd *prtd = runtime->private_data;
481
snd_pcm_uframes_t ptr;
482
483
ptr = q6asm_get_hw_pointer(prtd->audio_client, substream->stream) * runtime->period_size;
484
if (ptr)
485
return ptr - 1;
486
487
return 0;
488
}
489
490
static int q6asm_dai_hw_params(struct snd_soc_component *component,
491
struct snd_pcm_substream *substream,
492
struct snd_pcm_hw_params *params)
493
{
494
struct snd_pcm_runtime *runtime = substream->runtime;
495
struct q6asm_dai_rtd *prtd = runtime->private_data;
496
497
prtd->pcm_size = params_buffer_bytes(params);
498
prtd->periods = params_periods(params);
499
500
switch (params_format(params)) {
501
case SNDRV_PCM_FORMAT_S16_LE:
502
prtd->bits_per_sample = 16;
503
break;
504
case SNDRV_PCM_FORMAT_S24_LE:
505
prtd->bits_per_sample = 24;
506
break;
507
}
508
509
return 0;
510
}
511
512
static void compress_event_handler(uint32_t opcode, uint32_t token,
513
void *payload, void *priv)
514
{
515
struct q6asm_dai_rtd *prtd = priv;
516
struct snd_compr_stream *substream = prtd->cstream;
517
u32 wflags = 0;
518
uint64_t avail;
519
uint32_t bytes_written, bytes_to_write;
520
bool is_last_buffer = false;
521
522
guard(spinlock_irqsave)(&prtd->lock);
523
524
switch (opcode) {
525
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
526
if (!prtd->bytes_sent) {
527
q6asm_stream_remove_initial_silence(prtd->audio_client,
528
prtd->stream_id,
529
prtd->initial_samples_drop);
530
531
q6asm_write_async(prtd->audio_client, prtd->stream_id,
532
prtd->pcm_count, 0, 0, 0);
533
prtd->bytes_sent += prtd->pcm_count;
534
}
535
536
break;
537
538
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
539
if (prtd->notify_on_drain) {
540
if (substream->partial_drain) {
541
/*
542
* Close old stream and make it stale, switch
543
* the active stream now!
544
*/
545
q6asm_cmd_nowait(prtd->audio_client,
546
prtd->stream_id,
547
CMD_CLOSE);
548
/*
549
* vaild stream ids start from 1, So we are
550
* toggling this between 1 and 2.
551
*/
552
prtd->stream_id = (prtd->stream_id == 1 ? 2 : 1);
553
}
554
555
snd_compr_drain_notify(prtd->cstream);
556
prtd->notify_on_drain = false;
557
558
} else {
559
prtd->state = Q6ASM_STREAM_STOPPED;
560
}
561
break;
562
563
case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
564
565
bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
566
prtd->copied_total += bytes_written;
567
snd_compr_fragment_elapsed(substream);
568
569
if (prtd->state != Q6ASM_STREAM_RUNNING)
570
break;
571
572
avail = prtd->bytes_received - prtd->bytes_sent;
573
if (avail > prtd->pcm_count) {
574
bytes_to_write = prtd->pcm_count;
575
} else {
576
if (substream->partial_drain || prtd->notify_on_drain)
577
is_last_buffer = true;
578
bytes_to_write = avail;
579
}
580
581
if (bytes_to_write) {
582
if (substream->partial_drain && is_last_buffer) {
583
wflags |= ASM_LAST_BUFFER_FLAG;
584
q6asm_stream_remove_trailing_silence(prtd->audio_client,
585
prtd->stream_id,
586
prtd->trailing_samples_drop);
587
}
588
589
q6asm_write_async(prtd->audio_client, prtd->stream_id,
590
bytes_to_write, 0, 0, wflags);
591
592
prtd->bytes_sent += bytes_to_write;
593
}
594
595
if (prtd->notify_on_drain && is_last_buffer)
596
q6asm_cmd_nowait(prtd->audio_client,
597
prtd->stream_id, CMD_EOS);
598
599
break;
600
601
default:
602
break;
603
}
604
}
605
606
static int q6asm_dai_compr_open(struct snd_soc_component *component,
607
struct snd_compr_stream *stream)
608
{
609
struct snd_soc_pcm_runtime *rtd = stream->private_data;
610
struct snd_compr_runtime *runtime = stream->runtime;
611
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
612
struct q6asm_dai_data *pdata;
613
struct device *dev = component->dev;
614
struct q6asm_dai_rtd *prtd;
615
int stream_id, size, ret;
616
617
stream_id = cpu_dai->driver->id;
618
pdata = snd_soc_component_get_drvdata(component);
619
if (!pdata) {
620
dev_err(dev, "Drv data not found ..\n");
621
return -EINVAL;
622
}
623
624
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
625
if (!prtd)
626
return -ENOMEM;
627
628
/* DSP expects stream id from 1 */
629
prtd->stream_id = 1;
630
631
prtd->cstream = stream;
632
prtd->audio_client = q6asm_audio_client_alloc(dev,
633
(q6asm_cb)compress_event_handler,
634
prtd, stream_id, LEGACY_PCM_MODE);
635
if (IS_ERR(prtd->audio_client)) {
636
dev_err(dev, "Could not allocate memory\n");
637
ret = PTR_ERR(prtd->audio_client);
638
goto free_prtd;
639
}
640
641
size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
642
COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
643
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
644
&prtd->dma_buffer);
645
if (ret) {
646
dev_err(dev, "Cannot allocate buffer(s)\n");
647
goto free_client;
648
}
649
650
if (pdata->sid < 0)
651
prtd->phys = prtd->dma_buffer.addr;
652
else
653
prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
654
655
snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
656
spin_lock_init(&prtd->lock);
657
runtime->private_data = prtd;
658
659
return 0;
660
661
free_client:
662
q6asm_audio_client_free(prtd->audio_client);
663
free_prtd:
664
kfree(prtd);
665
666
return ret;
667
}
668
669
static int q6asm_dai_compr_free(struct snd_soc_component *component,
670
struct snd_compr_stream *stream)
671
{
672
struct snd_compr_runtime *runtime = stream->runtime;
673
struct q6asm_dai_rtd *prtd = runtime->private_data;
674
struct snd_soc_pcm_runtime *rtd = stream->private_data;
675
676
if (prtd->audio_client) {
677
if (prtd->state) {
678
q6asm_cmd(prtd->audio_client, prtd->stream_id,
679
CMD_CLOSE);
680
if (prtd->next_track_stream_id) {
681
q6asm_cmd(prtd->audio_client,
682
prtd->next_track_stream_id,
683
CMD_CLOSE);
684
}
685
}
686
687
snd_dma_free_pages(&prtd->dma_buffer);
688
q6asm_unmap_memory_regions(stream->direction,
689
prtd->audio_client);
690
q6asm_audio_client_free(prtd->audio_client);
691
prtd->audio_client = NULL;
692
}
693
q6routing_stream_close(rtd->dai_link->id, stream->direction);
694
kfree(prtd);
695
696
return 0;
697
}
698
699
static int __q6asm_dai_compr_set_codec_params(struct snd_soc_component *component,
700
struct snd_compr_stream *stream,
701
struct snd_codec *codec,
702
int stream_id)
703
{
704
struct snd_compr_runtime *runtime = stream->runtime;
705
struct q6asm_dai_rtd *prtd = runtime->private_data;
706
struct q6asm_flac_cfg flac_cfg;
707
struct q6asm_wma_cfg wma_cfg;
708
struct q6asm_alac_cfg alac_cfg;
709
struct q6asm_ape_cfg ape_cfg;
710
unsigned int wma_v9 = 0;
711
struct device *dev = component->dev;
712
int ret;
713
union snd_codec_options *codec_options;
714
struct snd_dec_flac *flac;
715
struct snd_dec_wma *wma;
716
struct snd_dec_alac *alac;
717
struct snd_dec_ape *ape;
718
719
codec_options = &(prtd->codec.options);
720
721
memcpy(&prtd->codec, codec, sizeof(*codec));
722
723
switch (codec->id) {
724
case SND_AUDIOCODEC_FLAC:
725
726
memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg));
727
flac = &codec_options->flac_d;
728
729
flac_cfg.ch_cfg = codec->ch_in;
730
flac_cfg.sample_rate = codec->sample_rate;
731
flac_cfg.stream_info_present = 1;
732
flac_cfg.sample_size = flac->sample_size;
733
flac_cfg.min_blk_size = flac->min_blk_size;
734
flac_cfg.max_blk_size = flac->max_blk_size;
735
flac_cfg.max_frame_size = flac->max_frame_size;
736
flac_cfg.min_frame_size = flac->min_frame_size;
737
738
ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
739
stream_id,
740
&flac_cfg);
741
if (ret < 0) {
742
dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
743
return -EIO;
744
}
745
break;
746
747
case SND_AUDIOCODEC_WMA:
748
wma = &codec_options->wma_d;
749
750
memset(&wma_cfg, 0x0, sizeof(struct q6asm_wma_cfg));
751
752
wma_cfg.sample_rate = codec->sample_rate;
753
wma_cfg.num_channels = codec->ch_in;
754
wma_cfg.bytes_per_sec = codec->bit_rate / 8;
755
wma_cfg.block_align = codec->align;
756
wma_cfg.bits_per_sample = prtd->bits_per_sample;
757
wma_cfg.enc_options = wma->encoder_option;
758
wma_cfg.adv_enc_options = wma->adv_encoder_option;
759
wma_cfg.adv_enc_options2 = wma->adv_encoder_option2;
760
761
if (wma_cfg.num_channels == 1)
762
wma_cfg.channel_mask = 4; /* Mono Center */
763
else if (wma_cfg.num_channels == 2)
764
wma_cfg.channel_mask = 3; /* Stereo FL/FR */
765
else
766
return -EINVAL;
767
768
/* check the codec profile */
769
switch (codec->profile) {
770
case SND_AUDIOPROFILE_WMA9:
771
wma_cfg.fmtag = 0x161;
772
wma_v9 = 1;
773
break;
774
775
case SND_AUDIOPROFILE_WMA10:
776
wma_cfg.fmtag = 0x166;
777
break;
778
779
case SND_AUDIOPROFILE_WMA9_PRO:
780
wma_cfg.fmtag = 0x162;
781
break;
782
783
case SND_AUDIOPROFILE_WMA9_LOSSLESS:
784
wma_cfg.fmtag = 0x163;
785
break;
786
787
case SND_AUDIOPROFILE_WMA10_LOSSLESS:
788
wma_cfg.fmtag = 0x167;
789
break;
790
791
default:
792
dev_err(dev, "Unknown WMA profile:%x\n",
793
codec->profile);
794
return -EIO;
795
}
796
797
if (wma_v9)
798
ret = q6asm_stream_media_format_block_wma_v9(
799
prtd->audio_client, stream_id,
800
&wma_cfg);
801
else
802
ret = q6asm_stream_media_format_block_wma_v10(
803
prtd->audio_client, stream_id,
804
&wma_cfg);
805
if (ret < 0) {
806
dev_err(dev, "WMA9 CMD failed:%d\n", ret);
807
return -EIO;
808
}
809
break;
810
811
case SND_AUDIOCODEC_ALAC:
812
memset(&alac_cfg, 0x0, sizeof(alac_cfg));
813
alac = &codec_options->alac_d;
814
815
alac_cfg.sample_rate = codec->sample_rate;
816
alac_cfg.avg_bit_rate = codec->bit_rate;
817
alac_cfg.bit_depth = prtd->bits_per_sample;
818
alac_cfg.num_channels = codec->ch_in;
819
820
alac_cfg.frame_length = alac->frame_length;
821
alac_cfg.pb = alac->pb;
822
alac_cfg.mb = alac->mb;
823
alac_cfg.kb = alac->kb;
824
alac_cfg.max_run = alac->max_run;
825
alac_cfg.compatible_version = alac->compatible_version;
826
alac_cfg.max_frame_bytes = alac->max_frame_bytes;
827
828
switch (codec->ch_in) {
829
case 1:
830
alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_MONO;
831
break;
832
case 2:
833
alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_STEREO;
834
break;
835
}
836
ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
837
stream_id,
838
&alac_cfg);
839
if (ret < 0) {
840
dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
841
return -EIO;
842
}
843
break;
844
845
case SND_AUDIOCODEC_APE:
846
memset(&ape_cfg, 0x0, sizeof(ape_cfg));
847
ape = &codec_options->ape_d;
848
849
ape_cfg.sample_rate = codec->sample_rate;
850
ape_cfg.num_channels = codec->ch_in;
851
ape_cfg.bits_per_sample = prtd->bits_per_sample;
852
853
ape_cfg.compatible_version = ape->compatible_version;
854
ape_cfg.compression_level = ape->compression_level;
855
ape_cfg.format_flags = ape->format_flags;
856
ape_cfg.blocks_per_frame = ape->blocks_per_frame;
857
ape_cfg.final_frame_blocks = ape->final_frame_blocks;
858
ape_cfg.total_frames = ape->total_frames;
859
ape_cfg.seek_table_present = ape->seek_table_present;
860
861
ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
862
stream_id,
863
&ape_cfg);
864
if (ret < 0) {
865
dev_err(dev, "APE CMD Format block failed:%d\n", ret);
866
return -EIO;
867
}
868
break;
869
870
default:
871
break;
872
}
873
874
return 0;
875
}
876
877
static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
878
struct snd_compr_stream *stream,
879
struct snd_compr_params *params)
880
{
881
struct snd_compr_runtime *runtime = stream->runtime;
882
struct q6asm_dai_rtd *prtd = runtime->private_data;
883
struct snd_soc_pcm_runtime *rtd = stream->private_data;
884
int dir = stream->direction;
885
struct q6asm_dai_data *pdata;
886
struct device *dev = component->dev;
887
int ret;
888
889
pdata = snd_soc_component_get_drvdata(component);
890
if (!pdata)
891
return -EINVAL;
892
893
if (!prtd || !prtd->audio_client) {
894
dev_err(dev, "private data null or audio client freed\n");
895
return -EINVAL;
896
}
897
898
prtd->periods = runtime->fragments;
899
prtd->pcm_count = runtime->fragment_size;
900
prtd->pcm_size = runtime->fragments * runtime->fragment_size;
901
prtd->bits_per_sample = 16;
902
903
if (dir == SND_COMPRESS_PLAYBACK) {
904
ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id,
905
params->codec.profile, prtd->bits_per_sample,
906
true);
907
908
if (ret < 0) {
909
dev_err(dev, "q6asm_open_write failed\n");
910
goto open_err;
911
}
912
}
913
914
prtd->session_id = q6asm_get_session_id(prtd->audio_client);
915
ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
916
prtd->session_id, dir);
917
if (ret) {
918
dev_err(dev, "Stream reg failed ret:%d\n", ret);
919
goto q6_err;
920
}
921
922
ret = __q6asm_dai_compr_set_codec_params(component, stream,
923
&params->codec,
924
prtd->stream_id);
925
if (ret) {
926
dev_err(dev, "codec param setup failed ret:%d\n", ret);
927
goto q6_err;
928
}
929
930
ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
931
(prtd->pcm_size / prtd->periods),
932
prtd->periods);
933
934
if (ret < 0) {
935
dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
936
ret = -ENOMEM;
937
goto q6_err;
938
}
939
940
prtd->state = Q6ASM_STREAM_RUNNING;
941
942
return 0;
943
944
q6_err:
945
q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
946
947
open_err:
948
q6asm_audio_client_free(prtd->audio_client);
949
prtd->audio_client = NULL;
950
return ret;
951
}
952
953
static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
954
struct snd_compr_stream *stream,
955
struct snd_compr_metadata *metadata)
956
{
957
struct snd_compr_runtime *runtime = stream->runtime;
958
struct q6asm_dai_rtd *prtd = runtime->private_data;
959
int ret = 0;
960
961
switch (metadata->key) {
962
case SNDRV_COMPRESS_ENCODER_PADDING:
963
prtd->trailing_samples_drop = metadata->value[0];
964
break;
965
case SNDRV_COMPRESS_ENCODER_DELAY:
966
prtd->initial_samples_drop = metadata->value[0];
967
if (prtd->next_track_stream_id) {
968
ret = q6asm_open_write(prtd->audio_client,
969
prtd->next_track_stream_id,
970
prtd->codec.id,
971
prtd->codec.profile,
972
prtd->bits_per_sample,
973
true);
974
if (ret < 0) {
975
dev_err(component->dev, "q6asm_open_write failed\n");
976
return ret;
977
}
978
ret = __q6asm_dai_compr_set_codec_params(component, stream,
979
&prtd->codec,
980
prtd->next_track_stream_id);
981
if (ret < 0) {
982
dev_err(component->dev, "q6asm_open_write failed\n");
983
return ret;
984
}
985
986
ret = q6asm_stream_remove_initial_silence(prtd->audio_client,
987
prtd->next_track_stream_id,
988
prtd->initial_samples_drop);
989
prtd->next_track_stream_id = 0;
990
991
}
992
993
break;
994
default:
995
ret = -EINVAL;
996
break;
997
}
998
999
return ret;
1000
}
1001
1002
static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
1003
struct snd_compr_stream *stream, int cmd)
1004
{
1005
struct snd_compr_runtime *runtime = stream->runtime;
1006
struct q6asm_dai_rtd *prtd = runtime->private_data;
1007
int ret = 0;
1008
1009
switch (cmd) {
1010
case SNDRV_PCM_TRIGGER_START:
1011
case SNDRV_PCM_TRIGGER_RESUME:
1012
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1013
ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
1014
0, 0, 0);
1015
break;
1016
case SNDRV_PCM_TRIGGER_STOP:
1017
prtd->state = Q6ASM_STREAM_STOPPED;
1018
ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
1019
CMD_EOS);
1020
break;
1021
case SNDRV_PCM_TRIGGER_SUSPEND:
1022
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1023
ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
1024
CMD_PAUSE);
1025
break;
1026
case SND_COMPR_TRIGGER_NEXT_TRACK:
1027
prtd->next_track = true;
1028
prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1);
1029
break;
1030
case SND_COMPR_TRIGGER_DRAIN:
1031
case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
1032
prtd->notify_on_drain = true;
1033
break;
1034
default:
1035
ret = -EINVAL;
1036
break;
1037
}
1038
1039
return ret;
1040
}
1041
1042
static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
1043
struct snd_compr_stream *stream,
1044
struct snd_compr_tstamp64 *tstamp)
1045
{
1046
struct snd_compr_runtime *runtime = stream->runtime;
1047
struct q6asm_dai_rtd *prtd = runtime->private_data;
1048
uint64_t temp_copied_total;
1049
1050
guard(spinlock_irqsave)(&prtd->lock);
1051
1052
tstamp->copied_total = prtd->copied_total;
1053
temp_copied_total = tstamp->copied_total;
1054
tstamp->byte_offset = do_div(temp_copied_total, prtd->pcm_size);
1055
1056
return 0;
1057
}
1058
1059
static int q6asm_compr_copy(struct snd_soc_component *component,
1060
struct snd_compr_stream *stream, char __user *buf,
1061
size_t count)
1062
{
1063
struct snd_compr_runtime *runtime = stream->runtime;
1064
struct q6asm_dai_rtd *prtd = runtime->private_data;
1065
u32 wflags = 0;
1066
uint64_t avail, bytes_in_flight = 0;
1067
void *dstn;
1068
size_t copy;
1069
u32 app_pointer;
1070
uint64_t bytes_received;
1071
uint64_t temp_bytes_received;
1072
1073
bytes_received = prtd->bytes_received;
1074
temp_bytes_received = bytes_received;
1075
1076
/**
1077
* Make sure that next track data pointer is aligned at 32 bit boundary
1078
* This is a Mandatory requirement from DSP data buffers alignment
1079
*/
1080
if (prtd->next_track) {
1081
bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
1082
temp_bytes_received = bytes_received;
1083
}
1084
1085
app_pointer = do_div(temp_bytes_received, prtd->pcm_size);
1086
dstn = prtd->dma_buffer.area + app_pointer;
1087
1088
if (count < prtd->pcm_size - app_pointer) {
1089
if (copy_from_user(dstn, buf, count))
1090
return -EFAULT;
1091
} else {
1092
copy = prtd->pcm_size - app_pointer;
1093
if (copy_from_user(dstn, buf, copy))
1094
return -EFAULT;
1095
if (copy_from_user(prtd->dma_buffer.area, buf + copy,
1096
count - copy))
1097
return -EFAULT;
1098
}
1099
1100
guard(spinlock_irqsave)(&prtd->lock);
1101
1102
bytes_in_flight = prtd->bytes_received - prtd->copied_total;
1103
1104
if (prtd->next_track) {
1105
prtd->next_track = false;
1106
prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
1107
prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
1108
}
1109
1110
prtd->bytes_received = bytes_received + count;
1111
1112
/* Kick off the data to dsp if its starving!! */
1113
if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
1114
uint32_t bytes_to_write = prtd->pcm_count;
1115
1116
avail = prtd->bytes_received - prtd->bytes_sent;
1117
1118
if (avail < prtd->pcm_count)
1119
bytes_to_write = avail;
1120
1121
q6asm_write_async(prtd->audio_client, prtd->stream_id,
1122
bytes_to_write, 0, 0, wflags);
1123
prtd->bytes_sent += bytes_to_write;
1124
}
1125
1126
return count;
1127
}
1128
1129
static int q6asm_dai_compr_mmap(struct snd_soc_component *component,
1130
struct snd_compr_stream *stream,
1131
struct vm_area_struct *vma)
1132
{
1133
struct snd_compr_runtime *runtime = stream->runtime;
1134
struct q6asm_dai_rtd *prtd = runtime->private_data;
1135
struct device *dev = component->dev;
1136
1137
return dma_mmap_coherent(dev, vma,
1138
prtd->dma_buffer.area, prtd->dma_buffer.addr,
1139
prtd->dma_buffer.bytes);
1140
}
1141
1142
static int q6asm_dai_compr_get_caps(struct snd_soc_component *component,
1143
struct snd_compr_stream *stream,
1144
struct snd_compr_caps *caps)
1145
{
1146
caps->direction = SND_COMPRESS_PLAYBACK;
1147
caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
1148
caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
1149
caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
1150
caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
1151
caps->num_codecs = 5;
1152
caps->codecs[0] = SND_AUDIOCODEC_MP3;
1153
caps->codecs[1] = SND_AUDIOCODEC_FLAC;
1154
caps->codecs[2] = SND_AUDIOCODEC_WMA;
1155
caps->codecs[3] = SND_AUDIOCODEC_ALAC;
1156
caps->codecs[4] = SND_AUDIOCODEC_APE;
1157
1158
return 0;
1159
}
1160
1161
static int q6asm_dai_compr_get_codec_caps(struct snd_soc_component *component,
1162
struct snd_compr_stream *stream,
1163
struct snd_compr_codec_caps *codec)
1164
{
1165
switch (codec->codec) {
1166
case SND_AUDIOCODEC_MP3:
1167
*codec = q6asm_compr_caps;
1168
break;
1169
default:
1170
break;
1171
}
1172
1173
return 0;
1174
}
1175
1176
static const struct snd_compress_ops q6asm_dai_compress_ops = {
1177
.open = q6asm_dai_compr_open,
1178
.free = q6asm_dai_compr_free,
1179
.set_params = q6asm_dai_compr_set_params,
1180
.set_metadata = q6asm_dai_compr_set_metadata,
1181
.pointer = q6asm_dai_compr_pointer,
1182
.trigger = q6asm_dai_compr_trigger,
1183
.get_caps = q6asm_dai_compr_get_caps,
1184
.get_codec_caps = q6asm_dai_compr_get_codec_caps,
1185
.mmap = q6asm_dai_compr_mmap,
1186
.copy = q6asm_compr_copy,
1187
};
1188
1189
static int q6asm_dai_pcm_new(struct snd_soc_component *component,
1190
struct snd_soc_pcm_runtime *rtd)
1191
{
1192
struct snd_pcm *pcm = rtd->pcm;
1193
size_t size = q6asm_dai_hardware_playback.buffer_bytes_max;
1194
1195
return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
1196
component->dev, size);
1197
}
1198
1199
static const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
1200
SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, SND_SOC_NOPM, 0, 0),
1201
SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, SND_SOC_NOPM, 0, 0),
1202
SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, SND_SOC_NOPM, 0, 0),
1203
SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, SND_SOC_NOPM, 0, 0),
1204
SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, SND_SOC_NOPM, 0, 0),
1205
SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, SND_SOC_NOPM, 0, 0),
1206
SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, SND_SOC_NOPM, 0, 0),
1207
SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, SND_SOC_NOPM, 0, 0),
1208
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, SND_SOC_NOPM, 0, 0),
1209
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, SND_SOC_NOPM, 0, 0),
1210
SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, SND_SOC_NOPM, 0, 0),
1211
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, SND_SOC_NOPM, 0, 0),
1212
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, SND_SOC_NOPM, 0, 0),
1213
SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, SND_SOC_NOPM, 0, 0),
1214
SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, SND_SOC_NOPM, 0, 0),
1215
SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, SND_SOC_NOPM, 0, 0),
1216
};
1217
1218
static const struct snd_soc_component_driver q6asm_fe_dai_component = {
1219
.name = DRV_NAME,
1220
.open = q6asm_dai_open,
1221
.hw_params = q6asm_dai_hw_params,
1222
.close = q6asm_dai_close,
1223
.prepare = q6asm_dai_prepare,
1224
.trigger = q6asm_dai_trigger,
1225
.ack = q6asm_dai_ack,
1226
.pointer = q6asm_dai_pointer,
1227
.pcm_construct = q6asm_dai_pcm_new,
1228
.compress_ops = &q6asm_dai_compress_ops,
1229
.dapm_widgets = q6asm_dapm_widgets,
1230
.num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
1231
.legacy_dai_naming = 1,
1232
};
1233
1234
static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
1235
Q6ASM_FEDAI_DRIVER(1),
1236
Q6ASM_FEDAI_DRIVER(2),
1237
Q6ASM_FEDAI_DRIVER(3),
1238
Q6ASM_FEDAI_DRIVER(4),
1239
Q6ASM_FEDAI_DRIVER(5),
1240
Q6ASM_FEDAI_DRIVER(6),
1241
Q6ASM_FEDAI_DRIVER(7),
1242
Q6ASM_FEDAI_DRIVER(8),
1243
};
1244
1245
static const struct snd_soc_dai_ops q6asm_dai_ops = {
1246
.compress_new = snd_soc_new_compress,
1247
};
1248
1249
static int of_q6asm_parse_dai_data(struct device *dev,
1250
struct q6asm_dai_data *pdata)
1251
{
1252
struct snd_soc_dai_driver *dai_drv;
1253
struct snd_soc_pcm_stream empty_stream;
1254
struct device_node *node;
1255
int ret, id, dir, idx = 0;
1256
1257
1258
pdata->num_dais = of_get_child_count(dev->of_node);
1259
if (!pdata->num_dais) {
1260
dev_err(dev, "No dais found in DT\n");
1261
return -EINVAL;
1262
}
1263
1264
pdata->dais = devm_kcalloc(dev, pdata->num_dais, sizeof(*dai_drv),
1265
GFP_KERNEL);
1266
if (!pdata->dais)
1267
return -ENOMEM;
1268
1269
memset(&empty_stream, 0, sizeof(empty_stream));
1270
1271
for_each_child_of_node(dev->of_node, node) {
1272
ret = of_property_read_u32(node, "reg", &id);
1273
if (ret || id >= MAX_SESSIONS || id < 0) {
1274
dev_err(dev, "valid dai id not found:%d\n", ret);
1275
continue;
1276
}
1277
1278
dai_drv = &pdata->dais[idx++];
1279
*dai_drv = q6asm_fe_dais_template[id];
1280
1281
ret = of_property_read_u32(node, "direction", &dir);
1282
if (ret)
1283
continue;
1284
1285
if (dir == Q6ASM_DAI_RX)
1286
dai_drv->capture = empty_stream;
1287
else if (dir == Q6ASM_DAI_TX)
1288
dai_drv->playback = empty_stream;
1289
1290
if (of_property_read_bool(node, "is-compress-dai"))
1291
dai_drv->ops = &q6asm_dai_ops;
1292
}
1293
1294
return 0;
1295
}
1296
1297
static int q6asm_dai_probe(struct platform_device *pdev)
1298
{
1299
struct device *dev = &pdev->dev;
1300
struct device_node *node = dev->of_node;
1301
struct of_phandle_args args;
1302
struct q6asm_dai_data *pdata;
1303
int rc;
1304
1305
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1306
if (!pdata)
1307
return -ENOMEM;
1308
1309
rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
1310
if (rc < 0)
1311
pdata->sid = -1;
1312
else
1313
pdata->sid = args.args[0] & SID_MASK_DEFAULT;
1314
1315
dev_set_drvdata(dev, pdata);
1316
1317
rc = of_q6asm_parse_dai_data(dev, pdata);
1318
if (rc)
1319
return rc;
1320
1321
return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
1322
pdata->dais, pdata->num_dais);
1323
}
1324
1325
#ifdef CONFIG_OF
1326
static const struct of_device_id q6asm_dai_device_id[] = {
1327
{ .compatible = "qcom,q6asm-dais" },
1328
{},
1329
};
1330
MODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
1331
#endif
1332
1333
static struct platform_driver q6asm_dai_platform_driver = {
1334
.driver = {
1335
.name = "q6asm-dai",
1336
.of_match_table = of_match_ptr(q6asm_dai_device_id),
1337
},
1338
.probe = q6asm_dai_probe,
1339
};
1340
module_platform_driver(q6asm_dai_platform_driver);
1341
1342
MODULE_DESCRIPTION("Q6ASM dai driver");
1343
MODULE_LICENSE("GPL v2");
1344
1345