Merge tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[pandora-kernel.git] / sound / soc / codecs / wm2000.c
index a3acb7a..683dc43 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/debugfs.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 
 #include "wm2000.h"
 
+#define WM2000_NUM_SUPPLIES 3
+
+static const char *wm2000_supplies[WM2000_NUM_SUPPLIES] = {
+       "SPKVDD",
+       "DBVDD",
+       "DCVDD",
+};
+
 enum wm2000_anc_mode {
        ANC_ACTIVE = 0,
        ANC_BYPASS = 1,
@@ -54,6 +63,8 @@ struct wm2000_priv {
        struct i2c_client *i2c;
        struct regmap *regmap;
 
+       struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES];
+
        enum wm2000_anc_mode anc_mode;
 
        unsigned int anc_active:1;
@@ -126,6 +137,12 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
 
        dev_dbg(&i2c->dev, "Beginning power up\n");
 
+       ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
        if (!wm2000->mclk_div) {
                dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
                wm2000_write(i2c, WM2000_REG_SYS_CTL2,
@@ -143,12 +160,14 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
        if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
                             WM2000_ANC_ENG_IDLE)) {
                dev_err(&i2c->dev, "ANC engine failed to reset\n");
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return -ETIMEDOUT;
        }
 
        if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
                             WM2000_STATUS_BOOT_COMPLETE)) {
                dev_err(&i2c->dev, "ANC engine failed to initialise\n");
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return -ETIMEDOUT;
        }
 
@@ -163,11 +182,13 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
                              wm2000->anc_download_size);
        if (ret < 0) {
                dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret);
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return ret;
        }
        if (ret != wm2000->anc_download_size) {
                dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n",
                        ret, wm2000->anc_download_size);
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return -EIO;
        }
 
@@ -201,6 +222,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
        if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
                             WM2000_STATUS_MOUSE_ACTIVE)) {
                dev_err(&i2c->dev, "Timed out waiting for device\n");
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return -ETIMEDOUT;
        }
 
@@ -238,6 +260,8 @@ static int wm2000_power_down(struct i2c_client *i2c, int analogue)
                return -ETIMEDOUT;
        }
 
+       regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+
        dev_dbg(&i2c->dev, "powered off\n");
        wm2000->anc_mode = ANC_OFF;
 
@@ -747,7 +771,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        struct wm2000_platform_data *pdata;
        const char *filename;
        const struct firmware *fw = NULL;
-       int ret;
+       int ret, i;
        int reg;
        u16 id;
 
@@ -760,7 +784,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 
        dev_set_drvdata(&i2c->dev, wm2000);
 
-       wm2000->regmap = regmap_init_i2c(i2c, &wm2000_regmap);
+       wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);
        if (IS_ERR(wm2000->regmap)) {
                ret = PTR_ERR(wm2000->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -768,6 +792,22 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
                goto out;
        }
 
+       for (i = 0; i < WM2000_NUM_SUPPLIES; i++)
+               wm2000->supplies[i].supply = wm2000_supplies[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, WM2000_NUM_SUPPLIES,
+                                     wm2000->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
        /* Verify that this is a WM2000 */
        reg = wm2000_read(i2c, WM2000_REG_ID1);
        id = reg << 8;
@@ -777,7 +817,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        if (id != 0x2000) {
                dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
                ret = -ENODEV;
-               goto out_regmap_exit;
+               goto err_supplies;
        }
 
        reg = wm2000_read(i2c, WM2000_REG_REVISON);
@@ -796,7 +836,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        ret = request_firmware(&fw, filename, &i2c->dev);
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
-               goto out_regmap_exit;
+               goto err_supplies;
        }
 
        /* Pre-cook the concatenation of the register address onto the image */
@@ -807,7 +847,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        if (wm2000->anc_download == NULL) {
                dev_err(&i2c->dev, "Out of memory\n");
                ret = -ENOMEM;
-               goto out_regmap_exit;
+               goto err_supplies;
        }
 
        wm2000->anc_download[0] = 0x80;
@@ -822,11 +862,10 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        wm2000_reset(wm2000);
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0);
-       if (!ret)
-               goto out;
 
-out_regmap_exit:
-       regmap_exit(wm2000->regmap);
+err_supplies:
+       regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+
 out:
        release_firmware(fw);
        return ret;
@@ -834,10 +873,7 @@ out:
 
 static __devexit int wm2000_i2c_remove(struct i2c_client *i2c)
 {
-       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
-
        snd_soc_unregister_codec(&i2c->dev);
-       regmap_exit(wm2000->regmap);
 
        return 0;
 }
@@ -858,17 +894,7 @@ static struct i2c_driver wm2000_i2c_driver = {
        .id_table = wm2000_i2c_id,
 };
 
-static int __init wm2000_init(void)
-{
-       return i2c_add_driver(&wm2000_i2c_driver);
-}
-module_init(wm2000_init);
-
-static void __exit wm2000_exit(void)
-{
-       i2c_del_driver(&wm2000_i2c_driver);
-}
-module_exit(wm2000_exit);
+module_i2c_driver(wm2000_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM2000 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");