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