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