ASoC: tpa6130a2: fix volume setting when no stream is running
authorNikita Yushchenko <nikita.yoush@cogentembedded.com>
Thu, 22 Sep 2016 10:10:40 +0000 (13:10 +0300)
committerMark Brown <broonie@kernel.org>
Sat, 24 Sep 2016 18:26:59 +0000 (19:26 +0100)
After moving tpa6130a2 power management to DAPM, if chip can be physically
powered off (either reset_gpio is defined, or regulator indeed removes
power), then volume change no longer works unless chip is on due to
a running stream.

Fix that by entering regcache cache_only mode while chip is off.

Move regcache calls to tpa6130a2_power() to get them at driver init time
as well.

Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/tpa6130a2.c

index f1ea052a822e1f584eb55cbc876b8e079e813ccd..3b6faed91d7eac7151dea511fd33585cb9a2c5b8 100644 (file)
@@ -52,7 +52,7 @@ struct tpa6130a2_data {
 
 static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
 {
-       int ret;
+       int ret = 0, ret2;
 
        if (enable) {
                ret = regulator_enable(data->supply);
@@ -64,20 +64,34 @@ static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
                /* Power on */
                if (data->power_gpio >= 0)
                        gpio_set_value(data->power_gpio, 1);
+
+               /* Sync registers */
+               regcache_cache_only(data->regmap, false);
+               ret = regcache_sync(data->regmap);
+               if (ret != 0) {
+                       dev_err(data->dev,
+                               "Failed to sync registers: %d\n", ret);
+                       goto regcache_sync_failed;
+               }
        } else {
+               /* Powered off device does not retain registers. While device
+                * is off, any register updates (i.e. volume changes) should
+                * happen in cache only.
+                */
+               regcache_mark_dirty(data->regmap);
+regcache_sync_failed:
+               regcache_cache_only(data->regmap, true);
+
                /* Power off */
                if (data->power_gpio >= 0)
                        gpio_set_value(data->power_gpio, 0);
 
-               ret = regulator_disable(data->supply);
-               if (ret != 0) {
+               ret2 = regulator_disable(data->supply);
+               if (ret2 != 0) {
                        dev_err(data->dev,
-                               "Failed to disable supply: %d\n", ret);
-                       return ret;
+                               "Failed to disable supply: %d\n", ret2);
+                       return ret ? ret : ret2;
                }
-
-               /* device regs does not match the cache state anymore */
-               regcache_mark_dirty(data->regmap);
        }
 
        return ret;
@@ -88,25 +102,14 @@ static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
        struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c);
-       int ret;
 
-       /* before widget power up */
        if (SND_SOC_DAPM_EVENT_ON(event)) {
-               /* Turn on the chip */
-               tpa6130a2_power(data, true);
-               /* Sync the registers */
-               ret = regcache_sync(data->regmap);
-               if (ret < 0) {
-                       dev_err(c->dev, "Failed to initialize chip\n");
-                       tpa6130a2_power(data, false);
-                       return ret;
-               }
-       /* after widget power down */
+               /* Before widget power up: turn chip on, sync registers */
+               return tpa6130a2_power(data, true);
        } else {
-               tpa6130a2_power(data, false);
+               /* After widget power down: turn chip off */
+               return tpa6130a2_power(data, false);
        }
-
-       return 0;
 }
 
 /*