*/
 #define WM_ADSP_FW_EVENT_SHUTDOWN            0x000001
 
+struct wm_adsp_ops wm_adsp1_ops;
+struct wm_adsp_ops wm_adsp2_ops[];
+
 struct wm_adsp_buf {
        struct list_head list;
        void *buf;
        return 0;
 }
 
+static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp,
+                                        const char * const file,
+                                        unsigned int pos,
+                                        const struct firmware *firmware)
+{
+       const struct wmfw_adsp1_sizes *adsp1_sizes;
+
+       adsp1_sizes = (void *)&firmware->data[pos];
+
+       adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
+                le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
+                le32_to_cpu(adsp1_sizes->zm));
+
+       return pos + sizeof(*adsp1_sizes);
+}
+
+static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp,
+                                        const char * const file,
+                                        unsigned int pos,
+                                        const struct firmware *firmware)
+{
+       const struct wmfw_adsp2_sizes *adsp2_sizes;
+
+       adsp2_sizes = (void *)&firmware->data[pos];
+
+       adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
+                le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
+                le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
+
+       return pos + sizeof(*adsp2_sizes);
+}
+
+static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version)
+{
+       switch (version) {
+       case 0:
+               adsp_warn(dsp, "Deprecated file format %d\n", version);
+               return true;
+       case 1:
+       case 2:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int wm_adsp_load(struct wm_adsp *dsp)
 {
        LIST_HEAD(buf_list);
        unsigned int pos = 0;
        const struct wmfw_header *header;
        const struct wmfw_adsp1_sizes *adsp1_sizes;
-       const struct wmfw_adsp2_sizes *adsp2_sizes;
        const struct wmfw_footer *footer;
        const struct wmfw_region *region;
        const struct wm_adsp_region *mem;
        struct wm_adsp_buf *buf;
        unsigned int reg;
        int regions = 0;
-       int ret, offset, type, sizes;
+       int ret, offset, type;
 
        file = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (file == NULL)
                goto out_fw;
        }
 
-       switch (header->ver) {
-       case 0:
-               adsp_warn(dsp, "%s: Depreciated file format %d\n",
-                         file, header->ver);
-               break;
-       case 1:
-       case 2:
-               break;
-       default:
+       if (!dsp->ops->validate_version(dsp, header->ver)) {
                adsp_err(dsp, "%s: unknown file format %d\n",
                         file, header->ver);
                goto out_fw;
                goto out_fw;
        }
 
-       switch (dsp->type) {
-       case WMFW_ADSP1:
-               pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
-               adsp1_sizes = (void *)&(header[1]);
-               footer = (void *)&(adsp1_sizes[1]);
-               sizes = sizeof(*adsp1_sizes);
+       pos = sizeof(*header);
+       pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
 
-               adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
-                        file, le32_to_cpu(adsp1_sizes->dm),
-                        le32_to_cpu(adsp1_sizes->pm),
-                        le32_to_cpu(adsp1_sizes->zm));
-               break;
-
-       case WMFW_ADSP2:
-               pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
-               adsp2_sizes = (void *)&(header[1]);
-               footer = (void *)&(adsp2_sizes[1]);
-               sizes = sizeof(*adsp2_sizes);
-
-               adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
-                        file, le32_to_cpu(adsp2_sizes->xm),
-                        le32_to_cpu(adsp2_sizes->ym),
-                        le32_to_cpu(adsp2_sizes->pm),
-                        le32_to_cpu(adsp2_sizes->zm));
-               break;
+       footer = (void *)&firmware->data[pos];
+       pos += sizeof(*footer);
 
-       default:
-               WARN(1, "Unknown DSP type");
-               goto out_fw;
-       }
-
-       if (le32_to_cpu(header->len) != sizeof(*header) +
-           sizes + sizeof(*footer)) {
+       if (le32_to_cpu(header->len) != pos) {
                adsp_err(dsp, "%s: unexpected header length %d\n",
                         file, le32_to_cpu(header->len));
                goto out_fw;
 
 int wm_adsp1_init(struct wm_adsp *dsp)
 {
+       dsp->ops = &wm_adsp1_ops;
+
        return wm_adsp_common_init(dsp);
 }
 EXPORT_SYMBOL_GPL(wm_adsp1_init);
 }
 EXPORT_SYMBOL_GPL(wm_adsp1_event);
 
-static int wm_adsp2_ena(struct wm_adsp *dsp)
+static int wm_adsp2v2_enable_core(struct wm_adsp *dsp)
 {
        unsigned int val;
        int ret, count;
 
-       switch (dsp->rev) {
-       case 0:
-               ret = regmap_update_bits_async(dsp->regmap,
-                                              dsp->base + ADSP2_CONTROL,
-                                              ADSP2_SYS_ENA, ADSP2_SYS_ENA);
-               if (ret != 0)
-                       return ret;
-               break;
-       default:
-               break;
-       }
-
        /* Wait for the RAM to start, should be near instantaneous */
        for (count = 0; count < 10; ++count) {
                ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
        return 0;
 }
 
+static int wm_adsp2_enable_core(struct wm_adsp *dsp)
+{
+       int ret;
+
+       ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
+                                      ADSP2_SYS_ENA, ADSP2_SYS_ENA);
+       if (ret != 0)
+               return ret;
+
+       return wm_adsp2v2_enable_core(dsp);
+}
+
 static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
 {
        struct regmap *regmap = dsp->regmap;
        return 0;
 }
 
-static void wm_adsp2_boot_work(struct work_struct *work)
+static int wm_adsp2_enable_memory(struct wm_adsp *dsp)
+{
+       return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+                                 ADSP2_MEM_ENA, ADSP2_MEM_ENA);
+}
+
+static void wm_adsp2_disable_memory(struct wm_adsp *dsp)
+{
+       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+                          ADSP2_MEM_ENA, 0);
+}
+
+static void wm_adsp2_disable_core(struct wm_adsp *dsp)
+{
+       regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
+       regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
+       regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
+
+       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+                          ADSP2_SYS_ENA, 0);
+}
+
+static void wm_adsp2v2_disable_core(struct wm_adsp *dsp)
+{
+       regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
+       regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
+       regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
+}
+
+static void wm_adsp_boot_work(struct work_struct *work)
 {
        struct wm_adsp *dsp = container_of(work,
                                           struct wm_adsp,
 
        mutex_lock(&dsp->pwr_lock);
 
-       ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
-                                ADSP2_MEM_ENA, ADSP2_MEM_ENA);
-       if (ret != 0)
-               goto err_mutex;
+       if (dsp->ops->enable_memory) {
+               ret = dsp->ops->enable_memory(dsp);
+               if (ret != 0)
+                       goto err_mutex;
+       }
 
-       ret = wm_adsp2_ena(dsp);
-       if (ret != 0)
-               goto err_mem;
+       if (dsp->ops->enable_core) {
+               ret = dsp->ops->enable_core(dsp);
+               if (ret != 0)
+                       goto err_mem;
+       }
 
        ret = wm_adsp_load(dsp);
        if (ret != 0)
                goto err_ena;
 
-       ret = wm_adsp2_setup_algs(dsp);
+       ret = dsp->ops->setup_algs(dsp);
        if (ret != 0)
                goto err_ena;
 
        if (ret != 0)
                goto err_ena;
 
-       switch (dsp->rev) {
-       case 0:
-               /* Turn DSP back off until we are ready to run */
-               ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
-                                        ADSP2_SYS_ENA, 0);
-               if (ret != 0)
-                       goto err_ena;
-               break;
-       default:
-               break;
-       }
+       if (dsp->ops->disable_core)
+               dsp->ops->disable_core(dsp);
 
        dsp->booted = true;
 
        return;
 
 err_ena:
