diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-01-13 07:33:03 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-01-13 07:33:03 -0500 |
commit | d37fb92326da880947d4dd72684ef1dd2d245727 (patch) | |
tree | 9f16c2061f5f1be6c02c355335645a17abb62f0e /sound | |
parent | b272efc8600a7bbf2dd91d0eba8a3b8949e84497 (diff) | |
parent | 1023dbd90c1e3e87921198939917c1f50b4b6af7 (diff) |
Merge remote-tracking branch 'asoc/topic/adsp' into asoc-arizona
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 367 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.h | 14 |
2 files changed, 374 insertions, 7 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index ffc89fab96fb..1f8e8e2a1a6a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -143,6 +143,71 @@ | |||
143 | #define ADSP2_RAM_RDY_SHIFT 0 | 143 | #define ADSP2_RAM_RDY_SHIFT 0 |
144 | #define ADSP2_RAM_RDY_WIDTH 1 | 144 | #define ADSP2_RAM_RDY_WIDTH 1 |
145 | 145 | ||
146 | #define WM_ADSP_NUM_FW 3 | ||
147 | |||
148 | static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { | ||
149 | "MBC/VSS", "Tx", "Rx ANC" | ||
150 | }; | ||
151 | |||
152 | static struct { | ||
153 | const char *file; | ||
154 | } wm_adsp_fw[WM_ADSP_NUM_FW] = { | ||
155 | { .file = "mbc-vss" }, | ||
156 | { .file = "tx" }, | ||
157 | { .file = "rx-anc" }, | ||
158 | }; | ||
159 | |||
160 | static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, | ||
161 | struct snd_ctl_elem_value *ucontrol) | ||
162 | { | ||
163 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
164 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
165 | struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); | ||
166 | |||
167 | ucontrol->value.integer.value[0] = adsp[e->shift_l].fw; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, | ||
173 | struct snd_ctl_elem_value *ucontrol) | ||
174 | { | ||
175 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
176 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
177 | struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec); | ||
178 | |||
179 | if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw) | ||
180 | return 0; | ||
181 | |||
182 | if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) | ||
183 | return -EINVAL; | ||
184 | |||
185 | if (adsp[e->shift_l].running) | ||
186 | return -EBUSY; | ||
187 | |||
188 | adsp->fw = ucontrol->value.integer.value[0]; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static const struct soc_enum wm_adsp_fw_enum[] = { | ||
194 | SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), | ||
195 | SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), | ||
196 | SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), | ||
197 | SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), | ||
198 | }; | ||
199 | |||
200 | const struct snd_kcontrol_new wm_adsp_fw_controls[] = { | ||
201 | SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], | ||
202 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
203 | SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], | ||
204 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
205 | SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], | ||
206 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
207 | SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], | ||
208 | wm_adsp_fw_get, wm_adsp_fw_put), | ||
209 | }; | ||
210 | EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); | ||
146 | 211 | ||
147 | static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, | 212 | static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, |
148 | int type) | 213 | int type) |
@@ -156,6 +221,26 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, | |||
156 | return NULL; | 221 | return NULL; |
157 | } | 222 | } |
158 | 223 | ||
224 | static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region, | ||
225 | unsigned int offset) | ||
226 | { | ||
227 | switch (region->type) { | ||
228 | case WMFW_ADSP1_PM: | ||
229 | return region->base + (offset * 3); | ||
230 | case WMFW_ADSP1_DM: | ||
231 | return region->base + (offset * 2); | ||
232 | case WMFW_ADSP2_XM: | ||
233 | return region->base + (offset * 2); | ||
234 | case WMFW_ADSP2_YM: | ||
235 | return region->base + (offset * 2); | ||
236 | case WMFW_ADSP1_ZM: | ||
237 | return region->base + (offset * 2); | ||
238 | default: | ||
239 | WARN_ON(NULL != "Unknown memory region type"); | ||
240 | return offset; | ||
241 | } | ||
242 | } | ||
243 | |||
159 | static int wm_adsp_load(struct wm_adsp *dsp) | 244 | static int wm_adsp_load(struct wm_adsp *dsp) |
160 | { | 245 | { |
161 | const struct firmware *firmware; | 246 | const struct firmware *firmware; |
@@ -177,7 +262,8 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
177 | if (file == NULL) | 262 | if (file == NULL) |
178 | return -ENOMEM; | 263 | return -ENOMEM; |
179 | 264 | ||
180 | snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num); | 265 | snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num, |
266 | wm_adsp_fw[dsp->fw].file); | ||
181 | file[PAGE_SIZE - 1] = '\0'; | 267 | file[PAGE_SIZE - 1] = '\0'; |
182 | 268 | ||
183 | ret = request_firmware(&firmware, file, dsp->dev); | 269 | ret = request_firmware(&firmware, file, dsp->dev); |
@@ -282,27 +368,27 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
282 | case WMFW_ADSP1_PM: | 368 | case WMFW_ADSP1_PM: |
283 | BUG_ON(!mem); | 369 | BUG_ON(!mem); |
284 | region_name = "PM"; | 370 | region_name = "PM"; |
285 | reg = mem->base + (offset * 3); | 371 | reg = wm_adsp_region_to_reg(mem, offset); |
286 | break; | 372 | break; |
287 | case WMFW_ADSP1_DM: | 373 | case WMFW_ADSP1_DM: |
288 | BUG_ON(!mem); | 374 | BUG_ON(!mem); |
289 | region_name = "DM"; | 375 | region_name = "DM"; |
290 | reg = mem->base + (offset * 2); | 376 | reg = wm_adsp_region_to_reg(mem, offset); |
291 | break; | 377 | break; |
292 | case WMFW_ADSP2_XM: | 378 | case WMFW_ADSP2_XM: |
293 | BUG_ON(!mem); | 379 | BUG_ON(!mem); |
294 | region_name = "XM"; | 380 | region_name = "XM"; |
295 | reg = mem->base + (offset * 2); | 381 | reg = wm_adsp_region_to_reg(mem, offset); |
296 | break; | 382 | break; |
297 | case WMFW_ADSP2_YM: | 383 | case WMFW_ADSP2_YM: |
298 | BUG_ON(!mem); | 384 | BUG_ON(!mem); |
299 | region_name = "YM"; | 385 | region_name = "YM"; |
300 | reg = mem->base + (offset * 2); | 386 | reg = wm_adsp_region_to_reg(mem, offset); |
301 | break; | 387 | break; |
302 | case WMFW_ADSP1_ZM: | 388 | case WMFW_ADSP1_ZM: |
303 | BUG_ON(!mem); | 389 | BUG_ON(!mem); |
304 | region_name = "ZM"; | 390 | region_name = "ZM"; |
305 | reg = mem->base + (offset * 2); | 391 | reg = wm_adsp_region_to_reg(mem, offset); |
306 | break; | 392 | break; |
307 | default: | 393 | default: |
308 | adsp_warn(dsp, | 394 | adsp_warn(dsp, |
@@ -350,12 +436,224 @@ out: | |||
350 | return ret; | 436 | return ret; |
351 | } | 437 | } |
352 | 438 | ||
439 | static int wm_adsp_setup_algs(struct wm_adsp *dsp) | ||
440 | { | ||
441 | struct regmap *regmap = dsp->regmap; | ||
442 | struct wmfw_adsp1_id_hdr adsp1_id; | ||
443 | struct wmfw_adsp2_id_hdr adsp2_id; | ||
444 | struct wmfw_adsp1_alg_hdr *adsp1_alg; | ||
445 | struct wmfw_adsp2_alg_hdr *adsp2_alg; | ||
446 | void *alg, *buf; | ||
447 | struct wm_adsp_alg_region *region; | ||
448 | const struct wm_adsp_region *mem; | ||
449 | unsigned int pos, term; | ||
450 | size_t algs, buf_size; | ||
451 | __be32 val; | ||
452 | int i, ret; | ||
453 | |||
454 | switch (dsp->type) { | ||
455 | case WMFW_ADSP1: | ||
456 | mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); | ||
457 | break; | ||
458 | case WMFW_ADSP2: | ||
459 | mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); | ||
460 | break; | ||
461 | default: | ||
462 | mem = NULL; | ||
463 | break; | ||
464 | } | ||
465 | |||
466 | if (mem == NULL) { | ||
467 | BUG_ON(mem != NULL); | ||
468 | return -EINVAL; | ||
469 | } | ||
470 | |||
471 | switch (dsp->type) { | ||
472 | case WMFW_ADSP1: | ||
473 | ret = regmap_raw_read(regmap, mem->base, &adsp1_id, | ||
474 | sizeof(adsp1_id)); | ||
475 | if (ret != 0) { | ||
476 | adsp_err(dsp, "Failed to read algorithm info: %d\n", | ||
477 | ret); | ||
478 | return ret; | ||
479 | } | ||
480 | |||
481 | buf = &adsp1_id; | ||
482 | buf_size = sizeof(adsp1_id); | ||
483 | |||
484 | algs = be32_to_cpu(adsp1_id.algs); | ||
485 | adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", | ||
486 | be32_to_cpu(adsp1_id.fw.id), | ||
487 | (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, | ||
488 | (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, | ||
489 | be32_to_cpu(adsp1_id.fw.ver) & 0xff, | ||
490 | algs); | ||
491 | |||
492 | pos = sizeof(adsp1_id) / 2; | ||
493 | term = pos + ((sizeof(*adsp1_alg) * algs) / 2); | ||
494 | break; | ||
495 | |||
496 | case WMFW_ADSP2: | ||
497 | ret = regmap_raw_read(regmap, mem->base, &adsp2_id, | ||
498 | sizeof(adsp2_id)); | ||
499 | if (ret != 0) { | ||
500 | adsp_err(dsp, "Failed to read algorithm info: %d\n", | ||
501 | ret); | ||
502 | return ret; | ||
503 | } | ||
504 | |||
505 | buf = &adsp2_id; | ||
506 | buf_size = sizeof(adsp2_id); | ||
507 | |||
508 | algs = be32_to_cpu(adsp2_id.algs); | ||
509 | adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", | ||
510 | be32_to_cpu(adsp2_id.fw.id), | ||
511 | (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, | ||
512 | (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, | ||
513 | be32_to_cpu(adsp2_id.fw.ver) & 0xff, | ||
514 | algs); | ||
515 | |||
516 | pos = sizeof(adsp2_id) / 2; | ||
517 | term = pos + ((sizeof(*adsp2_alg) * algs) / 2); | ||
518 | break; | ||
519 | |||
520 | default: | ||
521 | BUG_ON(NULL == "Unknown DSP type"); | ||
522 | return -EINVAL; | ||
523 | } | ||
524 | |||
525 | if (algs == 0) { | ||
526 | adsp_err(dsp, "No algorithms\n"); | ||
527 | return -EINVAL; | ||
528 | } | ||
529 | |||
530 | if (algs > 1024) { | ||
531 | adsp_err(dsp, "Algorithm count %zx excessive\n", algs); | ||
532 | print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET, | ||
533 | buf, buf_size); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | /* Read the terminator first to validate the length */ | ||
538 | ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val)); | ||
539 | if (ret != 0) { | ||
540 | adsp_err(dsp, "Failed to read algorithm list end: %d\n", | ||
541 | ret); | ||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | if (be32_to_cpu(val) != 0xbedead) | ||
546 | adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", | ||
547 | term, be32_to_cpu(val)); | ||
548 | |||
549 | alg = kzalloc((term - pos) * 2, GFP_KERNEL); | ||
550 | if (!alg) | ||
551 | return -ENOMEM; | ||
552 | |||
553 | ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2); | ||
554 | if (ret != 0) { | ||
555 | adsp_err(dsp, "Failed to read algorithm list: %d\n", | ||
556 | ret); | ||
557 | goto out; | ||
558 | } | ||
559 | |||
560 | adsp1_alg = alg; | ||
561 | adsp2_alg = alg; | ||
562 | |||
563 | for (i = 0; i < algs; i++) { | ||
564 | switch (dsp->type) { | ||
565 | case WMFW_ADSP1: | ||
566 | adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", | ||
567 | i, be32_to_cpu(adsp1_alg[i].alg.id), | ||
568 | (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, | ||
569 | (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, | ||
570 | be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, | ||
571 | be32_to_cpu(adsp1_alg[i].dm), | ||
572 | be32_to_cpu(adsp1_alg[i].zm)); | ||
573 | |||
574 | if (adsp1_alg[i].dm) { | ||
575 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
576 | if (!region) | ||
577 | return -ENOMEM; | ||
578 | region->type = WMFW_ADSP1_DM; | ||
579 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | ||
580 | region->base = be32_to_cpu(adsp1_alg[i].dm); | ||
581 | list_add_tail(®ion->list, | ||
582 | &dsp->alg_regions); | ||
583 | } | ||
584 | |||
585 | if (adsp1_alg[i].zm) { | ||
586 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
587 | if (!region) | ||
588 | return -ENOMEM; | ||
589 | region->type = WMFW_ADSP1_ZM; | ||
590 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | ||
591 | region->base = be32_to_cpu(adsp1_alg[i].zm); | ||
592 | list_add_tail(®ion->list, | ||
593 | &dsp->alg_regions); | ||
594 | } | ||
595 | break; | ||
596 | |||
597 | case WMFW_ADSP2: | ||
598 | adsp_info(dsp, | ||
599 | "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", | ||
600 | i, be32_to_cpu(adsp2_alg[i].alg.id), | ||
601 | (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, | ||
602 | (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, | ||
603 | be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, | ||
604 | be32_to_cpu(adsp2_alg[i].xm), | ||
605 | be32_to_cpu(adsp2_alg[i].ym), | ||
606 | be32_to_cpu(adsp2_alg[i].zm)); | ||
607 | |||
608 | if (adsp2_alg[i].xm) { | ||
609 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
610 | if (!region) | ||
611 | return -ENOMEM; | ||
612 | region->type = WMFW_ADSP2_XM; | ||
613 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | ||
614 | region->base = be32_to_cpu(adsp2_alg[i].xm); | ||
615 | list_add_tail(®ion->list, | ||
616 | &dsp->alg_regions); | ||
617 | } | ||
618 | |||
619 | if (adsp2_alg[i].ym) { | ||
620 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
621 | if (!region) | ||
622 | return -ENOMEM; | ||
623 | region->type = WMFW_ADSP2_YM; | ||
624 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | ||
625 | region->base = be32_to_cpu(adsp2_alg[i].ym); | ||
626 | list_add_tail(®ion->list, | ||
627 | &dsp->alg_regions); | ||
628 | } | ||
629 | |||
630 | if (adsp2_alg[i].zm) { | ||
631 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
632 | if (!region) | ||
633 | return -ENOMEM; | ||
634 | region->type = WMFW_ADSP2_ZM; | ||
635 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | ||
636 | region->base = be32_to_cpu(adsp2_alg[i].zm); | ||
637 | list_add_tail(®ion->list, | ||
638 | &dsp->alg_regions); | ||
639 | } | ||
640 | break; | ||
641 | } | ||
642 | } | ||
643 | |||
644 | out: | ||
645 | kfree(alg); | ||
646 | return ret; | ||
647 | } | ||
648 | |||
353 | static int wm_adsp_load_coeff(struct wm_adsp *dsp) | 649 | static int wm_adsp_load_coeff(struct wm_adsp *dsp) |
354 | { | 650 | { |
355 | struct regmap *regmap = dsp->regmap; | 651 | struct regmap *regmap = dsp->regmap; |
356 | struct wmfw_coeff_hdr *hdr; | 652 | struct wmfw_coeff_hdr *hdr; |
357 | struct wmfw_coeff_item *blk; | 653 | struct wmfw_coeff_item *blk; |
358 | const struct firmware *firmware; | 654 | const struct firmware *firmware; |
655 | const struct wm_adsp_region *mem; | ||
656 | struct wm_adsp_alg_region *alg_region; | ||
359 | const char *region_name; | 657 | const char *region_name; |
360 | int ret, pos, blocks, type, offset, reg; | 658 | int ret, pos, blocks, type, offset, reg; |
361 | char *file; | 659 | char *file; |
@@ -364,7 +662,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
364 | if (file == NULL) | 662 | if (file == NULL) |
365 | return -ENOMEM; | 663 | return -ENOMEM; |
366 | 664 | ||
367 | snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num); | 665 | snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num, |
666 | wm_adsp_fw[dsp->fw].file); | ||
368 | file[PAGE_SIZE - 1] = '\0'; | 667 | file[PAGE_SIZE - 1] = '\0'; |
369 | 668 | ||
370 | ret = request_firmware(&firmware, file, dsp->dev); | 669 | ret = request_firmware(&firmware, file, dsp->dev); |
@@ -420,6 +719,37 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
420 | region_name = "register"; | 719 | region_name = "register"; |
421 | reg = offset; | 720 | reg = offset; |
422 | break; | 721 | break; |
722 | |||
723 | case WMFW_ADSP1_DM: | ||
724 | case WMFW_ADSP1_ZM: | ||
725 | case WMFW_ADSP2_XM: | ||
726 | case WMFW_ADSP2_YM: | ||
727 | adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", | ||
728 | file, blocks, le32_to_cpu(blk->len), | ||
729 | type, le32_to_cpu(blk->id)); | ||
730 | |||
731 | mem = wm_adsp_find_region(dsp, type); | ||
732 | if (!mem) { | ||
733 | adsp_err(dsp, "No base for region %x\n", type); | ||
734 | break; | ||
735 | } | ||
736 | |||
737 | reg = 0; | ||
738 | list_for_each_entry(alg_region, | ||
739 | &dsp->alg_regions, list) { | ||
740 | if (le32_to_cpu(blk->id) == alg_region->alg && | ||
741 | type == alg_region->type) { | ||
742 | reg = alg_region->base + offset; | ||
743 | reg = wm_adsp_region_to_reg(mem, | ||
744 | reg); | ||
745 | } | ||
746 | } | ||
747 | |||
748 | if (reg == 0) | ||
749 | adsp_err(dsp, "No %x for algorithm %x\n", | ||
750 | type, le32_to_cpu(blk->id)); | ||
751 | break; | ||
752 | |||
423 | default: | 753 | default: |
424 | adsp_err(dsp, "Unknown region type %x\n", type); | 754 | adsp_err(dsp, "Unknown region type %x\n", type); |
425 | break; | 755 | break; |
@@ -468,6 +798,10 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
468 | if (ret != 0) | 798 | if (ret != 0) |
469 | goto err; | 799 | goto err; |
470 | 800 | ||
801 | ret = wm_adsp_setup_algs(dsp); | ||
802 | if (ret != 0) | ||
803 | goto err; | ||
804 | |||
471 | ret = wm_adsp_load_coeff(dsp); | 805 | ret = wm_adsp_load_coeff(dsp); |
472 | if (ret != 0) | 806 | if (ret != 0) |
473 | goto err; | 807 | goto err; |
@@ -539,6 +873,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
539 | struct snd_soc_codec *codec = w->codec; | 873 | struct snd_soc_codec *codec = w->codec; |
540 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 874 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); |
541 | struct wm_adsp *dsp = &dsps[w->shift]; | 875 | struct wm_adsp *dsp = &dsps[w->shift]; |
876 | struct wm_adsp_alg_region *alg_region; | ||
542 | unsigned int val; | 877 | unsigned int val; |
543 | int ret; | 878 | int ret; |
544 | 879 | ||
@@ -604,6 +939,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
604 | if (ret != 0) | 939 | if (ret != 0) |
605 | goto err; | 940 | goto err; |
606 | 941 | ||
942 | ret = wm_adsp_setup_algs(dsp); | ||
943 | if (ret != 0) | ||
944 | goto err; | ||
945 | |||
607 | ret = wm_adsp_load_coeff(dsp); | 946 | ret = wm_adsp_load_coeff(dsp); |
608 | if (ret != 0) | 947 | if (ret != 0) |
609 | goto err; | 948 | goto err; |
@@ -614,9 +953,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
614 | ADSP2_CORE_ENA | ADSP2_START); | 953 | ADSP2_CORE_ENA | ADSP2_START); |
615 | if (ret != 0) | 954 | if (ret != 0) |
616 | goto err; | 955 | goto err; |
956 | |||
957 | dsp->running = true; | ||
617 | break; | 958 | break; |
618 | 959 | ||
619 | case SND_SOC_DAPM_PRE_PMD: | 960 | case SND_SOC_DAPM_PRE_PMD: |
961 | dsp->running = false; | ||
962 | |||
620 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | 963 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
621 | ADSP2_SYS_ENA | ADSP2_CORE_ENA | | 964 | ADSP2_SYS_ENA | ADSP2_CORE_ENA | |
622 | ADSP2_START, 0); | 965 | ADSP2_START, 0); |
@@ -635,6 +978,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
635 | "Failed to enable supply: %d\n", | 978 | "Failed to enable supply: %d\n", |
636 | ret); | 979 | ret); |
637 | } | 980 | } |
981 | |||
982 | while (!list_empty(&dsp->alg_regions)) { | ||
983 | alg_region = list_first_entry(&dsp->alg_regions, | ||
984 | struct wm_adsp_alg_region, | ||
985 | list); | ||
986 | list_del(&alg_region->list); | ||
987 | kfree(alg_region); | ||
988 | } | ||
638 | break; | 989 | break; |
639 | 990 | ||
640 | default: | 991 | default: |
@@ -664,6 +1015,8 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) | |||
664 | return ret; | 1015 | return ret; |
665 | } | 1016 | } |
666 | 1017 | ||
1018 | INIT_LIST_HEAD(&adsp->alg_regions); | ||
1019 | |||
667 | if (dvfs) { | 1020 | if (dvfs) { |
668 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); | 1021 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); |
669 | if (IS_ERR(adsp->dvfs)) { | 1022 | if (IS_ERR(adsp->dvfs)) { |
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index ffd29a4609e2..5e71410f8b05 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h | |||
@@ -25,6 +25,13 @@ struct wm_adsp_region { | |||
25 | unsigned int base; | 25 | unsigned int base; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct wm_adsp_alg_region { | ||
29 | struct list_head list; | ||
30 | unsigned int alg; | ||
31 | int type; | ||
32 | unsigned int base; | ||
33 | }; | ||
34 | |||
28 | struct wm_adsp { | 35 | struct wm_adsp { |
29 | const char *part; | 36 | const char *part; |
30 | int num; | 37 | int num; |
@@ -34,9 +41,14 @@ struct wm_adsp { | |||
34 | 41 | ||
35 | int base; | 42 | int base; |
36 | 43 | ||
44 | struct list_head alg_regions; | ||
45 | |||
37 | const struct wm_adsp_region *mem; | 46 | const struct wm_adsp_region *mem; |
38 | int num_mems; | 47 | int num_mems; |
39 | 48 | ||
49 | int fw; | ||
50 | bool running; | ||
51 | |||
40 | struct regulator *dvfs; | 52 | struct regulator *dvfs; |
41 | }; | 53 | }; |
42 | 54 | ||
@@ -50,6 +62,8 @@ struct wm_adsp { | |||
50 | .shift = num, .event = wm_adsp2_event, \ | 62 | .shift = num, .event = wm_adsp2_event, \ |
51 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } | 63 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } |
52 | 64 | ||
65 | extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; | ||
66 | |||
53 | int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); | 67 | int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs); |
54 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, | 68 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, |
55 | struct snd_kcontrol *kcontrol, int event); | 69 | struct snd_kcontrol *kcontrol, int event); |