ASoC: Use SNDRV_PCM_RATE_8000_96000 macro for WM8731
[safe/jmp/linux-2.6] / sound / soc / codecs / wm8731.c
index 6232afd..d5e1c5b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>
 
 #include "wm8731.h"
 
 static struct snd_soc_codec *wm8731_codec;
 struct snd_soc_codec_device soc_codec_dev_wm8731;
 
+#define WM8731_NUM_SUPPLIES 4
+static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
+       "AVDD",
+       "HPVDD",
+       "DCVDD",
+       "DBVDD",
+};
+
 /* codec private data */
 struct wm8731_priv {
        struct snd_soc_codec codec;
+       struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
        u16 reg_cache[WM8731_CACHEREGNUM];
        unsigned int sysclk;
 };
 
-#ifdef CONFIG_SPI_MASTER
-static int wm8731_spi_write(struct spi_device *spi, const char *data, int len);
-#endif
 
 /*
  * wm8731 register cache
@@ -65,20 +73,26 @@ static const struct soc_enum wm8731_enum[] = {
        SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
 };
 
+static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+
 static const struct snd_kcontrol_new wm8731_snd_controls[] = {
 
-SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
-       0, 127, 0),
+SOC_DOUBLE_R_TLV("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
+                0, 127, 0, out_tlv),
 SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
        7, 1, 0),
 
-SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0,
+                in_tlv),
 SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
 
 SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
-SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1),
+SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1),
 
-SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1),
+SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
+              sidetone_tlv),
 
 SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
 SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
@@ -145,7 +159,6 @@ static int wm8731_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
-       snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
@@ -376,11 +389,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-#define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
-               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
-               SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
-               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
-               SNDRV_PCM_RATE_96000)
+#define WM8731_RATES SNDRV_PCM_RATE_8000_96000
 
 #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
@@ -409,6 +418,7 @@ struct snd_soc_dai wm8731_dai = {
                .rates = WM8731_RATES,
                .formats = WM8731_FORMATS,},
        .ops = &wm8731_dai_ops,
+       .symmetric_rates = 1,
 };
 EXPORT_SYMBOL_GPL(wm8731_dai);
 
@@ -417,9 +427,12 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8731_priv *wm8731 = codec->private_data;
 
        snd_soc_write(codec, WM8731_ACTIVE, 0x0);
        wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
+                              wm8731->supplies);
        return 0;
 }
 
@@ -427,18 +440,28 @@ static int wm8731_resume(struct platform_device *pdev)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->card->codec;
-       int i;
+       struct wm8731_priv *wm8731 = codec->private_data;
+       int i, ret;
        u8 data[2];
        u16 *cache = codec->reg_cache;
 
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
+                                   wm8731->supplies);
+       if (ret != 0)
+               return ret;
+
        /* Sync reg_cache with the hardware */
        for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
+               if (cache[i] == wm8731_reg[i])
+                       continue;
+
                data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
                data[1] = cache[i] & 0x00ff;
                codec->hw_write(codec->control_data, data, 2);
        }
        wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        wm8731_set_bias_level(codec, codec->suspend_bias_level);
+
        return 0;
 }
 #else
@@ -470,17 +493,9 @@ static int wm8731_probe(struct platform_device *pdev)
        snd_soc_add_controls(codec, wm8731_snd_controls,
                             ARRAY_SIZE(wm8731_snd_controls));
        wm8731_add_widgets(codec);
-       ret = snd_soc_init_card(socdev);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to register card: %d\n", ret);
-               goto card_err;
-       }
 
        return ret;
 
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 pcm_err:
        return ret;
 }
@@ -507,7 +522,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
 static int wm8731_register(struct wm8731_priv *wm8731,
                           enum snd_soc_control_type control)
 {
-       int ret;
+       int ret, i;
        struct snd_soc_codec *codec = &wm8731->codec;
 
        if (wm8731_codec) {
@@ -538,10 +553,27 @@ static int wm8731_register(struct wm8731_priv *wm8731,
                goto err;
        }
 
+       for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
+               wm8731->supplies[i].supply = wm8731_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
+                                wm8731->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
+                                   wm8731->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_regulator_get;
+       }
+
        ret = wm8731_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
-               goto err;
+               goto err_regulator_enable;
        }
 
        wm8731_dai.dev = codec->dev;
@@ -562,7 +594,7 @@ static int wm8731_register(struct wm8731_priv *wm8731,
        ret = snd_soc_register_codec(codec);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
+               goto err_regulator_enable;
        }
 
        ret = snd_soc_register_dai(&wm8731_dai);
@@ -576,6 +608,10 @@ static int wm8731_register(struct wm8731_priv *wm8731,
 
 err_codec:
        snd_soc_unregister_codec(codec);
+err_regulator_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
+err_regulator_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 err:
        kfree(wm8731);
        return ret;
@@ -586,6 +622,8 @@ static void wm8731_unregister(struct wm8731_priv *wm8731)
        wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
        snd_soc_unregister_dai(&wm8731_dai);
        snd_soc_unregister_codec(&wm8731->codec);
+       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
+       regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
        kfree(wm8731);
        wm8731_codec = NULL;
 }
@@ -618,21 +656,6 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8731_spi_resume(struct spi_device *spi)
-{
-       return snd_soc_resume_device(&spi->dev);
-}
-#else
-#define wm8731_spi_suspend NULL
-#define wm8731_spi_resume NULL
-#endif
-
 static struct spi_driver wm8731_spi_driver = {
        .driver = {
                .name   = "wm8731",
@@ -640,8 +663,6 @@ static struct spi_driver wm8731_spi_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = wm8731_spi_probe,
-       .suspend        = wm8731_spi_suspend,
-       .resume         = wm8731_spi_resume,
        .remove         = __devexit_p(wm8731_spi_remove),
 };
 #endif /* CONFIG_SPI_MASTER */
@@ -674,21 +695,6 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
-{
-       return snd_soc_suspend_device(&i2c->dev);
-}
-
-static int wm8731_i2c_resume(struct i2c_client *i2c)
-{
-       return snd_soc_resume_device(&i2c->dev);
-}
-#else
-#define wm8731_i2c_suspend NULL
-#define wm8731_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8731_i2c_id[] = {
        { "wm8731", 0 },
        { }
@@ -702,8 +708,6 @@ static struct i2c_driver wm8731_i2c_driver = {
        },
        .probe =    wm8731_i2c_probe,
        .remove =   __devexit_p(wm8731_i2c_remove),
-       .suspend =  wm8731_i2c_suspend,
-       .resume =   wm8731_i2c_resume,
        .id_table = wm8731_i2c_id,
 };
 #endif