]> Git Repo - linux.git/commitdiff
Merge remote-tracking branch 'asoc/fix/adsp' into asoc-adsp
authorMark Brown <[email protected]>
Mon, 21 Jan 2013 08:46:16 +0000 (17:46 +0900)
committerMark Brown <[email protected]>
Mon, 21 Jan 2013 08:46:16 +0000 (17:46 +0900)
1  2 
sound/soc/codecs/wm_adsp.c

index edb67138d548ada41ca60a11d07a26b514af865b,4196f2d54967253d154efd36c0867f658b7d0b2f..76ca176eac0712a973b03a8b8d5e152fdc475628
  #define ADSP1_START_SHIFT                      0  /* DSP1_START */
  #define ADSP1_START_WIDTH                      1  /* DSP1_START */
  
 +/*
 + * ADSP1 Control 31
 + */
 +#define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
 +#define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
 +#define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
 +
  #define ADSP2_CONTROL  0
  #define ADSP2_CLOCKING 1
  #define ADSP2_STATUS1  4
  #define ADSP2_RAM_RDY_SHIFT                    0
  #define ADSP2_RAM_RDY_WIDTH                    1
  
 +#define WM_ADSP_NUM_FW 3
 +
 +static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
 +      "MBC/VSS", "Tx", "Rx ANC"
 +};
 +
 +static struct {
 +      const char *file;
 +} wm_adsp_fw[WM_ADSP_NUM_FW] = {
 +      { .file = "mbc-vss" },
 +      { .file = "tx" },
 +      { .file = "rx-anc" },
 +};
 +
 +static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 +                        struct snd_ctl_elem_value *ucontrol)
 +{
 +      struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 +      struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 +      struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
 +
 +      ucontrol->value.integer.value[0] = adsp[e->shift_l].fw;
 +
 +      return 0;
 +}
 +
 +static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 +                        struct snd_ctl_elem_value *ucontrol)
 +{
 +      struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 +      struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 +      struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
 +
 +      if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw)
 +              return 0;
 +
 +      if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
 +              return -EINVAL;
 +
 +      if (adsp[e->shift_l].running)
 +              return -EBUSY;
 +
 +      adsp->fw = ucontrol->value.integer.value[0];
 +
 +      return 0;
 +}
 +
 +static const struct soc_enum wm_adsp_fw_enum[] = {
 +      SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 +      SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 +      SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 +      SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 +};
 +
 +const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
 +      SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
 +                   wm_adsp_fw_get, wm_adsp_fw_put),
 +      SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
 +                   wm_adsp_fw_get, wm_adsp_fw_put),
 +      SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
 +                   wm_adsp_fw_get, wm_adsp_fw_put),
 +      SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
 +                   wm_adsp_fw_get, wm_adsp_fw_put),
 +};
 +EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
  
  static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
                                                        int type)
        return NULL;
  }
  
 +static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
 +                                        unsigned int offset)
 +{
 +      switch (region->type) {
 +      case WMFW_ADSP1_PM:
 +              return region->base + (offset * 3);
 +      case WMFW_ADSP1_DM:
 +              return region->base + (offset * 2);
 +      case WMFW_ADSP2_XM:
 +              return region->base + (offset * 2);
 +      case WMFW_ADSP2_YM:
 +              return region->base + (offset * 2);
 +      case WMFW_ADSP1_ZM:
 +              return region->base + (offset * 2);
 +      default:
 +              WARN_ON(NULL != "Unknown memory region type");
 +              return offset;
 +      }
 +}
 +
  static int wm_adsp_load(struct wm_adsp *dsp)
  {
        const struct firmware *firmware;
        const struct wm_adsp_region *mem;
        const char *region_name;
        char *file, *text;
+       void *buf;
        unsigned int reg;
        int regions = 0;
        int ret, offset, type, sizes;
        if (file == NULL)
                return -ENOMEM;
  
 -      snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num);
 +      snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
 +               wm_adsp_fw[dsp->fw].file);
        file[PAGE_SIZE - 1] = '\0';
  
        ret = request_firmware(&firmware, file, dsp->dev);
                case WMFW_ADSP1_PM:
                        BUG_ON(!mem);
                        region_name = "PM";
 -                      reg = mem->base + (offset * 3);
 +                      reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                case WMFW_ADSP1_DM:
                        BUG_ON(!mem);
                        region_name = "DM";
 -                      reg = mem->base + (offset * 2);
 +                      reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                case WMFW_ADSP2_XM:
                        BUG_ON(!mem);
                        region_name = "XM";
 -                      reg = mem->base + (offset * 2);
 +                      reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                case WMFW_ADSP2_YM:
                        BUG_ON(!mem);
                        region_name = "YM";
 -                      reg = mem->base + (offset * 2);
 +                      reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                case WMFW_ADSP1_ZM:
                        BUG_ON(!mem);
                        region_name = "ZM";
 -                      reg = mem->base + (offset * 2);
 +                      reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                default:
                        adsp_warn(dsp,
                }
  
                if (reg) {
-                       ret = regmap_raw_write(regmap, reg, region->data,
+                       buf = kmemdup(region->data, le32_to_cpu(region->len),
+                                     GFP_KERNEL | GFP_DMA);
+                       if (!buf) {
+                               adsp_err(dsp, "Out of memory\n");
+                               return -ENOMEM;
+                       }
+                       ret = regmap_raw_write(regmap, reg, buf,
                                               le32_to_cpu(region->len));
+                       kfree(buf);
                        if (ret != 0) {
                                adsp_err(dsp,
                                        "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
        return ret;
  }
  
 +static int wm_adsp_setup_algs(struct wm_adsp *dsp)
 +{
 +      struct regmap *regmap = dsp->regmap;
 +      struct wmfw_adsp1_id_hdr adsp1_id;
 +      struct wmfw_adsp2_id_hdr adsp2_id;
 +      struct wmfw_adsp1_alg_hdr *adsp1_alg;
 +      struct wmfw_adsp2_alg_hdr *adsp2_alg;
 +      void *alg, *buf;
 +      struct wm_adsp_alg_region *region;
 +      const struct wm_adsp_region *mem;
 +      unsigned int pos, term;
 +      size_t algs, buf_size;
 +      __be32 val;
 +      int i, ret;
 +
 +      switch (dsp->type) {
 +      case WMFW_ADSP1:
 +              mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
 +              break;
 +      case WMFW_ADSP2:
 +              mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
 +              break;
 +      default:
 +              mem = NULL;
 +              break;
 +      }
 +
 +      if (mem == NULL) {
 +              BUG_ON(mem != NULL);
 +              return -EINVAL;
 +      }
 +
 +      switch (dsp->type) {
 +      case WMFW_ADSP1:
 +              ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
 +                                    sizeof(adsp1_id));
 +              if (ret != 0) {
 +                      adsp_err(dsp, "Failed to read algorithm info: %d\n",
 +                               ret);
 +                      return ret;
 +              }
 +
 +              buf = &adsp1_id;
 +              buf_size = sizeof(adsp1_id);
 +
 +              algs = be32_to_cpu(adsp1_id.algs);
 +              adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
 +                        be32_to_cpu(adsp1_id.fw.id),
 +                        (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
 +                        (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
 +                        be32_to_cpu(adsp1_id.fw.ver) & 0xff,
 +                        algs);
 +
 +              pos = sizeof(adsp1_id) / 2;
 +              term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
 +              break;
 +
 +      case WMFW_ADSP2:
 +              ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
 +                                    sizeof(adsp2_id));
 +              if (ret != 0) {
 +                      adsp_err(dsp, "Failed to read algorithm info: %d\n",
 +                               ret);
 +                      return ret;
 +              }
 +
 +              buf = &adsp2_id;
 +              buf_size = sizeof(adsp2_id);
 +
 +              algs = be32_to_cpu(adsp2_id.algs);
 +              adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
 +                        be32_to_cpu(adsp2_id.fw.id),
 +                        (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
 +                        (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
 +                        be32_to_cpu(adsp2_id.fw.ver) & 0xff,
 +                        algs);
 +
 +              pos = sizeof(adsp2_id) / 2;
 +              term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
 +              break;
 +
 +      default:
 +              BUG_ON(NULL == "Unknown DSP type");
 +              return -EINVAL;
 +      }
 +
 +      if (algs == 0) {
 +              adsp_err(dsp, "No algorithms\n");
 +              return -EINVAL;
 +      }
 +
 +      if (algs > 1024) {
 +              adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
 +              print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
 +                                   buf, buf_size);
 +              return -EINVAL;
 +      }
 +
 +      /* Read the terminator first to validate the length */
 +      ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
 +      if (ret != 0) {
 +              adsp_err(dsp, "Failed to read algorithm list end: %d\n",
 +                      ret);
 +              return ret;
 +      }
 +
 +      if (be32_to_cpu(val) != 0xbedead)
 +              adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
 +                        term, be32_to_cpu(val));
 +
 +      alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA);
 +      if (!alg)
 +              return -ENOMEM;
 +
 +      ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
 +      if (ret != 0) {
 +              adsp_err(dsp, "Failed to read algorithm list: %d\n",
 +                      ret);
 +              goto out;
 +      }
 +
 +      adsp1_alg = alg;
 +      adsp2_alg = alg;
 +
 +      for (i = 0; i < algs; i++) {
 +              switch (dsp->type) {
 +              case WMFW_ADSP1:
 +                      adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
 +                                i, be32_to_cpu(adsp1_alg[i].alg.id),
 +                                (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
 +                                (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
 +                                be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
 +                                be32_to_cpu(adsp1_alg[i].dm),
 +                                be32_to_cpu(adsp1_alg[i].zm));
 +
 +                      if (adsp1_alg[i].dm) {
 +                              region = kzalloc(sizeof(*region), GFP_KERNEL);
 +                              if (!region)
 +                                      return -ENOMEM;
 +                              region->type = WMFW_ADSP1_DM;
 +                              region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
 +                              region->base = be32_to_cpu(adsp1_alg[i].dm);
 +                              list_add_tail(&region->list,
 +                                            &dsp->alg_regions);
 +                      }
 +
 +                      if (adsp1_alg[i].zm) {
 +                              region = kzalloc(sizeof(*region), GFP_KERNEL);
 +                              if (!region)
 +                                      return -ENOMEM;
 +                              region->type = WMFW_ADSP1_ZM;
 +                              region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
 +                              region->base = be32_to_cpu(adsp1_alg[i].zm);
 +                              list_add_tail(&region->list,
 +                                            &dsp->alg_regions);
 +                      }
 +                      break;
 +
 +              case WMFW_ADSP2:
 +                      adsp_info(dsp,
 +                                "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
 +                                i, be32_to_cpu(adsp2_alg[i].alg.id),
 +                                (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
 +                                (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
 +                                be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
 +                                be32_to_cpu(adsp2_alg[i].xm),
 +                                be32_to_cpu(adsp2_alg[i].ym),
 +                                be32_to_cpu(adsp2_alg[i].zm));
 +
 +                      if (adsp2_alg[i].xm) {
 +                              region = kzalloc(sizeof(*region), GFP_KERNEL);
 +                              if (!region)
 +                                      return -ENOMEM;
 +                              region->type = WMFW_ADSP2_XM;
 +                              region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
 +                              region->base = be32_to_cpu(adsp2_alg[i].xm);
 +                              list_add_tail(&region->list,
 +                                            &dsp->alg_regions);
 +                      }
 +
 +                      if (adsp2_alg[i].ym) {
 +                              region = kzalloc(sizeof(*region), GFP_KERNEL);
 +                              if (!region)
 +                                      return -ENOMEM;
 +                              region->type = WMFW_ADSP2_YM;
 +                              region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
 +                              region->base = be32_to_cpu(adsp2_alg[i].ym);
 +                              list_add_tail(&region->list,
 +                                            &dsp->alg_regions);
 +                      }
 +
 +                      if (adsp2_alg[i].zm) {
 +                              region = kzalloc(sizeof(*region), GFP_KERNEL);
 +                              if (!region)
 +                                      return -ENOMEM;
 +                              region->type = WMFW_ADSP2_ZM;
 +                              region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
 +                              region->base = be32_to_cpu(adsp2_alg[i].zm);
 +                              list_add_tail(&region->list,
 +                                            &dsp->alg_regions);
 +                      }
 +                      break;
 +              }
 +      }
 +
 +out:
 +      kfree(alg);
 +      return ret;
 +}
 +
  static int wm_adsp_load_coeff(struct wm_adsp *dsp)
  {
        struct regmap *regmap = dsp->regmap;
        struct wmfw_coeff_hdr *hdr;
        struct wmfw_coeff_item *blk;
        const struct firmware *firmware;
 +      const struct wm_adsp_region *mem;
 +      struct wm_adsp_alg_region *alg_region;
        const char *region_name;
        int ret, pos, blocks, type, offset, reg;
        char *file;
+       void *buf;
  
        file = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (file == NULL)
                return -ENOMEM;
  
 -      snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num);
 +      snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
 +               wm_adsp_fw[dsp->fw].file);
        file[PAGE_SIZE - 1] = '\0';
  
        ret = request_firmware(&firmware, file, dsp->dev);
                return -EINVAL;
        }
  
 +      switch (be32_to_cpu(hdr->rev) & 0xff) {
 +      case 1:
 +              break;
 +      default:
 +              adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
 +                       file, be32_to_cpu(hdr->rev) & 0xff);
 +              ret = -EINVAL;
 +              goto out_fw;
 +      }
 +
        adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
                (le32_to_cpu(hdr->ver) >> 16) & 0xff,
                (le32_to_cpu(hdr->ver) >>  8) & 0xff,
               pos - firmware->size > sizeof(*blk)) {
                blk = (void*)(&firmware->data[pos]);
  
 -              type = be32_to_cpu(blk->type) & 0xff;
 -              offset = le32_to_cpu(blk->offset) & 0xffffff;
 +              type = le16_to_cpu(blk->type);
 +              offset = le16_to_cpu(blk->offset);
  
                adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
                         file, blocks, le32_to_cpu(blk->id),
                reg = 0;
                region_name = "Unknown";
                switch (type) {
 -              case WMFW_NAME_TEXT:
 -              case WMFW_INFO_TEXT:
 +              case (WMFW_NAME_TEXT << 8):
 +              case (WMFW_INFO_TEXT << 8):
                        break;
 -              case WMFW_ABSOLUTE:
 +              case (WMFW_ABSOLUTE << 8):
                        region_name = "register";
                        reg = offset;
                        break;
 +
 +              case WMFW_ADSP1_DM:
 +              case WMFW_ADSP1_ZM:
 +              case WMFW_ADSP2_XM:
 +              case WMFW_ADSP2_YM:
 +                      adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
 +                               file, blocks, le32_to_cpu(blk->len),
 +                               type, le32_to_cpu(blk->id));
 +
 +                      mem = wm_adsp_find_region(dsp, type);
 +                      if (!mem) {
 +                              adsp_err(dsp, "No base for region %x\n", type);
 +                              break;
 +                      }
 +
 +                      reg = 0;
 +                      list_for_each_entry(alg_region,
 +                                          &dsp->alg_regions, list) {
 +                              if (le32_to_cpu(blk->id) == alg_region->alg &&
 +                                  type == alg_region->type) {
 +                                      reg = alg_region->base + offset;
 +                                      reg = wm_adsp_region_to_reg(mem,
 +                                                                  reg);
 +                              }
 +                      }
 +
 +                      if (reg == 0)
 +                              adsp_err(dsp, "No %x for algorithm %x\n",
 +                                       type, le32_to_cpu(blk->id));
 +                      break;
 +
                default:
 -                      adsp_err(dsp, "Unknown region type %x\n", type);
 +                      adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
 +                               file, blocks, type, pos);
                        break;
                }
  
                if (reg) {
+                       buf = kmemdup(blk->data, le32_to_cpu(blk->len),
+                                     GFP_KERNEL | GFP_DMA);
+                       if (!buf) {
+                               adsp_err(dsp, "Out of memory\n");
+                               return -ENOMEM;
+                       }
                        ret = regmap_raw_write(regmap, reg, blk->data,
                                               le32_to_cpu(blk->len));
                        if (ret != 0) {
                                        "%s.%d: Failed to write to %x in %s\n",
                                        file, blocks, reg, region_name);
                        }
