File Index
Files and directories
Sign in
FILE

topology.c

File preview with syntax highlighting.

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