diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-06-25 09:28:39 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-06-25 09:28:39 -0400 |
commit | 62b1653e29d8f359c4c7e045b965dc963459473d (patch) | |
tree | 4f0d3f541c9eead5785f4e0230c46375a819ab60 | |
parent | 10121a12e2380fb34b6e646a8e367add06d036c3 (diff) | |
parent | d5fc3b5fe374f24b6773c22e90ef4bdda718b845 (diff) |
Merge branch 'for-2.6.32' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc
31 files changed, 3445 insertions, 352 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index ec8a45f9a069..35814ced2d22 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -279,6 +279,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | |||
279 | /* dapm events */ | 279 | /* dapm events */ |
280 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, | 280 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, |
281 | int event); | 281 | int event); |
282 | void snd_soc_dapm_shutdown(struct snd_soc_device *socdev); | ||
282 | 283 | ||
283 | /* dapm sys fs - used by the core */ | 284 | /* dapm sys fs - used by the core */ |
284 | int snd_soc_dapm_sys_add(struct device *dev); | 285 | int snd_soc_dapm_sys_add(struct device *dev); |
diff --git a/include/sound/soc.h b/include/sound/soc.h index cf6111d72b17..e6704c0a4404 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -192,6 +192,11 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform); | |||
192 | int snd_soc_register_codec(struct snd_soc_codec *codec); | 192 | int snd_soc_register_codec(struct snd_soc_codec *codec); |
193 | void snd_soc_unregister_codec(struct snd_soc_codec *codec); | 193 | void snd_soc_unregister_codec(struct snd_soc_codec *codec); |
194 | 194 | ||
195 | #ifdef CONFIG_PM | ||
196 | int snd_soc_suspend_device(struct device *dev); | ||
197 | int snd_soc_resume_device(struct device *dev); | ||
198 | #endif | ||
199 | |||
195 | /* pcm <-> DAI connect */ | 200 | /* pcm <-> DAI connect */ |
196 | void snd_soc_free_pcms(struct snd_soc_device *socdev); | 201 | void snd_soc_free_pcms(struct snd_soc_device *socdev); |
197 | int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); | 202 | int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); |
@@ -216,9 +221,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, | |||
216 | 221 | ||
217 | /* codec register bit access */ | 222 | /* codec register bit access */ |
218 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | 223 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, |
219 | unsigned short mask, unsigned short value); | 224 | unsigned int mask, unsigned int value); |
220 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | 225 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, |
221 | unsigned short mask, unsigned short value); | 226 | unsigned int mask, unsigned int value); |
222 | 227 | ||
223 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | 228 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, |
224 | struct snd_ac97_bus_ops *ops, int num); | 229 | struct snd_ac97_bus_ops *ops, int num); |
@@ -369,8 +374,6 @@ struct snd_soc_codec { | |||
369 | enum snd_soc_bias_level bias_level; | 374 | enum snd_soc_bias_level bias_level; |
370 | enum snd_soc_bias_level suspend_bias_level; | 375 | enum snd_soc_bias_level suspend_bias_level; |
371 | struct delayed_work delayed_work; | 376 | struct delayed_work delayed_work; |
372 | struct list_head up_list; | ||
373 | struct list_head down_list; | ||
374 | 377 | ||
375 | /* codec DAI's */ | 378 | /* codec DAI's */ |
376 | struct snd_soc_dai *dai; | 379 | struct snd_soc_dai *dai; |
diff --git a/include/sound/uda1380.h b/include/sound/uda1380.h new file mode 100644 index 000000000000..381319c7000c --- /dev/null +++ b/include/sound/uda1380.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * UDA1380 ALSA SoC Codec driver | ||
3 | * | ||
4 | * Copyright 2009 Philipp Zabel | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __UDA1380_H | ||
12 | #define __UDA1380_H | ||
13 | |||
14 | struct uda1380_platform_data { | ||
15 | int gpio_power; | ||
16 | int gpio_reset; | ||
17 | int dac_clk; | ||
18 | #define UDA1380_DAC_CLK_SYSCLK 0 | ||
19 | #define UDA1380_DAC_CLK_WSPLL 1 | ||
20 | }; | ||
21 | |||
22 | #endif /* __UDA1380_H */ | ||
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index edfbdc024e66..9825b71d0e28 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c | |||
@@ -203,23 +203,23 @@ static struct snd_soc_device bf5xx_ad73311_snd_devdata = { | |||
203 | .codec_dev = &soc_codec_dev_ad73311, | 203 | .codec_dev = &soc_codec_dev_ad73311, |
204 | }; | 204 | }; |
205 | 205 | ||
206 | static struct platform_device *bf52x_ad73311_snd_device; | 206 | static struct platform_device *bf5xx_ad73311_snd_device; |
207 | 207 | ||
208 | static int __init bf5xx_ad73311_init(void) | 208 | static int __init bf5xx_ad73311_init(void) |
209 | { | 209 | { |
210 | int ret; | 210 | int ret; |
211 | 211 | ||
212 | pr_debug("%s enter\n", __func__); | 212 | pr_debug("%s enter\n", __func__); |
213 | bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1); | 213 | bf5xx_ad73311_snd_device = platform_device_alloc("soc-audio", -1); |
214 | if (!bf52x_ad73311_snd_device) | 214 | if (!bf5xx_ad73311_snd_device) |
215 | return -ENOMEM; | 215 | return -ENOMEM; |
216 | 216 | ||
217 | platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata); | 217 | platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata); |
218 | bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev; | 218 | bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev; |
219 | ret = platform_device_add(bf52x_ad73311_snd_device); | 219 | ret = platform_device_add(bf5xx_ad73311_snd_device); |
220 | 220 | ||
221 | if (ret) | 221 | if (ret) |
222 | platform_device_put(bf52x_ad73311_snd_device); | 222 | platform_device_put(bf5xx_ad73311_snd_device); |
223 | 223 | ||
224 | return ret; | 224 | return ret; |
225 | } | 225 | } |
@@ -227,7 +227,7 @@ static int __init bf5xx_ad73311_init(void) | |||
227 | static void __exit bf5xx_ad73311_exit(void) | 227 | static void __exit bf5xx_ad73311_exit(void) |
228 | { | 228 | { |
229 | pr_debug("%s enter\n", __func__); | 229 | pr_debug("%s enter\n", __func__); |
230 | platform_device_unregister(bf52x_ad73311_snd_device); | 230 | platform_device_unregister(bf5xx_ad73311_snd_device); |
231 | } | 231 | } |
232 | 232 | ||
233 | module_init(bf5xx_ad73311_init); | 233 | module_init(bf5xx_ad73311_init); |
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index bc0cdded7116..3a00fa4dbe6d 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c | |||
@@ -148,24 +148,24 @@ static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { | |||
148 | .codec_data = &bf5xx_ssm2602_setup, | 148 | .codec_data = &bf5xx_ssm2602_setup, |
149 | }; | 149 | }; |
150 | 150 | ||
151 | static struct platform_device *bf52x_ssm2602_snd_device; | 151 | static struct platform_device *bf5xx_ssm2602_snd_device; |
152 | 152 | ||
153 | static int __init bf5xx_ssm2602_init(void) | 153 | static int __init bf5xx_ssm2602_init(void) |
154 | { | 154 | { |
155 | int ret; | 155 | int ret; |
156 | 156 | ||
157 | pr_debug("%s enter\n", __func__); | 157 | pr_debug("%s enter\n", __func__); |
158 | bf52x_ssm2602_snd_device = platform_device_alloc("soc-audio", -1); | 158 | bf5xx_ssm2602_snd_device = platform_device_alloc("soc-audio", -1); |
159 | if (!bf52x_ssm2602_snd_device) | 159 | if (!bf5xx_ssm2602_snd_device) |
160 | return -ENOMEM; | 160 | return -ENOMEM; |
161 | 161 | ||
162 | platform_set_drvdata(bf52x_ssm2602_snd_device, | 162 | platform_set_drvdata(bf5xx_ssm2602_snd_device, |
163 | &bf5xx_ssm2602_snd_devdata); | 163 | &bf5xx_ssm2602_snd_devdata); |
164 | bf5xx_ssm2602_snd_devdata.dev = &bf52x_ssm2602_snd_device->dev; | 164 | bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev; |
165 | ret = platform_device_add(bf52x_ssm2602_snd_device); | 165 | ret = platform_device_add(bf5xx_ssm2602_snd_device); |
166 | 166 | ||
167 | if (ret) | 167 | if (ret) |
168 | platform_device_put(bf52x_ssm2602_snd_device); | 168 | platform_device_put(bf5xx_ssm2602_snd_device); |
169 | 169 | ||
170 | return ret; | 170 | return ret; |
171 | } | 171 | } |
@@ -173,7 +173,7 @@ static int __init bf5xx_ssm2602_init(void) | |||
173 | static void __exit bf5xx_ssm2602_exit(void) | 173 | static void __exit bf5xx_ssm2602_exit(void) |
174 | { | 174 | { |
175 | pr_debug("%s enter\n", __func__); | 175 | pr_debug("%s enter\n", __func__); |
176 | platform_device_unregister(bf52x_ssm2602_snd_device); | 176 | platform_device_unregister(bf5xx_ssm2602_snd_device); |
177 | } | 177 | } |
178 | 178 | ||
179 | module_init(bf5xx_ssm2602_init); | 179 | module_init(bf5xx_ssm2602_init); |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bbc97fd76648..021dbdfa5b92 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -39,6 +39,7 @@ config SND_SOC_ALL_CODECS | |||
39 | select SND_SOC_WM8903 if I2C | 39 | select SND_SOC_WM8903 if I2C |
40 | select SND_SOC_WM8940 if I2C | 40 | select SND_SOC_WM8940 if I2C |
41 | select SND_SOC_WM8960 if I2C | 41 | select SND_SOC_WM8960 if I2C |
42 | select SND_SOC_WM8961 if I2C | ||
42 | select SND_SOC_WM8971 if I2C | 43 | select SND_SOC_WM8971 if I2C |
43 | select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI | 44 | select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI |
44 | select SND_SOC_WM8990 if I2C | 45 | select SND_SOC_WM8990 if I2C |
@@ -156,6 +157,9 @@ config SND_SOC_WM8940 | |||
156 | config SND_SOC_WM8960 | 157 | config SND_SOC_WM8960 |
157 | tristate | 158 | tristate |
158 | 159 | ||
160 | config SND_SOC_WM8961 | ||
161 | tristate | ||
162 | |||
159 | config SND_SOC_WM8971 | 163 | config SND_SOC_WM8971 |
160 | tristate | 164 | tristate |
161 | 165 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8b7530546f4d..e520c2b7f0e0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -27,6 +27,7 @@ snd-soc-wm8900-objs := wm8900.o | |||
27 | snd-soc-wm8903-objs := wm8903.o | 27 | snd-soc-wm8903-objs := wm8903.o |
28 | snd-soc-wm8940-objs := wm8940.o | 28 | snd-soc-wm8940-objs := wm8940.o |
29 | snd-soc-wm8960-objs := wm8960.o | 29 | snd-soc-wm8960-objs := wm8960.o |
30 | snd-soc-wm8961-objs := wm8961.o | ||
30 | snd-soc-wm8971-objs := wm8971.o | 31 | snd-soc-wm8971-objs := wm8971.o |
31 | snd-soc-wm8988-objs := wm8988.o | 32 | snd-soc-wm8988-objs := wm8988.o |
32 | snd-soc-wm8990-objs := wm8990.o | 33 | snd-soc-wm8990-objs := wm8990.o |
@@ -65,6 +66,7 @@ obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | |||
65 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o | 66 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o |
66 | obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o | 67 | obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o |
67 | obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o | 68 | obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o |
69 | obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o | ||
68 | obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o | 70 | obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o |
69 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | 71 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o |
70 | obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o | 72 | obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4dbb853eef5a..df42fa2abd91 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -712,7 +712,19 @@ static int bypass_event(struct snd_soc_dapm_widget *w, | |||
712 | 712 | ||
713 | reg = twl4030_read_reg_cache(w->codec, m->reg); | 713 | reg = twl4030_read_reg_cache(w->codec, m->reg); |
714 | 714 | ||
715 | if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) { | 715 | /* |
716 | * bypass_state[0:3] - analog HiFi bypass | ||
717 | * bypass_state[4] - analog voice bypass | ||
718 | * bypass_state[5] - digital voice bypass | ||
719 | * bypass_state[6:7] - digital HiFi bypass | ||
720 | */ | ||
721 | if (m->reg == TWL4030_REG_VSTPGA) { | ||
722 | /* Voice digital bypass */ | ||
723 | if (reg) | ||
724 | twl4030->bypass_state |= (1 << 5); | ||
725 | else | ||
726 | twl4030->bypass_state &= ~(1 << 5); | ||
727 | } else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) { | ||
716 | /* Analog bypass */ | 728 | /* Analog bypass */ |
717 | if (reg & (1 << m->shift)) | 729 | if (reg & (1 << m->shift)) |
718 | twl4030->bypass_state |= | 730 | twl4030->bypass_state |= |
@@ -726,12 +738,6 @@ static int bypass_event(struct snd_soc_dapm_widget *w, | |||
726 | twl4030->bypass_state |= (1 << 4); | 738 | twl4030->bypass_state |= (1 << 4); |
727 | else | 739 | else |
728 | twl4030->bypass_state &= ~(1 << 4); | 740 | twl4030->bypass_state &= ~(1 << 4); |
729 | } else if (m->reg == TWL4030_REG_VSTPGA) { | ||
730 | /* Voice digital bypass */ | ||
731 | if (reg) | ||
732 | twl4030->bypass_state |= (1 << 5); | ||
733 | else | ||
734 | twl4030->bypass_state &= ~(1 << 5); | ||
735 | } else { | 741 | } else { |
736 | /* Digital bypass */ | 742 | /* Digital bypass */ |
737 | if (reg & (0x7 << m->shift)) | 743 | if (reg & (0x7 << m->shift)) |
@@ -924,7 +930,7 @@ static const struct soc_enum twl4030_op_modes_enum = | |||
924 | ARRAY_SIZE(twl4030_op_modes_texts), | 930 | ARRAY_SIZE(twl4030_op_modes_texts), |
925 | twl4030_op_modes_texts); | 931 | twl4030_op_modes_texts); |
926 | 932 | ||
927 | int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, | 933 | static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, |
928 | struct snd_ctl_elem_value *ucontrol) | 934 | struct snd_ctl_elem_value *ucontrol) |
929 | { | 935 | { |
930 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 936 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
@@ -1005,6 +1011,16 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); | |||
1005 | */ | 1011 | */ |
1006 | static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); | 1012 | static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); |
1007 | 1013 | ||
1014 | /* AVADC clock priority */ | ||
1015 | static const char *twl4030_avadc_clk_priority_texts[] = { | ||
1016 | "Voice high priority", "HiFi high priority" | ||
1017 | }; | ||
1018 | |||
1019 | static const struct soc_enum twl4030_avadc_clk_priority_enum = | ||
1020 | SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2, | ||
1021 | ARRAY_SIZE(twl4030_avadc_clk_priority_texts), | ||
1022 | twl4030_avadc_clk_priority_texts); | ||
1023 | |||
1008 | static const char *twl4030_rampdelay_texts[] = { | 1024 | static const char *twl4030_rampdelay_texts[] = { |
1009 | "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", | 1025 | "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", |
1010 | "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms", | 1026 | "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms", |
@@ -1106,6 +1122,8 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { | |||
1106 | SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, | 1122 | SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, |
1107 | 0, 3, 5, 0, input_gain_tlv), | 1123 | 0, 3, 5, 0, input_gain_tlv), |
1108 | 1124 | ||
1125 | SOC_ENUM("AVADC Clock Priority", twl4030_avadc_clk_priority_enum), | ||
1126 | |||
1109 | SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum), | 1127 | SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum), |
1110 | 1128 | ||
1111 | SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum), | 1129 | SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum), |
@@ -1609,8 +1627,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1609 | 1627 | ||
1610 | /* If the substream has 4 channel, do the necessary setup */ | 1628 | /* If the substream has 4 channel, do the necessary setup */ |
1611 | if (params_channels(params) == 4) { | 1629 | if (params_channels(params) == 4) { |
1612 | u8 format, mode; | ||
1613 | |||
1614 | format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); | 1630 | format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); |
1615 | mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); | 1631 | mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); |
1616 | 1632 | ||
@@ -1948,7 +1964,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1948 | 1964 | ||
1949 | /* set master/slave audio interface */ | 1965 | /* set master/slave audio interface */ |
1950 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1966 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
1951 | case SND_SOC_DAIFMT_CBS_CFM: | 1967 | case SND_SOC_DAIFMT_CBM_CFM: |
1952 | format &= ~(TWL4030_VIF_SLAVE_EN); | 1968 | format &= ~(TWL4030_VIF_SLAVE_EN); |
1953 | break; | 1969 | break; |
1954 | case SND_SOC_DAIFMT_CBS_CFS: | 1970 | case SND_SOC_DAIFMT_CBS_CFS: |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 5b21594e0e58..92ec03442154 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -5,9 +5,7 @@ | |||
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> | 8 | * Copyright (c) 2007-2009 Philipp Zabel <philipp.zabel@gmail.com> |
9 | * Improved support for DAPM and audio routing/mixing capabilities, | ||
10 | * added TLV support. | ||
11 | * | 9 | * |
12 | * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC | 10 | * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC |
13 | * codec model. | 11 | * codec model. |
@@ -19,26 +17,32 @@ | |||
19 | #include <linux/module.h> | 17 | #include <linux/module.h> |
20 | #include <linux/init.h> | 18 | #include <linux/init.h> |
21 | #include <linux/types.h> | 19 | #include <linux/types.h> |
22 | #include <linux/string.h> | ||
23 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
24 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
25 | #include <linux/ioctl.h> | 22 | #include <linux/gpio.h> |
26 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
27 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
28 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
29 | #include <sound/core.h> | 26 | #include <sound/core.h> |
30 | #include <sound/control.h> | 27 | #include <sound/control.h> |
31 | #include <sound/initval.h> | 28 | #include <sound/initval.h> |
32 | #include <sound/info.h> | ||
33 | #include <sound/soc.h> | 29 | #include <sound/soc.h> |
34 | #include <sound/soc-dapm.h> | 30 | #include <sound/soc-dapm.h> |
35 | #include <sound/tlv.h> | 31 | #include <sound/tlv.h> |
32 | #include <sound/uda1380.h> | ||
36 | 33 | ||
37 | #include "uda1380.h" | 34 | #include "uda1380.h" |
38 | 35 | ||
39 | static struct work_struct uda1380_work; | ||
40 | static struct snd_soc_codec *uda1380_codec; | 36 | static struct snd_soc_codec *uda1380_codec; |
41 | 37 | ||
38 | /* codec private data */ | ||
39 | struct uda1380_priv { | ||
40 | struct snd_soc_codec codec; | ||
41 | u16 reg_cache[UDA1380_CACHEREGNUM]; | ||
42 | unsigned int dac_clk; | ||
43 | struct work_struct work; | ||
44 | }; | ||
45 | |||
42 | /* | 46 | /* |
43 | * uda1380 register cache | 47 | * uda1380 register cache |
44 | */ | 48 | */ |
@@ -473,6 +477,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd, | |||
473 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 477 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
474 | struct snd_soc_device *socdev = rtd->socdev; | 478 | struct snd_soc_device *socdev = rtd->socdev; |
475 | struct snd_soc_codec *codec = socdev->card->codec; | 479 | struct snd_soc_codec *codec = socdev->card->codec; |
480 | struct uda1380_priv *uda1380 = codec->private_data; | ||
476 | int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER); | 481 | int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER); |
477 | 482 | ||
478 | switch (cmd) { | 483 | switch (cmd) { |
@@ -480,13 +485,13 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd, | |||
480 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 485 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
481 | uda1380_write_reg_cache(codec, UDA1380_MIXER, | 486 | uda1380_write_reg_cache(codec, UDA1380_MIXER, |
482 | mixer & ~R14_SILENCE); | 487 | mixer & ~R14_SILENCE); |
483 | schedule_work(&uda1380_work); | 488 | schedule_work(&uda1380->work); |
484 | break; | 489 | break; |
485 | case SNDRV_PCM_TRIGGER_STOP: | 490 | case SNDRV_PCM_TRIGGER_STOP: |
486 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 491 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
487 | uda1380_write_reg_cache(codec, UDA1380_MIXER, | 492 | uda1380_write_reg_cache(codec, UDA1380_MIXER, |
488 | mixer | R14_SILENCE); | 493 | mixer | R14_SILENCE); |
489 | schedule_work(&uda1380_work); | 494 | schedule_work(&uda1380->work); |
490 | break; | 495 | break; |
491 | } | 496 | } |
492 | return 0; | 497 | return 0; |
@@ -670,44 +675,33 @@ static int uda1380_resume(struct platform_device *pdev) | |||
670 | return 0; | 675 | return 0; |
671 | } | 676 | } |
672 | 677 | ||
673 | /* | 678 | static int uda1380_probe(struct platform_device *pdev) |
674 | * initialise the UDA1380 driver | ||
675 | * register mixer and dsp interfaces with the kernel | ||
676 | */ | ||
677 | static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | ||
678 | { | 679 | { |
679 | struct snd_soc_codec *codec = socdev->card->codec; | 680 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
681 | struct snd_soc_codec *codec; | ||
682 | struct uda1380_platform_data *pdata; | ||
680 | int ret = 0; | 683 | int ret = 0; |
681 | 684 | ||
682 | codec->name = "UDA1380"; | 685 | if (uda1380_codec == NULL) { |
683 | codec->owner = THIS_MODULE; | 686 | dev_err(&pdev->dev, "Codec device not registered\n"); |
684 | codec->read = uda1380_read_reg_cache; | 687 | return -ENODEV; |
685 | codec->write = uda1380_write; | 688 | } |
686 | codec->set_bias_level = uda1380_set_bias_level; | ||
687 | codec->dai = uda1380_dai; | ||
688 | codec->num_dai = ARRAY_SIZE(uda1380_dai); | ||
689 | codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg), | ||
690 | GFP_KERNEL); | ||
691 | if (codec->reg_cache == NULL) | ||
692 | return -ENOMEM; | ||
693 | codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); | ||
694 | codec->reg_cache_step = 1; | ||
695 | uda1380_reset(codec); | ||
696 | 689 | ||
697 | uda1380_codec = codec; | 690 | socdev->card->codec = uda1380_codec; |
698 | INIT_WORK(&uda1380_work, uda1380_flush_work); | 691 | codec = uda1380_codec; |
692 | pdata = codec->dev->platform_data; | ||
699 | 693 | ||
700 | /* register pcms */ | 694 | /* register pcms */ |
701 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 695 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
702 | if (ret < 0) { | 696 | if (ret < 0) { |
703 | pr_err("uda1380: failed to create pcms\n"); | 697 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); |
704 | goto pcm_err; | 698 | goto pcm_err; |
705 | } | 699 | } |
706 | 700 | ||
707 | /* power on device */ | 701 | /* power on device */ |
708 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 702 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
709 | /* set clock input */ | 703 | /* set clock input */ |
710 | switch (dac_clk) { | 704 | switch (pdata->dac_clk) { |
711 | case UDA1380_DAC_CLK_SYSCLK: | 705 | case UDA1380_DAC_CLK_SYSCLK: |
712 | uda1380_write(codec, UDA1380_CLK, 0); | 706 | uda1380_write(codec, UDA1380_CLK, 0); |
713 | break; | 707 | break; |
@@ -716,13 +710,12 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | |||
716 | break; | 710 | break; |
717 | } | 711 | } |
718 | 712 | ||
719 | /* uda1380 init */ | ||
720 | snd_soc_add_controls(codec, uda1380_snd_controls, | 713 | snd_soc_add_controls(codec, uda1380_snd_controls, |
721 | ARRAY_SIZE(uda1380_snd_controls)); | 714 | ARRAY_SIZE(uda1380_snd_controls)); |
722 | uda1380_add_widgets(codec); | 715 | uda1380_add_widgets(codec); |
723 | ret = snd_soc_init_card(socdev); | 716 | ret = snd_soc_init_card(socdev); |
724 | if (ret < 0) { | 717 | if (ret < 0) { |
725 | pr_err("uda1380: failed to register card\n"); | 718 | dev_err(codec->dev, "failed to register card: %d\n", ret); |
726 | goto card_err; | 719 | goto card_err; |
727 | } | 720 | } |
728 | 721 | ||
@@ -732,165 +725,201 @@ card_err: | |||
732 | snd_soc_free_pcms(socdev); | 725 | snd_soc_free_pcms(socdev); |
733 | snd_soc_dapm_free(socdev); | 726 | snd_soc_dapm_free(socdev); |
734 | pcm_err: | 727 | pcm_err: |
735 | kfree(codec->reg_cache); | ||
736 | return ret; | 728 | return ret; |
737 | } | 729 | } |
738 | 730 | ||
739 | static struct snd_soc_device *uda1380_socdev; | 731 | /* power down chip */ |
740 | 732 | static int uda1380_remove(struct platform_device *pdev) | |
741 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
742 | |||
743 | static int uda1380_i2c_probe(struct i2c_client *i2c, | ||
744 | const struct i2c_device_id *id) | ||
745 | { | 733 | { |
746 | struct snd_soc_device *socdev = uda1380_socdev; | 734 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
747 | struct uda1380_setup_data *setup = socdev->codec_data; | ||
748 | struct snd_soc_codec *codec = socdev->card->codec; | 735 | struct snd_soc_codec *codec = socdev->card->codec; |
749 | int ret; | ||
750 | |||
751 | i2c_set_clientdata(i2c, codec); | ||
752 | codec->control_data = i2c; | ||
753 | 736 | ||
754 | ret = uda1380_init(socdev, setup->dac_clk); | 737 | if (codec->control_data) |
755 | if (ret < 0) | 738 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); |
756 | pr_err("uda1380: failed to initialise UDA1380\n"); | ||
757 | 739 | ||
758 | return ret; | 740 | snd_soc_free_pcms(socdev); |
759 | } | 741 | snd_soc_dapm_free(socdev); |
760 | 742 | ||
761 | static int uda1380_i2c_remove(struct i2c_client *client) | ||
762 | { | ||
763 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
764 | kfree(codec->reg_cache); | ||
765 | return 0; | 743 | return 0; |
766 | } | 744 | } |
767 | 745 | ||
768 | static const struct i2c_device_id uda1380_i2c_id[] = { | 746 | struct snd_soc_codec_device soc_codec_dev_uda1380 = { |
769 | { "uda1380", 0 }, | 747 | .probe = uda1380_probe, |
770 | { } | 748 | .remove = uda1380_remove, |
771 | }; | 749 | .suspend = uda1380_suspend, |
772 | MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); | 750 | .resume = uda1380_resume, |
773 | |||
774 | static struct i2c_driver uda1380_i2c_driver = { | ||
775 | .driver = { | ||
776 | .name = "UDA1380 I2C Codec", | ||
777 | .owner = THIS_MODULE, | ||
778 | }, | ||
779 | .probe = uda1380_i2c_probe, | ||
780 | .remove = uda1380_i2c_remove, | ||
781 | .id_table = uda1380_i2c_id, | ||
782 | }; | 751 | }; |
752 | EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); | ||
783 | 753 | ||
784 | static int uda1380_add_i2c_device(struct platform_device *pdev, | 754 | static int uda1380_register(struct uda1380_priv *uda1380) |
785 | const struct uda1380_setup_data *setup) | ||
786 | { | 755 | { |
787 | struct i2c_board_info info; | 756 | int ret, i; |
788 | struct i2c_adapter *adapter; | 757 | struct snd_soc_codec *codec = &uda1380->codec; |
789 | struct i2c_client *client; | 758 | struct uda1380_platform_data *pdata = codec->dev->platform_data; |
790 | int ret; | ||
791 | 759 | ||
792 | ret = i2c_add_driver(&uda1380_i2c_driver); | 760 | if (uda1380_codec) { |
793 | if (ret != 0) { | 761 | dev_err(codec->dev, "Another UDA1380 is registered\n"); |
794 | dev_err(&pdev->dev, "can't add i2c driver\n"); | 762 | return -EINVAL; |
795 | return ret; | 763 | } |
764 | |||
765 | if (!pdata || !pdata->gpio_power || !pdata->gpio_reset) | ||
766 | return -EINVAL; | ||
767 | |||
768 | ret = gpio_request(pdata->gpio_power, "uda1380 power"); | ||
769 | if (ret) | ||
770 | goto err_out; | ||
771 | ret = gpio_request(pdata->gpio_reset, "uda1380 reset"); | ||
772 | if (ret) | ||
773 | goto err_gpio; | ||
774 | |||
775 | gpio_direction_output(pdata->gpio_power, 1); | ||
776 | |||
777 | /* we may need to have the clock running here - pH5 */ | ||
778 | gpio_direction_output(pdata->gpio_reset, 1); | ||
779 | udelay(5); | ||
780 | gpio_set_value(pdata->gpio_reset, 0); | ||
781 | |||
782 | mutex_init(&codec->mutex); | ||
783 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
784 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
785 | |||
786 | codec->private_data = uda1380; | ||
787 | codec->name = "UDA1380"; | ||
788 | codec->owner = THIS_MODULE; | ||
789 | codec->read = uda1380_read_reg_cache; | ||
790 | codec->write = uda1380_write; | ||
791 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
792 | codec->set_bias_level = uda1380_set_bias_level; | ||
793 | codec->dai = uda1380_dai; | ||
794 | codec->num_dai = ARRAY_SIZE(uda1380_dai); | ||
795 | codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); | ||
796 | codec->reg_cache = &uda1380->reg_cache; | ||
797 | codec->reg_cache_step = 1; | ||
798 | |||
799 | memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg)); | ||
800 | |||
801 | ret = uda1380_reset(codec); | ||
802 | if (ret < 0) { | ||
803 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
804 | goto err_reset; | ||
796 | } | 805 | } |
797 | 806 | ||
798 | memset(&info, 0, sizeof(struct i2c_board_info)); | 807 | INIT_WORK(&uda1380->work, uda1380_flush_work); |
799 | info.addr = setup->i2c_address; | 808 | |
800 | strlcpy(info.type, "uda1380", I2C_NAME_SIZE); | 809 | for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++) |
810 | uda1380_dai[i].dev = codec->dev; | ||
801 | 811 | ||
802 | adapter = i2c_get_adapter(setup->i2c_bus); | 812 | uda1380_codec = codec; |
803 | if (!adapter) { | 813 | |
804 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | 814 | ret = snd_soc_register_codec(codec); |
805 | setup->i2c_bus); | 815 | if (ret != 0) { |
806 | goto err_driver; | 816 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
817 | goto err_reset; | ||
807 | } | 818 | } |
808 | 819 | ||
809 | client = i2c_new_device(adapter, &info); | 820 | ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); |
810 | i2c_put_adapter(adapter); | 821 | if (ret != 0) { |
811 | if (!client) { | 822 | dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); |
812 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | 823 | goto err_dai; |
813 | (unsigned int)info.addr); | ||
814 | goto err_driver; | ||
815 | } | 824 | } |
816 | 825 | ||
817 | return 0; | 826 | return 0; |
818 | 827 | ||
819 | err_driver: | 828 | err_dai: |
820 | i2c_del_driver(&uda1380_i2c_driver); | 829 | snd_soc_unregister_codec(codec); |
821 | return -ENODEV; | 830 | err_reset: |
831 | gpio_set_value(pdata->gpio_power, 0); | ||
832 | gpio_free(pdata->gpio_reset); | ||
833 | err_gpio: | ||
834 | gpio_free(pdata->gpio_power); | ||
835 | err_out: | ||
836 | return ret; | ||
822 | } | 837 | } |
823 | #endif | ||
824 | 838 | ||
825 | static int uda1380_probe(struct platform_device *pdev) | 839 | static void uda1380_unregister(struct uda1380_priv *uda1380) |
826 | { | 840 | { |
827 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 841 | struct snd_soc_codec *codec = &uda1380->codec; |
828 | struct uda1380_setup_data *setup; | 842 | struct uda1380_platform_data *pdata = codec->dev->platform_data; |
843 | |||
844 | snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); | ||
845 | snd_soc_unregister_codec(&uda1380->codec); | ||
846 | |||
847 | gpio_set_value(pdata->gpio_power, 0); | ||
848 | gpio_free(pdata->gpio_reset); | ||
849 | gpio_free(pdata->gpio_power); | ||
850 | |||
851 | kfree(uda1380); | ||
852 | uda1380_codec = NULL; | ||
853 | } | ||
854 | |||
855 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
856 | static __devinit int uda1380_i2c_probe(struct i2c_client *i2c, | ||
857 | const struct i2c_device_id *id) | ||
858 | { | ||
859 | struct uda1380_priv *uda1380; | ||
829 | struct snd_soc_codec *codec; | 860 | struct snd_soc_codec *codec; |
830 | int ret; | 861 | int ret; |
831 | 862 | ||
832 | setup = socdev->codec_data; | 863 | uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL); |
833 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 864 | if (uda1380 == NULL) |
834 | if (codec == NULL) | ||
835 | return -ENOMEM; | 865 | return -ENOMEM; |
836 | 866 | ||
837 | socdev->card->codec = codec; | 867 | codec = &uda1380->codec; |
838 | mutex_init(&codec->mutex); | 868 | codec->hw_write = (hw_write_t)i2c_master_send; |
839 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
840 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
841 | 869 | ||
842 | uda1380_socdev = socdev; | 870 | i2c_set_clientdata(i2c, uda1380); |
843 | ret = -ENODEV; | 871 | codec->control_data = i2c; |
844 | 872 | ||
845 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 873 | codec->dev = &i2c->dev; |
846 | if (setup->i2c_address) { | ||
847 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
848 | ret = uda1380_add_i2c_device(pdev, setup); | ||
849 | } | ||
850 | #endif | ||
851 | 874 | ||
875 | ret = uda1380_register(uda1380); | ||
852 | if (ret != 0) | 876 | if (ret != 0) |
853 | kfree(codec); | 877 | kfree(uda1380); |
878 | |||
854 | return ret; | 879 | return ret; |
855 | } | 880 | } |
856 | 881 | ||
857 | /* power down chip */ | 882 | static int __devexit uda1380_i2c_remove(struct i2c_client *i2c) |
858 | static int uda1380_remove(struct platform_device *pdev) | ||
859 | { | 883 | { |
860 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 884 | struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c); |
861 | struct snd_soc_codec *codec = socdev->card->codec; | 885 | uda1380_unregister(uda1380); |
862 | |||
863 | if (codec->control_data) | ||
864 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
865 | |||
866 | snd_soc_free_pcms(socdev); | ||
867 | snd_soc_dapm_free(socdev); | ||
868 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
869 | i2c_unregister_device(codec->control_data); | ||
870 | i2c_del_driver(&uda1380_i2c_driver); | ||
871 | #endif | ||
872 | kfree(codec); | ||
873 | |||
874 | return 0; | 886 | return 0; |
875 | } | 887 | } |
876 | 888 | ||
877 | struct snd_soc_codec_device soc_codec_dev_uda1380 = { | 889 | static const struct i2c_device_id uda1380_i2c_id[] = { |
878 | .probe = uda1380_probe, | 890 | { "uda1380", 0 }, |
879 | .remove = uda1380_remove, | 891 | { } |
880 | .suspend = uda1380_suspend, | ||
881 | .resume = uda1380_resume, | ||
882 | }; | 892 | }; |
883 | EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); | 893 | MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); |
894 | |||
895 | static struct i2c_driver uda1380_i2c_driver = { | ||
896 | .driver = { | ||
897 | .name = "UDA1380 I2C Codec", | ||
898 | .owner = THIS_MODULE, | ||
899 | }, | ||
900 | .probe = uda1380_i2c_probe, | ||
901 | .remove = __devexit_p(uda1380_i2c_remove), | ||
902 | .id_table = uda1380_i2c_id, | ||
903 | }; | ||
904 | #endif | ||
884 | 905 | ||
885 | static int __init uda1380_modinit(void) | 906 | static int __init uda1380_modinit(void) |
886 | { | 907 | { |
887 | return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); | 908 | int ret; |
909 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
910 | ret = i2c_add_driver(&uda1380_i2c_driver); | ||
911 | if (ret != 0) | ||
912 | pr_err("Failed to register UDA1380 I2C driver: %d\n", ret); | ||
913 | #endif | ||
914 | return 0; | ||
888 | } | 915 | } |
889 | module_init(uda1380_modinit); | 916 | module_init(uda1380_modinit); |
890 | 917 | ||
891 | static void __exit uda1380_exit(void) | 918 | static void __exit uda1380_exit(void) |
892 | { | 919 | { |
893 | snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); | 920 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
921 | i2c_del_driver(&uda1380_i2c_driver); | ||
922 | #endif | ||
894 | } | 923 | } |
895 | module_exit(uda1380_exit); | 924 | module_exit(uda1380_exit); |
896 | 925 | ||
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h index c55c17a52a12..9cefa8a54770 100644 --- a/sound/soc/codecs/uda1380.h +++ b/sound/soc/codecs/uda1380.h | |||
@@ -72,14 +72,6 @@ | |||
72 | #define R22_SKIP_DCFIL 0x0002 | 72 | #define R22_SKIP_DCFIL 0x0002 |
73 | #define R23_AGC_EN 0x0001 | 73 | #define R23_AGC_EN 0x0001 |
74 | 74 | ||
75 | struct uda1380_setup_data { | ||
76 | int i2c_bus; | ||
77 | unsigned short i2c_address; | ||
78 | int dac_clk; | ||
79 | #define UDA1380_DAC_CLK_SYSCLK 0 | ||
80 | #define UDA1380_DAC_CLK_WSPLL 1 | ||
81 | }; | ||
82 | |||
83 | #define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ | 75 | #define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ |
84 | #define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ | 76 | #define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ |
85 | #define UDA1380_DAI_CAPTURE 2 /* capture DAI */ | 77 | #define UDA1380_DAI_CAPTURE 2 /* capture DAI */ |
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index e7348d341b76..4ded0e3a35e0 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -406,7 +406,6 @@ static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | |||
406 | static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" }; | 406 | static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" }; |
407 | static const char *wm8350_dacmutem[] = { "Normal", "Soft" }; | 407 | static const char *wm8350_dacmutem[] = { "Normal", "Soft" }; |
408 | static const char *wm8350_dacmutes[] = { "Fast", "Slow" }; | 408 | static const char *wm8350_dacmutes[] = { "Fast", "Slow" }; |
409 | static const char *wm8350_dacfilter[] = { "Normal", "Sloping" }; | ||
410 | static const char *wm8350_adcfilter[] = { "None", "High Pass" }; | 409 | static const char *wm8350_adcfilter[] = { "None", "High Pass" }; |
411 | static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" }; | 410 | static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" }; |
412 | static const char *wm8350_lr[] = { "Left", "Right" }; | 411 | static const char *wm8350_lr[] = { "Left", "Right" }; |
@@ -416,7 +415,6 @@ static const struct soc_enum wm8350_enum[] = { | |||
416 | SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol), | 415 | SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol), |
417 | SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem), | 416 | SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem), |
418 | SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes), | 417 | SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes), |
419 | SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 12, 2, wm8350_dacfilter), | ||
420 | SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter), | 418 | SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter), |
421 | SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp), | 419 | SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp), |
422 | SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol), | 420 | SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol), |
@@ -444,10 +442,9 @@ static const struct snd_kcontrol_new wm8350_snd_controls[] = { | |||
444 | 0, 255, 0, dac_pcm_tlv), | 442 | 0, 255, 0, dac_pcm_tlv), |
445 | SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]), | 443 | SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]), |
446 | SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]), | 444 | SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]), |
447 | SOC_ENUM("Playback PCM Filter", wm8350_enum[4]), | 445 | SOC_ENUM("Capture PCM Filter", wm8350_enum[4]), |
448 | SOC_ENUM("Capture PCM Filter", wm8350_enum[5]), | 446 | SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]), |
449 | SOC_ENUM("Capture PCM HP Filter", wm8350_enum[6]), | 447 | SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]), |
450 | SOC_ENUM("Capture ADC Inversion", wm8350_enum[7]), | ||
451 | SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume", | 448 | SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume", |
452 | WM8350_ADC_DIGITAL_VOLUME_L, | 449 | WM8350_ADC_DIGITAL_VOLUME_L, |
453 | WM8350_ADC_DIGITAL_VOLUME_R, | 450 | WM8350_ADC_DIGITAL_VOLUME_R, |
@@ -993,6 +990,7 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream, | |||
993 | struct snd_soc_dai *codec_dai) | 990 | struct snd_soc_dai *codec_dai) |
994 | { | 991 | { |
995 | struct snd_soc_codec *codec = codec_dai->codec; | 992 | struct snd_soc_codec *codec = codec_dai->codec; |
993 | struct wm8350 *wm8350 = codec->control_data; | ||
996 | u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) & | 994 | u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) & |
997 | ~WM8350_AIF_WL_MASK; | 995 | ~WM8350_AIF_WL_MASK; |
998 | 996 | ||
@@ -1012,6 +1010,19 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream, | |||
1012 | } | 1010 | } |
1013 | 1011 | ||
1014 | wm8350_codec_write(codec, WM8350_AI_FORMATING, iface); | 1012 | wm8350_codec_write(codec, WM8350_AI_FORMATING, iface); |
1013 | |||
1014 | /* The sloping stopband filter is recommended for use with | ||
1015 | * lower sample rates to improve performance. | ||
1016 | */ | ||
1017 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1018 | if (params_rate(params) < 24000) | ||
1019 | wm8350_set_bits(wm8350, WM8350_DAC_MUTE_VOLUME, | ||
1020 | WM8350_DAC_SB_FILT); | ||
1021 | else | ||
1022 | wm8350_clear_bits(wm8350, WM8350_DAC_MUTE_VOLUME, | ||
1023 | WM8350_DAC_SB_FILT); | ||
1024 | } | ||
1025 | |||
1015 | return 0; | 1026 | return 0; |
1016 | } | 1027 | } |
1017 | 1028 | ||
@@ -1660,6 +1671,21 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev) | |||
1660 | return 0; | 1671 | return 0; |
1661 | } | 1672 | } |
1662 | 1673 | ||
1674 | #ifdef CONFIG_PM | ||
1675 | static int wm8350_codec_suspend(struct platform_device *pdev, pm_message_t m) | ||
1676 | { | ||
1677 | return snd_soc_suspend_device(&pdev->dev); | ||
1678 | } | ||
1679 | |||
1680 | static int wm8350_codec_resume(struct platform_device *pdev) | ||
1681 | { | ||
1682 | return snd_soc_resume_device(&pdev->dev); | ||
1683 | } | ||
1684 | #else | ||
1685 | #define wm8350_codec_suspend NULL | ||
1686 | #define wm8350_codec_resume NULL | ||
1687 | #endif | ||
1688 | |||
1663 | static struct platform_driver wm8350_codec_driver = { | 1689 | static struct platform_driver wm8350_codec_driver = { |
1664 | .driver = { | 1690 | .driver = { |
1665 | .name = "wm8350-codec", | 1691 | .name = "wm8350-codec", |
@@ -1667,6 +1693,8 @@ static struct platform_driver wm8350_codec_driver = { | |||
1667 | }, | 1693 | }, |
1668 | .probe = wm8350_codec_probe, | 1694 | .probe = wm8350_codec_probe, |
1669 | .remove = __devexit_p(wm8350_codec_remove), | 1695 | .remove = __devexit_p(wm8350_codec_remove), |
1696 | .suspend = wm8350_codec_suspend, | ||
1697 | .resume = wm8350_codec_resume, | ||
1670 | }; | 1698 | }; |
1671 | 1699 | ||
1672 | static __init int wm8350_init(void) | 1700 | static __init int wm8350_init(void) |
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 502eefac1ecd..0bf903f27564 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -1553,6 +1553,21 @@ static int __exit wm8400_codec_remove(struct platform_device *dev) | |||
1553 | return 0; | 1553 | return 0; |
1554 | } | 1554 | } |
1555 | 1555 | ||
1556 | #ifdef CONFIG_PM | ||
1557 | static int wm8400_pdev_suspend(struct platform_device *pdev, pm_message_t msg) | ||
1558 | { | ||
1559 | return snd_soc_suspend_device(&pdev->dev); | ||
1560 | } | ||
1561 | |||
1562 | static int wm8400_pdev_resume(struct platform_device *pdev) | ||
1563 | { | ||
1564 | return snd_soc_resume_device(&pdev->dev); | ||
1565 | } | ||
1566 | #else | ||
1567 | #define wm8400_pdev_suspend NULL | ||
1568 | #define wm8400_pdev_resume NULL | ||
1569 | #endif | ||
1570 | |||
1556 | static struct platform_driver wm8400_codec_driver = { | 1571 | static struct platform_driver wm8400_codec_driver = { |
1557 | .driver = { | 1572 | .driver = { |
1558 | .name = "wm8400-codec", | 1573 | .name = "wm8400-codec", |
@@ -1560,6 +1575,8 @@ static struct platform_driver wm8400_codec_driver = { | |||
1560 | }, | 1575 | }, |
1561 | .probe = wm8400_codec_probe, | 1576 | .probe = wm8400_codec_probe, |
1562 | .remove = __exit_p(wm8400_codec_remove), | 1577 | .remove = __exit_p(wm8400_codec_remove), |
1578 | .suspend = wm8400_pdev_suspend, | ||
1579 | .resume = wm8400_pdev_resume, | ||
1563 | }; | 1580 | }; |
1564 | 1581 | ||
1565 | static int __init wm8400_codec_init(void) | 1582 | static int __init wm8400_codec_init(void) |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 86c4b24db817..97b9ed95d289 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <linux/pm.h> | 24 | #include <linux/pm.h> |
25 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/regulator/consumer.h> | ||
28 | |||
27 | #include <sound/core.h> | 29 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 30 | #include <sound/pcm.h> |
29 | #include <sound/pcm_params.h> | 31 | #include <sound/pcm_params.h> |
@@ -187,15 +189,22 @@ struct pll_state { | |||
187 | unsigned int out; | 189 | unsigned int out; |
188 | }; | 190 | }; |
189 | 191 | ||
192 | #define WM8580_NUM_SUPPLIES 3 | ||
193 | static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = { | ||
194 | "AVDD", | ||
195 | "DVDD", | ||
196 | "PVDD", | ||
197 | }; | ||
198 | |||
190 | /* codec private data */ | 199 | /* codec private data */ |
191 | struct wm8580_priv { | 200 | struct wm8580_priv { |
192 | struct snd_soc_codec codec; | 201 | struct snd_soc_codec codec; |
202 | struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES]; | ||
193 | u16 reg_cache[WM8580_MAX_REGISTER + 1]; | 203 | u16 reg_cache[WM8580_MAX_REGISTER + 1]; |
194 | struct pll_state a; | 204 | struct pll_state a; |
195 | struct pll_state b; | 205 | struct pll_state b; |
196 | }; | 206 | }; |
197 | 207 | ||
198 | |||
199 | /* | 208 | /* |
200 | * read wm8580 register cache | 209 | * read wm8580 register cache |
201 | */ | 210 | */ |
@@ -922,11 +931,28 @@ static int wm8580_register(struct wm8580_priv *wm8580) | |||
922 | 931 | ||
923 | memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); | 932 | memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); |
924 | 933 | ||
934 | for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) | ||
935 | wm8580->supplies[i].supply = wm8580_supply_names[i]; | ||
936 | |||
937 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8580->supplies), | ||
938 | wm8580->supplies); | ||
939 | if (ret != 0) { | ||
940 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
941 | goto err; | ||
942 | } | ||
943 | |||
944 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies), | ||
945 | wm8580->supplies); | ||
946 | if (ret != 0) { | ||
947 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
948 | goto err_regulator_get; | ||
949 | } | ||
950 | |||
925 | /* Get the codec into a known state */ | 951 | /* Get the codec into a known state */ |
926 | ret = wm8580_write(codec, WM8580_RESET, 0); | 952 | ret = wm8580_write(codec, WM8580_RESET, 0); |
927 | if (ret != 0) { | 953 | if (ret != 0) { |
928 | dev_err(codec->dev, "Failed to reset codec: %d\n", ret); | 954 | dev_err(codec->dev, "Failed to reset codec: %d\n", ret); |
929 | goto err; | 955 | goto err_regulator_enable; |
930 | } | 956 | } |
931 | 957 | ||
932 | for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++) | 958 | for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++) |
@@ -939,7 +965,7 @@ static int wm8580_register(struct wm8580_priv *wm8580) | |||
939 | ret = snd_soc_register_codec(codec); | 965 | ret = snd_soc_register_codec(codec); |
940 | if (ret != 0) { | 966 | if (ret != 0) { |
941 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 967 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
942 | goto err; | 968 | goto err_regulator_enable; |
943 | } | 969 | } |
944 | 970 | ||
945 | ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | 971 | ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); |
@@ -952,6 +978,10 @@ static int wm8580_register(struct wm8580_priv *wm8580) | |||
952 | 978 | ||
953 | err_codec: | 979 | err_codec: |
954 | snd_soc_unregister_codec(codec); | 980 | snd_soc_unregister_codec(codec); |
981 | err_regulator_enable: | ||
982 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | ||
983 | err_regulator_get: | ||
984 | regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | ||
955 | err: | 985 | err: |
956 | kfree(wm8580); | 986 | kfree(wm8580); |
957 | return ret; | 987 | return ret; |
@@ -962,6 +992,8 @@ static void wm8580_unregister(struct wm8580_priv *wm8580) | |||
962 | wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF); | 992 | wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF); |
963 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | 993 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); |
964 | snd_soc_unregister_codec(&wm8580->codec); | 994 | snd_soc_unregister_codec(&wm8580->codec); |
995 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | ||
996 | regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | ||
965 | kfree(wm8580); | 997 | kfree(wm8580); |
966 | wm8580_codec = NULL; | 998 | wm8580_codec = NULL; |
967 | } | 999 | } |
@@ -995,6 +1027,21 @@ static int wm8580_i2c_remove(struct i2c_client *client) | |||
995 | return 0; | 1027 | return 0; |
996 | } | 1028 | } |
997 | 1029 | ||
1030 | #ifdef CONFIG_PM | ||
1031 | static int wm8580_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
1032 | { | ||
1033 | return snd_soc_suspend_device(&client->dev); | ||
1034 | } | ||
1035 | |||
1036 | static int wm8580_i2c_resume(struct i2c_client *client) | ||
1037 | { | ||
1038 | return snd_soc_resume_device(&client->dev); | ||
1039 | } | ||
1040 | #else | ||
1041 | #define wm8580_i2c_suspend NULL | ||
1042 | #define wm8580_i2c_resume NULL | ||
1043 | #endif | ||
1044 | |||
998 | static const struct i2c_device_id wm8580_i2c_id[] = { | 1045 | static const struct i2c_device_id wm8580_i2c_id[] = { |
999 | { "wm8580", 0 }, | 1046 | { "wm8580", 0 }, |
1000 | { } | 1047 | { } |
@@ -1008,6 +1055,8 @@ static struct i2c_driver wm8580_i2c_driver = { | |||
1008 | }, | 1055 | }, |
1009 | .probe = wm8580_i2c_probe, | 1056 | .probe = wm8580_i2c_probe, |
1010 | .remove = wm8580_i2c_remove, | 1057 | .remove = wm8580_i2c_remove, |
1058 | .suspend = wm8580_i2c_suspend, | ||
1059 | .resume = wm8580_i2c_resume, | ||
1011 | .id_table = wm8580_i2c_id, | 1060 | .id_table = wm8580_i2c_id, |
1012 | }; | 1061 | }; |
1013 | #endif | 1062 | #endif |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7a205876ef4f..d7f4788f7ace 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -460,6 +460,7 @@ struct snd_soc_dai wm8731_dai = { | |||
460 | }; | 460 | }; |
461 | EXPORT_SYMBOL_GPL(wm8731_dai); | 461 | EXPORT_SYMBOL_GPL(wm8731_dai); |
462 | 462 | ||
463 | #ifdef CONFIG_PM | ||
463 | static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | 464 | static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) |
464 | { | 465 | { |
465 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 466 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -488,6 +489,10 @@ static int wm8731_resume(struct platform_device *pdev) | |||
488 | wm8731_set_bias_level(codec, codec->suspend_bias_level); | 489 | wm8731_set_bias_level(codec, codec->suspend_bias_level); |
489 | return 0; | 490 | return 0; |
490 | } | 491 | } |
492 | #else | ||
493 | #define wm8731_suspend NULL | ||
494 | #define wm8731_resume NULL | ||
495 | #endif | ||
491 | 496 | ||
492 | static int wm8731_probe(struct platform_device *pdev) | 497 | static int wm8731_probe(struct platform_device *pdev) |
493 | { | 498 | { |
@@ -680,6 +685,21 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi) | |||
680 | return 0; | 685 | return 0; |
681 | } | 686 | } |
682 | 687 | ||
688 | #ifdef CONFIG_PM | ||
689 | static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg) | ||
690 | { | ||
691 | return snd_soc_suspend_device(&spi->dev); | ||
692 | } | ||
693 | |||
694 | static int wm8731_spi_resume(struct spi_device *spi) | ||
695 | { | ||
696 | return snd_soc_resume_device(&spi->dev); | ||
697 | } | ||
698 | #else | ||
699 | #define wm8731_spi_suspend NULL | ||
700 | #define wm8731_spi_resume NULL | ||
701 | #endif | ||
702 | |||
683 | static struct spi_driver wm8731_spi_driver = { | 703 | static struct spi_driver wm8731_spi_driver = { |
684 | .driver = { | 704 | .driver = { |
685 | .name = "wm8731", | 705 | .name = "wm8731", |
@@ -687,6 +707,8 @@ static struct spi_driver wm8731_spi_driver = { | |||
687 | .owner = THIS_MODULE, | 707 | .owner = THIS_MODULE, |
688 | }, | 708 | }, |
689 | .probe = wm8731_spi_probe, | 709 | .probe = wm8731_spi_probe, |
710 | .suspend = wm8731_spi_suspend, | ||
711 | .resume = wm8731_spi_resume, | ||
690 | .remove = __devexit_p(wm8731_spi_remove), | 712 | .remove = __devexit_p(wm8731_spi_remove), |
691 | }; | 713 | }; |
692 | #endif /* CONFIG_SPI_MASTER */ | 714 | #endif /* CONFIG_SPI_MASTER */ |
@@ -720,6 +742,21 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client) | |||
720 | return 0; | 742 | return 0; |
721 | } | 743 | } |
722 | 744 | ||
745 | #ifdef CONFIG_PM | ||
746 | static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) | ||
747 | { | ||
748 | return snd_soc_suspend_device(&i2c->dev); | ||
749 | } | ||
750 | |||
751 | static int wm8731_i2c_resume(struct i2c_client *i2c) | ||
752 | { | ||
753 | return snd_soc_resume_device(&i2c->dev); | ||
754 | } | ||
755 | #else | ||
756 | #define wm8731_i2c_suspend NULL | ||
757 | #define wm8731_i2c_resume NULL | ||
758 | #endif | ||
759 | |||
723 | static const struct i2c_device_id wm8731_i2c_id[] = { | 760 | static const struct i2c_device_id wm8731_i2c_id[] = { |
724 | { "wm8731", 0 }, | 761 | { "wm8731", 0 }, |
725 | { } | 762 | { } |
@@ -733,6 +770,8 @@ static struct i2c_driver wm8731_i2c_driver = { | |||
733 | }, | 770 | }, |
734 | .probe = wm8731_i2c_probe, | 771 | .probe = wm8731_i2c_probe, |
735 | .remove = __devexit_p(wm8731_i2c_remove), | 772 | .remove = __devexit_p(wm8731_i2c_remove), |
773 | .suspend = wm8731_i2c_suspend, | ||
774 | .resume = wm8731_i2c_resume, | ||
736 | .id_table = wm8731_i2c_id, | 775 | .id_table = wm8731_i2c_id, |
737 | }; | 776 | }; |
738 | #endif | 777 | #endif |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d28eeaceb857..370f7df03628 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -1766,6 +1766,21 @@ static int wm8753_i2c_remove(struct i2c_client *client) | |||
1766 | return 0; | 1766 | return 0; |
1767 | } | 1767 | } |
1768 | 1768 | ||
1769 | #ifdef CONFIG_PM | ||
1770 | static int wm8753_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
1771 | { | ||
1772 | return snd_soc_suspend_device(&client->dev); | ||
1773 | } | ||
1774 | |||
1775 | static int wm8753_i2c_resume(struct i2c_client *client) | ||
1776 | { | ||
1777 | return snd_soc_resume_device(&client->dev); | ||
1778 | } | ||
1779 | #else | ||
1780 | #define wm8753_i2c_suspend NULL | ||
1781 | #define wm8753_i2c_resume NULL | ||
1782 | #endif | ||
1783 | |||
1769 | static const struct i2c_device_id wm8753_i2c_id[] = { | 1784 | static const struct i2c_device_id wm8753_i2c_id[] = { |
1770 | { "wm8753", 0 }, | 1785 | { "wm8753", 0 }, |
1771 | { } | 1786 | { } |
@@ -1779,6 +1794,8 @@ static struct i2c_driver wm8753_i2c_driver = { | |||
1779 | }, | 1794 | }, |
1780 | .probe = wm8753_i2c_probe, | 1795 | .probe = wm8753_i2c_probe, |
1781 | .remove = wm8753_i2c_remove, | 1796 | .remove = wm8753_i2c_remove, |
1797 | .suspend = wm8753_i2c_suspend, | ||
1798 | .resume = wm8753_i2c_resume, | ||
1782 | .id_table = wm8753_i2c_id, | 1799 | .id_table = wm8753_i2c_id, |
1783 | }; | 1800 | }; |
1784 | #endif | 1801 | #endif |
@@ -1834,6 +1851,22 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi) | |||
1834 | return 0; | 1851 | return 0; |
1835 | } | 1852 | } |
1836 | 1853 | ||
1854 | #ifdef CONFIG_PM | ||
1855 | static int wm8753_spi_suspend(struct spi_device *spi, pm_message_t msg) | ||
1856 | { | ||
1857 | return snd_soc_suspend_device(&spi->dev); | ||
1858 | } | ||
1859 | |||
1860 | static int wm8753_spi_resume(struct spi_device *spi) | ||
1861 | { | ||
1862 | return snd_soc_resume_device(&spi->dev); | ||
1863 | } | ||
1864 | |||
1865 | #else | ||
1866 | #define wm8753_spi_suspend NULL | ||
1867 | #define wm8753_spi_resume NULL | ||
1868 | #endif | ||
1869 | |||
1837 | static struct spi_driver wm8753_spi_driver = { | 1870 | static struct spi_driver wm8753_spi_driver = { |
1838 | .driver = { | 1871 | .driver = { |
1839 | .name = "wm8753", | 1872 | .name = "wm8753", |
@@ -1842,6 +1875,8 @@ static struct spi_driver wm8753_spi_driver = { | |||
1842 | }, | 1875 | }, |
1843 | .probe = wm8753_spi_probe, | 1876 | .probe = wm8753_spi_probe, |
1844 | .remove = __devexit_p(wm8753_spi_remove), | 1877 | .remove = __devexit_p(wm8753_spi_remove), |
1878 | .suspend = wm8753_spi_suspend, | ||
1879 | .resume = wm8753_spi_resume, | ||
1845 | }; | 1880 | }; |
1846 | #endif | 1881 | #endif |
1847 | 1882 | ||
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 3c78945244b8..ac308993ac5a 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -116,6 +116,7 @@ | |||
116 | #define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c | 116 | #define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c |
117 | 117 | ||
118 | #define WM8900_REG_DACCTRL_MUTE 0x004 | 118 | #define WM8900_REG_DACCTRL_MUTE 0x004 |
119 | #define WM8900_REG_DACCTRL_DAC_SB_FILT 0x100 | ||
119 | #define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400 | 120 | #define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400 |
120 | 121 | ||
121 | #define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800 | 122 | #define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800 |
@@ -439,7 +440,6 @@ SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1), | |||
439 | SOC_ENUM("DAC Mute Rate", dac_mute_rate), | 440 | SOC_ENUM("DAC Mute Rate", dac_mute_rate), |
440 | SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0), | 441 | SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0), |
441 | SOC_ENUM("DAC Deemphasis", dac_deemphasis), | 442 | SOC_ENUM("DAC Deemphasis", dac_deemphasis), |
442 | SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0), | ||
443 | SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL, | 443 | SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL, |
444 | 12, 1, 0), | 444 | 12, 1, 0), |
445 | 445 | ||
@@ -743,6 +743,17 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, | |||
743 | 743 | ||
744 | wm8900_write(codec, WM8900_REG_AUDIO1, reg); | 744 | wm8900_write(codec, WM8900_REG_AUDIO1, reg); |
745 | 745 | ||
746 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
747 | reg = wm8900_read(codec, WM8900_REG_DACCTRL); | ||
748 | |||
749 | if (params_rate(params) <= 24000) | ||
750 | reg |= WM8900_REG_DACCTRL_DAC_SB_FILT; | ||
751 | else | ||
752 | reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT; | ||
753 | |||
754 | wm8900_write(codec, WM8900_REG_DACCTRL, reg); | ||
755 | } | ||
756 | |||
746 | return 0; | 757 | return 0; |
747 | } | 758 | } |
748 | 759 | ||
@@ -1388,6 +1399,21 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client) | |||
1388 | return 0; | 1399 | return 0; |
1389 | } | 1400 | } |
1390 | 1401 | ||
1402 | #ifdef CONFIG_PM | ||
1403 | static int wm8900_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
1404 | { | ||
1405 | return snd_soc_suspend_device(&client->dev); | ||
1406 | } | ||
1407 | |||
1408 | static int wm8900_i2c_resume(struct i2c_client *client) | ||
1409 | { | ||
1410 | return snd_soc_resume_device(&client->dev); | ||
1411 | } | ||
1412 | #else | ||
1413 | #define wm8900_i2c_suspend NULL | ||
1414 | #define wm8900_i2c_resume NULL | ||
1415 | #endif | ||
1416 | |||
1391 | static const struct i2c_device_id wm8900_i2c_id[] = { | 1417 | static const struct i2c_device_id wm8900_i2c_id[] = { |
1392 | { "wm8900", 0 }, | 1418 | { "wm8900", 0 }, |
1393 | { } | 1419 | { } |
@@ -1401,6 +1427,8 @@ static struct i2c_driver wm8900_i2c_driver = { | |||
1401 | }, | 1427 | }, |
1402 | .probe = wm8900_i2c_probe, | 1428 | .probe = wm8900_i2c_probe, |
1403 | .remove = __devexit_p(wm8900_i2c_remove), | 1429 | .remove = __devexit_p(wm8900_i2c_remove), |
1430 | .suspend = wm8900_i2c_suspend, | ||
1431 | .resume = wm8900_i2c_resume, | ||
1404 | .id_table = wm8900_i2c_id, | 1432 | .id_table = wm8900_i2c_id, |
1405 | }; | 1433 | }; |
1406 | 1434 | ||
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index e8d2e3e14c45..c9baeae3e275 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -715,8 +715,6 @@ SOC_ENUM("DAC Soft Mute Rate", soft_mute), | |||
715 | SOC_ENUM("DAC Mute Mode", mute_mode), | 715 | SOC_ENUM("DAC Mute Mode", mute_mode), |
716 | SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), | 716 | SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), |
717 | SOC_ENUM("DAC De-emphasis", dac_deemphasis), | 717 | SOC_ENUM("DAC De-emphasis", dac_deemphasis), |
718 | SOC_SINGLE("DAC Sloping Stopband Filter Switch", | ||
719 | WM8903_DAC_DIGITAL_1, 11, 1, 0), | ||
720 | SOC_ENUM("DAC Companding Mode", dac_companding), | 718 | SOC_ENUM("DAC Companding Mode", dac_companding), |
721 | SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), | 719 | SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), |
722 | 720 | ||
@@ -1373,12 +1371,19 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, | |||
1373 | u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3); | 1371 | u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3); |
1374 | u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0); | 1372 | u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0); |
1375 | u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1); | 1373 | u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1); |
1374 | u16 dac_digital1 = wm8903_read(codec, WM8903_DAC_DIGITAL_1); | ||
1376 | 1375 | ||
1377 | if (substream == wm8903->slave_substream) { | 1376 | if (substream == wm8903->slave_substream) { |
1378 | dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); | 1377 | dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); |
1379 | return 0; | 1378 | return 0; |
1380 | } | 1379 | } |
1381 | 1380 | ||
1381 | /* Enable sloping stopband filter for low sample rates */ | ||
1382 | if (fs <= 24000) | ||
1383 | dac_digital1 |= WM8903_DAC_SB_FILT; | ||
1384 | else | ||
1385 | dac_digital1 &= ~WM8903_DAC_SB_FILT; | ||
1386 | |||
1382 | /* Configure sample rate logic for DSP - choose nearest rate */ | 1387 | /* Configure sample rate logic for DSP - choose nearest rate */ |
1383 | dsp_config = 0; | 1388 | dsp_config = 0; |
1384 | best_val = abs(sample_rates[dsp_config].rate - fs); | 1389 | best_val = abs(sample_rates[dsp_config].rate - fs); |
@@ -1503,6 +1508,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, | |||
1503 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); | 1508 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); |
1504 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); | 1509 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); |
1505 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); | 1510 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); |
1511 | wm8903_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1); | ||
1506 | 1512 | ||
1507 | return 0; | 1513 | return 0; |
1508 | } | 1514 | } |
@@ -1721,6 +1727,21 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client) | |||
1721 | return 0; | 1727 | return 0; |
1722 | } | 1728 | } |
1723 | 1729 | ||
1730 | #ifdef CONFIG_PM | ||
1731 | static int wm8903_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
1732 | { | ||
1733 | return snd_soc_suspend_device(&client->dev); | ||
1734 | } | ||
1735 | |||
1736 | static int wm8903_i2c_resume(struct i2c_client *client) | ||
1737 | { | ||
1738 | return snd_soc_resume_device(&client->dev); | ||
1739 | } | ||
1740 | #else | ||
1741 | #define wm8903_i2c_suspend NULL | ||
1742 | #define wm8903_i2c_resume NULL | ||
1743 | #endif | ||
1744 | |||
1724 | /* i2c codec control layer */ | 1745 | /* i2c codec control layer */ |
1725 | static const struct i2c_device_id wm8903_i2c_id[] = { | 1746 | static const struct i2c_device_id wm8903_i2c_id[] = { |
1726 | { "wm8903", 0 }, | 1747 | { "wm8903", 0 }, |
@@ -1735,6 +1756,8 @@ static struct i2c_driver wm8903_i2c_driver = { | |||
1735 | }, | 1756 | }, |
1736 | .probe = wm8903_i2c_probe, | 1757 | .probe = wm8903_i2c_probe, |
1737 | .remove = __devexit_p(wm8903_i2c_remove), | 1758 | .remove = __devexit_p(wm8903_i2c_remove), |
1759 | .suspend = wm8903_i2c_suspend, | ||
1760 | .resume = wm8903_i2c_resume, | ||
1738 | .id_table = wm8903_i2c_id, | 1761 | .id_table = wm8903_i2c_id, |
1739 | }; | 1762 | }; |
1740 | 1763 | ||
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index b8e17d6bc1f7..b69210a77423 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -916,6 +916,21 @@ static int __devexit wm8940_i2c_remove(struct i2c_client *client) | |||
916 | return 0; | 916 | return 0; |
917 | } | 917 | } |
918 | 918 | ||
919 | #ifdef CONFIG_PM | ||
920 | static int wm8940_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
921 | { | ||
922 | return snd_soc_suspend_device(&client->dev); | ||
923 | } | ||
924 | |||
925 | static int wm8940_i2c_resume(struct i2c_client *client) | ||
926 | { | ||
927 | return snd_soc_resume_device(&client->dev); | ||
928 | } | ||
929 | #else | ||
930 | #define wm8940_i2c_suspend NULL | ||
931 | #define wm8940_i2c_resume NULL | ||
932 | #endif | ||
933 | |||
919 | static const struct i2c_device_id wm8940_i2c_id[] = { | 934 | static const struct i2c_device_id wm8940_i2c_id[] = { |
920 | { "wm8940", 0 }, | 935 | { "wm8940", 0 }, |
921 | { } | 936 | { } |
@@ -929,6 +944,8 @@ static struct i2c_driver wm8940_i2c_driver = { | |||
929 | }, | 944 | }, |
930 | .probe = wm8940_i2c_probe, | 945 | .probe = wm8940_i2c_probe, |
931 | .remove = __devexit_p(wm8940_i2c_remove), | 946 | .remove = __devexit_p(wm8940_i2c_remove), |
947 | .suspend = wm8940_i2c_suspend, | ||
948 | .resume = wm8940_i2c_resume, | ||
932 | .id_table = wm8940_i2c_id, | 949 | .id_table = wm8940_i2c_id, |
933 | }; | 950 | }; |
934 | 951 | ||
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index e224d8add170..b7894d6dffc0 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -927,6 +927,21 @@ static __devexit int wm8960_i2c_remove(struct i2c_client *client) | |||
927 | return 0; | 927 | return 0; |
928 | } | 928 | } |
929 | 929 | ||
930 | #ifdef CONFIG_PM | ||
931 | static int wm8960_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
932 | { | ||
933 | return snd_soc_suspend_device(&client->dev); | ||
934 | } | ||
935 | |||
936 | static int wm8960_i2c_resume(struct i2c_client *client) | ||
937 | { | ||
938 | return snd_soc_resume_device(&client->dev); | ||
939 | } | ||
940 | #else | ||
941 | #define wm8960_i2c_suspend NULL | ||
942 | #define wm8960_i2c_resume NULL | ||
943 | #endif | ||
944 | |||
930 | static const struct i2c_device_id wm8960_i2c_id[] = { | 945 | static const struct i2c_device_id wm8960_i2c_id[] = { |
931 | { "wm8960", 0 }, | 946 | { "wm8960", 0 }, |
932 | { } | 947 | { } |
@@ -940,6 +955,8 @@ static struct i2c_driver wm8960_i2c_driver = { | |||
940 | }, | 955 | }, |
941 | .probe = wm8960_i2c_probe, | 956 | .probe = wm8960_i2c_probe, |
942 | .remove = __devexit_p(wm8960_i2c_remove), | 957 | .remove = __devexit_p(wm8960_i2c_remove), |
958 | .suspend = wm8960_i2c_suspend, | ||
959 | .resume = wm8960_i2c_resume, | ||
943 | .id_table = wm8960_i2c_id, | 960 | .id_table = wm8960_i2c_id, |
944 | }; | 961 | }; |
945 | 962 | ||
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c new file mode 100644 index 000000000000..1af2d10702f4 --- /dev/null +++ b/sound/soc/codecs/wm8961.c | |||
@@ -0,0 +1,1326 @@ | |||
1 | /* | ||
2 | * wm8961.c -- WM8961 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Author: Mark Brown | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Currently unimplemented features: | ||
11 | * - ALC | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/tlv.h> | ||
28 | |||
29 | #include "wm8961.h" | ||
30 | |||
31 | #define WM8961_MAX_REGISTER 0xFC | ||
32 | |||
33 | static u16 wm8961_reg_defaults[] = { | ||
34 | 0x009F, /* R0 - Left Input volume */ | ||
35 | 0x009F, /* R1 - Right Input volume */ | ||
36 | 0x0000, /* R2 - LOUT1 volume */ | ||
37 | 0x0000, /* R3 - ROUT1 volume */ | ||
38 | 0x0020, /* R4 - Clocking1 */ | ||
39 | 0x0008, /* R5 - ADC & DAC Control 1 */ | ||
40 | 0x0000, /* R6 - ADC & DAC Control 2 */ | ||
41 | 0x000A, /* R7 - Audio Interface 0 */ | ||
42 | 0x01F4, /* R8 - Clocking2 */ | ||
43 | 0x0000, /* R9 - Audio Interface 1 */ | ||
44 | 0x00FF, /* R10 - Left DAC volume */ | ||
45 | 0x00FF, /* R11 - Right DAC volume */ | ||
46 | 0x0000, /* R12 */ | ||
47 | 0x0000, /* R13 */ | ||
48 | 0x0040, /* R14 - Audio Interface 2 */ | ||
49 | 0x0000, /* R15 - Software Reset */ | ||
50 | 0x0000, /* R16 */ | ||
51 | 0x007B, /* R17 - ALC1 */ | ||
52 | 0x0000, /* R18 - ALC2 */ | ||
53 | 0x0032, /* R19 - ALC3 */ | ||
54 | 0x0000, /* R20 - Noise Gate */ | ||
55 | 0x00C0, /* R21 - Left ADC volume */ | ||
56 | 0x00C0, /* R22 - Right ADC volume */ | ||
57 | 0x0120, /* R23 - Additional control(1) */ | ||
58 | 0x0000, /* R24 - Additional control(2) */ | ||
59 | 0x0000, /* R25 - Pwr Mgmt (1) */ | ||
60 | 0x0000, /* R26 - Pwr Mgmt (2) */ | ||
61 | 0x0000, /* R27 - Additional Control (3) */ | ||
62 | 0x0000, /* R28 - Anti-pop */ | ||
63 | 0x0000, /* R29 */ | ||
64 | 0x005F, /* R30 - Clocking 3 */ | ||
65 | 0x0000, /* R31 */ | ||
66 | 0x0000, /* R32 - ADCL signal path */ | ||
67 | 0x0000, /* R33 - ADCR signal path */ | ||
68 | 0x0000, /* R34 */ | ||
69 | 0x0000, /* R35 */ | ||
70 | 0x0000, /* R36 */ | ||
71 | 0x0000, /* R37 */ | ||
72 | 0x0000, /* R38 */ | ||
73 | 0x0000, /* R39 */ | ||
74 | 0x0000, /* R40 - LOUT2 volume */ | ||
75 | 0x0000, /* R41 - ROUT2 volume */ | ||
76 | 0x0000, /* R42 */ | ||
77 | 0x0000, /* R43 */ | ||
78 | 0x0000, /* R44 */ | ||
79 | 0x0000, /* R45 */ | ||
80 | 0x0000, /* R46 */ | ||
81 | 0x0000, /* R47 - Pwr Mgmt (3) */ | ||
82 | 0x0023, /* R48 - Additional Control (4) */ | ||
83 | 0x0000, /* R49 - Class D Control 1 */ | ||
84 | 0x0000, /* R50 */ | ||
85 | 0x0003, /* R51 - Class D Control 2 */ | ||
86 | 0x0000, /* R52 */ | ||
87 | 0x0000, /* R53 */ | ||
88 | 0x0000, /* R54 */ | ||
89 | 0x0000, /* R55 */ | ||
90 | 0x0106, /* R56 - Clocking 4 */ | ||
91 | 0x0000, /* R57 - DSP Sidetone 0 */ | ||
92 | 0x0000, /* R58 - DSP Sidetone 1 */ | ||
93 | 0x0000, /* R59 */ | ||
94 | 0x0000, /* R60 - DC Servo 0 */ | ||
95 | 0x0000, /* R61 - DC Servo 1 */ | ||
96 | 0x0000, /* R62 */ | ||
97 | 0x015E, /* R63 - DC Servo 3 */ | ||
98 | 0x0010, /* R64 */ | ||
99 | 0x0010, /* R65 - DC Servo 5 */ | ||
100 | 0x0000, /* R66 */ | ||
101 | 0x0001, /* R67 */ | ||
102 | 0x0003, /* R68 - Analogue PGA Bias */ | ||
103 | 0x0000, /* R69 - Analogue HP 0 */ | ||
104 | 0x0060, /* R70 */ | ||
105 | 0x01FB, /* R71 - Analogue HP 2 */ | ||
106 | 0x0000, /* R72 - Charge Pump 1 */ | ||
107 | 0x0065, /* R73 */ | ||
108 | 0x005F, /* R74 */ | ||
109 | 0x0059, /* R75 */ | ||
110 | 0x006B, /* R76 */ | ||
111 | 0x0038, /* R77 */ | ||
112 | 0x000C, /* R78 */ | ||
113 | 0x000A, /* R79 */ | ||
114 | 0x006B, /* R80 */ | ||
115 | 0x0000, /* R81 */ | ||
116 | 0x0000, /* R82 - Charge Pump B */ | ||
117 | 0x0087, /* R83 */ | ||
118 | 0x0000, /* R84 */ | ||
119 | 0x005C, /* R85 */ | ||
120 | 0x0000, /* R86 */ | ||
121 | 0x0000, /* R87 - Write Sequencer 1 */ | ||
122 | 0x0000, /* R88 - Write Sequencer 2 */ | ||
123 | 0x0000, /* R89 - Write Sequencer 3 */ | ||
124 | 0x0000, /* R90 - Write Sequencer 4 */ | ||
125 | 0x0000, /* R91 - Write Sequencer 5 */ | ||
126 | 0x0000, /* R92 - Write Sequencer 6 */ | ||
127 | 0x0000, /* R93 - Write Sequencer 7 */ | ||
128 | 0x0000, /* R94 */ | ||
129 | 0x0000, /* R95 */ | ||
130 | 0x0000, /* R96 */ | ||
131 | 0x0000, /* R97 */ | ||
132 | 0x0000, /* R98 */ | ||
133 | 0x0000, /* R99 */ | ||
134 | 0x0000, /* R100 */ | ||
135 | 0x0000, /* R101 */ | ||
136 | 0x0000, /* R102 */ | ||
137 | 0x0000, /* R103 */ | ||
138 | 0x0000, /* R104 */ | ||
139 | 0x0000, /* R105 */ | ||
140 | 0x0000, /* R106 */ | ||
141 | 0x0000, /* R107 */ | ||
142 | 0x0000, /* R108 */ | ||
143 | 0x0000, /* R109 */ | ||
144 | 0x0000, /* R110 */ | ||
145 | 0x0000, /* R111 */ | ||
146 | 0x0000, /* R112 */ | ||
147 | 0x0000, /* R113 */ | ||
148 | 0x0000, /* R114 */ | ||
149 | 0x0000, /* R115 */ | ||
150 | 0x0000, /* R116 */ | ||
151 | 0x0000, /* R117 */ | ||
152 | 0x0000, /* R118 */ | ||
153 | 0x0000, /* R119 */ | ||
154 | 0x0000, /* R120 */ | ||
155 | 0x0000, /* R121 */ | ||
156 | 0x0000, /* R122 */ | ||
157 | 0x0000, /* R123 */ | ||
158 | 0x0000, /* R124 */ | ||
159 | 0x0000, /* R125 */ | ||
160 | 0x0000, /* R126 */ | ||
161 | 0x0000, /* R127 */ | ||
162 | 0x0000, /* R128 */ | ||
163 | 0x0000, /* R129 */ | ||
164 | 0x0000, /* R130 */ | ||
165 | 0x0000, /* R131 */ | ||
166 | 0x0000, /* R132 */ | ||
167 | 0x0000, /* R133 */ | ||
168 | 0x0000, /* R134 */ | ||
169 | 0x0000, /* R135 */ | ||
170 | 0x0000, /* R136 */ | ||
171 | 0x0000, /* R137 */ | ||
172 | 0x0000, /* R138 */ | ||
173 | 0x0000, /* R139 */ | ||
174 | 0x0000, /* R140 */ | ||
175 | 0x0000, /* R141 */ | ||
176 | 0x0000, /* R142 */ | ||
177 | 0x0000, /* R143 */ | ||
178 | 0x0000, /* R144 */ | ||
179 | 0x0000, /* R145 */ | ||
180 | 0x0000, /* R146 */ | ||
181 | 0x0000, /* R147 */ | ||
182 | 0x0000, /* R148 */ | ||
183 | 0x0000, /* R149 */ | ||
184 | 0x0000, /* R150 */ | ||
185 | 0x0000, /* R151 */ | ||
186 | 0x0000, /* R152 */ | ||
187 | 0x0000, /* R153 */ | ||
188 | 0x0000, /* R154 */ | ||
189 | 0x0000, /* R155 */ | ||
190 | 0x0000, /* R156 */ | ||
191 | 0x0000, /* R157 */ | ||
192 | 0x0000, /* R158 */ | ||
193 | 0x0000, /* R159 */ | ||
194 | 0x0000, /* R160 */ | ||
195 | 0x0000, /* R161 */ | ||
196 | 0x0000, /* R162 */ | ||
197 | 0x0000, /* R163 */ | ||
198 | 0x0000, /* R164 */ | ||
199 | 0x0000, /* R165 */ | ||
200 | 0x0000, /* R166 */ | ||
201 | 0x0000, /* R167 */ | ||
202 | 0x0000, /* R168 */ | ||
203 | 0x0000, /* R169 */ | ||
204 | 0x0000, /* R170 */ | ||
205 | 0x0000, /* R171 */ | ||
206 | 0x0000, /* R172 */ | ||
207 | 0x0000, /* R173 */ | ||
208 | 0x0000, /* R174 */ | ||
209 | 0x0000, /* R175 */ | ||
210 | 0x0000, /* R176 */ | ||
211 | 0x0000, /* R177 */ | ||
212 | 0x0000, /* R178 */ | ||
213 | 0x0000, /* R179 */ | ||
214 | 0x0000, /* R180 */ | ||
215 | 0x0000, /* R181 */ | ||
216 | 0x0000, /* R182 */ | ||
217 | 0x0000, /* R183 */ | ||
218 | 0x0000, /* R184 */ | ||
219 | 0x0000, /* R185 */ | ||
220 | 0x0000, /* R186 */ | ||
221 | 0x0000, /* R187 */ | ||
222 | 0x0000, /* R188 */ | ||
223 | 0x0000, /* R189 */ | ||
224 | 0x0000, /* R190 */ | ||
225 | 0x0000, /* R191 */ | ||
226 | 0x0000, /* R192 */ | ||
227 | 0x0000, /* R193 */ | ||
228 | 0x0000, /* R194 */ | ||
229 | 0x0000, /* R195 */ | ||
230 | 0x0030, /* R196 */ | ||
231 | 0x0006, /* R197 */ | ||
232 | 0x0000, /* R198 */ | ||
233 | 0x0060, /* R199 */ | ||
234 | 0x0000, /* R200 */ | ||
235 | 0x003F, /* R201 */ | ||
236 | 0x0000, /* R202 */ | ||
237 | 0x0000, /* R203 */ | ||
238 | 0x0000, /* R204 */ | ||
239 | 0x0001, /* R205 */ | ||
240 | 0x0000, /* R206 */ | ||
241 | 0x0181, /* R207 */ | ||
242 | 0x0005, /* R208 */ | ||
243 | 0x0008, /* R209 */ | ||
244 | 0x0008, /* R210 */ | ||
245 | 0x0000, /* R211 */ | ||
246 | 0x013B, /* R212 */ | ||
247 | 0x0000, /* R213 */ | ||
248 | 0x0000, /* R214 */ | ||
249 | 0x0000, /* R215 */ | ||
250 | 0x0000, /* R216 */ | ||
251 | 0x0070, /* R217 */ | ||
252 | 0x0000, /* R218 */ | ||
253 | 0x0000, /* R219 */ | ||
254 | 0x0000, /* R220 */ | ||
255 | 0x0000, /* R221 */ | ||
256 | 0x0000, /* R222 */ | ||
257 | 0x0003, /* R223 */ | ||
258 | 0x0000, /* R224 */ | ||
259 | 0x0000, /* R225 */ | ||
260 | 0x0001, /* R226 */ | ||
261 | 0x0008, /* R227 */ | ||
262 | 0x0000, /* R228 */ | ||
263 | 0x0000, /* R229 */ | ||
264 | 0x0000, /* R230 */ | ||
265 | 0x0000, /* R231 */ | ||
266 | 0x0004, /* R232 */ | ||
267 | 0x0000, /* R233 */ | ||
268 | 0x0000, /* R234 */ | ||
269 | 0x0000, /* R235 */ | ||
270 | 0x0000, /* R236 */ | ||
271 | 0x0000, /* R237 */ | ||
272 | 0x0080, /* R238 */ | ||
273 | 0x0000, /* R239 */ | ||
274 | 0x0000, /* R240 */ | ||
275 | 0x0000, /* R241 */ | ||
276 | 0x0000, /* R242 */ | ||
277 | 0x0000, /* R243 */ | ||
278 | 0x0000, /* R244 */ | ||
279 | 0x0052, /* R245 */ | ||
280 | 0x0110, /* R246 */ | ||
281 | 0x0040, /* R247 */ | ||
282 | 0x0000, /* R248 */ | ||
283 | 0x0030, /* R249 */ | ||
284 | 0x0000, /* R250 */ | ||
285 | 0x0000, /* R251 */ | ||
286 | 0x0001, /* R252 - General test 1 */ | ||
287 | }; | ||
288 | |||
289 | struct wm8961_priv { | ||
290 | struct snd_soc_codec codec; | ||
291 | int sysclk; | ||
292 | u16 reg_cache[WM8961_MAX_REGISTER]; | ||
293 | }; | ||
294 | |||
295 | static int wm8961_reg_is_volatile(int reg) | ||
296 | { | ||
297 | switch (reg) { | ||
298 | case WM8961_WRITE_SEQUENCER_7: | ||
299 | case WM8961_DC_SERVO_1: | ||
300 | return 1; | ||
301 | |||
302 | default: | ||
303 | return 0; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static unsigned int wm8961_read_reg_cache(struct snd_soc_codec *codec, | ||
308 | unsigned int reg) | ||
309 | { | ||
310 | u16 *cache = codec->reg_cache; | ||
311 | BUG_ON(reg > WM8961_MAX_REGISTER); | ||
312 | return cache[reg]; | ||
313 | } | ||
314 | |||
315 | static unsigned int wm8961_read_hw(struct snd_soc_codec *codec, u8 reg) | ||
316 | { | ||
317 | struct i2c_msg xfer[2]; | ||
318 | u16 data; | ||
319 | int ret; | ||
320 | struct i2c_client *client = codec->control_data; | ||
321 | |||
322 | BUG_ON(reg > WM8961_MAX_REGISTER); | ||
323 | |||
324 | /* Write register */ | ||
325 | xfer[0].addr = client->addr; | ||
326 | xfer[0].flags = 0; | ||
327 | xfer[0].len = 1; | ||
328 | xfer[0].buf = ® | ||
329 | |||
330 | /* Read data */ | ||
331 | xfer[1].addr = client->addr; | ||
332 | xfer[1].flags = I2C_M_RD; | ||
333 | xfer[1].len = 2; | ||
334 | xfer[1].buf = (u8 *)&data; | ||
335 | |||
336 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
337 | if (ret != 2) { | ||
338 | dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | return (data >> 8) | ((data & 0xff) << 8); | ||
343 | } | ||
344 | |||
345 | static unsigned int wm8961_read(struct snd_soc_codec *codec, unsigned int reg) | ||
346 | { | ||
347 | if (wm8961_reg_is_volatile(reg)) | ||
348 | return wm8961_read_hw(codec, reg); | ||
349 | else | ||
350 | return wm8961_read_reg_cache(codec, reg); | ||
351 | } | ||
352 | |||
353 | static int wm8961_write(struct snd_soc_codec *codec, unsigned int reg, | ||
354 | unsigned int value) | ||
355 | { | ||
356 | u16 *cache = codec->reg_cache; | ||
357 | u8 data[3]; | ||
358 | |||
359 | BUG_ON(reg > WM8961_MAX_REGISTER); | ||
360 | |||
361 | if (!wm8961_reg_is_volatile(reg)) | ||
362 | cache[reg] = value; | ||
363 | |||
364 | data[0] = reg; | ||
365 | data[1] = value >> 8; | ||
366 | data[2] = value & 0x00ff; | ||
367 | |||
368 | if (codec->hw_write(codec->control_data, data, 3) == 3) | ||
369 | return 0; | ||
370 | else | ||
371 | return -EIO; | ||
372 | } | ||
373 | |||
374 | static int wm8961_reset(struct snd_soc_codec *codec) | ||
375 | { | ||
376 | return wm8961_write(codec, WM8961_SOFTWARE_RESET, 0); | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * The headphone output supports special anti-pop sequences giving | ||
381 | * silent power up and power down. | ||
382 | */ | ||
383 | static int wm8961_hp_event(struct snd_soc_dapm_widget *w, | ||
384 | struct snd_kcontrol *kcontrol, int event) | ||
385 | { | ||
386 | struct snd_soc_codec *codec = w->codec; | ||
387 | u16 hp_reg = wm8961_read(codec, WM8961_ANALOGUE_HP_0); | ||
388 | u16 cp_reg = wm8961_read(codec, WM8961_CHARGE_PUMP_1); | ||
389 | u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); | ||
390 | u16 dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); | ||
391 | int timeout = 500; | ||
392 | |||
393 | if (event & SND_SOC_DAPM_POST_PMU) { | ||
394 | /* Make sure the output is shorted */ | ||
395 | hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); | ||
396 | wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); | ||
397 | |||
398 | /* Enable the charge pump */ | ||
399 | cp_reg |= WM8961_CP_ENA; | ||
400 | wm8961_write(codec, WM8961_CHARGE_PUMP_1, cp_reg); | ||
401 | mdelay(5); | ||
402 | |||
403 | /* Enable the PGA */ | ||
404 | pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA; | ||
405 | wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); | ||
406 | |||
407 | /* Enable the amplifier */ | ||
408 | hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA; | ||
409 | wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); | ||
410 | |||
411 | /* Second stage enable */ | ||
412 | hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY; | ||
413 | wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); | ||
414 | |||
415 | /* Enable the DC servo & trigger startup */ | ||
416 | dcs_reg |= | ||
417 | WM8961_DCS_ENA_CHAN_HPR | WM8961_DCS_TRIG_STARTUP_HPR | | ||
418 | WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL; | ||
419 | dev_dbg(codec->dev, "Enabling DC servo\n"); | ||
420 | |||
421 | wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); | ||
422 | do { | ||
423 | msleep(1); | ||
424 | dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); | ||
425 | } while (--timeout && | ||
426 | dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR | | ||
427 | WM8961_DCS_TRIG_STARTUP_HPL)); | ||
428 | if (dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR | | ||
429 | WM8961_DCS_TRIG_STARTUP_HPL)) | ||
430 | dev_err(codec->dev, "DC servo timed out\n"); | ||
431 | else | ||
432 | dev_dbg(codec->dev, "DC servo startup complete\n"); | ||
433 | |||
434 | /* Enable the output stage */ | ||
435 | hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP; | ||
436 | wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); | ||
437 | |||
438 | /* Remove the short on the output stage */ | ||
439 | hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT; | ||
440 | wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); | ||
441 | } | ||
442 | |||
443 | if (event & SND_SOC_DAPM_PRE_PMD) { | ||
444 | /* Short the output */ | ||
445 | hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); | ||
446 | wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); | ||
447 | |||
448 | /* Disable the output stage */ | ||
449 | hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP); | ||
450 | wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); | ||
451 | |||
452 | /* Disable DC offset cancellation */ | ||
453 | dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR | | ||
454 | WM8961_DCS_ENA_CHAN_HPL); | ||
455 | wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); | ||
456 | |||
457 | /* Finish up */ | ||
458 | hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA | | ||
459 | WM8961_HPL_ENA_DLY | WM8961_HPL_ENA); | ||
460 | wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); | ||
461 | |||
462 | /* Disable the PGA */ | ||
463 | pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA); | ||
464 | wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); | ||
465 | |||
466 | /* Disable the charge pump */ | ||
467 | dev_dbg(codec->dev, "Disabling charge pump\n"); | ||
468 | wm8961_write(codec, WM8961_CHARGE_PUMP_1, | ||
469 | cp_reg & ~WM8961_CP_ENA); | ||
470 | } | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int wm8961_spk_event(struct snd_soc_dapm_widget *w, | ||
476 | struct snd_kcontrol *kcontrol, int event) | ||
477 | { | ||
478 | struct snd_soc_codec *codec = w->codec; | ||
479 | u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); | ||
480 | u16 spk_reg = wm8961_read(codec, WM8961_CLASS_D_CONTROL_1); | ||
481 | |||
482 | if (event & SND_SOC_DAPM_POST_PMU) { | ||
483 | /* Enable the PGA */ | ||
484 | pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA; | ||
485 | wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); | ||
486 | |||
487 | /* Enable the amplifier */ | ||
488 | spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA; | ||
489 | wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); | ||
490 | } | ||
491 | |||
492 | if (event & SND_SOC_DAPM_PRE_PMD) { | ||
493 | /* Enable the amplifier */ | ||
494 | spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA); | ||
495 | wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); | ||
496 | |||
497 | /* Enable the PGA */ | ||
498 | pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA); | ||
499 | wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); | ||
500 | } | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static const char *adc_hpf_text[] = { | ||
506 | "Hi-fi", "Voice 1", "Voice 2", "Voice 3", | ||
507 | }; | ||
508 | |||
509 | static const struct soc_enum adc_hpf = | ||
510 | SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_2, 7, 4, adc_hpf_text); | ||
511 | |||
512 | static const char *dac_deemph_text[] = { | ||
513 | "None", "32kHz", "44.1kHz", "48kHz", | ||
514 | }; | ||
515 | |||
516 | static const struct soc_enum dac_deemph = | ||
517 | SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_1, 1, 4, dac_deemph_text); | ||
518 | |||
519 | static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); | ||
520 | static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0); | ||
521 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); | ||
522 | static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); | ||
523 | static unsigned int boost_tlv[] = { | ||
524 | TLV_DB_RANGE_HEAD(4), | ||
525 | 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), | ||
526 | 1, 1, TLV_DB_SCALE_ITEM(13, 0, 0), | ||
527 | 2, 2, TLV_DB_SCALE_ITEM(20, 0, 0), | ||
528 | 3, 3, TLV_DB_SCALE_ITEM(29, 0, 0), | ||
529 | }; | ||
530 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -2325, 75, 0); | ||
531 | |||
532 | static const struct snd_kcontrol_new wm8961_snd_controls[] = { | ||
533 | SOC_DOUBLE_R_TLV("Headphone Volume", WM8961_LOUT1_VOLUME, WM8961_ROUT1_VOLUME, | ||
534 | 0, 127, 0, out_tlv), | ||
535 | SOC_DOUBLE_TLV("Headphone Secondary Volume", WM8961_ANALOGUE_HP_2, | ||
536 | 6, 3, 7, 0, hp_sec_tlv), | ||
537 | SOC_DOUBLE_R("Headphone ZC Switch", WM8961_LOUT1_VOLUME, WM8961_ROUT1_VOLUME, | ||
538 | 7, 1, 0), | ||
539 | |||
540 | SOC_DOUBLE_R_TLV("Speaker Volume", WM8961_LOUT2_VOLUME, WM8961_ROUT2_VOLUME, | ||
541 | 0, 127, 0, out_tlv), | ||
542 | SOC_DOUBLE_R("Speaker ZC Switch", WM8961_LOUT2_VOLUME, WM8961_ROUT2_VOLUME, | ||
543 | 7, 1, 0), | ||
544 | SOC_SINGLE("Speaker AC Gain", WM8961_CLASS_D_CONTROL_2, 0, 7, 0), | ||
545 | |||
546 | SOC_SINGLE("DAC x128 OSR Switch", WM8961_ADC_DAC_CONTROL_2, 0, 1, 0), | ||
547 | SOC_ENUM("DAC Deemphasis", dac_deemph), | ||
548 | SOC_SINGLE("DAC Soft Mute Switch", WM8961_ADC_DAC_CONTROL_2, 3, 1, 0), | ||
549 | |||
550 | SOC_DOUBLE_R_TLV("Sidetone Volume", WM8961_DSP_SIDETONE_0, | ||
551 | WM8961_DSP_SIDETONE_1, 4, 12, 0, sidetone_tlv), | ||
552 | |||
553 | SOC_SINGLE("ADC High Pass Filter Switch", WM8961_ADC_DAC_CONTROL_1, 0, 1, 0), | ||
554 | SOC_ENUM("ADC High Pass Filter Mode", adc_hpf), | ||
555 | |||
556 | SOC_DOUBLE_R_TLV("Capture Volume", | ||
557 | WM8961_LEFT_ADC_VOLUME, WM8961_RIGHT_ADC_VOLUME, | ||
558 | 1, 119, 0, adc_tlv), | ||
559 | SOC_DOUBLE_R_TLV("Capture Boost Volume", | ||
560 | WM8961_ADCL_SIGNAL_PATH, WM8961_ADCR_SIGNAL_PATH, | ||
561 | 4, 3, 0, boost_tlv), | ||
562 | SOC_DOUBLE_R_TLV("Capture PGA Volume", | ||
563 | WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME, | ||
564 | 0, 62, 0, pga_tlv), | ||
565 | SOC_DOUBLE_R("Capture PGA ZC Switch", | ||
566 | WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME, | ||
567 | 6, 1, 1), | ||
568 | SOC_DOUBLE_R("Capture PGA Switch", | ||
569 | WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME, | ||
570 | 7, 1, 1), | ||
571 | }; | ||
572 | |||
573 | static const char *sidetone_text[] = { | ||
574 | "None", "Left", "Right" | ||
575 | }; | ||
576 | |||
577 | static const struct soc_enum dacl_sidetone = | ||
578 | SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_0, 2, 3, sidetone_text); | ||
579 | |||
580 | static const struct soc_enum dacr_sidetone = | ||
581 | SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_1, 2, 3, sidetone_text); | ||
582 | |||
583 | static const struct snd_kcontrol_new dacl_mux = | ||
584 | SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone); | ||
585 | |||
586 | static const struct snd_kcontrol_new dacr_mux = | ||
587 | SOC_DAPM_ENUM("DACR Sidetone", dacr_sidetone); | ||
588 | |||
589 | static const struct snd_soc_dapm_widget wm8961_dapm_widgets[] = { | ||
590 | SND_SOC_DAPM_INPUT("LINPUT"), | ||
591 | SND_SOC_DAPM_INPUT("RINPUT"), | ||
592 | |||
593 | SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8961_CLOCKING2, 4, 0, NULL, 0), | ||
594 | |||
595 | SND_SOC_DAPM_PGA("Left Input", WM8961_PWR_MGMT_1, 5, 0, NULL, 0), | ||
596 | SND_SOC_DAPM_PGA("Right Input", WM8961_PWR_MGMT_1, 4, 0, NULL, 0), | ||
597 | |||
598 | SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", WM8961_PWR_MGMT_1, 3, 0), | ||
599 | SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", WM8961_PWR_MGMT_1, 2, 0), | ||
600 | |||
601 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8961_PWR_MGMT_1, 1, 0), | ||
602 | |||
603 | SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &dacl_mux), | ||
604 | SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &dacr_mux), | ||
605 | |||
606 | SND_SOC_DAPM_DAC("DACL", "HiFi Playback", WM8961_PWR_MGMT_2, 8, 0), | ||
607 | SND_SOC_DAPM_DAC("DACR", "HiFi Playback", WM8961_PWR_MGMT_2, 7, 0), | ||
608 | |||
609 | /* Handle as a mono path for DCS */ | ||
610 | SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, | ||
611 | 4, 0, NULL, 0, wm8961_hp_event, | ||
612 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
613 | SND_SOC_DAPM_PGA_E("Speaker Output", SND_SOC_NOPM, | ||
614 | 4, 0, NULL, 0, wm8961_spk_event, | ||
615 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
616 | |||
617 | SND_SOC_DAPM_OUTPUT("HP_L"), | ||
618 | SND_SOC_DAPM_OUTPUT("HP_R"), | ||
619 | SND_SOC_DAPM_OUTPUT("SPK_LN"), | ||
620 | SND_SOC_DAPM_OUTPUT("SPK_LP"), | ||
621 | SND_SOC_DAPM_OUTPUT("SPK_RN"), | ||
622 | SND_SOC_DAPM_OUTPUT("SPK_RP"), | ||
623 | }; | ||
624 | |||
625 | |||
626 | static const struct snd_soc_dapm_route audio_paths[] = { | ||
627 | { "DACL", NULL, "CLK_DSP" }, | ||
628 | { "DACL", NULL, "DACL Sidetone" }, | ||
629 | { "DACR", NULL, "CLK_DSP" }, | ||
630 | { "DACR", NULL, "DACR Sidetone" }, | ||
631 | |||
632 | { "DACL Sidetone", "Left", "ADCL" }, | ||
633 | { "DACL Sidetone", "Right", "ADCR" }, | ||
634 | |||
635 | { "DACR Sidetone", "Left", "ADCL" }, | ||
636 | { "DACR Sidetone", "Right", "ADCR" }, | ||
637 | |||
638 | { "HP_L", NULL, "Headphone Output" }, | ||
639 | { "HP_R", NULL, "Headphone Output" }, | ||
640 | { "Headphone Output", NULL, "DACL" }, | ||
641 | { "Headphone Output", NULL, "DACR" }, | ||
642 | |||
643 | { "SPK_LN", NULL, "Speaker Output" }, | ||
644 | { "SPK_LP", NULL, "Speaker Output" }, | ||
645 | { "SPK_RN", NULL, "Speaker Output" }, | ||
646 | { "SPK_RP", NULL, "Speaker Output" }, | ||
647 | |||
648 | { "Speaker Output", NULL, "DACL" }, | ||
649 | { "Speaker Output", NULL, "DACR" }, | ||
650 | |||
651 | { "ADCL", NULL, "Left Input" }, | ||
652 | { "ADCL", NULL, "CLK_DSP" }, | ||
653 | { "ADCR", NULL, "Right Input" }, | ||
654 | { "ADCR", NULL, "CLK_DSP" }, | ||
655 | |||
656 | { "Left Input", NULL, "LINPUT" }, | ||
657 | { "Right Input", NULL, "RINPUT" }, | ||
658 | |||
659 | }; | ||
660 | |||
661 | /* Values for CLK_SYS_RATE */ | ||
662 | static struct { | ||
663 | int ratio; | ||
664 | u16 val; | ||
665 | } wm8961_clk_sys_ratio[] = { | ||
666 | { 64, 0 }, | ||
667 | { 128, 1 }, | ||
668 | { 192, 2 }, | ||
669 | { 256, 3 }, | ||
670 | { 384, 4 }, | ||
671 | { 512, 5 }, | ||
672 | { 768, 6 }, | ||
673 | { 1024, 7 }, | ||
674 | { 1408, 8 }, | ||
675 | { 1536, 9 }, | ||
676 | }; | ||
677 | |||
678 | /* Values for SAMPLE_RATE */ | ||
679 | static struct { | ||
680 | int rate; | ||
681 | u16 val; | ||
682 | } wm8961_srate[] = { | ||
683 | { 48000, 0 }, | ||
684 | { 44100, 0 }, | ||
685 | { 32000, 1 }, | ||
686 | { 22050, 2 }, | ||
687 | { 24000, 2 }, | ||
688 | { 16000, 3 }, | ||
689 | { 11250, 4 }, | ||
690 | { 12000, 4 }, | ||
691 | { 8000, 5 }, | ||
692 | }; | ||
693 | |||
694 | static int wm8961_hw_params(struct snd_pcm_substream *substream, | ||
695 | struct snd_pcm_hw_params *params, | ||
696 | struct snd_soc_dai *dai) | ||
697 | { | ||
698 | struct snd_soc_codec *codec = dai->codec; | ||
699 | struct wm8961_priv *wm8961 = codec->private_data; | ||
700 | int i, best, target, fs; | ||
701 | u16 reg; | ||
702 | |||
703 | fs = params_rate(params); | ||
704 | |||
705 | if (!wm8961->sysclk) { | ||
706 | dev_err(codec->dev, "MCLK has not been specified\n"); | ||
707 | return -EINVAL; | ||
708 | } | ||
709 | |||
710 | /* Find the closest sample rate for the filters */ | ||
711 | best = 0; | ||
712 | for (i = 0; i < ARRAY_SIZE(wm8961_srate); i++) { | ||
713 | if (abs(wm8961_srate[i].rate - fs) < | ||
714 | abs(wm8961_srate[best].rate - fs)) | ||
715 | best = i; | ||
716 | } | ||
717 | reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_3); | ||
718 | reg &= ~WM8961_SAMPLE_RATE_MASK; | ||
719 | reg |= wm8961_srate[best].val; | ||
720 | wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg); | ||
721 | dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n", | ||
722 | wm8961_srate[best].rate, fs); | ||
723 | |||
724 | /* Select a CLK_SYS/fs ratio equal to or higher than required */ | ||
725 | target = wm8961->sysclk / fs; | ||
726 | |||
727 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && target < 64) { | ||
728 | dev_err(codec->dev, | ||
729 | "SYSCLK must be at least 64*fs for DAC\n"); | ||
730 | return -EINVAL; | ||
731 | } | ||
732 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && target < 256) { | ||
733 | dev_err(codec->dev, | ||
734 | "SYSCLK must be at least 256*fs for ADC\n"); | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
738 | for (i = 0; i < ARRAY_SIZE(wm8961_clk_sys_ratio); i++) { | ||
739 | if (wm8961_clk_sys_ratio[i].ratio >= target) | ||
740 | break; | ||
741 | } | ||
742 | if (i == ARRAY_SIZE(wm8961_clk_sys_ratio)) { | ||
743 | dev_err(codec->dev, "Unable to generate CLK_SYS_RATE\n"); | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | dev_dbg(codec->dev, "Selected CLK_SYS_RATE of %d for %d/%d=%d\n", | ||
747 | wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs, | ||
748 | wm8961->sysclk / fs); | ||
749 | |||
750 | reg = wm8961_read(codec, WM8961_CLOCKING_4); | ||
751 | reg &= ~WM8961_CLK_SYS_RATE_MASK; | ||
752 | reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT; | ||
753 | wm8961_write(codec, WM8961_CLOCKING_4, reg); | ||
754 | |||
755 | reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); | ||
756 | reg &= ~WM8961_WL_MASK; | ||
757 | switch (params_format(params)) { | ||
758 | case SNDRV_PCM_FORMAT_S16_LE: | ||
759 | break; | ||
760 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
761 | reg |= 1 << WM8961_WL_SHIFT; | ||
762 | break; | ||
763 | case SNDRV_PCM_FORMAT_S24_LE: | ||
764 | reg |= 2 << WM8961_WL_SHIFT; | ||
765 | break; | ||
766 | case SNDRV_PCM_FORMAT_S32_LE: | ||
767 | reg |= 3 << WM8961_WL_SHIFT; | ||
768 | break; | ||
769 | default: | ||
770 | return -EINVAL; | ||
771 | } | ||
772 | wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, reg); | ||
773 | |||
774 | /* Sloping stop-band filter is recommended for <= 24kHz */ | ||
775 | reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); | ||
776 | if (fs <= 24000) | ||
777 | reg |= WM8961_DACSLOPE; | ||
778 | else | ||
779 | reg &= WM8961_DACSLOPE; | ||
780 | wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
786 | unsigned int freq, | ||
787 | int dir) | ||
788 | { | ||
789 | struct snd_soc_codec *codec = dai->codec; | ||
790 | struct wm8961_priv *wm8961 = codec->private_data; | ||
791 | u16 reg = wm8961_read(codec, WM8961_CLOCKING1); | ||
792 | |||
793 | if (freq > 33000000) { | ||
794 | dev_err(codec->dev, "MCLK must be <33MHz\n"); | ||
795 | return -EINVAL; | ||
796 | } | ||
797 | |||
798 | if (freq > 16500000) { | ||
799 | dev_dbg(codec->dev, "Using MCLK/2 for %dHz MCLK\n", freq); | ||
800 | reg |= WM8961_MCLKDIV; | ||
801 | freq /= 2; | ||
802 | } else { | ||
803 | dev_dbg(codec->dev, "Using MCLK/1 for %dHz MCLK\n", freq); | ||
804 | reg &= WM8961_MCLKDIV; | ||
805 | } | ||
806 | |||
807 | wm8961_write(codec, WM8961_CLOCKING1, reg); | ||
808 | |||
809 | wm8961->sysclk = freq; | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
815 | { | ||
816 | struct snd_soc_codec *codec = dai->codec; | ||
817 | u16 aif = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); | ||
818 | |||
819 | aif &= ~(WM8961_BCLKINV | WM8961_LRP | | ||
820 | WM8961_MS | WM8961_FORMAT_MASK); | ||
821 | |||
822 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
823 | case SND_SOC_DAIFMT_CBM_CFM: | ||
824 | aif |= WM8961_MS; | ||
825 | break; | ||
826 | case SND_SOC_DAIFMT_CBS_CFS: | ||
827 | break; | ||
828 | default: | ||
829 | return -EINVAL; | ||
830 | } | ||
831 | |||
832 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
833 | case SND_SOC_DAIFMT_RIGHT_J: | ||
834 | break; | ||
835 | |||
836 | case SND_SOC_DAIFMT_LEFT_J: | ||
837 | aif |= 1; | ||
838 | break; | ||
839 | |||
840 | case SND_SOC_DAIFMT_I2S: | ||
841 | aif |= 2; | ||
842 | break; | ||
843 | |||
844 | case SND_SOC_DAIFMT_DSP_B: | ||
845 | aif |= WM8961_LRP; | ||
846 | case SND_SOC_DAIFMT_DSP_A: | ||
847 | aif |= 3; | ||
848 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
849 | case SND_SOC_DAIFMT_NB_NF: | ||
850 | case SND_SOC_DAIFMT_IB_NF: | ||
851 | break; | ||
852 | default: | ||
853 | return -EINVAL; | ||
854 | } | ||
855 | break; | ||
856 | |||
857 | default: | ||
858 | return -EINVAL; | ||
859 | } | ||
860 | |||
861 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
862 | case SND_SOC_DAIFMT_NB_NF: | ||
863 | break; | ||
864 | case SND_SOC_DAIFMT_NB_IF: | ||
865 | aif |= WM8961_LRP; | ||
866 | break; | ||
867 | case SND_SOC_DAIFMT_IB_NF: | ||
868 | aif |= WM8961_BCLKINV; | ||
869 | break; | ||
870 | case SND_SOC_DAIFMT_IB_IF: | ||
871 | aif |= WM8961_BCLKINV | WM8961_LRP; | ||
872 | break; | ||
873 | default: | ||
874 | return -EINVAL; | ||
875 | } | ||
876 | |||
877 | return wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, aif); | ||
878 | } | ||
879 | |||
880 | static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
881 | { | ||
882 | struct snd_soc_codec *codec = dai->codec; | ||
883 | u16 reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_2); | ||
884 | |||
885 | if (tristate) | ||
886 | reg |= WM8961_TRIS; | ||
887 | else | ||
888 | reg &= ~WM8961_TRIS; | ||
889 | |||
890 | return wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg); | ||
891 | } | ||
892 | |||
893 | static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute) | ||
894 | { | ||
895 | struct snd_soc_codec *codec = dai->codec; | ||
896 | u16 reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_1); | ||
897 | |||
898 | if (mute) | ||
899 | reg |= WM8961_DACMU; | ||
900 | else | ||
901 | reg &= ~WM8961_DACMU; | ||
902 | |||
903 | msleep(17); | ||
904 | |||
905 | return wm8961_write(codec, WM8961_ADC_DAC_CONTROL_1, reg); | ||
906 | } | ||
907 | |||
908 | static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) | ||
909 | { | ||
910 | struct snd_soc_codec *codec = dai->codec; | ||
911 | u16 reg; | ||
912 | |||
913 | switch (div_id) { | ||
914 | case WM8961_BCLK: | ||
915 | reg = wm8961_read(codec, WM8961_CLOCKING2); | ||
916 | reg &= ~WM8961_BCLKDIV_MASK; | ||
917 | reg |= div; | ||
918 | wm8961_write(codec, WM8961_CLOCKING2, reg); | ||
919 | break; | ||
920 | |||
921 | case WM8961_LRCLK: | ||
922 | reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_2); | ||
923 | reg &= ~WM8961_LRCLK_RATE_MASK; | ||
924 | reg |= div; | ||
925 | wm8961_write(codec, WM8961_AUDIO_INTERFACE_2, reg); | ||
926 | break; | ||
927 | |||
928 | default: | ||
929 | return -EINVAL; | ||
930 | } | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static int wm8961_set_bias_level(struct snd_soc_codec *codec, | ||
936 | enum snd_soc_bias_level level) | ||
937 | { | ||
938 | u16 reg; | ||
939 | |||
940 | /* This is all slightly unusual since we have no bypass paths | ||
941 | * and the output amplifier structure means we can just slam | ||
942 | * the biases straight up rather than having to ramp them | ||
943 | * slowly. | ||
944 | */ | ||
945 | switch (level) { | ||
946 | case SND_SOC_BIAS_ON: | ||
947 | break; | ||
948 | |||
949 | case SND_SOC_BIAS_PREPARE: | ||
950 | if (codec->bias_level == SND_SOC_BIAS_STANDBY) { | ||
951 | /* Enable bias generation */ | ||
952 | reg = wm8961_read(codec, WM8961_ANTI_POP); | ||
953 | reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; | ||
954 | wm8961_write(codec, WM8961_ANTI_POP, reg); | ||
955 | |||
956 | /* VMID=2*50k, VREF */ | ||
957 | reg = wm8961_read(codec, WM8961_PWR_MGMT_1); | ||
958 | reg &= ~WM8961_VMIDSEL_MASK; | ||
959 | reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF; | ||
960 | wm8961_write(codec, WM8961_PWR_MGMT_1, reg); | ||
961 | } | ||
962 | break; | ||
963 | |||
964 | case SND_SOC_BIAS_STANDBY: | ||
965 | if (codec->bias_level == SND_SOC_BIAS_PREPARE) { | ||
966 | /* VREF off */ | ||
967 | reg = wm8961_read(codec, WM8961_PWR_MGMT_1); | ||
968 | reg &= ~WM8961_VREF; | ||
969 | wm8961_write(codec, WM8961_PWR_MGMT_1, reg); | ||
970 | |||
971 | /* Bias generation off */ | ||
972 | reg = wm8961_read(codec, WM8961_ANTI_POP); | ||
973 | reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN); | ||
974 | wm8961_write(codec, WM8961_ANTI_POP, reg); | ||
975 | |||
976 | /* VMID off */ | ||
977 | reg = wm8961_read(codec, WM8961_PWR_MGMT_1); | ||
978 | reg &= ~WM8961_VMIDSEL_MASK; | ||
979 | wm8961_write(codec, WM8961_PWR_MGMT_1, reg); | ||
980 | } | ||
981 | break; | ||
982 | |||
983 | case SND_SOC_BIAS_OFF: | ||
984 | break; | ||
985 | } | ||
986 | |||
987 | codec->bias_level = level; | ||
988 | |||
989 | return 0; | ||
990 | } | ||
991 | |||
992 | |||
993 | #define WM8961_RATES SNDRV_PCM_RATE_8000_48000 | ||
994 | |||
995 | #define WM8961_FORMATS \ | ||
996 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
997 | SNDRV_PCM_FMTBIT_S24_LE) | ||
998 | |||
999 | static struct snd_soc_dai_ops wm8961_dai_ops = { | ||
1000 | .hw_params = wm8961_hw_params, | ||
1001 | .set_sysclk = wm8961_set_sysclk, | ||
1002 | .set_fmt = wm8961_set_fmt, | ||
1003 | .digital_mute = wm8961_digital_mute, | ||
1004 | .set_tristate = wm8961_set_tristate, | ||
1005 | .set_clkdiv = wm8961_set_clkdiv, | ||
1006 | }; | ||
1007 | |||
1008 | struct snd_soc_dai wm8961_dai = { | ||
1009 | .name = "WM8961", | ||
1010 | .playback = { | ||
1011 | .stream_name = "HiFi Playback", | ||
1012 | .channels_min = 1, | ||
1013 | .channels_max = 2, | ||
1014 | .rates = WM8961_RATES, | ||
1015 | .formats = WM8961_FORMATS,}, | ||
1016 | .capture = { | ||
1017 | .stream_name = "HiFi Capture", | ||
1018 | .channels_min = 1, | ||
1019 | .channels_max = 2, | ||
1020 | .rates = WM8961_RATES, | ||
1021 | .formats = WM8961_FORMATS,}, | ||
1022 | .ops = &wm8961_dai_ops, | ||
1023 | }; | ||
1024 | EXPORT_SYMBOL_GPL(wm8961_dai); | ||
1025 | |||
1026 | |||
1027 | static struct snd_soc_codec *wm8961_codec; | ||
1028 | |||
1029 | static int wm8961_probe(struct platform_device *pdev) | ||
1030 | { | ||
1031 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1032 | struct snd_soc_codec *codec; | ||
1033 | int ret = 0; | ||
1034 | |||
1035 | if (wm8961_codec == NULL) { | ||
1036 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
1037 | return -ENODEV; | ||
1038 | } | ||
1039 | |||
1040 | socdev->card->codec = wm8961_codec; | ||
1041 | codec = wm8961_codec; | ||
1042 | |||
1043 | /* register pcms */ | ||
1044 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1045 | if (ret < 0) { | ||
1046 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
1047 | goto pcm_err; | ||
1048 | } | ||
1049 | |||
1050 | snd_soc_add_controls(codec, wm8961_snd_controls, | ||
1051 | ARRAY_SIZE(wm8961_snd_controls)); | ||
1052 | snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets, | ||
1053 | ARRAY_SIZE(wm8961_dapm_widgets)); | ||
1054 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); | ||
1055 | snd_soc_dapm_new_widgets(codec); | ||
1056 | |||
1057 | ret = snd_soc_init_card(socdev); | ||
1058 | if (ret < 0) { | ||
1059 | dev_err(codec->dev, "failed to register card: %d\n", ret); | ||
1060 | goto card_err; | ||
1061 | } | ||
1062 | |||
1063 | return ret; | ||
1064 | |||
1065 | card_err: | ||
1066 | snd_soc_free_pcms(socdev); | ||
1067 | snd_soc_dapm_free(socdev); | ||
1068 | pcm_err: | ||
1069 | return ret; | ||
1070 | } | ||
1071 | |||
1072 | static int wm8961_remove(struct platform_device *pdev) | ||
1073 | { | ||
1074 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1075 | |||
1076 | snd_soc_free_pcms(socdev); | ||
1077 | snd_soc_dapm_free(socdev); | ||
1078 | |||
1079 | return 0; | ||
1080 | } | ||
1081 | |||
1082 | #ifdef CONFIG_PM | ||
1083 | static int wm8961_suspend(struct platform_device *pdev, pm_message_t state) | ||
1084 | { | ||
1085 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1086 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1087 | |||
1088 | wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1089 | |||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | static int wm8961_resume(struct platform_device *pdev) | ||
1094 | { | ||
1095 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1096 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1097 | u16 *reg_cache = codec->reg_cache; | ||
1098 | int i; | ||
1099 | |||
1100 | for (i = 0; i < codec->reg_cache_size; i++) { | ||
1101 | if (i == WM8961_SOFTWARE_RESET) | ||
1102 | continue; | ||
1103 | |||
1104 | wm8961_write(codec, i, reg_cache[i]); | ||
1105 | } | ||
1106 | |||
1107 | wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1108 | |||
1109 | return 0; | ||
1110 | } | ||
1111 | #else | ||
1112 | #define wm8961_suspend NULL | ||
1113 | #define wm8961_resume NULL | ||
1114 | #endif | ||
1115 | |||
1116 | struct snd_soc_codec_device soc_codec_dev_wm8961 = { | ||
1117 | .probe = wm8961_probe, | ||
1118 | .remove = wm8961_remove, | ||
1119 | .suspend = wm8961_suspend, | ||
1120 | .resume = wm8961_resume, | ||
1121 | }; | ||
1122 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8961); | ||
1123 | |||
1124 | static int wm8961_register(struct wm8961_priv *wm8961) | ||
1125 | { | ||
1126 | struct snd_soc_codec *codec = &wm8961->codec; | ||
1127 | int ret; | ||
1128 | u16 reg; | ||
1129 | |||
1130 | if (wm8961_codec) { | ||
1131 | dev_err(codec->dev, "Another WM8961 is registered\n"); | ||
1132 | ret = -EINVAL; | ||
1133 | goto err; | ||
1134 | } | ||
1135 | |||
1136 | mutex_init(&codec->mutex); | ||
1137 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1138 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1139 | |||
1140 | codec->private_data = wm8961; | ||
1141 | codec->name = "WM8961"; | ||
1142 | codec->owner = THIS_MODULE; | ||
1143 | codec->read = wm8961_read; | ||
1144 | codec->write = wm8961_write; | ||
1145 | codec->dai = &wm8961_dai; | ||
1146 | codec->num_dai = 1; | ||
1147 | codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache); | ||
1148 | codec->reg_cache = &wm8961->reg_cache; | ||
1149 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1150 | codec->set_bias_level = wm8961_set_bias_level; | ||
1151 | |||
1152 | memcpy(codec->reg_cache, wm8961_reg_defaults, | ||
1153 | sizeof(wm8961_reg_defaults)); | ||
1154 | |||
1155 | reg = wm8961_read_hw(codec, WM8961_SOFTWARE_RESET); | ||
1156 | if (reg != 0x1801) { | ||
1157 | dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg); | ||
1158 | ret = -EINVAL; | ||
1159 | goto err; | ||
1160 | } | ||
1161 | |||
1162 | reg = wm8961_read_hw(codec, WM8961_RIGHT_INPUT_VOLUME); | ||
1163 | dev_info(codec->dev, "WM8961 family %d revision %c\n", | ||
1164 | (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT, | ||
1165 | ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT) | ||
1166 | + 'A'); | ||
1167 | |||
1168 | ret = wm8961_reset(codec); | ||
1169 | if (ret < 0) { | ||
1170 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
1171 | return ret; | ||
1172 | } | ||
1173 | |||
1174 | /* Enable class W */ | ||
1175 | reg = wm8961_read(codec, WM8961_CHARGE_PUMP_B); | ||
1176 | reg |= WM8961_CP_DYN_PWR_MASK; | ||
1177 | wm8961_write(codec, WM8961_CHARGE_PUMP_B, reg); | ||
1178 | |||
1179 | /* Latch volume update bits (right channel only, we always | ||
1180 | * write both out) and default ZC on. */ | ||
1181 | reg = wm8961_read(codec, WM8961_ROUT1_VOLUME); | ||
1182 | wm8961_write(codec, WM8961_ROUT1_VOLUME, | ||
1183 | reg | WM8961_LO1ZC | WM8961_OUT1VU); | ||
1184 | wm8961_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC); | ||
1185 | reg = wm8961_read(codec, WM8961_ROUT2_VOLUME); | ||
1186 | wm8961_write(codec, WM8961_ROUT2_VOLUME, | ||
1187 | reg | WM8961_SPKRZC | WM8961_SPKVU); | ||
1188 | wm8961_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC); | ||
1189 | |||
1190 | reg = wm8961_read(codec, WM8961_RIGHT_ADC_VOLUME); | ||
1191 | wm8961_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU); | ||
1192 | reg = wm8961_read(codec, WM8961_RIGHT_INPUT_VOLUME); | ||
1193 | wm8961_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU); | ||
1194 | |||
1195 | /* Use soft mute by default */ | ||
1196 | reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); | ||
1197 | reg |= WM8961_DACSMM; | ||
1198 | wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); | ||
1199 | |||
1200 | /* Use automatic clocking mode by default; for now this is all | ||
1201 | * we support. | ||
1202 | */ | ||
1203 | reg = wm8961_read(codec, WM8961_CLOCKING_3); | ||
1204 | reg &= ~WM8961_MANUAL_MODE; | ||
1205 | wm8961_write(codec, WM8961_CLOCKING_3, reg); | ||
1206 | |||
1207 | wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1208 | |||
1209 | wm8961_dai.dev = codec->dev; | ||
1210 | |||
1211 | wm8961_codec = codec; | ||
1212 | |||
1213 | ret = snd_soc_register_codec(codec); | ||
1214 | if (ret != 0) { | ||
1215 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
1216 | return ret; | ||
1217 | } | ||
1218 | |||
1219 | ret = snd_soc_register_dai(&wm8961_dai); | ||
1220 | if (ret != 0) { | ||
1221 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
1222 | snd_soc_unregister_codec(codec); | ||
1223 | return ret; | ||
1224 | } | ||
1225 | |||
1226 | return 0; | ||
1227 | |||
1228 | err: | ||
1229 | kfree(wm8961); | ||
1230 | return ret; | ||
1231 | } | ||
1232 | |||
1233 | static void wm8961_unregister(struct wm8961_priv *wm8961) | ||
1234 | { | ||
1235 | wm8961_set_bias_level(&wm8961->codec, SND_SOC_BIAS_OFF); | ||
1236 | snd_soc_unregister_dai(&wm8961_dai); | ||
1237 | snd_soc_unregister_codec(&wm8961->codec); | ||
1238 | kfree(wm8961); | ||
1239 | wm8961_codec = NULL; | ||
1240 | } | ||
1241 | |||
1242 | static __devinit int wm8961_i2c_probe(struct i2c_client *i2c, | ||
1243 | const struct i2c_device_id *id) | ||
1244 | { | ||
1245 | struct wm8961_priv *wm8961; | ||
1246 | struct snd_soc_codec *codec; | ||
1247 | |||
1248 | wm8961 = kzalloc(sizeof(struct wm8961_priv), GFP_KERNEL); | ||
1249 | if (wm8961 == NULL) | ||
1250 | return -ENOMEM; | ||
1251 | |||
1252 | codec = &wm8961->codec; | ||
1253 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1254 | |||
1255 | i2c_set_clientdata(i2c, wm8961); | ||
1256 | codec->control_data = i2c; | ||
1257 | |||
1258 | codec->dev = &i2c->dev; | ||
1259 | |||
1260 | return wm8961_register(wm8961); | ||
1261 | } | ||
1262 | |||
1263 | static __devexit int wm8961_i2c_remove(struct i2c_client *client) | ||
1264 | { | ||
1265 | struct wm8961_priv *wm8961 = i2c_get_clientdata(client); | ||
1266 | wm8961_unregister(wm8961); | ||
1267 | return 0; | ||
1268 | } | ||
1269 | |||
1270 | #ifdef CONFIG_PM | ||
1271 | static int wm8961_i2c_suspend(struct i2c_client *client) | ||
1272 | { | ||
1273 | return snd_soc_suspend_device(&client->dev); | ||
1274 | } | ||
1275 | |||
1276 | static int wm8961_i2c_resume(struct i2c_client *client) | ||
1277 | { | ||
1278 | return snd_soc_resume_device(&client->dev); | ||
1279 | } | ||
1280 | #else | ||
1281 | #define wm8961_i2c_suspend NULL | ||
1282 | #define wm8961_i2c_resume NULL | ||
1283 | #endif | ||
1284 | |||
1285 | static const struct i2c_device_id wm8961_i2c_id[] = { | ||
1286 | { "wm8961", 0 }, | ||
1287 | { } | ||
1288 | }; | ||
1289 | MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id); | ||
1290 | |||
1291 | static struct i2c_driver wm8961_i2c_driver = { | ||
1292 | .driver = { | ||
1293 | .name = "wm8961", | ||
1294 | .owner = THIS_MODULE, | ||
1295 | }, | ||
1296 | .probe = wm8961_i2c_probe, | ||
1297 | .remove = __devexit_p(wm8961_i2c_remove), | ||
1298 | .suspend = wm8961_i2c_suspend, | ||
1299 | .resume = wm8961_i2c_resume, | ||
1300 | .id_table = wm8961_i2c_id, | ||
1301 | }; | ||
1302 | |||
1303 | static int __init wm8961_modinit(void) | ||
1304 | { | ||
1305 | int ret; | ||
1306 | |||
1307 | ret = i2c_add_driver(&wm8961_i2c_driver); | ||
1308 | if (ret != 0) { | ||
1309 | printk(KERN_ERR "Failed to register WM8961 I2C driver: %d\n", | ||
1310 | ret); | ||
1311 | } | ||
1312 | |||
1313 | return ret; | ||
1314 | } | ||
1315 | module_init(wm8961_modinit); | ||
1316 | |||
1317 | static void __exit wm8961_exit(void) | ||
1318 | { | ||
1319 | i2c_del_driver(&wm8961_i2c_driver); | ||
1320 | } | ||
1321 | module_exit(wm8961_exit); | ||
1322 | |||
1323 | |||
1324 | MODULE_DESCRIPTION("ASoC WM8961 driver"); | ||
1325 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
1326 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8961.h b/sound/soc/codecs/wm8961.h new file mode 100644 index 000000000000..5513bfd720d6 --- /dev/null +++ b/sound/soc/codecs/wm8961.h | |||
@@ -0,0 +1,866 @@ | |||
1 | /* | ||
2 | * wm8961.h -- WM8961 Soc Audio driver | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _WM8961_H | ||
10 | #define _WM8961_H | ||
11 | |||
12 | #include <sound/soc.h> | ||
13 | |||
14 | extern struct snd_soc_codec_device soc_codec_dev_wm8961; | ||
15 | extern struct snd_soc_dai wm8961_dai; | ||
16 | |||
17 | #define WM8961_BCLK 1 | ||
18 | #define WM8961_LRCLK 2 | ||
19 | |||
20 | #define WM8961_BCLK_DIV_1 0 | ||
21 | #define WM8961_BCLK_DIV_1_5 1 | ||
22 | #define WM8961_BCLK_DIV_2 2 | ||
23 | #define WM8961_BCLK_DIV_3 3 | ||
24 | #define WM8961_BCLK_DIV_4 4 | ||
25 | #define WM8961_BCLK_DIV_5_5 5 | ||
26 | #define WM8961_BCLK_DIV_6 6 | ||
27 | #define WM8961_BCLK_DIV_8 7 | ||
28 | #define WM8961_BCLK_DIV_11 8 | ||
29 | #define WM8961_BCLK_DIV_12 9 | ||
30 | #define WM8961_BCLK_DIV_16 10 | ||
31 | #define WM8961_BCLK_DIV_24 11 | ||
32 | #define WM8961_BCLK_DIV_32 13 | ||
33 | |||
34 | |||
35 | /* | ||
36 | * Register values. | ||
37 | */ | ||
38 | #define WM8961_LEFT_INPUT_VOLUME 0x00 | ||
39 | #define WM8961_RIGHT_INPUT_VOLUME 0x01 | ||
40 | #define WM8961_LOUT1_VOLUME 0x02 | ||
41 | #define WM8961_ROUT1_VOLUME 0x03 | ||
42 | #define WM8961_CLOCKING1 0x04 | ||
43 | #define WM8961_ADC_DAC_CONTROL_1 0x05 | ||
44 | #define WM8961_ADC_DAC_CONTROL_2 0x06 | ||
45 | #define WM8961_AUDIO_INTERFACE_0 0x07 | ||
46 | #define WM8961_CLOCKING2 0x08 | ||
47 | #define WM8961_AUDIO_INTERFACE_1 0x09 | ||
48 | #define WM8961_LEFT_DAC_VOLUME 0x0A | ||
49 | #define WM8961_RIGHT_DAC_VOLUME 0x0B | ||
50 | #define WM8961_AUDIO_INTERFACE_2 0x0E | ||
51 | #define WM8961_SOFTWARE_RESET 0x0F | ||
52 | #define WM8961_ALC1 0x11 | ||
53 | #define WM8961_ALC2 0x12 | ||
54 | #define WM8961_ALC3 0x13 | ||
55 | #define WM8961_NOISE_GATE 0x14 | ||
56 | #define WM8961_LEFT_ADC_VOLUME 0x15 | ||
57 | #define WM8961_RIGHT_ADC_VOLUME 0x16 | ||
58 | #define WM8961_ADDITIONAL_CONTROL_1 0x17 | ||
59 | #define WM8961_ADDITIONAL_CONTROL_2 0x18 | ||
60 | #define WM8961_PWR_MGMT_1 0x19 | ||
61 | #define WM8961_PWR_MGMT_2 0x1A | ||
62 | #define WM8961_ADDITIONAL_CONTROL_3 0x1B | ||
63 | #define WM8961_ANTI_POP 0x1C | ||
64 | #define WM8961_CLOCKING_3 0x1E | ||
65 | #define WM8961_ADCL_SIGNAL_PATH 0x20 | ||
66 | #define WM8961_ADCR_SIGNAL_PATH 0x21 | ||
67 | #define WM8961_LOUT2_VOLUME 0x28 | ||
68 | #define WM8961_ROUT2_VOLUME 0x29 | ||
69 | #define WM8961_PWR_MGMT_3 0x2F | ||
70 | #define WM8961_ADDITIONAL_CONTROL_4 0x30 | ||
71 | #define WM8961_CLASS_D_CONTROL_1 0x31 | ||
72 | #define WM8961_CLASS_D_CONTROL_2 0x33 | ||
73 | #define WM8961_CLOCKING_4 0x38 | ||
74 | #define WM8961_DSP_SIDETONE_0 0x39 | ||
75 | #define WM8961_DSP_SIDETONE_1 0x3A | ||
76 | #define WM8961_DC_SERVO_0 0x3C | ||
77 | #define WM8961_DC_SERVO_1 0x3D | ||
78 | #define WM8961_DC_SERVO_3 0x3F | ||
79 | #define WM8961_DC_SERVO_5 0x41 | ||
80 | #define WM8961_ANALOGUE_PGA_BIAS 0x44 | ||
81 | #define WM8961_ANALOGUE_HP_0 0x45 | ||
82 | #define WM8961_ANALOGUE_HP_2 0x47 | ||
83 | #define WM8961_CHARGE_PUMP_1 0x48 | ||
84 | #define WM8961_CHARGE_PUMP_B 0x52 | ||
85 | #define WM8961_WRITE_SEQUENCER_1 0x57 | ||
86 | #define WM8961_WRITE_SEQUENCER_2 0x58 | ||
87 | #define WM8961_WRITE_SEQUENCER_3 0x59 | ||
88 | #define WM8961_WRITE_SEQUENCER_4 0x5A | ||
89 | #define WM8961_WRITE_SEQUENCER_5 0x5B | ||
90 | #define WM8961_WRITE_SEQUENCER_6 0x5C | ||
91 | #define WM8961_WRITE_SEQUENCER_7 0x5D | ||
92 | #define WM8961_GENERAL_TEST_1 0xFC | ||
93 | |||
94 | |||
95 | /* | ||
96 | * Field Definitions. | ||
97 | */ | ||
98 | |||
99 | /* | ||
100 | * R0 (0x00) - Left Input volume | ||
101 | */ | ||
102 | #define WM8961_IPVU 0x0100 /* IPVU */ | ||
103 | #define WM8961_IPVU_MASK 0x0100 /* IPVU */ | ||
104 | #define WM8961_IPVU_SHIFT 8 /* IPVU */ | ||
105 | #define WM8961_IPVU_WIDTH 1 /* IPVU */ | ||
106 | #define WM8961_LINMUTE 0x0080 /* LINMUTE */ | ||
107 | #define WM8961_LINMUTE_MASK 0x0080 /* LINMUTE */ | ||
108 | #define WM8961_LINMUTE_SHIFT 7 /* LINMUTE */ | ||
109 | #define WM8961_LINMUTE_WIDTH 1 /* LINMUTE */ | ||
110 | #define WM8961_LIZC 0x0040 /* LIZC */ | ||
111 | #define WM8961_LIZC_MASK 0x0040 /* LIZC */ | ||
112 | #define WM8961_LIZC_SHIFT 6 /* LIZC */ | ||
113 | #define WM8961_LIZC_WIDTH 1 /* LIZC */ | ||
114 | #define WM8961_LINVOL_MASK 0x003F /* LINVOL - [5:0] */ | ||
115 | #define WM8961_LINVOL_SHIFT 0 /* LINVOL - [5:0] */ | ||
116 | #define WM8961_LINVOL_WIDTH 6 /* LINVOL - [5:0] */ | ||
117 | |||
118 | /* | ||
119 | * R1 (0x01) - Right Input volume | ||
120 | */ | ||
121 | #define WM8961_DEVICE_ID_MASK 0xF000 /* DEVICE_ID - [15:12] */ | ||
122 | #define WM8961_DEVICE_ID_SHIFT 12 /* DEVICE_ID - [15:12] */ | ||
123 | #define WM8961_DEVICE_ID_WIDTH 4 /* DEVICE_ID - [15:12] */ | ||
124 | #define WM8961_CHIP_REV_MASK 0x0E00 /* CHIP_REV - [11:9] */ | ||
125 | #define WM8961_CHIP_REV_SHIFT 9 /* CHIP_REV - [11:9] */ | ||
126 | #define WM8961_CHIP_REV_WIDTH 3 /* CHIP_REV - [11:9] */ | ||
127 | #define WM8961_IPVU 0x0100 /* IPVU */ | ||
128 | #define WM8961_IPVU_MASK 0x0100 /* IPVU */ | ||
129 | #define WM8961_IPVU_SHIFT 8 /* IPVU */ | ||
130 | #define WM8961_IPVU_WIDTH 1 /* IPVU */ | ||
131 | #define WM8961_RINMUTE 0x0080 /* RINMUTE */ | ||
132 | #define WM8961_RINMUTE_MASK 0x0080 /* RINMUTE */ | ||
133 | #define WM8961_RINMUTE_SHIFT 7 /* RINMUTE */ | ||
134 | #define WM8961_RINMUTE_WIDTH 1 /* RINMUTE */ | ||
135 | #define WM8961_RIZC 0x0040 /* RIZC */ | ||
136 | #define WM8961_RIZC_MASK 0x0040 /* RIZC */ | ||
137 | #define WM8961_RIZC_SHIFT 6 /* RIZC */ | ||
138 | #define WM8961_RIZC_WIDTH 1 /* RIZC */ | ||
139 | #define WM8961_RINVOL_MASK 0x003F /* RINVOL - [5:0] */ | ||
140 | #define WM8961_RINVOL_SHIFT 0 /* RINVOL - [5:0] */ | ||
141 | #define WM8961_RINVOL_WIDTH 6 /* RINVOL - [5:0] */ | ||
142 | |||
143 | /* | ||
144 | * R2 (0x02) - LOUT1 volume | ||
145 | */ | ||
146 | #define WM8961_OUT1VU 0x0100 /* OUT1VU */ | ||
147 | #define WM8961_OUT1VU_MASK 0x0100 /* OUT1VU */ | ||
148 | #define WM8961_OUT1VU_SHIFT 8 /* OUT1VU */ | ||
149 | #define WM8961_OUT1VU_WIDTH 1 /* OUT1VU */ | ||
150 | #define WM8961_LO1ZC 0x0080 /* LO1ZC */ | ||
151 | #define WM8961_LO1ZC_MASK 0x0080 /* LO1ZC */ | ||
152 | #define WM8961_LO1ZC_SHIFT 7 /* LO1ZC */ | ||
153 | #define WM8961_LO1ZC_WIDTH 1 /* LO1ZC */ | ||
154 | #define WM8961_LOUT1VOL_MASK 0x007F /* LOUT1VOL - [6:0] */ | ||
155 | #define WM8961_LOUT1VOL_SHIFT 0 /* LOUT1VOL - [6:0] */ | ||
156 | #define WM8961_LOUT1VOL_WIDTH 7 /* LOUT1VOL - [6:0] */ | ||
157 | |||
158 | /* | ||
159 | * R3 (0x03) - ROUT1 volume | ||
160 | */ | ||
161 | #define WM8961_OUT1VU 0x0100 /* OUT1VU */ | ||
162 | #define WM8961_OUT1VU_MASK 0x0100 /* OUT1VU */ | ||
163 | #define WM8961_OUT1VU_SHIFT 8 /* OUT1VU */ | ||
164 | #define WM8961_OUT1VU_WIDTH 1 /* OUT1VU */ | ||
165 | #define WM8961_RO1ZC 0x0080 /* RO1ZC */ | ||
166 | #define WM8961_RO1ZC_MASK 0x0080 /* RO1ZC */ | ||
167 | #define WM8961_RO1ZC_SHIFT 7 /* RO1ZC */ | ||
168 | #define WM8961_RO1ZC_WIDTH 1 /* RO1ZC */ | ||
169 | #define WM8961_ROUT1VOL_MASK 0x007F /* ROUT1VOL - [6:0] */ | ||
170 | #define WM8961_ROUT1VOL_SHIFT 0 /* ROUT1VOL - [6:0] */ | ||
171 | #define WM8961_ROUT1VOL_WIDTH 7 /* ROUT1VOL - [6:0] */ | ||
172 | |||
173 | /* | ||
174 | * R4 (0x04) - Clocking1 | ||
175 | */ | ||
176 | #define WM8961_ADCDIV_MASK 0x01C0 /* ADCDIV - [8:6] */ | ||
177 | #define WM8961_ADCDIV_SHIFT 6 /* ADCDIV - [8:6] */ | ||
178 | #define WM8961_ADCDIV_WIDTH 3 /* ADCDIV - [8:6] */ | ||
179 | #define WM8961_DACDIV_MASK 0x0038 /* DACDIV - [5:3] */ | ||
180 | #define WM8961_DACDIV_SHIFT 3 /* DACDIV - [5:3] */ | ||
181 | #define WM8961_DACDIV_WIDTH 3 /* DACDIV - [5:3] */ | ||
182 | #define WM8961_MCLKDIV 0x0004 /* MCLKDIV */ | ||
183 | #define WM8961_MCLKDIV_MASK 0x0004 /* MCLKDIV */ | ||
184 | #define WM8961_MCLKDIV_SHIFT 2 /* MCLKDIV */ | ||
185 | #define WM8961_MCLKDIV_WIDTH 1 /* MCLKDIV */ | ||
186 | |||
187 | /* | ||
188 | * R5 (0x05) - ADC & DAC Control 1 | ||
189 | */ | ||
190 | #define WM8961_ADCPOL_MASK 0x0060 /* ADCPOL - [6:5] */ | ||
191 | #define WM8961_ADCPOL_SHIFT 5 /* ADCPOL - [6:5] */ | ||
192 | #define WM8961_ADCPOL_WIDTH 2 /* ADCPOL - [6:5] */ | ||
193 | #define WM8961_DACMU 0x0008 /* DACMU */ | ||
194 | #define WM8961_DACMU_MASK 0x0008 /* DACMU */ | ||
195 | #define WM8961_DACMU_SHIFT 3 /* DACMU */ | ||
196 | #define WM8961_DACMU_WIDTH 1 /* DACMU */ | ||
197 | #define WM8961_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ | ||
198 | #define WM8961_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ | ||
199 | #define WM8961_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ | ||
200 | #define WM8961_ADCHPD 0x0001 /* ADCHPD */ | ||
201 | #define WM8961_ADCHPD_MASK 0x0001 /* ADCHPD */ | ||
202 | #define WM8961_ADCHPD_SHIFT 0 /* ADCHPD */ | ||
203 | #define WM8961_ADCHPD_WIDTH 1 /* ADCHPD */ | ||
204 | |||
205 | /* | ||
206 | * R6 (0x06) - ADC & DAC Control 2 | ||
207 | */ | ||
208 | #define WM8961_ADC_HPF_CUT_MASK 0x0180 /* ADC_HPF_CUT - [8:7] */ | ||
209 | #define WM8961_ADC_HPF_CUT_SHIFT 7 /* ADC_HPF_CUT - [8:7] */ | ||
210 | #define WM8961_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [8:7] */ | ||
211 | #define WM8961_DACPOL_MASK 0x0060 /* DACPOL - [6:5] */ | ||
212 | #define WM8961_DACPOL_SHIFT 5 /* DACPOL - [6:5] */ | ||
213 | #define WM8961_DACPOL_WIDTH 2 /* DACPOL - [6:5] */ | ||
214 | #define WM8961_DACSMM 0x0008 /* DACSMM */ | ||
215 | #define WM8961_DACSMM_MASK 0x0008 /* DACSMM */ | ||
216 | #define WM8961_DACSMM_SHIFT 3 /* DACSMM */ | ||
217 | #define WM8961_DACSMM_WIDTH 1 /* DACSMM */ | ||
218 | #define WM8961_DACMR 0x0004 /* DACMR */ | ||
219 | #define WM8961_DACMR_MASK 0x0004 /* DACMR */ | ||
220 | #define WM8961_DACMR_SHIFT 2 /* DACMR */ | ||
221 | #define WM8961_DACMR_WIDTH 1 /* DACMR */ | ||
222 | #define WM8961_DACSLOPE 0x0002 /* DACSLOPE */ | ||
223 | #define WM8961_DACSLOPE_MASK 0x0002 /* DACSLOPE */ | ||
224 | #define WM8961_DACSLOPE_SHIFT 1 /* DACSLOPE */ | ||
225 | #define WM8961_DACSLOPE_WIDTH 1 /* DACSLOPE */ | ||
226 | #define WM8961_DAC_OSR128 0x0001 /* DAC_OSR128 */ | ||
227 | #define WM8961_DAC_OSR128_MASK 0x0001 /* DAC_OSR128 */ | ||
228 | #define WM8961_DAC_OSR128_SHIFT 0 /* DAC_OSR128 */ | ||
229 | #define WM8961_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */ | ||
230 | |||
231 | /* | ||
232 | * R7 (0x07) - Audio Interface 0 | ||
233 | */ | ||
234 | #define WM8961_ALRSWAP 0x0100 /* ALRSWAP */ | ||
235 | #define WM8961_ALRSWAP_MASK 0x0100 /* ALRSWAP */ | ||
236 | #define WM8961_ALRSWAP_SHIFT 8 /* ALRSWAP */ | ||
237 | #define WM8961_ALRSWAP_WIDTH 1 /* ALRSWAP */ | ||
238 | #define WM8961_BCLKINV 0x0080 /* BCLKINV */ | ||
239 | #define WM8961_BCLKINV_MASK 0x0080 /* BCLKINV */ | ||
240 | #define WM8961_BCLKINV_SHIFT 7 /* BCLKINV */ | ||
241 | #define WM8961_BCLKINV_WIDTH 1 /* BCLKINV */ | ||
242 | #define WM8961_MS 0x0040 /* MS */ | ||
243 | #define WM8961_MS_MASK 0x0040 /* MS */ | ||
244 | #define WM8961_MS_SHIFT 6 /* MS */ | ||
245 | #define WM8961_MS_WIDTH 1 /* MS */ | ||
246 | #define WM8961_DLRSWAP 0x0020 /* DLRSWAP */ | ||
247 | #define WM8961_DLRSWAP_MASK 0x0020 /* DLRSWAP */ | ||
248 | #define WM8961_DLRSWAP_SHIFT 5 /* DLRSWAP */ | ||
249 | #define WM8961_DLRSWAP_WIDTH 1 /* DLRSWAP */ | ||
250 | #define WM8961_LRP 0x0010 /* LRP */ | ||
251 | #define WM8961_LRP_MASK 0x0010 /* LRP */ | ||
252 | #define WM8961_LRP_SHIFT 4 /* LRP */ | ||
253 | #define WM8961_LRP_WIDTH 1 /* LRP */ | ||
254 | #define WM8961_WL_MASK 0x000C /* WL - [3:2] */ | ||
255 | #define WM8961_WL_SHIFT 2 /* WL - [3:2] */ | ||
256 | #define WM8961_WL_WIDTH 2 /* WL - [3:2] */ | ||
257 | #define WM8961_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */ | ||
258 | #define WM8961_FORMAT_SHIFT 0 /* FORMAT - [1:0] */ | ||
259 | #define WM8961_FORMAT_WIDTH 2 /* FORMAT - [1:0] */ | ||
260 | |||
261 | /* | ||
262 | * R8 (0x08) - Clocking2 | ||
263 | */ | ||
264 | #define WM8961_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */ | ||
265 | #define WM8961_DCLKDIV_SHIFT 6 /* DCLKDIV - [8:6] */ | ||
266 | #define WM8961_DCLKDIV_WIDTH 3 /* DCLKDIV - [8:6] */ | ||
267 | #define WM8961_CLK_SYS_ENA 0x0020 /* CLK_SYS_ENA */ | ||
268 | #define WM8961_CLK_SYS_ENA_MASK 0x0020 /* CLK_SYS_ENA */ | ||
269 | #define WM8961_CLK_SYS_ENA_SHIFT 5 /* CLK_SYS_ENA */ | ||
270 | #define WM8961_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ | ||
271 | #define WM8961_CLK_DSP_ENA 0x0010 /* CLK_DSP_ENA */ | ||
272 | #define WM8961_CLK_DSP_ENA_MASK 0x0010 /* CLK_DSP_ENA */ | ||
273 | #define WM8961_CLK_DSP_ENA_SHIFT 4 /* CLK_DSP_ENA */ | ||
274 | #define WM8961_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ | ||
275 | #define WM8961_BCLKDIV_MASK 0x000F /* BCLKDIV - [3:0] */ | ||
276 | #define WM8961_BCLKDIV_SHIFT 0 /* BCLKDIV - [3:0] */ | ||
277 | #define WM8961_BCLKDIV_WIDTH 4 /* BCLKDIV - [3:0] */ | ||
278 | |||
279 | /* | ||
280 | * R9 (0x09) - Audio Interface 1 | ||
281 | */ | ||
282 | #define WM8961_DACCOMP_MASK 0x0018 /* DACCOMP - [4:3] */ | ||
283 | #define WM8961_DACCOMP_SHIFT 3 /* DACCOMP - [4:3] */ | ||
284 | #define WM8961_DACCOMP_WIDTH 2 /* DACCOMP - [4:3] */ | ||
285 | #define WM8961_ADCCOMP_MASK 0x0006 /* ADCCOMP - [2:1] */ | ||
286 | #define WM8961_ADCCOMP_SHIFT 1 /* ADCCOMP - [2:1] */ | ||
287 | #define WM8961_ADCCOMP_WIDTH 2 /* ADCCOMP - [2:1] */ | ||
288 | #define WM8961_LOOPBACK 0x0001 /* LOOPBACK */ | ||
289 | #define WM8961_LOOPBACK_MASK 0x0001 /* LOOPBACK */ | ||
290 | #define WM8961_LOOPBACK_SHIFT 0 /* LOOPBACK */ | ||
291 | #define WM8961_LOOPBACK_WIDTH 1 /* LOOPBACK */ | ||
292 | |||
293 | /* | ||
294 | * R10 (0x0A) - Left DAC volume | ||
295 | */ | ||
296 | #define WM8961_DACVU 0x0100 /* DACVU */ | ||
297 | #define WM8961_DACVU_MASK 0x0100 /* DACVU */ | ||
298 | #define WM8961_DACVU_SHIFT 8 /* DACVU */ | ||
299 | #define WM8961_DACVU_WIDTH 1 /* DACVU */ | ||
300 | #define WM8961_LDACVOL_MASK 0x00FF /* LDACVOL - [7:0] */ | ||
301 | #define WM8961_LDACVOL_SHIFT 0 /* LDACVOL - [7:0] */ | ||
302 | #define WM8961_LDACVOL_WIDTH 8 /* LDACVOL - [7:0] */ | ||
303 | |||
304 | /* | ||
305 | * R11 (0x0B) - Right DAC volume | ||
306 | */ | ||
307 | #define WM8961_DACVU 0x0100 /* DACVU */ | ||
308 | #define WM8961_DACVU_MASK 0x0100 /* DACVU */ | ||
309 | #define WM8961_DACVU_SHIFT 8 /* DACVU */ | ||
310 | #define WM8961_DACVU_WIDTH 1 /* DACVU */ | ||
311 | #define WM8961_RDACVOL_MASK 0x00FF /* RDACVOL - [7:0] */ | ||
312 | #define WM8961_RDACVOL_SHIFT 0 /* RDACVOL - [7:0] */ | ||
313 | #define WM8961_RDACVOL_WIDTH 8 /* RDACVOL - [7:0] */ | ||
314 | |||
315 | /* | ||
316 | * R14 (0x0E) - Audio Interface 2 | ||
317 | */ | ||
318 | #define WM8961_LRCLK_RATE_MASK 0x01FF /* LRCLK_RATE - [8:0] */ | ||
319 | #define WM8961_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [8:0] */ | ||
320 | #define WM8961_LRCLK_RATE_WIDTH 9 /* LRCLK_RATE - [8:0] */ | ||
321 | |||
322 | /* | ||
323 | * R15 (0x0F) - Software Reset | ||
324 | */ | ||
325 | #define WM8961_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */ | ||
326 | #define WM8961_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */ | ||
327 | #define WM8961_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */ | ||
328 | |||
329 | /* | ||
330 | * R17 (0x11) - ALC1 | ||
331 | */ | ||
332 | #define WM8961_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */ | ||
333 | #define WM8961_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */ | ||
334 | #define WM8961_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */ | ||
335 | #define WM8961_MAXGAIN_MASK 0x0070 /* MAXGAIN - [6:4] */ | ||
336 | #define WM8961_MAXGAIN_SHIFT 4 /* MAXGAIN - [6:4] */ | ||
337 | #define WM8961_MAXGAIN_WIDTH 3 /* MAXGAIN - [6:4] */ | ||
338 | #define WM8961_ALCL_MASK 0x000F /* ALCL - [3:0] */ | ||
339 | #define WM8961_ALCL_SHIFT 0 /* ALCL - [3:0] */ | ||
340 | #define WM8961_ALCL_WIDTH 4 /* ALCL - [3:0] */ | ||
341 | |||
342 | /* | ||
343 | * R18 (0x12) - ALC2 | ||
344 | */ | ||
345 | #define WM8961_ALCZC 0x0080 /* ALCZC */ | ||
346 | #define WM8961_ALCZC_MASK 0x0080 /* ALCZC */ | ||
347 | #define WM8961_ALCZC_SHIFT 7 /* ALCZC */ | ||
348 | #define WM8961_ALCZC_WIDTH 1 /* ALCZC */ | ||
349 | #define WM8961_MINGAIN_MASK 0x0070 /* MINGAIN - [6:4] */ | ||
350 | #define WM8961_MINGAIN_SHIFT 4 /* MINGAIN - [6:4] */ | ||
351 | #define WM8961_MINGAIN_WIDTH 3 /* MINGAIN - [6:4] */ | ||
352 | #define WM8961_HLD_MASK 0x000F /* HLD - [3:0] */ | ||
353 | #define WM8961_HLD_SHIFT 0 /* HLD - [3:0] */ | ||
354 | #define WM8961_HLD_WIDTH 4 /* HLD - [3:0] */ | ||
355 | |||
356 | /* | ||
357 | * R19 (0x13) - ALC3 | ||
358 | */ | ||
359 | #define WM8961_ALCMODE 0x0100 /* ALCMODE */ | ||
360 | #define WM8961_ALCMODE_MASK 0x0100 /* ALCMODE */ | ||
361 | #define WM8961_ALCMODE_SHIFT 8 /* ALCMODE */ | ||
362 | #define WM8961_ALCMODE_WIDTH 1 /* ALCMODE */ | ||
363 | #define WM8961_DCY_MASK 0x00F0 /* DCY - [7:4] */ | ||
364 | #define WM8961_DCY_SHIFT 4 /* DCY - [7:4] */ | ||
365 | #define WM8961_DCY_WIDTH 4 /* DCY - [7:4] */ | ||
366 | #define WM8961_ATK_MASK 0x000F /* ATK - [3:0] */ | ||
367 | #define WM8961_ATK_SHIFT 0 /* ATK - [3:0] */ | ||
368 | #define WM8961_ATK_WIDTH 4 /* ATK - [3:0] */ | ||
369 | |||
370 | /* | ||
371 | * R20 (0x14) - Noise Gate | ||
372 | */ | ||
373 | #define WM8961_NGTH_MASK 0x00F8 /* NGTH - [7:3] */ | ||
374 | #define WM8961_NGTH_SHIFT 3 /* NGTH - [7:3] */ | ||
375 | #define WM8961_NGTH_WIDTH 5 /* NGTH - [7:3] */ | ||
376 | #define WM8961_NGG 0x0002 /* NGG */ | ||
377 | #define WM8961_NGG_MASK 0x0002 /* NGG */ | ||
378 | #define WM8961_NGG_SHIFT 1 /* NGG */ | ||
379 | #define WM8961_NGG_WIDTH 1 /* NGG */ | ||
380 | #define WM8961_NGAT 0x0001 /* NGAT */ | ||
381 | #define WM8961_NGAT_MASK 0x0001 /* NGAT */ | ||
382 | #define WM8961_NGAT_SHIFT 0 /* NGAT */ | ||
383 | #define WM8961_NGAT_WIDTH 1 /* NGAT */ | ||
384 | |||
385 | /* | ||
386 | * R21 (0x15) - Left ADC volume | ||
387 | */ | ||
388 | #define WM8961_ADCVU 0x0100 /* ADCVU */ | ||
389 | #define WM8961_ADCVU_MASK 0x0100 /* ADCVU */ | ||
390 | #define WM8961_ADCVU_SHIFT 8 /* ADCVU */ | ||
391 | #define WM8961_ADCVU_WIDTH 1 /* ADCVU */ | ||
392 | #define WM8961_LADCVOL_MASK 0x00FF /* LADCVOL - [7:0] */ | ||
393 | #define WM8961_LADCVOL_SHIFT 0 /* LADCVOL - [7:0] */ | ||
394 | #define WM8961_LADCVOL_WIDTH 8 /* LADCVOL - [7:0] */ | ||
395 | |||
396 | /* | ||
397 | * R22 (0x16) - Right ADC volume | ||
398 | */ | ||
399 | #define WM8961_ADCVU 0x0100 /* ADCVU */ | ||
400 | #define WM8961_ADCVU_MASK 0x0100 /* ADCVU */ | ||
401 | #define WM8961_ADCVU_SHIFT 8 /* ADCVU */ | ||
402 | #define WM8961_ADCVU_WIDTH 1 /* ADCVU */ | ||
403 | #define WM8961_RADCVOL_MASK 0x00FF /* RADCVOL - [7:0] */ | ||
404 | #define WM8961_RADCVOL_SHIFT 0 /* RADCVOL - [7:0] */ | ||
405 | #define WM8961_RADCVOL_WIDTH 8 /* RADCVOL - [7:0] */ | ||
406 | |||
407 | /* | ||
408 | * R23 (0x17) - Additional control(1) | ||
409 | */ | ||
410 | #define WM8961_TSDEN 0x0100 /* TSDEN */ | ||
411 | #define WM8961_TSDEN_MASK 0x0100 /* TSDEN */ | ||
412 | #define WM8961_TSDEN_SHIFT 8 /* TSDEN */ | ||
413 | #define WM8961_TSDEN_WIDTH 1 /* TSDEN */ | ||
414 | #define WM8961_DMONOMIX 0x0010 /* DMONOMIX */ | ||
415 | #define WM8961_DMONOMIX_MASK 0x0010 /* DMONOMIX */ | ||
416 | #define WM8961_DMONOMIX_SHIFT 4 /* DMONOMIX */ | ||
417 | #define WM8961_DMONOMIX_WIDTH 1 /* DMONOMIX */ | ||
418 | #define WM8961_TOEN 0x0001 /* TOEN */ | ||
419 | #define WM8961_TOEN_MASK 0x0001 /* TOEN */ | ||
420 | #define WM8961_TOEN_SHIFT 0 /* TOEN */ | ||
421 | #define WM8961_TOEN_WIDTH 1 /* TOEN */ | ||
422 | |||
423 | /* | ||
424 | * R24 (0x18) - Additional control(2) | ||
425 | */ | ||
426 | #define WM8961_TRIS 0x0008 /* TRIS */ | ||
427 | #define WM8961_TRIS_MASK 0x0008 /* TRIS */ | ||
428 | #define WM8961_TRIS_SHIFT 3 /* TRIS */ | ||
429 | #define WM8961_TRIS_WIDTH 1 /* TRIS */ | ||
430 | |||
431 | /* | ||
432 | * R25 (0x19) - Pwr Mgmt (1) | ||
433 | */ | ||
434 | #define WM8961_VMIDSEL_MASK 0x0180 /* VMIDSEL - [8:7] */ | ||
435 | #define WM8961_VMIDSEL_SHIFT 7 /* VMIDSEL - [8:7] */ | ||
436 | #define WM8961_VMIDSEL_WIDTH 2 /* VMIDSEL - [8:7] */ | ||
437 | #define WM8961_VREF 0x0040 /* VREF */ | ||
438 | #define WM8961_VREF_MASK 0x0040 /* VREF */ | ||
439 | #define WM8961_VREF_SHIFT 6 /* VREF */ | ||
440 | #define WM8961_VREF_WIDTH 1 /* VREF */ | ||
441 | #define WM8961_AINL 0x0020 /* AINL */ | ||
442 | #define WM8961_AINL_MASK 0x0020 /* AINL */ | ||
443 | #define WM8961_AINL_SHIFT 5 /* AINL */ | ||
444 | #define WM8961_AINL_WIDTH 1 /* AINL */ | ||
445 | #define WM8961_AINR 0x0010 /* AINR */ | ||
446 | #define WM8961_AINR_MASK 0x0010 /* AINR */ | ||
447 | #define WM8961_AINR_SHIFT 4 /* AINR */ | ||
448 | #define WM8961_AINR_WIDTH 1 /* AINR */ | ||
449 | #define WM8961_ADCL 0x0008 /* ADCL */ | ||
450 | #define WM8961_ADCL_MASK 0x0008 /* ADCL */ | ||
451 | #define WM8961_ADCL_SHIFT 3 /* ADCL */ | ||
452 | #define WM8961_ADCL_WIDTH 1 /* ADCL */ | ||
453 | #define WM8961_ADCR 0x0004 /* ADCR */ | ||
454 | #define WM8961_ADCR_MASK 0x0004 /* ADCR */ | ||
455 | #define WM8961_ADCR_SHIFT 2 /* ADCR */ | ||
456 | #define WM8961_ADCR_WIDTH 1 /* ADCR */ | ||
457 | #define WM8961_MICB 0x0002 /* MICB */ | ||
458 | #define WM8961_MICB_MASK 0x0002 /* MICB */ | ||
459 | #define WM8961_MICB_SHIFT 1 /* MICB */ | ||
460 | #define WM8961_MICB_WIDTH 1 /* MICB */ | ||
461 | |||
462 | /* | ||
463 | * R26 (0x1A) - Pwr Mgmt (2) | ||
464 | */ | ||
465 | #define WM8961_DACL 0x0100 /* DACL */ | ||
466 | #define WM8961_DACL_MASK 0x0100 /* DACL */ | ||
467 | #define WM8961_DACL_SHIFT 8 /* DACL */ | ||
468 | #define WM8961_DACL_WIDTH 1 /* DACL */ | ||
469 | #define WM8961_DACR 0x0080 /* DACR */ | ||
470 | #define WM8961_DACR_MASK 0x0080 /* DACR */ | ||
471 | #define WM8961_DACR_SHIFT 7 /* DACR */ | ||
472 | #define WM8961_DACR_WIDTH 1 /* DACR */ | ||
473 | #define WM8961_LOUT1_PGA 0x0040 /* LOUT1_PGA */ | ||
474 | #define WM8961_LOUT1_PGA_MASK 0x0040 /* LOUT1_PGA */ | ||
475 | #define WM8961_LOUT1_PGA_SHIFT 6 /* LOUT1_PGA */ | ||
476 | #define WM8961_LOUT1_PGA_WIDTH 1 /* LOUT1_PGA */ | ||
477 | #define WM8961_ROUT1_PGA 0x0020 /* ROUT1_PGA */ | ||
478 | #define WM8961_ROUT1_PGA_MASK 0x0020 /* ROUT1_PGA */ | ||
479 | #define WM8961_ROUT1_PGA_SHIFT 5 /* ROUT1_PGA */ | ||
480 | #define WM8961_ROUT1_PGA_WIDTH 1 /* ROUT1_PGA */ | ||
481 | #define WM8961_SPKL_PGA 0x0010 /* SPKL_PGA */ | ||
482 | #define WM8961_SPKL_PGA_MASK 0x0010 /* SPKL_PGA */ | ||
483 | #define WM8961_SPKL_PGA_SHIFT 4 /* SPKL_PGA */ | ||
484 | #define WM8961_SPKL_PGA_WIDTH 1 /* SPKL_PGA */ | ||
485 | #define WM8961_SPKR_PGA 0x0008 /* SPKR_PGA */ | ||
486 | #define WM8961_SPKR_PGA_MASK 0x0008 /* SPKR_PGA */ | ||
487 | #define WM8961_SPKR_PGA_SHIFT 3 /* SPKR_PGA */ | ||
488 | #define WM8961_SPKR_PGA_WIDTH 1 /* SPKR_PGA */ | ||
489 | |||
490 | /* | ||
491 | * R27 (0x1B) - Additional Control (3) | ||
492 | */ | ||
493 | #define WM8961_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */ | ||
494 | #define WM8961_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */ | ||
495 | #define WM8961_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */ | ||
496 | |||
497 | /* | ||
498 | * R28 (0x1C) - Anti-pop | ||
499 | */ | ||
500 | #define WM8961_BUFDCOPEN 0x0010 /* BUFDCOPEN */ | ||
501 | #define WM8961_BUFDCOPEN_MASK 0x0010 /* BUFDCOPEN */ | ||
502 | #define WM8961_BUFDCOPEN_SHIFT 4 /* BUFDCOPEN */ | ||
503 | #define WM8961_BUFDCOPEN_WIDTH 1 /* BUFDCOPEN */ | ||
504 | #define WM8961_BUFIOEN 0x0008 /* BUFIOEN */ | ||
505 | #define WM8961_BUFIOEN_MASK 0x0008 /* BUFIOEN */ | ||
506 | #define WM8961_BUFIOEN_SHIFT 3 /* BUFIOEN */ | ||
507 | #define WM8961_BUFIOEN_WIDTH 1 /* BUFIOEN */ | ||
508 | #define WM8961_SOFT_ST 0x0004 /* SOFT_ST */ | ||
509 | #define WM8961_SOFT_ST_MASK 0x0004 /* SOFT_ST */ | ||
510 | #define WM8961_SOFT_ST_SHIFT 2 /* SOFT_ST */ | ||
511 | #define WM8961_SOFT_ST_WIDTH 1 /* SOFT_ST */ | ||
512 | |||
513 | /* | ||
514 | * R30 (0x1E) - Clocking 3 | ||
515 | */ | ||
516 | #define WM8961_CLK_TO_DIV_MASK 0x0180 /* CLK_TO_DIV - [8:7] */ | ||
517 | #define WM8961_CLK_TO_DIV_SHIFT 7 /* CLK_TO_DIV - [8:7] */ | ||
518 | #define WM8961_CLK_TO_DIV_WIDTH 2 /* CLK_TO_DIV - [8:7] */ | ||
519 | #define WM8961_CLK_256K_DIV_MASK 0x007E /* CLK_256K_DIV - [6:1] */ | ||
520 | #define WM8961_CLK_256K_DIV_SHIFT 1 /* CLK_256K_DIV - [6:1] */ | ||
521 | #define WM8961_CLK_256K_DIV_WIDTH 6 /* CLK_256K_DIV - [6:1] */ | ||
522 | #define WM8961_MANUAL_MODE 0x0001 /* MANUAL_MODE */ | ||
523 | #define WM8961_MANUAL_MODE_MASK 0x0001 /* MANUAL_MODE */ | ||
524 | #define WM8961_MANUAL_MODE_SHIFT 0 /* MANUAL_MODE */ | ||
525 | #define WM8961_MANUAL_MODE_WIDTH 1 /* MANUAL_MODE */ | ||
526 | |||
527 | /* | ||
528 | * R32 (0x20) - ADCL signal path | ||
529 | */ | ||
530 | #define WM8961_LMICBOOST_MASK 0x0030 /* LMICBOOST - [5:4] */ | ||
531 | #define WM8961_LMICBOOST_SHIFT 4 /* LMICBOOST - [5:4] */ | ||
532 | #define WM8961_LMICBOOST_WIDTH 2 /* LMICBOOST - [5:4] */ | ||
533 | |||
534 | /* | ||
535 | * R33 (0x21) - ADCR signal path | ||
536 | */ | ||
537 | #define WM8961_RMICBOOST_MASK 0x0030 /* RMICBOOST - [5:4] */ | ||
538 | #define WM8961_RMICBOOST_SHIFT 4 /* RMICBOOST - [5:4] */ | ||
539 | #define WM8961_RMICBOOST_WIDTH 2 /* RMICBOOST - [5:4] */ | ||
540 | |||
541 | /* | ||
542 | * R40 (0x28) - LOUT2 volume | ||
543 | */ | ||
544 | #define WM8961_SPKVU 0x0100 /* SPKVU */ | ||
545 | #define WM8961_SPKVU_MASK 0x0100 /* SPKVU */ | ||
546 | #define WM8961_SPKVU_SHIFT 8 /* SPKVU */ | ||
547 | #define WM8961_SPKVU_WIDTH 1 /* SPKVU */ | ||
548 | #define WM8961_SPKLZC 0x0080 /* SPKLZC */ | ||
549 | #define WM8961_SPKLZC_MASK 0x0080 /* SPKLZC */ | ||
550 | #define WM8961_SPKLZC_SHIFT 7 /* SPKLZC */ | ||
551 | #define WM8961_SPKLZC_WIDTH 1 /* SPKLZC */ | ||
552 | #define WM8961_SPKLVOL_MASK 0x007F /* SPKLVOL - [6:0] */ | ||
553 | #define WM8961_SPKLVOL_SHIFT 0 /* SPKLVOL - [6:0] */ | ||
554 | #define WM8961_SPKLVOL_WIDTH 7 /* SPKLVOL - [6:0] */ | ||
555 | |||
556 | /* | ||
557 | * R41 (0x29) - ROUT2 volume | ||
558 | */ | ||
559 | #define WM8961_SPKVU 0x0100 /* SPKVU */ | ||
560 | #define WM8961_SPKVU_MASK 0x0100 /* SPKVU */ | ||
561 | #define WM8961_SPKVU_SHIFT 8 /* SPKVU */ | ||
562 | #define WM8961_SPKVU_WIDTH 1 /* SPKVU */ | ||
563 | #define WM8961_SPKRZC 0x0080 /* SPKRZC */ | ||
564 | #define WM8961_SPKRZC_MASK 0x0080 /* SPKRZC */ | ||
565 | #define WM8961_SPKRZC_SHIFT 7 /* SPKRZC */ | ||
566 | #define WM8961_SPKRZC_WIDTH 1 /* SPKRZC */ | ||
567 | #define WM8961_SPKRVOL_MASK 0x007F /* SPKRVOL - [6:0] */ | ||
568 | #define WM8961_SPKRVOL_SHIFT 0 /* SPKRVOL - [6:0] */ | ||
569 | #define WM8961_SPKRVOL_WIDTH 7 /* SPKRVOL - [6:0] */ | ||
570 | |||
571 | /* | ||
572 | * R47 (0x2F) - Pwr Mgmt (3) | ||
573 | */ | ||
574 | #define WM8961_TEMP_SHUT 0x0002 /* TEMP_SHUT */ | ||
575 | #define WM8961_TEMP_SHUT_MASK 0x0002 /* TEMP_SHUT */ | ||
576 | #define WM8961_TEMP_SHUT_SHIFT 1 /* TEMP_SHUT */ | ||
577 | #define WM8961_TEMP_SHUT_WIDTH 1 /* TEMP_SHUT */ | ||
578 | #define WM8961_TEMP_WARN 0x0001 /* TEMP_WARN */ | ||
579 | #define WM8961_TEMP_WARN_MASK 0x0001 /* TEMP_WARN */ | ||
580 | #define WM8961_TEMP_WARN_SHIFT 0 /* TEMP_WARN */ | ||
581 | #define WM8961_TEMP_WARN_WIDTH 1 /* TEMP_WARN */ | ||
582 | |||
583 | /* | ||
584 | * R48 (0x30) - Additional Control (4) | ||
585 | */ | ||
586 | #define WM8961_TSENSEN 0x0002 /* TSENSEN */ | ||
587 | #define WM8961_TSENSEN_MASK 0x0002 /* TSENSEN */ | ||
588 | #define WM8961_TSENSEN_SHIFT 1 /* TSENSEN */ | ||
589 | #define WM8961_TSENSEN_WIDTH 1 /* TSENSEN */ | ||
590 | #define WM8961_MBSEL 0x0001 /* MBSEL */ | ||
591 | #define WM8961_MBSEL_MASK 0x0001 /* MBSEL */ | ||
592 | #define WM8961_MBSEL_SHIFT 0 /* MBSEL */ | ||
593 | #define WM8961_MBSEL_WIDTH 1 /* MBSEL */ | ||
594 | |||
595 | /* | ||
596 | * R49 (0x31) - Class D Control 1 | ||
597 | */ | ||
598 | #define WM8961_SPKR_ENA 0x0080 /* SPKR_ENA */ | ||
599 | #define WM8961_SPKR_ENA_MASK 0x0080 /* SPKR_ENA */ | ||
600 | #define WM8961_SPKR_ENA_SHIFT 7 /* SPKR_ENA */ | ||
601 | #define WM8961_SPKR_ENA_WIDTH 1 /* SPKR_ENA */ | ||
602 | #define WM8961_SPKL_ENA 0x0040 /* SPKL_ENA */ | ||
603 | #define WM8961_SPKL_ENA_MASK 0x0040 /* SPKL_ENA */ | ||
604 | #define WM8961_SPKL_ENA_SHIFT 6 /* SPKL_ENA */ | ||
605 | #define WM8961_SPKL_ENA_WIDTH 1 /* SPKL_ENA */ | ||
606 | |||
607 | /* | ||
608 | * R51 (0x33) - Class D Control 2 | ||
609 | */ | ||
610 | #define WM8961_CLASSD_ACGAIN_MASK 0x0007 /* CLASSD_ACGAIN - [2:0] */ | ||
611 | #define WM8961_CLASSD_ACGAIN_SHIFT 0 /* CLASSD_ACGAIN - [2:0] */ | ||
612 | #define WM8961_CLASSD_ACGAIN_WIDTH 3 /* CLASSD_ACGAIN - [2:0] */ | ||
613 | |||
614 | /* | ||
615 | * R56 (0x38) - Clocking 4 | ||
616 | */ | ||
617 | #define WM8961_CLK_DCS_DIV_MASK 0x01E0 /* CLK_DCS_DIV - [8:5] */ | ||
618 | #define WM8961_CLK_DCS_DIV_SHIFT 5 /* CLK_DCS_DIV - [8:5] */ | ||
619 | #define WM8961_CLK_DCS_DIV_WIDTH 4 /* CLK_DCS_DIV - [8:5] */ | ||
620 | #define WM8961_CLK_SYS_RATE_MASK 0x001E /* CLK_SYS_RATE - [4:1] */ | ||
621 | #define WM8961_CLK_SYS_RATE_SHIFT 1 /* CLK_SYS_RATE - [4:1] */ | ||
622 | #define WM8961_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [4:1] */ | ||
623 | |||
624 | /* | ||
625 | * R57 (0x39) - DSP Sidetone 0 | ||
626 | */ | ||
627 | #define WM8961_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */ | ||
628 | #define WM8961_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */ | ||
629 | #define WM8961_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */ | ||
630 | #define WM8961_ADC_TO_DACR_MASK 0x000C /* ADC_TO_DACR - [3:2] */ | ||
631 | #define WM8961_ADC_TO_DACR_SHIFT 2 /* ADC_TO_DACR - [3:2] */ | ||
632 | #define WM8961_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [3:2] */ | ||
633 | |||
634 | /* | ||
635 | * R58 (0x3A) - DSP Sidetone 1 | ||
636 | */ | ||
637 | #define WM8961_ADCL_DAC_SVOL_MASK 0x00F0 /* ADCL_DAC_SVOL - [7:4] */ | ||
638 | #define WM8961_ADCL_DAC_SVOL_SHIFT 4 /* ADCL_DAC_SVOL - [7:4] */ | ||
639 | #define WM8961_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [7:4] */ | ||
640 | #define WM8961_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */ | ||
641 | #define WM8961_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */ | ||
642 | #define WM8961_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */ | ||
643 | |||
644 | /* | ||
645 | * R60 (0x3C) - DC Servo 0 | ||
646 | */ | ||
647 | #define WM8961_DCS_ENA_CHAN_INL 0x0080 /* DCS_ENA_CHAN_INL */ | ||
648 | #define WM8961_DCS_ENA_CHAN_INL_MASK 0x0080 /* DCS_ENA_CHAN_INL */ | ||
649 | #define WM8961_DCS_ENA_CHAN_INL_SHIFT 7 /* DCS_ENA_CHAN_INL */ | ||
650 | #define WM8961_DCS_ENA_CHAN_INL_WIDTH 1 /* DCS_ENA_CHAN_INL */ | ||
651 | #define WM8961_DCS_TRIG_STARTUP_INL 0x0040 /* DCS_TRIG_STARTUP_INL */ | ||
652 | #define WM8961_DCS_TRIG_STARTUP_INL_MASK 0x0040 /* DCS_TRIG_STARTUP_INL */ | ||
653 | #define WM8961_DCS_TRIG_STARTUP_INL_SHIFT 6 /* DCS_TRIG_STARTUP_INL */ | ||
654 | #define WM8961_DCS_TRIG_STARTUP_INL_WIDTH 1 /* DCS_TRIG_STARTUP_INL */ | ||
655 | #define WM8961_DCS_TRIG_SERIES_INL 0x0010 /* DCS_TRIG_SERIES_INL */ | ||
656 | #define WM8961_DCS_TRIG_SERIES_INL_MASK 0x0010 /* DCS_TRIG_SERIES_INL */ | ||
657 | #define WM8961_DCS_TRIG_SERIES_INL_SHIFT 4 /* DCS_TRIG_SERIES_INL */ | ||
658 | #define WM8961_DCS_TRIG_SERIES_INL_WIDTH 1 /* DCS_TRIG_SERIES_INL */ | ||
659 | #define WM8961_DCS_ENA_CHAN_INR 0x0008 /* DCS_ENA_CHAN_INR */ | ||
660 | #define WM8961_DCS_ENA_CHAN_INR_MASK 0x0008 /* DCS_ENA_CHAN_INR */ | ||
661 | #define WM8961_DCS_ENA_CHAN_INR_SHIFT 3 /* DCS_ENA_CHAN_INR */ | ||
662 | #define WM8961_DCS_ENA_CHAN_INR_WIDTH 1 /* DCS_ENA_CHAN_INR */ | ||
663 | #define WM8961_DCS_TRIG_STARTUP_INR 0x0004 /* DCS_TRIG_STARTUP_INR */ | ||
664 | #define WM8961_DCS_TRIG_STARTUP_INR_MASK 0x0004 /* DCS_TRIG_STARTUP_INR */ | ||
665 | #define WM8961_DCS_TRIG_STARTUP_INR_SHIFT 2 /* DCS_TRIG_STARTUP_INR */ | ||
666 | #define WM8961_DCS_TRIG_STARTUP_INR_WIDTH 1 /* DCS_TRIG_STARTUP_INR */ | ||
667 | #define WM8961_DCS_TRIG_SERIES_INR 0x0001 /* DCS_TRIG_SERIES_INR */ | ||
668 | #define WM8961_DCS_TRIG_SERIES_INR_MASK 0x0001 /* DCS_TRIG_SERIES_INR */ | ||
669 | #define WM8961_DCS_TRIG_SERIES_INR_SHIFT 0 /* DCS_TRIG_SERIES_INR */ | ||
670 | #define WM8961_DCS_TRIG_SERIES_INR_WIDTH 1 /* DCS_TRIG_SERIES_INR */ | ||
671 | |||
672 | /* | ||
673 | * R61 (0x3D) - DC Servo 1 | ||
674 | */ | ||
675 | #define WM8961_DCS_ENA_CHAN_HPL 0x0080 /* DCS_ENA_CHAN_HPL */ | ||
676 | #define WM8961_DCS_ENA_CHAN_HPL_MASK 0x0080 /* DCS_ENA_CHAN_HPL */ | ||
677 | #define WM8961_DCS_ENA_CHAN_HPL_SHIFT 7 /* DCS_ENA_CHAN_HPL */ | ||
678 | #define WM8961_DCS_ENA_CHAN_HPL_WIDTH 1 /* DCS_ENA_CHAN_HPL */ | ||
679 | #define WM8961_DCS_TRIG_STARTUP_HPL 0x0040 /* DCS_TRIG_STARTUP_HPL */ | ||
680 | #define WM8961_DCS_TRIG_STARTUP_HPL_MASK 0x0040 /* DCS_TRIG_STARTUP_HPL */ | ||
681 | #define WM8961_DCS_TRIG_STARTUP_HPL_SHIFT 6 /* DCS_TRIG_STARTUP_HPL */ | ||
682 | #define WM8961_DCS_TRIG_STARTUP_HPL_WIDTH 1 /* DCS_TRIG_STARTUP_HPL */ | ||
683 | #define WM8961_DCS_TRIG_SERIES_HPL 0x0010 /* DCS_TRIG_SERIES_HPL */ | ||
684 | #define WM8961_DCS_TRIG_SERIES_HPL_MASK 0x0010 /* DCS_TRIG_SERIES_HPL */ | ||
685 | #define WM8961_DCS_TRIG_SERIES_HPL_SHIFT 4 /* DCS_TRIG_SERIES_HPL */ | ||
686 | #define WM8961_DCS_TRIG_SERIES_HPL_WIDTH 1 /* DCS_TRIG_SERIES_HPL */ | ||
687 | #define WM8961_DCS_ENA_CHAN_HPR 0x0008 /* DCS_ENA_CHAN_HPR */ | ||
688 | #define WM8961_DCS_ENA_CHAN_HPR_MASK 0x0008 /* DCS_ENA_CHAN_HPR */ | ||
689 | #define WM8961_DCS_ENA_CHAN_HPR_SHIFT 3 /* DCS_ENA_CHAN_HPR */ | ||
690 | #define WM8961_DCS_ENA_CHAN_HPR_WIDTH 1 /* DCS_ENA_CHAN_HPR */ | ||
691 | #define WM8961_DCS_TRIG_STARTUP_HPR 0x0004 /* DCS_TRIG_STARTUP_HPR */ | ||
692 | #define WM8961_DCS_TRIG_STARTUP_HPR_MASK 0x0004 /* DCS_TRIG_STARTUP_HPR */ | ||
693 | #define WM8961_DCS_TRIG_STARTUP_HPR_SHIFT 2 /* DCS_TRIG_STARTUP_HPR */ | ||
694 | #define WM8961_DCS_TRIG_STARTUP_HPR_WIDTH 1 /* DCS_TRIG_STARTUP_HPR */ | ||
695 | #define WM8961_DCS_TRIG_SERIES_HPR 0x0001 /* DCS_TRIG_SERIES_HPR */ | ||
696 | #define WM8961_DCS_TRIG_SERIES_HPR_MASK 0x0001 /* DCS_TRIG_SERIES_HPR */ | ||
697 | #define WM8961_DCS_TRIG_SERIES_HPR_SHIFT 0 /* DCS_TRIG_SERIES_HPR */ | ||
698 | #define WM8961_DCS_TRIG_SERIES_HPR_WIDTH 1 /* DCS_TRIG_SERIES_HPR */ | ||
699 | |||
700 | /* | ||
701 | * R63 (0x3F) - DC Servo 3 | ||
702 | */ | ||
703 | #define WM8961_DCS_FILT_BW_SERIES_MASK 0x0030 /* DCS_FILT_BW_SERIES - [5:4] */ | ||
704 | #define WM8961_DCS_FILT_BW_SERIES_SHIFT 4 /* DCS_FILT_BW_SERIES - [5:4] */ | ||
705 | #define WM8961_DCS_FILT_BW_SERIES_WIDTH 2 /* DCS_FILT_BW_SERIES - [5:4] */ | ||
706 | |||
707 | /* | ||
708 | * R65 (0x41) - DC Servo 5 | ||
709 | */ | ||
710 | #define WM8961_DCS_SERIES_NO_HP_MASK 0x007F /* DCS_SERIES_NO_HP - [6:0] */ | ||
711 | #define WM8961_DCS_SERIES_NO_HP_SHIFT 0 /* DCS_SERIES_NO_HP - [6:0] */ | ||
712 | #define WM8961_DCS_SERIES_NO_HP_WIDTH 7 /* DCS_SERIES_NO_HP - [6:0] */ | ||
713 | |||
714 | /* | ||
715 | * R68 (0x44) - Analogue PGA Bias | ||
716 | */ | ||
717 | #define WM8961_HP_PGAS_BIAS_MASK 0x0007 /* HP_PGAS_BIAS - [2:0] */ | ||
718 | #define WM8961_HP_PGAS_BIAS_SHIFT 0 /* HP_PGAS_BIAS - [2:0] */ | ||
719 | #define WM8961_HP_PGAS_BIAS_WIDTH 3 /* HP_PGAS_BIAS - [2:0] */ | ||
720 | |||
721 | /* | ||
722 | * R69 (0x45) - Analogue HP 0 | ||
723 | */ | ||
724 | #define WM8961_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */ | ||
725 | #define WM8961_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */ | ||
726 | #define WM8961_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */ | ||
727 | #define WM8961_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */ | ||
728 | #define WM8961_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */ | ||
729 | #define WM8961_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */ | ||
730 | #define WM8961_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */ | ||
731 | #define WM8961_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */ | ||
732 | #define WM8961_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */ | ||
733 | #define WM8961_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */ | ||
734 | #define WM8961_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */ | ||
735 | #define WM8961_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */ | ||
736 | #define WM8961_HPL_ENA 0x0010 /* HPL_ENA */ | ||
737 | #define WM8961_HPL_ENA_MASK 0x0010 /* HPL_ENA */ | ||
738 | #define WM8961_HPL_ENA_SHIFT 4 /* HPL_ENA */ | ||
739 | #define WM8961_HPL_ENA_WIDTH 1 /* HPL_ENA */ | ||
740 | #define WM8961_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */ | ||
741 | #define WM8961_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */ | ||
742 | #define WM8961_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */ | ||
743 | #define WM8961_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */ | ||
744 | #define WM8961_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */ | ||
745 | #define WM8961_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */ | ||
746 | #define WM8961_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */ | ||
747 | #define WM8961_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */ | ||
748 | #define WM8961_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */ | ||
749 | #define WM8961_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */ | ||
750 | #define WM8961_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */ | ||
751 | #define WM8961_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */ | ||
752 | #define WM8961_HPR_ENA 0x0001 /* HPR_ENA */ | ||
753 | #define WM8961_HPR_ENA_MASK 0x0001 /* HPR_ENA */ | ||
754 | #define WM8961_HPR_ENA_SHIFT 0 /* HPR_ENA */ | ||
755 | #define WM8961_HPR_ENA_WIDTH 1 /* HPR_ENA */ | ||
756 | |||
757 | /* | ||
758 | * R71 (0x47) - Analogue HP 2 | ||
759 | */ | ||
760 | #define WM8961_HPL_VOL_MASK 0x01C0 /* HPL_VOL - [8:6] */ | ||
761 | #define WM8961_HPL_VOL_SHIFT 6 /* HPL_VOL - [8:6] */ | ||
762 | #define WM8961_HPL_VOL_WIDTH 3 /* HPL_VOL - [8:6] */ | ||
763 | #define WM8961_HPR_VOL_MASK 0x0038 /* HPR_VOL - [5:3] */ | ||
764 | #define WM8961_HPR_VOL_SHIFT 3 /* HPR_VOL - [5:3] */ | ||
765 | #define WM8961_HPR_VOL_WIDTH 3 /* HPR_VOL - [5:3] */ | ||
766 | #define WM8961_HP_BIAS_BOOST_MASK 0x0007 /* HP_BIAS_BOOST - [2:0] */ | ||
767 | #define WM8961_HP_BIAS_BOOST_SHIFT 0 /* HP_BIAS_BOOST - [2:0] */ | ||
768 | #define WM8961_HP_BIAS_BOOST_WIDTH 3 /* HP_BIAS_BOOST - [2:0] */ | ||
769 | |||
770 | /* | ||
771 | * R72 (0x48) - Charge Pump 1 | ||
772 | */ | ||
773 | #define WM8961_CP_ENA 0x0001 /* CP_ENA */ | ||
774 | #define WM8961_CP_ENA_MASK 0x0001 /* CP_ENA */ | ||
775 | #define WM8961_CP_ENA_SHIFT 0 /* CP_ENA */ | ||
776 | #define WM8961_CP_ENA_WIDTH 1 /* CP_ENA */ | ||
777 | |||
778 | /* | ||
779 | * R82 (0x52) - Charge Pump B | ||
780 | */ | ||
781 | #define WM8961_CP_DYN_PWR_MASK 0x0003 /* CP_DYN_PWR - [1:0] */ | ||
782 | #define WM8961_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR - [1:0] */ | ||
783 | #define WM8961_CP_DYN_PWR_WIDTH 2 /* CP_DYN_PWR - [1:0] */ | ||
784 | |||
785 | /* | ||
786 | * R87 (0x57) - Write Sequencer 1 | ||
787 | */ | ||
788 | #define WM8961_WSEQ_ENA 0x0020 /* WSEQ_ENA */ | ||
789 | #define WM8961_WSEQ_ENA_MASK 0x0020 /* WSEQ_ENA */ | ||
790 | #define WM8961_WSEQ_ENA_SHIFT 5 /* WSEQ_ENA */ | ||
791 | #define WM8961_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ | ||
792 | #define WM8961_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */ | ||
793 | #define WM8961_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */ | ||
794 | #define WM8961_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */ | ||
795 | |||
796 | /* | ||
797 | * R88 (0x58) - Write Sequencer 2 | ||
798 | */ | ||
799 | #define WM8961_WSEQ_EOS 0x0100 /* WSEQ_EOS */ | ||
800 | #define WM8961_WSEQ_EOS_MASK 0x0100 /* WSEQ_EOS */ | ||
801 | #define WM8961_WSEQ_EOS_SHIFT 8 /* WSEQ_EOS */ | ||
802 | #define WM8961_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */ | ||
803 | #define WM8961_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */ | ||
804 | #define WM8961_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */ | ||
805 | #define WM8961_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */ | ||
806 | |||
807 | /* | ||
808 | * R89 (0x59) - Write Sequencer 3 | ||
809 | */ | ||
810 | #define WM8961_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */ | ||
811 | #define WM8961_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */ | ||
812 | #define WM8961_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */ | ||
813 | |||
814 | /* | ||
815 | * R90 (0x5A) - Write Sequencer 4 | ||
816 | */ | ||
817 | #define WM8961_WSEQ_ABORT 0x0100 /* WSEQ_ABORT */ | ||
818 | #define WM8961_WSEQ_ABORT_MASK 0x0100 /* WSEQ_ABORT */ | ||
819 | #define WM8961_WSEQ_ABORT_SHIFT 8 /* WSEQ_ABORT */ | ||
820 | #define WM8961_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ | ||
821 | #define WM8961_WSEQ_START 0x0080 /* WSEQ_START */ | ||
822 | #define WM8961_WSEQ_START_MASK 0x0080 /* WSEQ_START */ | ||
823 | #define WM8961_WSEQ_START_SHIFT 7 /* WSEQ_START */ | ||
824 | #define WM8961_WSEQ_START_WIDTH 1 /* WSEQ_START */ | ||
825 | #define WM8961_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */ | ||
826 | #define WM8961_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */ | ||
827 | #define WM8961_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */ | ||
828 | |||
829 | /* | ||
830 | * R91 (0x5B) - Write Sequencer 5 | ||
831 | */ | ||
832 | #define WM8961_WSEQ_DATA_WIDTH_MASK 0x0070 /* WSEQ_DATA_WIDTH - [6:4] */ | ||
833 | #define WM8961_WSEQ_DATA_WIDTH_SHIFT 4 /* WSEQ_DATA_WIDTH - [6:4] */ | ||
834 | #define WM8961_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [6:4] */ | ||
835 | #define WM8961_WSEQ_DATA_START_MASK 0x000F /* WSEQ_DATA_START - [3:0] */ | ||
836 | #define WM8961_WSEQ_DATA_START_SHIFT 0 /* WSEQ_DATA_START - [3:0] */ | ||
837 | #define WM8961_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [3:0] */ | ||
838 | |||
839 | /* | ||
840 | * R92 (0x5C) - Write Sequencer 6 | ||
841 | */ | ||
842 | #define WM8961_WSEQ_DELAY_MASK 0x000F /* WSEQ_DELAY - [3:0] */ | ||
843 | #define WM8961_WSEQ_DELAY_SHIFT 0 /* WSEQ_DELAY - [3:0] */ | ||
844 | #define WM8961_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [3:0] */ | ||
845 | |||
846 | /* | ||
847 | * R93 (0x5D) - Write Sequencer 7 | ||
848 | */ | ||
849 | #define WM8961_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ | ||
850 | #define WM8961_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ | ||
851 | #define WM8961_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ | ||
852 | #define WM8961_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ | ||
853 | |||
854 | /* | ||
855 | * R252 (0xFC) - General test 1 | ||
856 | */ | ||
857 | #define WM8961_ARA_ENA 0x0002 /* ARA_ENA */ | ||
858 | #define WM8961_ARA_ENA_MASK 0x0002 /* ARA_ENA */ | ||
859 | #define WM8961_ARA_ENA_SHIFT 1 /* ARA_ENA */ | ||
860 | #define WM8961_ARA_ENA_WIDTH 1 /* ARA_ENA */ | ||
861 | #define WM8961_AUTO_INC 0x0001 /* AUTO_INC */ | ||
862 | #define WM8961_AUTO_INC_MASK 0x0001 /* AUTO_INC */ | ||
863 | #define WM8961_AUTO_INC_SHIFT 0 /* AUTO_INC */ | ||
864 | #define WM8961_AUTO_INC_WIDTH 1 /* AUTO_INC */ | ||
865 | |||
866 | #endif | ||
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index c05f71803aa8..03fac6a0f805 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c | |||
@@ -981,6 +981,21 @@ static int wm8988_i2c_remove(struct i2c_client *client) | |||
981 | return 0; | 981 | return 0; |
982 | } | 982 | } |
983 | 983 | ||
984 | #ifdef CONFIG_PM | ||
985 | static int wm8988_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
986 | { | ||
987 | return snd_soc_suspend_device(&client->dev); | ||
988 | } | ||
989 | |||
990 | static int wm8988_i2c_resume(struct i2c_client *client) | ||
991 | { | ||
992 | return snd_soc_resume_device(&client->dev); | ||
993 | } | ||
994 | #else | ||
995 | #define wm8988_i2c_suspend NULL | ||
996 | #define wm8988_i2c_resume NULL | ||
997 | #endif | ||
998 | |||
984 | static const struct i2c_device_id wm8988_i2c_id[] = { | 999 | static const struct i2c_device_id wm8988_i2c_id[] = { |
985 | { "wm8988", 0 }, | 1000 | { "wm8988", 0 }, |
986 | { } | 1001 | { } |
@@ -994,6 +1009,8 @@ static struct i2c_driver wm8988_i2c_driver = { | |||
994 | }, | 1009 | }, |
995 | .probe = wm8988_i2c_probe, | 1010 | .probe = wm8988_i2c_probe, |
996 | .remove = wm8988_i2c_remove, | 1011 | .remove = wm8988_i2c_remove, |
1012 | .suspend = wm8988_i2c_suspend, | ||
1013 | .resume = wm8988_i2c_resume, | ||
997 | .id_table = wm8988_i2c_id, | 1014 | .id_table = wm8988_i2c_id, |
998 | }; | 1015 | }; |
999 | #endif | 1016 | #endif |
@@ -1051,6 +1068,21 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi) | |||
1051 | return 0; | 1068 | return 0; |
1052 | } | 1069 | } |
1053 | 1070 | ||
1071 | #ifdef CONFIG_PM | ||
1072 | static int wm8988_spi_suspend(struct spi_device *spi, pm_message_t msg) | ||
1073 | { | ||
1074 | return snd_soc_suspend_device(&spi->dev); | ||
1075 | } | ||
1076 | |||
1077 | static int wm8988_spi_resume(struct spi_device *spi) | ||
1078 | { | ||
1079 | return snd_soc_resume_device(&spi->dev); | ||
1080 | } | ||
1081 | #else | ||
1082 | #define wm8988_spi_suspend NULL | ||
1083 | #define wm8988_spi_resume NULL | ||
1084 | #endif | ||
1085 | |||
1054 | static struct spi_driver wm8988_spi_driver = { | 1086 | static struct spi_driver wm8988_spi_driver = { |
1055 | .driver = { | 1087 | .driver = { |
1056 | .name = "wm8988", | 1088 | .name = "wm8988", |
@@ -1059,6 +1091,8 @@ static struct spi_driver wm8988_spi_driver = { | |||
1059 | }, | 1091 | }, |
1060 | .probe = wm8988_spi_probe, | 1092 | .probe = wm8988_spi_probe, |
1061 | .remove = __devexit_p(wm8988_spi_remove), | 1093 | .remove = __devexit_p(wm8988_spi_remove), |
1094 | .suspend = wm8988_spi_suspend, | ||
1095 | .resume = wm8988_spi_resume, | ||
1062 | }; | 1096 | }; |
1063 | #endif | 1097 | #endif |
1064 | 1098 | ||
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 86fc57e25f97..dbe20597d872 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -1492,6 +1492,21 @@ static __devexit int wm9081_i2c_remove(struct i2c_client *client) | |||
1492 | return 0; | 1492 | return 0; |
1493 | } | 1493 | } |
1494 | 1494 | ||
1495 | #ifdef CONFIG_PM | ||
1496 | static int wm9081_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
1497 | { | ||
1498 | return snd_soc_suspend_device(&client->dev); | ||
1499 | } | ||
1500 | |||
1501 | static int wm9081_i2c_resume(struct i2c_client *client) | ||
1502 | { | ||
1503 | return snd_soc_resume_device(&client->dev); | ||
1504 | } | ||
1505 | #else | ||
1506 | #define wm9081_i2c_suspend NULL | ||
1507 | #define wm9081_i2c_resume NULL | ||
1508 | #endif | ||
1509 | |||
1495 | static const struct i2c_device_id wm9081_i2c_id[] = { | 1510 | static const struct i2c_device_id wm9081_i2c_id[] = { |
1496 | { "wm9081", 0 }, | 1511 | { "wm9081", 0 }, |
1497 | { } | 1512 | { } |
@@ -1505,6 +1520,8 @@ static struct i2c_driver wm9081_i2c_driver = { | |||
1505 | }, | 1520 | }, |
1506 | .probe = wm9081_i2c_probe, | 1521 | .probe = wm9081_i2c_probe, |
1507 | .remove = __devexit_p(wm9081_i2c_remove), | 1522 | .remove = __devexit_p(wm9081_i2c_remove), |
1523 | .suspend = wm9081_i2c_suspend, | ||
1524 | .resume = wm9081_i2c_resume, | ||
1508 | .id_table = wm9081_i2c_id, | 1525 | .id_table = wm9081_i2c_id, |
1509 | }; | 1526 | }; |
1510 | 1527 | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index b771238662b6..a5a90e594535 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -72,4 +72,11 @@ config SND_OMAP_SOC_OMAP3_BEAGLE | |||
72 | help | 72 | help |
73 | Say Y if you want to add support for SoC audio on the Beagleboard. | 73 | Say Y if you want to add support for SoC audio on the Beagleboard. |
74 | 74 | ||
75 | config SND_OMAP_SOC_ZOOM2 | ||
76 | tristate "SoC Audio support for Zoom2" | ||
77 | depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2 | ||
78 | select SND_OMAP_SOC_MCBSP | ||
79 | select SND_SOC_TWL4030 | ||
80 | help | ||
81 | Say Y if you want to add support for Soc audio on Zoom2 board. | ||
75 | 82 | ||
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index a37f49862389..fefc48f02bd3 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
@@ -14,6 +14,7 @@ snd-soc-omap3evm-objs := omap3evm.o | |||
14 | snd-soc-sdp3430-objs := sdp3430.o | 14 | snd-soc-sdp3430-objs := sdp3430.o |
15 | snd-soc-omap3pandora-objs := omap3pandora.o | 15 | snd-soc-omap3pandora-objs := omap3pandora.o |
16 | snd-soc-omap3beagle-objs := omap3beagle.o | 16 | snd-soc-omap3beagle-objs := omap3beagle.o |
17 | snd-soc-zoom2-objs := zoom2.o | ||
17 | 18 | ||
18 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 19 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
19 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o | 20 | obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o |
@@ -23,3 +24,4 @@ obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o | |||
23 | obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o | 24 | obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o |
24 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o | 25 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o |
25 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o | 26 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o |
27 | obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o | ||
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index b719e5db4f57..c51594d8fd13 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c | |||
@@ -96,7 +96,7 @@ static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream, | |||
96 | ret = snd_soc_dai_set_fmt(codec_dai, | 96 | ret = snd_soc_dai_set_fmt(codec_dai, |
97 | SND_SOC_DAIFMT_DSP_A | | 97 | SND_SOC_DAIFMT_DSP_A | |
98 | SND_SOC_DAIFMT_IB_NF | | 98 | SND_SOC_DAIFMT_IB_NF | |
99 | SND_SOC_DAIFMT_CBS_CFM); | 99 | SND_SOC_DAIFMT_CBM_CFM); |
100 | if (ret) { | 100 | if (ret) { |
101 | printk(KERN_ERR "can't set codec DAI configuration\n"); | 101 | printk(KERN_ERR "can't set codec DAI configuration\n"); |
102 | return ret; | 102 | return ret; |
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c new file mode 100644 index 000000000000..3de6d2bd3903 --- /dev/null +++ b/sound/soc/omap/zoom2.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * zoom2.c -- SoC audio for Zoom2 | ||
3 | * | ||
4 | * Author: Misael Lopez Cruz <x0052729@ti.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/clk.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | |||
29 | #include <asm/mach-types.h> | ||
30 | #include <mach/hardware.h> | ||
31 | #include <mach/gpio.h> | ||
32 | #include <mach/mcbsp.h> | ||
33 | |||
34 | #include "omap-mcbsp.h" | ||
35 | #include "omap-pcm.h" | ||
36 | #include "../codecs/twl4030.h" | ||
37 | |||
38 | #define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15) | ||
39 | |||
40 | static int zoom2_hw_params(struct snd_pcm_substream *substream, | ||
41 | struct snd_pcm_hw_params *params) | ||
42 | { | ||
43 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
44 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
45 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
46 | int ret; | ||
47 | |||
48 | /* Set codec DAI configuration */ | ||
49 | ret = snd_soc_dai_set_fmt(codec_dai, | ||
50 | SND_SOC_DAIFMT_I2S | | ||
51 | SND_SOC_DAIFMT_NB_NF | | ||
52 | SND_SOC_DAIFMT_CBM_CFM); | ||
53 | if (ret < 0) { | ||
54 | printk(KERN_ERR "can't set codec DAI configuration\n"); | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | /* Set cpu DAI configuration */ | ||
59 | ret = snd_soc_dai_set_fmt(cpu_dai, | ||
60 | SND_SOC_DAIFMT_I2S | | ||
61 | SND_SOC_DAIFMT_NB_NF | | ||
62 | SND_SOC_DAIFMT_CBM_CFM); | ||
63 | if (ret < 0) { | ||
64 | printk(KERN_ERR "can't set cpu DAI configuration\n"); | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | /* Set the codec system clock for DAC and ADC */ | ||
69 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, | ||
70 | SND_SOC_CLOCK_IN); | ||
71 | if (ret < 0) { | ||
72 | printk(KERN_ERR "can't set codec system clock\n"); | ||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static struct snd_soc_ops zoom2_ops = { | ||
80 | .hw_params = zoom2_hw_params, | ||
81 | }; | ||
82 | |||
83 | static int zoom2_hw_voice_params(struct snd_pcm_substream *substream, | ||
84 | struct snd_pcm_hw_params *params) | ||
85 | { | ||
86 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
87 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
88 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
89 | int ret; | ||
90 | |||
91 | /* Set codec DAI configuration */ | ||
92 | ret = snd_soc_dai_set_fmt(codec_dai, | ||
93 | SND_SOC_DAIFMT_DSP_A | | ||
94 | SND_SOC_DAIFMT_IB_NF | | ||
95 | SND_SOC_DAIFMT_CBM_CFM); | ||
96 | if (ret) { | ||
97 | printk(KERN_ERR "can't set codec DAI configuration\n"); | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | /* Set cpu DAI configuration */ | ||
102 | ret = snd_soc_dai_set_fmt(cpu_dai, | ||
103 | SND_SOC_DAIFMT_DSP_A | | ||
104 | SND_SOC_DAIFMT_IB_NF | | ||
105 | SND_SOC_DAIFMT_CBM_CFM); | ||
106 | if (ret < 0) { | ||
107 | printk(KERN_ERR "can't set cpu DAI configuration\n"); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | /* Set the codec system clock for DAC and ADC */ | ||
112 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, | ||
113 | SND_SOC_CLOCK_IN); | ||
114 | if (ret < 0) { | ||
115 | printk(KERN_ERR "can't set codec system clock\n"); | ||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static struct snd_soc_ops zoom2_voice_ops = { | ||
123 | .hw_params = zoom2_hw_voice_params, | ||
124 | }; | ||
125 | |||
126 | /* Zoom2 machine DAPM */ | ||
127 | static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = { | ||
128 | SND_SOC_DAPM_MIC("Ext Mic", NULL), | ||
129 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
130 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
131 | SND_SOC_DAPM_HP("Headset Stereophone", NULL), | ||
132 | SND_SOC_DAPM_LINE("Aux In", NULL), | ||
133 | }; | ||
134 | |||
135 | static const struct snd_soc_dapm_route audio_map[] = { | ||
136 | /* External Mics: MAINMIC, SUBMIC with bias*/ | ||
137 | {"MAINMIC", NULL, "Mic Bias 1"}, | ||
138 | {"SUBMIC", NULL, "Mic Bias 2"}, | ||
139 | {"Mic Bias 1", NULL, "Ext Mic"}, | ||
140 | {"Mic Bias 2", NULL, "Ext Mic"}, | ||
141 | |||
142 | /* External Speakers: HFL, HFR */ | ||
143 | {"Ext Spk", NULL, "HFL"}, | ||
144 | {"Ext Spk", NULL, "HFR"}, | ||
145 | |||
146 | /* Headset Stereophone: HSOL, HSOR */ | ||
147 | {"Headset Stereophone", NULL, "HSOL"}, | ||
148 | {"Headset Stereophone", NULL, "HSOR"}, | ||
149 | |||
150 | /* Headset Mic: HSMIC with bias */ | ||
151 | {"HSMIC", NULL, "Headset Mic Bias"}, | ||
152 | {"Headset Mic Bias", NULL, "Headset Mic"}, | ||
153 | |||
154 | /* Aux In: AUXL, AUXR */ | ||
155 | {"Aux In", NULL, "AUXL"}, | ||
156 | {"Aux In", NULL, "AUXR"}, | ||
157 | }; | ||
158 | |||
159 | static int zoom2_twl4030_init(struct snd_soc_codec *codec) | ||
160 | { | ||
161 | int ret; | ||
162 | |||
163 | /* Add Zoom2 specific widgets */ | ||
164 | ret = snd_soc_dapm_new_controls(codec, zoom2_twl4030_dapm_widgets, | ||
165 | ARRAY_SIZE(zoom2_twl4030_dapm_widgets)); | ||
166 | if (ret) | ||
167 | return ret; | ||
168 | |||
169 | /* Set up Zoom2 specific audio path audio_map */ | ||
170 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
171 | |||
172 | /* Zoom2 connected pins */ | ||
173 | snd_soc_dapm_enable_pin(codec, "Ext Mic"); | ||
174 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
175 | snd_soc_dapm_enable_pin(codec, "Headset Mic"); | ||
176 | snd_soc_dapm_enable_pin(codec, "Headset Stereophone"); | ||
177 | snd_soc_dapm_enable_pin(codec, "Aux In"); | ||
178 | |||
179 | /* TWL4030 not connected pins */ | ||
180 | snd_soc_dapm_nc_pin(codec, "CARKITMIC"); | ||
181 | snd_soc_dapm_nc_pin(codec, "DIGIMIC0"); | ||
182 | snd_soc_dapm_nc_pin(codec, "DIGIMIC1"); | ||
183 | |||
184 | snd_soc_dapm_nc_pin(codec, "OUTL"); | ||
185 | snd_soc_dapm_nc_pin(codec, "OUTR"); | ||
186 | snd_soc_dapm_nc_pin(codec, "EARPIECE"); | ||
187 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"); | ||
188 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"); | ||
189 | snd_soc_dapm_nc_pin(codec, "CARKITL"); | ||
190 | snd_soc_dapm_nc_pin(codec, "CARKITR"); | ||
191 | |||
192 | ret = snd_soc_dapm_sync(codec); | ||
193 | |||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static int zoom2_twl4030_voice_init(struct snd_soc_codec *codec) | ||
198 | { | ||
199 | unsigned short reg; | ||
200 | |||
201 | /* Enable voice interface */ | ||
202 | reg = codec->read(codec, TWL4030_REG_VOICE_IF); | ||
203 | reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN; | ||
204 | codec->write(codec, TWL4030_REG_VOICE_IF, reg); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | /* Digital audio interface glue - connects codec <--> CPU */ | ||
210 | static struct snd_soc_dai_link zoom2_dai[] = { | ||
211 | { | ||
212 | .name = "TWL4030 I2S", | ||
213 | .stream_name = "TWL4030 Audio", | ||
214 | .cpu_dai = &omap_mcbsp_dai[0], | ||
215 | .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], | ||
216 | .init = zoom2_twl4030_init, | ||
217 | .ops = &zoom2_ops, | ||
218 | }, | ||
219 | { | ||
220 | .name = "TWL4030 PCM", | ||
221 | .stream_name = "TWL4030 Voice", | ||
222 | .cpu_dai = &omap_mcbsp_dai[1], | ||
223 | .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE], | ||
224 | .init = zoom2_twl4030_voice_init, | ||
225 | .ops = &zoom2_voice_ops, | ||
226 | }, | ||
227 | }; | ||
228 | |||
229 | /* Audio machine driver */ | ||
230 | static struct snd_soc_card snd_soc_zoom2 = { | ||
231 | .name = "Zoom2", | ||
232 | .platform = &omap_soc_platform, | ||
233 | .dai_link = zoom2_dai, | ||
234 | .num_links = ARRAY_SIZE(zoom2_dai), | ||
235 | }; | ||
236 | |||
237 | /* twl4030 setup */ | ||
238 | static struct twl4030_setup_data twl4030_setup = { | ||
239 | .ramp_delay_value = 2, /* 81 ms */ | ||
240 | .sysclk = 26000, | ||
241 | }; | ||
242 | |||
243 | /* Audio subsystem */ | ||
244 | static struct snd_soc_device zoom2_snd_devdata = { | ||
245 | .card = &snd_soc_zoom2, | ||
246 | .codec_dev = &soc_codec_dev_twl4030, | ||
247 | .codec_data = &twl4030_setup, | ||
248 | }; | ||
249 | |||
250 | static struct platform_device *zoom2_snd_device; | ||
251 | |||
252 | static int __init zoom2_soc_init(void) | ||
253 | { | ||
254 | int ret; | ||
255 | |||
256 | if (!machine_is_omap_zoom2()) { | ||
257 | pr_debug("Not Zoom2!\n"); | ||
258 | return -ENODEV; | ||
259 | } | ||
260 | printk(KERN_INFO "Zoom2 SoC init\n"); | ||
261 | |||
262 | zoom2_snd_device = platform_device_alloc("soc-audio", -1); | ||
263 | if (!zoom2_snd_device) { | ||
264 | printk(KERN_ERR "Platform device allocation failed\n"); | ||
265 | return -ENOMEM; | ||
266 | } | ||
267 | |||
268 | platform_set_drvdata(zoom2_snd_device, &zoom2_snd_devdata); | ||
269 | zoom2_snd_devdata.dev = &zoom2_snd_device->dev; | ||
270 | *(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */ | ||
271 | *(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ | ||
272 | |||
273 | ret = platform_device_add(zoom2_snd_device); | ||
274 | if (ret) | ||
275 | goto err1; | ||
276 | |||
277 | BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0); | ||
278 | gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0); | ||
279 | |||
280 | return 0; | ||
281 | |||
282 | err1: | ||
283 | printk(KERN_ERR "Unable to add platform device\n"); | ||
284 | platform_device_put(zoom2_snd_device); | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | module_init(zoom2_soc_init); | ||
289 | |||
290 | static void __exit zoom2_soc_exit(void) | ||
291 | { | ||
292 | gpio_free(ZOOM2_HEADSET_MUX_GPIO); | ||
293 | |||
294 | platform_device_unregister(zoom2_snd_device); | ||
295 | } | ||
296 | module_exit(zoom2_soc_exit); | ||
297 | |||
298 | MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>"); | ||
299 | MODULE_DESCRIPTION("ALSA SoC Zoom2"); | ||
300 | MODULE_LICENSE("GPL"); | ||
301 | |||
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 326955dea36c..8889cd371608 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c | |||
@@ -20,12 +20,14 @@ | |||
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
23 | #include <linux/i2c.h> | ||
23 | 24 | ||
24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
26 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
27 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
28 | #include <sound/soc-dapm.h> | 29 | #include <sound/soc-dapm.h> |
30 | #include <sound/uda1380.h> | ||
29 | 31 | ||
30 | #include <mach/magician.h> | 32 | #include <mach/magician.h> |
31 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
@@ -447,34 +449,47 @@ static struct snd_soc_card snd_soc_card_magician = { | |||
447 | .platform = &pxa2xx_soc_platform, | 449 | .platform = &pxa2xx_soc_platform, |
448 | }; | 450 | }; |
449 | 451 | ||
450 | /* magician audio private data */ | ||
451 | static struct uda1380_setup_data magician_uda1380_setup = { | ||
452 | .i2c_address = 0x18, | ||
453 | .dac_clk = UDA1380_DAC_CLK_WSPLL, | ||
454 | }; | ||
455 | |||
456 | /* magician audio subsystem */ | 452 | /* magician audio subsystem */ |
457 | static struct snd_soc_device magician_snd_devdata = { | 453 | static struct snd_soc_device magician_snd_devdata = { |
458 | .card = &snd_soc_card_magician, | 454 | .card = &snd_soc_card_magician, |
459 | .codec_dev = &soc_codec_dev_uda1380, | 455 | .codec_dev = &soc_codec_dev_uda1380, |
460 | .codec_data = &magician_uda1380_setup, | ||
461 | }; | 456 | }; |
462 | 457 | ||
463 | static struct platform_device *magician_snd_device; | 458 | static struct platform_device *magician_snd_device; |
464 | 459 | ||
460 | /* | ||
461 | * FIXME: move into magician board file once merged into the pxa tree | ||
462 | */ | ||
463 | static struct uda1380_platform_data uda1380_info = { | ||
464 | .gpio_power = EGPIO_MAGICIAN_CODEC_POWER, | ||
465 | .gpio_reset = EGPIO_MAGICIAN_CODEC_RESET, | ||
466 | .dac_clk = UDA1380_DAC_CLK_WSPLL, | ||
467 | }; | ||
468 | |||
469 | static struct i2c_board_info i2c_board_info[] = { | ||
470 | { | ||
471 | I2C_BOARD_INFO("uda1380", 0x18), | ||
472 | .platform_data = &uda1380_info, | ||
473 | }, | ||
474 | }; | ||
475 | |||
465 | static int __init magician_init(void) | 476 | static int __init magician_init(void) |
466 | { | 477 | { |
467 | int ret; | 478 | int ret; |
479 | struct i2c_adapter *adapter; | ||
480 | struct i2c_client *client; | ||
468 | 481 | ||
469 | if (!machine_is_magician()) | 482 | if (!machine_is_magician()) |
470 | return -ENODEV; | 483 | return -ENODEV; |
471 | 484 | ||
472 | ret = gpio_request(EGPIO_MAGICIAN_CODEC_POWER, "CODEC_POWER"); | 485 | adapter = i2c_get_adapter(0); |
473 | if (ret) | 486 | if (!adapter) |
474 | goto err_request_power; | 487 | return -ENODEV; |
475 | ret = gpio_request(EGPIO_MAGICIAN_CODEC_RESET, "CODEC_RESET"); | 488 | client = i2c_new_device(adapter, i2c_board_info); |
476 | if (ret) | 489 | i2c_put_adapter(adapter); |
477 | goto err_request_reset; | 490 | if (!client) |
491 | return -ENODEV; | ||
492 | |||
478 | ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER"); | 493 | ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER"); |
479 | if (ret) | 494 | if (ret) |
480 | goto err_request_spk; | 495 | goto err_request_spk; |
@@ -491,14 +506,8 @@ static int __init magician_init(void) | |||
491 | if (ret) | 506 | if (ret) |
492 | goto err_request_in_sel1; | 507 | goto err_request_in_sel1; |
493 | 508 | ||
494 | gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 1); | ||
495 | gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0); | 509 | gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0); |
496 | 510 | ||
497 | /* we may need to have the clock running here - pH5 */ | ||
498 | gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 1); | ||
499 | udelay(5); | ||
500 | gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 0); | ||
501 | |||
502 | magician_snd_device = platform_device_alloc("soc-audio", -1); | 511 | magician_snd_device = platform_device_alloc("soc-audio", -1); |
503 | if (!magician_snd_device) { | 512 | if (!magician_snd_device) { |
504 | ret = -ENOMEM; | 513 | ret = -ENOMEM; |
@@ -526,10 +535,6 @@ err_request_mic: | |||
526 | err_request_ep: | 535 | err_request_ep: |
527 | gpio_free(EGPIO_MAGICIAN_SPK_POWER); | 536 | gpio_free(EGPIO_MAGICIAN_SPK_POWER); |
528 | err_request_spk: | 537 | err_request_spk: |
529 | gpio_free(EGPIO_MAGICIAN_CODEC_RESET); | ||
530 | err_request_reset: | ||
531 | gpio_free(EGPIO_MAGICIAN_CODEC_POWER); | ||
532 | err_request_power: | ||
533 | return ret; | 538 | return ret; |
534 | } | 539 | } |
535 | 540 | ||
@@ -540,15 +545,12 @@ static void __exit magician_exit(void) | |||
540 | gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0); | 545 | gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0); |
541 | gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0); | 546 | gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0); |
542 | gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0); | 547 | gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0); |
543 | gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 0); | ||
544 | 548 | ||
545 | gpio_free(EGPIO_MAGICIAN_IN_SEL1); | 549 | gpio_free(EGPIO_MAGICIAN_IN_SEL1); |
546 | gpio_free(EGPIO_MAGICIAN_IN_SEL0); | 550 | gpio_free(EGPIO_MAGICIAN_IN_SEL0); |
547 | gpio_free(EGPIO_MAGICIAN_MIC_POWER); | 551 | gpio_free(EGPIO_MAGICIAN_MIC_POWER); |
548 | gpio_free(EGPIO_MAGICIAN_EP_POWER); | 552 | gpio_free(EGPIO_MAGICIAN_EP_POWER); |
549 | gpio_free(EGPIO_MAGICIAN_SPK_POWER); | 553 | gpio_free(EGPIO_MAGICIAN_SPK_POWER); |
550 | gpio_free(EGPIO_MAGICIAN_CODEC_RESET); | ||
551 | gpio_free(EGPIO_MAGICIAN_CODEC_POWER); | ||
552 | } | 554 | } |
553 | 555 | ||
554 | module_init(magician_init); | 556 | module_init(magician_init); |
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 19c45409d94c..e22c5cef8fec 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -457,31 +457,27 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
457 | return -EINVAL; | 457 | return -EINVAL; |
458 | } | 458 | } |
459 | 459 | ||
460 | ssp_write_reg(ssp, SSCR0, sscr0); | 460 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
461 | ssp_write_reg(ssp, SSCR1, sscr1); | 461 | case SND_SOC_DAIFMT_NB_NF: |
462 | ssp_write_reg(ssp, SSPSP, sspsp); | 462 | sspsp |= SSPSP_SFRMP; |
463 | break; | ||
464 | case SND_SOC_DAIFMT_NB_IF: | ||
465 | break; | ||
466 | case SND_SOC_DAIFMT_IB_IF: | ||
467 | sspsp |= SSPSP_SCMODE(2); | ||
468 | break; | ||
469 | case SND_SOC_DAIFMT_IB_NF: | ||
470 | sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; | ||
471 | break; | ||
472 | default: | ||
473 | return -EINVAL; | ||
474 | } | ||
463 | 475 | ||
464 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 476 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
465 | case SND_SOC_DAIFMT_I2S: | 477 | case SND_SOC_DAIFMT_I2S: |
466 | sscr0 |= SSCR0_PSP; | 478 | sscr0 |= SSCR0_PSP; |
467 | sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; | 479 | sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; |
468 | |||
469 | /* See hw_params() */ | 480 | /* See hw_params() */ |
470 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
471 | case SND_SOC_DAIFMT_NB_NF: | ||
472 | sspsp |= SSPSP_SFRMP; | ||
473 | break; | ||
474 | case SND_SOC_DAIFMT_NB_IF: | ||
475 | break; | ||
476 | case SND_SOC_DAIFMT_IB_IF: | ||
477 | sspsp |= SSPSP_SCMODE(2); | ||
478 | break; | ||
479 | case SND_SOC_DAIFMT_IB_NF: | ||
480 | sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; | ||
481 | break; | ||
482 | default: | ||
483 | return -EINVAL; | ||
484 | } | ||
485 | break; | 481 | break; |
486 | 482 | ||
487 | case SND_SOC_DAIFMT_DSP_A: | 483 | case SND_SOC_DAIFMT_DSP_A: |
@@ -489,22 +485,6 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
489 | case SND_SOC_DAIFMT_DSP_B: | 485 | case SND_SOC_DAIFMT_DSP_B: |
490 | sscr0 |= SSCR0_MOD | SSCR0_PSP; | 486 | sscr0 |= SSCR0_MOD | SSCR0_PSP; |
491 | sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; | 487 | sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; |
492 | |||
493 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
494 | case SND_SOC_DAIFMT_NB_NF: | ||
495 | sspsp |= SSPSP_SFRMP; | ||
496 | break; | ||
497 | case SND_SOC_DAIFMT_NB_IF: | ||
498 | break; | ||
499 | case SND_SOC_DAIFMT_IB_IF: | ||
500 | sspsp |= SSPSP_SCMODE(2); | ||
501 | break; | ||
502 | case SND_SOC_DAIFMT_IB_NF: | ||
503 | sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; | ||
504 | break; | ||
505 | default: | ||
506 | return -EINVAL; | ||
507 | } | ||
508 | break; | 488 | break; |
509 | 489 | ||
510 | default: | 490 | default: |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1d70829464ef..235503230fe7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -788,6 +788,45 @@ static int soc_resume(struct platform_device *pdev) | |||
788 | return 0; | 788 | return 0; |
789 | } | 789 | } |
790 | 790 | ||
791 | /** | ||
792 | * snd_soc_suspend_device: Notify core of device suspend | ||
793 | * | ||
794 | * @dev: Device being suspended. | ||
795 | * | ||
796 | * In order to ensure that the entire audio subsystem is suspended in a | ||
797 | * coordinated fashion ASoC devices should suspend themselves when | ||
798 | * called by ASoC. When the standard kernel suspend process asks the | ||
799 | * device to suspend it should call this function to initiate a suspend | ||
800 | * of the entire ASoC card. | ||
801 | * | ||
802 | * \note Currently this function is stubbed out. | ||
803 | */ | ||
804 | int snd_soc_suspend_device(struct device *dev) | ||
805 | { | ||
806 | return 0; | ||
807 | } | ||
808 | EXPORT_SYMBOL_GPL(snd_soc_suspend_device); | ||
809 | |||
810 | /** | ||
811 | * snd_soc_resume_device: Notify core of device resume | ||
812 | * | ||
813 | * @dev: Device being resumed. | ||
814 | * | ||
815 | * In order to ensure that the entire audio subsystem is resumed in a | ||
816 | * coordinated fashion ASoC devices should resume themselves when called | ||
817 | * by ASoC. When the standard kernel resume process asks the device | ||
818 | * to resume it should call this function. Once all the components of | ||
819 | * the card have notified that they are ready to be resumed the card | ||
820 | * will be resumed. | ||
821 | * | ||
822 | * \note Currently this function is stubbed out. | ||
823 | */ | ||
824 | int snd_soc_resume_device(struct device *dev) | ||
825 | { | ||
826 | return 0; | ||
827 | } | ||
828 | EXPORT_SYMBOL_GPL(snd_soc_resume_device); | ||
829 | |||
791 | #else | 830 | #else |
792 | #define soc_suspend NULL | 831 | #define soc_suspend NULL |
793 | #define soc_resume NULL | 832 | #define soc_resume NULL |
@@ -981,6 +1020,21 @@ static int soc_remove(struct platform_device *pdev) | |||
981 | return 0; | 1020 | return 0; |
982 | } | 1021 | } |
983 | 1022 | ||
1023 | static void soc_shutdown(struct platform_device *pdev) | ||
1024 | { | ||
1025 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1026 | struct snd_soc_card *card = socdev->card; | ||
1027 | |||
1028 | if (!card->instantiated) | ||
1029 | return; | ||
1030 | |||
1031 | /* Flush out pmdown_time work - we actually do want to run it | ||
1032 | * now, we're shutting down so no imminent restart. */ | ||
1033 | run_delayed_work(&card->delayed_work); | ||
1034 | |||
1035 | snd_soc_dapm_shutdown(socdev); | ||
1036 | } | ||
1037 | |||
984 | /* ASoC platform driver */ | 1038 | /* ASoC platform driver */ |
985 | static struct platform_driver soc_driver = { | 1039 | static struct platform_driver soc_driver = { |
986 | .driver = { | 1040 | .driver = { |
@@ -991,6 +1045,7 @@ static struct platform_driver soc_driver = { | |||
991 | .remove = soc_remove, | 1045 | .remove = soc_remove, |
992 | .suspend = soc_suspend, | 1046 | .suspend = soc_suspend, |
993 | .resume = soc_resume, | 1047 | .resume = soc_resume, |
1048 | .shutdown = soc_shutdown, | ||
994 | }; | 1049 | }; |
995 | 1050 | ||
996 | /* create a new pcm */ | 1051 | /* create a new pcm */ |
@@ -1264,10 +1319,10 @@ EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | |||
1264 | * Returns 1 for change else 0. | 1319 | * Returns 1 for change else 0. |
1265 | */ | 1320 | */ |
1266 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | 1321 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, |
1267 | unsigned short mask, unsigned short value) | 1322 | unsigned int mask, unsigned int value) |
1268 | { | 1323 | { |
1269 | int change; | 1324 | int change; |
1270 | unsigned short old, new; | 1325 | unsigned int old, new; |
1271 | 1326 | ||
1272 | mutex_lock(&io_mutex); | 1327 | mutex_lock(&io_mutex); |
1273 | old = snd_soc_read(codec, reg); | 1328 | old = snd_soc_read(codec, reg); |
@@ -1294,10 +1349,10 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits); | |||
1294 | * Returns 1 for change else 0. | 1349 | * Returns 1 for change else 0. |
1295 | */ | 1350 | */ |
1296 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | 1351 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, |
1297 | unsigned short mask, unsigned short value) | 1352 | unsigned int mask, unsigned int value) |
1298 | { | 1353 | { |
1299 | int change; | 1354 | int change; |
1300 | unsigned short old, new; | 1355 | unsigned int old, new; |
1301 | 1356 | ||
1302 | mutex_lock(&io_mutex); | 1357 | mutex_lock(&io_mutex); |
1303 | old = snd_soc_read(codec, reg); | 1358 | old = snd_soc_read(codec, reg); |
@@ -1586,7 +1641,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
1586 | { | 1641 | { |
1587 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1642 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1588 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1643 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1589 | unsigned short val, bitmask; | 1644 | unsigned int val, bitmask; |
1590 | 1645 | ||
1591 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 1646 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1592 | ; | 1647 | ; |
@@ -1615,8 +1670,8 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1615 | { | 1670 | { |
1616 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1671 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1617 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1672 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1618 | unsigned short val; | 1673 | unsigned int val; |
1619 | unsigned short mask, bitmask; | 1674 | unsigned int mask, bitmask; |
1620 | 1675 | ||
1621 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 1676 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1622 | ; | 1677 | ; |
@@ -1652,7 +1707,7 @@ int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1652 | { | 1707 | { |
1653 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1708 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1654 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1709 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1655 | unsigned short reg_val, val, mux; | 1710 | unsigned int reg_val, val, mux; |
1656 | 1711 | ||
1657 | reg_val = snd_soc_read(codec, e->reg); | 1712 | reg_val = snd_soc_read(codec, e->reg); |
1658 | val = (reg_val >> e->shift_l) & e->mask; | 1713 | val = (reg_val >> e->shift_l) & e->mask; |
@@ -1691,8 +1746,8 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1691 | { | 1746 | { |
1692 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1747 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1693 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1748 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1694 | unsigned short val; | 1749 | unsigned int val; |
1695 | unsigned short mask; | 1750 | unsigned int mask; |
1696 | 1751 | ||
1697 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 1752 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
1698 | return -EINVAL; | 1753 | return -EINVAL; |
@@ -1852,7 +1907,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
1852 | int max = mc->max; | 1907 | int max = mc->max; |
1853 | unsigned int mask = (1 << fls(max)) - 1; | 1908 | unsigned int mask = (1 << fls(max)) - 1; |
1854 | unsigned int invert = mc->invert; | 1909 | unsigned int invert = mc->invert; |
1855 | unsigned short val, val2, val_mask; | 1910 | unsigned int val, val2, val_mask; |
1856 | 1911 | ||
1857 | val = (ucontrol->value.integer.value[0] & mask); | 1912 | val = (ucontrol->value.integer.value[0] & mask); |
1858 | if (invert) | 1913 | if (invert) |
@@ -1918,7 +1973,7 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1918 | unsigned int reg2 = mc->rreg; | 1973 | unsigned int reg2 = mc->rreg; |
1919 | unsigned int shift = mc->shift; | 1974 | unsigned int shift = mc->shift; |
1920 | int max = mc->max; | 1975 | int max = mc->max; |
1921 | unsigned int mask = (1<<fls(max))-1; | 1976 | unsigned int mask = (1 << fls(max)) - 1; |
1922 | unsigned int invert = mc->invert; | 1977 | unsigned int invert = mc->invert; |
1923 | 1978 | ||
1924 | ucontrol->value.integer.value[0] = | 1979 | ucontrol->value.integer.value[0] = |
@@ -1958,7 +2013,7 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1958 | unsigned int mask = (1 << fls(max)) - 1; | 2013 | unsigned int mask = (1 << fls(max)) - 1; |
1959 | unsigned int invert = mc->invert; | 2014 | unsigned int invert = mc->invert; |
1960 | int err; | 2015 | int err; |
1961 | unsigned short val, val2, val_mask; | 2016 | unsigned int val, val2, val_mask; |
1962 | 2017 | ||
1963 | val_mask = mask << shift; | 2018 | val_mask = mask << shift; |
1964 | val = (ucontrol->value.integer.value[0] & mask); | 2019 | val = (ucontrol->value.integer.value[0] & mask); |
@@ -2050,7 +2105,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | |||
2050 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2105 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2051 | unsigned int reg = mc->reg; | 2106 | unsigned int reg = mc->reg; |
2052 | int min = mc->min; | 2107 | int min = mc->min; |
2053 | unsigned short val; | 2108 | unsigned int val; |
2054 | 2109 | ||
2055 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | 2110 | val = (ucontrol->value.integer.value[0]+min) & 0xff; |
2056 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; | 2111 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 21c69074aa17..b9129efeedf3 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -52,19 +52,37 @@ | |||
52 | 52 | ||
53 | /* dapm power sequences - make this per codec in the future */ | 53 | /* dapm power sequences - make this per codec in the future */ |
54 | static int dapm_up_seq[] = { | 54 | static int dapm_up_seq[] = { |
55 | snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias, | 55 | [snd_soc_dapm_pre] = 0, |
56 | snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux, | 56 | [snd_soc_dapm_supply] = 1, |
57 | snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, | 57 | [snd_soc_dapm_micbias] = 2, |
58 | snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, | 58 | [snd_soc_dapm_mic] = 3, |
59 | snd_soc_dapm_post | 59 | [snd_soc_dapm_mux] = 4, |
60 | [snd_soc_dapm_value_mux] = 4, | ||
61 | [snd_soc_dapm_dac] = 5, | ||
62 | [snd_soc_dapm_mixer] = 6, | ||
63 | [snd_soc_dapm_mixer_named_ctl] = 6, | ||
64 | [snd_soc_dapm_pga] = 7, | ||
65 | [snd_soc_dapm_adc] = 8, | ||
66 | [snd_soc_dapm_hp] = 9, | ||
67 | [snd_soc_dapm_spk] = 10, | ||
68 | [snd_soc_dapm_post] = 11, | ||
60 | }; | 69 | }; |
61 | 70 | ||
62 | static int dapm_down_seq[] = { | 71 | static int dapm_down_seq[] = { |
63 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, | 72 | [snd_soc_dapm_pre] = 0, |
64 | snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer, | 73 | [snd_soc_dapm_adc] = 1, |
65 | snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias, | 74 | [snd_soc_dapm_hp] = 2, |
66 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply, | 75 | [snd_soc_dapm_spk] = 3, |
67 | snd_soc_dapm_post | 76 | [snd_soc_dapm_pga] = 4, |
77 | [snd_soc_dapm_mixer_named_ctl] = 5, | ||
78 | [snd_soc_dapm_mixer] = 5, | ||
79 | [snd_soc_dapm_dac] = 6, | ||
80 | [snd_soc_dapm_mic] = 7, | ||
81 | [snd_soc_dapm_micbias] = 8, | ||
82 | [snd_soc_dapm_mux] = 9, | ||
83 | [snd_soc_dapm_value_mux] = 9, | ||
84 | [snd_soc_dapm_supply] = 10, | ||
85 | [snd_soc_dapm_post] = 11, | ||
68 | }; | 86 | }; |
69 | 87 | ||
70 | static void pop_wait(u32 pop_time) | 88 | static void pop_wait(u32 pop_time) |
@@ -268,7 +286,7 @@ static int dapm_connect_mixer(struct snd_soc_codec *codec, | |||
268 | static int dapm_update_bits(struct snd_soc_dapm_widget *widget) | 286 | static int dapm_update_bits(struct snd_soc_dapm_widget *widget) |
269 | { | 287 | { |
270 | int change, power; | 288 | int change, power; |
271 | unsigned short old, new; | 289 | unsigned int old, new; |
272 | struct snd_soc_codec *codec = widget->codec; | 290 | struct snd_soc_codec *codec = widget->codec; |
273 | 291 | ||
274 | /* check for valid widgets */ | 292 | /* check for valid widgets */ |
@@ -689,53 +707,211 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
689 | return power; | 707 | return power; |
690 | } | 708 | } |
691 | 709 | ||
692 | /* | 710 | static int dapm_seq_compare(struct snd_soc_dapm_widget *a, |
693 | * Scan a single DAPM widget for a complete audio path and update the | 711 | struct snd_soc_dapm_widget *b, |
694 | * power status appropriately. | 712 | int sort[]) |
695 | */ | ||
696 | static int dapm_power_widget(struct snd_soc_codec *codec, int event, | ||
697 | struct snd_soc_dapm_widget *w) | ||
698 | { | 713 | { |
699 | int ret; | 714 | if (sort[a->id] != sort[b->id]) |
715 | return sort[a->id] - sort[b->id]; | ||
716 | if (a->reg != b->reg) | ||
717 | return a->reg - b->reg; | ||
700 | 718 | ||
701 | switch (w->id) { | 719 | return 0; |
702 | case snd_soc_dapm_pre: | 720 | } |
703 | if (!w->event) | ||
704 | return 0; | ||
705 | 721 | ||
706 | if (event == SND_SOC_DAPM_STREAM_START) { | 722 | /* Insert a widget in order into a DAPM power sequence. */ |
707 | ret = w->event(w, | 723 | static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, |
708 | NULL, SND_SOC_DAPM_PRE_PMU); | 724 | struct list_head *list, |
725 | int sort[]) | ||
726 | { | ||
727 | struct snd_soc_dapm_widget *w; | ||
728 | |||
729 | list_for_each_entry(w, list, power_list) | ||
730 | if (dapm_seq_compare(new_widget, w, sort) < 0) { | ||
731 | list_add_tail(&new_widget->power_list, &w->power_list); | ||
732 | return; | ||
733 | } | ||
734 | |||
735 | list_add_tail(&new_widget->power_list, list); | ||
736 | } | ||
737 | |||
738 | /* Apply the coalesced changes from a DAPM sequence */ | ||
739 | static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, | ||
740 | struct list_head *pending) | ||
741 | { | ||
742 | struct snd_soc_dapm_widget *w; | ||
743 | int reg, power, ret; | ||
744 | unsigned int value = 0; | ||
745 | unsigned int mask = 0; | ||
746 | unsigned int cur_mask; | ||
747 | |||
748 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, | ||
749 | power_list)->reg; | ||
750 | |||
751 | list_for_each_entry(w, pending, power_list) { | ||
752 | cur_mask = 1 << w->shift; | ||
753 | BUG_ON(reg != w->reg); | ||
754 | |||
755 | if (w->invert) | ||
756 | power = !w->power; | ||
757 | else | ||
758 | power = w->power; | ||
759 | |||
760 | mask |= cur_mask; | ||
761 | if (power) | ||
762 | value |= cur_mask; | ||
763 | |||
764 | pop_dbg(codec->pop_time, | ||
765 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", | ||
766 | w->name, reg, value, mask); | ||
767 | |||
768 | /* power up pre event */ | ||
769 | if (w->power && w->event && | ||
770 | (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { | ||
771 | pop_dbg(codec->pop_time, "pop test : %s PRE_PMU\n", | ||
772 | w->name); | ||
773 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); | ||
709 | if (ret < 0) | 774 | if (ret < 0) |
710 | return ret; | 775 | pr_err("%s: pre event failed: %d\n", |
711 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | 776 | w->name, ret); |
712 | ret = w->event(w, | 777 | } |
713 | NULL, SND_SOC_DAPM_PRE_PMD); | 778 | |
779 | /* power down pre event */ | ||
780 | if (!w->power && w->event && | ||
781 | (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { | ||
782 | pop_dbg(codec->pop_time, "pop test : %s PRE_PMD\n", | ||
783 | w->name); | ||
784 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); | ||
714 | if (ret < 0) | 785 | if (ret < 0) |
715 | return ret; | 786 | pr_err("%s: pre event failed: %d\n", |
787 | w->name, ret); | ||
716 | } | 788 | } |
717 | return 0; | ||
718 | 789 | ||
719 | case snd_soc_dapm_post: | 790 | /* Lower PGA volume to reduce pops */ |
720 | if (!w->event) | 791 | if (w->id == snd_soc_dapm_pga && !w->power) |
721 | return 0; | 792 | dapm_set_pga(w, w->power); |
793 | } | ||
722 | 794 | ||
723 | if (event == SND_SOC_DAPM_STREAM_START) { | 795 | if (reg >= 0) { |
796 | pop_dbg(codec->pop_time, | ||
797 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | ||
798 | value, mask, reg, codec->pop_time); | ||
799 | pop_wait(codec->pop_time); | ||
800 | snd_soc_update_bits(codec, reg, mask, value); | ||
801 | } | ||
802 | |||
803 | list_for_each_entry(w, pending, power_list) { | ||
804 | /* Raise PGA volume to reduce pops */ | ||
805 | if (w->id == snd_soc_dapm_pga && w->power) | ||
806 | dapm_set_pga(w, w->power); | ||
807 | |||
808 | /* power up post event */ | ||
809 | if (w->power && w->event && | ||
810 | (w->event_flags & SND_SOC_DAPM_POST_PMU)) { | ||
811 | pop_dbg(codec->pop_time, "pop test : %s POST_PMU\n", | ||
812 | w->name); | ||
724 | ret = w->event(w, | 813 | ret = w->event(w, |
725 | NULL, SND_SOC_DAPM_POST_PMU); | 814 | NULL, SND_SOC_DAPM_POST_PMU); |
726 | if (ret < 0) | 815 | if (ret < 0) |
727 | return ret; | 816 | pr_err("%s: post event failed: %d\n", |
728 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | 817 | w->name, ret); |
729 | ret = w->event(w, | 818 | } |
730 | NULL, SND_SOC_DAPM_POST_PMD); | 819 | |
820 | /* power down post event */ | ||
821 | if (!w->power && w->event && | ||
822 | (w->event_flags & SND_SOC_DAPM_POST_PMD)) { | ||
823 | pop_dbg(codec->pop_time, "pop test : %s POST_PMD\n", | ||
824 | w->name); | ||
825 | ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); | ||
731 | if (ret < 0) | 826 | if (ret < 0) |
732 | return ret; | 827 | pr_err("%s: post event failed: %d\n", |
828 | w->name, ret); | ||
733 | } | 829 | } |
734 | return 0; | 830 | } |
831 | } | ||
735 | 832 | ||
736 | default: | 833 | /* Apply a DAPM power sequence. |
737 | return dapm_generic_apply_power(w); | 834 | * |
835 | * We walk over a pre-sorted list of widgets to apply power to. In | ||
836 | * order to minimise the number of writes to the device required | ||
837 | * multiple widgets will be updated in a single write where possible. | ||
838 | * Currently anything that requires more than a single write is not | ||
839 | * handled. | ||
840 | */ | ||
841 | static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, | ||
842 | int event, int sort[]) | ||
843 | { | ||
844 | struct snd_soc_dapm_widget *w, *n; | ||
845 | LIST_HEAD(pending); | ||
846 | int cur_sort = -1; | ||
847 | int cur_reg = SND_SOC_NOPM; | ||
848 | int ret; | ||
849 | |||
850 | list_for_each_entry_safe(w, n, list, power_list) { | ||
851 | ret = 0; | ||
852 | |||
853 | /* Do we need to apply any queued changes? */ | ||
854 | if (sort[w->id] != cur_sort || w->reg != cur_reg) { | ||
855 | if (!list_empty(&pending)) | ||
856 | dapm_seq_run_coalesced(codec, &pending); | ||
857 | |||
858 | INIT_LIST_HEAD(&pending); | ||
859 | cur_sort = -1; | ||
860 | cur_reg = SND_SOC_NOPM; | ||
861 | } | ||
862 | |||
863 | switch (w->id) { | ||
864 | case snd_soc_dapm_pre: | ||
865 | if (!w->event) | ||
866 | list_for_each_entry_safe_continue(w, n, list, | ||
867 | power_list); | ||
868 | |||
869 | if (event == SND_SOC_DAPM_STREAM_START) | ||
870 | ret = w->event(w, | ||
871 | NULL, SND_SOC_DAPM_PRE_PMU); | ||
872 | else if (event == SND_SOC_DAPM_STREAM_STOP) | ||
873 | ret = w->event(w, | ||
874 | NULL, SND_SOC_DAPM_PRE_PMD); | ||
875 | break; | ||
876 | |||
877 | case snd_soc_dapm_post: | ||
878 | if (!w->event) | ||
879 | list_for_each_entry_safe_continue(w, n, list, | ||
880 | power_list); | ||
881 | |||
882 | if (event == SND_SOC_DAPM_STREAM_START) | ||
883 | ret = w->event(w, | ||
884 | NULL, SND_SOC_DAPM_POST_PMU); | ||
885 | else if (event == SND_SOC_DAPM_STREAM_STOP) | ||
886 | ret = w->event(w, | ||
887 | NULL, SND_SOC_DAPM_POST_PMD); | ||
888 | break; | ||
889 | |||
890 | case snd_soc_dapm_input: | ||
891 | case snd_soc_dapm_output: | ||
892 | case snd_soc_dapm_hp: | ||
893 | case snd_soc_dapm_mic: | ||
894 | case snd_soc_dapm_line: | ||
895 | case snd_soc_dapm_spk: | ||
896 | /* No register support currently */ | ||
897 | ret = dapm_generic_apply_power(w); | ||
898 | break; | ||
899 | |||
900 | default: | ||
901 | /* Queue it up for application */ | ||
902 | cur_sort = sort[w->id]; | ||
903 | cur_reg = w->reg; | ||
904 | list_move(&w->power_list, &pending); | ||
905 | break; | ||
906 | } | ||
907 | |||
908 | if (ret < 0) | ||
909 | pr_err("Failed to apply widget power: %d\n", | ||
910 | ret); | ||
738 | } | 911 | } |
912 | |||
913 | if (!list_empty(&pending)) | ||
914 | dapm_seq_run_coalesced(codec, &pending); | ||
739 | } | 915 | } |
740 | 916 | ||
741 | /* | 917 | /* |
@@ -751,23 +927,22 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
751 | { | 927 | { |
752 | struct snd_soc_device *socdev = codec->socdev; | 928 | struct snd_soc_device *socdev = codec->socdev; |
753 | struct snd_soc_dapm_widget *w; | 929 | struct snd_soc_dapm_widget *w; |
930 | LIST_HEAD(up_list); | ||
931 | LIST_HEAD(down_list); | ||
754 | int ret = 0; | 932 | int ret = 0; |
755 | int i, power; | 933 | int power; |
756 | int sys_power = 0; | 934 | int sys_power = 0; |
757 | 935 | ||
758 | INIT_LIST_HEAD(&codec->up_list); | ||
759 | INIT_LIST_HEAD(&codec->down_list); | ||
760 | |||
761 | /* Check which widgets we need to power and store them in | 936 | /* Check which widgets we need to power and store them in |
762 | * lists indicating if they should be powered up or down. | 937 | * lists indicating if they should be powered up or down. |
763 | */ | 938 | */ |
764 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 939 | list_for_each_entry(w, &codec->dapm_widgets, list) { |
765 | switch (w->id) { | 940 | switch (w->id) { |
766 | case snd_soc_dapm_pre: | 941 | case snd_soc_dapm_pre: |
767 | list_add_tail(&codec->down_list, &w->power_list); | 942 | dapm_seq_insert(w, &down_list, dapm_down_seq); |
768 | break; | 943 | break; |
769 | case snd_soc_dapm_post: | 944 | case snd_soc_dapm_post: |
770 | list_add_tail(&codec->up_list, &w->power_list); | 945 | dapm_seq_insert(w, &up_list, dapm_up_seq); |
771 | break; | 946 | break; |
772 | 947 | ||
773 | default: | 948 | default: |
@@ -782,10 +957,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
782 | continue; | 957 | continue; |
783 | 958 | ||
784 | if (power) | 959 | if (power) |
785 | list_add_tail(&w->power_list, &codec->up_list); | 960 | dapm_seq_insert(w, &up_list, dapm_up_seq); |
786 | else | 961 | else |
787 | list_add_tail(&w->power_list, | 962 | dapm_seq_insert(w, &down_list, dapm_down_seq); |
788 | &codec->down_list); | ||
789 | 963 | ||
790 | w->power = power; | 964 | w->power = power; |
791 | break; | 965 | break; |
@@ -802,32 +976,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
802 | } | 976 | } |
803 | 977 | ||
804 | /* Power down widgets first; try to avoid amplifying pops. */ | 978 | /* Power down widgets first; try to avoid amplifying pops. */ |
805 | for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) { | 979 | dapm_seq_run(codec, &down_list, event, dapm_down_seq); |
806 | list_for_each_entry(w, &codec->down_list, power_list) { | ||
807 | /* is widget in stream order */ | ||
808 | if (w->id != dapm_down_seq[i]) | ||
809 | continue; | ||
810 | |||
811 | ret = dapm_power_widget(codec, event, w); | ||
812 | if (ret != 0) | ||
813 | pr_err("Failed to power down %s: %d\n", | ||
814 | w->name, ret); | ||
815 | } | ||
816 | } | ||
817 | 980 | ||
818 | /* Now power up. */ | 981 | /* Now power up. */ |
819 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) { | 982 | dapm_seq_run(codec, &up_list, event, dapm_up_seq); |
820 | list_for_each_entry(w, &codec->up_list, power_list) { | ||
821 | /* is widget in stream order */ | ||
822 | if (w->id != dapm_up_seq[i]) | ||
823 | continue; | ||
824 | |||
825 | ret = dapm_power_widget(codec, event, w); | ||
826 | if (ret != 0) | ||
827 | pr_err("Failed to power up %s: %d\n", | ||
828 | w->name, ret); | ||
829 | } | ||
830 | } | ||
831 | 983 | ||
832 | /* If we just powered the last thing off drop to standby bias */ | 984 | /* If we just powered the last thing off drop to standby bias */ |
833 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { | 985 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { |
@@ -1372,7 +1524,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1372 | int max = mc->max; | 1524 | int max = mc->max; |
1373 | unsigned int mask = (1 << fls(max)) - 1; | 1525 | unsigned int mask = (1 << fls(max)) - 1; |
1374 | unsigned int invert = mc->invert; | 1526 | unsigned int invert = mc->invert; |
1375 | unsigned short val, val2, val_mask; | 1527 | unsigned int val, val2, val_mask; |
1376 | int ret; | 1528 | int ret; |
1377 | 1529 | ||
1378 | val = (ucontrol->value.integer.value[0] & mask); | 1530 | val = (ucontrol->value.integer.value[0] & mask); |
@@ -1436,7 +1588,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
1436 | { | 1588 | { |
1437 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1589 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1438 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1590 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1439 | unsigned short val, bitmask; | 1591 | unsigned int val, bitmask; |
1440 | 1592 | ||
1441 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 1593 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1442 | ; | 1594 | ; |
@@ -1464,8 +1616,8 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1464 | { | 1616 | { |
1465 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1617 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1466 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1618 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1467 | unsigned short val, mux; | 1619 | unsigned int val, mux; |
1468 | unsigned short mask, bitmask; | 1620 | unsigned int mask, bitmask; |
1469 | int ret = 0; | 1621 | int ret = 0; |
1470 | 1622 | ||
1471 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 1623 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
@@ -1523,7 +1675,7 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1523 | { | 1675 | { |
1524 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1676 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1525 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1677 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1526 | unsigned short reg_val, val, mux; | 1678 | unsigned int reg_val, val, mux; |
1527 | 1679 | ||
1528 | reg_val = snd_soc_read(widget->codec, e->reg); | 1680 | reg_val = snd_soc_read(widget->codec, e->reg); |
1529 | val = (reg_val >> e->shift_l) & e->mask; | 1681 | val = (reg_val >> e->shift_l) & e->mask; |
@@ -1563,8 +1715,8 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1563 | { | 1715 | { |
1564 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1716 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1565 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1717 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1566 | unsigned short val, mux; | 1718 | unsigned int val, mux; |
1567 | unsigned short mask; | 1719 | unsigned int mask; |
1568 | int ret = 0; | 1720 | int ret = 0; |
1569 | 1721 | ||
1570 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 1722 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
@@ -1880,6 +2032,35 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev) | |||
1880 | } | 2032 | } |
1881 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); | 2033 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); |
1882 | 2034 | ||
2035 | /* | ||
2036 | * snd_soc_dapm_shutdown - callback for system shutdown | ||
2037 | */ | ||
2038 | void snd_soc_dapm_shutdown(struct snd_soc_device *socdev) | ||
2039 | { | ||
2040 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2041 | struct snd_soc_dapm_widget *w; | ||
2042 | LIST_HEAD(down_list); | ||
2043 | int powerdown = 0; | ||
2044 | |||
2045 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
2046 | if (w->power) { | ||
2047 | dapm_seq_insert(w, &down_list, dapm_down_seq); | ||
2048 | powerdown = 1; | ||
2049 | } | ||
2050 | } | ||
2051 | |||
2052 | /* If there were no widgets to power down we're already in | ||
2053 | * standby. | ||
2054 | */ | ||
2055 | if (powerdown) { | ||
2056 | snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE); | ||
2057 | dapm_seq_run(codec, &down_list, 0, dapm_down_seq); | ||
2058 | snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY); | ||
2059 | } | ||
2060 | |||
2061 | snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); | ||
2062 | } | ||
2063 | |||
1883 | /* Module information */ | 2064 | /* Module information */ |
1884 | MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); | 2065 | MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); |
1885 | MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); | 2066 | MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); |