forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/sound/soc/qcom/qdsp6/q6asm-dai.c
....@@ -8,9 +8,10 @@
88 #include <linux/platform_device.h>
99 #include <linux/slab.h>
1010 #include <sound/soc.h>
11
-#include <sound/soc.h>
1211 #include <sound/soc-dapm.h>
1312 #include <sound/pcm.h>
13
+#include <linux/spinlock.h>
14
+#include <sound/compress_driver.h>
1415 #include <asm/dma.h>
1516 #include <linux/dma-mapping.h>
1617 #include <linux/of_device.h>
....@@ -31,6 +32,15 @@
3132 #define CAPTURE_MIN_PERIOD_SIZE 320
3233 #define SID_MASK_DEFAULT 0xF
3334
35
+/* Default values used if user space does not set */
36
+#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
37
+#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
38
+#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
39
+#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
40
+
41
+#define ALAC_CH_LAYOUT_MONO ((101 << 16) | 1)
42
+#define ALAC_CH_LAYOUT_STEREO ((101 << 16) | 2)
43
+
3444 enum stream_state {
3545 Q6ASM_STREAM_IDLE = 0,
3646 Q6ASM_STREAM_STOPPED,
....@@ -39,24 +49,39 @@
3949
4050 struct q6asm_dai_rtd {
4151 struct snd_pcm_substream *substream;
52
+ struct snd_compr_stream *cstream;
53
+ struct snd_codec codec;
54
+ struct snd_dma_buffer dma_buffer;
55
+ spinlock_t lock;
4256 phys_addr_t phys;
4357 unsigned int pcm_size;
4458 unsigned int pcm_count;
4559 unsigned int pcm_irq_pos; /* IRQ position */
4660 unsigned int periods;
61
+ unsigned int bytes_sent;
62
+ unsigned int bytes_received;
63
+ unsigned int copied_total;
4764 uint16_t bits_per_sample;
4865 uint16_t source; /* Encoding source bit mask */
4966 struct audio_client *audio_client;
67
+ uint32_t next_track_stream_id;
68
+ bool next_track;
69
+ uint32_t stream_id;
5070 uint16_t session_id;
5171 enum stream_state state;
72
+ uint32_t initial_samples_drop;
73
+ uint32_t trailing_samples_drop;
74
+ bool notify_on_drain;
5275 };
5376
5477 struct q6asm_dai_data {
78
+ struct snd_soc_dai_driver *dais;
79
+ int num_dais;
5580 long long int sid;
5681 };
5782
58
-static struct snd_pcm_hardware q6asm_dai_hardware_capture = {
59
- .info = (SNDRV_PCM_INFO_MMAP |
83
+static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
84
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
6085 SNDRV_PCM_INFO_BLOCK_TRANSFER |
6186 SNDRV_PCM_INFO_MMAP_VALID |
6287 SNDRV_PCM_INFO_INTERLEAVED |
....@@ -78,7 +103,7 @@
78103 };
79104
80105 static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
81
- .info = (SNDRV_PCM_INFO_MMAP |
106
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
82107 SNDRV_PCM_INFO_BLOCK_TRANSFER |
83108 SNDRV_PCM_INFO_MMAP_VALID |
84109 SNDRV_PCM_INFO_INTERLEAVED |
....@@ -123,7 +148,6 @@
123148 .rate_max = 48000, \
124149 }, \
125150 .name = "MultiMedia"#num, \
126
- .probe = fe_dai_probe, \
127151 .id = MSM_FRONTEND_DAI_MULTIMEDIA##num, \
128152 }
129153
....@@ -139,8 +163,23 @@
139163 .mask = 0,
140164 };
141165
166
+static const struct snd_compr_codec_caps q6asm_compr_caps = {
167
+ .num_descriptors = 1,
168
+ .descriptor[0].max_ch = 2,
169
+ .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
170
+ 24000, 32000, 44100, 48000, 88200,
171
+ 96000, 176400, 192000 },
172
+ .descriptor[0].num_sample_rates = 13,
173
+ .descriptor[0].bit_rate[0] = 320,
174
+ .descriptor[0].bit_rate[1] = 128,
175
+ .descriptor[0].num_bitrates = 2,
176
+ .descriptor[0].profiles = 0,
177
+ .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
178
+ .descriptor[0].formats = 0,
179
+};
180
+
142181 static void event_handler(uint32_t opcode, uint32_t token,
143
- uint32_t *payload, void *priv)
182
+ void *payload, void *priv)
144183 {
145184 struct q6asm_dai_rtd *prtd = priv;
146185 struct snd_pcm_substream *substream = prtd->substream;
....@@ -148,8 +187,8 @@
148187 switch (opcode) {
149188 case ASM_CLIENT_EVENT_CMD_RUN_DONE:
150189 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
151
- q6asm_write_async(prtd->audio_client,
152
- prtd->pcm_count, 0, 0, NO_TIMESTAMP);
190
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
191
+ prtd->pcm_count, 0, 0, 0);
153192 break;
154193 case ASM_CLIENT_EVENT_CMD_EOS_DONE:
155194 prtd->state = Q6ASM_STREAM_STOPPED;
....@@ -158,8 +197,8 @@
158197 prtd->pcm_irq_pos += prtd->pcm_count;
159198 snd_pcm_period_elapsed(substream);
160199 if (prtd->state == Q6ASM_STREAM_RUNNING)
161
- q6asm_write_async(prtd->audio_client,
162
- prtd->pcm_count, 0, 0, NO_TIMESTAMP);
200
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
201
+ prtd->pcm_count, 0, 0, 0);
163202
164203 break;
165204 }
....@@ -167,7 +206,7 @@
167206 prtd->pcm_irq_pos += prtd->pcm_count;
168207 snd_pcm_period_elapsed(substream);
169208 if (prtd->state == Q6ASM_STREAM_RUNNING)
170
- q6asm_read(prtd->audio_client);
209
+ q6asm_read(prtd->audio_client, prtd->stream_id);
171210
172211 break;
173212 default:
....@@ -175,21 +214,22 @@
175214 }
176215 }
177216
178
-static int q6asm_dai_prepare(struct snd_pcm_substream *substream)
217
+static int q6asm_dai_prepare(struct snd_soc_component *component,
218
+ struct snd_pcm_substream *substream)
179219 {
180220 struct snd_pcm_runtime *runtime = substream->runtime;
181
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
221
+ struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
182222 struct q6asm_dai_rtd *prtd = runtime->private_data;
183
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
184223 struct q6asm_dai_data *pdata;
224
+ struct device *dev = component->dev;
185225 int ret, i;
186226
187
- pdata = snd_soc_component_get_drvdata(c);
227
+ pdata = snd_soc_component_get_drvdata(component);
188228 if (!pdata)
189229 return -EINVAL;
190230
191231 if (!prtd || !prtd->audio_client) {
192
- pr_err("%s: private data null or audio client freed\n",
232
+ dev_err(dev, "%s: private data null or audio client freed\n",
193233 __func__);
194234 return -EINVAL;
195235 }
....@@ -199,7 +239,7 @@
199239 /* rate and channels are sent to audio driver */
200240 if (prtd->state) {
201241 /* clear the previous setup if any */
202
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
242
+ q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
203243 q6asm_unmap_memory_regions(substream->stream,
204244 prtd->audio_client);
205245 q6routing_stream_close(soc_prtd->dai_link->id,
....@@ -212,58 +252,70 @@
212252 prtd->periods);
213253
214254 if (ret < 0) {
215
- pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
255
+ dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n",
216256 ret);
217257 return -ENOMEM;
218258 }
219259
220260 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
221
- ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM,
222
- prtd->bits_per_sample);
261
+ ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
262
+ FORMAT_LINEAR_PCM,
263
+ 0, prtd->bits_per_sample, false);
223264 } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
224
- ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM,
225
- prtd->bits_per_sample);
265
+ ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
266
+ FORMAT_LINEAR_PCM,
267
+ prtd->bits_per_sample);
226268 }
227269
228270 if (ret < 0) {
229
- pr_err("%s: q6asm_open_write failed\n", __func__);
230
- q6asm_audio_client_free(prtd->audio_client);
231
- prtd->audio_client = NULL;
232
- return -ENOMEM;
271
+ dev_err(dev, "%s: q6asm_open_write failed\n", __func__);
272
+ goto open_err;
233273 }
234274
235275 prtd->session_id = q6asm_get_session_id(prtd->audio_client);
236276 ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
237277 prtd->session_id, substream->stream);
238278 if (ret) {
239
- pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
240
- return ret;
279
+ dev_err(dev, "%s: stream reg failed ret:%d\n", __func__, ret);
280
+ goto routing_err;
241281 }
242282
243283 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
244284 ret = q6asm_media_format_block_multi_ch_pcm(
245
- prtd->audio_client, runtime->rate,
246
- runtime->channels, NULL,
285
+ prtd->audio_client, prtd->stream_id,
286
+ runtime->rate, runtime->channels, NULL,
247287 prtd->bits_per_sample);
248288 } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
249289 ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
250
- runtime->rate, runtime->channels,
251
- prtd->bits_per_sample);
290
+ prtd->stream_id,
291
+ runtime->rate,
292
+ runtime->channels,
293
+ prtd->bits_per_sample);
252294
253295 /* Queue the buffers */
254296 for (i = 0; i < runtime->periods; i++)
255
- q6asm_read(prtd->audio_client);
297
+ q6asm_read(prtd->audio_client, prtd->stream_id);
256298
257299 }
258300 if (ret < 0)
259
- pr_info("%s: CMD Format block failed\n", __func__);
301
+ dev_info(dev, "%s: CMD Format block failed\n", __func__);
302
+ else
303
+ prtd->state = Q6ASM_STREAM_RUNNING;
260304
261
- prtd->state = Q6ASM_STREAM_RUNNING;
305
+ return ret;
262306
263
- return 0;
307
+routing_err:
308
+ q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
309
+open_err:
310
+ q6asm_unmap_memory_regions(substream->stream, prtd->audio_client);
311
+ q6asm_audio_client_free(prtd->audio_client);
312
+ prtd->audio_client = NULL;
313
+
314
+ return ret;
264315 }
265316
266
-static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd)
317
+static int q6asm_dai_trigger(struct snd_soc_component *component,
318
+ struct snd_pcm_substream *substream, int cmd)
267319 {
268320 int ret = 0;
269321 struct snd_pcm_runtime *runtime = substream->runtime;
....@@ -273,15 +325,18 @@
273325 case SNDRV_PCM_TRIGGER_START:
274326 case SNDRV_PCM_TRIGGER_RESUME:
275327 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
276
- ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
328
+ ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
329
+ 0, 0, 0);
277330 break;
278331 case SNDRV_PCM_TRIGGER_STOP:
279332 prtd->state = Q6ASM_STREAM_STOPPED;
280
- ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
333
+ ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
334
+ CMD_EOS);
281335 break;
282336 case SNDRV_PCM_TRIGGER_SUSPEND:
283337 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
284
- ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
338
+ ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
339
+ CMD_PAUSE);
285340 break;
286341 default:
287342 ret = -EINVAL;
....@@ -291,23 +346,23 @@
291346 return ret;
292347 }
293348
294
-static int q6asm_dai_open(struct snd_pcm_substream *substream)
349
+static int q6asm_dai_open(struct snd_soc_component *component,
350
+ struct snd_pcm_substream *substream)
295351 {
296352 struct snd_pcm_runtime *runtime = substream->runtime;
297
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
298
- struct snd_soc_dai *cpu_dai = soc_prtd->cpu_dai;
299
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
353
+ struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
354
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_prtd, 0);
300355 struct q6asm_dai_rtd *prtd;
301356 struct q6asm_dai_data *pdata;
302
- struct device *dev = c->dev;
357
+ struct device *dev = component->dev;
303358 int ret = 0;
304359 int stream_id;
305360
306361 stream_id = cpu_dai->driver->id;
307362
308
- pdata = snd_soc_component_get_drvdata(c);
363
+ pdata = snd_soc_component_get_drvdata(component);
309364 if (!pdata) {
310
- pr_err("Drv data not found ..\n");
365
+ dev_err(dev, "Drv data not found ..\n");
311366 return -EINVAL;
312367 }
313368
....@@ -320,11 +375,14 @@
320375 (q6asm_cb)event_handler, prtd, stream_id,
321376 LEGACY_PCM_MODE);
322377 if (IS_ERR(prtd->audio_client)) {
323
- pr_info("%s: Could not allocate memory\n", __func__);
378
+ dev_info(dev, "%s: Could not allocate memory\n", __func__);
324379 ret = PTR_ERR(prtd->audio_client);
325380 kfree(prtd);
326381 return ret;
327382 }
383
+
384
+ /* DSP expects stream id from 1 */
385
+ prtd->stream_id = 1;
328386
329387 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
330388 runtime->hw = q6asm_dai_hardware_playback;
....@@ -335,12 +393,12 @@
335393 SNDRV_PCM_HW_PARAM_RATE,
336394 &constraints_sample_rates);
337395 if (ret < 0)
338
- pr_info("snd_pcm_hw_constraint_list failed\n");
396
+ dev_info(dev, "snd_pcm_hw_constraint_list failed\n");
339397 /* Ensure that buffer size is a multiple of period size */
340398 ret = snd_pcm_hw_constraint_integer(runtime,
341399 SNDRV_PCM_HW_PARAM_PERIODS);
342400 if (ret < 0)
343
- pr_info("snd_pcm_hw_constraint_integer failed\n");
401
+ dev_info(dev, "snd_pcm_hw_constraint_integer failed\n");
344402
345403 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
346404 ret = snd_pcm_hw_constraint_minmax(runtime,
....@@ -348,21 +406,21 @@
348406 PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
349407 PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
350408 if (ret < 0) {
351
- pr_err("constraint for buffer bytes min max ret = %d\n",
352
- ret);
409
+ dev_err(dev, "constraint for buffer bytes min max ret = %d\n",
410
+ ret);
353411 }
354412 }
355413
356414 ret = snd_pcm_hw_constraint_step(runtime, 0,
357415 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
358416 if (ret < 0) {
359
- pr_err("constraint for period bytes step ret = %d\n",
417
+ dev_err(dev, "constraint for period bytes step ret = %d\n",
360418 ret);
361419 }
362420 ret = snd_pcm_hw_constraint_step(runtime, 0,
363421 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
364422 if (ret < 0) {
365
- pr_err("constraint for buffer bytes step ret = %d\n",
423
+ dev_err(dev, "constraint for buffer bytes step ret = %d\n",
366424 ret);
367425 }
368426
....@@ -383,15 +441,17 @@
383441 return 0;
384442 }
385443
386
-static int q6asm_dai_close(struct snd_pcm_substream *substream)
444
+static int q6asm_dai_close(struct snd_soc_component *component,
445
+ struct snd_pcm_substream *substream)
387446 {
388447 struct snd_pcm_runtime *runtime = substream->runtime;
389
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
448
+ struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
390449 struct q6asm_dai_rtd *prtd = runtime->private_data;
391450
392451 if (prtd->audio_client) {
393452 if (prtd->state)
394
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
453
+ q6asm_cmd(prtd->audio_client, prtd->stream_id,
454
+ CMD_CLOSE);
395455
396456 q6asm_unmap_memory_regions(substream->stream,
397457 prtd->audio_client);
....@@ -404,7 +464,8 @@
404464 return 0;
405465 }
406466
407
-static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream)
467
+static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component,
468
+ struct snd_pcm_substream *substream)
408469 {
409470
410471 struct snd_pcm_runtime *runtime = substream->runtime;
....@@ -416,22 +477,21 @@
416477 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
417478 }
418479
419
-static int q6asm_dai_mmap(struct snd_pcm_substream *substream,
420
- struct vm_area_struct *vma)
480
+static int q6asm_dai_mmap(struct snd_soc_component *component,
481
+ struct snd_pcm_substream *substream,
482
+ struct vm_area_struct *vma)
421483 {
422
-
423484 struct snd_pcm_runtime *runtime = substream->runtime;
424
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
425
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
426
- struct device *dev = c->dev;
485
+ struct device *dev = component->dev;
427486
428487 return dma_mmap_coherent(dev, vma,
429488 runtime->dma_area, runtime->dma_addr,
430489 runtime->dma_bytes);
431490 }
432491
433
-static int q6asm_dai_hw_params(struct snd_pcm_substream *substream,
434
- struct snd_pcm_hw_params *params)
492
+static int q6asm_dai_hw_params(struct snd_soc_component *component,
493
+ struct snd_pcm_substream *substream,
494
+ struct snd_pcm_hw_params *params)
435495 {
436496 struct snd_pcm_runtime *runtime = substream->runtime;
437497 struct q6asm_dai_rtd *prtd = runtime->private_data;
....@@ -451,26 +511,693 @@
451511 return 0;
452512 }
453513
454
-static struct snd_pcm_ops q6asm_dai_ops = {
455
- .open = q6asm_dai_open,
456
- .hw_params = q6asm_dai_hw_params,
457
- .close = q6asm_dai_close,
458
- .ioctl = snd_pcm_lib_ioctl,
459
- .prepare = q6asm_dai_prepare,
460
- .trigger = q6asm_dai_trigger,
461
- .pointer = q6asm_dai_pointer,
462
- .mmap = q6asm_dai_mmap,
514
+static void compress_event_handler(uint32_t opcode, uint32_t token,
515
+ void *payload, void *priv)
516
+{
517
+ struct q6asm_dai_rtd *prtd = priv;
518
+ struct snd_compr_stream *substream = prtd->cstream;
519
+ unsigned long flags;
520
+ u32 wflags = 0;
521
+ uint64_t avail;
522
+ uint32_t bytes_written, bytes_to_write;
523
+ bool is_last_buffer = false;
524
+
525
+ switch (opcode) {
526
+ case ASM_CLIENT_EVENT_CMD_RUN_DONE:
527
+ spin_lock_irqsave(&prtd->lock, flags);
528
+ if (!prtd->bytes_sent) {
529
+ q6asm_stream_remove_initial_silence(prtd->audio_client,
530
+ prtd->stream_id,
531
+ prtd->initial_samples_drop);
532
+
533
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
534
+ prtd->pcm_count, 0, 0, 0);
535
+ prtd->bytes_sent += prtd->pcm_count;
536
+ }
537
+
538
+ spin_unlock_irqrestore(&prtd->lock, flags);
539
+ break;
540
+
541
+ case ASM_CLIENT_EVENT_CMD_EOS_DONE:
542
+ spin_lock_irqsave(&prtd->lock, flags);
543
+ if (prtd->notify_on_drain) {
544
+ if (substream->partial_drain) {
545
+ /*
546
+ * Close old stream and make it stale, switch
547
+ * the active stream now!
548
+ */
549
+ q6asm_cmd_nowait(prtd->audio_client,
550
+ prtd->stream_id,
551
+ CMD_CLOSE);
552
+ /*
553
+ * vaild stream ids start from 1, So we are
554
+ * toggling this between 1 and 2.
555
+ */
556
+ prtd->stream_id = (prtd->stream_id == 1 ? 2 : 1);
557
+ }
558
+
559
+ snd_compr_drain_notify(prtd->cstream);
560
+ prtd->notify_on_drain = false;
561
+
562
+ } else {
563
+ prtd->state = Q6ASM_STREAM_STOPPED;
564
+ }
565
+ spin_unlock_irqrestore(&prtd->lock, flags);
566
+ break;
567
+
568
+ case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
569
+ spin_lock_irqsave(&prtd->lock, flags);
570
+
571
+ bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
572
+ prtd->copied_total += bytes_written;
573
+ snd_compr_fragment_elapsed(substream);
574
+
575
+ if (prtd->state != Q6ASM_STREAM_RUNNING) {
576
+ spin_unlock_irqrestore(&prtd->lock, flags);
577
+ break;
578
+ }
579
+
580
+ avail = prtd->bytes_received - prtd->bytes_sent;
581
+ if (avail > prtd->pcm_count) {
582
+ bytes_to_write = prtd->pcm_count;
583
+ } else {
584
+ if (substream->partial_drain || prtd->notify_on_drain)
585
+ is_last_buffer = true;
586
+ bytes_to_write = avail;
587
+ }
588
+
589
+ if (bytes_to_write) {
590
+ if (substream->partial_drain && is_last_buffer) {
591
+ wflags |= ASM_LAST_BUFFER_FLAG;
592
+ q6asm_stream_remove_trailing_silence(prtd->audio_client,
593
+ prtd->stream_id,
594
+ prtd->trailing_samples_drop);
595
+ }
596
+
597
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
598
+ bytes_to_write, 0, 0, wflags);
599
+
600
+ prtd->bytes_sent += bytes_to_write;
601
+ }
602
+
603
+ if (prtd->notify_on_drain && is_last_buffer)
604
+ q6asm_cmd_nowait(prtd->audio_client,
605
+ prtd->stream_id, CMD_EOS);
606
+
607
+ spin_unlock_irqrestore(&prtd->lock, flags);
608
+ break;
609
+
610
+ default:
611
+ break;
612
+ }
613
+}
614
+
615
+static int q6asm_dai_compr_open(struct snd_soc_component *component,
616
+ struct snd_compr_stream *stream)
617
+{
618
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
619
+ struct snd_compr_runtime *runtime = stream->runtime;
620
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
621
+ struct q6asm_dai_data *pdata;
622
+ struct device *dev = component->dev;
623
+ struct q6asm_dai_rtd *prtd;
624
+ int stream_id, size, ret;
625
+
626
+ stream_id = cpu_dai->driver->id;
627
+ pdata = snd_soc_component_get_drvdata(component);
628
+ if (!pdata) {
629
+ dev_err(dev, "Drv data not found ..\n");
630
+ return -EINVAL;
631
+ }
632
+
633
+ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
634
+ if (!prtd)
635
+ return -ENOMEM;
636
+
637
+ /* DSP expects stream id from 1 */
638
+ prtd->stream_id = 1;
639
+
640
+ prtd->cstream = stream;
641
+ prtd->audio_client = q6asm_audio_client_alloc(dev,
642
+ (q6asm_cb)compress_event_handler,
643
+ prtd, stream_id, LEGACY_PCM_MODE);
644
+ if (IS_ERR(prtd->audio_client)) {
645
+ dev_err(dev, "Could not allocate memory\n");
646
+ ret = PTR_ERR(prtd->audio_client);
647
+ goto free_prtd;
648
+ }
649
+
650
+ size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
651
+ COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
652
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
653
+ &prtd->dma_buffer);
654
+ if (ret) {
655
+ dev_err(dev, "Cannot allocate buffer(s)\n");
656
+ goto free_client;
657
+ }
658
+
659
+ if (pdata->sid < 0)
660
+ prtd->phys = prtd->dma_buffer.addr;
661
+ else
662
+ prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
663
+
664
+ snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
665
+ spin_lock_init(&prtd->lock);
666
+ runtime->private_data = prtd;
667
+
668
+ return 0;
669
+
670
+free_client:
671
+ q6asm_audio_client_free(prtd->audio_client);
672
+free_prtd:
673
+ kfree(prtd);
674
+
675
+ return ret;
676
+}
677
+
678
+static int q6asm_dai_compr_free(struct snd_soc_component *component,
679
+ struct snd_compr_stream *stream)
680
+{
681
+ struct snd_compr_runtime *runtime = stream->runtime;
682
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
683
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
684
+
685
+ if (prtd->audio_client) {
686
+ if (prtd->state) {
687
+ q6asm_cmd(prtd->audio_client, prtd->stream_id,
688
+ CMD_CLOSE);
689
+ if (prtd->next_track_stream_id) {
690
+ q6asm_cmd(prtd->audio_client,
691
+ prtd->next_track_stream_id,
692
+ CMD_CLOSE);
693
+ }
694
+ }
695
+
696
+ snd_dma_free_pages(&prtd->dma_buffer);
697
+ q6asm_unmap_memory_regions(stream->direction,
698
+ prtd->audio_client);
699
+ q6asm_audio_client_free(prtd->audio_client);
700
+ prtd->audio_client = NULL;
701
+ }
702
+ q6routing_stream_close(rtd->dai_link->id, stream->direction);
703
+ kfree(prtd);
704
+
705
+ return 0;
706
+}
707
+
708
+static int __q6asm_dai_compr_set_codec_params(struct snd_soc_component *component,
709
+ struct snd_compr_stream *stream,
710
+ struct snd_codec *codec,
711
+ int stream_id)
712
+{
713
+ struct snd_compr_runtime *runtime = stream->runtime;
714
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
715
+ struct q6asm_flac_cfg flac_cfg;
716
+ struct q6asm_wma_cfg wma_cfg;
717
+ struct q6asm_alac_cfg alac_cfg;
718
+ struct q6asm_ape_cfg ape_cfg;
719
+ unsigned int wma_v9 = 0;
720
+ struct device *dev = component->dev;
721
+ int ret;
722
+ union snd_codec_options *codec_options;
723
+ struct snd_dec_flac *flac;
724
+ struct snd_dec_wma *wma;
725
+ struct snd_dec_alac *alac;
726
+ struct snd_dec_ape *ape;
727
+
728
+ codec_options = &(prtd->codec.options);
729
+
730
+ memcpy(&prtd->codec, codec, sizeof(*codec));
731
+
732
+ switch (codec->id) {
733
+ case SND_AUDIOCODEC_FLAC:
734
+
735
+ memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg));
736
+ flac = &codec_options->flac_d;
737
+
738
+ flac_cfg.ch_cfg = codec->ch_in;
739
+ flac_cfg.sample_rate = codec->sample_rate;
740
+ flac_cfg.stream_info_present = 1;
741
+ flac_cfg.sample_size = flac->sample_size;
742
+ flac_cfg.min_blk_size = flac->min_blk_size;
743
+ flac_cfg.max_blk_size = flac->max_blk_size;
744
+ flac_cfg.max_frame_size = flac->max_frame_size;
745
+ flac_cfg.min_frame_size = flac->min_frame_size;
746
+
747
+ ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
748
+ stream_id,
749
+ &flac_cfg);
750
+ if (ret < 0) {
751
+ dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
752
+ return -EIO;
753
+ }
754
+ break;
755
+
756
+ case SND_AUDIOCODEC_WMA:
757
+ wma = &codec_options->wma_d;
758
+
759
+ memset(&wma_cfg, 0x0, sizeof(struct q6asm_wma_cfg));
760
+
761
+ wma_cfg.sample_rate = codec->sample_rate;
762
+ wma_cfg.num_channels = codec->ch_in;
763
+ wma_cfg.bytes_per_sec = codec->bit_rate / 8;
764
+ wma_cfg.block_align = codec->align;
765
+ wma_cfg.bits_per_sample = prtd->bits_per_sample;
766
+ wma_cfg.enc_options = wma->encoder_option;
767
+ wma_cfg.adv_enc_options = wma->adv_encoder_option;
768
+ wma_cfg.adv_enc_options2 = wma->adv_encoder_option2;
769
+
770
+ if (wma_cfg.num_channels == 1)
771
+ wma_cfg.channel_mask = 4; /* Mono Center */
772
+ else if (wma_cfg.num_channels == 2)
773
+ wma_cfg.channel_mask = 3; /* Stereo FL/FR */
774
+ else
775
+ return -EINVAL;
776
+
777
+ /* check the codec profile */
778
+ switch (codec->profile) {
779
+ case SND_AUDIOPROFILE_WMA9:
780
+ wma_cfg.fmtag = 0x161;
781
+ wma_v9 = 1;
782
+ break;
783
+
784
+ case SND_AUDIOPROFILE_WMA10:
785
+ wma_cfg.fmtag = 0x166;
786
+ break;
787
+
788
+ case SND_AUDIOPROFILE_WMA9_PRO:
789
+ wma_cfg.fmtag = 0x162;
790
+ break;
791
+
792
+ case SND_AUDIOPROFILE_WMA9_LOSSLESS:
793
+ wma_cfg.fmtag = 0x163;
794
+ break;
795
+
796
+ case SND_AUDIOPROFILE_WMA10_LOSSLESS:
797
+ wma_cfg.fmtag = 0x167;
798
+ break;
799
+
800
+ default:
801
+ dev_err(dev, "Unknown WMA profile:%x\n",
802
+ codec->profile);
803
+ return -EIO;
804
+ }
805
+
806
+ if (wma_v9)
807
+ ret = q6asm_stream_media_format_block_wma_v9(
808
+ prtd->audio_client, stream_id,
809
+ &wma_cfg);
810
+ else
811
+ ret = q6asm_stream_media_format_block_wma_v10(
812
+ prtd->audio_client, stream_id,
813
+ &wma_cfg);
814
+ if (ret < 0) {
815
+ dev_err(dev, "WMA9 CMD failed:%d\n", ret);
816
+ return -EIO;
817
+ }
818
+ break;
819
+
820
+ case SND_AUDIOCODEC_ALAC:
821
+ memset(&alac_cfg, 0x0, sizeof(alac_cfg));
822
+ alac = &codec_options->alac_d;
823
+
824
+ alac_cfg.sample_rate = codec->sample_rate;
825
+ alac_cfg.avg_bit_rate = codec->bit_rate;
826
+ alac_cfg.bit_depth = prtd->bits_per_sample;
827
+ alac_cfg.num_channels = codec->ch_in;
828
+
829
+ alac_cfg.frame_length = alac->frame_length;
830
+ alac_cfg.pb = alac->pb;
831
+ alac_cfg.mb = alac->mb;
832
+ alac_cfg.kb = alac->kb;
833
+ alac_cfg.max_run = alac->max_run;
834
+ alac_cfg.compatible_version = alac->compatible_version;
835
+ alac_cfg.max_frame_bytes = alac->max_frame_bytes;
836
+
837
+ switch (codec->ch_in) {
838
+ case 1:
839
+ alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_MONO;
840
+ break;
841
+ case 2:
842
+ alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_STEREO;
843
+ break;
844
+ }
845
+ ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
846
+ stream_id,
847
+ &alac_cfg);
848
+ if (ret < 0) {
849
+ dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
850
+ return -EIO;
851
+ }
852
+ break;
853
+
854
+ case SND_AUDIOCODEC_APE:
855
+ memset(&ape_cfg, 0x0, sizeof(ape_cfg));
856
+ ape = &codec_options->ape_d;
857
+
858
+ ape_cfg.sample_rate = codec->sample_rate;
859
+ ape_cfg.num_channels = codec->ch_in;
860
+ ape_cfg.bits_per_sample = prtd->bits_per_sample;
861
+
862
+ ape_cfg.compatible_version = ape->compatible_version;
863
+ ape_cfg.compression_level = ape->compression_level;
864
+ ape_cfg.format_flags = ape->format_flags;
865
+ ape_cfg.blocks_per_frame = ape->blocks_per_frame;
866
+ ape_cfg.final_frame_blocks = ape->final_frame_blocks;
867
+ ape_cfg.total_frames = ape->total_frames;
868
+ ape_cfg.seek_table_present = ape->seek_table_present;
869
+
870
+ ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
871
+ stream_id,
872
+ &ape_cfg);
873
+ if (ret < 0) {
874
+ dev_err(dev, "APE CMD Format block failed:%d\n", ret);
875
+ return -EIO;
876
+ }
877
+ break;
878
+
879
+ default:
880
+ break;
881
+ }
882
+
883
+ return 0;
884
+}
885
+
886
+static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
887
+ struct snd_compr_stream *stream,
888
+ struct snd_compr_params *params)
889
+{
890
+ struct snd_compr_runtime *runtime = stream->runtime;
891
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
892
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
893
+ int dir = stream->direction;
894
+ struct q6asm_dai_data *pdata;
895
+ struct device *dev = component->dev;
896
+ int ret;
897
+
898
+ pdata = snd_soc_component_get_drvdata(component);
899
+ if (!pdata)
900
+ return -EINVAL;
901
+
902
+ if (!prtd || !prtd->audio_client) {
903
+ dev_err(dev, "private data null or audio client freed\n");
904
+ return -EINVAL;
905
+ }
906
+
907
+ prtd->periods = runtime->fragments;
908
+ prtd->pcm_count = runtime->fragment_size;
909
+ prtd->pcm_size = runtime->fragments * runtime->fragment_size;
910
+ prtd->bits_per_sample = 16;
911
+
912
+ if (dir == SND_COMPRESS_PLAYBACK) {
913
+ ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id,
914
+ params->codec.profile, prtd->bits_per_sample,
915
+ true);
916
+
917
+ if (ret < 0) {
918
+ dev_err(dev, "q6asm_open_write failed\n");
919
+ q6asm_audio_client_free(prtd->audio_client);
920
+ prtd->audio_client = NULL;
921
+ return ret;
922
+ }
923
+ }
924
+
925
+ prtd->session_id = q6asm_get_session_id(prtd->audio_client);
926
+ ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
927
+ prtd->session_id, dir);
928
+ if (ret) {
929
+ dev_err(dev, "Stream reg failed ret:%d\n", ret);
930
+ return ret;
931
+ }
932
+
933
+ ret = __q6asm_dai_compr_set_codec_params(component, stream,
934
+ &params->codec,
935
+ prtd->stream_id);
936
+ if (ret) {
937
+ dev_err(dev, "codec param setup failed ret:%d\n", ret);
938
+ return ret;
939
+ }
940
+
941
+ ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
942
+ (prtd->pcm_size / prtd->periods),
943
+ prtd->periods);
944
+
945
+ if (ret < 0) {
946
+ dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
947
+ return -ENOMEM;
948
+ }
949
+
950
+ prtd->state = Q6ASM_STREAM_RUNNING;
951
+
952
+ return 0;
953
+}
954
+
955
+static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
956
+ struct snd_compr_stream *stream,
957
+ struct snd_compr_metadata *metadata)
958
+{
959
+ struct snd_compr_runtime *runtime = stream->runtime;
960
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
961
+ int ret = 0;
962
+
963
+ switch (metadata->key) {
964
+ case SNDRV_COMPRESS_ENCODER_PADDING:
965
+ prtd->trailing_samples_drop = metadata->value[0];
966
+ break;
967
+ case SNDRV_COMPRESS_ENCODER_DELAY:
968
+ prtd->initial_samples_drop = metadata->value[0];
969
+ if (prtd->next_track_stream_id) {
970
+ ret = q6asm_open_write(prtd->audio_client,
971
+ prtd->next_track_stream_id,
972
+ prtd->codec.id,
973
+ prtd->codec.profile,
974
+ prtd->bits_per_sample,
975
+ true);
976
+ if (ret < 0) {
977
+ dev_err(component->dev, "q6asm_open_write failed\n");
978
+ return ret;
979
+ }
980
+ ret = __q6asm_dai_compr_set_codec_params(component, stream,
981
+ &prtd->codec,
982
+ prtd->next_track_stream_id);
983
+ if (ret < 0) {
984
+ dev_err(component->dev, "q6asm_open_write failed\n");
985
+ return ret;
986
+ }
987
+
988
+ ret = q6asm_stream_remove_initial_silence(prtd->audio_client,
989
+ prtd->next_track_stream_id,
990
+ prtd->initial_samples_drop);
991
+ prtd->next_track_stream_id = 0;
992
+
993
+ }
994
+
995
+ break;
996
+ default:
997
+ ret = -EINVAL;
998
+ break;
999
+ }
1000
+
1001
+ return ret;
1002
+}
1003
+
1004
+static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
1005
+ struct snd_compr_stream *stream, int cmd)
1006
+{
1007
+ struct snd_compr_runtime *runtime = stream->runtime;
1008
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
1009
+ int ret = 0;
1010
+
1011
+ switch (cmd) {
1012
+ case SNDRV_PCM_TRIGGER_START:
1013
+ case SNDRV_PCM_TRIGGER_RESUME:
1014
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1015
+ ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
1016
+ 0, 0, 0);
1017
+ break;
1018
+ case SNDRV_PCM_TRIGGER_STOP:
1019
+ prtd->state = Q6ASM_STREAM_STOPPED;
1020
+ ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
1021
+ CMD_EOS);
1022
+ break;
1023
+ case SNDRV_PCM_TRIGGER_SUSPEND:
1024
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1025
+ ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
1026
+ CMD_PAUSE);
1027
+ break;
1028
+ case SND_COMPR_TRIGGER_NEXT_TRACK:
1029
+ prtd->next_track = true;
1030
+ prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1);
1031
+ break;
1032
+ case SND_COMPR_TRIGGER_DRAIN:
1033
+ case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
1034
+ prtd->notify_on_drain = true;
1035
+ break;
1036
+ default:
1037
+ ret = -EINVAL;
1038
+ break;
1039
+ }
1040
+
1041
+ return ret;
1042
+}
1043
+
1044
+static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
1045
+ struct snd_compr_stream *stream,
1046
+ struct snd_compr_tstamp *tstamp)
1047
+{
1048
+ struct snd_compr_runtime *runtime = stream->runtime;
1049
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
1050
+ unsigned long flags;
1051
+
1052
+ spin_lock_irqsave(&prtd->lock, flags);
1053
+
1054
+ tstamp->copied_total = prtd->copied_total;
1055
+ tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
1056
+
1057
+ spin_unlock_irqrestore(&prtd->lock, flags);
1058
+
1059
+ return 0;
1060
+}
1061
+
1062
+static int q6asm_compr_copy(struct snd_soc_component *component,
1063
+ struct snd_compr_stream *stream, char __user *buf,
1064
+ size_t count)
1065
+{
1066
+ struct snd_compr_runtime *runtime = stream->runtime;
1067
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
1068
+ unsigned long flags;
1069
+ u32 wflags = 0;
1070
+ int avail, bytes_in_flight = 0;
1071
+ void *dstn;
1072
+ size_t copy;
1073
+ u32 app_pointer;
1074
+ u32 bytes_received;
1075
+
1076
+ bytes_received = prtd->bytes_received;
1077
+
1078
+ /**
1079
+ * Make sure that next track data pointer is aligned at 32 bit boundary
1080
+ * This is a Mandatory requirement from DSP data buffers alignment
1081
+ */
1082
+ if (prtd->next_track)
1083
+ bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
1084
+
1085
+ app_pointer = bytes_received/prtd->pcm_size;
1086
+ app_pointer = bytes_received - (app_pointer * prtd->pcm_size);
1087
+ dstn = prtd->dma_buffer.area + app_pointer;
1088
+
1089
+ if (count < prtd->pcm_size - app_pointer) {
1090
+ if (copy_from_user(dstn, buf, count))
1091
+ return -EFAULT;
1092
+ } else {
1093
+ copy = prtd->pcm_size - app_pointer;
1094
+ if (copy_from_user(dstn, buf, copy))
1095
+ return -EFAULT;
1096
+ if (copy_from_user(prtd->dma_buffer.area, buf + copy,
1097
+ count - copy))
1098
+ return -EFAULT;
1099
+ }
1100
+
1101
+ spin_lock_irqsave(&prtd->lock, flags);
1102
+
1103
+ bytes_in_flight = prtd->bytes_received - prtd->copied_total;
1104
+
1105
+ if (prtd->next_track) {
1106
+ prtd->next_track = false;
1107
+ prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
1108
+ prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
1109
+ }
1110
+
1111
+ prtd->bytes_received = bytes_received + count;
1112
+
1113
+ /* Kick off the data to dsp if its starving!! */
1114
+ if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
1115
+ uint32_t bytes_to_write = prtd->pcm_count;
1116
+
1117
+ avail = prtd->bytes_received - prtd->bytes_sent;
1118
+
1119
+ if (avail < prtd->pcm_count)
1120
+ bytes_to_write = avail;
1121
+
1122
+ q6asm_write_async(prtd->audio_client, prtd->stream_id,
1123
+ bytes_to_write, 0, 0, wflags);
1124
+ prtd->bytes_sent += bytes_to_write;
1125
+ }
1126
+
1127
+ spin_unlock_irqrestore(&prtd->lock, flags);
1128
+
1129
+ return count;
1130
+}
1131
+
1132
+static int q6asm_dai_compr_mmap(struct snd_soc_component *component,
1133
+ struct snd_compr_stream *stream,
1134
+ struct vm_area_struct *vma)
1135
+{
1136
+ struct snd_compr_runtime *runtime = stream->runtime;
1137
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
1138
+ struct device *dev = component->dev;
1139
+
1140
+ return dma_mmap_coherent(dev, vma,
1141
+ prtd->dma_buffer.area, prtd->dma_buffer.addr,
1142
+ prtd->dma_buffer.bytes);
1143
+}
1144
+
1145
+static int q6asm_dai_compr_get_caps(struct snd_soc_component *component,
1146
+ struct snd_compr_stream *stream,
1147
+ struct snd_compr_caps *caps)
1148
+{
1149
+ caps->direction = SND_COMPRESS_PLAYBACK;
1150
+ caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
1151
+ caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
1152
+ caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
1153
+ caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
1154
+ caps->num_codecs = 5;
1155
+ caps->codecs[0] = SND_AUDIOCODEC_MP3;
1156
+ caps->codecs[1] = SND_AUDIOCODEC_FLAC;
1157
+ caps->codecs[2] = SND_AUDIOCODEC_WMA;
1158
+ caps->codecs[3] = SND_AUDIOCODEC_ALAC;
1159
+ caps->codecs[4] = SND_AUDIOCODEC_APE;
1160
+
1161
+ return 0;
1162
+}
1163
+
1164
+static int q6asm_dai_compr_get_codec_caps(struct snd_soc_component *component,
1165
+ struct snd_compr_stream *stream,
1166
+ struct snd_compr_codec_caps *codec)
1167
+{
1168
+ switch (codec->codec) {
1169
+ case SND_AUDIOCODEC_MP3:
1170
+ *codec = q6asm_compr_caps;
1171
+ break;
1172
+ default:
1173
+ break;
1174
+ }
1175
+
1176
+ return 0;
1177
+}
1178
+
1179
+static struct snd_compress_ops q6asm_dai_compress_ops = {
1180
+ .open = q6asm_dai_compr_open,
1181
+ .free = q6asm_dai_compr_free,
1182
+ .set_params = q6asm_dai_compr_set_params,
1183
+ .set_metadata = q6asm_dai_compr_set_metadata,
1184
+ .pointer = q6asm_dai_compr_pointer,
1185
+ .trigger = q6asm_dai_compr_trigger,
1186
+ .get_caps = q6asm_dai_compr_get_caps,
1187
+ .get_codec_caps = q6asm_dai_compr_get_codec_caps,
1188
+ .mmap = q6asm_dai_compr_mmap,
1189
+ .copy = q6asm_compr_copy,
4631190 };
4641191
465
-static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
1192
+static int q6asm_dai_pcm_new(struct snd_soc_component *component,
1193
+ struct snd_soc_pcm_runtime *rtd)
4661194 {
4671195 struct snd_pcm_substream *psubstream, *csubstream;
468
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
4691196 struct snd_pcm *pcm = rtd->pcm;
4701197 struct device *dev;
4711198 int size, ret;
4721199
473
- dev = c->dev;
1200
+ dev = component->dev;
4741201 size = q6asm_dai_hardware_playback.buffer_bytes_max;
4751202 psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
4761203 if (psubstream) {
....@@ -494,10 +1221,11 @@
4941221 }
4951222 }
4961223
497
- return ret;
1224
+ return 0;
4981225 }
4991226
500
-static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
1227
+static void q6asm_dai_pcm_free(struct snd_soc_component *component,
1228
+ struct snd_pcm *pcm)
5011229 {
5021230 struct snd_pcm_substream *substream;
5031231 int i;
....@@ -512,47 +1240,42 @@
5121240 }
5131241 }
5141242
515
-static const struct snd_soc_dapm_route afe_pcm_routes[] = {
516
- {"MM_DL1", NULL, "MultiMedia1 Playback" },
517
- {"MM_DL2", NULL, "MultiMedia2 Playback" },
518
- {"MM_DL3", NULL, "MultiMedia3 Playback" },
519
- {"MM_DL4", NULL, "MultiMedia4 Playback" },
520
- {"MM_DL5", NULL, "MultiMedia5 Playback" },
521
- {"MM_DL6", NULL, "MultiMedia6 Playback" },
522
- {"MM_DL7", NULL, "MultiMedia7 Playback" },
523
- {"MM_DL7", NULL, "MultiMedia8 Playback" },
524
- {"MultiMedia1 Capture", NULL, "MM_UL1"},
525
- {"MultiMedia2 Capture", NULL, "MM_UL2"},
526
- {"MultiMedia3 Capture", NULL, "MM_UL3"},
527
- {"MultiMedia4 Capture", NULL, "MM_UL4"},
528
- {"MultiMedia5 Capture", NULL, "MM_UL5"},
529
- {"MultiMedia6 Capture", NULL, "MM_UL6"},
530
- {"MultiMedia7 Capture", NULL, "MM_UL7"},
531
- {"MultiMedia8 Capture", NULL, "MM_UL8"},
532
-
1243
+static const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
1244
+ SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, SND_SOC_NOPM, 0, 0),
1245
+ SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, SND_SOC_NOPM, 0, 0),
1246
+ SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, SND_SOC_NOPM, 0, 0),
1247
+ SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, SND_SOC_NOPM, 0, 0),
1248
+ SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, SND_SOC_NOPM, 0, 0),
1249
+ SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, SND_SOC_NOPM, 0, 0),
1250
+ SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, SND_SOC_NOPM, 0, 0),
1251
+ SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, SND_SOC_NOPM, 0, 0),
1252
+ SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, SND_SOC_NOPM, 0, 0),
1253
+ SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, SND_SOC_NOPM, 0, 0),
1254
+ SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, SND_SOC_NOPM, 0, 0),
1255
+ SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, SND_SOC_NOPM, 0, 0),
1256
+ SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, SND_SOC_NOPM, 0, 0),
1257
+ SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, SND_SOC_NOPM, 0, 0),
1258
+ SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, SND_SOC_NOPM, 0, 0),
1259
+ SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, SND_SOC_NOPM, 0, 0),
5331260 };
534
-
535
-static int fe_dai_probe(struct snd_soc_dai *dai)
536
-{
537
- struct snd_soc_dapm_context *dapm;
538
-
539
- dapm = snd_soc_component_get_dapm(dai->component);
540
- snd_soc_dapm_add_routes(dapm, afe_pcm_routes,
541
- ARRAY_SIZE(afe_pcm_routes));
542
-
543
- return 0;
544
-}
545
-
5461261
5471262 static const struct snd_soc_component_driver q6asm_fe_dai_component = {
5481263 .name = DRV_NAME,
549
- .ops = &q6asm_dai_ops,
550
- .pcm_new = q6asm_dai_pcm_new,
551
- .pcm_free = q6asm_dai_pcm_free,
552
-
1264
+ .open = q6asm_dai_open,
1265
+ .hw_params = q6asm_dai_hw_params,
1266
+ .close = q6asm_dai_close,
1267
+ .prepare = q6asm_dai_prepare,
1268
+ .trigger = q6asm_dai_trigger,
1269
+ .pointer = q6asm_dai_pointer,
1270
+ .mmap = q6asm_dai_mmap,
1271
+ .pcm_construct = q6asm_dai_pcm_new,
1272
+ .pcm_destruct = q6asm_dai_pcm_free,
1273
+ .compress_ops = &q6asm_dai_compress_ops,
1274
+ .dapm_widgets = q6asm_dapm_widgets,
1275
+ .num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
5531276 };
5541277
555
-static struct snd_soc_dai_driver q6asm_fe_dais[] = {
1278
+static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
5561279 Q6ASM_FEDAI_DRIVER(1),
5571280 Q6ASM_FEDAI_DRIVER(2),
5581281 Q6ASM_FEDAI_DRIVER(3),
....@@ -562,6 +1285,54 @@
5621285 Q6ASM_FEDAI_DRIVER(7),
5631286 Q6ASM_FEDAI_DRIVER(8),
5641287 };
1288
+
1289
+static int of_q6asm_parse_dai_data(struct device *dev,
1290
+ struct q6asm_dai_data *pdata)
1291
+{
1292
+ struct snd_soc_dai_driver *dai_drv;
1293
+ struct snd_soc_pcm_stream empty_stream;
1294
+ struct device_node *node;
1295
+ int ret, id, dir, idx = 0;
1296
+
1297
+
1298
+ pdata->num_dais = of_get_child_count(dev->of_node);
1299
+ if (!pdata->num_dais) {
1300
+ dev_err(dev, "No dais found in DT\n");
1301
+ return -EINVAL;
1302
+ }
1303
+
1304
+ pdata->dais = devm_kcalloc(dev, pdata->num_dais, sizeof(*dai_drv),
1305
+ GFP_KERNEL);
1306
+ if (!pdata->dais)
1307
+ return -ENOMEM;
1308
+
1309
+ memset(&empty_stream, 0, sizeof(empty_stream));
1310
+
1311
+ for_each_child_of_node(dev->of_node, node) {
1312
+ ret = of_property_read_u32(node, "reg", &id);
1313
+ if (ret || id >= MAX_SESSIONS || id < 0) {
1314
+ dev_err(dev, "valid dai id not found:%d\n", ret);
1315
+ continue;
1316
+ }
1317
+
1318
+ dai_drv = &pdata->dais[idx++];
1319
+ *dai_drv = q6asm_fe_dais_template[id];
1320
+
1321
+ ret = of_property_read_u32(node, "direction", &dir);
1322
+ if (ret)
1323
+ continue;
1324
+
1325
+ if (dir == Q6ASM_DAI_RX)
1326
+ dai_drv->capture = empty_stream;
1327
+ else if (dir == Q6ASM_DAI_TX)
1328
+ dai_drv->playback = empty_stream;
1329
+
1330
+ if (of_property_read_bool(node, "is-compress-dai"))
1331
+ dai_drv->compress_new = snd_soc_new_compress;
1332
+ }
1333
+
1334
+ return 0;
1335
+}
5651336
5661337 static int q6asm_dai_probe(struct platform_device *pdev)
5671338 {
....@@ -583,16 +1354,21 @@
5831354
5841355 dev_set_drvdata(dev, pdata);
5851356
1357
+ rc = of_q6asm_parse_dai_data(dev, pdata);
1358
+ if (rc)
1359
+ return rc;
1360
+
5861361 return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
587
- q6asm_fe_dais,
588
- ARRAY_SIZE(q6asm_fe_dais));
1362
+ pdata->dais, pdata->num_dais);
5891363 }
5901364
1365
+#ifdef CONFIG_OF
5911366 static const struct of_device_id q6asm_dai_device_id[] = {
5921367 { .compatible = "qcom,q6asm-dais" },
5931368 {},
5941369 };
5951370 MODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
1371
+#endif
5961372
5971373 static struct platform_driver q6asm_dai_platform_driver = {
5981374 .driver = {