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