diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-09-22 18:33:23 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-09-22 18:38:06 -0400 |
commit | a89be93c28cd656d1c3c49fe627666b3bbecd45a (patch) | |
tree | 6fab96dafd3fc11d07616e59ebb3c643341a9c88 | |
parent | 8fed54aec8fa5bc6ebfee95454a2cb33101ad917 (diff) |
ASoC: wm2000: Add regulator support
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/wm2000.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 6675477a63cb..b723e910fcdc 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/i2c.h> | 31 | #include <linux/i2c.h> |
32 | #include <linux/regmap.h> | 32 | #include <linux/regmap.h> |
33 | #include <linux/debugfs.h> | 33 | #include <linux/debugfs.h> |
34 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
35 | #include <sound/core.h> | 36 | #include <sound/core.h> |
36 | #include <sound/pcm.h> | 37 | #include <sound/pcm.h> |
@@ -43,6 +44,14 @@ | |||
43 | 44 | ||
44 | #include "wm2000.h" | 45 | #include "wm2000.h" |
45 | 46 | ||
47 | #define WM2000_NUM_SUPPLIES 3 | ||
48 | |||
49 | static const char *wm2000_supplies[WM2000_NUM_SUPPLIES] = { | ||
50 | "SPKVDD", | ||
51 | "DBVDD", | ||
52 | "DCVDD", | ||
53 | }; | ||
54 | |||
46 | enum wm2000_anc_mode { | 55 | enum wm2000_anc_mode { |
47 | ANC_ACTIVE = 0, | 56 | ANC_ACTIVE = 0, |
48 | ANC_BYPASS = 1, | 57 | ANC_BYPASS = 1, |
@@ -54,6 +63,8 @@ struct wm2000_priv { | |||
54 | struct i2c_client *i2c; | 63 | struct i2c_client *i2c; |
55 | struct regmap *regmap; | 64 | struct regmap *regmap; |
56 | 65 | ||
66 | struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES]; | ||
67 | |||
57 | enum wm2000_anc_mode anc_mode; | 68 | enum wm2000_anc_mode anc_mode; |
58 | 69 | ||
59 | unsigned int anc_active:1; | 70 | unsigned int anc_active:1; |
@@ -126,6 +137,12 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) | |||
126 | 137 | ||
127 | dev_dbg(&i2c->dev, "Beginning power up\n"); | 138 | dev_dbg(&i2c->dev, "Beginning power up\n"); |
128 | 139 | ||
140 | ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
141 | if (ret != 0) { | ||
142 | dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
129 | if (!wm2000->mclk_div) { | 146 | if (!wm2000->mclk_div) { |
130 | dev_dbg(&i2c->dev, "Disabling MCLK divider\n"); | 147 | dev_dbg(&i2c->dev, "Disabling MCLK divider\n"); |
131 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, | 148 | wm2000_write(i2c, WM2000_REG_SYS_CTL2, |
@@ -143,12 +160,14 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) | |||
143 | if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, | 160 | if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, |
144 | WM2000_ANC_ENG_IDLE)) { | 161 | WM2000_ANC_ENG_IDLE)) { |
145 | dev_err(&i2c->dev, "ANC engine failed to reset\n"); | 162 | dev_err(&i2c->dev, "ANC engine failed to reset\n"); |
163 | regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
146 | return -ETIMEDOUT; | 164 | return -ETIMEDOUT; |
147 | } | 165 | } |
148 | 166 | ||
149 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | 167 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, |
150 | WM2000_STATUS_BOOT_COMPLETE)) { | 168 | WM2000_STATUS_BOOT_COMPLETE)) { |
151 | dev_err(&i2c->dev, "ANC engine failed to initialise\n"); | 169 | dev_err(&i2c->dev, "ANC engine failed to initialise\n"); |
170 | regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
152 | return -ETIMEDOUT; | 171 | return -ETIMEDOUT; |
153 | } | 172 | } |
154 | 173 | ||
@@ -163,11 +182,13 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) | |||
163 | wm2000->anc_download_size); | 182 | wm2000->anc_download_size); |
164 | if (ret < 0) { | 183 | if (ret < 0) { |
165 | dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret); | 184 | dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret); |
185 | regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
166 | return ret; | 186 | return ret; |
167 | } | 187 | } |
168 | if (ret != wm2000->anc_download_size) { | 188 | if (ret != wm2000->anc_download_size) { |
169 | dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n", | 189 | dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n", |
170 | ret, wm2000->anc_download_size); | 190 | ret, wm2000->anc_download_size); |
191 | regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
171 | return -EIO; | 192 | return -EIO; |
172 | } | 193 | } |
173 | 194 | ||
@@ -201,6 +222,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) | |||
201 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, | 222 | if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS, |
202 | WM2000_STATUS_MOUSE_ACTIVE)) { | 223 | WM2000_STATUS_MOUSE_ACTIVE)) { |
203 | dev_err(&i2c->dev, "Timed out waiting for device\n"); | 224 | dev_err(&i2c->dev, "Timed out waiting for device\n"); |
225 | regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
204 | return -ETIMEDOUT; | 226 | return -ETIMEDOUT; |
205 | } | 227 | } |
206 | 228 | ||
@@ -238,6 +260,8 @@ static int wm2000_power_down(struct i2c_client *i2c, int analogue) | |||
238 | return -ETIMEDOUT; | 260 | return -ETIMEDOUT; |
239 | } | 261 | } |
240 | 262 | ||
263 | regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
264 | |||
241 | dev_dbg(&i2c->dev, "powered off\n"); | 265 | dev_dbg(&i2c->dev, "powered off\n"); |
242 | wm2000->anc_mode = ANC_OFF; | 266 | wm2000->anc_mode = ANC_OFF; |
243 | 267 | ||
@@ -747,7 +771,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | |||
747 | struct wm2000_platform_data *pdata; | 771 | struct wm2000_platform_data *pdata; |
748 | const char *filename; | 772 | const char *filename; |
749 | const struct firmware *fw = NULL; | 773 | const struct firmware *fw = NULL; |
750 | int ret; | 774 | int ret, i; |
751 | int reg; | 775 | int reg; |
752 | u16 id; | 776 | u16 id; |
753 | 777 | ||
@@ -768,6 +792,22 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | |||
768 | goto out; | 792 | goto out; |
769 | } | 793 | } |
770 | 794 | ||
795 | for (i = 0; i < WM2000_NUM_SUPPLIES; i++) | ||
796 | wm2000->supplies[i].supply = wm2000_supplies[i]; | ||
797 | |||
798 | ret = devm_regulator_bulk_get(&i2c->dev, WM2000_NUM_SUPPLIES, | ||
799 | wm2000->supplies); | ||
800 | if (ret != 0) { | ||
801 | dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret); | ||
802 | return ret; | ||
803 | } | ||
804 | |||
805 | ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
806 | if (ret != 0) { | ||
807 | dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); | ||
808 | return ret; | ||
809 | } | ||
810 | |||
771 | /* Verify that this is a WM2000 */ | 811 | /* Verify that this is a WM2000 */ |
772 | reg = wm2000_read(i2c, WM2000_REG_ID1); | 812 | reg = wm2000_read(i2c, WM2000_REG_ID1); |
773 | id = reg << 8; | 813 | id = reg << 8; |
@@ -777,7 +817,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | |||
777 | if (id != 0x2000) { | 817 | if (id != 0x2000) { |
778 | dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id); | 818 | dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id); |
779 | ret = -ENODEV; | 819 | ret = -ENODEV; |
780 | goto out; | 820 | goto err_supplies; |
781 | } | 821 | } |
782 | 822 | ||
783 | reg = wm2000_read(i2c, WM2000_REG_REVISON); | 823 | reg = wm2000_read(i2c, WM2000_REG_REVISON); |
@@ -796,7 +836,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | |||
796 | ret = request_firmware(&fw, filename, &i2c->dev); | 836 | ret = request_firmware(&fw, filename, &i2c->dev); |
797 | if (ret != 0) { | 837 | if (ret != 0) { |
798 | dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret); | 838 | dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret); |
799 | goto out; | 839 | goto err_supplies; |
800 | } | 840 | } |
801 | 841 | ||
802 | /* Pre-cook the concatenation of the register address onto the image */ | 842 | /* 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, | |||
807 | if (wm2000->anc_download == NULL) { | 847 | if (wm2000->anc_download == NULL) { |
808 | dev_err(&i2c->dev, "Out of memory\n"); | 848 | dev_err(&i2c->dev, "Out of memory\n"); |
809 | ret = -ENOMEM; | 849 | ret = -ENOMEM; |
810 | goto out; | 850 | goto err_supplies; |
811 | } | 851 | } |
812 | 852 | ||
813 | wm2000->anc_download[0] = 0x80; | 853 | wm2000->anc_download[0] = 0x80; |
@@ -822,8 +862,9 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | |||
822 | wm2000_reset(wm2000); | 862 | wm2000_reset(wm2000); |
823 | 863 | ||
824 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0); | 864 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0); |
825 | if (!ret) | 865 | |
826 | goto out; | 866 | err_supplies: |
867 | regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); | ||
827 | 868 | ||
828 | out: | 869 | out: |
829 | release_firmware(fw); | 870 | release_firmware(fw); |