-       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
-                          ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+       if (dsp->ops->disable_core)
+               dsp->ops->disable_core(dsp);
 err_mem:
-       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
-                          ADSP2_MEM_ENA, 0);
+       if (dsp->ops->disable_memory)
+               dsp->ops->disable_memory(dsp);
 err_mutex:
        mutex_unlock(&dsp->pwr_lock);
 }
 
 static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
 {
-       switch (dsp->rev) {
-       case 0:
-       case 1:
-               return;
-       default:
-               regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
-                                  ADSP2_WDT_ENA_MASK, 0);
-       }
+       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
+                          ADSP2_WDT_ENA_MASK, 0);
 }
 
-int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
-                        struct snd_kcontrol *kcontrol, int event)
+int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
        struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
 
                dsp->booted = false;
 
-               regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
-                                  ADSP2_MEM_ENA, 0);
+               if (dsp->ops->disable_memory)
+                       dsp->ops->disable_memory(dsp);
 
                list_for_each_entry(ctl, &dsp->ctl_list, list)
                        ctl->enabled = 0;
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
+EXPORT_SYMBOL_GPL(wm_adsp_early_event);
 
-int wm_adsp2_event(struct snd_soc_dapm_widget *w,
-                  struct snd_kcontrol *kcontrol, int event)
+static int wm_adsp2_start_core(struct wm_adsp *dsp)
+{
+       return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+                                ADSP2_CORE_ENA | ADSP2_START,
+                                ADSP2_CORE_ENA | ADSP2_START);
+}
+
+static void wm_adsp2_stop_core(struct wm_adsp *dsp)
+{
+       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+                          ADSP2_CORE_ENA | ADSP2_START, 0);
+}
+
+int wm_adsp_event(struct snd_soc_dapm_widget *w,
+                 struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
        struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
                        goto err;
                }
 
