Merge remote-tracking branch 'asoc/topic/wm8770' into asoc-next
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Sun, 2 Dec 2012 04:35:23 +0000 (13:35 +0900)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Sun, 2 Dec 2012 04:35:23 +0000 (13:35 +0900)
sound/soc/codecs/wm8770.c

index c7c0034d39669a5e4b548bd7a46f40eb716f00cd..0b690ba875f84ba1bd2df6934afc27930a81a29b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/of_device.h>
 #include <linux/pm.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -35,19 +36,52 @@ static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = {
        "DVDD"
 };
 
-static const u16 wm8770_reg_defs[WM8770_CACHEREGNUM] = {
-       0x7f, 0x7f, 0x7f, 0x7f,
-       0x7f, 0x7f, 0x7f, 0x7f,
-       0x7f, 0xff, 0xff, 0xff,
-       0xff, 0xff, 0xff, 0xff,
-       0xff, 0xff, 0, 0x90, 0,
-       0, 0x22, 0x22, 0x3e,
-       0xc, 0xc, 0x100, 0x189,
-       0x189, 0x8770
+static const struct reg_default wm8770_reg_defaults[] = {
+       {  0, 0x7f },
+       {  1, 0x7f },
+       {  2, 0x7f },
+       {  3, 0x7f },
+       {  4, 0x7f },
+       {  5, 0x7f },
+       {  6, 0x7f },
+       {  7, 0x7f },
+       {  8, 0x7f },
+       {  9, 0xff },
+       { 10, 0xff },
+       { 11, 0xff },
+       { 12, 0xff },
+       { 13, 0xff },
+       { 14, 0xff },
+       { 15, 0xff },
+       { 16, 0xff },
+       { 17, 0xff },
+       { 18, 0    },
+       { 19, 0x90 },
+       { 20, 0    },
+       { 21, 0    },
+       { 22, 0x22 },
+       { 23, 0x22 },
+       { 24, 0x3e },
+       { 25, 0xc  },
+       { 26, 0xc  },
+       { 27, 0x100 },
+       { 28, 0x189 },
+       { 29, 0x189 },
+       { 30, 0x8770 },
 };
 
+static bool wm8770_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8770_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
 struct wm8770_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES];
        struct notifier_block disable_nb[WM8770_NUM_SUPPLIES];
        struct snd_soc_codec *codec;
@@ -71,7 +105,7 @@ static int wm8770_regulator_event_##n(struct notifier_block *nb, \
        struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \
                                     disable_nb[n]); \
        if (event & REGULATOR_EVENT_DISABLE) { \
-               wm8770->codec->cache_sync = 1; \
+               regcache_mark_dirty(wm8770->regmap);    \
        } \
        return 0; \
 }
@@ -466,24 +500,6 @@ static int wm8770_set_sysclk(struct snd_soc_dai *dai,
        return 0;
 }
 
-static void wm8770_sync_cache(struct snd_soc_codec *codec)
-{
-       int i;
-       u16 *cache;
-
-       if (!codec->cache_sync)
-               return;
-
-       codec->cache_only = 0;
-       cache = codec->reg_cache;
-       for (i = 0; i < codec->driver->reg_cache_size; i++) {
-               if (i == WM8770_RESET || cache[i] == wm8770_reg_defs[i])
-                       continue;
-               snd_soc_write(codec, i, cache[i]);
-       }
-       codec->cache_sync = 0;
-}
-
 static int wm8770_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
@@ -507,7 +523,9 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec,
                                        ret);
                                return ret;
                        }
-                       wm8770_sync_cache(codec);
+
+                       regcache_sync(wm8770->regmap);
+
                        /* global powerup */
                        snd_soc_write(codec, WM8770_PWDNCTRL, 0);
                }
@@ -554,68 +572,25 @@ static struct snd_soc_dai_driver wm8770_dai = {
        .symmetric_rates = 1
 };
 
-#ifdef CONFIG_PM
-static int wm8770_suspend(struct snd_soc_codec *codec)
-{
-       wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       return 0;
-}
-
-static int wm8770_resume(struct snd_soc_codec *codec)
-{
-       wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       return 0;
-}
-#else
-#define wm8770_suspend NULL
-#define wm8770_resume NULL
-#endif
-
 static int wm8770_probe(struct snd_soc_codec *codec)
 {
        struct wm8770_priv *wm8770;
        int ret;
-       int i;
 
        wm8770 = snd_soc_codec_get_drvdata(codec);
        wm8770->codec = codec;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++)
