topology.c (29489B)
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2020, Linaro Limited 3 4#include <sound/soc.h> 5#include <sound/soc-dapm.h> 6#include <sound/pcm.h> 7#include <sound/control.h> 8#include <sound/asound.h> 9#include <linux/firmware.h> 10#include <sound/soc-topology.h> 11#include <sound/soc-dpcm.h> 12#include <uapi/sound/snd_ar_tokens.h> 13#include <linux/kernel.h> 14#include <linux/wait.h> 15#include "q6apm.h" 16#include "audioreach.h" 17 18struct snd_ar_control { 19 u32 sgid; /* Sub Graph ID */ 20 struct snd_soc_component *scomp; 21}; 22 23static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6apm *apm, 24 uint32_t graph_id, 25 bool *found) 26{ 27 struct audioreach_graph_info *info; 28 int ret; 29 30 mutex_lock(&apm->lock); 31 info = idr_find(&apm->graph_info_idr, graph_id); 32 mutex_unlock(&apm->lock); 33 34 if (info) { 35 *found = true; 36 return info; 37 } 38 39 *found = false; 40 info = kzalloc(sizeof(*info), GFP_KERNEL); 41 if (!info) 42 return ERR_PTR(-ENOMEM); 43 44 INIT_LIST_HEAD(&info->sg_list); 45 46 mutex_lock(&apm->lock); 47 ret = idr_alloc(&apm->graph_info_idr, info, graph_id, graph_id + 1, GFP_KERNEL); 48 mutex_unlock(&apm->lock); 49 50 if (ret < 0) { 51 dev_err(apm->dev, "Failed to allocate Graph ID (%x)\n", graph_id); 52 kfree(info); 53 return ERR_PTR(ret); 54 } 55 56 info->id = ret; 57 58 return info; 59} 60 61static void audioreach_tplg_add_sub_graph(struct audioreach_sub_graph *sg, 62 struct audioreach_graph_info *info) 63{ 64 list_add_tail(&sg->node, &info->sg_list); 65 sg->info = info; 66 info->num_sub_graphs++; 67} 68 69static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm *apm, 70 uint32_t sub_graph_id, 71 bool *found) 72{ 73 struct audioreach_sub_graph *sg; 74 int ret; 75 76 if (!sub_graph_id) 77 return ERR_PTR(-EINVAL); 78 79 /* Find if there is already a matching sub-graph */ 80 mutex_lock(&apm->lock); 81 sg = idr_find(&apm->sub_graphs_idr, sub_graph_id); 82 mutex_unlock(&apm->lock); 83 84 if (sg) { 85 *found = true; 86 return sg; 87 } 88 89 *found = false; 90 sg = kzalloc(sizeof(*sg), GFP_KERNEL); 91 if (!sg) 92 return ERR_PTR(-ENOMEM); 93 94 INIT_LIST_HEAD(&sg->container_list); 95 96 mutex_lock(&apm->lock); 97 ret = idr_alloc(&apm->sub_graphs_idr, sg, sub_graph_id, sub_graph_id + 1, GFP_KERNEL); 98 mutex_unlock(&apm->lock); 99 100 if (ret < 0) { 101 dev_err(apm->dev, "Failed to allocate Sub-Graph Instance ID (%x)\n", sub_graph_id); 102 kfree(sg); 103 return ERR_PTR(ret); 104 } 105 106 sg->sub_graph_id = ret; 107 108 return sg; 109} 110 111static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm *apm, 112 struct audioreach_sub_graph *sg, 113 uint32_t container_id, 114 bool *found) 115{ 116 struct audioreach_container *cont; 117 int ret; 118 119 if (!container_id) 120 return ERR_PTR(-EINVAL); 121 122 mutex_lock(&apm->lock); 123 cont = idr_find(&apm->containers_idr, container_id); 124 mutex_unlock(&apm->lock); 125 126 if (cont) { 127 *found = true; 128 return cont; 129 } 130 *found = false; 131 132 cont = kzalloc(sizeof(*cont), GFP_KERNEL); 133 if (!cont) 134 return ERR_PTR(-ENOMEM); 135 136 INIT_LIST_HEAD(&cont->modules_list); 137 138 mutex_lock(&apm->lock); 139 ret = idr_alloc(&apm->containers_idr, cont, container_id, container_id + 1, GFP_KERNEL); 140 mutex_unlock(&apm->lock); 141 142 if (ret < 0) { 143 dev_err(apm->dev, "Failed to allocate Container Instance ID (%x)\n", container_id); 144 kfree(cont); 145 return ERR_PTR(ret); 146 } 147 148 cont->container_id = ret; 149 cont->sub_graph = sg; 150 /* add to container list */ 151 list_add_tail(&cont->node, &sg->container_list); 152 sg->num_containers++; 153 154 return cont; 155} 156 157static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm, 158 struct audioreach_container *cont, 159 struct snd_soc_dapm_widget *w, 160 uint32_t module_id, bool *found) 161{ 162 struct audioreach_module *mod; 163 int ret; 164 165 mutex_lock(&apm->lock); 166 mod = idr_find(&apm->modules_idr, module_id); 167 mutex_unlock(&apm->lock); 168 169 if (mod) { 170 *found = true; 171 return mod; 172 } 173 *found = false; 174 mod = kzalloc(sizeof(*mod), GFP_KERNEL); 175 if (!mod) 176 return ERR_PTR(-ENOMEM); 177 178 mutex_lock(&apm->lock); 179 if (!module_id) { /* alloc module id dynamically */ 180 ret = idr_alloc_cyclic(&apm->modules_idr, mod, 181 AR_MODULE_DYNAMIC_INSTANCE_ID_START, 182 AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL); 183 } else { 184 ret = idr_alloc(&apm->modules_idr, mod, module_id, module_id + 1, GFP_KERNEL); 185 } 186 mutex_unlock(&apm->lock); 187 188 if (ret < 0) { 189 dev_err(apm->dev, "Failed to allocate Module Instance ID (%x)\n", module_id); 190 kfree(mod); 191 return ERR_PTR(ret); 192 } 193 194 mod->instance_id = ret; 195 /* add to module list */ 196 list_add_tail(&mod->node, &cont->modules_list); 197 mod->container = cont; 198 mod->widget = w; 199 cont->num_modules++; 200 201 return mod; 202} 203 204static struct snd_soc_tplg_vendor_array *audioreach_get_sg_array( 205 struct snd_soc_tplg_private *private) 206{ 207 struct snd_soc_tplg_vendor_array *sg_array = NULL; 208 bool found = false; 209 int sz; 210 211 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 212 struct snd_soc_tplg_vendor_value_elem *sg_elem; 213 int tkn_count = 0; 214 215 sg_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 216 sg_elem = sg_array->value; 217 sz = sz + le32_to_cpu(sg_array->size); 218 while (!found && tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) { 219 switch (le32_to_cpu(sg_elem->token)) { 220 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 221 found = true; 222 break; 223 default: 224 break; 225 } 226 tkn_count++; 227 sg_elem++; 228 } 229 } 230 231 if (found) 232 return sg_array; 233 234 return NULL; 235} 236 237static struct snd_soc_tplg_vendor_array *audioreach_get_cont_array( 238 struct snd_soc_tplg_private *private) 239{ 240 struct snd_soc_tplg_vendor_array *cont_array = NULL; 241 bool found = false; 242 int sz; 243 244 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 245 struct snd_soc_tplg_vendor_value_elem *cont_elem; 246 int tkn_count = 0; 247 248 cont_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 249 cont_elem = cont_array->value; 250 sz = sz + le32_to_cpu(cont_array->size); 251 while (!found && tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) { 252 switch (le32_to_cpu(cont_elem->token)) { 253 case AR_TKN_U32_CONTAINER_INSTANCE_ID: 254 found = true; 255 break; 256 default: 257 break; 258 } 259 tkn_count++; 260 cont_elem++; 261 } 262 } 263 264 if (found) 265 return cont_array; 266 267 return NULL; 268} 269 270static struct snd_soc_tplg_vendor_array *audioreach_get_module_array( 271 struct snd_soc_tplg_private *private) 272{ 273 struct snd_soc_tplg_vendor_array *mod_array = NULL; 274 bool found = false; 275 int sz = 0; 276 277 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 278 struct snd_soc_tplg_vendor_value_elem *mod_elem; 279 int tkn_count = 0; 280 281 mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 282 mod_elem = mod_array->value; 283 sz = sz + le32_to_cpu(mod_array->size); 284 while (!found && tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 285 switch (le32_to_cpu(mod_elem->token)) { 286 case AR_TKN_U32_MODULE_INSTANCE_ID: 287 found = true; 288 break; 289 default: 290 break; 291 } 292 tkn_count++; 293 mod_elem++; 294 } 295 } 296 297 if (found) 298 return mod_array; 299 300 return NULL; 301} 302 303static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm, 304 struct snd_soc_tplg_private *private) 305{ 306 struct snd_soc_tplg_vendor_value_elem *sg_elem; 307 struct snd_soc_tplg_vendor_array *sg_array; 308 struct audioreach_graph_info *info = NULL; 309 int graph_id, sub_graph_id, tkn_count = 0; 310 struct audioreach_sub_graph *sg; 311 bool found; 312 313 sg_array = audioreach_get_sg_array(private); 314 sg_elem = sg_array->value; 315 316 while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) { 317 switch (le32_to_cpu(sg_elem->token)) { 318 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 319 sub_graph_id = le32_to_cpu(sg_elem->value); 320 sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found); 321 if (IS_ERR(sg)) { 322 return sg; 323 } else if (found) { 324 /* Already parsed data for this sub-graph */ 325 return sg; 326 } 327 break; 328 case AR_TKN_DAI_INDEX: 329 /* Sub graph is associated with predefined graph */ 330 graph_id = le32_to_cpu(sg_elem->value); 331 info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found); 332 if (IS_ERR(info)) 333 return ERR_CAST(info); 334 break; 335 case AR_TKN_U32_SUB_GRAPH_PERF_MODE: 336 sg->perf_mode = le32_to_cpu(sg_elem->value); 337 break; 338 case AR_TKN_U32_SUB_GRAPH_DIRECTION: 339 sg->direction = le32_to_cpu(sg_elem->value); 340 break; 341 case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID: 342 sg->scenario_id = le32_to_cpu(sg_elem->value); 343 break; 344 default: 345 dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token); 346 break; 347 348 } 349 tkn_count++; 350 sg_elem++; 351 } 352 353 /* Sub graph is associated with predefined graph */ 354 if (info) 355 audioreach_tplg_add_sub_graph(sg, info); 356 357 return sg; 358} 359 360static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm, 361 struct audioreach_sub_graph *sg, 362 struct snd_soc_tplg_private *private) 363{ 364 struct snd_soc_tplg_vendor_value_elem *cont_elem; 365 struct snd_soc_tplg_vendor_array *cont_array; 366 struct audioreach_container *cont; 367 int container_id, tkn_count = 0; 368 bool found = false; 369 370 cont_array = audioreach_get_cont_array(private); 371 cont_elem = cont_array->value; 372 373 while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) { 374 switch (le32_to_cpu(cont_elem->token)) { 375 case AR_TKN_U32_CONTAINER_INSTANCE_ID: 376 container_id = le32_to_cpu(cont_elem->value); 377 cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found); 378 if (IS_ERR(cont) || found)/* Error or Already parsed container data */ 379 return cont; 380 break; 381 case AR_TKN_U32_CONTAINER_CAPABILITY_ID: 382 cont->capability_id = le32_to_cpu(cont_elem->value); 383 break; 384 case AR_TKN_U32_CONTAINER_STACK_SIZE: 385 cont->stack_size = le32_to_cpu(cont_elem->value); 386 break; 387 case AR_TKN_U32_CONTAINER_GRAPH_POS: 388 cont->graph_pos = le32_to_cpu(cont_elem->value); 389 break; 390 case AR_TKN_U32_CONTAINER_PROC_DOMAIN: 391 cont->proc_domain = le32_to_cpu(cont_elem->value); 392 break; 393 default: 394 dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token); 395 break; 396 397 } 398 tkn_count++; 399 cont_elem++; 400 } 401 402 return cont; 403} 404 405static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm, 406 struct audioreach_container *cont, 407 struct snd_soc_tplg_private *private, 408 struct snd_soc_dapm_widget *w) 409{ 410 uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0; 411 uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0; 412 uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0; 413 int module_id = 0, instance_id = 0, tkn_count = 0; 414 struct snd_soc_tplg_vendor_value_elem *mod_elem; 415 struct snd_soc_tplg_vendor_array *mod_array; 416 struct audioreach_module *mod = NULL; 417 bool found; 418 419 mod_array = audioreach_get_module_array(private); 420 mod_elem = mod_array->value; 421 422 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 423 switch (le32_to_cpu(mod_elem->token)) { 424 /* common module info */ 425 case AR_TKN_U32_MODULE_ID: 426 module_id = le32_to_cpu(mod_elem->value); 427 break; 428 case AR_TKN_U32_MODULE_INSTANCE_ID: 429 instance_id = le32_to_cpu(mod_elem->value); 430 mod = audioreach_tplg_alloc_module(apm, cont, w, 431 instance_id, &found); 432 if (IS_ERR(mod)) { 433 return mod; 434 } else if (found) { 435 dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n", 436 instance_id); 437 return ERR_PTR(-EINVAL); 438 } 439 440 break; 441 case AR_TKN_U32_MODULE_MAX_IP_PORTS: 442 max_ip_port = le32_to_cpu(mod_elem->value); 443 break; 444 case AR_TKN_U32_MODULE_MAX_OP_PORTS: 445 max_op_port = le32_to_cpu(mod_elem->value); 446 break; 447 case AR_TKN_U32_MODULE_IN_PORTS: 448 in_port = le32_to_cpu(mod_elem->value); 449 break; 450 case AR_TKN_U32_MODULE_OUT_PORTS: 451 out_port = le32_to_cpu(mod_elem->value); 452 break; 453 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID: 454 src_mod_op_port_id = le32_to_cpu(mod_elem->value); 455 break; 456 case AR_TKN_U32_MODULE_SRC_INSTANCE_ID: 457 src_mod_inst_id = le32_to_cpu(mod_elem->value); 458 break; 459 case AR_TKN_U32_MODULE_DST_INSTANCE_ID: 460 dst_mod_inst_id = le32_to_cpu(mod_elem->value); 461 break; 462 case AR_TKN_U32_MODULE_DST_IN_PORT_ID: 463 dst_mod_ip_port_id = le32_to_cpu(mod_elem->value); 464 break; 465 default: 466 break; 467 468 } 469 tkn_count++; 470 mod_elem++; 471 } 472 473 if (mod) { 474 mod->module_id = module_id; 475 mod->max_ip_port = max_ip_port; 476 mod->max_op_port = max_op_port; 477 mod->in_port = in_port; 478 mod->out_port = out_port; 479 mod->src_mod_inst_id = src_mod_inst_id; 480 mod->src_mod_op_port_id = src_mod_op_port_id; 481 mod->dst_mod_inst_id = dst_mod_inst_id; 482 mod->dst_mod_ip_port_id = dst_mod_ip_port_id; 483 } 484 485 return mod; 486} 487 488static int audioreach_widget_load_module_common(struct snd_soc_component *component, 489 int index, struct snd_soc_dapm_widget *w, 490 struct snd_soc_tplg_dapm_widget *tplg_w) 491{ 492 struct q6apm *apm = dev_get_drvdata(component->dev); 493 struct audioreach_container *cont; 494 struct audioreach_sub_graph *sg; 495 struct audioreach_module *mod; 496 struct snd_soc_dobj *dobj; 497 498 sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv); 499 if (IS_ERR(sg)) 500 return PTR_ERR(sg); 501 502 cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv); 503 if (IS_ERR(cont)) 504 return PTR_ERR(cont); 505 506 mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w); 507 if (IS_ERR(mod)) 508 return PTR_ERR(mod); 509 510 dobj = &w->dobj; 511 dobj->private = mod; 512 513 return 0; 514} 515 516static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component, 517 int index, struct snd_soc_dapm_widget *w, 518 struct snd_soc_tplg_dapm_widget *tplg_w) 519{ 520 struct snd_soc_tplg_vendor_value_elem *mod_elem; 521 struct snd_soc_tplg_vendor_array *mod_array; 522 struct audioreach_module *mod; 523 struct snd_soc_dobj *dobj; 524 int tkn_count = 0; 525 int ret; 526 527 ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 528 if (ret) 529 return ret; 530 531 dobj = &w->dobj; 532 mod = dobj->private; 533 mod_array = audioreach_get_module_array(&tplg_w->priv); 534 mod_elem = mod_array->value; 535 536 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 537 switch (le32_to_cpu(mod_elem->token)) { 538 case AR_TKN_U32_MODULE_FMT_INTERLEAVE: 539 mod->interleave_type = le32_to_cpu(mod_elem->value); 540 break; 541 case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE: 542 mod->rate = le32_to_cpu(mod_elem->value); 543 break; 544 case AR_TKN_U32_MODULE_FMT_BIT_DEPTH: 545 mod->bit_depth = le32_to_cpu(mod_elem->value); 546 break; 547 default: 548 break; 549 } 550 tkn_count++; 551 mod_elem++; 552 } 553 554 return 0; 555} 556 557static int audioreach_widget_log_module_load(struct audioreach_module *mod, 558 struct snd_soc_tplg_vendor_array *mod_array) 559{ 560 struct snd_soc_tplg_vendor_value_elem *mod_elem; 561 int tkn_count = 0; 562 563 mod_elem = mod_array->value; 564 565 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 566 switch (le32_to_cpu(mod_elem->token)) { 567 568 case AR_TKN_U32_MODULE_LOG_CODE: 569 mod->log_code = le32_to_cpu(mod_elem->value); 570 break; 571 case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID: 572 mod->log_tap_point_id = le32_to_cpu(mod_elem->value); 573 break; 574 case AR_TKN_U32_MODULE_LOG_MODE: 575 mod->log_mode = le32_to_cpu(mod_elem->value); 576 break; 577 default: 578 break; 579 } 580 tkn_count++; 581 mod_elem++; 582 } 583 584 return 0; 585} 586 587static int audioreach_widget_dma_module_load(struct audioreach_module *mod, 588 struct snd_soc_tplg_vendor_array *mod_array) 589{ 590 struct snd_soc_tplg_vendor_value_elem *mod_elem; 591 int tkn_count = 0; 592 593 mod_elem = mod_array->value; 594 595 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 596 switch (le32_to_cpu(mod_elem->token)) { 597 case AR_TKN_U32_MODULE_HW_IF_IDX: 598 mod->hw_interface_idx = le32_to_cpu(mod_elem->value); 599 break; 600 case AR_TKN_U32_MODULE_FMT_DATA: 601 mod->data_format = le32_to_cpu(mod_elem->value); 602 break; 603 case AR_TKN_U32_MODULE_HW_IF_TYPE: 604 mod->hw_interface_type = le32_to_cpu(mod_elem->value); 605 break; 606 default: 607 break; 608 } 609 tkn_count++; 610 mod_elem++; 611 } 612 613 return 0; 614} 615 616static int audioreach_widget_i2s_module_load(struct audioreach_module *mod, 617 struct snd_soc_tplg_vendor_array *mod_array) 618{ 619 struct snd_soc_tplg_vendor_value_elem *mod_elem; 620 int tkn_count = 0; 621 622 mod_elem = mod_array->value; 623 624 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 625 switch (le32_to_cpu(mod_elem->token)) { 626 case AR_TKN_U32_MODULE_HW_IF_IDX: 627 mod->hw_interface_idx = le32_to_cpu(mod_elem->value); 628 break; 629 case AR_TKN_U32_MODULE_FMT_DATA: 630 mod->data_format = le32_to_cpu(mod_elem->value); 631 break; 632 case AR_TKN_U32_MODULE_HW_IF_TYPE: 633 mod->hw_interface_type = le32_to_cpu(mod_elem->value); 634 break; 635 case AR_TKN_U32_MODULE_SD_LINE_IDX: 636 mod->sd_line_idx = le32_to_cpu(mod_elem->value); 637 break; 638 case AR_TKN_U32_MODULE_WS_SRC: 639 mod->ws_src = le32_to_cpu(mod_elem->value); 640 break; 641 default: 642 break; 643 } 644 tkn_count++; 645 mod_elem++; 646 } 647 648 return 0; 649} 650 651static int audioreach_widget_load_buffer(struct snd_soc_component *component, 652 int index, struct snd_soc_dapm_widget *w, 653 struct snd_soc_tplg_dapm_widget *tplg_w) 654{ 655 struct snd_soc_tplg_vendor_array *mod_array; 656 struct audioreach_module *mod; 657 struct snd_soc_dobj *dobj; 658 int ret; 659 660 ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 661 if (ret) 662 return ret; 663 664 dobj = &w->dobj; 665 mod = dobj->private; 666 667 mod_array = audioreach_get_module_array(&tplg_w->priv); 668 669 switch (mod->module_id) { 670 case MODULE_ID_CODEC_DMA_SINK: 671 case MODULE_ID_CODEC_DMA_SOURCE: 672 audioreach_widget_dma_module_load(mod, mod_array); 673 break; 674 case MODULE_ID_DATA_LOGGING: 675 audioreach_widget_log_module_load(mod, mod_array); 676 break; 677 case MODULE_ID_I2S_SINK: 678 case MODULE_ID_I2S_SOURCE: 679 audioreach_widget_i2s_module_load(mod, mod_array); 680 break; 681 default: 682 return -EINVAL; 683 } 684 685 return 0; 686} 687 688static int audioreach_widget_load_mixer(struct snd_soc_component *component, 689 int index, struct snd_soc_dapm_widget *w, 690 struct snd_soc_tplg_dapm_widget *tplg_w) 691{ 692 struct snd_soc_tplg_vendor_value_elem *w_elem; 693 struct snd_soc_tplg_vendor_array *w_array; 694 struct snd_ar_control *scontrol; 695 struct snd_soc_dobj *dobj; 696 int tkn_count = 0; 697 698 w_array = &tplg_w->priv.array[0]; 699 700 scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); 701 if (!scontrol) 702 return -ENOMEM; 703 704 scontrol->scomp = component; 705 dobj = &w->dobj; 706 dobj->private = scontrol; 707 708 w_elem = w_array->value; 709 while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) { 710 switch (le32_to_cpu(w_elem->token)) { 711 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 712 scontrol->sgid = le32_to_cpu(w_elem->value); 713 break; 714 default: /* ignore other tokens */ 715 break; 716 } 717 tkn_count++; 718 w_elem++; 719 } 720 721 return 0; 722} 723 724static int audioreach_pga_event(struct snd_soc_dapm_widget *w, 725 struct snd_kcontrol *kcontrol, int event) 726 727{ 728 struct snd_soc_dapm_context *dapm = w->dapm; 729 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 730 struct audioreach_module *mod = w->dobj.private; 731 struct q6apm *apm = dev_get_drvdata(c->dev); 732 733 switch (event) { 734 case SND_SOC_DAPM_POST_PMU: 735 /* apply gain after power up of widget */ 736 audioreach_gain_set_vol_ctrl(apm, mod, mod->gain); 737 break; 738 default: 739 break; 740 } 741 742 return 0; 743} 744 745static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = { 746 { AR_PGA_DAPM_EVENT, audioreach_pga_event }, 747}; 748 749static int audioreach_widget_load_pga(struct snd_soc_component *component, 750 int index, struct snd_soc_dapm_widget *w, 751 struct snd_soc_tplg_dapm_widget *tplg_w) 752{ 753 struct audioreach_module *mod; 754 struct snd_soc_dobj *dobj; 755 int ret; 756 757 ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 758 if (ret) 759 return ret; 760 761 dobj = &w->dobj; 762 mod = dobj->private; 763 mod->gain = VOL_CTRL_DEFAULT_GAIN; 764 765 ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops, 766 ARRAY_SIZE(audioreach_widget_ops), 767 le16_to_cpu(tplg_w->event_type)); 768 if (ret) { 769 dev_err(component->dev, "matching event handlers NOT found for %d\n", 770 le16_to_cpu(tplg_w->event_type)); 771 return -EINVAL; 772 } 773 774 return 0; 775} 776 777static int audioreach_widget_ready(struct snd_soc_component *component, 778 int index, struct snd_soc_dapm_widget *w, 779 struct snd_soc_tplg_dapm_widget *tplg_w) 780{ 781 switch (w->id) { 782 case snd_soc_dapm_aif_in: 783 case snd_soc_dapm_aif_out: 784 audioreach_widget_load_buffer(component, index, w, tplg_w); 785 break; 786 case snd_soc_dapm_decoder: 787 case snd_soc_dapm_encoder: 788 case snd_soc_dapm_src: 789 audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w); 790 break; 791 case snd_soc_dapm_buffer: 792 audioreach_widget_load_buffer(component, index, w, tplg_w); 793 break; 794 case snd_soc_dapm_mixer: 795 return audioreach_widget_load_mixer(component, index, w, tplg_w); 796 case snd_soc_dapm_pga: 797 return audioreach_widget_load_pga(component, index, w, tplg_w); 798 case snd_soc_dapm_dai_link: 799 case snd_soc_dapm_scheduler: 800 case snd_soc_dapm_out_drv: 801 default: 802 dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id); 803 break; 804 } 805 806 return 0; 807} 808 809static int audioreach_widget_unload(struct snd_soc_component *scomp, 810 struct snd_soc_dobj *dobj) 811{ 812 struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj); 813 struct q6apm *apm = dev_get_drvdata(scomp->dev); 814 struct audioreach_container *cont; 815 struct audioreach_module *mod; 816 817 mod = dobj->private; 818 cont = mod->container; 819 820 if (w->id == snd_soc_dapm_mixer) { 821 /* virtual widget */ 822 kfree(dobj->private); 823 return 0; 824 } 825 826 mutex_lock(&apm->lock); 827 idr_remove(&apm->modules_idr, mod->instance_id); 828 cont->num_modules--; 829 830 list_del(&mod->node); 831 kfree(mod); 832 /* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */ 833 if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */ 834 struct audioreach_sub_graph *sg = cont->sub_graph; 835 836 idr_remove(&apm->containers_idr, cont->container_id); 837 list_del(&cont->node); 838 sg->num_containers--; 839 kfree(cont); 840 /* check if there are no more containers in the sub graph and remove it */ 841 if (list_empty(&sg->container_list)) { 842 struct audioreach_graph_info *info = sg->info; 843 844 idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id); 845 list_del(&sg->node); 846 info->num_sub_graphs--; 847 kfree(sg); 848 /* Check if there are no more sub-graphs left then remove graph info */ 849 if (list_empty(&info->sg_list)) { 850 idr_remove(&apm->graph_info_idr, info->id); 851 kfree(info); 852 } 853 } 854 } 855 856 mutex_unlock(&apm->lock); 857 858 return 0; 859} 860 861static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp, 862 const char *name) 863{ 864 struct q6apm *apm = dev_get_drvdata(comp->dev); 865 struct audioreach_module *module; 866 int id; 867 868 idr_for_each_entry(&apm->modules_idr, module, id) { 869 if (!strcmp(name, module->widget->name)) 870 return module; 871 } 872 873 return NULL; 874} 875 876static int audioreach_route_load(struct snd_soc_component *scomp, int index, 877 struct snd_soc_dapm_route *route) 878{ 879 struct audioreach_module *src, *sink; 880 881 src = audioreach_find_widget(scomp, route->source); 882 sink = audioreach_find_widget(scomp, route->sink); 883 884 if (src && sink) { 885 src->dst_mod_inst_id = sink->instance_id; 886 sink->src_mod_inst_id = src->instance_id; 887 } 888 889 return 0; 890} 891 892static int audioreach_route_unload(struct snd_soc_component *scomp, 893 struct snd_soc_dobj *dobj) 894{ 895 return 0; 896} 897 898static int audioreach_tplg_complete(struct snd_soc_component *component) 899{ 900 /* TBD */ 901 return 0; 902} 903 904/* DAI link - used for any driver specific init */ 905static int audioreach_link_load(struct snd_soc_component *component, int index, 906 struct snd_soc_dai_link *link, 907 struct snd_soc_tplg_link_config *cfg) 908{ 909 link->nonatomic = true; 910 link->dynamic = true; 911 link->platforms->name = NULL; 912 link->platforms->of_node = of_get_compatible_child(component->dev->of_node, 913 "qcom,q6apm-dais"); 914 return 0; 915} 916 917static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol, 918 struct snd_ctl_elem_value *ucontrol) 919{ 920 struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 921 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 922 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 923 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 924 struct snd_ar_control *dapm_scontrol = dw->dobj.private; 925 struct snd_ar_control *scontrol = mc->dobj.private; 926 struct q6apm *data = dev_get_drvdata(c->dev); 927 bool connected; 928 929 connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid); 930 if (connected) 931 ucontrol->value.integer.value[0] = 1; 932 else 933 ucontrol->value.integer.value[0] = 0; 934 935 return 0; 936} 937 938static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol, 939 struct snd_ctl_elem_value *ucontrol) 940{ 941 struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 942 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 943 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 944 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 945 struct snd_ar_control *dapm_scontrol = dw->dobj.private; 946 struct snd_ar_control *scontrol = mc->dobj.private; 947 struct q6apm *data = dev_get_drvdata(c->dev); 948 949 if (ucontrol->value.integer.value[0]) { 950 q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true); 951 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL); 952 } else { 953 q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false); 954 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL); 955 } 956 return 0; 957} 958 959static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, 960 struct snd_ctl_elem_value *ucontrol) 961{ 962 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 963 struct audioreach_module *mod = dw->dobj.private; 964 965 ucontrol->value.integer.value[0] = mod->gain; 966 967 return 0; 968} 969 970static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, 971 struct snd_ctl_elem_value *ucontrol) 972{ 973 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 974 struct audioreach_module *mod = dw->dobj.private; 975 976 mod->gain = ucontrol->value.integer.value[0]; 977 978 return 1; 979} 980 981static int audioreach_control_load_mix(struct snd_soc_component *scomp, 982 struct snd_ar_control *scontrol, 983 struct snd_kcontrol_new *kc, 984 struct snd_soc_tplg_ctl_hdr *hdr) 985{ 986 struct snd_soc_tplg_vendor_value_elem *c_elem; 987 struct snd_soc_tplg_vendor_array *c_array; 988 struct snd_soc_tplg_mixer_control *mc; 989 int tkn_count = 0; 990 991 mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); 992 c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data; 993 994 c_elem = c_array->value; 995 996 while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) { 997 switch (le32_to_cpu(c_elem->token)) { 998 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 999 scontrol->sgid = le32_to_cpu(c_elem->value); 1000 break; 1001 default: 1002 /* Ignore other tokens */ 1003 break; 1004 } 1005 c_elem++; 1006 tkn_count++; 1007 } 1008 1009 return 0; 1010} 1011 1012static int audioreach_control_load(struct snd_soc_component *scomp, int index, 1013 struct snd_kcontrol_new *kc, 1014 struct snd_soc_tplg_ctl_hdr *hdr) 1015{ 1016 struct snd_ar_control *scontrol; 1017 struct soc_mixer_control *sm; 1018 struct snd_soc_dobj *dobj; 1019 int ret = 0; 1020 1021 scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); 1022 if (!scontrol) 1023 return -ENOMEM; 1024 1025 scontrol->scomp = scomp; 1026 1027 switch (le32_to_cpu(hdr->ops.get)) { 1028 case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX: 1029 sm = (struct soc_mixer_control *)kc->private_value; 1030 dobj = &sm->dobj; 1031 ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr); 1032 break; 1033 case SND_SOC_AR_TPLG_VOL_CTL: 1034 sm = (struct soc_mixer_control *)kc->private_value; 1035 dobj = &sm->dobj; 1036 break; 1037 default: 1038 dev_warn(scomp->dev, "control type not supported %d:%d:%d\n", 1039 hdr->ops.get, hdr->ops.put, hdr->ops.info); 1040 kfree(scontrol); 1041 return -EINVAL; 1042 } 1043 1044 dobj->private = scontrol; 1045 return ret; 1046} 1047 1048static int audioreach_control_unload(struct snd_soc_component *scomp, 1049 struct snd_soc_dobj *dobj) 1050{ 1051 struct snd_ar_control *scontrol = dobj->private; 1052 1053 kfree(scontrol); 1054 1055 return 0; 1056} 1057 1058static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = { 1059 {SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer, 1060 audioreach_put_audio_mixer, snd_soc_info_volsw}, 1061 {SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer, 1062 audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw}, 1063}; 1064 1065static struct snd_soc_tplg_ops audioreach_tplg_ops = { 1066 .io_ops = audioreach_io_ops, 1067 .io_ops_count = ARRAY_SIZE(audioreach_io_ops), 1068 1069 .control_load = audioreach_control_load, 1070 .control_unload = audioreach_control_unload, 1071 1072 .widget_ready = audioreach_widget_ready, 1073 .widget_unload = audioreach_widget_unload, 1074 1075 .complete = audioreach_tplg_complete, 1076 .link_load = audioreach_link_load, 1077 1078 .dapm_route_load = audioreach_route_load, 1079 .dapm_route_unload = audioreach_route_unload, 1080}; 1081 1082int audioreach_tplg_init(struct snd_soc_component *component) 1083{ 1084 struct snd_soc_card *card = component->card; 1085 struct device *dev = component->dev; 1086 const struct firmware *fw; 1087 char *tplg_fw_name; 1088 int ret; 1089 1090 /* Inline with Qualcomm UCM configs and linux-firmware path */ 1091 tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name); 1092 if (!tplg_fw_name) 1093 return -ENOMEM; 1094 1095 ret = request_firmware(&fw, tplg_fw_name, dev); 1096 if (ret < 0) { 1097 dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); 1098 goto err; 1099 } 1100 1101 ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw); 1102 if (ret < 0) { 1103 dev_err(dev, "tplg component load failed%d\n", ret); 1104 ret = -EINVAL; 1105 } 1106 1107 release_firmware(fw); 1108err: 1109 kfree(tplg_fw_name); 1110 1111 return ret; 1112} 1113EXPORT_SYMBOL_GPL(audioreach_tplg_init);