-               ret = wm_adsp2_ena(dsp);
-               if (ret != 0)
-                       goto err;
+               if (dsp->ops->enable_core) {
+                       ret = dsp->ops->enable_core(dsp);
+                       if (ret != 0)
+                               goto err;
+               }
 
                /* Sync set controls */
                ret = wm_coeff_sync_controls(dsp);
                if (ret != 0)
                        goto err;
 
-               wm_adsp2_lock(dsp, dsp->lock_regions);
+               if (dsp->ops->lock_memory) {
+                       ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
+                       if (ret != 0) {
+                               adsp_err(dsp, "Error configuring MPU: %d\n",
+                                        ret);
+                               goto err;
+                       }
+               }
 
-               ret = regmap_update_bits(dsp->regmap,
-                                        dsp->base + ADSP2_CONTROL,
-                                        ADSP2_CORE_ENA | ADSP2_START,
-                                        ADSP2_CORE_ENA | ADSP2_START);
-               if (ret != 0)
-                       goto err;
+               if (dsp->ops->start_core) {
+                       ret = dsp->ops->start_core(dsp);
+                       if (ret != 0)
+                               goto err;
+               }
 
                if (wm_adsp_fw[dsp->fw].num_caps != 0) {
                        ret = wm_adsp_buffer_init(dsp);
                dsp->running = true;
 
                mutex_unlock(&dsp->pwr_lock);
-
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
                /* Tell the firmware to cleanup */
                wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
 
-               wm_adsp_stop_watchdog(dsp);
+               if (dsp->ops->stop_watchdog)
+                       dsp->ops->stop_watchdog(dsp);
 
                /* Log firmware state, it can be useful for analysis */
-               switch (dsp->rev) {
-               case 0:
-                       wm_adsp2_show_fw_status(dsp);
-                       break;
-               default:
-                       wm_adsp2v2_show_fw_status(dsp);
-                       break;
-               }
+               if (dsp->ops->show_fw_status)
+                       dsp->ops->show_fw_status(dsp);
 
                mutex_lock(&dsp->pwr_lock);
 
                dsp->running = false;
 
-               regmap_update_bits(dsp->regmap,
-                                  dsp->base + ADSP2_CONTROL,
-                                  ADSP2_CORE_ENA | ADSP2_START, 0);
-
-               /* Make sure DMAs are quiesced */
-               switch (dsp->rev) {
-               case 0:
-                       regmap_write(dsp->regmap,
-                                    dsp->base + ADSP2_RDMA_CONFIG_1, 0);
-                       regmap_write(dsp->regmap,
-                                    dsp->base + ADSP2_WDMA_CONFIG_1, 0);
-                       regmap_write(dsp->regmap,
-                                    dsp->base + ADSP2_WDMA_CONFIG_2, 0);
-
-                       regmap_update_bits(dsp->regmap,
-                                          dsp->base + ADSP2_CONTROL,
-                                          ADSP2_SYS_ENA, 0);
-                       break;
-               default:
-                       regmap_write(dsp->regmap,
-                                    dsp->base + ADSP2_RDMA_CONFIG_1, 0);
-                       regmap_write(dsp->regmap,
-                                    dsp->base + ADSP2_WDMA_CONFIG_1, 0);
-                       regmap_write(dsp->regmap,
-                                    dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
-                       break;
-               }
+               if (dsp->ops->stop_core)
+                       dsp->ops->stop_core(dsp);
+               if (dsp->ops->disable_core)
+                       dsp->ops->disable_core(dsp);
 
                if (wm_adsp_fw[dsp->fw].num_caps != 0)
                        wm_adsp_buffer_free(dsp);
 
        return 0;
 err:
-       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
-                          ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+       if (dsp->ops->stop_core)
+               dsp->ops->stop_core(dsp);
+       if (dsp->ops->disable_core)
+               dsp->ops->disable_core(dsp);
        mutex_unlock(&dsp->pwr_lock);
        return ret;
 }
-EXPORT_SYMBOL_GPL(wm_adsp2_event);
+EXPORT_SYMBOL_GPL(wm_adsp_event);
 
 int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
 {
                                 "Failed to clear memory retention: %d\n", ret);
                        return ret;
                }
