Merge remote-tracking branch 'asoc/topic/rt5670' into asoc-next
[deliverable/linux.git] / sound / soc / codecs / wm_adsp.c
index 53fc7f88fa660d6d1688f3df0ae67dc88942817f..b62ffd0c133ea1f02868f774d12f9ecc70a64357 100644 (file)
 #define ADSP2_WDMA_CONFIG_2 0x31
 #define ADSP2_RDMA_CONFIG_1 0x34
 
+#define ADSP2_SCRATCH0        0x40
+#define ADSP2_SCRATCH1        0x41
+#define ADSP2_SCRATCH2        0x42
+#define ADSP2_SCRATCH3        0x43
+
 /*
  * ADSP2 Control
  */
@@ -240,6 +245,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,
@@ -363,6 +369,25 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
        }
 }
 
+static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
+{
+       u16 scratch[4];
+       int ret;
+
+       ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0,
+                               scratch, sizeof(scratch));
+       if (ret) {
+               adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
+               return;
+       }
+
+       adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
+                be16_to_cpu(scratch[0]),
+                be16_to_cpu(scratch[1]),
+                be16_to_cpu(scratch[2]),
+                be16_to_cpu(scratch[3]));
+}
+
 static int wm_coeff_info(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_info *uinfo)
 {
@@ -472,7 +497,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 +534,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 +568,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 +589,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 +614,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 +623,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 +698,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 +902,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 +1288,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 +1308,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 +1398,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 +1418,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 +1438,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));
@@ -1760,35 +1811,6 @@ static void wm_adsp2_boot_work(struct work_struct *work)
                return;
        }
 
-       if (dsp->dvfs) {
-               ret = regmap_read(dsp->regmap,
-                                 dsp->base + ADSP2_CLOCKING, &val);
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to read clocking: %d\n", ret);
-                       return;
-               }
-
-               if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
-                       ret = regulator_enable(dsp->dvfs);
-                       if (ret != 0) {
-                               adsp_err(dsp,
-                                        "Failed to enable supply: %d\n",
-                                        ret);
-                               return;
-                       }
-
-                       ret = regulator_set_voltage(dsp->dvfs,
-                                                   1800000,
-                                                   1800000);
-                       if (ret != 0) {
-                               adsp_err(dsp,
-                                        "Failed to raise supply: %d\n",
-                                        ret);
-                               return;
-                       }
-               }
-       }
-
        ret = wm_adsp2_ena(dsp);
        if (ret != 0)
                return;
@@ -1871,6 +1893,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
+               /* Log firmware state, it can be useful for analysis */
+               wm_adsp2_show_fw_status(dsp);
+
                dsp->running = false;
 
                regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
@@ -1882,21 +1907,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
                regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
 
-               if (dsp->dvfs) {
-                       ret = regulator_set_voltage(dsp->dvfs, 1200000,
-                                                   1800000);
-                       if (ret != 0)
-                               adsp_warn(dsp,
-                                         "Failed to lower supply: %d\n",
-                                         ret);
-
-                       ret = regulator_disable(dsp->dvfs);
-                       if (ret != 0)
-                               adsp_err(dsp,
-                                        "Failed to enable supply: %d\n",
-                                        ret);
-               }
-
                list_for_each_entry(ctl, &dsp->ctl_list, list)
                        ctl->enabled = 0;
 
@@ -1923,7 +1933,7 @@ err:
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_event);
 
-int wm_adsp2_init(struct wm_adsp *dsp, bool dvfs)
+int wm_adsp2_init(struct wm_adsp *dsp)
 {
        int ret;
 
@@ -1942,33 +1952,6 @@ int wm_adsp2_init(struct wm_adsp *dsp, bool dvfs)
        INIT_LIST_HEAD(&dsp->ctl_list);
        INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
 
-       if (dvfs) {
-               dsp->dvfs = devm_regulator_get(dsp->dev, "DCVDD");
-               if (IS_ERR(dsp->dvfs)) {
-                       ret = PTR_ERR(dsp->dvfs);
-                       adsp_err(dsp, "Failed to get DCVDD: %d\n", ret);
-                       return ret;
-               }
-
-               ret = regulator_enable(dsp->dvfs);
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to enable DCVDD: %d\n", ret);
-                       return ret;
-               }
-
-               ret = regulator_set_voltage(dsp->dvfs, 1200000, 1800000);
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to initialise DVFS: %d\n", ret);
-                       return ret;
-               }
-
-               ret = regulator_disable(dsp->dvfs);
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to disable DCVDD: %d\n", ret);
-                       return ret;
-               }
-       }
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
This page took 0.032373 seconds and 5 git commands to generate.