ASoC: wm_adsp: Factor out ADSP2 boot proceedure
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>
Wed, 8 Jan 2014 17:42:18 +0000 (17:42 +0000)
committerMark Brown <broonie@linaro.org>
Wed, 8 Jan 2014 18:17:37 +0000 (18:17 +0000)
Move the ADSP2 boot proceedure into a work structure in preparation for
running it asynchronously with the reset of the audio path bring up.

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

index 8f720ded27c4208203a05e325805582033e93417..2087ae2eb32350d699f914349f68f2589a4807a9 100644 (file)
@@ -1492,107 +1492,131 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
        return 0;
 }
 
-int wm_adsp2_event(struct snd_soc_dapm_widget *w,
-                  struct snd_kcontrol *kcontrol, int event)
+void wm_adsp2_boot_work(struct work_struct *work)
 {
-       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;
-       struct wm_coeff_ctl *ctl;
-       unsigned int val;
+       struct wm_adsp *dsp = container_of(work,
+                                          struct wm_adsp,
+                                          boot_work);
        int ret;
+       unsigned int val;
 
-       dsp->card = codec->card;
+       /*
+        * For simplicity set the DSP clock rate to be the
+        * SYSCLK rate rather than making it configurable.
+        */
+       ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
+       if (ret != 0) {
+               adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
+               return;
+       }
+       val = (val & ARIZONA_SYSCLK_FREQ_MASK)
+               >> ARIZONA_SYSCLK_FREQ_SHIFT;
 
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               /*
-                * For simplicity set the DSP clock rate to be the
-                * SYSCLK rate rather than making it configurable.
-                */
-               ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
-               if (ret != 0) {
-                       adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
-                                ret);
-                       return ret;
-               }
-               val = (val & ARIZONA_SYSCLK_FREQ_MASK)
-                       >> ARIZONA_SYSCLK_FREQ_SHIFT;
+       ret = regmap_update_bits_async(dsp->regmap,
+                                      dsp->base + ADSP2_CLOCKING,
+                                      ADSP2_CLK_SEL_MASK, val);
+       if (ret != 0) {
+               adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
+               return;
+       }
 
-               ret = regmap_update_bits_async(dsp->regmap,
-                                              dsp->base + ADSP2_CLOCKING,
-                                              ADSP2_CLK_SEL_MASK, val);
+       if (dsp->dvfs) {
+               ret = regmap_read(dsp->regmap,
+                                 dsp->base + ADSP2_CLOCKING, &val);
                if (ret != 0) {
-                       adsp_err(dsp, "Failed to set clock rate: %d\n",
-                                ret);
-                       return ret;
+                       dev_err(dsp->dev, "Failed to read clocking: %d\n", ret);
+                       return;
                }
 
-               if (dsp->dvfs) {
-                       ret = regmap_read(dsp->regmap,
-                                         dsp->base + ADSP2_CLOCKING, &val);
+               if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
+                       ret = regulator_enable(dsp->dvfs);
                        if (ret != 0) {
                                dev_err(dsp->dev,
-                                       "Failed to read clocking: %d\n", ret);
-                               return ret;
+                                       "Failed to enable supply: %d\n",
+                                       ret);
+                               return;
                        }
 
-                       if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
-                               ret = regulator_enable(dsp->dvfs);
-                               if (ret != 0) {
-                                       dev_err(dsp->dev,
-                                               "Failed to enable supply: %d\n",
-                                               ret);
-                                       return ret;
-                               }
-
-                               ret = regulator_set_voltage(dsp->dvfs,
-                                                           1800000,
-                                                           1800000);
-                               if (ret != 0) {
-                                       dev_err(dsp->dev,
-                                               "Failed to raise supply: %d\n",
-                                               ret);
-                                       return ret;
-                               }
+                       ret = regulator_set_voltage(dsp->dvfs,
+                                                   1800000,
+                                                   1800000);
+                       if (ret != 0) {
+                               dev_err(dsp->dev,
+                                       "Failed to raise supply: %d\n",
+                                       ret);
+                               return;
                        }
                }
+       }
 
-               ret = wm_adsp2_ena(dsp);
-               if (ret != 0)
-                       return ret;
+       ret = wm_adsp2_ena(dsp);
+       if (ret != 0)
+               return;
 
-               ret = wm_adsp_load(dsp);
-               if (ret != 0)
-                       goto err;
+       ret = wm_adsp_load(dsp);
+       if (ret != 0)
+               goto err;
 
-               ret = wm_adsp_setup_algs(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;
+       ret = wm_adsp_load_coeff(dsp);
+       if (ret != 0)
+               goto err;
 
-               /* Initialize caches for enabled and unset controls */
-               ret = wm_coeff_init_control_caches(dsp);
-               if (ret != 0)
-                       goto err;
+       /* Initialize caches for enabled and unset controls */
+       ret = wm_coeff_init_control_caches(dsp);
+       if (ret != 0)
+               goto err;
 
-               /* Sync set controls */
-               ret = wm_coeff_sync_controls(dsp);
-               if (ret != 0)
-                       goto err;
+       /* Sync set controls */
+       ret = wm_coeff_sync_controls(dsp);
+       if (ret != 0)
+               goto err;
+
+       ret = regmap_update_bits_async(dsp->regmap,
+                                      dsp->base + ADSP2_CONTROL,
+                                      ADSP2_CORE_ENA,
+                                      ADSP2_CORE_ENA);
+       if (ret != 0)
+               goto err;
+
+       dsp->running = true;
+
+       return;
 
-               ret = regmap_update_bits_async(dsp->regmap,
-                                              dsp->base + ADSP2_CONTROL,
-                                              ADSP2_CORE_ENA | ADSP2_START,
-                                              ADSP2_CORE_ENA | ADSP2_START);
+err:
+       regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+                          ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+}
+
+int wm_adsp2_event(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol, int event)
+{
+       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;
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       dsp->card = codec->card;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               queue_work(system_unbound_wq, &dsp->boot_work);
+               flush_work(&dsp->boot_work);
+
+               if (!dsp->running)
+                       return -EIO;
+
+               ret = regmap_update_bits(dsp->regmap,
+                                        dsp->base + ADSP2_CONTROL,
+                                        ADSP2_START,
+                                        ADSP2_START);
                if (ret != 0)
                        goto err;
-
-               dsp->running = true;
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
@@ -1663,6 +1687,7 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
 
        INIT_LIST_HEAD(&adsp->alg_regions);
        INIT_LIST_HEAD(&adsp->ctl_list);
+       INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work);
 
        if (dvfs) {
                adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
index d018dea6254de44c5997813fcb9b958eeca09706..b172c1df9159fca54e9483d9d23f311c3b91a887 100644 (file)
@@ -59,6 +59,8 @@ struct wm_adsp {
        struct regulator *dvfs;
 
        struct list_head ctl_list;
+
+       struct work_struct boot_work;
 };
 
 #define WM_ADSP1(wname, num) \