pcm.c (31397B)
1// SPDX-License-Identifier: GPL-2.0-only 2// 3// Copyright(c) 2020 Intel Corporation. All rights reserved. 4// 5// Author: Cezary Rojewski <cezary.rojewski@intel.com> 6// 7 8#include <linux/pm_runtime.h> 9#include <sound/soc.h> 10#include <sound/pcm_params.h> 11#include <uapi/sound/tlv.h> 12#include "core.h" 13#include "messages.h" 14 15struct catpt_stream_template { 16 enum catpt_path_id path_id; 17 enum catpt_stream_type type; 18 u32 persistent_size; 19 u8 num_entries; 20 struct catpt_module_entry entries[]; 21}; 22 23static struct catpt_stream_template system_pb = { 24 .path_id = CATPT_PATH_SSP0_OUT, 25 .type = CATPT_STRM_TYPE_SYSTEM, 26 .num_entries = 1, 27 .entries = {{ CATPT_MODID_PCM_SYSTEM, 0 }}, 28}; 29 30static struct catpt_stream_template system_cp = { 31 .path_id = CATPT_PATH_SSP0_IN, 32 .type = CATPT_STRM_TYPE_CAPTURE, 33 .num_entries = 1, 34 .entries = {{ CATPT_MODID_PCM_CAPTURE, 0 }}, 35}; 36 37static struct catpt_stream_template offload_pb = { 38 .path_id = CATPT_PATH_SSP0_OUT, 39 .type = CATPT_STRM_TYPE_RENDER, 40 .num_entries = 1, 41 .entries = {{ CATPT_MODID_PCM, 0 }}, 42}; 43 44static struct catpt_stream_template loopback_cp = { 45 .path_id = CATPT_PATH_SSP0_OUT, 46 .type = CATPT_STRM_TYPE_LOOPBACK, 47 .num_entries = 1, 48 .entries = {{ CATPT_MODID_PCM_REFERENCE, 0 }}, 49}; 50 51static struct catpt_stream_template bluetooth_pb = { 52 .path_id = CATPT_PATH_SSP1_OUT, 53 .type = CATPT_STRM_TYPE_BLUETOOTH_RENDER, 54 .num_entries = 1, 55 .entries = {{ CATPT_MODID_BLUETOOTH_RENDER, 0 }}, 56}; 57 58static struct catpt_stream_template bluetooth_cp = { 59 .path_id = CATPT_PATH_SSP1_IN, 60 .type = CATPT_STRM_TYPE_BLUETOOTH_CAPTURE, 61 .num_entries = 1, 62 .entries = {{ CATPT_MODID_BLUETOOTH_CAPTURE, 0 }}, 63}; 64 65static struct catpt_stream_template *catpt_topology[] = { 66 [CATPT_STRM_TYPE_RENDER] = &offload_pb, 67 [CATPT_STRM_TYPE_SYSTEM] = &system_pb, 68 [CATPT_STRM_TYPE_CAPTURE] = &system_cp, 69 [CATPT_STRM_TYPE_LOOPBACK] = &loopback_cp, 70 [CATPT_STRM_TYPE_BLUETOOTH_RENDER] = &bluetooth_pb, 71 [CATPT_STRM_TYPE_BLUETOOTH_CAPTURE] = &bluetooth_cp, 72}; 73 74static struct catpt_stream_template * 75catpt_get_stream_template(struct snd_pcm_substream *substream) 76{ 77 struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream); 78 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0); 79 enum catpt_stream_type type; 80 81 type = cpu_dai->driver->id; 82 83 /* account for capture in bidirectional dais */ 84 switch (type) { 85 case CATPT_STRM_TYPE_SYSTEM: 86 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 87 type = CATPT_STRM_TYPE_CAPTURE; 88 break; 89 case CATPT_STRM_TYPE_BLUETOOTH_RENDER: 90 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 91 type = CATPT_STRM_TYPE_BLUETOOTH_CAPTURE; 92 break; 93 default: 94 break; 95 } 96 97 return catpt_topology[type]; 98} 99 100struct catpt_stream_runtime * 101catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id) 102{ 103 struct catpt_stream_runtime *pos, *result = NULL; 104 105 spin_lock(&cdev->list_lock); 106 list_for_each_entry(pos, &cdev->stream_list, node) { 107 if (pos->info.stream_hw_id == stream_hw_id) { 108 result = pos; 109 break; 110 } 111 } 112 113 spin_unlock(&cdev->list_lock); 114 return result; 115} 116 117static u32 catpt_stream_read_position(struct catpt_dev *cdev, 118 struct catpt_stream_runtime *stream) 119{ 120 u32 pos; 121 122 memcpy_fromio(&pos, cdev->lpe_ba + stream->info.read_pos_regaddr, 123 sizeof(pos)); 124 return pos; 125} 126 127static u32 catpt_stream_volume(struct catpt_dev *cdev, 128 struct catpt_stream_runtime *stream, u32 channel) 129{ 130 u32 volume, offset; 131 132 if (channel >= CATPT_CHANNELS_MAX) 133 channel = 0; 134 135 offset = stream->info.volume_regaddr[channel]; 136 memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume)); 137 return volume; 138} 139 140static u32 catpt_mixer_volume(struct catpt_dev *cdev, 141 struct catpt_mixer_stream_info *info, u32 channel) 142{ 143 u32 volume, offset; 144 145 if (channel >= CATPT_CHANNELS_MAX) 146 channel = 0; 147 148 offset = info->volume_regaddr[channel]; 149 memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume)); 150 return volume; 151} 152 153static void catpt_arrange_page_table(struct snd_pcm_substream *substream, 154 struct snd_dma_buffer *pgtbl) 155{ 156 struct snd_pcm_runtime *rtm = substream->runtime; 157 struct snd_dma_buffer *databuf = snd_pcm_get_dma_buf(substream); 158 int i, pages; 159 160 pages = snd_sgbuf_aligned_pages(rtm->dma_bytes); 161 162 for (i = 0; i < pages; i++) { 163 u32 pfn, offset; 164 u32 *page_table; 165 166 pfn = PFN_DOWN(snd_sgbuf_get_addr(databuf, i * PAGE_SIZE)); 167 /* incrementing by 2 on even and 3 on odd */ 168 offset = ((i << 2) + i) >> 1; 169 page_table = (u32 *)(pgtbl->area + offset); 170 171 if (i & 1) 172 *page_table |= (pfn << 4); 173 else 174 *page_table |= pfn; 175 } 176} 177 178static u32 catpt_get_channel_map(enum catpt_channel_config config) 179{ 180 switch (config) { 181 case CATPT_CHANNEL_CONFIG_MONO: 182 return GENMASK(31, 4) | CATPT_CHANNEL_CENTER; 183 184 case CATPT_CHANNEL_CONFIG_STEREO: 185 return GENMASK(31, 8) | CATPT_CHANNEL_LEFT 186 | (CATPT_CHANNEL_RIGHT << 4); 187 188 case CATPT_CHANNEL_CONFIG_2_POINT_1: 189 return GENMASK(31, 12) | CATPT_CHANNEL_LEFT 190 | (CATPT_CHANNEL_RIGHT << 4) 191 | (CATPT_CHANNEL_LFE << 8); 192 193 case CATPT_CHANNEL_CONFIG_3_POINT_0: 194 return GENMASK(31, 12) | CATPT_CHANNEL_LEFT 195 | (CATPT_CHANNEL_CENTER << 4) 196 | (CATPT_CHANNEL_RIGHT << 8); 197 198 case CATPT_CHANNEL_CONFIG_3_POINT_1: 199 return GENMASK(31, 16) | CATPT_CHANNEL_LEFT 200 | (CATPT_CHANNEL_CENTER << 4) 201 | (CATPT_CHANNEL_RIGHT << 8) 202 | (CATPT_CHANNEL_LFE << 12); 203 204 case CATPT_CHANNEL_CONFIG_QUATRO: 205 return GENMASK(31, 16) | CATPT_CHANNEL_LEFT 206 | (CATPT_CHANNEL_RIGHT << 4) 207 | (CATPT_CHANNEL_LEFT_SURROUND << 8) 208 | (CATPT_CHANNEL_RIGHT_SURROUND << 12); 209 210 case CATPT_CHANNEL_CONFIG_4_POINT_0: 211 return GENMASK(31, 16) | CATPT_CHANNEL_LEFT 212 | (CATPT_CHANNEL_CENTER << 4) 213 | (CATPT_CHANNEL_RIGHT << 8) 214 | (CATPT_CHANNEL_CENTER_SURROUND << 12); 215 216 case CATPT_CHANNEL_CONFIG_5_POINT_0: 217 return GENMASK(31, 20) | CATPT_CHANNEL_LEFT 218 | (CATPT_CHANNEL_CENTER << 4) 219 | (CATPT_CHANNEL_RIGHT << 8) 220 | (CATPT_CHANNEL_LEFT_SURROUND << 12) 221 | (CATPT_CHANNEL_RIGHT_SURROUND << 16); 222 223 case CATPT_CHANNEL_CONFIG_5_POINT_1: 224 return GENMASK(31, 24) | CATPT_CHANNEL_CENTER 225 | (CATPT_CHANNEL_LEFT << 4) 226 | (CATPT_CHANNEL_RIGHT << 8) 227 | (CATPT_CHANNEL_LEFT_SURROUND << 12) 228 | (CATPT_CHANNEL_RIGHT_SURROUND << 16) 229 | (CATPT_CHANNEL_LFE << 20); 230 231 case CATPT_CHANNEL_CONFIG_DUAL_MONO: 232 return GENMASK(31, 8) | CATPT_CHANNEL_LEFT 233 | (CATPT_CHANNEL_LEFT << 4); 234 235 default: 236 return U32_MAX; 237 } 238} 239 240static enum catpt_channel_config catpt_get_channel_config(u32 num_channels) 241{ 242 switch (num_channels) { 243 case 6: 244 return CATPT_CHANNEL_CONFIG_5_POINT_1; 245 case 5: 246 return CATPT_CHANNEL_CONFIG_5_POINT_0; 247 case 4: 248 return CATPT_CHANNEL_CONFIG_QUATRO; 249 case 3: 250 return CATPT_CHANNEL_CONFIG_2_POINT_1; 251 case 1: 252 return CATPT_CHANNEL_CONFIG_MONO; 253 case 2: 254 default: 255 return CATPT_CHANNEL_CONFIG_STEREO; 256 } 257} 258 259static int catpt_dai_startup(struct snd_pcm_substream *substream, 260 struct snd_soc_dai *dai) 261{ 262 struct catpt_stream_template *template; 263 struct catpt_stream_runtime *stream; 264 struct catpt_dev *cdev = dev_get_drvdata(dai->dev); 265 struct resource *res; 266 int ret; 267 268 template = catpt_get_stream_template(substream); 269 270 stream = kzalloc(sizeof(*stream), GFP_KERNEL); 271 if (!stream) 272 return -ENOMEM; 273 274 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, cdev->dev, PAGE_SIZE, 275 &stream->pgtbl); 276 if (ret) 277 goto err_pgtbl; 278 279 res = catpt_request_region(&cdev->dram, template->persistent_size); 280 if (!res) { 281 ret = -EBUSY; 282 goto err_request; 283 } 284 285 catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); 286 287 stream->template = template; 288 stream->persistent = res; 289 stream->substream = substream; 290 INIT_LIST_HEAD(&stream->node); 291 snd_soc_dai_set_dma_data(dai, substream, stream); 292 293 spin_lock(&cdev->list_lock); 294 list_add_tail(&stream->node, &cdev->stream_list); 295 spin_unlock(&cdev->list_lock); 296 297 return 0; 298 299err_request: 300 snd_dma_free_pages(&stream->pgtbl); 301err_pgtbl: 302 kfree(stream); 303 return ret; 304} 305 306static void catpt_dai_shutdown(struct snd_pcm_substream *substream, 307 struct snd_soc_dai *dai) 308{ 309 struct catpt_stream_runtime *stream; 310 struct catpt_dev *cdev = dev_get_drvdata(dai->dev); 311 312 stream = snd_soc_dai_get_dma_data(dai, substream); 313 314 spin_lock(&cdev->list_lock); 315 list_del(&stream->node); 316 spin_unlock(&cdev->list_lock); 317 318 release_resource(stream->persistent); 319 kfree(stream->persistent); 320 catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); 321 322 snd_dma_free_pages(&stream->pgtbl); 323 kfree(stream); 324 snd_soc_dai_set_dma_data(dai, substream, NULL); 325} 326 327static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol); 328 329static int catpt_dai_apply_usettings(struct snd_soc_dai *dai, 330 struct catpt_stream_runtime *stream) 331{ 332 struct snd_soc_component *component = dai->component; 333 struct snd_kcontrol *pos; 334 struct catpt_dev *cdev = dev_get_drvdata(dai->dev); 335 const char *name; 336 int ret; 337 u32 id = stream->info.stream_hw_id; 338 339 /* only selected streams have individual controls */ 340 switch (id) { 341 case CATPT_PIN_ID_OFFLOAD1: 342 name = "Media0 Playback Volume"; 343 break; 344 case CATPT_PIN_ID_OFFLOAD2: 345 name = "Media1 Playback Volume"; 346 break; 347 case CATPT_PIN_ID_CAPTURE1: 348 name = "Mic Capture Volume"; 349 break; 350 case CATPT_PIN_ID_REFERENCE: 351 name = "Loopback Mute"; 352 break; 353 default: 354 return 0; 355 } 356 357 list_for_each_entry(pos, &component->card->snd_card->controls, list) { 358 if (pos->private_data == component && 359 !strncmp(name, pos->id.name, sizeof(pos->id.name))) 360 break; 361 } 362 if (list_entry_is_head(pos, &component->card->snd_card->controls, list)) 363 return -ENOENT; 364 365 if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK) 366 return catpt_set_dspvol(cdev, id, (long *)pos->private_value); 367 ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)pos->private_value); 368 if (ret) 369 return CATPT_IPC_ERROR(ret); 370 return 0; 371} 372 373static int catpt_dai_hw_params(struct snd_pcm_substream *substream, 374 struct snd_pcm_hw_params *params, 375 struct snd_soc_dai *dai) 376{ 377 struct snd_pcm_runtime *rtm = substream->runtime; 378 struct snd_dma_buffer *dmab; 379 struct catpt_stream_runtime *stream; 380 struct catpt_audio_format afmt; 381 struct catpt_ring_info rinfo; 382 struct catpt_dev *cdev = dev_get_drvdata(dai->dev); 383 int ret; 384 385 stream = snd_soc_dai_get_dma_data(dai, substream); 386 if (stream->allocated) 387 return 0; 388 389 memset(&afmt, 0, sizeof(afmt)); 390 afmt.sample_rate = params_rate(params); 391 afmt.bit_depth = params_physical_width(params); 392 afmt.valid_bit_depth = params_width(params); 393 afmt.num_channels = params_channels(params); 394 afmt.channel_config = catpt_get_channel_config(afmt.num_channels); 395 afmt.channel_map = catpt_get_channel_map(afmt.channel_config); 396 afmt.interleaving = CATPT_INTERLEAVING_PER_CHANNEL; 397 398 dmab = snd_pcm_get_dma_buf(substream); 399 catpt_arrange_page_table(substream, &stream->pgtbl); 400 401 memset(&rinfo, 0, sizeof(rinfo)); 402 rinfo.page_table_addr = stream->pgtbl.addr; 403 rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE); 404 rinfo.size = rtm->dma_bytes; 405 rinfo.offset = 0; 406 rinfo.ring_first_page_pfn = PFN_DOWN(snd_sgbuf_get_addr(dmab, 0)); 407 408 ret = catpt_ipc_alloc_stream(cdev, stream->template->path_id, 409 stream->template->type, 410 &afmt, &rinfo, 411 stream->template->num_entries, 412 stream->template->entries, 413 stream->persistent, 414 cdev->scratch, 415 &stream->info); 416 if (ret) 417 return CATPT_IPC_ERROR(ret); 418 419 ret = catpt_dai_apply_usettings(dai, stream); 420 if (ret) 421 return ret; 422 423 stream->allocated = true; 424 return 0; 425} 426 427static int catpt_dai_hw_free(struct snd_pcm_substream *substream, 428 struct snd_soc_dai *dai) 429{ 430 struct catpt_stream_runtime *stream; 431 struct catpt_dev *cdev = dev_get_drvdata(dai->dev); 432 433 stream = snd_soc_dai_get_dma_data(dai, substream); 434 if (!stream->allocated) 435 return 0; 436 437 catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id); 438 catpt_ipc_free_stream(cdev, stream->info.stream_hw_id); 439 440 stream->allocated = false; 441 return 0; 442} 443 444static int catpt_dai_prepare(struct snd_pcm_substream *substream, 445 struct snd_soc_dai *dai) 446{ 447 struct catpt_stream_runtime *stream; 448 struct catpt_dev *cdev = dev_get_drvdata(dai->dev); 449 int ret; 450 451 stream = snd_soc_dai_get_dma_data(dai, substream); 452 if (stream->prepared) 453 return 0; 454 455 ret = catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id); 456 if (ret) 457 return CATPT_IPC_ERROR(ret); 458 459 ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id); 460 if (ret) 461 return CATPT_IPC_ERROR(ret); 462 463 stream->prepared = true; 464 return 0; 465} 466 467static int catpt_dai_trigger(struct snd_pcm_substream *substream, int cmd, 468 struct snd_soc_dai *dai) 469{ 470 struct snd_pcm_runtime *runtime = substream->runtime; 471 struct catpt_stream_runtime *stream; 472 struct catpt_dev *cdev = dev_get_drvdata(dai->dev); 473 snd_pcm_uframes_t pos; 474 int ret; 475 476 stream = snd_soc_dai_get_dma_data(dai, substream); 477 478 switch (cmd) { 479 case SNDRV_PCM_TRIGGER_START: 480 /* only offload is set_write_pos driven */ 481 if (stream->template->type != CATPT_STRM_TYPE_RENDER) 482 goto resume_stream; 483 484 pos = frames_to_bytes(runtime, runtime->start_threshold); 485 /* 486 * Dsp operates on buffer halves, thus max 2x set_write_pos 487 * (entire buffer filled) prior to stream start. 488 */ 489 ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id, 490 pos, false, false); 491 if (ret) 492 return CATPT_IPC_ERROR(ret); 493 fallthrough; 494 case SNDRV_PCM_TRIGGER_RESUME: 495 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 496 resume_stream: 497 catpt_dsp_update_lpclock(cdev); 498 ret = catpt_ipc_resume_stream(cdev, stream->info.stream_hw_id); 499 if (ret) 500 return CATPT_IPC_ERROR(ret); 501 break; 502 503 case SNDRV_PCM_TRIGGER_STOP: 504 stream->prepared = false; 505 fallthrough; 506 case SNDRV_PCM_TRIGGER_SUSPEND: 507 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 508 ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id); 509 catpt_dsp_update_lpclock(cdev); 510 if (ret) 511 return CATPT_IPC_ERROR(ret); 512 break; 513 514 default: 515 break; 516 } 517 518 return 0; 519} 520 521void catpt_stream_update_position(struct catpt_dev *cdev, 522 struct catpt_stream_runtime *stream, 523 struct catpt_notify_position *pos) 524{ 525 struct snd_pcm_substream *substream = stream->substream; 526 struct snd_pcm_runtime *r = substream->runtime; 527 snd_pcm_uframes_t dsppos, newpos; 528 int ret; 529 530 dsppos = bytes_to_frames(r, pos->stream_position); 531 532 if (!stream->prepared) 533 goto exit; 534 /* only offload is set_write_pos driven */ 535 if (stream->template->type != CATPT_STRM_TYPE_RENDER) 536 goto exit; 537 538 if (dsppos >= r->buffer_size / 2) 539 newpos = r->buffer_size / 2; 540 else 541 newpos = 0; 542 /* 543 * Dsp operates on buffer halves, thus on every notify position 544 * (buffer half consumed) update wp to allow stream progression. 545 */ 546 ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id, 547 frames_to_bytes(r, newpos), 548 false, false); 549 if (ret) { 550 dev_err(cdev->dev, "update position for stream %d failed: %d\n", 551 stream->info.stream_hw_id, ret); 552 return; 553 } 554exit: 555 snd_pcm_period_elapsed(substream); 556} 557 558/* 200 ms for 2 32-bit channels at 48kHz (native format) */ 559#define CATPT_BUFFER_MAX_SIZE 76800 560#define CATPT_PCM_PERIODS_MAX 4 561#define CATPT_PCM_PERIODS_MIN 2 562 563static const struct snd_pcm_hardware catpt_pcm_hardware = { 564 .info = SNDRV_PCM_INFO_MMAP | 565 SNDRV_PCM_INFO_MMAP_VALID | 566 SNDRV_PCM_INFO_INTERLEAVED | 567 SNDRV_PCM_INFO_PAUSE | 568 SNDRV_PCM_INFO_RESUME | 569 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 570 .formats = SNDRV_PCM_FMTBIT_S16_LE | 571 SNDRV_PCM_FMTBIT_S24_LE | 572 SNDRV_PCM_FMTBIT_S32_LE, 573 .period_bytes_min = PAGE_SIZE, 574 .period_bytes_max = CATPT_BUFFER_MAX_SIZE / CATPT_PCM_PERIODS_MIN, 575 .periods_min = CATPT_PCM_PERIODS_MIN, 576 .periods_max = CATPT_PCM_PERIODS_MAX, 577 .buffer_bytes_max = CATPT_BUFFER_MAX_SIZE, 578}; 579 580static int catpt_component_pcm_construct(struct snd_soc_component *component, 581 struct snd_soc_pcm_runtime *rtm) 582{ 583 struct catpt_dev *cdev = dev_get_drvdata(component->dev); 584 585 snd_pcm_set_managed_buffer_all(rtm->pcm, SNDRV_DMA_TYPE_DEV_SG, 586 cdev->dev, 587 catpt_pcm_hardware.buffer_bytes_max, 588 catpt_pcm_hardware.buffer_bytes_max); 589 590 return 0; 591} 592 593static int catpt_component_open(struct snd_soc_component *component, 594 struct snd_pcm_substream *substream) 595{ 596 struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream); 597 598 if (!rtm->dai_link->no_pcm) 599 snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware); 600 return 0; 601} 602 603static snd_pcm_uframes_t 604catpt_component_pointer(struct snd_soc_component *component, 605 struct snd_pcm_substream *substream) 606{ 607 struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream); 608 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0); 609 struct catpt_stream_runtime *stream; 610 struct catpt_dev *cdev = dev_get_drvdata(component->dev); 611 u32 pos; 612 613 if (rtm->dai_link->no_pcm) 614 return 0; 615 616 stream = snd_soc_dai_get_dma_data(cpu_dai, substream); 617 pos = catpt_stream_read_position(cdev, stream); 618 619 return bytes_to_frames(substream->runtime, pos); 620} 621 622static const struct snd_soc_dai_ops catpt_fe_dai_ops = { 623 .startup = catpt_dai_startup, 624 .shutdown = catpt_dai_shutdown, 625 .hw_params = catpt_dai_hw_params, 626 .hw_free = catpt_dai_hw_free, 627 .prepare = catpt_dai_prepare, 628 .trigger = catpt_dai_trigger, 629}; 630 631static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, 632 struct snd_soc_dai *dai) 633{ 634 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0); 635 struct catpt_ssp_device_format devfmt; 636 struct catpt_dev *cdev = dev_get_drvdata(dai->dev); 637 int ret; 638 639 devfmt.iface = dai->driver->id; 640 devfmt.channels = codec_dai->driver->capture.channels_max; 641 642 switch (devfmt.iface) { 643 case CATPT_SSP_IFACE_0: 644 devfmt.mclk = CATPT_MCLK_FREQ_24_MHZ; 645 646 switch (devfmt.channels) { 647 case 4: 648 devfmt.mode = CATPT_SSP_MODE_TDM_PROVIDER; 649 devfmt.clock_divider = 4; 650 break; 651 case 2: 652 default: 653 devfmt.mode = CATPT_SSP_MODE_I2S_PROVIDER; 654 devfmt.clock_divider = 9; 655 break; 656 } 657 break; 658 659 case CATPT_SSP_IFACE_1: 660 devfmt.mclk = CATPT_MCLK_OFF; 661 devfmt.mode = CATPT_SSP_MODE_I2S_CONSUMER; 662 devfmt.clock_divider = 0; 663 break; 664 } 665 666 /* see if this is a new configuration */ 667 if (!memcmp(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt))) 668 return 0; 669 670 pm_runtime_get_sync(cdev->dev); 671 672 ret = catpt_ipc_set_device_format(cdev, &devfmt); 673 674 pm_runtime_mark_last_busy(cdev->dev); 675 pm_runtime_put_autosuspend(cdev->dev); 676 677 if (ret) 678 return CATPT_IPC_ERROR(ret); 679 680 /* store device format set for given SSP */ 681 memcpy(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt)); 682 return 0; 683} 684 685static struct snd_soc_dai_driver dai_drivers[] = { 686/* FE DAIs */ 687{ 688 .name = "System Pin", 689 .id = CATPT_STRM_TYPE_SYSTEM, 690 .ops = &catpt_fe_dai_ops, 691 .playback = { 692 .stream_name = "System Playback", 693 .channels_min = 2, 694 .channels_max = 2, 695 .rates = SNDRV_PCM_RATE_48000, 696 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 697 }, 698 .capture = { 699 .stream_name = "Analog Capture", 700 .channels_min = 2, 701 .channels_max = 4, 702 .rates = SNDRV_PCM_RATE_48000, 703 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 704 }, 705}, 706{ 707 .name = "Offload0 Pin", 708 .id = CATPT_STRM_TYPE_RENDER, 709 .ops = &catpt_fe_dai_ops, 710 .playback = { 711 .stream_name = "Offload0 Playback", 712 .channels_min = 2, 713 .channels_max = 2, 714 .rates = SNDRV_PCM_RATE_8000_192000, 715 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 716 }, 717}, 718{ 719 .name = "Offload1 Pin", 720 .id = CATPT_STRM_TYPE_RENDER, 721 .ops = &catpt_fe_dai_ops, 722 .playback = { 723 .stream_name = "Offload1 Playback", 724 .channels_min = 2, 725 .channels_max = 2, 726 .rates = SNDRV_PCM_RATE_8000_192000, 727 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 728 }, 729}, 730{ 731 .name = "Loopback Pin", 732 .id = CATPT_STRM_TYPE_LOOPBACK, 733 .ops = &catpt_fe_dai_ops, 734 .capture = { 735 .stream_name = "Loopback Capture", 736 .channels_min = 2, 737 .channels_max = 2, 738 .rates = SNDRV_PCM_RATE_48000, 739 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 740 }, 741}, 742{ 743 .name = "Bluetooth Pin", 744 .id = CATPT_STRM_TYPE_BLUETOOTH_RENDER, 745 .ops = &catpt_fe_dai_ops, 746 .playback = { 747 .stream_name = "Bluetooth Playback", 748 .channels_min = 1, 749 .channels_max = 1, 750 .rates = SNDRV_PCM_RATE_8000, 751 .formats = SNDRV_PCM_FMTBIT_S16_LE, 752 }, 753 .capture = { 754 .stream_name = "Bluetooth Capture", 755 .channels_min = 1, 756 .channels_max = 1, 757 .rates = SNDRV_PCM_RATE_8000, 758 .formats = SNDRV_PCM_FMTBIT_S16_LE, 759 }, 760}, 761/* BE DAIs */ 762{ 763 .name = "ssp0-port", 764 .id = CATPT_SSP_IFACE_0, 765 .pcm_new = catpt_dai_pcm_new, 766 .playback = { 767 .channels_min = 1, 768 .channels_max = 8, 769 }, 770 .capture = { 771 .channels_min = 1, 772 .channels_max = 8, 773 }, 774}, 775{ 776 .name = "ssp1-port", 777 .id = CATPT_SSP_IFACE_1, 778 .pcm_new = catpt_dai_pcm_new, 779 .playback = { 780 .channels_min = 1, 781 .channels_max = 8, 782 }, 783 .capture = { 784 .channels_min = 1, 785 .channels_max = 8, 786 }, 787}, 788}; 789 790#define DSP_VOLUME_MAX S32_MAX /* 0db */ 791#define DSP_VOLUME_STEP_MAX 30 792 793static u32 ctlvol_to_dspvol(u32 value) 794{ 795 if (value > DSP_VOLUME_STEP_MAX) 796 value = 0; 797 return DSP_VOLUME_MAX >> (DSP_VOLUME_STEP_MAX - value); 798} 799 800static u32 dspvol_to_ctlvol(u32 volume) 801{ 802 if (volume > DSP_VOLUME_MAX) 803 return DSP_VOLUME_STEP_MAX; 804 return volume ? __fls(volume) : 0; 805} 806 807static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol) 808{ 809 u32 dspvol; 810 int ret, i; 811 812 for (i = 1; i < CATPT_CHANNELS_MAX; i++) 813 if (ctlvol[i] != ctlvol[0]) 814 break; 815 816 if (i == CATPT_CHANNELS_MAX) { 817 dspvol = ctlvol_to_dspvol(ctlvol[0]); 818 819 ret = catpt_ipc_set_volume(cdev, stream_id, 820 CATPT_ALL_CHANNELS_MASK, dspvol, 821 0, CATPT_AUDIO_CURVE_NONE); 822 } else { 823 for (i = 0; i < CATPT_CHANNELS_MAX; i++) { 824 dspvol = ctlvol_to_dspvol(ctlvol[i]); 825 826 ret = catpt_ipc_set_volume(cdev, stream_id, 827 i, dspvol, 828 0, CATPT_AUDIO_CURVE_NONE); 829 if (ret) 830 break; 831 } 832 } 833 834 if (ret) 835 return CATPT_IPC_ERROR(ret); 836 return 0; 837} 838 839static int catpt_volume_info(struct snd_kcontrol *kcontrol, 840 struct snd_ctl_elem_info *uinfo) 841{ 842 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 843 uinfo->count = CATPT_CHANNELS_MAX; 844 uinfo->value.integer.min = 0; 845 uinfo->value.integer.max = DSP_VOLUME_STEP_MAX; 846 return 0; 847} 848 849static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol, 850 struct snd_ctl_elem_value *ucontrol) 851{ 852 struct snd_soc_component *component = 853 snd_soc_kcontrol_component(kcontrol); 854 struct catpt_dev *cdev = dev_get_drvdata(component->dev); 855 u32 dspvol; 856 int i; 857 858 pm_runtime_get_sync(cdev->dev); 859 860 for (i = 0; i < CATPT_CHANNELS_MAX; i++) { 861 dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i); 862 ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol); 863 } 864 865 pm_runtime_mark_last_busy(cdev->dev); 866 pm_runtime_put_autosuspend(cdev->dev); 867 868 return 0; 869} 870 871static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol, 872 struct snd_ctl_elem_value *ucontrol) 873{ 874 struct snd_soc_component *component = 875 snd_soc_kcontrol_component(kcontrol); 876 struct catpt_dev *cdev = dev_get_drvdata(component->dev); 877 int ret; 878 879 pm_runtime_get_sync(cdev->dev); 880 881 ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id, 882 ucontrol->value.integer.value); 883 884 pm_runtime_mark_last_busy(cdev->dev); 885 pm_runtime_put_autosuspend(cdev->dev); 886 887 return ret; 888} 889 890static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, 891 struct snd_ctl_elem_value *ucontrol, 892 enum catpt_pin_id pin_id) 893{ 894 struct snd_soc_component *component = 895 snd_soc_kcontrol_component(kcontrol); 896 struct catpt_stream_runtime *stream; 897 struct catpt_dev *cdev = dev_get_drvdata(component->dev); 898 long *ctlvol = (long *)kcontrol->private_value; 899 u32 dspvol; 900 int i; 901 902 stream = catpt_stream_find(cdev, pin_id); 903 if (!stream) { 904 for (i = 0; i < CATPT_CHANNELS_MAX; i++) 905 ucontrol->value.integer.value[i] = ctlvol[i]; 906 return 0; 907 } 908 909 pm_runtime_get_sync(cdev->dev); 910 911 for (i = 0; i < CATPT_CHANNELS_MAX; i++) { 912 dspvol = catpt_stream_volume(cdev, stream, i); 913 ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol); 914 } 915 916 pm_runtime_mark_last_busy(cdev->dev); 917 pm_runtime_put_autosuspend(cdev->dev); 918 919 return 0; 920} 921 922static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol, 923 struct snd_ctl_elem_value *ucontrol, 924 enum catpt_pin_id pin_id) 925{ 926 struct snd_soc_component *component = 927 snd_soc_kcontrol_component(kcontrol); 928 struct catpt_stream_runtime *stream; 929 struct catpt_dev *cdev = dev_get_drvdata(component->dev); 930 long *ctlvol = (long *)kcontrol->private_value; 931 int ret, i; 932 933 stream = catpt_stream_find(cdev, pin_id); 934 if (!stream) { 935 for (i = 0; i < CATPT_CHANNELS_MAX; i++) 936 ctlvol[i] = ucontrol->value.integer.value[i]; 937 return 0; 938 } 939 940 pm_runtime_get_sync(cdev->dev); 941 942 ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id, 943 ucontrol->value.integer.value); 944 945 pm_runtime_mark_last_busy(cdev->dev); 946 pm_runtime_put_autosuspend(cdev->dev); 947 948 if (ret) 949 return ret; 950 951 for (i = 0; i < CATPT_CHANNELS_MAX; i++) 952 ctlvol[i] = ucontrol->value.integer.value[i]; 953 return 0; 954} 955 956static int catpt_offload1_volume_get(struct snd_kcontrol *kctl, 957 struct snd_ctl_elem_value *uctl) 958{ 959 return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD1); 960} 961 962static int catpt_offload1_volume_put(struct snd_kcontrol *kctl, 963 struct snd_ctl_elem_value *uctl) 964{ 965 return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD1); 966} 967 968static int catpt_offload2_volume_get(struct snd_kcontrol *kctl, 969 struct snd_ctl_elem_value *uctl) 970{ 971 return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD2); 972} 973 974static int catpt_offload2_volume_put(struct snd_kcontrol *kctl, 975 struct snd_ctl_elem_value *uctl) 976{ 977 return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD2); 978} 979 980static int catpt_capture_volume_get(struct snd_kcontrol *kctl, 981 struct snd_ctl_elem_value *uctl) 982{ 983 return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_CAPTURE1); 984} 985 986static int catpt_capture_volume_put(struct snd_kcontrol *kctl, 987 struct snd_ctl_elem_value *uctl) 988{ 989 return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_CAPTURE1); 990} 991 992static int catpt_loopback_switch_get(struct snd_kcontrol *kcontrol, 993 struct snd_ctl_elem_value *ucontrol) 994{ 995 ucontrol->value.integer.value[0] = *(bool *)kcontrol->private_value; 996 return 0; 997} 998 999static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol, 1000 struct snd_ctl_elem_value *ucontrol) 1001{ 1002 struct snd_soc_component *component = 1003 snd_soc_kcontrol_component(kcontrol); 1004 struct catpt_stream_runtime *stream; 1005 struct catpt_dev *cdev = dev_get_drvdata(component->dev); 1006 bool mute; 1007 int ret; 1008 1009 mute = (bool)ucontrol->value.integer.value[0]; 1010 stream = catpt_stream_find(cdev, CATPT_PIN_ID_REFERENCE); 1011 if (!stream) { 1012 *(bool *)kcontrol->private_value = mute; 1013 return 0; 1014 } 1015 1016 pm_runtime_get_sync(cdev->dev); 1017 1018 ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute); 1019 1020 pm_runtime_mark_last_busy(cdev->dev); 1021 pm_runtime_put_autosuspend(cdev->dev); 1022 1023 if (ret) 1024 return CATPT_IPC_ERROR(ret); 1025 1026 *(bool *)kcontrol->private_value = mute; 1027 return 0; 1028} 1029 1030static int catpt_waves_switch_get(struct snd_kcontrol *kcontrol, 1031 struct snd_ctl_elem_value *ucontrol) 1032{ 1033 return 0; 1034} 1035 1036static int catpt_waves_switch_put(struct snd_kcontrol *kcontrol, 1037 struct snd_ctl_elem_value *ucontrol) 1038{ 1039 return 0; 1040} 1041 1042static int catpt_waves_param_get(struct snd_kcontrol *kcontrol, 1043 unsigned int __user *bytes, 1044 unsigned int size) 1045{ 1046 return 0; 1047} 1048 1049static int catpt_waves_param_put(struct snd_kcontrol *kcontrol, 1050 const unsigned int __user *bytes, 1051 unsigned int size) 1052{ 1053 return 0; 1054} 1055 1056static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(catpt_volume_tlv, -9000, 300, 1); 1057 1058#define CATPT_VOLUME_CTL(kname, sname) \ 1059{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 1060 .name = (kname), \ 1061 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ 1062 SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 1063 .info = catpt_volume_info, \ 1064 .get = catpt_##sname##_volume_get, \ 1065 .put = catpt_##sname##_volume_put, \ 1066 .tlv.p = catpt_volume_tlv, \ 1067 .private_value = (unsigned long) \ 1068 &(long[CATPT_CHANNELS_MAX]) {0} } 1069 1070static const struct snd_kcontrol_new component_kcontrols[] = { 1071/* Master volume (mixer stream) */ 1072CATPT_VOLUME_CTL("Master Playback Volume", mixer), 1073/* Individual volume controls for offload and capture */ 1074CATPT_VOLUME_CTL("Media0 Playback Volume", offload1), 1075CATPT_VOLUME_CTL("Media1 Playback Volume", offload2), 1076CATPT_VOLUME_CTL("Mic Capture Volume", capture), 1077SOC_SINGLE_BOOL_EXT("Loopback Mute", (unsigned long)&(bool[1]) {0}, 1078 catpt_loopback_switch_get, catpt_loopback_switch_put), 1079/* Enable or disable WAVES module */ 1080SOC_SINGLE_BOOL_EXT("Waves Switch", 0, 1081 catpt_waves_switch_get, catpt_waves_switch_put), 1082/* WAVES module parameter control */ 1083SND_SOC_BYTES_TLV("Waves Set Param", 128, 1084 catpt_waves_param_get, catpt_waves_param_put), 1085}; 1086 1087static const struct snd_soc_dapm_widget component_widgets[] = { 1088 SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0), 1089 SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0), 1090 SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0), 1091 SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0), 1092 1093 SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), 1094}; 1095 1096static const struct snd_soc_dapm_route component_routes[] = { 1097 {"Playback VMixer", NULL, "System Playback"}, 1098 {"Playback VMixer", NULL, "Offload0 Playback"}, 1099 {"Playback VMixer", NULL, "Offload1 Playback"}, 1100 1101 {"SSP0 CODEC OUT", NULL, "Playback VMixer"}, 1102 1103 {"Analog Capture", NULL, "SSP0 CODEC IN"}, 1104 {"Loopback Capture", NULL, "SSP0 CODEC IN"}, 1105 1106 {"SSP1 BT OUT", NULL, "Bluetooth Playback"}, 1107 {"Bluetooth Capture", NULL, "SSP1 BT IN"}, 1108}; 1109 1110static const struct snd_soc_component_driver catpt_comp_driver = { 1111 .name = "catpt-platform", 1112 1113 .pcm_construct = catpt_component_pcm_construct, 1114 .open = catpt_component_open, 1115 .pointer = catpt_component_pointer, 1116 1117 .controls = component_kcontrols, 1118 .num_controls = ARRAY_SIZE(component_kcontrols), 1119 .dapm_widgets = component_widgets, 1120 .num_dapm_widgets = ARRAY_SIZE(component_widgets), 1121 .dapm_routes = component_routes, 1122 .num_dapm_routes = ARRAY_SIZE(component_routes), 1123}; 1124 1125int catpt_arm_stream_templates(struct catpt_dev *cdev) 1126{ 1127 struct resource *res; 1128 u32 scratch_size = 0; 1129 int i, j; 1130 1131 for (i = 0; i < ARRAY_SIZE(catpt_topology); i++) { 1132 struct catpt_stream_template *template; 1133 struct catpt_module_entry *entry; 1134 struct catpt_module_type *type; 1135 1136 template = catpt_topology[i]; 1137 template->persistent_size = 0; 1138 1139 for (j = 0; j < template->num_entries; j++) { 1140 entry = &template->entries[j]; 1141 type = &cdev->modules[entry->module_id]; 1142 1143 if (!type->loaded) 1144 return -ENOENT; 1145 1146 entry->entry_point = type->entry_point; 1147 template->persistent_size += type->persistent_size; 1148 if (type->scratch_size > scratch_size) 1149 scratch_size = type->scratch_size; 1150 } 1151 } 1152 1153 if (scratch_size) { 1154 /* allocate single scratch area for all modules */ 1155 res = catpt_request_region(&cdev->dram, scratch_size); 1156 if (!res) 1157 return -EBUSY; 1158 cdev->scratch = res; 1159 } 1160 1161 return 0; 1162} 1163 1164int catpt_register_plat_component(struct catpt_dev *cdev) 1165{ 1166 struct snd_soc_component *component; 1167 int ret; 1168 1169 component = devm_kzalloc(cdev->dev, sizeof(*component), GFP_KERNEL); 1170 if (!component) 1171 return -ENOMEM; 1172 1173 ret = snd_soc_component_initialize(component, &catpt_comp_driver, 1174 cdev->dev); 1175 if (ret) 1176 return ret; 1177 1178 component->name = catpt_comp_driver.name; 1179 return snd_soc_add_component(component, dai_drivers, 1180 ARRAY_SIZE(dai_drivers)); 1181}