diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-08 18:07:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-08 18:07:14 -0400 |
commit | f5a246eab9a268f51ba8189ea5b098a1bfff200e (patch) | |
tree | a6ff7169e0bcaca498d9aec8b0624de1b74eaecb /sound/soc/codecs/wm2000.c | |
parent | d5bbd43d5f450c3fca058f5b85f3dfb4e8cc88c9 (diff) | |
parent | 7ff34ad80b7080fafaac8efa9ef0061708eddd51 (diff) |
Merge tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"This contains pretty many small commits covering fairly large range of
files in sound/ directory. Partly because of additional API support
and partly because of constantly developed ASoC and ARM stuff.
Some highlights:
- Introduced the helper function and documentation for exposing the
channel map via control API, as discussed in Plumbers; most of PCI
drivers are covered, will follow more drivers later
- Most of drivers have been replaced with the new PM callbacks (if
the bus is supported)
- HD-audio controller got the support of runtime PM and the support
of D3 clock-stop. Also changing the power_save option in sysfs
kicks off immediately to enable / disable the power-save mode.
- Another significant code change in HD-audio is the rewrite of
firmware loading code. Other than that, most of changes in
HD-audio are continued cleanups and standardization for the generic
auto parser and bug fixes (HBR, device-specific fixups), in
addition to the support of channel-map API.
- Addition of ASoC bindings for the compressed API, used by the
mid-x86 drivers.
- Lots of cleanups and API refreshes for ASoC codec drivers and
DaVinci.
- Conversion of OMAP to dmaengine.
- New machine driver for Wolfson Microelectronics Bells.
- New CODEC driver for Wolfson Microelectronics WM0010.
- Enhancements to the ux500 and wm2000 drivers
- A new driver for DA9055 and the support for regulator bypass mode."
Fix up various arm soc header file reorg conflicts.
* tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (339 commits)
ALSA: hda - Add new codec ALC283 ALC290 support
ALSA: hda - avoid unneccesary indices on "Headphone Jack" controls
ALSA: hda - fix indices on boost volume on Conexant
ALSA: aloop - add locking to timer access
ALSA: hda - Fix hang caused by race during suspend.
sound: Remove unnecessary semicolon
ALSA: hda/realtek - Fix detection of ALC271X codec
ALSA: hda - Add inverted internal mic quirk for Lenovo IdeaPad U310
ALSA: hda - make Realtek/Sigmatel/Conexant use the generic unsol event
ALSA: hda - make a generic unsol event handler
ASoC: codecs: Add DA9055 codec driver
ASoC: eukrea-tlv320: Convert it to platform driver
ALSA: ASoC: add DT bindings for CS4271
ASoC: wm_hubs: Ensure volume updates are handled during class W startup
ASoC: wm5110: Adding missing volume update bits
ASoC: wm5110: Add OUT3R support
ASoC: wm5110: Add AEC loopback support
ASoC: wm5110: Rename EPOUT to HPOUT3
ASoC: arizona: Add more clock rates
ASoC: arizona: Add more DSP options for mixer input muxes
...
Diffstat (limited to 'sound/soc/codecs/wm2000.c')
-rw-r--r-- | sound/soc/codecs/wm2000.c | 72 |
1 files changed, 49 insertions, 23 deletions
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index a3acb7a85f6a..683dc43b1d87 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 | ||
@@ -760,7 +784,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | |||
760 | 784 | ||
761 | dev_set_drvdata(&i2c->dev, wm2000); | 785 | dev_set_drvdata(&i2c->dev, wm2000); |
762 | 786 | ||
763 | wm2000->regmap = regmap_init_i2c(i2c, &wm2000_regmap); | 787 | wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap); |
764 | if (IS_ERR(wm2000->regmap)) { | 788 | if (IS_ERR(wm2000->regmap)) { |
765 | ret = PTR_ERR(wm2000->regmap); | 789 | ret = PTR_ERR(wm2000->regmap); |
766 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | 790 | 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, | |||
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_regmap_exit; | 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_regmap_exit; | 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_regmap_exit; | 850 | goto err_supplies; |
811 | } | 851 | } |
812 | 852 | ||
813 | wm2000->anc_download[0] = 0x80; | 853 | wm2000->anc_download[0] = 0x80; |
@@ -822,11 +862,10 @@ 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) | ||
826 | goto out; | ||
827 | 865 | ||
828 | out_regmap_exit: | 866 | err_supplies: |
829 | regmap_exit(wm2000->regmap); | 867 | regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); |
868 | |||
830 | out: | 869 | out: |
831 | release_firmware(fw); | 870 | release_firmware(fw); |
832 | return ret; | 871 | return ret; |
@@ -834,10 +873,7 @@ out: | |||
834 | 873 | ||
835 | static __devexit int wm2000_i2c_remove(struct i2c_client *i2c) | 874 | static __devexit int wm2000_i2c_remove(struct i2c_client *i2c) |
836 | { | 875 | { |
837 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | ||
838 | |||
839 | snd_soc_unregister_codec(&i2c->dev); | 876 | snd_soc_unregister_codec(&i2c->dev); |
840 | regmap_exit(wm2000->regmap); | ||
841 | 877 | ||
842 | return 0; | 878 | return 0; |
843 | } | 879 | } |
@@ -858,17 +894,7 @@ static struct i2c_driver wm2000_i2c_driver = { | |||
858 | .id_table = wm2000_i2c_id, | 894 | .id_table = wm2000_i2c_id, |
859 | }; | 895 | }; |
860 | 896 | ||
861 | static int __init wm2000_init(void) | 897 | module_i2c_driver(wm2000_i2c_driver); |
862 | { | ||
863 | return i2c_add_driver(&wm2000_i2c_driver); | ||
864 | } | ||
865 | module_init(wm2000_init); | ||
866 | |||
867 | static void __exit wm2000_exit(void) | ||
868 | { | ||
869 | i2c_del_driver(&wm2000_i2c_driver); | ||
870 | } | ||
871 | module_exit(wm2000_exit); | ||
872 | 898 | ||
873 | MODULE_DESCRIPTION("ASoC WM2000 driver"); | 899 | MODULE_DESCRIPTION("ASoC WM2000 driver"); |
874 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); | 900 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); |