0001
0002
0003
0004 #include <sound/soc.h>
0005 #include <sound/soc-dapm.h>
0006 #include <sound/pcm.h>
0007 #include <sound/control.h>
0008 #include <sound/asound.h>
0009 #include <linux/firmware.h>
0010 #include <sound/soc-topology.h>
0011 #include <sound/soc-dpcm.h>
0012 #include <uapi/sound/snd_ar_tokens.h>
0013 #include <linux/kernel.h>
0014 #include <linux/wait.h>
0015 #include "q6apm.h"
0016 #include "audioreach.h"
0017
0018 struct snd_ar_control {
0019 u32 sgid;
0020 struct snd_soc_component *scomp;
0021 };
0022
0023 static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6apm *apm,
0024 uint32_t graph_id,
0025 bool *found)
0026 {
0027 struct audioreach_graph_info *info;
0028 int ret;
0029
0030 mutex_lock(&apm->lock);
0031 info = idr_find(&apm->graph_info_idr, graph_id);
0032 mutex_unlock(&apm->lock);
0033
0034 if (info) {
0035 *found = true;
0036 return info;
0037 }
0038
0039 *found = false;
0040 info = kzalloc(sizeof(*info), GFP_KERNEL);
0041 if (!info)
0042 return ERR_PTR(-ENOMEM);
0043
0044 INIT_LIST_HEAD(&info->sg_list);
0045
0046 mutex_lock(&apm->lock);
0047 ret = idr_alloc(&apm->graph_info_idr, info, graph_id, graph_id + 1, GFP_KERNEL);
0048 mutex_unlock(&apm->lock);
0049
0050 if (ret < 0) {
0051 dev_err(apm->dev, "Failed to allocate Graph ID (%x)\n", graph_id);
0052 kfree(info);
0053 return ERR_PTR(ret);
0054 }
0055
0056 info->id = ret;
0057
0058 return info;
0059 }
0060
0061 static void audioreach_tplg_add_sub_graph(struct audioreach_sub_graph *sg,
0062 struct audioreach_graph_info *info)
0063 {
0064 list_add_tail(&sg->node, &info->sg_list);
0065 sg->info = info;
0066 info->num_sub_graphs++;
0067 }
0068
0069 static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm *apm,
0070 uint32_t sub_graph_id,
0071 bool *found)
0072 {
0073 struct audioreach_sub_graph *sg;
0074 int ret;
0075
0076 if (!sub_graph_id)
0077 return ERR_PTR(-EINVAL);
0078
0079
0080 mutex_lock(&apm->lock);
0081 sg = idr_find(&apm->sub_graphs_idr, sub_graph_id);
0082 mutex_unlock(&apm->lock);
0083
0084 if (sg) {
0085 *found = true;
0086 return sg;
0087 }
0088
0089 *found = false;
0090 sg = kzalloc(sizeof(*sg), GFP_KERNEL);
0091 if (!sg)
0092 return ERR_PTR(-ENOMEM);
0093
0094 INIT_LIST_HEAD(&sg->container_list);
0095
0096 mutex_lock(&apm->lock);
0097 ret = idr_alloc(&apm->sub_graphs_idr, sg, sub_graph_id, sub_graph_id + 1, GFP_KERNEL);
0098 mutex_unlock(&apm->lock);
0099
0100 if (ret < 0) {
0101 dev_err(apm->dev, "Failed to allocate Sub-Graph Instance ID (%x)\n", sub_graph_id);
0102 kfree(sg);
0103 return ERR_PTR(ret);
0104 }
0105
0106 sg->sub_graph_id = ret;
0107
0108 return sg;
0109 }
0110
0111 static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm *apm,
0112 struct audioreach_sub_graph *sg,
0113 uint32_t container_id,
0114 bool *found)
0115 {
0116 struct audioreach_container *cont;
0117 int ret;
0118
0119 if (!container_id)
0120 return ERR_PTR(-EINVAL);
0121
0122 mutex_lock(&apm->lock);
0123 cont = idr_find(&apm->containers_idr, container_id);
0124 mutex_unlock(&apm->lock);
0125
0126 if (cont) {
0127 *found = true;
0128 return cont;
0129 }
0130 *found = false;
0131
0132 cont = kzalloc(sizeof(*cont), GFP_KERNEL);
0133 if (!cont)
0134 return ERR_PTR(-ENOMEM);
0135
0136 INIT_LIST_HEAD(&cont->modules_list);
0137
0138 mutex_lock(&apm->lock);
0139 ret = idr_alloc(&apm->containers_idr, cont, container_id, container_id + 1, GFP_KERNEL);
0140 mutex_unlock(&apm->lock);
0141
0142 if (ret < 0) {
0143 dev_err(apm->dev, "Failed to allocate Container Instance ID (%x)\n", container_id);
0144 kfree(cont);
0145 return ERR_PTR(ret);
0146 }
0147
0148 cont->container_id = ret;
0149 cont->sub_graph = sg;
0150
0151 list_add_tail(&cont->node, &sg->container_list);
0152 sg->num_containers++;
0153
0154 return cont;
0155 }
0156
0157 static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
0158 struct audioreach_container *cont,
0159 struct snd_soc_dapm_widget *w,
0160 uint32_t module_id, bool *found)
0161 {
0162 struct audioreach_module *mod;
0163 int ret;
0164
0165 mutex_lock(&apm->lock);
0166 mod = idr_find(&apm->modules_idr, module_id);
0167 mutex_unlock(&apm->lock);
0168
0169 if (mod) {
0170 *found = true;
0171 return mod;
0172 }
0173 *found = false;
0174 mod = kzalloc(sizeof(*mod), GFP_KERNEL);
0175 if (!mod)
0176 return ERR_PTR(-ENOMEM);
0177
0178 mutex_lock(&apm->lock);
0179 if (!module_id) {
0180 ret = idr_alloc_cyclic(&apm->modules_idr, mod,
0181 AR_MODULE_DYNAMIC_INSTANCE_ID_START,
0182 AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL);
0183 } else {
0184 ret = idr_alloc(&apm->modules_idr, mod, module_id, module_id + 1, GFP_KERNEL);
0185 }
0186 mutex_unlock(&apm->lock);
0187
0188 if (ret < 0) {
0189 dev_err(apm->dev, "Failed to allocate Module Instance ID (%x)\n", module_id);
0190 kfree(mod);
0191 return ERR_PTR(ret);
0192 }
0193
0194 mod->instance_id = ret;
0195
0196 list_add_tail(&mod->node, &cont->modules_list);
0197 mod->container = cont;
0198 mod->widget = w;
0199 cont->num_modules++;
0200
0201 return mod;
0202 }
0203
0204 static struct snd_soc_tplg_vendor_array *audioreach_get_sg_array(
0205 struct snd_soc_tplg_private *private)
0206 {
0207 struct snd_soc_tplg_vendor_array *sg_array = NULL;
0208 bool found = false;
0209 int sz;
0210
0211 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
0212 struct snd_soc_tplg_vendor_value_elem *sg_elem;
0213 int tkn_count = 0;
0214
0215 sg_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
0216 sg_elem = sg_array->value;
0217 sz = sz + le32_to_cpu(sg_array->size);
0218 while (!found && tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
0219 switch (le32_to_cpu(sg_elem->token)) {
0220 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
0221 found = true;
0222 break;
0223 default:
0224 break;
0225 }
0226 tkn_count++;
0227 sg_elem++;
0228 }
0229 }
0230
0231 if (found)
0232 return sg_array;
0233
0234 return NULL;
0235 }
0236
0237 static struct snd_soc_tplg_vendor_array *audioreach_get_cont_array(
0238 struct snd_soc_tplg_private *private)
0239 {
0240 struct snd_soc_tplg_vendor_array *cont_array = NULL;
0241 bool found = false;
0242 int sz;
0243
0244 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
0245 struct snd_soc_tplg_vendor_value_elem *cont_elem;
0246 int tkn_count = 0;
0247
0248 cont_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
0249 cont_elem = cont_array->value;
0250 sz = sz + le32_to_cpu(cont_array->size);
0251 while (!found && tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
0252 switch (le32_to_cpu(cont_elem->token)) {
0253 case AR_TKN_U32_CONTAINER_INSTANCE_ID:
0254 found = true;
0255 break;
0256 default:
0257 break;
0258 }
0259 tkn_count++;
0260 cont_elem++;
0261 }
0262 }
0263
0264 if (found)
0265 return cont_array;
0266
0267 return NULL;
0268 }
0269
0270 static struct snd_soc_tplg_vendor_array *audioreach_get_module_array(
0271 struct snd_soc_tplg_private *private)
0272 {
0273 struct snd_soc_tplg_vendor_array *mod_array = NULL;
0274 bool found = false;
0275 int sz = 0;
0276
0277 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
0278 struct snd_soc_tplg_vendor_value_elem *mod_elem;
0279 int tkn_count = 0;
0280
0281 mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
0282 mod_elem = mod_array->value;
0283 sz = sz + le32_to_cpu(mod_array->size);
0284 while (!found && tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
0285 switch (le32_to_cpu(mod_elem->token)) {
0286 case AR_TKN_U32_MODULE_INSTANCE_ID:
0287 found = true;
0288 break;
0289 default:
0290 break;
0291 }
0292 tkn_count++;
0293 mod_elem++;
0294 }
0295 }
0296
0297 if (found)
0298 return mod_array;
0299
0300 return NULL;
0301 }
0302
0303 static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm,
0304 struct snd_soc_tplg_private *private)
0305 {
0306 struct snd_soc_tplg_vendor_value_elem *sg_elem;
0307 struct snd_soc_tplg_vendor_array *sg_array;
0308 struct audioreach_graph_info *info = NULL;
0309 int graph_id, sub_graph_id, tkn_count = 0;
0310 struct audioreach_sub_graph *sg;
0311 bool found;
0312
0313 sg_array = audioreach_get_sg_array(private);
0314 sg_elem = sg_array->value;
0315
0316 while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
0317 switch (le32_to_cpu(sg_elem->token)) {
0318 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
0319 sub_graph_id = le32_to_cpu(sg_elem->value);
0320 sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found);
0321 if (IS_ERR(sg)) {
0322 return sg;
0323 } else if (found) {
0324
0325 return sg;
0326 }
0327 break;
0328 case AR_TKN_DAI_INDEX:
0329
0330 graph_id = le32_to_cpu(sg_elem->value);
0331 info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found);
0332 if (IS_ERR(info))
0333 return ERR_CAST(info);
0334 break;
0335 case AR_TKN_U32_SUB_GRAPH_PERF_MODE:
0336 sg->perf_mode = le32_to_cpu(sg_elem->value);
0337 break;
0338 case AR_TKN_U32_SUB_GRAPH_DIRECTION:
0339 sg->direction = le32_to_cpu(sg_elem->value);
0340 break;
0341 case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID:
0342 sg->scenario_id = le32_to_cpu(sg_elem->value);
0343 break;
0344 default:
0345 dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token);
0346 break;
0347
0348 }
0349 tkn_count++;
0350 sg_elem++;
0351 }
0352
0353
0354 if (info)
0355 audioreach_tplg_add_sub_graph(sg, info);
0356
0357 return sg;
0358 }
0359
0360 static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm,
0361 struct audioreach_sub_graph *sg,
0362 struct snd_soc_tplg_private *private)
0363 {
0364 struct snd_soc_tplg_vendor_value_elem *cont_elem;
0365 struct snd_soc_tplg_vendor_array *cont_array;
0366 struct audioreach_container *cont;
0367 int container_id, tkn_count = 0;
0368 bool found = false;
0369
0370 cont_array = audioreach_get_cont_array(private);
0371 cont_elem = cont_array->value;
0372
0373 while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
0374 switch (le32_to_cpu(cont_elem->token)) {
0375 case AR_TKN_U32_CONTAINER_INSTANCE_ID:
0376 container_id = le32_to_cpu(cont_elem->value);
0377 cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found);
0378 if (IS_ERR(cont) || found)
0379 return cont;
0380 break;
0381 case AR_TKN_U32_CONTAINER_CAPABILITY_ID:
0382 cont->capability_id = le32_to_cpu(cont_elem->value);
0383 break;
0384 case AR_TKN_U32_CONTAINER_STACK_SIZE:
0385 cont->stack_size = le32_to_cpu(cont_elem->value);
0386 break;
0387 case AR_TKN_U32_CONTAINER_GRAPH_POS:
0388 cont->graph_pos = le32_to_cpu(cont_elem->value);
0389 break;
0390 case AR_TKN_U32_CONTAINER_PROC_DOMAIN:
0391 cont->proc_domain = le32_to_cpu(cont_elem->value);
0392 break;
0393 default:
0394 dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token);
0395 break;
0396
0397 }
0398 tkn_count++;
0399 cont_elem++;
0400 }
0401
0402 return cont;
0403 }
0404
0405 static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm,
0406 struct audioreach_container *cont,
0407 struct snd_soc_tplg_private *private,
0408 struct snd_soc_dapm_widget *w)
0409 {
0410 uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
0411 uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0;
0412 uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0;
0413 int module_id = 0, instance_id = 0, tkn_count = 0;
0414 struct snd_soc_tplg_vendor_value_elem *mod_elem;
0415 struct snd_soc_tplg_vendor_array *mod_array;
0416 struct audioreach_module *mod = NULL;
0417 bool found;
0418
0419 mod_array = audioreach_get_module_array(private);
0420 mod_elem = mod_array->value;
0421
0422 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
0423 switch (le32_to_cpu(mod_elem->token)) {
0424
0425 case AR_TKN_U32_MODULE_ID:
0426 module_id = le32_to_cpu(mod_elem->value);
0427 break;
0428 case AR_TKN_U32_MODULE_INSTANCE_ID:
0429 instance_id = le32_to_cpu(mod_elem->value);
0430 mod = audioreach_tplg_alloc_module(apm, cont, w,
0431 instance_id, &found);
0432 if (IS_ERR(mod)) {
0433 return mod;
0434 } else if (found) {
0435 dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n",
0436 instance_id);
0437 return ERR_PTR(-EINVAL);
0438 }
0439
0440 break;
0441 case AR_TKN_U32_MODULE_MAX_IP_PORTS:
0442 max_ip_port = le32_to_cpu(mod_elem->value);
0443 break;
0444 case AR_TKN_U32_MODULE_MAX_OP_PORTS:
0445 max_op_port = le32_to_cpu(mod_elem->value);
0446 break;
0447 case AR_TKN_U32_MODULE_IN_PORTS:
0448 in_port = le32_to_cpu(mod_elem->value);
0449 break;
0450 case AR_TKN_U32_MODULE_OUT_PORTS:
0451 out_port = le32_to_cpu(mod_elem->value);
0452 break;
0453 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
0454 src_mod_op_port_id = le32_to_cpu(mod_elem->value);
0455 break;
0456 case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
0457 src_mod_inst_id = le32_to_cpu(mod_elem->value);
0458 break;
0459 case AR_TKN_U32_MODULE_DST_INSTANCE_ID:
0460 dst_mod_inst_id = le32_to_cpu(mod_elem->value);
0461 break;
0462 case AR_TKN_U32_MODULE_DST_IN_PORT_ID:
0463 dst_mod_ip_port_id = le32_to_cpu(mod_elem->value);
0464 break;
0465 default:
0466 break;
0467
0468 }
0469 tkn_count++;
0470 mod_elem++;
0471 }
0472
0473 if (mod) {
0474 mod->module_id = module_id;
0475 mod->max_ip_port = max_ip_port;
0476 mod->max_op_port = max_op_port;
0477 mod->in_port = in_port;
0478 mod->out_port = out_port;
0479 mod->src_mod_inst_id = src_mod_inst_id;
0480 mod->src_mod_op_port_id = src_mod_op_port_id;
0481 mod->dst_mod_inst_id = dst_mod_inst_id;
0482 mod->dst_mod_ip_port_id = dst_mod_ip_port_id;
0483 }
0484
0485 return mod;
0486 }
0487
0488 static int audioreach_widget_load_module_common(struct snd_soc_component *component,
0489 int index, struct snd_soc_dapm_widget *w,
0490 struct snd_soc_tplg_dapm_widget *tplg_w)
0491 {
0492 struct q6apm *apm = dev_get_drvdata(component->dev);
0493 struct audioreach_container *cont;
0494 struct audioreach_sub_graph *sg;
0495 struct audioreach_module *mod;
0496 struct snd_soc_dobj *dobj;
0497
0498 sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv);
0499 if (IS_ERR(sg))
0500 return PTR_ERR(sg);
0501
0502 cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv);
0503 if (IS_ERR(cont))
0504 return PTR_ERR(cont);
0505
0506 mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w);
0507 if (IS_ERR(mod))
0508 return PTR_ERR(mod);
0509
0510 dobj = &w->dobj;
0511 dobj->private = mod;
0512
0513 return 0;
0514 }
0515
0516 static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component,
0517 int index, struct snd_soc_dapm_widget *w,
0518 struct snd_soc_tplg_dapm_widget *tplg_w)
0519 {
0520 struct snd_soc_tplg_vendor_value_elem *mod_elem;
0521 struct snd_soc_tplg_vendor_array *mod_array;
0522 struct audioreach_module *mod;
0523 struct snd_soc_dobj *dobj;
0524 int tkn_count = 0;
0525 int ret;
0526
0527 ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
0528 if (ret)
0529 return ret;
0530
0531 dobj = &w->dobj;
0532 mod = dobj->private;
0533 mod_array = audioreach_get_module_array(&tplg_w->priv);
0534 mod_elem = mod_array->value;
0535
0536 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
0537 switch (le32_to_cpu(mod_elem->token)) {
0538 case AR_TKN_U32_MODULE_FMT_INTERLEAVE:
0539 mod->interleave_type = le32_to_cpu(mod_elem->value);
0540 break;
0541 case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE:
0542 mod->rate = le32_to_cpu(mod_elem->value);
0543 break;
0544 case AR_TKN_U32_MODULE_FMT_BIT_DEPTH:
0545 mod->bit_depth = le32_to_cpu(mod_elem->value);
0546 break;
0547 default:
0548 break;
0549 }
0550 tkn_count++;
0551 mod_elem++;
0552 }
0553
0554 return 0;
0555 }
0556
0557 static int audioreach_widget_log_module_load(struct audioreach_module *mod,
0558 struct snd_soc_tplg_vendor_array *mod_array)
0559 {
0560 struct snd_soc_tplg_vendor_value_elem *mod_elem;
0561 int tkn_count = 0;
0562
0563 mod_elem = mod_array->value;
0564
0565 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
0566 switch (le32_to_cpu(mod_elem->token)) {
0567
0568 case AR_TKN_U32_MODULE_LOG_CODE:
0569 mod->log_code = le32_to_cpu(mod_elem->value);
0570 break;
0571 case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID:
0572 mod->log_tap_point_id = le32_to_cpu(mod_elem->value);
0573 break;
0574 case AR_TKN_U32_MODULE_LOG_MODE:
0575 mod->log_mode = le32_to_cpu(mod_elem->value);
0576 break;
0577 default:
0578 break;
0579 }
0580 tkn_count++;
0581 mod_elem++;
0582 }
0583
0584 return 0;
0585 }
0586
0587 static int audioreach_widget_dma_module_load(struct audioreach_module *mod,
0588 struct snd_soc_tplg_vendor_array *mod_array)
0589 {
0590 struct snd_soc_tplg_vendor_value_elem *mod_elem;
0591 int tkn_count = 0;
0592
0593 mod_elem = mod_array->value;
0594
0595 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
0596 switch (le32_to_cpu(mod_elem->token)) {
0597 case AR_TKN_U32_MODULE_HW_IF_IDX:
0598 mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
0599 break;
0600 case AR_TKN_U32_MODULE_FMT_DATA:
0601 mod->data_format = le32_to_cpu(mod_elem->value);
0602 break;
0603 case AR_TKN_U32_MODULE_HW_IF_TYPE:
0604 mod->hw_interface_type = le32_to_cpu(mod_elem->value);
0605 break;
0606 default:
0607 break;
0608 }
0609 tkn_count++;
0610 mod_elem++;
0611 }
0612
0613 return 0;
0614 }
0615
0616 static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
0617 struct snd_soc_tplg_vendor_array *mod_array)
0618 {
0619 struct snd_soc_tplg_vendor_value_elem *mod_elem;
0620 int tkn_count = 0;
0621
0622 mod_elem = mod_array->value;
0623
0624 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
0625 switch (le32_to_cpu(mod_elem->token)) {
0626 case AR_TKN_U32_MODULE_HW_IF_IDX:
0627 mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
0628 break;
0629 case AR_TKN_U32_MODULE_FMT_DATA:
0630 mod->data_format = le32_to_cpu(mod_elem->value);
0631 break;
0632 case AR_TKN_U32_MODULE_HW_IF_TYPE:
0633 mod->hw_interface_type = le32_to_cpu(mod_elem->value);
0634 break;
0635 case AR_TKN_U32_MODULE_SD_LINE_IDX:
0636 mod->sd_line_idx = le32_to_cpu(mod_elem->value);
0637 break;
0638 case AR_TKN_U32_MODULE_WS_SRC:
0639 mod->ws_src = le32_to_cpu(mod_elem->value);
0640 break;
0641 default:
0642 break;
0643 }
0644 tkn_count++;
0645 mod_elem++;
0646 }
0647
0648 return 0;
0649 }
0650
0651 static int audioreach_widget_load_buffer(struct snd_soc_component *component,
0652 int index, struct snd_soc_dapm_widget *w,
0653 struct snd_soc_tplg_dapm_widget *tplg_w)
0654 {
0655 struct snd_soc_tplg_vendor_array *mod_array;
0656 struct audioreach_module *mod;
0657 struct snd_soc_dobj *dobj;
0658 int ret;
0659
0660 ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
0661 if (ret)
0662 return ret;
0663
0664 dobj = &w->dobj;
0665 mod = dobj->private;
0666
0667 mod_array = audioreach_get_module_array(&tplg_w->priv);
0668
0669 switch (mod->module_id) {
0670 case MODULE_ID_CODEC_DMA_SINK:
0671 case MODULE_ID_CODEC_DMA_SOURCE:
0672 audioreach_widget_dma_module_load(mod, mod_array);
0673 break;
0674 case MODULE_ID_DATA_LOGGING:
0675 audioreach_widget_log_module_load(mod, mod_array);
0676 break;
0677 case MODULE_ID_I2S_SINK:
0678 case MODULE_ID_I2S_SOURCE:
0679 audioreach_widget_i2s_module_load(mod, mod_array);
0680 break;
0681 default:
0682 return -EINVAL;
0683 }
0684
0685 return 0;
0686 }
0687
0688 static int audioreach_widget_load_mixer(struct snd_soc_component *component,
0689 int index, struct snd_soc_dapm_widget *w,
0690 struct snd_soc_tplg_dapm_widget *tplg_w)
0691 {
0692 struct snd_soc_tplg_vendor_value_elem *w_elem;
0693 struct snd_soc_tplg_vendor_array *w_array;
0694 struct snd_ar_control *scontrol;
0695 struct snd_soc_dobj *dobj;
0696 int tkn_count = 0;
0697
0698 w_array = &tplg_w->priv.array[0];
0699
0700 scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
0701 if (!scontrol)
0702 return -ENOMEM;
0703
0704 scontrol->scomp = component;
0705 dobj = &w->dobj;
0706 dobj->private = scontrol;
0707
0708 w_elem = w_array->value;
0709 while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) {
0710 switch (le32_to_cpu(w_elem->token)) {
0711 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
0712 scontrol->sgid = le32_to_cpu(w_elem->value);
0713 break;
0714 default:
0715 break;
0716 }
0717 tkn_count++;
0718 w_elem++;
0719 }
0720
0721 return 0;
0722 }
0723
0724 static int audioreach_pga_event(struct snd_soc_dapm_widget *w,
0725 struct snd_kcontrol *kcontrol, int event)
0726
0727 {
0728 struct snd_soc_dapm_context *dapm = w->dapm;
0729 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
0730 struct audioreach_module *mod = w->dobj.private;
0731 struct q6apm *apm = dev_get_drvdata(c->dev);
0732
0733 switch (event) {
0734 case SND_SOC_DAPM_POST_PMU:
0735
0736 audioreach_gain_set_vol_ctrl(apm, mod, mod->gain);
0737 break;
0738 default:
0739 break;
0740 }
0741
0742 return 0;
0743 }
0744
0745 static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = {
0746 { AR_PGA_DAPM_EVENT, audioreach_pga_event },
0747 };
0748
0749 static int audioreach_widget_load_pga(struct snd_soc_component *component,
0750 int index, struct snd_soc_dapm_widget *w,
0751 struct snd_soc_tplg_dapm_widget *tplg_w)
0752 {
0753 struct audioreach_module *mod;
0754 struct snd_soc_dobj *dobj;
0755 int ret;
0756
0757 ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
0758 if (ret)
0759 return ret;
0760
0761 dobj = &w->dobj;
0762 mod = dobj->private;
0763 mod->gain = VOL_CTRL_DEFAULT_GAIN;
0764
0765 ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops,
0766 ARRAY_SIZE(audioreach_widget_ops),
0767 le16_to_cpu(tplg_w->event_type));
0768 if (ret) {
0769 dev_err(component->dev, "matching event handlers NOT found for %d\n",
0770 le16_to_cpu(tplg_w->event_type));
0771 return -EINVAL;
0772 }
0773
0774 return 0;
0775 }
0776
0777 static int audioreach_widget_ready(struct snd_soc_component *component,
0778 int index, struct snd_soc_dapm_widget *w,
0779 struct snd_soc_tplg_dapm_widget *tplg_w)
0780 {
0781 switch (w->id) {
0782 case snd_soc_dapm_aif_in:
0783 case snd_soc_dapm_aif_out:
0784 audioreach_widget_load_buffer(component, index, w, tplg_w);
0785 break;
0786 case snd_soc_dapm_decoder:
0787 case snd_soc_dapm_encoder:
0788 case snd_soc_dapm_src:
0789 audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w);
0790 break;
0791 case snd_soc_dapm_buffer:
0792 audioreach_widget_load_buffer(component, index, w, tplg_w);
0793 break;
0794 case snd_soc_dapm_mixer:
0795 return audioreach_widget_load_mixer(component, index, w, tplg_w);
0796 case snd_soc_dapm_pga:
0797 return audioreach_widget_load_pga(component, index, w, tplg_w);
0798 case snd_soc_dapm_dai_link:
0799 case snd_soc_dapm_scheduler:
0800 case snd_soc_dapm_out_drv:
0801 default:
0802 dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id);
0803 break;
0804 }
0805
0806 return 0;
0807 }
0808
0809 static int audioreach_widget_unload(struct snd_soc_component *scomp,
0810 struct snd_soc_dobj *dobj)
0811 {
0812 struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj);
0813 struct q6apm *apm = dev_get_drvdata(scomp->dev);
0814 struct audioreach_container *cont;
0815 struct audioreach_module *mod;
0816
0817 mod = dobj->private;
0818 cont = mod->container;
0819
0820 if (w->id == snd_soc_dapm_mixer) {
0821
0822 kfree(dobj->private);
0823 return 0;
0824 }
0825
0826 mutex_lock(&apm->lock);
0827 idr_remove(&apm->modules_idr, mod->instance_id);
0828 cont->num_modules--;
0829
0830 list_del(&mod->node);
0831 kfree(mod);
0832
0833 if (list_empty(&cont->modules_list)) {
0834 struct audioreach_sub_graph *sg = cont->sub_graph;
0835
0836 idr_remove(&apm->containers_idr, cont->container_id);
0837 list_del(&cont->node);
0838 sg->num_containers--;
0839 kfree(cont);
0840
0841 if (list_empty(&sg->container_list)) {
0842 struct audioreach_graph_info *info = sg->info;
0843
0844 idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id);
0845 list_del(&sg->node);
0846 info->num_sub_graphs--;
0847 kfree(sg);
0848
0849 if (list_empty(&info->sg_list)) {
0850 idr_remove(&apm->graph_info_idr, info->id);
0851 kfree(info);
0852 }
0853 }
0854 }
0855
0856 mutex_unlock(&apm->lock);
0857
0858 return 0;
0859 }
0860
0861 static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp,
0862 const char *name)
0863 {
0864 struct q6apm *apm = dev_get_drvdata(comp->dev);
0865 struct audioreach_module *module;
0866 int id;
0867
0868 idr_for_each_entry(&apm->modules_idr, module, id) {
0869 if (!strcmp(name, module->widget->name))
0870 return module;
0871 }
0872
0873 return NULL;
0874 }
0875
0876 static int audioreach_route_load(struct snd_soc_component *scomp, int index,
0877 struct snd_soc_dapm_route *route)
0878 {
0879 struct audioreach_module *src, *sink;
0880
0881 src = audioreach_find_widget(scomp, route->source);
0882 sink = audioreach_find_widget(scomp, route->sink);
0883
0884 if (src && sink) {
0885 src->dst_mod_inst_id = sink->instance_id;
0886 sink->src_mod_inst_id = src->instance_id;
0887 }
0888
0889 return 0;
0890 }
0891
0892 static int audioreach_route_unload(struct snd_soc_component *scomp,
0893 struct snd_soc_dobj *dobj)
0894 {
0895 return 0;
0896 }
0897
0898 static int audioreach_tplg_complete(struct snd_soc_component *component)
0899 {
0900
0901 return 0;
0902 }
0903
0904
0905 static int audioreach_link_load(struct snd_soc_component *component, int index,
0906 struct snd_soc_dai_link *link,
0907 struct snd_soc_tplg_link_config *cfg)
0908 {
0909 link->nonatomic = true;
0910 link->dynamic = true;
0911 link->platforms->name = NULL;
0912 link->platforms->of_node = of_get_compatible_child(component->dev->of_node,
0913 "qcom,q6apm-dais");
0914 return 0;
0915 }
0916
0917 static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
0918 struct snd_ctl_elem_value *ucontrol)
0919 {
0920 struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
0921 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
0922 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
0923 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
0924 struct snd_ar_control *dapm_scontrol = dw->dobj.private;
0925 struct snd_ar_control *scontrol = mc->dobj.private;
0926 struct q6apm *data = dev_get_drvdata(c->dev);
0927 bool connected;
0928
0929 connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid);
0930 if (connected)
0931 ucontrol->value.integer.value[0] = 1;
0932 else
0933 ucontrol->value.integer.value[0] = 0;
0934
0935 return 0;
0936 }
0937
0938 static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
0939 struct snd_ctl_elem_value *ucontrol)
0940 {
0941 struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
0942 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
0943 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
0944 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
0945 struct snd_ar_control *dapm_scontrol = dw->dobj.private;
0946 struct snd_ar_control *scontrol = mc->dobj.private;
0947 struct q6apm *data = dev_get_drvdata(c->dev);
0948
0949 if (ucontrol->value.integer.value[0]) {
0950 q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true);
0951 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
0952 } else {
0953 q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false);
0954 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
0955 }
0956 return 0;
0957 }
0958
0959 static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
0960 struct snd_ctl_elem_value *ucontrol)
0961 {
0962 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
0963 struct audioreach_module *mod = dw->dobj.private;
0964
0965 ucontrol->value.integer.value[0] = mod->gain;
0966
0967 return 0;
0968 }
0969
0970 static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
0971 struct snd_ctl_elem_value *ucontrol)
0972 {
0973 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
0974 struct audioreach_module *mod = dw->dobj.private;
0975
0976 mod->gain = ucontrol->value.integer.value[0];
0977
0978 return 1;
0979 }
0980
0981 static int audioreach_control_load_mix(struct snd_soc_component *scomp,
0982 struct snd_ar_control *scontrol,
0983 struct snd_kcontrol_new *kc,
0984 struct snd_soc_tplg_ctl_hdr *hdr)
0985 {
0986 struct snd_soc_tplg_vendor_value_elem *c_elem;
0987 struct snd_soc_tplg_vendor_array *c_array;
0988 struct snd_soc_tplg_mixer_control *mc;
0989 int tkn_count = 0;
0990
0991 mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
0992 c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data;
0993
0994 c_elem = c_array->value;
0995
0996 while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) {
0997 switch (le32_to_cpu(c_elem->token)) {
0998 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
0999 scontrol->sgid = le32_to_cpu(c_elem->value);
1000 break;
1001 default:
1002
1003 break;
1004 }
1005 c_elem++;
1006 tkn_count++;
1007 }
1008
1009 return 0;
1010 }
1011
1012 static int audioreach_control_load(struct snd_soc_component *scomp, int index,
1013 struct snd_kcontrol_new *kc,
1014 struct snd_soc_tplg_ctl_hdr *hdr)
1015 {
1016 struct snd_ar_control *scontrol;
1017 struct soc_mixer_control *sm;
1018 struct snd_soc_dobj *dobj;
1019 int ret = 0;
1020
1021 scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
1022 if (!scontrol)
1023 return -ENOMEM;
1024
1025 scontrol->scomp = scomp;
1026
1027 switch (le32_to_cpu(hdr->ops.get)) {
1028 case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX:
1029 sm = (struct soc_mixer_control *)kc->private_value;
1030 dobj = &sm->dobj;
1031 ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr);
1032 break;
1033 case SND_SOC_AR_TPLG_VOL_CTL:
1034 sm = (struct soc_mixer_control *)kc->private_value;
1035 dobj = &sm->dobj;
1036 break;
1037 default:
1038 dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
1039 hdr->ops.get, hdr->ops.put, hdr->ops.info);
1040 kfree(scontrol);
1041 return -EINVAL;
1042 }
1043
1044 dobj->private = scontrol;
1045 return ret;
1046 }
1047
1048 static int audioreach_control_unload(struct snd_soc_component *scomp,
1049 struct snd_soc_dobj *dobj)
1050 {
1051 struct snd_ar_control *scontrol = dobj->private;
1052
1053 kfree(scontrol);
1054
1055 return 0;
1056 }
1057
1058 static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
1059 {SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer,
1060 audioreach_put_audio_mixer, snd_soc_info_volsw},
1061 {SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer,
1062 audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
1063 };
1064
1065 static struct snd_soc_tplg_ops audioreach_tplg_ops = {
1066 .io_ops = audioreach_io_ops,
1067 .io_ops_count = ARRAY_SIZE(audioreach_io_ops),
1068
1069 .control_load = audioreach_control_load,
1070 .control_unload = audioreach_control_unload,
1071
1072 .widget_ready = audioreach_widget_ready,
1073 .widget_unload = audioreach_widget_unload,
1074
1075 .complete = audioreach_tplg_complete,
1076 .link_load = audioreach_link_load,
1077
1078 .dapm_route_load = audioreach_route_load,
1079 .dapm_route_unload = audioreach_route_unload,
1080 };
1081
1082 int audioreach_tplg_init(struct snd_soc_component *component)
1083 {
1084 struct snd_soc_card *card = component->card;
1085 struct device *dev = component->dev;
1086 const struct firmware *fw;
1087 char *tplg_fw_name;
1088 int ret;
1089
1090
1091 tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name);
1092 if (!tplg_fw_name)
1093 return -ENOMEM;
1094
1095 ret = request_firmware(&fw, tplg_fw_name, dev);
1096 if (ret < 0) {
1097 dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret);
1098 goto err;
1099 }
1100
1101 ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw);
1102 if (ret < 0) {
1103 dev_err(dev, "tplg component load failed%d\n", ret);
1104 ret = -EINVAL;
1105 }
1106
1107 release_firmware(fw);
1108 err:
1109 kfree(tplg_fw_name);
1110
1111 return ret;
1112 }
1113 EXPORT_SYMBOL_GPL(audioreach_tplg_init);