-               wm8770->supplies[i].supply = wm8770_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8770->supplies),
-                                wm8770->supplies);
-       if (ret) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               return ret;
-       }
-
-       wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0;
-       wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1;
-       wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2;
-
-       /* This should really be moved into the regulator core */
-       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) {
-               ret = regulator_register_notifier(wm8770->supplies[i].consumer,
-                                                 &wm8770->disable_nb[i]);
-               if (ret) {
-                       dev_err(codec->dev,
-                               "Failed to register regulator notifier: %d\n",
-                               ret);
-               }
-       }
-
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
                                    wm8770->supplies);
        if (ret) {
                dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_reg_get;
+               return ret;
        }
 
        ret = wm8770_reset(codec);
@@ -624,8 +599,6 @@ static int wm8770_probe(struct snd_soc_codec *codec)
                goto err_reg_enable;
        }
 
-       wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        /* latch the volume update bits */
        snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100);
        snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100);
@@ -641,46 +614,22 @@ static int wm8770_probe(struct snd_soc_codec *codec)
        /* mute all DACs */
        snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10);
 
-       snd_soc_add_codec_controls(codec, wm8770_snd_controls,
-                            ARRAY_SIZE(wm8770_snd_controls));
-       snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets,
-                                 ARRAY_SIZE(wm8770_dapm_widgets));
-       snd_soc_dapm_add_routes(&codec->dapm, wm8770_intercon,
-                               ARRAY_SIZE(wm8770_intercon));
-       return 0;
-
 err_reg_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
-err_reg_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
        return ret;
 }
 
-static int wm8770_remove(struct snd_soc_codec *codec)
-{
-       struct wm8770_priv *wm8770;
-       int i;
-
-       wm8770 = snd_soc_codec_get_drvdata(codec);
-       wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i)
-               regulator_unregister_notifier(wm8770->supplies[i].consumer,
-                                             &wm8770->disable_nb[i]);
-       regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
-       return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
        .probe = wm8770_probe,
-       .remove = wm8770_remove,
-       .suspend = wm8770_suspend,
-       .resume = wm8770_resume,
        .set_bias_level = wm8770_set_bias_level,
        .idle_bias_off = true,
-       .reg_cache_size = ARRAY_SIZE(wm8770_reg_defs),
-       .reg_word_size = sizeof (u16),
-       .reg_cache_default = wm8770_reg_defs
+
+       .controls = wm8770_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8770_snd_controls),
+       .dapm_widgets = wm8770_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8770_dapm_widgets),
+       .dapm_routes = wm8770_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8770_intercon),
 };
 
 static const struct of_device_id wm8770_of_match[] = {
@@ -689,17 +638,57 @@ static const struct of_device_id wm8770_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8770_of_match);
 
+static const struct regmap_config wm8770_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8770_RESET,
+
+       .reg_defaults = wm8770_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8770_volatile_reg,
+};
+
 static int __devinit wm8770_spi_probe(struct spi_device *spi)
 {
        struct wm8770_priv *wm8770;
-       int ret;
+       int ret, i;
 
        wm8770 = devm_kzalloc(&spi->dev, sizeof(struct wm8770_priv),
                              GFP_KERNEL);
        if (!wm8770)
                return -ENOMEM;
 
-       wm8770->control_type = SND_SOC_SPI;
+       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++)
+               wm8770->supplies[i].supply = wm8770_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8770->supplies),
+                                     wm8770->supplies);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0;
+       wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1;
+       wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2;
+
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) {
+               ret = regulator_register_notifier(wm8770->supplies[i].consumer,
+                                                 &wm8770->disable_nb[i]);
+               if (ret) {
+                       dev_err(&spi->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       wm8770->regmap = devm_regmap_init_spi(spi, &wm8770_regmap);
+       if (IS_ERR(wm8770->regmap))
+               return PTR_ERR(wm8770->regmap);
+
        spi_set_drvdata(spi, wm8770);
 
        ret = snd_soc_register_codec(&spi->dev,
@@ -710,7 +699,15 @@ static int __devinit wm8770_spi_probe(struct spi_device *spi)
 
 static int __devexit wm8770_spi_remove(struct spi_device *spi)
 {
+       struct wm8770_priv *wm8770 = spi_get_drvdata(spi);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i)
+               regulator_unregister_notifier(wm8770->supplies[i].consumer,
+                                             &wm8770->disable_nb[i]);
+
        snd_soc_unregister_codec(&spi->dev);
+
        return 0;
 }