xref: /linux/sound/soc/qcom/qdsp6/topology.c (revision d53b8e36925256097a08d7cb749198d85cbf9b2b)
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 
19 struct 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 
28 static 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 
66 static 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 
74 static 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 
116 static 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 
162 static 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 
209 static 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 
242 static 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 
275 static 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 
308 static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm,
309 						       struct snd_soc_tplg_private *private)
310 {
311 	struct snd_soc_tplg_vendor_value_elem *sg_elem;
312 	struct snd_soc_tplg_vendor_array *sg_array;
313 	struct audioreach_graph_info *info = NULL;
314 	int graph_id, sub_graph_id, tkn_count = 0;
315 	struct audioreach_sub_graph *sg;
316 	bool found;
317 
318 	sg_array = audioreach_get_sg_array(private);
319 	sg_elem = sg_array->value;
320 
321 	while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
322 		switch (le32_to_cpu(sg_elem->token)) {
323 		case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
324 			sub_graph_id = le32_to_cpu(sg_elem->value);
325 			sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found);
326 			if (IS_ERR(sg)) {
327 				return sg;
328 			} else if (found) {
329 				/* Already parsed data for this sub-graph */
330 				return sg;
331 			}
332 			break;
333 		case AR_TKN_DAI_INDEX:
334 			/* Sub graph is associated with predefined graph */
335 			graph_id = le32_to_cpu(sg_elem->value);
336 			info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found);
337 			if (IS_ERR(info))
338 				return ERR_CAST(info);
339 			break;
340 		case AR_TKN_U32_SUB_GRAPH_PERF_MODE:
341 			sg->perf_mode = le32_to_cpu(sg_elem->value);
342 			break;
343 		case AR_TKN_U32_SUB_GRAPH_DIRECTION:
344 			sg->direction = le32_to_cpu(sg_elem->value);
345 			break;
346 		case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID:
347 			sg->scenario_id = le32_to_cpu(sg_elem->value);
348 			break;
349 		default:
350 			dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token);
351 			break;
352 
353 		}
354 		tkn_count++;
355 		sg_elem++;
356 	}
357 
358 	/* Sub graph is associated with predefined graph */
359 	if (info)
360 		audioreach_tplg_add_sub_graph(sg, info);
361 
362 	return sg;
363 }
364 
365 static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm,
366 							 struct audioreach_sub_graph *sg,
367 							 struct snd_soc_tplg_private *private)
368 {
369 	struct snd_soc_tplg_vendor_value_elem *cont_elem;
370 	struct snd_soc_tplg_vendor_array *cont_array;
371 	struct audioreach_container *cont;
372 	int container_id, tkn_count = 0;
373 	bool found = false;
374 
375 	cont_array = audioreach_get_cont_array(private);
376 	cont_elem = cont_array->value;
377 
378 	while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
379 		switch (le32_to_cpu(cont_elem->token)) {
380 		case AR_TKN_U32_CONTAINER_INSTANCE_ID:
381 			container_id = le32_to_cpu(cont_elem->value);
382 			cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found);
383 			if (IS_ERR(cont) || found)/* Error or Already parsed container data */
384 				return cont;
385 			break;
386 		case AR_TKN_U32_CONTAINER_CAPABILITY_ID:
387 			cont->capability_id = le32_to_cpu(cont_elem->value);
388 			break;
389 		case AR_TKN_U32_CONTAINER_STACK_SIZE:
390 			cont->stack_size = le32_to_cpu(cont_elem->value);
391 			break;
392 		case AR_TKN_U32_CONTAINER_GRAPH_POS:
393 			cont->graph_pos = le32_to_cpu(cont_elem->value);
394 			break;
395 		case AR_TKN_U32_CONTAINER_PROC_DOMAIN:
396 			cont->proc_domain = le32_to_cpu(cont_elem->value);
397 			break;
398 		default:
399 			dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token);
400 			break;
401 
402 		}
403 		tkn_count++;
404 		cont_elem++;
405 	}
406 
407 	return cont;
408 }
409 
410 static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm,
411 							struct audioreach_container *cont,
412 							struct snd_soc_tplg_private *private,
413 							struct snd_soc_dapm_widget *w)
414 {
415 	uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
416 	uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, };
417 	uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, };
418 	uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, };
419 	uint32_t src_mod_inst_id = 0;
420 
421 	int module_id = 0, instance_id = 0, tkn_count = 0;
422 	struct snd_soc_tplg_vendor_value_elem *mod_elem;
423 	struct snd_soc_tplg_vendor_array *mod_array;
424 	struct audioreach_module *mod = NULL;
425 	uint32_t token;
426 	bool found;
427 	int max_tokens;
428 
429 	mod_array = audioreach_get_module_array(private);
430 	mod_elem = mod_array->value;
431 	max_tokens = le32_to_cpu(mod_array->num_elems);
432 	while (tkn_count <= (max_tokens - 1)) {
433 		token = le32_to_cpu(mod_elem->token);
434 		switch (token) {
435 		/* common module info */
436 		case AR_TKN_U32_MODULE_ID:
437 			module_id = le32_to_cpu(mod_elem->value);
438 			break;
439 		case AR_TKN_U32_MODULE_INSTANCE_ID:
440 			instance_id = le32_to_cpu(mod_elem->value);
441 			mod = audioreach_tplg_alloc_module(apm, cont, w,
442 							   instance_id, &found);
443 			if (IS_ERR(mod)) {
444 				return mod;
445 			} else if (found) {
446 				dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n",
447 					instance_id);
448 				return ERR_PTR(-EINVAL);
449 			}
450 
451 			break;
452 		case AR_TKN_U32_MODULE_MAX_IP_PORTS:
453 			max_ip_port = le32_to_cpu(mod_elem->value);
454 			break;
455 		case AR_TKN_U32_MODULE_MAX_OP_PORTS:
456 			max_op_port = le32_to_cpu(mod_elem->value);
457 			break;
458 		case AR_TKN_U32_MODULE_IN_PORTS:
459 			in_port = le32_to_cpu(mod_elem->value);
460 			break;
461 		case AR_TKN_U32_MODULE_OUT_PORTS:
462 			out_port = le32_to_cpu(mod_elem->value);
463 			break;
464 		case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
465 			src_mod_inst_id = le32_to_cpu(mod_elem->value);
466 			break;
467 		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
468 			src_mod_op_port_id[0] = le32_to_cpu(mod_elem->value);
469 			break;
470 		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID1:
471 			src_mod_op_port_id[1] = le32_to_cpu(mod_elem->value);
472 			break;
473 		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID2:
474 			src_mod_op_port_id[2] = le32_to_cpu(mod_elem->value);
475 			break;
476 		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID3:
477 			src_mod_op_port_id[3] = le32_to_cpu(mod_elem->value);
478 			break;
479 		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID4:
480 			src_mod_op_port_id[4] = le32_to_cpu(mod_elem->value);
481 			break;
482 		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID5:
483 			src_mod_op_port_id[5] = le32_to_cpu(mod_elem->value);
484 			break;
485 		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID6:
486 			src_mod_op_port_id[6] = le32_to_cpu(mod_elem->value);
487 			break;
488 		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID7:
489 			src_mod_op_port_id[7] = le32_to_cpu(mod_elem->value);
490 			break;
491 		case AR_TKN_U32_MODULE_DST_INSTANCE_ID:
492 			dst_mod_inst_id[0] = le32_to_cpu(mod_elem->value);
493 			break;
494 		case AR_TKN_U32_MODULE_DST_INSTANCE_ID1:
495 			dst_mod_inst_id[1] = le32_to_cpu(mod_elem->value);
496 			break;
497 		case AR_TKN_U32_MODULE_DST_INSTANCE_ID2:
498 			dst_mod_inst_id[2] = le32_to_cpu(mod_elem->value);
499 			break;
500 		case AR_TKN_U32_MODULE_DST_INSTANCE_ID3:
501 			dst_mod_inst_id[3] = le32_to_cpu(mod_elem->value);
502 			break;
503 		case AR_TKN_U32_MODULE_DST_INSTANCE_ID4:
504 			dst_mod_inst_id[4] = le32_to_cpu(mod_elem->value);
505 			break;
506 		case AR_TKN_U32_MODULE_DST_INSTANCE_ID5:
507 			dst_mod_inst_id[5] = le32_to_cpu(mod_elem->value);
508 			break;
509 		case AR_TKN_U32_MODULE_DST_INSTANCE_ID6:
510 			dst_mod_inst_id[6] = le32_to_cpu(mod_elem->value);
511 			break;
512 		case AR_TKN_U32_MODULE_DST_INSTANCE_ID7:
513 			dst_mod_inst_id[7] = le32_to_cpu(mod_elem->value);
514 			break;
515 		case AR_TKN_U32_MODULE_DST_IN_PORT_ID:
516 			dst_mod_ip_port_id[0] = le32_to_cpu(mod_elem->value);
517 			break;
518 		case AR_TKN_U32_MODULE_DST_IN_PORT_ID1:
519 			dst_mod_ip_port_id[1] = le32_to_cpu(mod_elem->value);
520 			break;
521 		case AR_TKN_U32_MODULE_DST_IN_PORT_ID2:
522 			dst_mod_ip_port_id[2] = le32_to_cpu(mod_elem->value);
523 			break;
524 		case AR_TKN_U32_MODULE_DST_IN_PORT_ID3:
525 			dst_mod_ip_port_id[3] = le32_to_cpu(mod_elem->value);
526 			break;
527 		case AR_TKN_U32_MODULE_DST_IN_PORT_ID4:
528 			dst_mod_ip_port_id[4] = le32_to_cpu(mod_elem->value);
529 			break;
530 		case AR_TKN_U32_MODULE_DST_IN_PORT_ID5:
531 			dst_mod_ip_port_id[5] = le32_to_cpu(mod_elem->value);
532 			break;
533 		case AR_TKN_U32_MODULE_DST_IN_PORT_ID6:
534 			dst_mod_ip_port_id[6] = le32_to_cpu(mod_elem->value);
535 			break;
536 		case AR_TKN_U32_MODULE_DST_IN_PORT_ID7:
537 			dst_mod_ip_port_id[7] = le32_to_cpu(mod_elem->value);
538 			break;
539 		default:
540 			break;
541 
542 		}
543 		tkn_count++;
544 		mod_elem++;
545 	}
546 
547 	if (mod) {
548 		int pn, id = 0;
549 
550 		mod->module_id = module_id;
551 		mod->max_ip_port = max_ip_port;
552 		mod->max_op_port = max_op_port;
553 		mod->in_port = in_port;
554 		mod->out_port = out_port;
555 		mod->src_mod_inst_id = src_mod_inst_id;
556 		for (pn = 0; pn < mod->max_op_port; pn++) {
557 			if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] &&
558 			    dst_mod_ip_port_id[pn]) {
559 				mod->src_mod_op_port_id[id] = src_mod_op_port_id[pn];
560 				mod->dst_mod_inst_id[id] = dst_mod_inst_id[pn];
561 				mod->dst_mod_ip_port_id[id] = dst_mod_ip_port_id[pn];
562 				id++;
563 				mod->num_connections = id;
564 			}
565 		}
566 	}
567 
568 	return mod;
569 }
570 
571 static int audioreach_widget_load_module_common(struct snd_soc_component *component,
572 						int index, struct snd_soc_dapm_widget *w,
573 						struct snd_soc_tplg_dapm_widget *tplg_w)
574 {
575 	struct q6apm *apm = dev_get_drvdata(component->dev);
576 	struct audioreach_container *cont;
577 	struct audioreach_sub_graph *sg;
578 	struct audioreach_module *mod;
579 	struct snd_soc_dobj *dobj;
580 
581 	sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv);
582 	if (IS_ERR(sg))
583 		return PTR_ERR(sg);
584 
585 	cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv);
586 	if (IS_ERR(cont))
587 		return PTR_ERR(cont);
588 
589 	mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w);
590 	if (IS_ERR(mod))
591 		return PTR_ERR(mod);
592 
593 	dobj = &w->dobj;
594 	dobj->private = mod;
595 
596 	return 0;
597 }
598 
599 static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component,
600 					      int index, struct snd_soc_dapm_widget *w,
601 					      struct snd_soc_tplg_dapm_widget *tplg_w)
602 {
603 	struct snd_soc_tplg_vendor_value_elem *mod_elem;
604 	struct snd_soc_tplg_vendor_array *mod_array;
605 	struct audioreach_module *mod;
606 	struct snd_soc_dobj *dobj;
607 	int tkn_count = 0;
608 	int ret;
609 
610 	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
611 	if (ret)
612 		return ret;
613 
614 	dobj = &w->dobj;
615 	mod = dobj->private;
616 	mod_array = audioreach_get_module_array(&tplg_w->priv);
617 	mod_elem = mod_array->value;
618 
619 	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
620 		switch (le32_to_cpu(mod_elem->token)) {
621 		case AR_TKN_U32_MODULE_FMT_INTERLEAVE:
622 			mod->interleave_type = le32_to_cpu(mod_elem->value);
623 			break;
624 		case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE:
625 			mod->rate = le32_to_cpu(mod_elem->value);
626 			break;
627 		case AR_TKN_U32_MODULE_FMT_BIT_DEPTH:
628 			mod->bit_depth = le32_to_cpu(mod_elem->value);
629 			break;
630 		default:
631 			break;
632 		}
633 		tkn_count++;
634 		mod_elem++;
635 	}
636 
637 	return 0;
638 }
639 
640 static int audioreach_widget_log_module_load(struct audioreach_module *mod,
641 					     struct snd_soc_tplg_vendor_array *mod_array)
642 {
643 	struct snd_soc_tplg_vendor_value_elem *mod_elem;
644 	int tkn_count = 0;
645 
646 	mod_elem = mod_array->value;
647 
648 	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
649 		switch (le32_to_cpu(mod_elem->token)) {
650 
651 		case AR_TKN_U32_MODULE_LOG_CODE:
652 			mod->log_code = le32_to_cpu(mod_elem->value);
653 			break;
654 		case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID:
655 			mod->log_tap_point_id = le32_to_cpu(mod_elem->value);
656 			break;
657 		case AR_TKN_U32_MODULE_LOG_MODE:
658 			mod->log_mode = le32_to_cpu(mod_elem->value);
659 			break;
660 		default:
661 			break;
662 		}
663 		tkn_count++;
664 		mod_elem++;
665 	}
666 
667 	return 0;
668 }
669 
670 static int audioreach_widget_dma_module_load(struct audioreach_module *mod,
671 					     struct snd_soc_tplg_vendor_array *mod_array)
672 {
673 	struct snd_soc_tplg_vendor_value_elem *mod_elem;
674 	int tkn_count = 0;
675 
676 	mod_elem = mod_array->value;
677 
678 	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
679 		switch (le32_to_cpu(mod_elem->token)) {
680 		case AR_TKN_U32_MODULE_HW_IF_IDX:
681 			mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
682 			break;
683 		case AR_TKN_U32_MODULE_FMT_DATA:
684 			mod->data_format = le32_to_cpu(mod_elem->value);
685 			break;
686 		case AR_TKN_U32_MODULE_HW_IF_TYPE:
687 			mod->hw_interface_type = le32_to_cpu(mod_elem->value);
688 			break;
689 		default:
690 			break;
691 		}
692 		tkn_count++;
693 		mod_elem++;
694 	}
695 
696 	return 0;
697 }
698 
699 static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
700 					     struct snd_soc_tplg_vendor_array *mod_array)
701 {
702 	struct snd_soc_tplg_vendor_value_elem *mod_elem;
703 	int tkn_count = 0;
704 
705 	mod_elem = mod_array->value;
706 
707 	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
708 		switch (le32_to_cpu(mod_elem->token)) {
709 		case AR_TKN_U32_MODULE_HW_IF_IDX:
710 			mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
711 			break;
712 		case AR_TKN_U32_MODULE_FMT_DATA:
713 			mod->data_format = le32_to_cpu(mod_elem->value);
714 			break;
715 		case AR_TKN_U32_MODULE_HW_IF_TYPE:
716 			mod->hw_interface_type = le32_to_cpu(mod_elem->value);
717 			break;
718 		case AR_TKN_U32_MODULE_SD_LINE_IDX:
719 			mod->sd_line_idx = le32_to_cpu(mod_elem->value);
720 			break;
721 		case AR_TKN_U32_MODULE_WS_SRC:
722 			mod->ws_src = le32_to_cpu(mod_elem->value);
723 			break;
724 		default:
725 			break;
726 		}
727 		tkn_count++;
728 		mod_elem++;
729 	}
730 
731 	return 0;
732 }
733 
734 static int audioreach_widget_dp_module_load(struct audioreach_module *mod,
735 					struct snd_soc_tplg_vendor_array *mod_array)
736 {
737 	struct snd_soc_tplg_vendor_value_elem *mod_elem;
738 	int tkn_count = 0;
739 
740 	mod_elem = mod_array->value;
741 
742 	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
743 		switch (le32_to_cpu(mod_elem->token)) {
744 		case AR_TKN_U32_MODULE_FMT_DATA:
745 			mod->data_format = le32_to_cpu(mod_elem->value);
746 			break;
747 		default:
748 			break;
749 		}
750 		tkn_count++;
751 		mod_elem++;
752 	}
753 
754 	return 0;
755 }
756 
757 static int audioreach_widget_load_buffer(struct snd_soc_component *component,
758 					 int index, struct snd_soc_dapm_widget *w,
759 					 struct snd_soc_tplg_dapm_widget *tplg_w)
760 {
761 	struct snd_soc_tplg_vendor_array *mod_array;
762 	struct audioreach_module *mod;
763 	struct snd_soc_dobj *dobj;
764 	int ret;
765 
766 	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
767 	if (ret)
768 		return ret;
769 
770 	dobj = &w->dobj;
771 	mod = dobj->private;
772 
773 	mod_array = audioreach_get_module_array(&tplg_w->priv);
774 
775 	switch (mod->module_id) {
776 	case MODULE_ID_CODEC_DMA_SINK:
777 	case MODULE_ID_CODEC_DMA_SOURCE:
778 		audioreach_widget_dma_module_load(mod, mod_array);
779 		break;
780 	case MODULE_ID_DATA_LOGGING:
781 		audioreach_widget_log_module_load(mod, mod_array);
782 		break;
783 	case MODULE_ID_I2S_SINK:
784 	case MODULE_ID_I2S_SOURCE:
785 		audioreach_widget_i2s_module_load(mod, mod_array);
786 		break;
787 	case MODULE_ID_DISPLAY_PORT_SINK:
788 		audioreach_widget_dp_module_load(mod, mod_array);
789 		break;
790 	default:
791 		return -EINVAL;
792 	}
793 
794 	return 0;
795 }
796 
797 static int audioreach_widget_load_mixer(struct snd_soc_component *component,
798 					int index, struct snd_soc_dapm_widget *w,
799 					struct snd_soc_tplg_dapm_widget *tplg_w)
800 {
801 	struct snd_soc_tplg_vendor_value_elem *w_elem;
802 	struct snd_soc_tplg_vendor_array *w_array;
803 	struct snd_ar_control *scontrol;
804 	struct q6apm *data = dev_get_drvdata(component->dev);
805 	struct snd_soc_dobj *dobj;
806 	int tkn_count = 0;
807 
808 	w_array = &tplg_w->priv.array[0];
809 
810 	scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
811 	if (!scontrol)
812 		return -ENOMEM;
813 
814 	scontrol->scomp = component;
815 	dobj = &w->dobj;
816 	dobj->private = scontrol;
817 
818 	w_elem = w_array->value;
819 	while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) {
820 		switch (le32_to_cpu(w_elem->token)) {
821 		case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
822 			scontrol->sgid = le32_to_cpu(w_elem->value);
823 			break;
824 		case AR_TKN_DAI_INDEX:
825 			scontrol->graph_id = le32_to_cpu(w_elem->value);
826 			break;
827 		default: /* ignore other tokens */
828 			break;
829 		}
830 		tkn_count++;
831 		w_elem++;
832 	}
833 
834 	scontrol->w = w;
835 	list_add_tail(&scontrol->node, &data->widget_list);
836 
837 	return 0;
838 }
839 
840 static int audioreach_pga_event(struct snd_soc_dapm_widget *w,
841 				struct snd_kcontrol *kcontrol, int event)
842 
843 {
844 	struct snd_soc_dapm_context *dapm = w->dapm;
845 	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
846 	struct audioreach_module *mod = w->dobj.private;
847 	struct q6apm *apm = dev_get_drvdata(c->dev);
848 
849 	switch (event) {
850 	case SND_SOC_DAPM_POST_PMU:
851 		/* apply gain after power up of widget */
852 		audioreach_gain_set_vol_ctrl(apm, mod, mod->gain);
853 		break;
854 	default:
855 		break;
856 	}
857 
858 	return 0;
859 }
860 
861 static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = {
862 	{ AR_PGA_DAPM_EVENT, audioreach_pga_event },
863 };
864 
865 static int audioreach_widget_load_pga(struct snd_soc_component *component,
866 				      int index, struct snd_soc_dapm_widget *w,
867 				      struct snd_soc_tplg_dapm_widget *tplg_w)
868 {
869 	struct audioreach_module *mod;
870 	struct snd_soc_dobj *dobj;
871 	int ret;
872 
873 	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
874 	if (ret)
875 		return ret;
876 
877 	dobj = &w->dobj;
878 	mod = dobj->private;
879 	mod->gain = VOL_CTRL_DEFAULT_GAIN;
880 
881 	ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops,
882 					     ARRAY_SIZE(audioreach_widget_ops),
883 					     le16_to_cpu(tplg_w->event_type));
884 	if (ret) {
885 		dev_err(component->dev, "matching event handlers NOT found for %d\n",
886 			le16_to_cpu(tplg_w->event_type));
887 		return -EINVAL;
888 	}
889 
890 	return 0;
891 }
892 
893 static int audioreach_widget_ready(struct snd_soc_component *component,
894 				   int index, struct snd_soc_dapm_widget *w,
895 				   struct snd_soc_tplg_dapm_widget *tplg_w)
896 {
897 	switch (w->id) {
898 	case snd_soc_dapm_aif_in:
899 	case snd_soc_dapm_aif_out:
900 		audioreach_widget_load_buffer(component, index, w, tplg_w);
901 		break;
902 	case snd_soc_dapm_decoder:
903 	case snd_soc_dapm_encoder:
904 	case snd_soc_dapm_src:
905 		audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w);
906 		break;
907 	case snd_soc_dapm_buffer:
908 		audioreach_widget_load_buffer(component, index, w, tplg_w);
909 		break;
910 	case snd_soc_dapm_mixer:
911 		return audioreach_widget_load_mixer(component, index, w, tplg_w);
912 	case snd_soc_dapm_pga:
913 		return audioreach_widget_load_pga(component, index, w, tplg_w);
914 	case snd_soc_dapm_dai_link:
915 	case snd_soc_dapm_scheduler:
916 	case snd_soc_dapm_out_drv:
917 	default:
918 		dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id);
919 		break;
920 	}
921 
922 	return 0;
923 }
924 
925 static int audioreach_widget_unload(struct snd_soc_component *scomp,
926 				    struct snd_soc_dobj *dobj)
927 {
928 	struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj);
929 	struct q6apm *apm = dev_get_drvdata(scomp->dev);
930 	struct audioreach_container *cont;
931 	struct audioreach_module *mod;
932 
933 	mod = dobj->private;
934 	cont = mod->container;
935 
936 	if (w->id == snd_soc_dapm_mixer) {
937 		/* virtual widget */
938 		struct snd_ar_control *scontrol = dobj->private;
939 
940 		list_del(&scontrol->node);
941 		kfree(scontrol);
942 		return 0;
943 	}
944 
945 	mutex_lock(&apm->lock);
946 	idr_remove(&apm->modules_idr, mod->instance_id);
947 	cont->num_modules--;
948 
949 	list_del(&mod->node);
950 	kfree(mod);
951 	/* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */
952 	if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */
953 		struct audioreach_sub_graph *sg = cont->sub_graph;
954 
955 		idr_remove(&apm->containers_idr, cont->container_id);
956 		list_del(&cont->node);
957 		sg->num_containers--;
958 		kfree(cont);
959 		/* check if there are no more containers in the sub graph and remove it */
960 		if (list_empty(&sg->container_list)) {
961 			struct audioreach_graph_info *info = sg->info;
962 
963 			idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id);
964 			list_del(&sg->node);
965 			info->num_sub_graphs--;
966 			kfree(sg);
967 			/* Check if there are no more sub-graphs left then remove graph info */
968 			if (list_empty(&info->sg_list)) {
969 				idr_remove(&apm->graph_info_idr, info->id);
970 				kfree(info);
971 			}
972 		}
973 	}
974 
975 	mutex_unlock(&apm->lock);
976 
977 	return 0;
978 }
979 
980 static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp,
981 						     const char *name)
982 {
983 	struct q6apm *apm = dev_get_drvdata(comp->dev);
984 	struct snd_ar_control *control;
985 
986 	list_for_each_entry(control, &apm->widget_list, node) {
987 		if (control->w && !strcmp(name, control->w->name))
988 			return control;
989 	}
990 
991 	return NULL;
992 }
993 
994 static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp,
995 							const char *name)
996 {
997 	struct q6apm *apm = dev_get_drvdata(comp->dev);
998 	struct audioreach_module *module;
999 	int id;
1000 
1001 	idr_for_each_entry(&apm->modules_idr, module, id) {
1002 		if (!strcmp(name, module->widget->name))
1003 			return module;
1004 	}
1005 
1006 	return NULL;
1007 }
1008 
1009 static int audioreach_route_load(struct snd_soc_component *scomp, int index,
1010 				 struct snd_soc_dapm_route *route)
1011 {
1012 	struct audioreach_module *src_module, *sink_module;
1013 	struct snd_ar_control *control;
1014 	struct snd_soc_dapm_widget *w;
1015 	int i;
1016 
1017 	/* check if these are actual modules */
1018 	src_module = audioreach_find_module(scomp, route->source);
1019 	sink_module = audioreach_find_module(scomp, route->sink);
1020 
1021 	if (sink_module && !src_module) {
1022 		control = audioreach_find_widget(scomp, route->source);
1023 		if (control)
1024 			control->module_instance_id = sink_module->instance_id;
1025 
1026 	} else if (!sink_module && src_module && route->control) {
1027 		/* check if this is a virtual mixer */
1028 		control = audioreach_find_widget(scomp, route->sink);
1029 		if (!control || !control->w)
1030 			return 0;
1031 
1032 		w = control->w;
1033 
1034 		for (i = 0; i < w->num_kcontrols; i++) {
1035 			if (!strcmp(route->control, w->kcontrol_news[i].name)) {
1036 				struct soc_mixer_control *sm;
1037 				struct snd_soc_dobj *dobj;
1038 				struct snd_ar_control *scontrol;
1039 
1040 				sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value;
1041 				dobj = &sm->dobj;
1042 				scontrol = dobj->private;
1043 				scontrol->module_instance_id = src_module->instance_id;
1044 			}
1045 		}
1046 
1047 	}
1048 
1049 	return 0;
1050 }
1051 
1052 static int audioreach_route_unload(struct snd_soc_component *scomp,
1053 				   struct snd_soc_dobj *dobj)
1054 {
1055 	return 0;
1056 }
1057 
1058 static int audioreach_tplg_complete(struct snd_soc_component *component)
1059 {
1060 	/* TBD */
1061 	return 0;
1062 }
1063 
1064 /* DAI link - used for any driver specific init */
1065 static int audioreach_link_load(struct snd_soc_component *component, int index,
1066 				struct snd_soc_dai_link *link,
1067 				struct snd_soc_tplg_link_config *cfg)
1068 {
1069 	link->nonatomic = true;
1070 	link->dynamic = true;
1071 	link->platforms->name = NULL;
1072 	link->platforms->of_node = of_get_compatible_child(component->dev->of_node,
1073 							   "qcom,q6apm-dais");
1074 	return 0;
1075 }
1076 
1077 static void audioreach_connect_sub_graphs(struct q6apm *apm,
1078 					  struct snd_ar_control *m1,
1079 					  struct snd_ar_control *m2,
1080 					  bool connect)
1081 {
1082 	struct audioreach_graph_info *info;
1083 
1084 	mutex_lock(&apm->lock);
1085 	info = idr_find(&apm->graph_info_idr, m2->graph_id);
1086 	mutex_unlock(&apm->lock);
1087 
1088 	if (connect) {
1089 		info->src_mod_inst_id = m1->module_instance_id;
1090 		info->src_mod_op_port_id = 1;
1091 		info->dst_mod_inst_id = m2->module_instance_id;
1092 		info->dst_mod_ip_port_id = 2;
1093 
1094 	} else {
1095 		info->src_mod_inst_id = 0;
1096 		info->src_mod_op_port_id = 0;
1097 		info->dst_mod_inst_id = 0;
1098 		info->dst_mod_ip_port_id = 0;
1099 	}
1100 }
1101 
1102 static bool audioreach_is_vmixer_connected(struct q6apm *apm,
1103 					   struct snd_ar_control *m1,
1104 					   struct snd_ar_control *m2)
1105 {
1106 	struct audioreach_graph_info *info;
1107 
1108 	mutex_lock(&apm->lock);
1109 	info = idr_find(&apm->graph_info_idr, m2->graph_id);
1110 	mutex_unlock(&apm->lock);
1111 
1112 	if (info->dst_mod_inst_id == m2->module_instance_id &&
1113 	    info->src_mod_inst_id == m1->module_instance_id)
1114 		return true;
1115 
1116 	return false;
1117 }
1118 
1119 static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
1120 				      struct snd_ctl_elem_value *ucontrol)
1121 {
1122 	struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
1123 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
1124 	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1125 	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
1126 	struct snd_ar_control *dapm_scontrol = dw->dobj.private;
1127 	struct snd_ar_control *scontrol = mc->dobj.private;
1128 	struct q6apm *data = dev_get_drvdata(c->dev);
1129 	bool connected;
1130 
1131 	connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol);
1132 	if (connected)
1133 		ucontrol->value.integer.value[0] = 1;
1134 	else
1135 		ucontrol->value.integer.value[0] = 0;
1136 
1137 	return 0;
1138 }
1139 
1140 static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
1141 				      struct snd_ctl_elem_value *ucontrol)
1142 {
1143 	struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
1144 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
1145 	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1146 	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
1147 	struct snd_ar_control *dapm_scontrol = dw->dobj.private;
1148 	struct snd_ar_control *scontrol = mc->dobj.private;
1149 	struct q6apm *data = dev_get_drvdata(c->dev);
1150 
1151 	if (ucontrol->value.integer.value[0]) {
1152 		audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true);
1153 		snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
1154 	} else {
1155 		audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false);
1156 		snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
1157 	}
1158 	return 0;
1159 }
1160 
1161 static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
1162 					       struct snd_ctl_elem_value *ucontrol)
1163 {
1164 	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1165 	struct audioreach_module *mod = dw->dobj.private;
1166 
1167 	ucontrol->value.integer.value[0] = mod->gain;
1168 
1169 	return 0;
1170 }
1171 
1172 static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
1173 					       struct snd_ctl_elem_value *ucontrol)
1174 {
1175 	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1176 	struct audioreach_module *mod = dw->dobj.private;
1177 
1178 	mod->gain = ucontrol->value.integer.value[0];
1179 
1180 	return 1;
1181 }
1182 
1183 static int audioreach_control_load_mix(struct snd_soc_component *scomp,
1184 				       struct snd_ar_control *scontrol,
1185 				       struct snd_kcontrol_new *kc,
1186 				       struct snd_soc_tplg_ctl_hdr *hdr)
1187 {
1188 	struct snd_soc_tplg_vendor_value_elem *c_elem;
1189 	struct snd_soc_tplg_vendor_array *c_array;
1190 	struct snd_soc_tplg_mixer_control *mc;
1191 	int tkn_count = 0;
1192 
1193 	mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
1194 	c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data;
1195 
1196 	c_elem = c_array->value;
1197 
1198 	while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) {
1199 		switch (le32_to_cpu(c_elem->token)) {
1200 		case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
1201 			scontrol->sgid = le32_to_cpu(c_elem->value);
1202 			break;
1203 		case AR_TKN_DAI_INDEX:
1204 			scontrol->graph_id = le32_to_cpu(c_elem->value);
1205 			break;
1206 		default:
1207 			/* Ignore other tokens */
1208 			break;
1209 		}
1210 		c_elem++;
1211 		tkn_count++;
1212 	}
1213 
1214 	return 0;
1215 }
1216 
1217 static int audioreach_control_load(struct snd_soc_component *scomp, int index,
1218 				   struct snd_kcontrol_new *kc,
1219 				   struct snd_soc_tplg_ctl_hdr *hdr)
1220 {
1221 	struct snd_ar_control *scontrol;
1222 	struct soc_mixer_control *sm;
1223 	struct snd_soc_dobj *dobj;
1224 	int ret = 0;
1225 
1226 	scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
1227 	if (!scontrol)
1228 		return -ENOMEM;
1229 
1230 	scontrol->scomp = scomp;
1231 
1232 	switch (le32_to_cpu(hdr->ops.get)) {
1233 	case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX:
1234 		sm = (struct soc_mixer_control *)kc->private_value;
1235 		dobj = &sm->dobj;
1236 		ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr);
1237 		break;
1238 	case SND_SOC_AR_TPLG_VOL_CTL:
1239 		sm = (struct soc_mixer_control *)kc->private_value;
1240 		dobj = &sm->dobj;
1241 		break;
1242 	default:
1243 		dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
1244 			 hdr->ops.get, hdr->ops.put, hdr->ops.info);
1245 		kfree(scontrol);
1246 		return -EINVAL;
1247 	}
1248 
1249 	dobj->private = scontrol;
1250 	return ret;
1251 }
1252 
1253 static int audioreach_control_unload(struct snd_soc_component *scomp,
1254 				     struct snd_soc_dobj *dobj)
1255 {
1256 	struct snd_ar_control *scontrol = dobj->private;
1257 
1258 	kfree(scontrol);
1259 
1260 	return 0;
1261 }
1262 
1263 static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
1264 	{SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer,
1265 		audioreach_put_audio_mixer, snd_soc_info_volsw},
1266 	{SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer,
1267 		audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
1268 };
1269 
1270 static const struct snd_soc_tplg_ops audioreach_tplg_ops = {
1271 	.io_ops = audioreach_io_ops,
1272 	.io_ops_count = ARRAY_SIZE(audioreach_io_ops),
1273 
1274 	.control_load	= audioreach_control_load,
1275 	.control_unload	= audioreach_control_unload,
1276 
1277 	.widget_ready = audioreach_widget_ready,
1278 	.widget_unload = audioreach_widget_unload,
1279 
1280 	.complete = audioreach_tplg_complete,
1281 	.link_load = audioreach_link_load,
1282 
1283 	.dapm_route_load	= audioreach_route_load,
1284 	.dapm_route_unload	= audioreach_route_unload,
1285 };
1286 
1287 int audioreach_tplg_init(struct snd_soc_component *component)
1288 {
1289 	struct snd_soc_card *card = component->card;
1290 	struct device *dev = component->dev;
1291 	const struct firmware *fw;
1292 	int ret;
1293 
1294 	/* Inline with Qualcomm UCM configs and linux-firmware path */
1295 	char *tplg_fw_name __free(kfree) = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin",
1296 						     card->driver_name,
1297 						     card->name);
1298 	if (!tplg_fw_name)
1299 		return -ENOMEM;
1300 
1301 	ret = request_firmware(&fw, tplg_fw_name, dev);
1302 	if (ret < 0) {
1303 		dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret);
1304 		return ret;
1305 	}
1306 
1307 	ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw);
1308 	if (ret < 0) {
1309 		if (ret != -EPROBE_DEFER)
1310 			dev_err(dev, "tplg component load failed: %d\n", ret);
1311 	}
1312 
1313 	release_firmware(fw);
1314 
1315 	return ret;
1316 }
1317 EXPORT_SYMBOL_GPL(audioreach_tplg_init);
1318