ASoC: wm_adsp: Add support for DSP control flags
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>
Mon, 20 Apr 2015 12:52:45 +0000 (13:52 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 27 Apr 2015 14:38:26 +0000 (15:38 +0100)
The DSP control information contains various hints about the usage of
the control use these when handling the control.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wmfw.h

index 53fc7f8..f6642c1 100644 (file)
@@ -240,6 +240,7 @@ struct wm_coeff_ctl {
        size_t len;
        unsigned int set:1;
        struct snd_kcontrol *kcontrol;
+       unsigned int flags;
 };
 
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
@@ -472,7 +473,15 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol,
        struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
        char *p = ucontrol->value.bytes.data;
 
+       if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
+               if (ctl->enabled)
+                       return wm_coeff_read_control(ctl, p, ctl->len);
+               else
+                       return -EPERM;
+       }
+
        memcpy(p, ctl->cache, ctl->len);
+
        return 0;
 }
 
@@ -501,6 +510,15 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
        kcontrol->put = wm_coeff_put;
        kcontrol->private_value = (unsigned long)ctl;
 
+       if (ctl->flags) {
+               if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE)
+                       kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+               if (ctl->flags & WMFW_CTL_FLAG_READABLE)
+                       kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
+               if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+                       kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+       }
+
        ret = snd_soc_add_card_controls(dsp->card,
                                        kcontrol, 1);
        if (ret < 0)
@@ -526,6 +544,9 @@ static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
        list_for_each_entry(ctl, &dsp->ctl_list, list) {
                if (!ctl->enabled || ctl->set)
                        continue;
+               if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+                       continue;
+
                ret = wm_coeff_read_control(ctl,
                                            ctl->cache,
                                            ctl->len);
@@ -544,7 +565,7 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp)
        list_for_each_entry(ctl, &dsp->ctl_list, list) {
                if (!ctl->enabled)
                        continue;
-               if (ctl->set) {
+               if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
                        ret = wm_coeff_write_control(ctl,
                                                     ctl->cache,
                                                     ctl->len);
@@ -569,7 +590,8 @@ static void wm_adsp_ctl_work(struct work_struct *work)
 static int wm_adsp_create_control(struct wm_adsp *dsp,
                                  const struct wm_adsp_alg_region *alg_region,
                                  unsigned int offset, unsigned int len,
-                                 const char *subname, unsigned int subname_len)
+                                 const char *subname, unsigned int subname_len,
+                                 unsigned int flags)
 {
        struct wm_coeff_ctl *ctl;
        struct wmfw_ctl_work *ctl_work;
@@ -577,6 +599,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
        char *region_name;
        int ret;
 
+       if (flags & WMFW_CTL_FLAG_SYS)
+               return 0;
+
        switch (alg_region->type) {
        case WMFW_ADSP1_PM:
                region_name = "PM";
@@ -649,6 +674,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
        ctl->ops.xput = wm_coeff_put;
        ctl->dsp = dsp;
 
+       ctl->flags = flags;
        ctl->offset = offset;
        if (len > 512) {
                adsp_warn(dsp, "Truncating control %s from %d\n",
@@ -852,7 +878,8 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
                                             coeff_blk.offset,
                                             coeff_blk.len,
                                             coeff_blk.name,
-                                            coeff_blk.name_len);
+                                            coeff_blk.name_len,
+                                            coeff_blk.flags);
                if (ret < 0)
                        adsp_err(dsp, "Failed to create control: %.*s, %d\n",
                                 coeff_blk.name_len, coeff_blk.name, ret);
@@ -1237,7 +1264,7 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp1_alg[i].dm);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0);
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1257,7 +1284,7 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp1_alg[i].zm);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0);
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1347,7 +1374,7 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp2_alg[i].xm);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0);
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1367,7 +1394,7 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp2_alg[i].ym);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0);
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1387,7 +1414,7 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp2_alg[i].zm);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0);
+                                                      len, NULL, 0, 0);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
index 04690b2..7613d60 100644 (file)
 #define WMFW_MAX_COEFF_NAME       256
 #define WMFW_MAX_COEFF_DESCR_NAME 256
 
+#define WMFW_CTL_FLAG_SYS         0x8000
+#define WMFW_CTL_FLAG_VOLATILE    0x0004
+#define WMFW_CTL_FLAG_WRITEABLE   0x0002
+#define WMFW_CTL_FLAG_READABLE    0x0001
+
 struct wmfw_header {
        char magic[4];
        __le32 len;