+                       kfree(buf);
                }
  
                pos += le32_to_cpu(blk->len) + sizeof(*blk);
@@@ -798,14 -471,6 +819,14 @@@ out
        return 0;
  }
  
 +int wm_adsp1_init(struct wm_adsp *adsp)
 +{
 +      INIT_LIST_HEAD(&adsp->alg_regions);
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(wm_adsp1_init);
 +
  int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
        int ret;
 +      int val;
  
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
                                   ADSP1_SYS_ENA, ADSP1_SYS_ENA);
  
 +              /*
 +               * For simplicity set the DSP clock rate to be the
 +               * SYSCLK rate rather than making it configurable.
 +               */
 +              if(dsp->sysclk_reg) {
 +                      ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
 +                      if (ret != 0) {
 +                              adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
 +                              ret);
 +                              return ret;
 +                      }
 +
 +                      val = (val & dsp->sysclk_mask)
 +                              >> dsp->sysclk_shift;
 +
 +                      ret = regmap_update_bits(dsp->regmap,
 +                                               dsp->base + ADSP1_CONTROL_31,
 +                                               ADSP1_CLK_SEL_MASK, val);
 +                      if (ret != 0) {
 +                              adsp_err(dsp, "Failed to set clock rate: %d\n",
 +                                       ret);
 +                              return ret;
 +                      }
 +              }
 +
                ret = wm_adsp_load(dsp);
                if (ret != 0)
                        goto err;
  
 +              ret = wm_adsp_setup_algs(dsp);
 +              if (ret != 0)
 +                      goto err;
 +
                ret = wm_adsp_load_coeff(dsp);
                if (ret != 0)
                        goto err;
