aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm_adsp.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-10-26 14:30:40 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-01-08 15:47:29 -0500
commitdb40517c75e1a33a886c8cadfa2d95f0fe5f5f4c (patch)
treed55fe03dfb9f368d3814f88e63bbddb0f0936e36 /sound/soc/codecs/wm_adsp.c
parentd1c3ed669a2d452cacfb48c2d171a1f364dae2ed (diff)
ASoC: wm_adsp: Add support for parsing algorithms
ADSP devices report information on the algorithms loaded on them. Parse this data and use it to allow coefficients to be configured for specific algorithms. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r--sound/soc/codecs/wm_adsp.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index ffc89fab96fb..990403b162fe 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -350,6 +350,141 @@ out:
350 return ret; 350 return ret;
351} 351}
352 352
353static int wm_adsp_setup_algs(struct wm_adsp *dsp)
354{
355 struct regmap *regmap = dsp->regmap;
356 struct wmfw_adsp1_id_hdr adsp1_id;
357 struct wmfw_adsp2_id_hdr adsp2_id;
358 struct wmfw_adsp1_alg_hdr *adsp1_alg;
359 struct wmfw_adsp2_alg_hdr *adsp2_alg;
360 void *alg;
361 const struct wm_adsp_region *mem;
362 unsigned int pos, term;
363 size_t algs;
364 __be32 val;
365 int i, ret;
366
367 switch (dsp->type) {
368 case WMFW_ADSP1:
369 mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
370 break;
371 case WMFW_ADSP2:
372 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
373 break;
374 default:
375 mem = NULL;
376 break;
377 }
378
379 if (mem == NULL) {
380 BUG_ON(mem != NULL);
381 return -EINVAL;
382 }
383
384 switch (dsp->type) {
385 case WMFW_ADSP1:
386 ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
387 sizeof(adsp1_id));
388 if (ret != 0) {
389 adsp_err(dsp, "Failed to read algorithm info: %d\n",
390 ret);
391 return ret;
392 }
393
394 algs = be32_to_cpu(adsp1_id.algs);
395 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
396 be32_to_cpu(adsp1_id.fw.id),
397 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
398 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
399 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
400 algs);
401
402 pos = sizeof(adsp1_id) / 2;
403 term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
404 break;
405
406 case WMFW_ADSP2:
407 ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
408 sizeof(adsp2_id));
409 if (ret != 0) {
410 adsp_err(dsp, "Failed to read algorithm info: %d\n",
411 ret);
412 return ret;
413 }
414
415 algs = be32_to_cpu(adsp2_id.algs);
416 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
417 be32_to_cpu(adsp2_id.fw.id),
418 (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
419 (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
420 be32_to_cpu(adsp2_id.fw.ver) & 0xff,
421 algs);
422
423 pos = sizeof(adsp2_id) / 2;
424 term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
425 break;
426
427 default:
428 BUG_ON(NULL == "Unknown DSP type");
429 return -EINVAL;
430 }
431
432 if (algs == 0) {
433 adsp_err(dsp, "No algorithms\n");
434 return -EINVAL;
435 }
436
437 /* Read the terminator first to validate the length */
438 ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
439 if (ret != 0) {
440 adsp_err(dsp, "Failed to read algorithm list end: %d\n",
441 ret);
442 return ret;
443 }
444
445 if (be32_to_cpu(val) != 0xbedead)
446 adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
447 term, be32_to_cpu(val));
448
449 alg = kzalloc((term - pos) * 2, GFP_KERNEL);
450 if (!alg)
451 return -ENOMEM;
452
453 ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
454 if (ret != 0) {
455 adsp_err(dsp, "Failed to read algorithm list: %d\n",
456 ret);
457 goto out;
458 }
459
460 adsp1_alg = alg;
461 adsp2_alg = alg;
462
463 for (i = 0; i < algs; i++) {
464 switch (dsp->type) {
465 case WMFW_ADSP1:
466 adsp_info(dsp, "%d: ID %x v%d.%d.%d\n",
467 i, be32_to_cpu(adsp1_alg[i].alg.id),
468 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
469 (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
470 be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff);
471 break;
472
473 case WMFW_ADSP2:
474 adsp_info(dsp, "%d: ID %x v%d.%d.%d\n",
475 i, be32_to_cpu(adsp2_alg[i].alg.id),
476 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
477 (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
478 be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff);
479 break;
480 }
481 }
482
483out:
484 kfree(alg);
485 return ret;
486}
487
353static int wm_adsp_load_coeff(struct wm_adsp *dsp) 488static int wm_adsp_load_coeff(struct wm_adsp *dsp)
354{ 489{
355 struct regmap *regmap = dsp->regmap; 490 struct regmap *regmap = dsp->regmap;
@@ -468,6 +603,10 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
468 if (ret != 0) 603 if (ret != 0)
469 goto err; 604 goto err;
470 605
606 ret = wm_adsp_setup_algs(dsp);
607 if (ret != 0)
608 goto err;
609
471 ret = wm_adsp_load_coeff(dsp); 610 ret = wm_adsp_load_coeff(dsp);
472 if (ret != 0) 611 if (ret != 0)
473 goto err; 612 goto err;
@@ -604,6 +743,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
604 if (ret != 0) 743 if (ret != 0)
605 goto err; 744 goto err;
606 745
746 ret = wm_adsp_setup_algs(dsp);
747 if (ret != 0)
748 goto err;
749
607 ret = wm_adsp_load_coeff(dsp); 750 ret = wm_adsp_load_coeff(dsp);
608 if (ret != 0) 751 if (ret != 0)
609 goto err; 752 goto err;