+
+               dsp->ops = &wm_adsp2_ops[0];
+               break;
+       case 1:
+               dsp->ops = &wm_adsp2_ops[1];
                break;
        default:
+               dsp->ops = &wm_adsp2_ops[2];
                break;
        }
 
-       INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
+       INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
 
        return 0;
 }
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
 
+struct wm_adsp_ops wm_adsp1_ops = {
+       .validate_version = wm_adsp_validate_version,
+       .parse_sizes = wm_adsp1_parse_sizes,
+};
+
+struct wm_adsp_ops wm_adsp2_ops[] = {
+       {
+               .parse_sizes = wm_adsp2_parse_sizes,
+               .validate_version = wm_adsp_validate_version,
+               .setup_algs = wm_adsp2_setup_algs,
+
+               .show_fw_status = wm_adsp2_show_fw_status,
+
+               .enable_memory = wm_adsp2_enable_memory,
+               .disable_memory = wm_adsp2_disable_memory,
+
+               .enable_core = wm_adsp2_enable_core,
+               .disable_core = wm_adsp2_disable_core,
+
+               .start_core = wm_adsp2_start_core,
+               .stop_core = wm_adsp2_stop_core,
+
+       },
+       {
+               .parse_sizes = wm_adsp2_parse_sizes,
+               .validate_version = wm_adsp_validate_version,
+               .setup_algs = wm_adsp2_setup_algs,
+
+               .show_fw_status = wm_adsp2v2_show_fw_status,
+
+               .enable_memory = wm_adsp2_enable_memory,
+               .disable_memory = wm_adsp2_disable_memory,
+               .lock_memory = wm_adsp2_lock,
+
+               .enable_core = wm_adsp2v2_enable_core,
+               .disable_core = wm_adsp2v2_disable_core,
+
+               .start_core = wm_adsp2_start_core,
+               .stop_core = wm_adsp2_stop_core,
+       },
+       {
+               .parse_sizes = wm_adsp2_parse_sizes,
+               .validate_version = wm_adsp_validate_version,
+               .setup_algs = wm_adsp2_setup_algs,
+
+               .show_fw_status = wm_adsp2v2_show_fw_status,
+               .stop_watchdog = wm_adsp_stop_watchdog,
+
+               .enable_memory = wm_adsp2_enable_memory,
+               .disable_memory = wm_adsp2_disable_memory,
+               .lock_memory = wm_adsp2_lock,
+
+               .enable_core = wm_adsp2v2_enable_core,
+               .disable_core = wm_adsp2v2_disable_core,
+
+               .start_core = wm_adsp2_start_core,
+               .stop_core = wm_adsp2_stop_core,
+       },
+};
+
 MODULE_LICENSE("GPL v2");