ASoC: dapm: Allow regulators to bypass as well as disable when idle
[linux-2.6-block.git] / sound / soc / codecs / ad1836.c
index c67b50d8b3170cd388a1279516a186c9a23e9a99..dce6ebeef4527cfb176063e91c90a9a741ee3f89 100644 (file)
@@ -19,6 +19,8 @@
 #include <sound/soc.h>
 #include <sound/tlv.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
 #include "ad1836.h"
 
 enum ad1836_type {
@@ -30,6 +32,7 @@ enum ad1836_type {
 /* codec private data */
 struct ad1836_priv {
        enum ad1836_type type;
+       struct regmap *regmap;
 };
 
 /*
@@ -161,8 +164,8 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params,
                struct snd_soc_dai *dai)
 {
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(dai->codec);
        int word_len = 0;
-       struct snd_soc_codec *codec = dai->codec;
 
        /* bit size */
        switch (params_format(params)) {
@@ -178,10 +181,12 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       snd_soc_update_bits(codec, AD1836_DAC_CTRL1, AD1836_DAC_WORD_LEN_MASK,
+       regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1,
+               AD1836_DAC_WORD_LEN_MASK,
                word_len << AD1836_DAC_WORD_LEN_OFFSET);
 
-       snd_soc_update_bits(codec, AD1836_ADC_CTRL2, AD1836_ADC_WORD_LEN_MASK,
+       regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
+               AD1836_ADC_WORD_LEN_MASK,
                word_len << AD1836_ADC_WORD_OFFSET);
 
        return 0;
@@ -223,15 +228,17 @@ static struct snd_soc_dai_driver ad183x_dais[] = {
 #ifdef CONFIG_PM
 static int ad1836_suspend(struct snd_soc_codec *codec)
 {
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
        /* reset clock control mode */
-       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+       return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
                AD1836_ADC_SERFMT_MASK, 0);
 }
 
 static int ad1836_resume(struct snd_soc_codec *codec)
 {
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
        /* restore clock control mode */
-       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+       return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
                AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX);
 }
 #else
@@ -250,37 +257,30 @@ static int ad1836_probe(struct snd_soc_codec *codec)
        num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2;
        num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2;
 
-       ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to set cache I/O: %d\n",
-                               ret);
-               return ret;
-       }
-
        /* default setting for ad1836 */
        /* de-emphasis: 48kHz, power-on dac */
-       snd_soc_write(codec, AD1836_DAC_CTRL1, 0x300);
+       regmap_write(ad1836->regmap, AD1836_DAC_CTRL1, 0x300);
        /* unmute dac channels */
-       snd_soc_write(codec, AD1836_DAC_CTRL2, 0x0);
+       regmap_write(ad1836->regmap, AD1836_DAC_CTRL2, 0x0);
        /* high-pass filter enable, power-on adc */
-       snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100);
+       regmap_write(ad1836->regmap, AD1836_ADC_CTRL1, 0x100);
        /* unmute adc channles, adc aux mode */
-       snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180);
+       regmap_write(ad1836->regmap, AD1836_ADC_CTRL2, 0x180);
        /* volume */
        for (i = 1; i <= num_dacs; ++i) {
-               snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF);
-               snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF);
+               regmap_write(ad1836->regmap, AD1836_DAC_L_VOL(i), 0x3FF);
+               regmap_write(ad1836->regmap, AD1836_DAC_R_VOL(i), 0x3FF);
        }
 
        if (ad1836->type == AD1836) {
                /* left/right diff:PGA/MUX */
-               snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
+               regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x3A);
                ret = snd_soc_add_codec_controls(codec, ad1836_controls,
                                ARRAY_SIZE(ad1836_controls));
                if (ret)
                        return ret;
        } else {
-               snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00);
+               regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x00);
        }
 
        ret = snd_soc_add_codec_controls(codec, ad183x_dac_controls, num_dacs * 2);
@@ -313,8 +313,9 @@ static int ad1836_probe(struct snd_soc_codec *codec)
 /* power down chip */
 static int ad1836_remove(struct snd_soc_codec *codec)
 {
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
        /* reset clock control mode */
-       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+       return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
                AD1836_ADC_SERFMT_MASK, 0);
 }
 
@@ -323,8 +324,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
        .remove = ad1836_remove,
        .suspend = ad1836_suspend,
        .resume = ad1836_resume,
-       .reg_cache_size = AD1836_NUM_REGS,
-       .reg_word_size = sizeof(u16),
 
        .controls = ad183x_controls,
        .num_controls = ARRAY_SIZE(ad183x_controls),
@@ -334,6 +333,33 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
        .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),
 };
 
+static const struct reg_default ad1836_reg_defaults[] = {
+       { AD1836_DAC_CTRL1, 0x0000 },
+       { AD1836_DAC_CTRL2, 0x0000 },
+       { AD1836_DAC_L_VOL(0), 0x0000 },
+       { AD1836_DAC_R_VOL(0), 0x0000 },
+       { AD1836_DAC_L_VOL(1), 0x0000 },
+       { AD1836_DAC_R_VOL(1), 0x0000 },
+       { AD1836_DAC_L_VOL(2), 0x0000 },
+       { AD1836_DAC_R_VOL(2), 0x0000 },
+       { AD1836_DAC_L_VOL(3), 0x0000 },
+       { AD1836_DAC_R_VOL(3), 0x0000 },
+       { AD1836_ADC_CTRL1, 0x0000 },
+       { AD1836_ADC_CTRL2, 0x0000 },
+       { AD1836_ADC_CTRL3, 0x0000 },
+};
+
+static const struct regmap_config ad1836_regmap_config = {
+       .val_bits = 12,
+       .reg_bits = 4,
+       .read_flag_mask = 0x08,
+
+       .max_register = AD1836_ADC_CTRL3,
+       .reg_defaults = ad1836_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int __devinit ad1836_spi_probe(struct spi_device *spi)
 {
        struct ad1836_priv *ad1836;
@@ -344,6 +370,10 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi)
        if (ad1836 == NULL)
                return -ENOMEM;
 
+       ad1836->regmap = devm_regmap_init_spi(spi, &ad1836_regmap_config);
+       if (IS_ERR(ad1836->regmap))
+               return PTR_ERR(ad1836->regmap);
+
        ad1836->type = spi_get_device_id(spi)->driver_data;
 
        spi_set_drvdata(spi, ad1836);
@@ -379,17 +409,7 @@ static struct spi_driver ad1836_spi_driver = {
        .id_table       = ad1836_ids,
 };
 
-static int __init ad1836_init(void)
-{
-       return spi_register_driver(&ad1836_spi_driver);
-}
-module_init(ad1836_init);
-
-static void __exit ad1836_exit(void)
-{
-       spi_unregister_driver(&ad1836_spi_driver);
-}
-module_exit(ad1836_exit);
+module_spi_driver(ad1836_spi_driver);
 
 MODULE_DESCRIPTION("ASoC ad1836 driver");
 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");