Merge remote-tracking branches 'asoc/topic/da7218', 'asoc/topic/da7219' and 'asoc...
[linux-2.6-block.git] / sound / soc / codecs / da7219.c
index 50ea94317cb3216d116b9351cf5387a0213b4689..1152aa5e7c394208d6e42f04a2c4d44c8b0ea906 100644 (file)
@@ -801,7 +801,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
                                ++i;
                                msleep(50);
                        }
-               } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock));
+               } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
 
                if (!srm_lock)
                        dev_warn(codec->dev, "SRM failed to lock\n");
@@ -1482,6 +1482,8 @@ static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_codec *codec)
        if (!pdata)
                return NULL;
 
+       pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source");
+
        if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0)
                pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32);
        else
@@ -1508,11 +1510,10 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-       case SND_SOC_BIAS_PREPARE:
                break;
-       case SND_SOC_BIAS_STANDBY:
-               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-                       /* MCLK */
+       case SND_SOC_BIAS_PREPARE:
+               /* Enable MCLK for transition to ON state */
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
                        if (da7219->mclk) {
                                ret = clk_prepare_enable(da7219->mclk);
                                if (ret) {
@@ -1521,22 +1522,28 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
                                        return ret;
                                }
                        }
+               }
 
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                        /* Master bias */
                        snd_soc_update_bits(codec, DA7219_REFERENCES,
                                            DA7219_BIAS_EN_MASK,
                                            DA7219_BIAS_EN_MASK);
+
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) {
+                       /* Remove MCLK */
+                       if (da7219->mclk)
+                               clk_disable_unprepare(da7219->mclk);
                }
                break;
        case SND_SOC_BIAS_OFF:
-               /* Only disable master bias if jack detection not active */
-               if (!da7219->aad->jack)
+               /* Only disable master bias if we're not a wake-up source */
+               if (!da7219->wakeup_source)
                        snd_soc_update_bits(codec, DA7219_REFERENCES,
                                            DA7219_BIAS_EN_MASK, 0);
 
-               /* MCLK */
-               if (da7219->mclk)
-                       clk_disable_unprepare(da7219->mclk);
                break;
        }
 
@@ -1599,6 +1606,8 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec)
        if (pdata) {
                u8 micbias_lvl = 0;
 
+               da7219->wakeup_source = pdata->wakeup_source;
+
                /* Mic Bias voltages */
                switch (pdata->micbias_lvl) {
                case DA7219_MICBIAS_1_6V:
@@ -1733,11 +1742,11 @@ static int da7219_suspend(struct snd_soc_codec *codec)
 {
        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 
-       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+       /* Suspend AAD if we're not a wake-up source */
+       if (!da7219->wakeup_source)
+               da7219_aad_suspend(codec);
 
-       /* Put device into standby mode if jack detection disabled */
-       if (!da7219->aad->jack)
-               snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, 0);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
@@ -1746,13 +1755,12 @@ static int da7219_resume(struct snd_soc_codec *codec)
 {
        struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
 
-       /* Put device into active mode if previously pushed to standby */
-       if (!da7219->aad->jack)
-               snd_soc_write(codec, DA7219_SYSTEM_ACTIVE,
-                             DA7219_SYSTEM_ACTIVE_MASK);
-
        snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+       /* Resume AAD if previously suspended */
+       if (!da7219->wakeup_source)
+               da7219_aad_resume(codec);
+
        return 0;
 }
 #else
@@ -1767,13 +1775,14 @@ static struct snd_soc_codec_driver soc_codec_dev_da7219 = {
        .resume                 = da7219_resume,
        .set_bias_level         = da7219_set_bias_level,
 
-       .controls               = da7219_snd_controls,
-       .num_controls           = ARRAY_SIZE(da7219_snd_controls),
-
-       .dapm_widgets           = da7219_dapm_widgets,
-       .num_dapm_widgets       = ARRAY_SIZE(da7219_dapm_widgets),
-       .dapm_routes            = da7219_audio_map,
-       .num_dapm_routes        = ARRAY_SIZE(da7219_audio_map),
+       .component_driver = {
+               .controls               = da7219_snd_controls,
+               .num_controls           = ARRAY_SIZE(da7219_snd_controls),
+               .dapm_widgets           = da7219_dapm_widgets,
+               .num_dapm_widgets       = ARRAY_SIZE(da7219_dapm_widgets),
+               .dapm_routes            = da7219_audio_map,
+               .num_dapm_routes        = ARRAY_SIZE(da7219_audio_map),
+       },
 };
 
 
@@ -1921,7 +1930,8 @@ static int da7219_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct da7219_priv *da7219;
-       int ret;
+       unsigned int system_active, system_status;
+       int i, ret;
 
        da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv),
                              GFP_KERNEL);
@@ -1937,6 +1947,37 @@ static int da7219_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
+       regcache_cache_bypass(da7219->regmap, true);
+
+       /* Disable audio paths if still active from previous start */
+       regmap_read(da7219->regmap, DA7219_SYSTEM_ACTIVE, &system_active);
+       if (system_active) {
+               regmap_write(da7219->regmap, DA7219_GAIN_RAMP_CTRL,
+                            DA7219_GAIN_RAMP_RATE_NOMINAL);
+               regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_INPUT, 0x00);
+               regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_OUTPUT, 0x01);
+
+               for (i = 0; i < DA7219_SYS_STAT_CHECK_RETRIES; ++i) {
+                       regmap_read(da7219->regmap, DA7219_SYSTEM_STATUS,
+                                   &system_status);
+                       if (!system_status)
+                               break;
+
+                       msleep(DA7219_SYS_STAT_CHECK_DELAY);
+               }
+       }
+
+       /* Soft reset codec */
+       regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1,
+                         DA7219_ACCDET_EN_MASK, 0);
+       regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL,
+                         DA7219_CIF_REG_SOFT_RESET_MASK,
+                         DA7219_CIF_REG_SOFT_RESET_MASK);
+       regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE,
+                         DA7219_SYSTEM_ACTIVE_MASK, 0);
+
+       regcache_cache_bypass(da7219->regmap, false);
+
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7219,
                                     &da7219_dai, 1);
        if (ret < 0) {