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
549		mod->module_id = module_id;
550		mod->max_ip_port = max_ip_port;
551		mod->max_op_port = max_op_port;
552		mod->in_port = in_port;
553		mod->out_port = out_port;
554		mod->src_mod_inst_id = src_mod_inst_id;
555		for (pn = 0; pn < mod->max_op_port; pn++) {
556			if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] &&
557			    dst_mod_ip_port_id[pn]) {
558				mod->src_mod_op_port_id[id] = src_mod_op_port_id[pn];
559				mod->dst_mod_inst_id[id] = dst_mod_inst_id[pn];
560				mod->dst_mod_ip_port_id[id] = dst_mod_ip_port_id[pn];
561				id++;
562				mod->num_connections = id;
563			}
564		}
565	}
566
567	return mod;
568}
569
570static int audioreach_widget_load_module_common(struct snd_soc_component *component,
571						int index, struct snd_soc_dapm_widget *w,
572						struct snd_soc_tplg_dapm_widget *tplg_w)
573{
574	struct q6apm *apm = dev_get_drvdata(component->dev);
575	struct audioreach_container *cont;
576	struct audioreach_sub_graph *sg;
577	struct audioreach_module *mod;
578	struct snd_soc_dobj *dobj;
579
580	sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv);
581	if (IS_ERR(sg))
582		return PTR_ERR(sg);
583
584	cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv);
585	if (IS_ERR(cont))
586		return PTR_ERR(cont);
587
588	mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w);
589	if (IS_ERR(mod))
590		return PTR_ERR(mod);
591
592	dobj = &w->dobj;
593	dobj->private = mod;
594
595	return 0;
596}
597
598static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component,
599					      int index, struct snd_soc_dapm_widget *w,
600					      struct snd_soc_tplg_dapm_widget *tplg_w)
601{
602	struct snd_soc_tplg_vendor_value_elem *mod_elem;
603	struct snd_soc_tplg_vendor_array *mod_array;
604	struct audioreach_module *mod;
605	struct snd_soc_dobj *dobj;
606	int tkn_count = 0;
607	int ret;
608
609	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
610	if (ret)
611		return ret;
612
613	dobj = &w->dobj;
614	mod = dobj->private;
615	mod_array = audioreach_get_module_array(&tplg_w->priv);
616	mod_elem = mod_array->value;
617
618	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
619		switch (le32_to_cpu(mod_elem->token)) {
620		case AR_TKN_U32_MODULE_FMT_INTERLEAVE:
621			mod->interleave_type = le32_to_cpu(mod_elem->value);
622			break;
623		case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE:
624			mod->rate = le32_to_cpu(mod_elem->value);
625			break;
626		case AR_TKN_U32_MODULE_FMT_BIT_DEPTH:
627			mod->bit_depth = le32_to_cpu(mod_elem->value);
628			break;
629		default:
630			break;
631		}
632		tkn_count++;
633		mod_elem++;
634	}
635
636	return 0;
637}
638
639static int audioreach_widget_log_module_load(struct audioreach_module *mod,
640					     struct snd_soc_tplg_vendor_array *mod_array)
641{
642	struct snd_soc_tplg_vendor_value_elem *mod_elem;
643	int tkn_count = 0;
644
645	mod_elem = mod_array->value;
646
647	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
648		switch (le32_to_cpu(mod_elem->token)) {
649
650		case AR_TKN_U32_MODULE_LOG_CODE:
651			mod->log_code = le32_to_cpu(mod_elem->value);
652			break;
653		case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID:
654			mod->log_tap_point_id = le32_to_cpu(mod_elem->value);
655			break;
656		case AR_TKN_U32_MODULE_LOG_MODE:
657			mod->log_mode = le32_to_cpu(mod_elem->value);
658			break;
659		default:
660			break;
661		}
662		tkn_count++;
663		mod_elem++;
664	}
665
666	return 0;
667}
668
669static int audioreach_widget_dma_module_load(struct audioreach_module *mod,
670					     struct snd_soc_tplg_vendor_array *mod_array)
671{
672	struct snd_soc_tplg_vendor_value_elem *mod_elem;
673	int tkn_count = 0;
674
675	mod_elem = mod_array->value;
676
677	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
678		switch (le32_to_cpu(mod_elem->token)) {
679		case AR_TKN_U32_MODULE_HW_IF_IDX:
680			mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
681			break;
682		case AR_TKN_U32_MODULE_FMT_DATA:
683			mod->data_format = le32_to_cpu(mod_elem->value);
684			break;
685		case AR_TKN_U32_MODULE_HW_IF_TYPE:
686			mod->hw_interface_type = le32_to_cpu(mod_elem->value);
687			break;
688		default:
689			break;
690		}
691		tkn_count++;
692		mod_elem++;
693	}
694
695	return 0;
696}
697
698static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
699					     struct snd_soc_tplg_vendor_array *mod_array)
700{
701	struct snd_soc_tplg_vendor_value_elem *mod_elem;
702	int tkn_count = 0;
703
704	mod_elem = mod_array->value;
705
706	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
707		switch (le32_to_cpu(mod_elem->token)) {
708		case AR_TKN_U32_MODULE_HW_IF_IDX:
709			mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
710			break;
711		case AR_TKN_U32_MODULE_FMT_DATA:
712			mod->data_format = le32_to_cpu(mod_elem->value);
713			break;
714		case AR_TKN_U32_MODULE_HW_IF_TYPE:
715			mod->hw_interface_type = le32_to_cpu(mod_elem->value);
716			break;
717		case AR_TKN_U32_MODULE_SD_LINE_IDX:
718			mod->sd_line_idx = le32_to_cpu(mod_elem->value);
719			break;
720		case AR_TKN_U32_MODULE_WS_SRC:
721			mod->ws_src = le32_to_cpu(mod_elem->value);
722			break;
723		default:
724			break;
725		}
726		tkn_count++;
727		mod_elem++;
728	}
729
730	return 0;
731}
732
733static int audioreach_widget_load_buffer(struct snd_soc_component *component,
734					 int index, struct snd_soc_dapm_widget *w,
735					 struct snd_soc_tplg_dapm_widget *tplg_w)
736{
737	struct snd_soc_tplg_vendor_array *mod_array;
738	struct audioreach_module *mod;
739	struct snd_soc_dobj *dobj;
740	int ret;
741
742	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
743	if (ret)
744		return ret;
745
746	dobj = &w->dobj;
747	mod = dobj->private;
748
749	mod_array = audioreach_get_module_array(&tplg_w->priv);
750
751	switch (mod->module_id) {
752	case MODULE_ID_CODEC_DMA_SINK:
753	case MODULE_ID_CODEC_DMA_SOURCE:
754		audioreach_widget_dma_module_load(mod, mod_array);
755		break;
756	case MODULE_ID_DATA_LOGGING:
757		audioreach_widget_log_module_load(mod, mod_array);
758		break;
759	case MODULE_ID_I2S_SINK:
760	case MODULE_ID_I2S_SOURCE:
761		audioreach_widget_i2s_module_load(mod, mod_array);
762		break;
763	default:
764		return -EINVAL;
765	}
766
767	return 0;
768}
769
770static int audioreach_widget_load_mixer(struct snd_soc_component *component,
771					int index, struct snd_soc_dapm_widget *w,
772					struct snd_soc_tplg_dapm_widget *tplg_w)
773{
774	struct snd_soc_tplg_vendor_value_elem *w_elem;
775	struct snd_soc_tplg_vendor_array *w_array;
776	struct snd_ar_control *scontrol;
777	struct q6apm *data = dev_get_drvdata(component->dev);
778	struct snd_soc_dobj *dobj;
779	int tkn_count = 0;
780
781	w_array = &tplg_w->priv.array[0];
782
783	scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
784	if (!scontrol)
785		return -ENOMEM;
786
787	scontrol->scomp = component;
788	dobj = &w->dobj;
789	dobj->private = scontrol;
790
791	w_elem = w_array->value;
792	while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) {
793		switch (le32_to_cpu(w_elem->token)) {
794		case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
795			scontrol->sgid = le32_to_cpu(w_elem->value);
796			break;
797		case AR_TKN_DAI_INDEX:
798			scontrol->graph_id = le32_to_cpu(w_elem->value);
799			break;
800		default: /* ignore other tokens */
801			break;
802		}
803		tkn_count++;
804		w_elem++;
805	}
806
807	scontrol->w = w;
808	list_add_tail(&scontrol->node, &data->widget_list);
809
810	return 0;
811}
812
813static int audioreach_pga_event(struct snd_soc_dapm_widget *w,
814				struct snd_kcontrol *kcontrol, int event)
815
816{
817	struct snd_soc_dapm_context *dapm = w->dapm;
818	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
819	struct audioreach_module *mod = w->dobj.private;
820	struct q6apm *apm = dev_get_drvdata(c->dev);
821
822	switch (event) {
823	case SND_SOC_DAPM_POST_PMU:
824		/* apply gain after power up of widget */
825		audioreach_gain_set_vol_ctrl(apm, mod, mod->gain);
826		break;
827	default:
828		break;
829	}
830
831	return 0;
832}
833
834static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = {
835	{ AR_PGA_DAPM_EVENT, audioreach_pga_event },
836};
837
838static int audioreach_widget_load_pga(struct snd_soc_component *component,
839				      int index, struct snd_soc_dapm_widget *w,
840				      struct snd_soc_tplg_dapm_widget *tplg_w)
841{
842	struct audioreach_module *mod;
843	struct snd_soc_dobj *dobj;
844	int ret;
845
846	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
847	if (ret)
848		return ret;
849
850	dobj = &w->dobj;
851	mod = dobj->private;
852	mod->gain = VOL_CTRL_DEFAULT_GAIN;
853
854	ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops,
855					     ARRAY_SIZE(audioreach_widget_ops),
856					     le16_to_cpu(tplg_w->event_type));
857	if (ret) {
858		dev_err(component->dev, "matching event handlers NOT found for %d\n",
859			le16_to_cpu(tplg_w->event_type));
860		return -EINVAL;
861	}
862
863	return 0;
864}
865
866static int audioreach_widget_ready(struct snd_soc_component *component,
867				   int index, struct snd_soc_dapm_widget *w,
868				   struct snd_soc_tplg_dapm_widget *tplg_w)
869{
870	switch (w->id) {
871	case snd_soc_dapm_aif_in:
872	case snd_soc_dapm_aif_out:
873		audioreach_widget_load_buffer(component, index, w, tplg_w);
874		break;
875	case snd_soc_dapm_decoder:
876	case snd_soc_dapm_encoder:
877	case snd_soc_dapm_src:
878		audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w);
879		break;
880	case snd_soc_dapm_buffer:
881		audioreach_widget_load_buffer(component, index, w, tplg_w);
882		break;
883	case snd_soc_dapm_mixer:
884		return audioreach_widget_load_mixer(component, index, w, tplg_w);
885	case snd_soc_dapm_pga:
886		return audioreach_widget_load_pga(component, index, w, tplg_w);
887	case snd_soc_dapm_dai_link:
888	case snd_soc_dapm_scheduler:
889	case snd_soc_dapm_out_drv:
890	default:
891		dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id);
892		break;
893	}
894
895	return 0;
896}
897
898static int audioreach_widget_unload(struct snd_soc_component *scomp,
899				    struct snd_soc_dobj *dobj)
900{
901	struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj);
902	struct q6apm *apm = dev_get_drvdata(scomp->dev);
903	struct audioreach_container *cont;
904	struct audioreach_module *mod;
905
906	mod = dobj->private;
907	cont = mod->container;
908
909	if (w->id == snd_soc_dapm_mixer) {
910		/* virtual widget */
911		struct snd_ar_control *scontrol = dobj->private;
912
913		list_del(&scontrol->node);
914		kfree(scontrol);
915		return 0;
916	}
917
918	mutex_lock(&apm->lock);
919	idr_remove(&apm->modules_idr, mod->instance_id);
920	cont->num_modules--;
921
922	list_del(&mod->node);
923	kfree(mod);
924	/* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */
925	if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */
926		struct audioreach_sub_graph *sg = cont->sub_graph;
927
928		idr_remove(&apm->containers_idr, cont->container_id);
929		list_del(&cont->node);
930		sg->num_containers--;
931		kfree(cont);
932		/* check if there are no more containers in the sub graph and remove it */
933		if (list_empty(&sg->container_list)) {
934			struct audioreach_graph_info *info = sg->info;
935
936			idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id);
937			list_del(&sg->node);
938			info->num_sub_graphs--;
939			kfree(sg);
940			/* Check if there are no more sub-graphs left then remove graph info */
941			if (list_empty(&info->sg_list)) {
942				idr_remove(&apm->graph_info_idr, info->id);
943				kfree(info);
944			}
945		}
946	}
947
948	mutex_unlock(&apm->lock);
949
950	return 0;
951}
952
953static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp,
954						     const char *name)
955{
956	struct q6apm *apm = dev_get_drvdata(comp->dev);
957	struct snd_ar_control *control;
958
959	list_for_each_entry(control, &apm->widget_list, node) {
960		if (control->w && !strcmp(name, control->w->name))
961			return control;
962	}
963
964	return NULL;
965}
966
967static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp,
968							const char *name)
969{
970	struct q6apm *apm = dev_get_drvdata(comp->dev);
971	struct audioreach_module *module;
972	int id;
973
974	idr_for_each_entry(&apm->modules_idr, module, id) {
975		if (!strcmp(name, module->widget->name))
976			return module;
977	}
978
979	return NULL;
980}
981
982static int audioreach_route_load(struct snd_soc_component *scomp, int index,
983				 struct snd_soc_dapm_route *route)
984{
985	struct audioreach_module *src_module, *sink_module;
986	struct snd_ar_control *control;
987	struct snd_soc_dapm_widget *w;
988	int i;
989
990	/* check if these are actual modules */
991	src_module = audioreach_find_module(scomp, route->source);
992	sink_module = audioreach_find_module(scomp, route->sink);
993
994	if (sink_module && !src_module) {
995		control = audioreach_find_widget(scomp, route->source);
996		if (control)
997			control->module_instance_id = sink_module->instance_id;
998
999	} else if (!sink_module && src_module && route->control) {
1000		/* check if this is a virtual mixer */
1001		control = audioreach_find_widget(scomp, route->sink);
1002		if (!control || !control->w)
1003			return 0;
1004
1005		w = control->w;
1006
1007		for (i = 0; i < w->num_kcontrols; i++) {
1008			if (!strcmp(route->control, w->kcontrol_news[i].name)) {
1009				struct soc_mixer_control *sm;
1010				struct snd_soc_dobj *dobj;
1011				struct snd_ar_control *scontrol;
1012
1013				sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value;
1014				dobj = &sm->dobj;
1015				scontrol = dobj->private;
1016				scontrol->module_instance_id = src_module->instance_id;
1017			}
1018		}
1019
1020	}
1021
1022	return 0;
1023}
1024
1025static int audioreach_route_unload(struct snd_soc_component *scomp,
1026				   struct snd_soc_dobj *dobj)
1027{
1028	return 0;
1029}
1030
1031static int audioreach_tplg_complete(struct snd_soc_component *component)
1032{
1033	/* TBD */
1034	return 0;
1035}
1036
1037/* DAI link - used for any driver specific init */
1038static int audioreach_link_load(struct snd_soc_component *component, int index,
1039				struct snd_soc_dai_link *link,
1040				struct snd_soc_tplg_link_config *cfg)
1041{
1042	link->nonatomic = true;
1043	link->dynamic = true;
1044	link->platforms->name = NULL;
1045	link->platforms->of_node = of_get_compatible_child(component->dev->of_node,
1046							   "qcom,q6apm-dais");
1047	return 0;
1048}
1049
1050static void audioreach_connect_sub_graphs(struct q6apm *apm,
1051					  struct snd_ar_control *m1,
1052					  struct snd_ar_control *m2,
1053					  bool connect)
1054{
1055	struct audioreach_graph_info *info;
1056
1057	mutex_lock(&apm->lock);
1058	info = idr_find(&apm->graph_info_idr, m2->graph_id);
1059	mutex_unlock(&apm->lock);
1060
1061	if (connect) {
1062		info->src_mod_inst_id = m1->module_instance_id;
1063		info->src_mod_op_port_id = 1;
1064		info->dst_mod_inst_id = m2->module_instance_id;
1065		info->dst_mod_ip_port_id = 2;
1066
1067	} else {
1068		info->src_mod_inst_id = 0;
1069		info->src_mod_op_port_id = 0;
1070		info->dst_mod_inst_id = 0;
1071		info->dst_mod_ip_port_id = 0;
1072	}
1073}
1074
1075static bool audioreach_is_vmixer_connected(struct q6apm *apm,
1076					   struct snd_ar_control *m1,
1077					   struct snd_ar_control *m2)
1078{
1079	struct audioreach_graph_info *info;
1080
1081	mutex_lock(&apm->lock);
1082	info = idr_find(&apm->graph_info_idr, m2->graph_id);
1083	mutex_unlock(&apm->lock);
1084
1085	if (info->dst_mod_inst_id == m2->module_instance_id &&
1086	    info->src_mod_inst_id == m1->module_instance_id)
1087		return true;
1088
1089	return false;
1090}
1091
1092static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
1093				      struct snd_ctl_elem_value *ucontrol)
1094{
1095	struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
1096	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
1097	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1098	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
1099	struct snd_ar_control *dapm_scontrol = dw->dobj.private;
1100	struct snd_ar_control *scontrol = mc->dobj.private;
1101	struct q6apm *data = dev_get_drvdata(c->dev);
1102	bool connected;
1103
1104	connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol);
1105	if (connected)
1106		ucontrol->value.integer.value[0] = 1;
1107	else
1108		ucontrol->value.integer.value[0] = 0;
1109
1110	return 0;
1111}
1112
1113static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
1114				      struct snd_ctl_elem_value *ucontrol)
1115{
1116	struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
1117	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
1118	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1119	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
1120	struct snd_ar_control *dapm_scontrol = dw->dobj.private;
1121	struct snd_ar_control *scontrol = mc->dobj.private;
1122	struct q6apm *data = dev_get_drvdata(c->dev);
1123
1124	if (ucontrol->value.integer.value[0]) {
1125		audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true);
1126		snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
1127	} else {
1128		audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false);
1129		snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
1130	}
1131	return 0;
1132}
1133
1134static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
1135					       struct snd_ctl_elem_value *ucontrol)
1136{
1137	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1138	struct audioreach_module *mod = dw->dobj.private;
1139
1140	ucontrol->value.integer.value[0] = mod->gain;
1141
1142	return 0;
1143}
1144
1145static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
1146					       struct snd_ctl_elem_value *ucontrol)
1147{
1148	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1149	struct audioreach_module *mod = dw->dobj.private;
1150
1151	mod->gain = ucontrol->value.integer.value[0];
1152
1153	return 1;
1154}
1155
1156static int audioreach_control_load_mix(struct snd_soc_component *scomp,
1157				       struct snd_ar_control *scontrol,
1158				       struct snd_kcontrol_new *kc,
1159				       struct snd_soc_tplg_ctl_hdr *hdr)
1160{
1161	struct snd_soc_tplg_vendor_value_elem *c_elem;
1162	struct snd_soc_tplg_vendor_array *c_array;
1163	struct snd_soc_tplg_mixer_control *mc;
1164	int tkn_count = 0;
1165
1166	mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
1167	c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data;
1168
1169	c_elem = c_array->value;
1170
1171	while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) {
1172		switch (le32_to_cpu(c_elem->token)) {
1173		case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
1174			scontrol->sgid = le32_to_cpu(c_elem->value);
1175			break;
1176		case AR_TKN_DAI_INDEX:
1177			scontrol->graph_id = le32_to_cpu(c_elem->value);
1178			break;
1179		default:
1180			/* Ignore other tokens */
1181			break;
1182		}
1183		c_elem++;
1184		tkn_count++;
1185	}
1186
1187	return 0;
1188}
1189
1190static int audioreach_control_load(struct snd_soc_component *scomp, int index,
1191				   struct snd_kcontrol_new *kc,
1192				   struct snd_soc_tplg_ctl_hdr *hdr)
1193{
1194	struct snd_ar_control *scontrol;
1195	struct soc_mixer_control *sm;
1196	struct snd_soc_dobj *dobj;
1197	int ret = 0;
1198
1199	scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
1200	if (!scontrol)
1201		return -ENOMEM;
1202
1203	scontrol->scomp = scomp;
1204
1205	switch (le32_to_cpu(hdr->ops.get)) {
1206	case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX:
1207		sm = (struct soc_mixer_control *)kc->private_value;
1208		dobj = &sm->dobj;
1209		ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr);
1210		break;
1211	case SND_SOC_AR_TPLG_VOL_CTL:
1212		sm = (struct soc_mixer_control *)kc->private_value;
1213		dobj = &sm->dobj;
1214		break;
1215	default:
1216		dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
1217			 hdr->ops.get, hdr->ops.put, hdr->ops.info);
1218		kfree(scontrol);
1219		return -EINVAL;
1220	}
1221
1222	dobj->private = scontrol;
1223	return ret;
1224}
1225
1226static int audioreach_control_unload(struct snd_soc_component *scomp,
1227				     struct snd_soc_dobj *dobj)
1228{
1229	struct snd_ar_control *scontrol = dobj->private;
1230
1231	kfree(scontrol);
1232
1233	return 0;
1234}
1235
1236static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
1237	{SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer,
1238		audioreach_put_audio_mixer, snd_soc_info_volsw},
1239	{SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer,
1240		audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
1241};
1242
1243static struct snd_soc_tplg_ops audioreach_tplg_ops  = {
1244	.io_ops = audioreach_io_ops,
1245	.io_ops_count = ARRAY_SIZE(audioreach_io_ops),
1246
1247	.control_load	= audioreach_control_load,
1248	.control_unload	= audioreach_control_unload,
1249
1250	.widget_ready = audioreach_widget_ready,
1251	.widget_unload = audioreach_widget_unload,
1252
1253	.complete = audioreach_tplg_complete,
1254	.link_load = audioreach_link_load,
1255
1256	.dapm_route_load	= audioreach_route_load,
1257	.dapm_route_unload	= audioreach_route_unload,
1258};
1259
1260int audioreach_tplg_init(struct snd_soc_component *component)
1261{
1262	struct snd_soc_card *card = component->card;
1263	struct device *dev = component->dev;
1264	const struct firmware *fw;
1265	char *tplg_fw_name;
1266	int ret;
1267
1268	/* Inline with Qualcomm UCM configs and linux-firmware path */
1269	tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name);
1270	if (!tplg_fw_name)
1271		return -ENOMEM;
1272
1273	ret = request_firmware(&fw, tplg_fw_name, dev);
1274	if (ret < 0) {
1275		dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret);
1276		goto err;
1277	}
1278
1279	ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw);
1280	if (ret < 0) {
1281		if (ret != -EPROBE_DEFER)
1282			dev_err(dev, "tplg component load failed: %d\n", ret);
1283	}
1284
1285	release_firmware(fw);
1286err:
1287	kfree(tplg_fw_name);
1288
1289	return ret;
1290}
1291EXPORT_SYMBOL_GPL(audioreach_tplg_init);
1292