@@@ -925,7 -560,6 +946,7 @@@ int wm_adsp2_event(struct snd_soc_dapm_
        struct snd_soc_codec *codec = w->codec;
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
 +      struct wm_adsp_alg_region *alg_region;
        unsigned int val;
        int ret;
  
                if (ret != 0)
                        goto err;
  
 +              ret = wm_adsp_setup_algs(dsp);
 +              if (ret != 0)
 +                      goto err;
 +
                ret = wm_adsp_load_coeff(dsp);
                if (ret != 0)
                        goto err;
                                         ADSP2_CORE_ENA | ADSP2_START);
                if (ret != 0)
                        goto err;
 +
 +              dsp->running = true;
                break;
  
        case SND_SOC_DAPM_PRE_PMD:
 +              dsp->running = false;
 +
                regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
                                   ADSP2_SYS_ENA | ADSP2_CORE_ENA |
                                   ADSP2_START, 0);
                                        "Failed to enable supply: %d\n",
                                        ret);
                }
 +
 +              while (!list_empty(&dsp->alg_regions)) {
 +                      alg_region = list_first_entry(&dsp->alg_regions,
 +                                                    struct wm_adsp_alg_region,
 +                                                    list);
 +                      list_del(&alg_region->list);
 +                      kfree(alg_region);
 +              }
                break;
  
        default:
@@@ -1067,8 -685,6 +1088,8 @@@ int wm_adsp2_init(struct wm_adsp *adsp
                return ret;
        }
  
 +      INIT_LIST_HEAD(&adsp->alg_regions);
 +
        if (dvfs) {
                adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
                if (IS_ERR(adsp->dvfs)) {
This page took 0.082925 seconds and 4 git commands to generate.