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