aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2013-06-30 07:42:24 -0400
committerMark Brown <broonie@linaro.org>2013-06-30 07:42:24 -0400
commitfbc6c4ee659da5bdd49ab85c5d7e50c51db1b4fa (patch)
tree22da5a7ae0c2f038ff404c37220f5471cc44e214 /sound
parent4494783793459dc601aad574802e81592cf3173f (diff)
parent0c2e3f3420bb790a4e5bc14d3d50a722964ad73e (diff)
Merge remote-tracking branch 'asoc/topic/adsp' into asoc-next
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm_adsp.c459
-rw-r--r--sound/soc/codecs/wm_adsp.h3
2 files changed, 455 insertions, 7 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 3470b649c0b2..ddba3fea39eb 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -21,6 +21,7 @@
21#include <linux/regmap.h> 21#include <linux/regmap.h>
22#include <linux/regulator/consumer.h> 22#include <linux/regulator/consumer.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/workqueue.h>
24#include <sound/core.h> 25#include <sound/core.h>
25#include <sound/pcm.h> 26#include <sound/pcm.h>
26#include <sound/pcm_params.h> 27#include <sound/pcm_params.h>
@@ -215,6 +216,36 @@ static struct {
215 [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, 216 [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" },
216}; 217};
217 218
219struct wm_coeff_ctl_ops {
220 int (*xget)(struct snd_kcontrol *kcontrol,
221 struct snd_ctl_elem_value *ucontrol);
222 int (*xput)(struct snd_kcontrol *kcontrol,
223 struct snd_ctl_elem_value *ucontrol);
224 int (*xinfo)(struct snd_kcontrol *kcontrol,
225 struct snd_ctl_elem_info *uinfo);
226};
227
228struct wm_coeff {
229 struct device *dev;
230 struct list_head ctl_list;
231 struct regmap *regmap;
232};
233
234struct wm_coeff_ctl {
235 const char *name;
236 struct snd_card *card;
237 struct wm_adsp_alg_region region;
238 struct wm_coeff_ctl_ops ops;
239 struct wm_adsp *adsp;
240 void *private;
241 unsigned int enabled:1;
242 struct list_head list;
243 void *cache;
244 size_t len;
245 unsigned int set:1;
246 struct snd_kcontrol *kcontrol;
247};
248
218static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, 249static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
219 struct snd_ctl_elem_value *ucontrol) 250 struct snd_ctl_elem_value *ucontrol)
220{ 251{
@@ -334,6 +365,181 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
334 } 365 }
335} 366}
336 367
368static int wm_coeff_info(struct snd_kcontrol *kcontrol,
369 struct snd_ctl_elem_info *uinfo)
370{
371 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
372
373 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
374 uinfo->count = ctl->len;
375 return 0;
376}
377
378static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
379 const void *buf, size_t len)
380{
381 struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
382 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
383 struct wm_adsp_alg_region *region = &ctl->region;
384 const struct wm_adsp_region *mem;
385 struct wm_adsp *adsp = ctl->adsp;
386 void *scratch;
387 int ret;
388 unsigned int reg;
389
390 mem = wm_adsp_find_region(adsp, region->type);
391 if (!mem) {
392 adsp_err(adsp, "No base for region %x\n",
393 region->type);
394 return -EINVAL;
395 }
396
397 reg = ctl->region.base;
398 reg = wm_adsp_region_to_reg(mem, reg);
399
400 scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
401 if (!scratch)
402 return -ENOMEM;
403
404 ret = regmap_raw_write(wm_coeff->regmap, reg, scratch,
405 ctl->len);
406 if (ret) {
407 adsp_err(adsp, "Failed to write %zu bytes to %x\n",
408 ctl->len, reg);
409 kfree(scratch);
410 return ret;
411 }
412
413 kfree(scratch);
414
415 return 0;
416}
417
418static int wm_coeff_put(struct snd_kcontrol *kcontrol,
419 struct snd_ctl_elem_value *ucontrol)
420{
421 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
422 char *p = ucontrol->value.bytes.data;
423
424 memcpy(ctl->cache, p, ctl->len);
425
426 if (!ctl->enabled) {
427 ctl->set = 1;
428 return 0;
429 }
430
431 return wm_coeff_write_control(kcontrol, p, ctl->len);
432}
433
434static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
435 void *buf, size_t len)
436{
437 struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
438 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
439 struct wm_adsp_alg_region *region = &ctl->region;
440 const struct wm_adsp_region *mem;
441 struct wm_adsp *adsp = ctl->adsp;
442 void *scratch;
443 int ret;
444 unsigned int reg;
445
446 mem = wm_adsp_find_region(adsp, region->type);
447 if (!mem) {
448 adsp_err(adsp, "No base for region %x\n",
449 region->type);
450 return -EINVAL;
451 }
452
453 reg = ctl->region.base;
454 reg = wm_adsp_region_to_reg(mem, reg);
455
456 scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
457 if (!scratch)
458 return -ENOMEM;
459
460 ret = regmap_raw_read(wm_coeff->regmap, reg, scratch, ctl->len);
461 if (ret) {
462 adsp_err(adsp, "Failed to read %zu bytes from %x\n",
463 ctl->len, reg);
464 kfree(scratch);
465 return ret;
466 }
467
468 memcpy(buf, scratch, ctl->len);
469 kfree(scratch);
470
471 return 0;
472}
473
474static int wm_coeff_get(struct snd_kcontrol *kcontrol,
475 struct snd_ctl_elem_value *ucontrol)
476{
477 struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
478 char *p = ucontrol->value.bytes.data;
479
480 memcpy(p, ctl->cache, ctl->len);
481 return 0;
482}
483
484static int wm_coeff_add_kcontrol(struct wm_coeff *wm_coeff,
485 struct wm_coeff_ctl *ctl,
486 const struct snd_kcontrol_new *kctl)
487{
488 int ret;
489 struct snd_kcontrol *kcontrol;
490
491 kcontrol = snd_ctl_new1(kctl, wm_coeff);
492 ret = snd_ctl_add(ctl->card, kcontrol);
493 if (ret < 0) {
494 dev_err(wm_coeff->dev, "Failed to add %s: %d\n",
495 kctl->name, ret);
496 return ret;
497 }
498 ctl->kcontrol = kcontrol;
499 return 0;
500}
501
502struct wmfw_ctl_work {
503 struct wm_coeff *wm_coeff;
504 struct wm_coeff_ctl *ctl;
505 struct work_struct work;
506};
507
508static int wmfw_add_ctl(struct wm_coeff *wm_coeff,
509 struct wm_coeff_ctl *ctl)
510{
511 struct snd_kcontrol_new *kcontrol;
512 int ret;
513
514 if (!wm_coeff || !ctl || !ctl->name || !ctl->card)
515 return -EINVAL;
516
517 kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
518 if (!kcontrol)
519 return -ENOMEM;
520 kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
521
522 kcontrol->name = ctl->name;
523 kcontrol->info = wm_coeff_info;
524 kcontrol->get = wm_coeff_get;
525 kcontrol->put = wm_coeff_put;
526 kcontrol->private_value = (unsigned long)ctl;
527
528 ret = wm_coeff_add_kcontrol(wm_coeff,
529 ctl, kcontrol);
530 if (ret < 0)
531 goto err_kcontrol;
532
533 kfree(kcontrol);
534
535 list_add(&ctl->list, &wm_coeff->ctl_list);
536 return 0;
537
538err_kcontrol:
539 kfree(kcontrol);
540 return ret;
541}
542
337static int wm_adsp_load(struct wm_adsp *dsp) 543static int wm_adsp_load(struct wm_adsp *dsp)
338{ 544{
339 LIST_HEAD(buf_list); 545 LIST_HEAD(buf_list);
@@ -547,7 +753,157 @@ out:
547 return ret; 753 return ret;
548} 754}
549 755
550static int wm_adsp_setup_algs(struct wm_adsp *dsp) 756static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff)
757{
758 struct wm_coeff_ctl *ctl;
759 int ret;
760
761 list_for_each_entry(ctl, &wm_coeff->ctl_list,
762 list) {
763 if (!ctl->enabled || ctl->set)
764 continue;
765 ret = wm_coeff_read_control(ctl->kcontrol,
766 ctl->cache,
767 ctl->len);
768 if (ret < 0)
769 return ret;
770 }
771
772 return 0;
773}
774
775static int wm_coeff_sync_controls(struct wm_coeff *wm_coeff)
776{
777 struct wm_coeff_ctl *ctl;
778 int ret;
779
780 list_for_each_entry(ctl, &wm_coeff->ctl_list,
781 list) {
782 if (!ctl->enabled)
783 continue;
784 if (ctl->set) {
785 ret = wm_coeff_write_control(ctl->kcontrol,
786 ctl->cache,
787 ctl->len);
788 if (ret < 0)
789 return ret;
790 }
791 }
792
793 return 0;
794}
795
796static void wm_adsp_ctl_work(struct work_struct *work)
797{
798 struct wmfw_ctl_work *ctl_work = container_of(work,
799 struct wmfw_ctl_work,
800 work);
801
802 wmfw_add_ctl(ctl_work->wm_coeff, ctl_work->ctl);
803 kfree(ctl_work);
804}
805
806static int wm_adsp_create_control(struct snd_soc_codec *codec,
807 const struct wm_adsp_alg_region *region)
808
809{
810 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
811 struct wm_coeff_ctl *ctl;
812 struct wmfw_ctl_work *ctl_work;
813 char *name;
814 char *region_name;
815 int ret;
816
817 name = kmalloc(PAGE_SIZE, GFP_KERNEL);
818 if (!name)
819 return -ENOMEM;
820
821 switch (region->type) {
822 case WMFW_ADSP1_PM:
823 region_name = "PM";
824 break;
825 case WMFW_ADSP1_DM:
826 region_name = "DM";
827 break;
828 case WMFW_ADSP2_XM:
829 region_name = "XM";
830 break;
831 case WMFW_ADSP2_YM:
832 region_name = "YM";
833 break;
834 case WMFW_ADSP1_ZM:
835 region_name = "ZM";
836 break;
837 default:
838 ret = -EINVAL;
839 goto err_name;
840 }
841
842 snprintf(name, PAGE_SIZE, "DSP%d %s %x",
843 dsp->num, region_name, region->alg);
844
845 list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
846 list) {
847 if (!strcmp(ctl->name, name)) {
848 if (!ctl->enabled)
849 ctl->enabled = 1;
850 goto found;
851 }
852 }
853
854 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
855 if (!ctl) {
856 ret = -ENOMEM;
857 goto err_name;
858 }
859 ctl->region = *region;
860 ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
861 if (!ctl->name) {
862 ret = -ENOMEM;
863 goto err_ctl;
864 }
865 ctl->enabled = 1;
866 ctl->set = 0;
867 ctl->ops.xget = wm_coeff_get;
868 ctl->ops.xput = wm_coeff_put;
869 ctl->card = codec->card->snd_card;
870 ctl->adsp = dsp;
871
872 ctl->len = region->len;
873 ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
874 if (!ctl->cache) {
875 ret = -ENOMEM;
876 goto err_ctl_name;
877 }
878
879 ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
880 if (!ctl_work) {
881 ret = -ENOMEM;
882 goto err_ctl_cache;
883 }
884
885 ctl_work->wm_coeff = dsp->wm_coeff;
886 ctl_work->ctl = ctl;
887 INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
888 schedule_work(&ctl_work->work);
889
890found:
891 kfree(name);
892
893 return 0;
894
895err_ctl_cache:
896 kfree(ctl->cache);
897err_ctl_name:
898 kfree(ctl->name);
899err_ctl:
900 kfree(ctl);
901err_name:
902 kfree(name);
903 return ret;
904}
905
906static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
551{ 907{
552 struct regmap *regmap = dsp->regmap; 908 struct regmap *regmap = dsp->regmap;
553 struct wmfw_adsp1_id_hdr adsp1_id; 909 struct wmfw_adsp1_id_hdr adsp1_id;
@@ -730,7 +1086,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
730 region->type = WMFW_ADSP1_DM; 1086 region->type = WMFW_ADSP1_DM;
731 region->alg = be32_to_cpu(adsp1_alg[i].alg.id); 1087 region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
732 region->base = be32_to_cpu(adsp1_alg[i].dm); 1088 region->base = be32_to_cpu(adsp1_alg[i].dm);
1089 region->len = 0;
733 list_add_tail(&region->list, &dsp->alg_regions); 1090 list_add_tail(&region->list, &dsp->alg_regions);
1091 if (i + 1 < algs) {
1092 region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
1093 region->len -= be32_to_cpu(adsp1_alg[i].dm);
1094 wm_adsp_create_control(codec, region);
1095 } else {
1096 adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
1097 be32_to_cpu(adsp1_alg[i].alg.id));
1098 }
734 1099
735 region = kzalloc(sizeof(*region), GFP_KERNEL); 1100 region = kzalloc(sizeof(*region), GFP_KERNEL);
736 if (!region) 1101 if (!region)
@@ -738,7 +1103,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
738 region->type = WMFW_ADSP1_ZM; 1103 region->type = WMFW_ADSP1_ZM;
739 region->alg = be32_to_cpu(adsp1_alg[i].alg.id); 1104 region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
740 region->base = be32_to_cpu(adsp1_alg[i].zm); 1105 region->base = be32_to_cpu(adsp1_alg[i].zm);
1106 region->len = 0;
741 list_add_tail(&region->list, &dsp->alg_regions); 1107 list_add_tail(&region->list, &dsp->alg_regions);
1108 if (i + 1 < algs) {
1109 region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
1110 region->len -= be32_to_cpu(adsp1_alg[i].zm);
1111 wm_adsp_create_control(codec, region);
1112 } else {
1113 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1114 be32_to_cpu(adsp1_alg[i].alg.id));
1115 }
742 break; 1116 break;
743 1117
744 case WMFW_ADSP2: 1118 case WMFW_ADSP2:
@@ -758,7 +1132,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
758 region->type = WMFW_ADSP2_XM; 1132 region->type = WMFW_ADSP2_XM;
759 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1133 region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
760 region->base = be32_to_cpu(adsp2_alg[i].xm); 1134 region->base = be32_to_cpu(adsp2_alg[i].xm);
1135 region->len = 0;
761 list_add_tail(&region->list, &dsp->alg_regions); 1136 list_add_tail(&region->list, &dsp->alg_regions);
1137 if (i + 1 < algs) {
1138 region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
1139 region->len -= be32_to_cpu(adsp2_alg[i].xm);
1140 wm_adsp_create_control(codec, region);
1141 } else {
1142 adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
1143 be32_to_cpu(adsp2_alg[i].alg.id));
1144 }
762 1145
763 region = kzalloc(sizeof(*region), GFP_KERNEL); 1146 region = kzalloc(sizeof(*region), GFP_KERNEL);
764 if (!region) 1147 if (!region)
@@ -766,7 +1149,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
766 region->type = WMFW_ADSP2_YM; 1149 region->type = WMFW_ADSP2_YM;
767 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1150 region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
768 region->base = be32_to_cpu(adsp2_alg[i].ym); 1151 region->base = be32_to_cpu(adsp2_alg[i].ym);
1152 region->len = 0;
769 list_add_tail(&region->list, &dsp->alg_regions); 1153 list_add_tail(&region->list, &dsp->alg_regions);
1154 if (i + 1 < algs) {
1155 region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
1156 region->len -= be32_to_cpu(adsp2_alg[i].ym);
1157 wm_adsp_create_control(codec, region);
1158 } else {
1159 adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
1160 be32_to_cpu(adsp2_alg[i].alg.id));
1161 }
770 1162
771 region = kzalloc(sizeof(*region), GFP_KERNEL); 1163 region = kzalloc(sizeof(*region), GFP_KERNEL);
772 if (!region) 1164 if (!region)
@@ -774,7 +1166,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
774 region->type = WMFW_ADSP2_ZM; 1166 region->type = WMFW_ADSP2_ZM;
775 region->alg = be32_to_cpu(adsp2_alg[i].alg.id); 1167 region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
776 region->base = be32_to_cpu(adsp2_alg[i].zm); 1168 region->base = be32_to_cpu(adsp2_alg[i].zm);
1169 region->len = 0;
777 list_add_tail(&region->list, &dsp->alg_regions); 1170 list_add_tail(&region->list, &dsp->alg_regions);
1171 if (i + 1 < algs) {
1172 region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
1173 region->len -= be32_to_cpu(adsp2_alg[i].zm);
1174 wm_adsp_create_control(codec, region);
1175 } else {
1176 adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
1177 be32_to_cpu(adsp2_alg[i].alg.id));
1178 }
778 break; 1179 break;
779 } 1180 }
780 } 1181 }
@@ -986,6 +1387,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
986 struct snd_soc_codec *codec = w->codec; 1387 struct snd_soc_codec *codec = w->codec;
987 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 1388 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
988 struct wm_adsp *dsp = &dsps[w->shift]; 1389 struct wm_adsp *dsp = &dsps[w->shift];
1390 struct wm_coeff_ctl *ctl;
989 int ret; 1391 int ret;
990 int val; 1392 int val;
991 1393
@@ -1023,7 +1425,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
1023 if (ret != 0) 1425 if (ret != 0)
1024 goto err; 1426 goto err;
1025 1427
1026 ret = wm_adsp_setup_algs(dsp); 1428 ret = wm_adsp_setup_algs(dsp, codec);
1027 if (ret != 0) 1429 if (ret != 0)
1028 goto err; 1430 goto err;
1029 1431
@@ -1031,6 +1433,16 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
1031 if (ret != 0) 1433 if (ret != 0)
1032 goto err; 1434 goto err;
1033 1435
1436 /* Initialize caches for enabled and unset controls */
1437 ret = wm_coeff_init_control_caches(dsp->wm_coeff);
1438 if (ret != 0)
1439 goto err;
1440
1441 /* Sync set controls */
1442 ret = wm_coeff_sync_controls(dsp->wm_coeff);
1443 if (ret != 0)
1444 goto err;
1445
1034 /* Start the core running */ 1446 /* Start the core running */
1035 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1447 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1036 ADSP1_CORE_ENA | ADSP1_START, 1448 ADSP1_CORE_ENA | ADSP1_START,
@@ -1047,6 +1459,11 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
1047 1459
1048 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, 1460 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
1049 ADSP1_SYS_ENA, 0); 1461 ADSP1_SYS_ENA, 0);
1462
1463 list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
1464 list) {
1465 ctl->enabled = 0;
1466 }
1050 break; 1467 break;
1051 1468
1052 default: 1469 default:
@@ -1099,6 +1516,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1099 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); 1516 struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
1100 struct wm_adsp *dsp = &dsps[w->shift]; 1517 struct wm_adsp *dsp = &dsps[w->shift];
1101 struct wm_adsp_alg_region *alg_region; 1518 struct wm_adsp_alg_region *alg_region;
1519 struct wm_coeff_ctl *ctl;
1102 unsigned int val; 1520 unsigned int val;
1103 int ret; 1521 int ret;
1104 1522
@@ -1164,7 +1582,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1164 if (ret != 0) 1582 if (ret != 0)
1165 goto err; 1583 goto err;
1166 1584
1167 ret = wm_adsp_setup_algs(dsp); 1585 ret = wm_adsp_setup_algs(dsp, codec);
1168 if (ret != 0) 1586 if (ret != 0)
1169 goto err; 1587 goto err;
1170 1588
@@ -1172,6 +1590,16 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1172 if (ret != 0) 1590 if (ret != 0)
1173 goto err; 1591 goto err;
1174 1592
1593 /* Initialize caches for enabled and unset controls */
1594 ret = wm_coeff_init_control_caches(dsp->wm_coeff);
1595 if (ret != 0)
1596 goto err;
1597
1598 /* Sync set controls */
1599 ret = wm_coeff_sync_controls(dsp->wm_coeff);
1600 if (ret != 0)
1601 goto err;
1602
1175 ret = regmap_update_bits(dsp->regmap, 1603 ret = regmap_update_bits(dsp->regmap,
1176 dsp->base + ADSP2_CONTROL, 1604 dsp->base + ADSP2_CONTROL,
1177 ADSP2_CORE_ENA | ADSP2_START, 1605 ADSP2_CORE_ENA | ADSP2_START,
@@ -1209,6 +1637,11 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
1209 ret); 1637 ret);
1210 } 1638 }
1211 1639
1640 list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
1641 list) {
1642 ctl->enabled = 0;
1643 }
1644
1212 while (!list_empty(&dsp->alg_regions)) { 1645 while (!list_empty(&dsp->alg_regions)) {
1213 alg_region = list_first_entry(&dsp->alg_regions, 1646 alg_region = list_first_entry(&dsp->alg_regions,
1214 struct wm_adsp_alg_region, 1647 struct wm_adsp_alg_region,
@@ -1247,36 +1680,48 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
1247 1680
1248 INIT_LIST_HEAD(&adsp->alg_regions); 1681 INIT_LIST_HEAD(&adsp->alg_regions);
1249 1682
1683 adsp->wm_coeff = kzalloc(sizeof(*adsp->wm_coeff),
1684 GFP_KERNEL);
1685 if (!adsp->wm_coeff)
1686 return -ENOMEM;
1687 adsp->wm_coeff->regmap = adsp->regmap;
1688 adsp->wm_coeff->dev = adsp->dev;
1689 INIT_LIST_HEAD(&adsp->wm_coeff->ctl_list);
1690
1250 if (dvfs) { 1691 if (dvfs) {
1251 adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); 1692 adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
1252 if (IS_ERR(adsp->dvfs)) { 1693 if (IS_ERR(adsp->dvfs)) {
1253 ret = PTR_ERR(adsp->dvfs); 1694 ret = PTR_ERR(adsp->dvfs);
1254 dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); 1695 dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
1255 return ret; 1696 goto out_coeff;
1256 } 1697 }
1257 1698
1258 ret = regulator_enable(adsp->dvfs); 1699 ret = regulator_enable(adsp->dvfs);
1259 if (ret != 0) { 1700 if (ret != 0) {
1260 dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", 1701 dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
1261 ret); 1702 ret);
1262 return ret; 1703 goto out_coeff;
1263 } 1704 }
1264 1705
1265 ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); 1706 ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
1266 if (ret != 0) { 1707 if (ret != 0) {
1267 dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", 1708 dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
1268 ret); 1709 ret);
1269 return ret; 1710 goto out_coeff;
1270 } 1711 }
1271 1712
1272 ret = regulator_disable(adsp->dvfs); 1713 ret = regulator_disable(adsp->dvfs);
1273 if (ret != 0) { 1714 if (ret != 0) {
1274 dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", 1715 dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
1275 ret); 1716 ret);
1276 return ret; 1717 goto out_coeff;
1277 } 1718 }
1278 } 1719 }
1279 1720
1280 return 0; 1721 return 0;
1722
1723out_coeff:
1724 kfree(adsp->wm_coeff);
1725 return ret;
1281} 1726}
1282EXPORT_SYMBOL_GPL(wm_adsp2_init); 1727EXPORT_SYMBOL_GPL(wm_adsp2_init);
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index fea514627526..6e890b916592 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -30,6 +30,7 @@ struct wm_adsp_alg_region {
30 unsigned int alg; 30 unsigned int alg;
31 int type; 31 int type;
32 unsigned int base; 32 unsigned int base;
33 size_t len;
33}; 34};
34 35
35struct wm_adsp { 36struct wm_adsp {
@@ -55,6 +56,8 @@ struct wm_adsp {
55 bool running; 56 bool running;
56 57
57 struct regulator *dvfs; 58 struct regulator *dvfs;
59
60 struct wm_coeff *wm_coeff;
58}; 61};
59 62
60#define WM_ADSP1(wname, num) \ 63#define WM_ADSP1(wname, num) \