Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/qcom/qdsp6/q6apm-dai.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0
2
// Copyright (c) 2021, Linaro Limited
3
4
#include <linux/init.h>
5
#include <linux/err.h>
6
#include <linux/module.h>
7
#include <linux/of.h>
8
#include <linux/platform_device.h>
9
#include <linux/slab.h>
10
#include <sound/soc.h>
11
#include <sound/soc-dapm.h>
12
#include <linux/spinlock.h>
13
#include <sound/pcm.h>
14
#include <asm/dma.h>
15
#include <linux/dma-mapping.h>
16
#include <sound/pcm_params.h>
17
#include "q6apm.h"
18
19
#define DRV_NAME "q6apm-dai"
20
21
#define PLAYBACK_MIN_NUM_PERIODS 2
22
#define PLAYBACK_MAX_NUM_PERIODS 8
23
#define PLAYBACK_MAX_PERIOD_SIZE 65536
24
#define PLAYBACK_MIN_PERIOD_SIZE 128
25
#define CAPTURE_MIN_NUM_PERIODS 2
26
#define CAPTURE_MAX_NUM_PERIODS 8
27
#define CAPTURE_MAX_PERIOD_SIZE 65536
28
#define CAPTURE_MIN_PERIOD_SIZE 6144
29
#define BUFFER_BYTES_MAX (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE)
30
#define BUFFER_BYTES_MIN (PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE)
31
#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
32
#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
33
#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
34
#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
35
#define SID_MASK_DEFAULT 0xF
36
37
static const struct snd_compr_codec_caps q6apm_compr_caps = {
38
.num_descriptors = 1,
39
.descriptor[0].max_ch = 2,
40
.descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
41
24000, 32000, 44100, 48000, 88200,
42
96000, 176400, 192000 },
43
.descriptor[0].num_sample_rates = 13,
44
.descriptor[0].bit_rate[0] = 320,
45
.descriptor[0].bit_rate[1] = 128,
46
.descriptor[0].num_bitrates = 2,
47
.descriptor[0].profiles = 0,
48
.descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
49
.descriptor[0].formats = 0,
50
};
51
52
enum stream_state {
53
Q6APM_STREAM_IDLE = 0,
54
Q6APM_STREAM_STOPPED,
55
Q6APM_STREAM_RUNNING,
56
};
57
58
struct q6apm_dai_rtd {
59
struct snd_pcm_substream *substream;
60
struct snd_compr_stream *cstream;
61
struct snd_codec codec;
62
struct snd_compr_params codec_param;
63
struct snd_dma_buffer dma_buffer;
64
phys_addr_t phys;
65
unsigned int pcm_size;
66
unsigned int pcm_count;
67
unsigned int periods;
68
unsigned int bytes_sent;
69
unsigned int bytes_received;
70
unsigned int copied_total;
71
uint16_t bits_per_sample;
72
snd_pcm_uframes_t queue_ptr;
73
bool next_track;
74
enum stream_state state;
75
struct q6apm_graph *graph;
76
spinlock_t lock;
77
bool notify_on_drain;
78
};
79
80
struct q6apm_dai_data {
81
long long sid;
82
};
83
84
static const struct snd_pcm_hardware q6apm_dai_hardware_capture = {
85
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER |
86
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED |
87
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
88
SNDRV_PCM_INFO_BATCH),
89
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE),
90
.rates = SNDRV_PCM_RATE_8000_48000,
91
.rate_min = 8000,
92
.rate_max = 48000,
93
.channels_min = 2,
94
.channels_max = 4,
95
.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
96
.period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
97
.period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
98
.periods_min = CAPTURE_MIN_NUM_PERIODS,
99
.periods_max = CAPTURE_MAX_NUM_PERIODS,
100
.fifo_size = 0,
101
};
102
103
static const struct snd_pcm_hardware q6apm_dai_hardware_playback = {
104
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER |
105
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED |
106
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
107
SNDRV_PCM_INFO_BATCH),
108
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE),
109
.rates = SNDRV_PCM_RATE_8000_192000,
110
.rate_min = 8000,
111
.rate_max = 192000,
112
.channels_min = 2,
113
.channels_max = 8,
114
.buffer_bytes_max = (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE),
115
.period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
116
.period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
117
.periods_min = PLAYBACK_MIN_NUM_PERIODS,
118
.periods_max = PLAYBACK_MAX_NUM_PERIODS,
119
.fifo_size = 0,
120
};
121
122
static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *priv)
123
{
124
struct q6apm_dai_rtd *prtd = priv;
125
struct snd_pcm_substream *substream = prtd->substream;
126
127
switch (opcode) {
128
case APM_CLIENT_EVENT_CMD_EOS_DONE:
129
prtd->state = Q6APM_STREAM_STOPPED;
130
break;
131
case APM_CLIENT_EVENT_DATA_WRITE_DONE:
132
snd_pcm_period_elapsed(substream);
133
134
break;
135
case APM_CLIENT_EVENT_DATA_READ_DONE:
136
snd_pcm_period_elapsed(substream);
137
if (prtd->state == Q6APM_STREAM_RUNNING)
138
q6apm_read(prtd->graph);
139
140
break;
141
default:
142
break;
143
}
144
}
145
146
static void event_handler_compr(uint32_t opcode, uint32_t token,
147
void *payload, void *priv)
148
{
149
struct q6apm_dai_rtd *prtd = priv;
150
struct snd_compr_stream *substream = prtd->cstream;
151
unsigned long flags;
152
uint32_t wflags = 0;
153
uint64_t avail;
154
uint32_t bytes_written, bytes_to_write;
155
bool is_last_buffer = false;
156
157
switch (opcode) {
158
case APM_CLIENT_EVENT_CMD_EOS_DONE:
159
spin_lock_irqsave(&prtd->lock, flags);
160
if (prtd->notify_on_drain) {
161
snd_compr_drain_notify(prtd->cstream);
162
prtd->notify_on_drain = false;
163
} else {
164
prtd->state = Q6APM_STREAM_STOPPED;
165
}
166
spin_unlock_irqrestore(&prtd->lock, flags);
167
break;
168
case APM_CLIENT_EVENT_DATA_WRITE_DONE:
169
spin_lock_irqsave(&prtd->lock, flags);
170
bytes_written = token >> APM_WRITE_TOKEN_LEN_SHIFT;
171
prtd->copied_total += bytes_written;
172
snd_compr_fragment_elapsed(substream);
173
174
if (prtd->state != Q6APM_STREAM_RUNNING) {
175
spin_unlock_irqrestore(&prtd->lock, flags);
176
break;
177
}
178
179
avail = prtd->bytes_received - prtd->bytes_sent;
180
181
if (avail > prtd->pcm_count) {
182
bytes_to_write = prtd->pcm_count;
183
} else {
184
if (substream->partial_drain || prtd->notify_on_drain)
185
is_last_buffer = true;
186
bytes_to_write = avail;
187
}
188
189
if (bytes_to_write) {
190
if (substream->partial_drain && is_last_buffer)
191
wflags |= APM_LAST_BUFFER_FLAG;
192
193
q6apm_write_async(prtd->graph,
194
bytes_to_write, 0, 0, wflags);
195
196
prtd->bytes_sent += bytes_to_write;
197
198
if (prtd->notify_on_drain && is_last_buffer)
199
audioreach_shared_memory_send_eos(prtd->graph);
200
}
201
202
spin_unlock_irqrestore(&prtd->lock, flags);
203
break;
204
default:
205
break;
206
}
207
}
208
209
static int q6apm_dai_prepare(struct snd_soc_component *component,
210
struct snd_pcm_substream *substream)
211
{
212
struct snd_pcm_runtime *runtime = substream->runtime;
213
struct q6apm_dai_rtd *prtd = runtime->private_data;
214
struct audioreach_module_config cfg;
215
struct device *dev = component->dev;
216
struct q6apm_dai_data *pdata;
217
int ret;
218
219
pdata = snd_soc_component_get_drvdata(component);
220
if (!pdata)
221
return -EINVAL;
222
223
if (!prtd || !prtd->graph) {
224
dev_err(dev, "%s: private data null or audio client freed\n", __func__);
225
return -EINVAL;
226
}
227
228
cfg.direction = substream->stream;
229
cfg.sample_rate = runtime->rate;
230
cfg.num_channels = runtime->channels;
231
cfg.bit_width = prtd->bits_per_sample;
232
cfg.fmt = SND_AUDIOCODEC_PCM;
233
audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels);
234
235
if (prtd->state) {
236
/* clear the previous setup if any */
237
q6apm_graph_stop(prtd->graph);
238
q6apm_unmap_memory_regions(prtd->graph, substream->stream);
239
}
240
241
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
242
/* rate and channels are sent to audio driver */
243
ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);
244
if (ret < 0) {
245
dev_err(dev, "%s: q6apm_open_write failed\n", __func__);
246
return ret;
247
}
248
249
ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg);
250
if (ret < 0)
251
dev_err(dev, "%s: CMD Format block failed\n", __func__);
252
253
ret = q6apm_map_memory_regions(prtd->graph, substream->stream, prtd->phys,
254
(prtd->pcm_size / prtd->periods), prtd->periods);
255
256
if (ret < 0) {
257
dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret);
258
return -ENOMEM;
259
}
260
261
ret = q6apm_graph_prepare(prtd->graph);
262
if (ret) {
263
dev_err(dev, "Failed to prepare Graph %d\n", ret);
264
return ret;
265
}
266
267
ret = q6apm_graph_start(prtd->graph);
268
if (ret) {
269
dev_err(dev, "Failed to Start Graph %d\n", ret);
270
return ret;
271
}
272
273
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
274
int i;
275
/* Queue the buffers for Capture ONLY after graph is started */
276
for (i = 0; i < runtime->periods; i++)
277
q6apm_read(prtd->graph);
278
279
}
280
281
/* Now that graph as been prepared and started update the internal state accordingly */
282
prtd->state = Q6APM_STREAM_RUNNING;
283
284
return 0;
285
}
286
287
static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream)
288
{
289
struct snd_pcm_runtime *runtime = substream->runtime;
290
struct q6apm_dai_rtd *prtd = runtime->private_data;
291
int i, ret = 0, avail_periods;
292
293
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
294
avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size;
295
for (i = 0; i < avail_periods; i++) {
296
ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP);
297
if (ret < 0) {
298
dev_err(component->dev, "Error queuing playback buffer %d\n", ret);
299
return ret;
300
}
301
prtd->queue_ptr += runtime->period_size;
302
}
303
}
304
305
return ret;
306
}
307
308
static int q6apm_dai_trigger(struct snd_soc_component *component,
309
struct snd_pcm_substream *substream, int cmd)
310
{
311
struct snd_pcm_runtime *runtime = substream->runtime;
312
struct q6apm_dai_rtd *prtd = runtime->private_data;
313
int ret = 0;
314
315
switch (cmd) {
316
case SNDRV_PCM_TRIGGER_START:
317
case SNDRV_PCM_TRIGGER_RESUME:
318
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
319
break;
320
case SNDRV_PCM_TRIGGER_STOP:
321
/* TODO support be handled via SoftPause Module */
322
prtd->state = Q6APM_STREAM_STOPPED;
323
break;
324
case SNDRV_PCM_TRIGGER_SUSPEND:
325
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
326
break;
327
default:
328
ret = -EINVAL;
329
break;
330
}
331
332
return ret;
333
}
334
335
static int q6apm_dai_open(struct snd_soc_component *component,
336
struct snd_pcm_substream *substream)
337
{
338
struct snd_pcm_runtime *runtime = substream->runtime;
339
struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
340
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0);
341
struct device *dev = component->dev;
342
struct q6apm_dai_data *pdata;
343
struct q6apm_dai_rtd *prtd;
344
int graph_id, ret;
345
346
graph_id = cpu_dai->driver->id;
347
348
pdata = snd_soc_component_get_drvdata(component);
349
if (!pdata) {
350
dev_err(dev, "Drv data not found ..\n");
351
return -EINVAL;
352
}
353
354
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
355
if (prtd == NULL)
356
return -ENOMEM;
357
358
spin_lock_init(&prtd->lock);
359
prtd->substream = substream;
360
prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id);
361
if (IS_ERR(prtd->graph)) {
362
dev_err(dev, "%s: Could not allocate memory\n", __func__);
363
ret = PTR_ERR(prtd->graph);
364
goto err;
365
}
366
367
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
368
runtime->hw = q6apm_dai_hardware_playback;
369
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
370
runtime->hw = q6apm_dai_hardware_capture;
371
372
/* Ensure that buffer size is a multiple of period size */
373
ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
374
if (ret < 0) {
375
dev_err(dev, "snd_pcm_hw_constraint_integer failed\n");
376
goto err;
377
}
378
379
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
380
ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
381
BUFFER_BYTES_MIN, BUFFER_BYTES_MAX);
382
if (ret < 0) {
383
dev_err(dev, "constraint for buffer bytes min max ret = %d\n", ret);
384
goto err;
385
}
386
}
387
388
/* setup 10ms latency to accommodate DSP restrictions */
389
ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480);
390
if (ret < 0) {
391
dev_err(dev, "constraint for period bytes step ret = %d\n", ret);
392
goto err;
393
}
394
395
ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480);
396
if (ret < 0) {
397
dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret);
398
goto err;
399
}
400
401
runtime->private_data = prtd;
402
runtime->dma_bytes = BUFFER_BYTES_MAX;
403
if (pdata->sid < 0)
404
prtd->phys = substream->dma_buffer.addr;
405
else
406
prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
407
408
return 0;
409
err:
410
kfree(prtd);
411
412
return ret;
413
}
414
415
static int q6apm_dai_close(struct snd_soc_component *component,
416
struct snd_pcm_substream *substream)
417
{
418
struct snd_pcm_runtime *runtime = substream->runtime;
419
struct q6apm_dai_rtd *prtd = runtime->private_data;
420
421
if (prtd->state) { /* only stop graph that is started */
422
q6apm_graph_stop(prtd->graph);
423
q6apm_unmap_memory_regions(prtd->graph, substream->stream);
424
}
425
426
q6apm_graph_close(prtd->graph);
427
prtd->graph = NULL;
428
kfree(prtd);
429
runtime->private_data = NULL;
430
431
return 0;
432
}
433
434
static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component,
435
struct snd_pcm_substream *substream)
436
{
437
struct snd_pcm_runtime *runtime = substream->runtime;
438
struct q6apm_dai_rtd *prtd = runtime->private_data;
439
snd_pcm_uframes_t ptr;
440
441
ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size;
442
if (ptr)
443
return ptr - 1;
444
445
return 0;
446
}
447
448
static int q6apm_dai_hw_params(struct snd_soc_component *component,
449
struct snd_pcm_substream *substream,
450
struct snd_pcm_hw_params *params)
451
{
452
struct snd_pcm_runtime *runtime = substream->runtime;
453
struct q6apm_dai_rtd *prtd = runtime->private_data;
454
455
prtd->pcm_size = params_buffer_bytes(params);
456
prtd->periods = params_periods(params);
457
458
switch (params_format(params)) {
459
case SNDRV_PCM_FORMAT_S16_LE:
460
prtd->bits_per_sample = 16;
461
break;
462
case SNDRV_PCM_FORMAT_S24_LE:
463
prtd->bits_per_sample = 24;
464
break;
465
default:
466
return -EINVAL;
467
}
468
469
return 0;
470
}
471
472
static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd)
473
{
474
int size = BUFFER_BYTES_MAX;
475
476
return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size);
477
}
478
479
static int q6apm_dai_compr_open(struct snd_soc_component *component,
480
struct snd_compr_stream *stream)
481
{
482
struct snd_soc_pcm_runtime *rtd = stream->private_data;
483
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
484
struct snd_compr_runtime *runtime = stream->runtime;
485
struct q6apm_dai_rtd *prtd;
486
struct q6apm_dai_data *pdata;
487
struct device *dev = component->dev;
488
int ret, size;
489
int graph_id;
490
491
graph_id = cpu_dai->driver->id;
492
pdata = snd_soc_component_get_drvdata(component);
493
if (!pdata)
494
return -EINVAL;
495
496
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
497
if (prtd == NULL)
498
return -ENOMEM;
499
500
prtd->cstream = stream;
501
prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id);
502
if (IS_ERR(prtd->graph)) {
503
ret = PTR_ERR(prtd->graph);
504
kfree(prtd);
505
return ret;
506
}
507
508
runtime->private_data = prtd;
509
runtime->dma_bytes = BUFFER_BYTES_MAX;
510
size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE * COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
511
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, &prtd->dma_buffer);
512
if (ret)
513
return ret;
514
515
if (pdata->sid < 0)
516
prtd->phys = prtd->dma_buffer.addr;
517
else
518
prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
519
520
snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
521
spin_lock_init(&prtd->lock);
522
523
q6apm_enable_compress_module(dev, prtd->graph, true);
524
return 0;
525
}
526
527
static int q6apm_dai_compr_free(struct snd_soc_component *component,
528
struct snd_compr_stream *stream)
529
{
530
struct snd_compr_runtime *runtime = stream->runtime;
531
struct q6apm_dai_rtd *prtd = runtime->private_data;
532
533
q6apm_graph_stop(prtd->graph);
534
q6apm_unmap_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK);
535
q6apm_graph_close(prtd->graph);
536
snd_dma_free_pages(&prtd->dma_buffer);
537
prtd->graph = NULL;
538
kfree(prtd);
539
runtime->private_data = NULL;
540
541
return 0;
542
}
543
544
static int q6apm_dai_compr_get_caps(struct snd_soc_component *component,
545
struct snd_compr_stream *stream,
546
struct snd_compr_caps *caps)
547
{
548
caps->direction = SND_COMPRESS_PLAYBACK;
549
caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
550
caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
551
caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
552
caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
553
caps->num_codecs = 3;
554
caps->codecs[0] = SND_AUDIOCODEC_MP3;
555
caps->codecs[1] = SND_AUDIOCODEC_AAC;
556
caps->codecs[2] = SND_AUDIOCODEC_FLAC;
557
558
return 0;
559
}
560
561
static int q6apm_dai_compr_get_codec_caps(struct snd_soc_component *component,
562
struct snd_compr_stream *stream,
563
struct snd_compr_codec_caps *codec)
564
{
565
switch (codec->codec) {
566
case SND_AUDIOCODEC_MP3:
567
*codec = q6apm_compr_caps;
568
break;
569
default:
570
break;
571
}
572
573
return 0;
574
}
575
576
static int q6apm_dai_compr_pointer(struct snd_soc_component *component,
577
struct snd_compr_stream *stream,
578
struct snd_compr_tstamp *tstamp)
579
{
580
struct snd_compr_runtime *runtime = stream->runtime;
581
struct q6apm_dai_rtd *prtd = runtime->private_data;
582
unsigned long flags;
583
584
spin_lock_irqsave(&prtd->lock, flags);
585
tstamp->copied_total = prtd->copied_total;
586
tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
587
spin_unlock_irqrestore(&prtd->lock, flags);
588
589
return 0;
590
}
591
592
static int q6apm_dai_compr_trigger(struct snd_soc_component *component,
593
struct snd_compr_stream *stream, int cmd)
594
{
595
struct snd_compr_runtime *runtime = stream->runtime;
596
struct q6apm_dai_rtd *prtd = runtime->private_data;
597
int ret = 0;
598
599
switch (cmd) {
600
case SNDRV_PCM_TRIGGER_START:
601
case SNDRV_PCM_TRIGGER_RESUME:
602
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
603
ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP);
604
break;
605
case SNDRV_PCM_TRIGGER_STOP:
606
break;
607
case SNDRV_PCM_TRIGGER_SUSPEND:
608
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
609
break;
610
case SND_COMPR_TRIGGER_NEXT_TRACK:
611
prtd->next_track = true;
612
break;
613
case SND_COMPR_TRIGGER_DRAIN:
614
case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
615
prtd->notify_on_drain = true;
616
break;
617
default:
618
ret = -EINVAL;
619
break;
620
}
621
622
return ret;
623
}
624
625
static int q6apm_dai_compr_ack(struct snd_soc_component *component, struct snd_compr_stream *stream,
626
size_t count)
627
{
628
struct snd_compr_runtime *runtime = stream->runtime;
629
struct q6apm_dai_rtd *prtd = runtime->private_data;
630
unsigned long flags;
631
632
spin_lock_irqsave(&prtd->lock, flags);
633
prtd->bytes_received += count;
634
spin_unlock_irqrestore(&prtd->lock, flags);
635
636
return count;
637
}
638
639
static int q6apm_dai_compr_set_params(struct snd_soc_component *component,
640
struct snd_compr_stream *stream,
641
struct snd_compr_params *params)
642
{
643
struct snd_compr_runtime *runtime = stream->runtime;
644
struct q6apm_dai_rtd *prtd = runtime->private_data;
645
struct q6apm_dai_data *pdata;
646
struct audioreach_module_config cfg;
647
struct snd_codec *codec = &params->codec;
648
int dir = stream->direction;
649
int ret;
650
651
pdata = snd_soc_component_get_drvdata(component);
652
if (!pdata)
653
return -EINVAL;
654
655
prtd->periods = runtime->fragments;
656
prtd->pcm_count = runtime->fragment_size;
657
prtd->pcm_size = runtime->fragments * runtime->fragment_size;
658
prtd->bits_per_sample = 16;
659
660
if (prtd->next_track != true) {
661
memcpy(&prtd->codec, codec, sizeof(*codec));
662
663
ret = q6apm_set_real_module_id(component->dev, prtd->graph, codec->id);
664
if (ret)
665
return ret;
666
667
cfg.direction = dir;
668
cfg.sample_rate = codec->sample_rate;
669
cfg.num_channels = 2;
670
cfg.bit_width = prtd->bits_per_sample;
671
cfg.fmt = codec->id;
672
audioreach_set_default_channel_mapping(cfg.channel_map,
673
cfg.num_channels);
674
memcpy(&cfg.codec, codec, sizeof(*codec));
675
676
ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);
677
if (ret < 0)
678
return ret;
679
680
ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg);
681
if (ret)
682
return ret;
683
684
ret = q6apm_map_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK,
685
prtd->phys, (prtd->pcm_size / prtd->periods),
686
prtd->periods);
687
if (ret < 0)
688
return -ENOMEM;
689
690
ret = q6apm_graph_prepare(prtd->graph);
691
if (ret)
692
return ret;
693
694
ret = q6apm_graph_start(prtd->graph);
695
if (ret)
696
return ret;
697
698
} else {
699
cfg.direction = dir;
700
cfg.sample_rate = codec->sample_rate;
701
cfg.num_channels = 2;
702
cfg.bit_width = prtd->bits_per_sample;
703
cfg.fmt = codec->id;
704
memcpy(&cfg.codec, codec, sizeof(*codec));
705
706
ret = audioreach_compr_set_param(prtd->graph, &cfg);
707
if (ret < 0)
708
return ret;
709
}
710
prtd->state = Q6APM_STREAM_RUNNING;
711
712
return 0;
713
}
714
715
static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component,
716
struct snd_compr_stream *stream,
717
struct snd_compr_metadata *metadata)
718
{
719
struct snd_compr_runtime *runtime = stream->runtime;
720
struct q6apm_dai_rtd *prtd = runtime->private_data;
721
int ret = 0;
722
723
switch (metadata->key) {
724
case SNDRV_COMPRESS_ENCODER_PADDING:
725
q6apm_remove_trailing_silence(component->dev, prtd->graph,
726
metadata->value[0]);
727
break;
728
case SNDRV_COMPRESS_ENCODER_DELAY:
729
q6apm_remove_initial_silence(component->dev, prtd->graph,
730
metadata->value[0]);
731
break;
732
default:
733
ret = -EINVAL;
734
break;
735
}
736
737
return ret;
738
}
739
740
static int q6apm_dai_compr_mmap(struct snd_soc_component *component,
741
struct snd_compr_stream *stream,
742
struct vm_area_struct *vma)
743
{
744
struct snd_compr_runtime *runtime = stream->runtime;
745
struct q6apm_dai_rtd *prtd = runtime->private_data;
746
struct device *dev = component->dev;
747
748
return dma_mmap_coherent(dev, vma, prtd->dma_buffer.area, prtd->dma_buffer.addr,
749
prtd->dma_buffer.bytes);
750
}
751
752
static int q6apm_compr_copy(struct snd_soc_component *component,
753
struct snd_compr_stream *stream, char __user *buf,
754
size_t count)
755
{
756
struct snd_compr_runtime *runtime = stream->runtime;
757
struct q6apm_dai_rtd *prtd = runtime->private_data;
758
void *dstn;
759
unsigned long flags;
760
size_t copy;
761
u32 wflags = 0;
762
u32 app_pointer;
763
u32 bytes_received;
764
uint32_t bytes_to_write;
765
int avail, bytes_in_flight = 0;
766
767
bytes_received = prtd->bytes_received;
768
769
/**
770
* Make sure that next track data pointer is aligned at 32 bit boundary
771
* This is a Mandatory requirement from DSP data buffers alignment
772
*/
773
if (prtd->next_track)
774
bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
775
776
app_pointer = bytes_received/prtd->pcm_size;
777
app_pointer = bytes_received - (app_pointer * prtd->pcm_size);
778
dstn = prtd->dma_buffer.area + app_pointer;
779
780
if (count < prtd->pcm_size - app_pointer) {
781
if (copy_from_user(dstn, buf, count))
782
return -EFAULT;
783
} else {
784
copy = prtd->pcm_size - app_pointer;
785
if (copy_from_user(dstn, buf, copy))
786
return -EFAULT;
787
if (copy_from_user(prtd->dma_buffer.area, buf + copy, count - copy))
788
return -EFAULT;
789
}
790
791
spin_lock_irqsave(&prtd->lock, flags);
792
bytes_in_flight = prtd->bytes_received - prtd->copied_total;
793
794
if (prtd->next_track) {
795
prtd->next_track = false;
796
prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
797
prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
798
}
799
800
prtd->bytes_received = bytes_received + count;
801
802
/* Kick off the data to dsp if its starving!! */
803
if (prtd->state == Q6APM_STREAM_RUNNING && (bytes_in_flight == 0)) {
804
bytes_to_write = prtd->pcm_count;
805
avail = prtd->bytes_received - prtd->bytes_sent;
806
807
if (avail < prtd->pcm_count)
808
bytes_to_write = avail;
809
810
q6apm_write_async(prtd->graph, bytes_to_write, 0, 0, wflags);
811
prtd->bytes_sent += bytes_to_write;
812
}
813
814
spin_unlock_irqrestore(&prtd->lock, flags);
815
816
return count;
817
}
818
819
static const struct snd_compress_ops q6apm_dai_compress_ops = {
820
.open = q6apm_dai_compr_open,
821
.free = q6apm_dai_compr_free,
822
.get_caps = q6apm_dai_compr_get_caps,
823
.get_codec_caps = q6apm_dai_compr_get_codec_caps,
824
.pointer = q6apm_dai_compr_pointer,
825
.trigger = q6apm_dai_compr_trigger,
826
.ack = q6apm_dai_compr_ack,
827
.set_params = q6apm_dai_compr_set_params,
828
.set_metadata = q6apm_dai_compr_set_metadata,
829
.mmap = q6apm_dai_compr_mmap,
830
.copy = q6apm_compr_copy,
831
};
832
833
static const struct snd_soc_component_driver q6apm_fe_dai_component = {
834
.name = DRV_NAME,
835
.open = q6apm_dai_open,
836
.close = q6apm_dai_close,
837
.prepare = q6apm_dai_prepare,
838
.pcm_construct = q6apm_dai_pcm_new,
839
.hw_params = q6apm_dai_hw_params,
840
.pointer = q6apm_dai_pointer,
841
.trigger = q6apm_dai_trigger,
842
.ack = q6apm_dai_ack,
843
.compress_ops = &q6apm_dai_compress_ops,
844
.use_dai_pcm_id = true,
845
};
846
847
static int q6apm_dai_probe(struct platform_device *pdev)
848
{
849
struct device *dev = &pdev->dev;
850
struct device_node *node = dev->of_node;
851
struct q6apm_dai_data *pdata;
852
struct of_phandle_args args;
853
int rc;
854
855
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
856
if (!pdata)
857
return -ENOMEM;
858
859
rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
860
if (rc < 0)
861
pdata->sid = -1;
862
else
863
pdata->sid = args.args[0] & SID_MASK_DEFAULT;
864
865
dev_set_drvdata(dev, pdata);
866
867
return devm_snd_soc_register_component(dev, &q6apm_fe_dai_component, NULL, 0);
868
}
869
870
#ifdef CONFIG_OF
871
static const struct of_device_id q6apm_dai_device_id[] = {
872
{ .compatible = "qcom,q6apm-dais" },
873
{},
874
};
875
MODULE_DEVICE_TABLE(of, q6apm_dai_device_id);
876
#endif
877
878
static struct platform_driver q6apm_dai_platform_driver = {
879
.driver = {
880
.name = "q6apm-dai",
881
.of_match_table = of_match_ptr(q6apm_dai_device_id),
882
},
883
.probe = q6apm_dai_probe,
884
};
885
module_platform_driver(q6apm_dai_platform_driver);
886
887
MODULE_DESCRIPTION("Q6APM dai driver");
888
MODULE_LICENSE("GPL");
889
890