diff options
Diffstat (limited to 'sound')
47 files changed, 1490 insertions, 449 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index ef025c66cc66..3d2bb6fc6dcc 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -6,6 +6,7 @@ menuconfig SND_SOC | |||
6 | tristate "ALSA for SoC audio support" | 6 | tristate "ALSA for SoC audio support" |
7 | select SND_PCM | 7 | select SND_PCM |
8 | select AC97_BUS if SND_SOC_AC97_BUS | 8 | select AC97_BUS if SND_SOC_AC97_BUS |
9 | select SND_JACK if INPUT=y || INPUT=SND | ||
9 | ---help--- | 10 | ---help--- |
10 | 11 | ||
11 | If you want ASoC support, you should say Y here and also to the | 12 | If you want ASoC support, you should say Y here and also to the |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 86a9b1f5b0f3..0237879fd412 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o |
2 | 2 | ||
3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | 3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o |
4 | obj-$(CONFIG_SND_SOC) += codecs/ | 4 | obj-$(CONFIG_SND_SOC) += codecs/ |
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 3dcdc4e3cfa0..9ef6b96373f5 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c | |||
@@ -347,7 +347,7 @@ static int atmel_pcm_mmap(struct snd_pcm_substream *substream, | |||
347 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | 347 | vma->vm_end - vma->vm_start, vma->vm_page_prot); |
348 | } | 348 | } |
349 | 349 | ||
350 | struct snd_pcm_ops atmel_pcm_ops = { | 350 | static struct snd_pcm_ops atmel_pcm_ops = { |
351 | .open = atmel_pcm_open, | 351 | .open = atmel_pcm_open, |
352 | .close = atmel_pcm_close, | 352 | .close = atmel_pcm_close, |
353 | .ioctl = snd_pcm_lib_ioctl, | 353 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index bc8d654576c0..30490a259148 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c | |||
@@ -305,7 +305,7 @@ static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) | |||
305 | return 0; | 305 | return 0; |
306 | } | 306 | } |
307 | 307 | ||
308 | struct snd_pcm_ops au1xpsc_pcm_ops = { | 308 | static struct snd_pcm_ops au1xpsc_pcm_ops = { |
309 | .open = au1xpsc_pcm_open, | 309 | .open = au1xpsc_pcm_open, |
310 | .close = au1xpsc_pcm_close, | 310 | .close = au1xpsc_pcm_close, |
311 | .ioctl = snd_pcm_lib_ioctl, | 311 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 8067cfafa3a7..8cfed1a5dcbe 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c | |||
@@ -297,7 +297,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
297 | } | 297 | } |
298 | #endif | 298 | #endif |
299 | 299 | ||
300 | struct snd_pcm_ops bf5xx_pcm_ac97_ops = { | 300 | static struct snd_pcm_ops bf5xx_pcm_ac97_ops = { |
301 | .open = bf5xx_pcm_open, | 301 | .open = bf5xx_pcm_open, |
302 | .ioctl = snd_pcm_lib_ioctl, | 302 | .ioctl = snd_pcm_lib_ioctl, |
303 | .hw_params = bf5xx_pcm_hw_params, | 303 | .hw_params = bf5xx_pcm_hw_params, |
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 53d290b3ea47..1318c4f627b7 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c | |||
@@ -184,7 +184,7 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, | |||
184 | return 0 ; | 184 | return 0 ; |
185 | } | 185 | } |
186 | 186 | ||
187 | struct snd_pcm_ops bf5xx_pcm_i2s_ops = { | 187 | static struct snd_pcm_ops bf5xx_pcm_i2s_ops = { |
188 | .open = bf5xx_pcm_open, | 188 | .open = bf5xx_pcm_open, |
189 | .ioctl = snd_pcm_lib_ioctl, | 189 | .ioctl = snd_pcm_lib_ioctl, |
190 | .hw_params = bf5xx_pcm_hw_params, | 190 | .hw_params = bf5xx_pcm_hw_params, |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d0e0d691ae51..cb5fcd605acc 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -34,6 +34,7 @@ config SND_SOC_ALL_CODECS | |||
34 | select SND_SOC_WM8903 if I2C | 34 | select SND_SOC_WM8903 if I2C |
35 | select SND_SOC_WM8971 if I2C | 35 | select SND_SOC_WM8971 if I2C |
36 | select SND_SOC_WM8990 if I2C | 36 | select SND_SOC_WM8990 if I2C |
37 | select SND_SOC_WM9705 if SND_SOC_AC97_BUS | ||
37 | select SND_SOC_WM9712 if SND_SOC_AC97_BUS | 38 | select SND_SOC_WM9712 if SND_SOC_AC97_BUS |
38 | select SND_SOC_WM9713 if SND_SOC_AC97_BUS | 39 | select SND_SOC_WM9713 if SND_SOC_AC97_BUS |
39 | help | 40 | help |
@@ -144,6 +145,9 @@ config SND_SOC_WM8971 | |||
144 | config SND_SOC_WM8990 | 145 | config SND_SOC_WM8990 |
145 | tristate | 146 | tristate |
146 | 147 | ||
148 | config SND_SOC_WM9705 | ||
149 | tristate | ||
150 | |||
147 | config SND_SOC_WM9712 | 151 | config SND_SOC_WM9712 |
148 | tristate | 152 | tristate |
149 | 153 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index c4ddc9aa2bbd..3664cdc300b2 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -23,6 +23,7 @@ snd-soc-wm8900-objs := wm8900.o | |||
23 | snd-soc-wm8903-objs := wm8903.o | 23 | snd-soc-wm8903-objs := wm8903.o |
24 | snd-soc-wm8971-objs := wm8971.o | 24 | snd-soc-wm8971-objs := wm8971.o |
25 | snd-soc-wm8990-objs := wm8990.o | 25 | snd-soc-wm8990-objs := wm8990.o |
26 | snd-soc-wm9705-objs := wm9705.o | ||
26 | snd-soc-wm9712-objs := wm9712.o | 27 | snd-soc-wm9712-objs := wm9712.o |
27 | snd-soc-wm9713-objs := wm9713.o | 28 | snd-soc-wm9713-objs := wm9713.o |
28 | 29 | ||
@@ -51,5 +52,7 @@ obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o | |||
51 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | 52 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o |
52 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o | 53 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o |
53 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | 54 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o |
55 | obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o | ||
56 | obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o | ||
54 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 57 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
55 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 58 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index fb53e6511af2..89d41277616d 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -123,7 +123,6 @@ bus_err: | |||
123 | snd_soc_free_pcms(socdev); | 123 | snd_soc_free_pcms(socdev); |
124 | 124 | ||
125 | err: | 125 | err: |
126 | kfree(socdev->codec->reg_cache); | ||
127 | kfree(socdev->codec); | 126 | kfree(socdev->codec); |
128 | socdev->codec = NULL; | 127 | socdev->codec = NULL; |
129 | return ret; | 128 | return ret; |
@@ -138,7 +137,6 @@ static int ac97_soc_remove(struct platform_device *pdev) | |||
138 | return 0; | 137 | return 0; |
139 | 138 | ||
140 | snd_soc_free_pcms(socdev); | 139 | snd_soc_free_pcms(socdev); |
141 | kfree(socdev->codec->reg_cache); | ||
142 | kfree(socdev->codec); | 140 | kfree(socdev->codec); |
143 | 141 | ||
144 | return 0; | 142 | return 0; |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 73fdbb4d4a3d..faf358758e13 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -93,20 +93,6 @@ SOC_ENUM("Capture Source", ad1980_cap_src), | |||
93 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), | 93 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), |
94 | }; | 94 | }; |
95 | 95 | ||
96 | /* add non dapm controls */ | ||
97 | static int ad1980_add_controls(struct snd_soc_codec *codec) | ||
98 | { | ||
99 | int err, i; | ||
100 | |||
101 | for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) { | ||
102 | err = snd_ctl_add(codec->card, snd_soc_cnew( | ||
103 | &ad1980_snd_ac97_controls[i], codec, NULL)); | ||
104 | if (err < 0) | ||
105 | return err; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 96 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
111 | unsigned int reg) | 97 | unsigned int reg) |
112 | { | 98 | { |
@@ -123,7 +109,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
123 | default: | 109 | default: |
124 | reg = reg >> 1; | 110 | reg = reg >> 1; |
125 | 111 | ||
126 | if (reg >= (ARRAY_SIZE(ad1980_reg))) | 112 | if (reg >= ARRAY_SIZE(ad1980_reg)) |
127 | return -EINVAL; | 113 | return -EINVAL; |
128 | 114 | ||
129 | return cache[reg]; | 115 | return cache[reg]; |
@@ -137,7 +123,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
137 | 123 | ||
138 | soc_ac97_ops.write(codec->ac97, reg, val); | 124 | soc_ac97_ops.write(codec->ac97, reg, val); |
139 | reg = reg >> 1; | 125 | reg = reg >> 1; |
140 | if (reg < (ARRAY_SIZE(ad1980_reg))) | 126 | if (reg < ARRAY_SIZE(ad1980_reg)) |
141 | cache[reg] = val; | 127 | cache[reg] = val; |
142 | 128 | ||
143 | return 0; | 129 | return 0; |
@@ -269,7 +255,8 @@ static int ad1980_soc_probe(struct platform_device *pdev) | |||
269 | ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); | 255 | ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); |
270 | ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); | 256 | ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); |
271 | 257 | ||
272 | ad1980_add_controls(codec); | 258 | snd_soc_add_controls(codec, ad1980_snd_ac97_controls, |
259 | ARRAY_SIZE(ad1980_snd_ac97_controls)); | ||
273 | ret = snd_soc_init_card(socdev); | 260 | ret = snd_soc_init_card(socdev); |
274 | if (ret < 0) { | 261 | if (ret < 0) { |
275 | printk(KERN_ERR "ad1980: failed to register card\n"); | 262 | printk(KERN_ERR "ad1980: failed to register card\n"); |
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 81300d8d42ca..f17c363cb1db 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -155,21 +155,6 @@ static const struct snd_kcontrol_new ak4535_snd_controls[] = { | |||
155 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), | 155 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), |
156 | }; | 156 | }; |
157 | 157 | ||
158 | /* add non dapm controls */ | ||
159 | static int ak4535_add_controls(struct snd_soc_codec *codec) | ||
160 | { | ||
161 | int err, i; | ||
162 | |||
163 | for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) { | ||
164 | err = snd_ctl_add(codec->card, | ||
165 | snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL)); | ||
166 | if (err < 0) | ||
167 | return err; | ||
168 | } | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* Mono 1 Mixer */ | 158 | /* Mono 1 Mixer */ |
174 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { | 159 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { |
175 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), | 160 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), |
@@ -510,7 +495,8 @@ static int ak4535_init(struct snd_soc_device *socdev) | |||
510 | /* power on device */ | 495 | /* power on device */ |
511 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 496 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
512 | 497 | ||
513 | ak4535_add_controls(codec); | 498 | snd_soc_add_controls(codec, ak4535_snd_controls, |
499 | ARRAY_SIZE(ak4535_snd_controls)); | ||
514 | ak4535_add_widgets(codec); | 500 | ak4535_add_widgets(codec); |
515 | ret = snd_soc_init_card(socdev); | 501 | ret = snd_soc_init_card(socdev); |
516 | if (ret < 0) { | 502 | if (ret < 0) { |
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index cac373616768..ec7fe3b7b0cb 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -151,21 +151,6 @@ SOC_ENUM("Capture Source", ssm2602_enum[0]), | |||
151 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), | 151 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), |
152 | }; | 152 | }; |
153 | 153 | ||
154 | /* add non dapm controls */ | ||
155 | static int ssm2602_add_controls(struct snd_soc_codec *codec) | ||
156 | { | ||
157 | int err, i; | ||
158 | |||
159 | for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) { | ||
160 | err = snd_ctl_add(codec->card, | ||
161 | snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL)); | ||
162 | if (err < 0) | ||
163 | return err; | ||
164 | } | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | /* Output Mixer */ | 154 | /* Output Mixer */ |
170 | static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { | 155 | static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { |
171 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), | 156 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), |
@@ -622,7 +607,8 @@ static int ssm2602_init(struct snd_soc_device *socdev) | |||
622 | APANA_ENABLE_MIC_BOOST); | 607 | APANA_ENABLE_MIC_BOOST); |
623 | ssm2602_write(codec, SSM2602_PWR, 0); | 608 | ssm2602_write(codec, SSM2602_PWR, 0); |
624 | 609 | ||
625 | ssm2602_add_controls(codec); | 610 | snd_soc_add_controls(codec, ssm2602_snd_controls, |
611 | ARRAY_SIZE(ssm2602_snd_controls)); | ||
626 | ssm2602_add_widgets(codec); | 612 | ssm2602_add_widgets(codec); |
627 | ret = snd_soc_init_card(socdev); | 613 | ret = snd_soc_init_card(socdev); |
628 | if (ret < 0) { | 614 | if (ret < 0) { |
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index cfdea007c4cb..a0e47c1dcd64 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -183,24 +183,6 @@ static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = { | |||
183 | SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph), | 183 | SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph), |
184 | }; | 184 | }; |
185 | 185 | ||
186 | /* add non dapm controls */ | ||
187 | static int tlv320aic23_add_controls(struct snd_soc_codec *codec) | ||
188 | { | ||
189 | |||
190 | int err, i; | ||
191 | |||
192 | for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) { | ||
193 | err = snd_ctl_add(codec->card, | ||
194 | snd_soc_cnew(&tlv320aic23_snd_controls[i], | ||
195 | codec, NULL)); | ||
196 | if (err < 0) | ||
197 | return err; | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | |||
202 | } | ||
203 | |||
204 | /* PGA Mixer controls for Line and Mic switch */ | 186 | /* PGA Mixer controls for Line and Mic switch */ |
205 | static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = { | 187 | static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = { |
206 | SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0), | 188 | SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0), |
@@ -718,7 +700,8 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) | |||
718 | 700 | ||
719 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1); | 701 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1); |
720 | 702 | ||
721 | tlv320aic23_add_controls(codec); | 703 | snd_soc_add_controls(codec, tlv320aic23_snd_controls, |
704 | ARRAY_SIZE(tlv320aic23_snd_controls)); | ||
722 | tlv320aic23_add_widgets(codec); | 705 | tlv320aic23_add_widgets(codec); |
723 | ret = snd_soc_init_card(socdev); | 706 | ret = snd_soc_init_card(socdev); |
724 | if (ret < 0) { | 707 | if (ret < 0) { |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b47a749c5ea2..36ab0198ca3f 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -311,22 +311,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
311 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | 311 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), |
312 | }; | 312 | }; |
313 | 313 | ||
314 | /* add non dapm controls */ | ||
315 | static int aic3x_add_controls(struct snd_soc_codec *codec) | ||
316 | { | ||
317 | int err, i; | ||
318 | |||
319 | for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) { | ||
320 | err = snd_ctl_add(codec->card, | ||
321 | snd_soc_cnew(&aic3x_snd_controls[i], | ||
322 | codec, NULL)); | ||
323 | if (err < 0) | ||
324 | return err; | ||
325 | } | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | /* Left DAC Mux */ | 314 | /* Left DAC Mux */ |
331 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | 315 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = |
332 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); | 316 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); |
@@ -1224,7 +1208,8 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
1224 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); | 1208 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); |
1225 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); | 1209 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); |
1226 | 1210 | ||
1227 | aic3x_add_controls(codec); | 1211 | snd_soc_add_controls(codec, aic3x_snd_controls, |
1212 | ARRAY_SIZE(aic3x_snd_controls)); | ||
1228 | aic3x_add_widgets(codec); | 1213 | aic3x_add_widgets(codec); |
1229 | ret = snd_soc_init_card(socdev); | 1214 | ret = snd_soc_init_card(socdev); |
1230 | if (ret < 0) { | 1215 | if (ret < 0) { |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ea370a4f86d5..f530c1e6d9e8 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -125,6 +125,9 @@ static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, | |||
125 | { | 125 | { |
126 | u8 *cache = codec->reg_cache; | 126 | u8 *cache = codec->reg_cache; |
127 | 127 | ||
128 | if (reg >= TWL4030_CACHEREGNUM) | ||
129 | return -EIO; | ||
130 | |||
128 | return cache[reg]; | 131 | return cache[reg]; |
129 | } | 132 | } |
130 | 133 | ||
@@ -670,22 +673,6 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { | |||
670 | 0, 3, 5, 0, input_gain_tlv), | 673 | 0, 3, 5, 0, input_gain_tlv), |
671 | }; | 674 | }; |
672 | 675 | ||
673 | /* add non dapm controls */ | ||
674 | static int twl4030_add_controls(struct snd_soc_codec *codec) | ||
675 | { | ||
676 | int err, i; | ||
677 | |||
678 | for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) { | ||
679 | err = snd_ctl_add(codec->card, | ||
680 | snd_soc_cnew(&twl4030_snd_controls[i], | ||
681 | codec, NULL)); | ||
682 | if (err < 0) | ||
683 | return err; | ||
684 | } | ||
685 | |||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | 676 | static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { |
690 | /* Left channel inputs */ | 677 | /* Left channel inputs */ |
691 | SND_SOC_DAPM_INPUT("MAINMIC"), | 678 | SND_SOC_DAPM_INPUT("MAINMIC"), |
@@ -1233,7 +1220,8 @@ static int twl4030_init(struct snd_soc_device *socdev) | |||
1233 | /* power on device */ | 1220 | /* power on device */ |
1234 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1221 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1235 | 1222 | ||
1236 | twl4030_add_controls(codec); | 1223 | snd_soc_add_controls(codec, twl4030_snd_controls, |
1224 | ARRAY_SIZE(twl4030_snd_controls)); | ||
1237 | twl4030_add_widgets(codec); | 1225 | twl4030_add_widgets(codec); |
1238 | 1226 | ||
1239 | ret = snd_soc_init_card(socdev); | 1227 | ret = snd_soc_init_card(socdev); |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index a2c5064a774b..277825d155a6 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -431,39 +431,6 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), | |||
431 | SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), | 431 | SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), |
432 | }; | 432 | }; |
433 | 433 | ||
434 | static int uda134x_add_controls(struct snd_soc_codec *codec) | ||
435 | { | ||
436 | int err, i, n; | ||
437 | const struct snd_kcontrol_new *ctrls; | ||
438 | struct uda134x_platform_data *pd = codec->control_data; | ||
439 | |||
440 | switch (pd->model) { | ||
441 | case UDA134X_UDA1340: | ||
442 | case UDA134X_UDA1344: | ||
443 | n = ARRAY_SIZE(uda1340_snd_controls); | ||
444 | ctrls = uda1340_snd_controls; | ||
445 | break; | ||
446 | case UDA134X_UDA1341: | ||
447 | n = ARRAY_SIZE(uda1341_snd_controls); | ||
448 | ctrls = uda1341_snd_controls; | ||
449 | break; | ||
450 | default: | ||
451 | printk(KERN_ERR "%s unkown codec type: %d", | ||
452 | __func__, pd->model); | ||
453 | return -EINVAL; | ||
454 | } | ||
455 | |||
456 | for (i = 0; i < n; i++) { | ||
457 | err = snd_ctl_add(codec->card, | ||
458 | snd_soc_cnew(&ctrls[i], | ||
459 | codec, NULL)); | ||
460 | if (err < 0) | ||
461 | return err; | ||
462 | } | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | struct snd_soc_dai uda134x_dai = { | 434 | struct snd_soc_dai uda134x_dai = { |
468 | .name = "UDA134X", | 435 | .name = "UDA134X", |
469 | /* playback capabilities */ | 436 | /* playback capabilities */ |
@@ -572,7 +539,22 @@ static int uda134x_soc_probe(struct platform_device *pdev) | |||
572 | goto pcm_err; | 539 | goto pcm_err; |
573 | } | 540 | } |
574 | 541 | ||
575 | ret = uda134x_add_controls(codec); | 542 | switch (pd->model) { |
543 | case UDA134X_UDA1340: | ||
544 | case UDA134X_UDA1344: | ||
545 | ret = snd_soc_add_controls(codec, uda1340_snd_controls, | ||
546 | ARRAY_SIZE(uda1340_snd_controls)); | ||
547 | break; | ||
548 | case UDA134X_UDA1341: | ||
549 | ret = snd_soc_add_controls(codec, uda1341_snd_controls, | ||
550 | ARRAY_SIZE(uda1341_snd_controls)); | ||
551 | break; | ||
552 | default: | ||
553 | printk(KERN_ERR "%s unkown codec type: %d", | ||
554 | __func__, pd->model); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
576 | if (ret < 0) { | 558 | if (ret < 0) { |
577 | printk(KERN_ERR "UDA134X: failed to register controls\n"); | 559 | printk(KERN_ERR "UDA134X: failed to register controls\n"); |
578 | goto pcm_err; | 560 | goto pcm_err; |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index e6bf0844fbf3..a957b4365b9d 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -271,21 +271,6 @@ static const struct snd_kcontrol_new uda1380_snd_controls[] = { | |||
271 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), | 271 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), |
272 | }; | 272 | }; |
273 | 273 | ||
274 | /* add non dapm controls */ | ||
275 | static int uda1380_add_controls(struct snd_soc_codec *codec) | ||
276 | { | ||
277 | int err, i; | ||
278 | |||
279 | for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) { | ||
280 | err = snd_ctl_add(codec->card, | ||
281 | snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL)); | ||
282 | if (err < 0) | ||
283 | return err; | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | /* Input mux */ | 274 | /* Input mux */ |
290 | static const struct snd_kcontrol_new uda1380_input_mux_control = | 275 | static const struct snd_kcontrol_new uda1380_input_mux_control = |
291 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); | 276 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); |
@@ -675,7 +660,8 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | |||
675 | } | 660 | } |
676 | 661 | ||
677 | /* uda1380 init */ | 662 | /* uda1380 init */ |
678 | uda1380_add_controls(codec); | 663 | snd_soc_add_controls(codec, uda1380_snd_controls, |
664 | ARRAY_SIZE(uda1380_snd_controls)); | ||
679 | uda1380_add_widgets(codec); | 665 | uda1380_add_widgets(codec); |
680 | ret = snd_soc_init_card(socdev); | 666 | ret = snd_soc_init_card(socdev); |
681 | if (ret < 0) { | 667 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index e3989d406f54..2e0db29b4998 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -51,10 +51,17 @@ struct wm8350_output { | |||
51 | u16 mute; | 51 | u16 mute; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | struct wm8350_jack_data { | ||
55 | struct snd_soc_jack *jack; | ||
56 | int report; | ||
57 | }; | ||
58 | |||
54 | struct wm8350_data { | 59 | struct wm8350_data { |
55 | struct snd_soc_codec codec; | 60 | struct snd_soc_codec codec; |
56 | struct wm8350_output out1; | 61 | struct wm8350_output out1; |
57 | struct wm8350_output out2; | 62 | struct wm8350_output out2; |
63 | struct wm8350_jack_data hpl; | ||
64 | struct wm8350_jack_data hpr; | ||
58 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | 65 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; |
59 | }; | 66 | }; |
60 | 67 | ||
@@ -775,21 +782,6 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
775 | {"Beep", NULL, "IN3R PGA"}, | 782 | {"Beep", NULL, "IN3R PGA"}, |
776 | }; | 783 | }; |
777 | 784 | ||
778 | static int wm8350_add_controls(struct snd_soc_codec *codec) | ||
779 | { | ||
780 | int err, i; | ||
781 | |||
782 | for (i = 0; i < ARRAY_SIZE(wm8350_snd_controls); i++) { | ||
783 | err = snd_ctl_add(codec->card, | ||
784 | snd_soc_cnew(&wm8350_snd_controls[i], | ||
785 | codec, NULL)); | ||
786 | if (err < 0) | ||
787 | return err; | ||
788 | } | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int wm8350_add_widgets(struct snd_soc_codec *codec) | 785 | static int wm8350_add_widgets(struct snd_soc_codec *codec) |
794 | { | 786 | { |
795 | int ret; | 787 | int ret; |
@@ -1328,6 +1320,95 @@ static int wm8350_resume(struct platform_device *pdev) | |||
1328 | return 0; | 1320 | return 0; |
1329 | } | 1321 | } |
1330 | 1322 | ||
1323 | static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data) | ||
1324 | { | ||
1325 | struct wm8350_data *priv = data; | ||
1326 | u16 reg; | ||
1327 | int report; | ||
1328 | int mask; | ||
1329 | struct wm8350_jack_data *jack = NULL; | ||
1330 | |||
1331 | switch (irq) { | ||
1332 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
1333 | jack = &priv->hpl; | ||
1334 | mask = WM8350_JACK_L_LVL; | ||
1335 | break; | ||
1336 | |||
1337 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
1338 | jack = &priv->hpr; | ||
1339 | mask = WM8350_JACK_R_LVL; | ||
1340 | break; | ||
1341 | |||
1342 | default: | ||
1343 | BUG(); | ||
1344 | } | ||
1345 | |||
1346 | if (!jack->jack) { | ||
1347 | dev_warn(wm8350->dev, "Jack interrupt called with no jack\n"); | ||
1348 | return; | ||
1349 | } | ||
1350 | |||
1351 | /* Debounce */ | ||
1352 | msleep(200); | ||
1353 | |||
1354 | reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); | ||
1355 | if (reg & mask) | ||
1356 | report = jack->report; | ||
1357 | else | ||
1358 | report = 0; | ||
1359 | |||
1360 | snd_soc_jack_report(jack->jack, report, jack->report); | ||
1361 | } | ||
1362 | |||
1363 | /** | ||
1364 | * wm8350_hp_jack_detect - Enable headphone jack detection. | ||
1365 | * | ||
1366 | * @codec: WM8350 codec | ||
1367 | * @which: left or right jack detect signal | ||
1368 | * @jack: jack to report detection events on | ||
1369 | * @report: value to report | ||
1370 | * | ||
1371 | * Enables the headphone jack detection of the WM8350. | ||
1372 | */ | ||
1373 | int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, | ||
1374 | struct snd_soc_jack *jack, int report) | ||
1375 | { | ||
1376 | struct wm8350_data *priv = codec->private_data; | ||
1377 | struct wm8350 *wm8350 = codec->control_data; | ||
1378 | int irq; | ||
1379 | int ena; | ||
1380 | |||
1381 | switch (which) { | ||
1382 | case WM8350_JDL: | ||
1383 | priv->hpl.jack = jack; | ||
1384 | priv->hpl.report = report; | ||
1385 | irq = WM8350_IRQ_CODEC_JCK_DET_L; | ||
1386 | ena = WM8350_JDL_ENA; | ||
1387 | break; | ||
1388 | |||
1389 | case WM8350_JDR: | ||
1390 | priv->hpr.jack = jack; | ||
1391 | priv->hpr.report = report; | ||
1392 | irq = WM8350_IRQ_CODEC_JCK_DET_R; | ||
1393 | ena = WM8350_JDR_ENA; | ||
1394 | break; | ||
1395 | |||
1396 | default: | ||
1397 | return -EINVAL; | ||
1398 | } | ||
1399 | |||
1400 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); | ||
1401 | wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); | ||
1402 | |||
1403 | /* Sync status */ | ||
1404 | wm8350_hp_jack_handler(wm8350, irq, priv); | ||
1405 | |||
1406 | wm8350_unmask_irq(wm8350, irq); | ||
1407 | |||
1408 | return 0; | ||
1409 | } | ||
1410 | EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect); | ||
1411 | |||
1331 | static struct snd_soc_codec *wm8350_codec; | 1412 | static struct snd_soc_codec *wm8350_codec; |
1332 | 1413 | ||
1333 | static int wm8350_probe(struct platform_device *pdev) | 1414 | static int wm8350_probe(struct platform_device *pdev) |
@@ -1381,13 +1462,21 @@ static int wm8350_probe(struct platform_device *pdev) | |||
1381 | wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, | 1462 | wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, |
1382 | WM8350_OUT2_VU | WM8350_OUT2R_MUTE); | 1463 | WM8350_OUT2_VU | WM8350_OUT2R_MUTE); |
1383 | 1464 | ||
1465 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1466 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1467 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, | ||
1468 | wm8350_hp_jack_handler, priv); | ||
1469 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, | ||
1470 | wm8350_hp_jack_handler, priv); | ||
1471 | |||
1384 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1472 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
1385 | if (ret < 0) { | 1473 | if (ret < 0) { |
1386 | dev_err(&pdev->dev, "failed to create pcms\n"); | 1474 | dev_err(&pdev->dev, "failed to create pcms\n"); |
1387 | return ret; | 1475 | return ret; |
1388 | } | 1476 | } |
1389 | 1477 | ||
1390 | wm8350_add_controls(codec); | 1478 | snd_soc_add_controls(codec, wm8350_snd_controls, |
1479 | ARRAY_SIZE(wm8350_snd_controls)); | ||
1391 | wm8350_add_widgets(codec); | 1480 | wm8350_add_widgets(codec); |
1392 | 1481 | ||
1393 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1482 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
@@ -1411,8 +1500,21 @@ static int wm8350_remove(struct platform_device *pdev) | |||
1411 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1500 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1412 | struct snd_soc_codec *codec = socdev->codec; | 1501 | struct snd_soc_codec *codec = socdev->codec; |
1413 | struct wm8350 *wm8350 = codec->control_data; | 1502 | struct wm8350 *wm8350 = codec->control_data; |
1503 | struct wm8350_data *priv = codec->private_data; | ||
1414 | int ret; | 1504 | int ret; |
1415 | 1505 | ||
1506 | wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, | ||
1507 | WM8350_JDL_ENA | WM8350_JDR_ENA); | ||
1508 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); | ||
1509 | |||
1510 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1511 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1512 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1513 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1514 | |||
1515 | priv->hpl.jack = NULL; | ||
1516 | priv->hpr.jack = NULL; | ||
1517 | |||
1416 | /* cancel any work waiting to be queued. */ | 1518 | /* cancel any work waiting to be queued. */ |
1417 | ret = cancel_delayed_work(&codec->delayed_work); | 1519 | ret = cancel_delayed_work(&codec->delayed_work); |
1418 | 1520 | ||
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h index cc2887aa6c38..d11bd9288cf9 100644 --- a/sound/soc/codecs/wm8350.h +++ b/sound/soc/codecs/wm8350.h | |||
@@ -17,4 +17,12 @@ | |||
17 | extern struct snd_soc_dai wm8350_dai; | 17 | extern struct snd_soc_dai wm8350_dai; |
18 | extern struct snd_soc_codec_device soc_codec_dev_wm8350; | 18 | extern struct snd_soc_codec_device soc_codec_dev_wm8350; |
19 | 19 | ||
20 | enum wm8350_jack { | ||
21 | WM8350_JDL = 1, | ||
22 | WM8350_JDR = 2, | ||
23 | }; | ||
24 | |||
25 | int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, | ||
26 | struct snd_soc_jack *jack, int report); | ||
27 | |||
20 | #endif | 28 | #endif |
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 40f8238df717..abe7cce87714 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -171,22 +171,6 @@ SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0), | |||
171 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), | 171 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), |
172 | }; | 172 | }; |
173 | 173 | ||
174 | /* add non dapm controls */ | ||
175 | static int wm8510_add_controls(struct snd_soc_codec *codec) | ||
176 | { | ||
177 | int err, i; | ||
178 | |||
179 | for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) { | ||
180 | err = snd_ctl_add(codec->card, | ||
181 | snd_soc_cnew(&wm8510_snd_controls[i], codec, | ||
182 | NULL)); | ||
183 | if (err < 0) | ||
184 | return err; | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* Speaker Output Mixer */ | 174 | /* Speaker Output Mixer */ |
191 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { | 175 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { |
192 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), | 176 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), |
@@ -656,7 +640,8 @@ static int wm8510_init(struct snd_soc_device *socdev) | |||
656 | /* power on device */ | 640 | /* power on device */ |
657 | codec->bias_level = SND_SOC_BIAS_OFF; | 641 | codec->bias_level = SND_SOC_BIAS_OFF; |
658 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 642 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
659 | wm8510_add_controls(codec); | 643 | snd_soc_add_controls(codec, wm8510_snd_controls, |
644 | ARRAY_SIZE(wm8510_snd_controls)); | ||
660 | wm8510_add_widgets(codec); | 645 | wm8510_add_widgets(codec); |
661 | ret = snd_soc_init_card(socdev); | 646 | ret = snd_soc_init_card(socdev); |
662 | if (ret < 0) { | 647 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index d004e5845298..3faf0e70ce10 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -200,7 +200,7 @@ static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec, | |||
200 | unsigned int reg) | 200 | unsigned int reg) |
201 | { | 201 | { |
202 | u16 *cache = codec->reg_cache; | 202 | u16 *cache = codec->reg_cache; |
203 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | 203 | BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); |
204 | return cache[reg]; | 204 | return cache[reg]; |
205 | } | 205 | } |
206 | 206 | ||
@@ -223,7 +223,7 @@ static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg, | |||
223 | { | 223 | { |
224 | u8 data[2]; | 224 | u8 data[2]; |
225 | 225 | ||
226 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | 226 | BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); |
227 | 227 | ||
228 | /* Registers are 9 bits wide */ | 228 | /* Registers are 9 bits wide */ |
229 | value &= 0x1ff; | 229 | value &= 0x1ff; |
@@ -330,20 +330,6 @@ SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | |||
330 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | 330 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), |
331 | }; | 331 | }; |
332 | 332 | ||
333 | /* Add non-DAPM controls */ | ||
334 | static int wm8580_add_controls(struct snd_soc_codec *codec) | ||
335 | { | ||
336 | int err, i; | ||
337 | |||
338 | for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) { | ||
339 | err = snd_ctl_add(codec->card, | ||
340 | snd_soc_cnew(&wm8580_snd_controls[i], | ||
341 | codec, NULL)); | ||
342 | if (err < 0) | ||
343 | return err; | ||
344 | } | ||
345 | return 0; | ||
346 | } | ||
347 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { | 333 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { |
348 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), | 334 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), |
349 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), | 335 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), |
@@ -866,7 +852,8 @@ static int wm8580_init(struct snd_soc_device *socdev) | |||
866 | goto pcm_err; | 852 | goto pcm_err; |
867 | } | 853 | } |
868 | 854 | ||
869 | wm8580_add_controls(codec); | 855 | snd_soc_add_controls(codec, wm8580_snd_controls, |
856 | ARRAY_SIZE(wm8580_snd_controls)); | ||
870 | wm8580_add_widgets(codec); | 857 | wm8580_add_widgets(codec); |
871 | 858 | ||
872 | ret = snd_soc_init_card(socdev); | 859 | ret = snd_soc_init_card(socdev); |
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 80b11983e137..f90dc52e975d 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c | |||
@@ -47,7 +47,7 @@ static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, | |||
47 | unsigned int reg) | 47 | unsigned int reg) |
48 | { | 48 | { |
49 | u16 *cache = codec->reg_cache; | 49 | u16 *cache = codec->reg_cache; |
50 | BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); | 50 | BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); |
51 | return cache[reg]; | 51 | return cache[reg]; |
52 | } | 52 | } |
53 | 53 | ||
@@ -55,7 +55,7 @@ static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, | |||
55 | u16 reg, unsigned int value) | 55 | u16 reg, unsigned int value) |
56 | { | 56 | { |
57 | u16 *cache = codec->reg_cache; | 57 | u16 *cache = codec->reg_cache; |
58 | BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); | 58 | BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); |
59 | cache[reg] = value; | 59 | cache[reg] = value; |
60 | } | 60 | } |
61 | 61 | ||
@@ -92,21 +92,6 @@ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL, | |||
92 | SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), | 92 | SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), |
93 | }; | 93 | }; |
94 | 94 | ||
95 | static int wm8728_add_controls(struct snd_soc_codec *codec) | ||
96 | { | ||
97 | int err, i; | ||
98 | |||
99 | for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) { | ||
100 | err = snd_ctl_add(codec->card, | ||
101 | snd_soc_cnew(&wm8728_snd_controls[i], | ||
102 | codec, NULL)); | ||
103 | if (err < 0) | ||
104 | return err; | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* | 95 | /* |
111 | * DAPM controls. | 96 | * DAPM controls. |
112 | */ | 97 | */ |
@@ -330,7 +315,8 @@ static int wm8728_init(struct snd_soc_device *socdev) | |||
330 | /* power on device */ | 315 | /* power on device */ |
331 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 316 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
332 | 317 | ||
333 | wm8728_add_controls(codec); | 318 | snd_soc_add_controls(codec, wm8728_snd_controls, |
319 | ARRAY_SIZE(wm8728_snd_controls)); | ||
334 | wm8728_add_widgets(codec); | 320 | wm8728_add_widgets(codec); |
335 | ret = snd_soc_init_card(socdev); | 321 | ret = snd_soc_init_card(socdev); |
336 | if (ret < 0) { | 322 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index c444b9f2701e..96d6e1aeaf43 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -129,22 +129,6 @@ SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), | |||
129 | SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), | 129 | SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), |
130 | }; | 130 | }; |
131 | 131 | ||
132 | /* add non dapm controls */ | ||
133 | static int wm8731_add_controls(struct snd_soc_codec *codec) | ||
134 | { | ||
135 | int err, i; | ||
136 | |||
137 | for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) { | ||
138 | err = snd_ctl_add(codec->card, | ||
139 | snd_soc_cnew(&wm8731_snd_controls[i], | ||
140 | codec, NULL)); | ||
141 | if (err < 0) | ||
142 | return err; | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* Output Mixer */ | 132 | /* Output Mixer */ |
149 | static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { | 133 | static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { |
150 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), | 134 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), |
@@ -543,7 +527,8 @@ static int wm8731_init(struct snd_soc_device *socdev) | |||
543 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | 527 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); |
544 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); | 528 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); |
545 | 529 | ||
546 | wm8731_add_controls(codec); | 530 | snd_soc_add_controls(codec, wm8731_snd_controls, |
531 | ARRAY_SIZE(wm8731_snd_controls)); | ||
547 | wm8731_add_widgets(codec); | 532 | wm8731_add_widgets(codec); |
548 | ret = snd_soc_init_card(socdev); | 533 | ret = snd_soc_init_card(socdev); |
549 | if (ret < 0) { | 534 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 5997fa68e0d5..1578569793a2 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -231,21 +231,6 @@ SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), | |||
231 | 231 | ||
232 | }; | 232 | }; |
233 | 233 | ||
234 | /* add non dapm controls */ | ||
235 | static int wm8750_add_controls(struct snd_soc_codec *codec) | ||
236 | { | ||
237 | int err, i; | ||
238 | |||
239 | for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) { | ||
240 | err = snd_ctl_add(codec->card, | ||
241 | snd_soc_cnew(&wm8750_snd_controls[i], | ||
242 | codec, NULL)); | ||
243 | if (err < 0) | ||
244 | return err; | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | 234 | /* |
250 | * DAPM Controls | 235 | * DAPM Controls |
251 | */ | 236 | */ |
@@ -816,7 +801,8 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
816 | reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); | 801 | reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); |
817 | wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); | 802 | wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); |
818 | 803 | ||
819 | wm8750_add_controls(codec); | 804 | snd_soc_add_controls(codec, wm8750_snd_controls, |
805 | ARRAY_SIZE(wm8750_snd_controls)); | ||
820 | wm8750_add_widgets(codec); | 806 | wm8750_add_widgets(codec); |
821 | ret = snd_soc_init_card(socdev); | 807 | ret = snd_soc_init_card(socdev); |
822 | if (ret < 0) { | 808 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 6c21b50c9375..5a1c1fca120f 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -97,7 +97,7 @@ static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec, | |||
97 | unsigned int reg) | 97 | unsigned int reg) |
98 | { | 98 | { |
99 | u16 *cache = codec->reg_cache; | 99 | u16 *cache = codec->reg_cache; |
100 | if (reg < 1 || reg > (ARRAY_SIZE(wm8753_reg) + 1)) | 100 | if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1)) |
101 | return -1; | 101 | return -1; |
102 | return cache[reg - 1]; | 102 | return cache[reg - 1]; |
103 | } | 103 | } |
@@ -109,7 +109,7 @@ static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec, | |||
109 | unsigned int reg, unsigned int value) | 109 | unsigned int reg, unsigned int value) |
110 | { | 110 | { |
111 | u16 *cache = codec->reg_cache; | 111 | u16 *cache = codec->reg_cache; |
112 | if (reg < 1 || reg > 0x3f) | 112 | if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1)) |
113 | return; | 113 | return; |
114 | cache[reg - 1] = value; | 114 | cache[reg - 1] = value; |
115 | } | 115 | } |
@@ -339,21 +339,6 @@ SOC_ENUM("ADC Data Select", wm8753_enum[27]), | |||
339 | SOC_ENUM("ROUT2 Phase", wm8753_enum[28]), | 339 | SOC_ENUM("ROUT2 Phase", wm8753_enum[28]), |
340 | }; | 340 | }; |
341 | 341 | ||
342 | /* add non dapm controls */ | ||
343 | static int wm8753_add_controls(struct snd_soc_codec *codec) | ||
344 | { | ||
345 | int err, i; | ||
346 | |||
347 | for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) { | ||
348 | err = snd_ctl_add(codec->card, | ||
349 | snd_soc_cnew(&wm8753_snd_controls[i], | ||
350 | codec, NULL)); | ||
351 | if (err < 0) | ||
352 | return err; | ||
353 | } | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* | 342 | /* |
358 | * _DAPM_ Controls | 343 | * _DAPM_ Controls |
359 | */ | 344 | */ |
@@ -1603,7 +1588,8 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
1603 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); | 1588 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); |
1604 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); | 1589 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); |
1605 | 1590 | ||
1606 | wm8753_add_controls(codec); | 1591 | snd_soc_add_controls(codec, wm8753_snd_controls, |
1592 | ARRAY_SIZE(wm8753_snd_controls)); | ||
1607 | wm8753_add_widgets(codec); | 1593 | wm8753_add_widgets(codec); |
1608 | ret = snd_soc_init_card(socdev); | 1594 | ret = snd_soc_init_card(socdev); |
1609 | if (ret < 0) { | 1595 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 6767de10ded0..1e08d4f065f2 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -517,22 +517,6 @@ SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1, | |||
517 | 517 | ||
518 | }; | 518 | }; |
519 | 519 | ||
520 | /* add non dapm controls */ | ||
521 | static int wm8900_add_controls(struct snd_soc_codec *codec) | ||
522 | { | ||
523 | int err, i; | ||
524 | |||
525 | for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) { | ||
526 | err = snd_ctl_add(codec->card, | ||
527 | snd_soc_cnew(&wm8900_snd_controls[i], | ||
528 | codec, NULL)); | ||
529 | if (err < 0) | ||
530 | return err; | ||
531 | } | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = | 520 | static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = |
537 | SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); | 521 | SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); |
538 | 522 | ||
@@ -1439,7 +1423,8 @@ static int wm8900_probe(struct platform_device *pdev) | |||
1439 | goto pcm_err; | 1423 | goto pcm_err; |
1440 | } | 1424 | } |
1441 | 1425 | ||
1442 | wm8900_add_controls(codec); | 1426 | snd_soc_add_controls(codec, wm8900_snd_controls, |
1427 | ARRAY_SIZE(wm8900_snd_controls)); | ||
1443 | wm8900_add_widgets(codec); | 1428 | wm8900_add_widgets(codec); |
1444 | 1429 | ||
1445 | ret = snd_soc_init_card(socdev); | 1430 | ret = snd_soc_init_card(socdev); |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index bde74546db4a..6ff34b957dce 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -744,21 +744,6 @@ SOC_DOUBLE_R_TLV("Speaker Volume", | |||
744 | 0, 63, 0, out_tlv), | 744 | 0, 63, 0, out_tlv), |
745 | }; | 745 | }; |
746 | 746 | ||
747 | static int wm8903_add_controls(struct snd_soc_codec *codec) | ||
748 | { | ||
749 | int err, i; | ||
750 | |||
751 | for (i = 0; i < ARRAY_SIZE(wm8903_snd_controls); i++) { | ||
752 | err = snd_ctl_add(codec->card, | ||
753 | snd_soc_cnew(&wm8903_snd_controls[i], | ||
754 | codec, NULL)); | ||
755 | if (err < 0) | ||
756 | return err; | ||
757 | } | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static const struct snd_kcontrol_new linput_mode_mux = | 747 | static const struct snd_kcontrol_new linput_mode_mux = |
763 | SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum); | 748 | SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum); |
764 | 749 | ||
@@ -1737,7 +1722,8 @@ static int wm8903_probe(struct platform_device *pdev) | |||
1737 | goto err; | 1722 | goto err; |
1738 | } | 1723 | } |
1739 | 1724 | ||
1740 | wm8903_add_controls(socdev->codec); | 1725 | snd_soc_add_controls(socdev->codec, wm8903_snd_controls, |
1726 | ARRAY_SIZE(wm8903_snd_controls)); | ||
1741 | wm8903_add_widgets(socdev->codec); | 1727 | wm8903_add_widgets(socdev->codec); |
1742 | 1728 | ||
1743 | ret = snd_soc_init_card(socdev); | 1729 | ret = snd_soc_init_card(socdev); |
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 88ead7f8dd98..c8bd9b06f330 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c | |||
@@ -195,21 +195,6 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = { | |||
195 | SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), | 195 | SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), |
196 | }; | 196 | }; |
197 | 197 | ||
198 | /* add non-DAPM controls */ | ||
199 | static int wm8971_add_controls(struct snd_soc_codec *codec) | ||
200 | { | ||
201 | int err, i; | ||
202 | |||
203 | for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) { | ||
204 | err = snd_ctl_add(codec->card, | ||
205 | snd_soc_cnew(&wm8971_snd_controls[i], | ||
206 | codec, NULL)); | ||
207 | if (err < 0) | ||
208 | return err; | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | /* | 198 | /* |
214 | * DAPM Controls | 199 | * DAPM Controls |
215 | */ | 200 | */ |
@@ -745,7 +730,8 @@ static int wm8971_init(struct snd_soc_device *socdev) | |||
745 | reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); | 730 | reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); |
746 | wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); | 731 | wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); |
747 | 732 | ||
748 | wm8971_add_controls(codec); | 733 | snd_soc_add_controls(codec, wm8971_snd_controls, |
734 | ARRAY_SIZE(wm8971_snd_controls)); | ||
749 | wm8971_add_widgets(codec); | 735 | wm8971_add_widgets(codec); |
750 | ret = snd_soc_init_card(socdev); | 736 | ret = snd_soc_init_card(socdev); |
751 | if (ret < 0) { | 737 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 5b5afc144478..f93c0955ed9d 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -116,7 +116,7 @@ static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, | |||
116 | unsigned int reg) | 116 | unsigned int reg) |
117 | { | 117 | { |
118 | u16 *cache = codec->reg_cache; | 118 | u16 *cache = codec->reg_cache; |
119 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | 119 | BUG_ON(reg >= ARRAY_SIZE(wm8990_reg)); |
120 | return cache[reg]; | 120 | return cache[reg]; |
121 | } | 121 | } |
122 | 122 | ||
@@ -129,7 +129,7 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, | |||
129 | u16 *cache = codec->reg_cache; | 129 | u16 *cache = codec->reg_cache; |
130 | 130 | ||
131 | /* Reset register and reserved registers are uncached */ | 131 | /* Reset register and reserved registers are uncached */ |
132 | if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1) | 132 | if (reg == 0 || reg >= ARRAY_SIZE(wm8990_reg)) |
133 | return; | 133 | return; |
134 | 134 | ||
135 | cache[reg] = value; | 135 | cache[reg] = value; |
@@ -417,21 +417,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | |||
417 | 417 | ||
418 | }; | 418 | }; |
419 | 419 | ||
420 | /* add non dapm controls */ | ||
421 | static int wm8990_add_controls(struct snd_soc_codec *codec) | ||
422 | { | ||
423 | int err, i; | ||
424 | |||
425 | for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) { | ||
426 | err = snd_ctl_add(codec->card, | ||
427 | snd_soc_cnew(&wm8990_snd_controls[i], codec, | ||
428 | NULL)); | ||
429 | if (err < 0) | ||
430 | return err; | ||
431 | } | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | /* | 420 | /* |
436 | * _DAPM_ Controls | 421 | * _DAPM_ Controls |
437 | */ | 422 | */ |
@@ -1460,7 +1445,8 @@ static int wm8990_init(struct snd_soc_device *socdev) | |||
1460 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1445 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1461 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1446 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1462 | 1447 | ||
1463 | wm8990_add_controls(codec); | 1448 | snd_soc_add_controls(codec, wm8990_snd_controls, |
1449 | ARRAY_SIZE(wm8990_snd_controls)); | ||
1464 | wm8990_add_widgets(codec); | 1450 | wm8990_add_widgets(codec); |
1465 | ret = snd_soc_init_card(socdev); | 1451 | ret = snd_soc_init_card(socdev); |
1466 | if (ret < 0) { | 1452 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c new file mode 100644 index 000000000000..5e1937ac0b5e --- /dev/null +++ b/sound/soc/codecs/wm9705.c | |||
@@ -0,0 +1,410 @@ | |||
1 | /* | ||
2 | * wm9705.c -- ALSA Soc WM9705 codec support | ||
3 | * | ||
4 | * Copyright 2008 Ian Molton <spyro@f2s.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; Version 2 of the License only. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | #include <sound/ac97_codec.h> | ||
19 | #include <sound/initval.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include <sound/soc-dapm.h> | ||
22 | |||
23 | /* | ||
24 | * WM9705 register cache | ||
25 | */ | ||
26 | static const u16 wm9705_reg[] = { | ||
27 | 0x6150, 0x8000, 0x8000, 0x8000, /* 0x0 */ | ||
28 | 0x0000, 0x8000, 0x8008, 0x8008, /* 0x8 */ | ||
29 | 0x8808, 0x8808, 0x8808, 0x8808, /* 0x10 */ | ||
30 | 0x8808, 0x0000, 0x8000, 0x0000, /* 0x18 */ | ||
31 | 0x0000, 0x0000, 0x0000, 0x000f, /* 0x20 */ | ||
32 | 0x0605, 0x0000, 0xbb80, 0x0000, /* 0x28 */ | ||
33 | 0x0000, 0xbb80, 0x0000, 0x0000, /* 0x30 */ | ||
34 | 0x0000, 0x2000, 0x0000, 0x0000, /* 0x38 */ | ||
35 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x40 */ | ||
36 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x48 */ | ||
37 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x50 */ | ||
38 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x58 */ | ||
39 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x60 */ | ||
40 | 0x0000, 0x0000, 0x0000, 0x0000, /* 0x68 */ | ||
41 | 0x0000, 0x0808, 0x0000, 0x0006, /* 0x70 */ | ||
42 | 0x0000, 0x0000, 0x574d, 0x4c05, /* 0x78 */ | ||
43 | }; | ||
44 | |||
45 | static const struct snd_kcontrol_new wm9705_snd_ac97_controls[] = { | ||
46 | SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), | ||
47 | SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1), | ||
48 | SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), | ||
49 | SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1), | ||
50 | SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1), | ||
51 | SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1), | ||
52 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1), | ||
53 | SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), | ||
54 | SOC_SINGLE("PCBeep Playback Volume", AC97_PC_BEEP, 1, 15, 1), | ||
55 | SOC_SINGLE("Phone Playback Volume", AC97_PHONE, 0, 31, 1), | ||
56 | SOC_DOUBLE("Line Playback Volume", AC97_LINE, 8, 0, 31, 1), | ||
57 | SOC_DOUBLE("CD Playback Volume", AC97_CD, 8, 0, 31, 1), | ||
58 | SOC_SINGLE("Mic Playback Volume", AC97_MIC, 0, 31, 1), | ||
59 | SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 6, 1, 0), | ||
60 | SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0), | ||
61 | SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1), | ||
62 | }; | ||
63 | |||
64 | static const char *wm9705_mic[] = {"Mic 1", "Mic 2"}; | ||
65 | static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC", | ||
66 | "Line", "Stereo Mix", "Mono Mix", "Phone"}; | ||
67 | |||
68 | static const struct soc_enum wm9705_enum_mic = | ||
69 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic); | ||
70 | static const struct soc_enum wm9705_enum_rec_l = | ||
71 | SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel); | ||
72 | static const struct soc_enum wm9705_enum_rec_r = | ||
73 | SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel); | ||
74 | |||
75 | /* Headphone Mixer */ | ||
76 | static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = { | ||
77 | SOC_DAPM_SINGLE("PCBeep Playback Switch", AC97_PC_BEEP, 15, 1, 1), | ||
78 | SOC_DAPM_SINGLE("CD Playback Switch", AC97_CD, 15, 1, 1), | ||
79 | SOC_DAPM_SINGLE("Mic Playback Switch", AC97_MIC, 15, 1, 1), | ||
80 | SOC_DAPM_SINGLE("Phone Playback Switch", AC97_PHONE, 15, 1, 1), | ||
81 | SOC_DAPM_SINGLE("Line Playback Switch", AC97_LINE, 15, 1, 1), | ||
82 | }; | ||
83 | |||
84 | /* Mic source */ | ||
85 | static const struct snd_kcontrol_new wm9705_mic_src_controls = | ||
86 | SOC_DAPM_ENUM("Route", wm9705_enum_mic); | ||
87 | |||
88 | /* Capture source */ | ||
89 | static const struct snd_kcontrol_new wm9705_capture_selectl_controls = | ||
90 | SOC_DAPM_ENUM("Route", wm9705_enum_rec_l); | ||
91 | static const struct snd_kcontrol_new wm9705_capture_selectr_controls = | ||
92 | SOC_DAPM_ENUM("Route", wm9705_enum_rec_r); | ||
93 | |||
94 | /* DAPM widgets */ | ||
95 | static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = { | ||
96 | SND_SOC_DAPM_MUX("Mic Source", SND_SOC_NOPM, 0, 0, | ||
97 | &wm9705_mic_src_controls), | ||
98 | SND_SOC_DAPM_MUX("Left Capture Source", SND_SOC_NOPM, 0, 0, | ||
99 | &wm9705_capture_selectl_controls), | ||
100 | SND_SOC_DAPM_MUX("Right Capture Source", SND_SOC_NOPM, 0, 0, | ||
101 | &wm9705_capture_selectr_controls), | ||
102 | SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", | ||
103 | SND_SOC_NOPM, 0, 0), | ||
104 | SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", | ||
105 | SND_SOC_NOPM, 0, 0), | ||
106 | SND_SOC_DAPM_MIXER_NAMED_CTL("HP Mixer", SND_SOC_NOPM, 0, 0, | ||
107 | &wm9705_hp_mixer_controls[0], | ||
108 | ARRAY_SIZE(wm9705_hp_mixer_controls)), | ||
109 | SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
110 | SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
111 | SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
112 | SND_SOC_DAPM_PGA("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
113 | SND_SOC_DAPM_PGA("Speaker PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
114 | SND_SOC_DAPM_PGA("Line PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
115 | SND_SOC_DAPM_PGA("Line out PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
116 | SND_SOC_DAPM_PGA("Mono PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
117 | SND_SOC_DAPM_PGA("Phone PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
118 | SND_SOC_DAPM_PGA("Mic PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
119 | SND_SOC_DAPM_PGA("PCBEEP PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
120 | SND_SOC_DAPM_PGA("CD PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
121 | SND_SOC_DAPM_PGA("ADC PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
122 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
123 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
124 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
125 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
126 | SND_SOC_DAPM_OUTPUT("MONOOUT"), | ||
127 | SND_SOC_DAPM_INPUT("PHONE"), | ||
128 | SND_SOC_DAPM_INPUT("LINEINL"), | ||
129 | SND_SOC_DAPM_INPUT("LINEINR"), | ||
130 | SND_SOC_DAPM_INPUT("CDINL"), | ||
131 | SND_SOC_DAPM_INPUT("CDINR"), | ||
132 | SND_SOC_DAPM_INPUT("PCBEEP"), | ||
133 | SND_SOC_DAPM_INPUT("MIC1"), | ||
134 | SND_SOC_DAPM_INPUT("MIC2"), | ||
135 | }; | ||
136 | |||
137 | /* Audio map | ||
138 | * WM9705 has no switches to disable the route from the inputs to the HP mixer | ||
139 | * so in order to prevent active inputs from forcing the audio outputs to be | ||
140 | * constantly enabled, we use the mutes on those inputs to simulate such | ||
141 | * controls. | ||
142 | */ | ||
143 | static const struct snd_soc_dapm_route audio_map[] = { | ||
144 | /* HP mixer */ | ||
145 | {"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"}, | ||
146 | {"HP Mixer", "CD Playback Switch", "CD PGA"}, | ||
147 | {"HP Mixer", "Mic Playback Switch", "Mic PGA"}, | ||
148 | {"HP Mixer", "Phone Playback Switch", "Phone PGA"}, | ||
149 | {"HP Mixer", "Line Playback Switch", "Line PGA"}, | ||
150 | {"HP Mixer", NULL, "Left DAC"}, | ||
151 | {"HP Mixer", NULL, "Right DAC"}, | ||
152 | |||
153 | /* mono mixer */ | ||
154 | {"Mono Mixer", NULL, "HP Mixer"}, | ||
155 | |||
156 | /* outputs */ | ||
157 | {"Headphone PGA", NULL, "HP Mixer"}, | ||
158 | {"HPOUTL", NULL, "Headphone PGA"}, | ||
159 | {"HPOUTR", NULL, "Headphone PGA"}, | ||
160 | {"Line out PGA", NULL, "HP Mixer"}, | ||
161 | {"LOUT", NULL, "Line out PGA"}, | ||
162 | {"ROUT", NULL, "Line out PGA"}, | ||
163 | {"Mono PGA", NULL, "Mono Mixer"}, | ||
164 | {"MONOOUT", NULL, "Mono PGA"}, | ||
165 | |||
166 | /* inputs */ | ||
167 | {"CD PGA", NULL, "CDINL"}, | ||
168 | {"CD PGA", NULL, "CDINR"}, | ||
169 | {"Line PGA", NULL, "LINEINL"}, | ||
170 | {"Line PGA", NULL, "LINEINR"}, | ||
171 | {"Phone PGA", NULL, "PHONE"}, | ||
172 | {"Mic Source", "Mic 1", "MIC1"}, | ||
173 | {"Mic Source", "Mic 2", "MIC2"}, | ||
174 | {"Mic PGA", NULL, "Mic Source"}, | ||
175 | {"PCBEEP PGA", NULL, "PCBEEP"}, | ||
176 | |||
177 | /* Left capture selector */ | ||
178 | {"Left Capture Source", "Mic", "Mic Source"}, | ||
179 | {"Left Capture Source", "CD", "CDINL"}, | ||
180 | {"Left Capture Source", "Line", "LINEINL"}, | ||
181 | {"Left Capture Source", "Stereo Mix", "HP Mixer"}, | ||
182 | {"Left Capture Source", "Mono Mix", "HP Mixer"}, | ||
183 | {"Left Capture Source", "Phone", "PHONE"}, | ||
184 | |||
185 | /* Right capture source */ | ||
186 | {"Right Capture Source", "Mic", "Mic Source"}, | ||
187 | {"Right Capture Source", "CD", "CDINR"}, | ||
188 | {"Right Capture Source", "Line", "LINEINR"}, | ||
189 | {"Right Capture Source", "Stereo Mix", "HP Mixer"}, | ||
190 | {"Right Capture Source", "Mono Mix", "HP Mixer"}, | ||
191 | {"Right Capture Source", "Phone", "PHONE"}, | ||
192 | |||
193 | {"ADC PGA", NULL, "Left Capture Source"}, | ||
194 | {"ADC PGA", NULL, "Right Capture Source"}, | ||
195 | |||
196 | /* ADC's */ | ||
197 | {"Left ADC", NULL, "ADC PGA"}, | ||
198 | {"Right ADC", NULL, "ADC PGA"}, | ||
199 | }; | ||
200 | |||
201 | static int wm9705_add_widgets(struct snd_soc_codec *codec) | ||
202 | { | ||
203 | snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets, | ||
204 | ARRAY_SIZE(wm9705_dapm_widgets)); | ||
205 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
206 | snd_soc_dapm_new_widgets(codec); | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* We use a register cache to enhance read performance. */ | ||
212 | static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) | ||
213 | { | ||
214 | u16 *cache = codec->reg_cache; | ||
215 | |||
216 | switch (reg) { | ||
217 | case AC97_RESET: | ||
218 | case AC97_VENDOR_ID1: | ||
219 | case AC97_VENDOR_ID2: | ||
220 | return soc_ac97_ops.read(codec->ac97, reg); | ||
221 | default: | ||
222 | reg = reg >> 1; | ||
223 | |||
224 | if (reg >= (ARRAY_SIZE(wm9705_reg))) | ||
225 | return -EIO; | ||
226 | |||
227 | return cache[reg]; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
232 | unsigned int val) | ||
233 | { | ||
234 | u16 *cache = codec->reg_cache; | ||
235 | |||
236 | soc_ac97_ops.write(codec->ac97, reg, val); | ||
237 | reg = reg >> 1; | ||
238 | if (reg < (ARRAY_SIZE(wm9705_reg))) | ||
239 | cache[reg] = val; | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int ac97_prepare(struct snd_pcm_substream *substream, | ||
245 | struct snd_soc_dai *dai) | ||
246 | { | ||
247 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
248 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
249 | struct snd_soc_device *socdev = rtd->socdev; | ||
250 | struct snd_soc_codec *codec = socdev->codec; | ||
251 | int reg; | ||
252 | u16 vra; | ||
253 | |||
254 | vra = ac97_read(codec, AC97_EXTENDED_STATUS); | ||
255 | ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); | ||
256 | |||
257 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
258 | reg = AC97_PCM_FRONT_DAC_RATE; | ||
259 | else | ||
260 | reg = AC97_PCM_LR_ADC_RATE; | ||
261 | |||
262 | return ac97_write(codec, reg, runtime->rate); | ||
263 | } | ||
264 | |||
265 | #define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ | ||
266 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | ||
267 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
268 | SNDRV_PCM_RATE_48000) | ||
269 | |||
270 | struct snd_soc_dai wm9705_dai[] = { | ||
271 | { | ||
272 | .name = "AC97 HiFi", | ||
273 | .ac97_control = 1, | ||
274 | .playback = { | ||
275 | .stream_name = "HiFi Playback", | ||
276 | .channels_min = 1, | ||
277 | .channels_max = 2, | ||
278 | .rates = WM9705_AC97_RATES, | ||
279 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
280 | }, | ||
281 | .capture = { | ||
282 | .stream_name = "HiFi Capture", | ||
283 | .channels_min = 1, | ||
284 | .channels_max = 2, | ||
285 | .rates = WM9705_AC97_RATES, | ||
286 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
287 | }, | ||
288 | .ops = { | ||
289 | .prepare = ac97_prepare, | ||
290 | }, | ||
291 | }, | ||
292 | { | ||
293 | .name = "AC97 Aux", | ||
294 | .playback = { | ||
295 | .stream_name = "Aux Playback", | ||
296 | .channels_min = 1, | ||
297 | .channels_max = 1, | ||
298 | .rates = WM9705_AC97_RATES, | ||
299 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
300 | }, | ||
301 | } | ||
302 | }; | ||
303 | EXPORT_SYMBOL_GPL(wm9705_dai); | ||
304 | |||
305 | static int wm9705_reset(struct snd_soc_codec *codec) | ||
306 | { | ||
307 | if (soc_ac97_ops.reset) { | ||
308 | soc_ac97_ops.reset(codec->ac97); | ||
309 | if (ac97_read(codec, 0) == wm9705_reg[0]) | ||
310 | return 0; /* Success */ | ||
311 | } | ||
312 | |||
313 | return -EIO; | ||
314 | } | ||
315 | |||
316 | static int wm9705_soc_probe(struct platform_device *pdev) | ||
317 | { | ||
318 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
319 | struct snd_soc_codec *codec; | ||
320 | int ret = 0; | ||
321 | |||
322 | printk(KERN_INFO "WM9705 SoC Audio Codec\n"); | ||
323 | |||
324 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
325 | if (socdev->codec == NULL) | ||
326 | return -ENOMEM; | ||
327 | codec = socdev->codec; | ||
328 | mutex_init(&codec->mutex); | ||
329 | |||
330 | codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL); | ||
331 | if (codec->reg_cache == NULL) { | ||
332 | ret = -ENOMEM; | ||
333 | goto cache_err; | ||
334 | } | ||
335 | codec->reg_cache_size = sizeof(wm9705_reg); | ||
336 | codec->reg_cache_step = 2; | ||
337 | |||
338 | codec->name = "WM9705"; | ||
339 | codec->owner = THIS_MODULE; | ||
340 | codec->dai = wm9705_dai; | ||
341 | codec->num_dai = ARRAY_SIZE(wm9705_dai); | ||
342 | codec->write = ac97_write; | ||
343 | codec->read = ac97_read; | ||
344 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
345 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
346 | |||
347 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | ||
348 | if (ret < 0) { | ||
349 | printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); | ||
350 | goto codec_err; | ||
351 | } | ||
352 | |||
353 | /* register pcms */ | ||
354 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
355 | if (ret < 0) | ||
356 | goto pcm_err; | ||
357 | |||
358 | ret = wm9705_reset(codec); | ||
359 | if (ret) | ||
360 | goto reset_err; | ||
361 | |||
362 | snd_soc_add_controls(codec, wm9705_snd_ac97_controls, | ||
363 | ARRAY_SIZE(wm9705_snd_ac97_controls)); | ||
364 | wm9705_add_widgets(codec); | ||
365 | |||
366 | ret = snd_soc_init_card(socdev); | ||
367 | if (ret < 0) { | ||
368 | printk(KERN_ERR "wm9705: failed to register card\n"); | ||
369 | goto pcm_err; | ||
370 | } | ||
371 | |||
372 | return 0; | ||
373 | |||
374 | reset_err: | ||
375 | snd_soc_free_pcms(socdev); | ||
376 | pcm_err: | ||
377 | snd_soc_free_ac97_codec(codec); | ||
378 | codec_err: | ||
379 | kfree(codec->reg_cache); | ||
380 | cache_err: | ||
381 | kfree(socdev->codec); | ||
382 | socdev->codec = NULL; | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | static int wm9705_soc_remove(struct platform_device *pdev) | ||
387 | { | ||
388 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
389 | struct snd_soc_codec *codec = socdev->codec; | ||
390 | |||
391 | if (codec == NULL) | ||
392 | return 0; | ||
393 | |||
394 | snd_soc_dapm_free(socdev); | ||
395 | snd_soc_free_pcms(socdev); | ||
396 | snd_soc_free_ac97_codec(codec); | ||
397 | kfree(codec->reg_cache); | ||
398 | kfree(codec); | ||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | struct snd_soc_codec_device soc_codec_dev_wm9705 = { | ||
403 | .probe = wm9705_soc_probe, | ||
404 | .remove = wm9705_soc_remove, | ||
405 | }; | ||
406 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705); | ||
407 | |||
408 | MODULE_DESCRIPTION("ASoC WM9705 driver"); | ||
409 | MODULE_AUTHOR("Ian Molton"); | ||
410 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/wm9705.h b/sound/soc/codecs/wm9705.h new file mode 100644 index 000000000000..d380f110f9e2 --- /dev/null +++ b/sound/soc/codecs/wm9705.h | |||
@@ -0,0 +1,14 @@ | |||
1 | /* | ||
2 | * wm9705.h -- WM9705 Soc Audio driver | ||
3 | */ | ||
4 | |||
5 | #ifndef _WM9705_H | ||
6 | #define _WM9705_H | ||
7 | |||
8 | #define WM9705_DAI_AC97_HIFI 0 | ||
9 | #define WM9705_DAI_AC97_AUX 1 | ||
10 | |||
11 | extern struct snd_soc_dai wm9705_dai[2]; | ||
12 | extern struct snd_soc_codec_device soc_codec_dev_wm9705; | ||
13 | |||
14 | #endif | ||
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index af83d629078a..4dc90d67530e 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -154,21 +154,6 @@ SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), | |||
154 | SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), | 154 | SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), |
155 | }; | 155 | }; |
156 | 156 | ||
157 | /* add non dapm controls */ | ||
158 | static int wm9712_add_controls(struct snd_soc_codec *codec) | ||
159 | { | ||
160 | int err, i; | ||
161 | |||
162 | for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) { | ||
163 | err = snd_ctl_add(codec->card, | ||
164 | snd_soc_cnew(&wm9712_snd_ac97_controls[i], | ||
165 | codec, NULL)); | ||
166 | if (err < 0) | ||
167 | return err; | ||
168 | } | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | /* We have to create a fake left and right HP mixers because | 157 | /* We have to create a fake left and right HP mixers because |
173 | * the codec only has a single control that is shared by both channels. | 158 | * the codec only has a single control that is shared by both channels. |
174 | * This makes it impossible to determine the audio path. | 159 | * This makes it impossible to determine the audio path. |
@@ -467,7 +452,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
467 | else { | 452 | else { |
468 | reg = reg >> 1; | 453 | reg = reg >> 1; |
469 | 454 | ||
470 | if (reg > (ARRAY_SIZE(wm9712_reg))) | 455 | if (reg >= (ARRAY_SIZE(wm9712_reg))) |
471 | return -EIO; | 456 | return -EIO; |
472 | 457 | ||
473 | return cache[reg]; | 458 | return cache[reg]; |
@@ -481,7 +466,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
481 | 466 | ||
482 | soc_ac97_ops.write(codec->ac97, reg, val); | 467 | soc_ac97_ops.write(codec->ac97, reg, val); |
483 | reg = reg >> 1; | 468 | reg = reg >> 1; |
484 | if (reg <= (ARRAY_SIZE(wm9712_reg))) | 469 | if (reg < (ARRAY_SIZE(wm9712_reg))) |
485 | cache[reg] = val; | 470 | cache[reg] = val; |
486 | 471 | ||
487 | return 0; | 472 | return 0; |
@@ -698,7 +683,8 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
698 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | 683 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); |
699 | 684 | ||
700 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 685 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
701 | wm9712_add_controls(codec); | 686 | snd_soc_add_controls(codec, wm9712_snd_ac97_controls, |
687 | ARRAY_SIZE(wm9712_snd_ac97_controls)); | ||
702 | wm9712_add_widgets(codec); | 688 | wm9712_add_widgets(codec); |
703 | ret = snd_soc_init_card(socdev); | 689 | ret = snd_soc_init_card(socdev); |
704 | if (ret < 0) { | 690 | if (ret < 0) { |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index f3ca8aaf0139..0e60e16973d4 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -32,7 +32,6 @@ | |||
32 | 32 | ||
33 | struct wm9713_priv { | 33 | struct wm9713_priv { |
34 | u32 pll_in; /* PLL input frequency */ | 34 | u32 pll_in; /* PLL input frequency */ |
35 | u32 pll_out; /* PLL output frequency */ | ||
36 | }; | 35 | }; |
37 | 36 | ||
38 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 37 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
@@ -190,21 +189,6 @@ SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0), | |||
190 | SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), | 189 | SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), |
191 | }; | 190 | }; |
192 | 191 | ||
193 | /* add non dapm controls */ | ||
194 | static int wm9713_add_controls(struct snd_soc_codec *codec) | ||
195 | { | ||
196 | int err, i; | ||
197 | |||
198 | for (i = 0; i < ARRAY_SIZE(wm9713_snd_ac97_controls); i++) { | ||
199 | err = snd_ctl_add(codec->card, | ||
200 | snd_soc_cnew(&wm9713_snd_ac97_controls[i], | ||
201 | codec, NULL)); | ||
202 | if (err < 0) | ||
203 | return err; | ||
204 | } | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* We have to create a fake left and right HP mixers because | 192 | /* We have to create a fake left and right HP mixers because |
209 | * the codec only has a single control that is shared by both channels. | 193 | * the codec only has a single control that is shared by both channels. |
210 | * This makes it impossible to determine the audio path using the current | 194 | * This makes it impossible to determine the audio path using the current |
@@ -636,7 +620,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
636 | else { | 620 | else { |
637 | reg = reg >> 1; | 621 | reg = reg >> 1; |
638 | 622 | ||
639 | if (reg > (ARRAY_SIZE(wm9713_reg))) | 623 | if (reg >= (ARRAY_SIZE(wm9713_reg))) |
640 | return -EIO; | 624 | return -EIO; |
641 | 625 | ||
642 | return cache[reg]; | 626 | return cache[reg]; |
@@ -650,7 +634,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
650 | if (reg < 0x7c) | 634 | if (reg < 0x7c) |
651 | soc_ac97_ops.write(codec->ac97, reg, val); | 635 | soc_ac97_ops.write(codec->ac97, reg, val); |
652 | reg = reg >> 1; | 636 | reg = reg >> 1; |
653 | if (reg <= (ARRAY_SIZE(wm9713_reg))) | 637 | if (reg < (ARRAY_SIZE(wm9713_reg))) |
654 | cache[reg] = val; | 638 | cache[reg] = val; |
655 | 639 | ||
656 | return 0; | 640 | return 0; |
@@ -738,13 +722,13 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
738 | struct _pll_div pll_div; | 722 | struct _pll_div pll_div; |
739 | 723 | ||
740 | /* turn PLL off ? */ | 724 | /* turn PLL off ? */ |
741 | if (freq_in == 0 || freq_out == 0) { | 725 | if (freq_in == 0) { |
742 | /* disable PLL power and select ext source */ | 726 | /* disable PLL power and select ext source */ |
743 | reg = ac97_read(codec, AC97_HANDSET_RATE); | 727 | reg = ac97_read(codec, AC97_HANDSET_RATE); |
744 | ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080); | 728 | ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080); |
745 | reg = ac97_read(codec, AC97_EXTENDED_MID); | 729 | reg = ac97_read(codec, AC97_EXTENDED_MID); |
746 | ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200); | 730 | ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200); |
747 | wm9713->pll_out = 0; | 731 | wm9713->pll_in = 0; |
748 | return 0; | 732 | return 0; |
749 | } | 733 | } |
750 | 734 | ||
@@ -788,7 +772,6 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
788 | ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff); | 772 | ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff); |
789 | reg = ac97_read(codec, AC97_HANDSET_RATE); | 773 | reg = ac97_read(codec, AC97_HANDSET_RATE); |
790 | ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f); | 774 | ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f); |
791 | wm9713->pll_out = freq_out; | ||
792 | wm9713->pll_in = freq_in; | 775 | wm9713->pll_in = freq_in; |
793 | 776 | ||
794 | /* wait 10ms AC97 link frames for the link to stabilise */ | 777 | /* wait 10ms AC97 link frames for the link to stabilise */ |
@@ -1164,8 +1147,8 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
1164 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1147 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1165 | 1148 | ||
1166 | /* do we need to re-start the PLL ? */ | 1149 | /* do we need to re-start the PLL ? */ |
1167 | if (wm9713->pll_out) | 1150 | if (wm9713->pll_in) |
1168 | wm9713_set_pll(codec, 0, wm9713->pll_in, wm9713->pll_out); | 1151 | wm9713_set_pll(codec, 0, wm9713->pll_in, 0); |
1169 | 1152 | ||
1170 | /* only synchronise the codec if warm reset failed */ | 1153 | /* only synchronise the codec if warm reset failed */ |
1171 | if (ret == 0) { | 1154 | if (ret == 0) { |
@@ -1245,7 +1228,8 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1245 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1228 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
1246 | ac97_write(codec, AC97_CD, reg); | 1229 | ac97_write(codec, AC97_CD, reg); |
1247 | 1230 | ||
1248 | wm9713_add_controls(codec); | 1231 | snd_soc_add_controls(codec, wm9713_snd_ac97_controls, |
1232 | ARRAY_SIZE(wm9713_snd_ac97_controls)); | ||
1249 | wm9713_add_widgets(codec); | 1233 | wm9713_add_widgets(codec); |
1250 | ret = snd_soc_init_card(socdev); | 1234 | ret = snd_soc_init_card(socdev); |
1251 | if (ret < 0) | 1235 | if (ret < 0) |
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 366049d8578c..7af3b5b3a53d 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
@@ -286,7 +286,7 @@ static int davinci_pcm_mmap(struct snd_pcm_substream *substream, | |||
286 | runtime->dma_bytes); | 286 | runtime->dma_bytes); |
287 | } | 287 | } |
288 | 288 | ||
289 | struct snd_pcm_ops davinci_pcm_ops = { | 289 | static struct snd_pcm_ops davinci_pcm_ops = { |
290 | .open = davinci_pcm_open, | 290 | .open = davinci_pcm_open, |
291 | .close = davinci_pcm_close, | 291 | .close = davinci_pcm_close, |
292 | .ioctl = snd_pcm_lib_ioctl, | 292 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 4935d1bcbd8d..50baef1fe5b4 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c | |||
@@ -25,7 +25,9 @@ | |||
25 | 25 | ||
26 | #include <asm/dma.h> | 26 | #include <asm/dma.h> |
27 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
28 | #ifdef CONFIG_SFFSDR_FPGA | ||
28 | #include <asm/plat-sffsdr/sffsdr-fpga.h> | 29 | #include <asm/plat-sffsdr/sffsdr-fpga.h> |
30 | #endif | ||
29 | 31 | ||
30 | #include <mach/mcbsp.h> | 32 | #include <mach/mcbsp.h> |
31 | #include <mach/edma.h> | 33 | #include <mach/edma.h> |
@@ -43,6 +45,17 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream, | |||
43 | int fs; | 45 | int fs; |
44 | int ret = 0; | 46 | int ret = 0; |
45 | 47 | ||
48 | /* Fsref can be 32000, 44100 or 48000. */ | ||
49 | fs = params_rate(params); | ||
50 | |||
51 | #ifndef CONFIG_SFFSDR_FPGA | ||
52 | /* Without the FPGA module, the Fs is fixed at 44100 Hz */ | ||
53 | if (fs != 44100) { | ||
54 | pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n"); | ||
55 | return -EINVAL; | ||
56 | } | ||
57 | #endif | ||
58 | |||
46 | /* Set cpu DAI configuration: | 59 | /* Set cpu DAI configuration: |
47 | * CLKX and CLKR are the inputs for the Sample Rate Generator. | 60 | * CLKX and CLKR are the inputs for the Sample Rate Generator. |
48 | * FSX and FSR are outputs, driven by the sample Rate Generator. */ | 61 | * FSX and FSR are outputs, driven by the sample Rate Generator. */ |
@@ -53,12 +66,13 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream, | |||
53 | if (ret < 0) | 66 | if (ret < 0) |
54 | return ret; | 67 | return ret; |
55 | 68 | ||
56 | /* Fsref can be 32000, 44100 or 48000. */ | ||
57 | fs = params_rate(params); | ||
58 | |||
59 | pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); | 69 | pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); |
60 | 70 | ||
71 | #ifndef CONFIG_SFFSDR_FPGA | ||
72 | return 0; | ||
73 | #else | ||
61 | return sffsdr_fpga_set_codec_fs(fs); | 74 | return sffsdr_fpga_set_codec_fs(fs); |
75 | #endif | ||
62 | } | 76 | } |
63 | 77 | ||
64 | static struct snd_soc_ops sffsdr_ops = { | 78 | static struct snd_soc_ops sffsdr_ops = { |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 95c12b26fe37..c7c78c39cfed 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -1,17 +1,17 @@ | |||
1 | config SND_SOC_OF_SIMPLE | 1 | config SND_SOC_OF_SIMPLE |
2 | tristate | 2 | tristate |
3 | 3 | ||
4 | # ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers | ||
5 | # for the SSI and the Elo DMA controller. You will still need to select | ||
6 | # a platform driver and a codec driver. | ||
4 | config SND_SOC_MPC8610 | 7 | config SND_SOC_MPC8610 |
5 | bool "ALSA SoC support for the MPC8610 SOC" | 8 | tristate |
6 | depends on MPC8610_HPCD | 9 | depends on MPC8610 |
7 | default y if MPC8610 | ||
8 | help | ||
9 | Say Y if you want to add support for codecs attached to the SSI | ||
10 | device on an MPC8610. | ||
11 | 10 | ||
12 | config SND_SOC_MPC8610_HPCD | 11 | config SND_SOC_MPC8610_HPCD |
13 | bool "ALSA SoC support for the Freescale MPC8610 HPCD board" | 12 | tristate "ALSA SoC support for the Freescale MPC8610 HPCD board" |
14 | depends on SND_SOC_MPC8610 | 13 | depends on MPC8610_HPCD |
14 | select SND_SOC_MPC8610 | ||
15 | select SND_SOC_CS4270 | 15 | select SND_SOC_CS4270 |
16 | select SND_SOC_CS4270_VD33_ERRATA | 16 | select SND_SOC_CS4270_VD33_ERRATA |
17 | default y if MPC8610_HPCD | 17 | default y if MPC8610_HPCD |
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 035da4afec34..f85134c86387 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -2,10 +2,13 @@ | |||
2 | obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o | 2 | obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o |
3 | 3 | ||
4 | # MPC8610 HPCD Machine Support | 4 | # MPC8610 HPCD Machine Support |
5 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o | 5 | snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o |
6 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o | ||
6 | 7 | ||
7 | # MPC8610 Platform Support | 8 | # MPC8610 Platform Support |
8 | obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o | 9 | snd-soc-fsl-ssi-objs := fsl_ssi.o |
10 | snd-soc-fsl-dma-objs := fsl_dma.o | ||
11 | obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o | ||
9 | 12 | ||
10 | obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o | 13 | obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o |
11 | 14 | ||
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index b0362dfd5b71..607a38c7ae48 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -264,7 +264,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream, | |||
264 | runtime->dma_bytes); | 264 | runtime->dma_bytes); |
265 | } | 265 | } |
266 | 266 | ||
267 | struct snd_pcm_ops omap_pcm_ops = { | 267 | static struct snd_pcm_ops omap_pcm_ops = { |
268 | .open = omap_pcm_open, | 268 | .open = omap_pcm_open, |
269 | .close = omap_pcm_close, | 269 | .close = omap_pcm_close, |
270 | .ioctl = snd_pcm_lib_ioctl, | 270 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index f82e10699471..958ac3fe15d1 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -61,6 +61,24 @@ config SND_PXA2XX_SOC_TOSA | |||
61 | Say Y if you want to add support for SoC audio on Sharp | 61 | Say Y if you want to add support for SoC audio on Sharp |
62 | Zaurus SL-C6000x models (Tosa). | 62 | Zaurus SL-C6000x models (Tosa). |
63 | 63 | ||
64 | config SND_PXA2XX_SOC_E740 | ||
65 | tristate "SoC AC97 Audio support for e740" | ||
66 | depends on SND_PXA2XX_SOC && MACH_E740 | ||
67 | select SND_SOC_WM9705 | ||
68 | select SND_PXA2XX_SOC_AC97 | ||
69 | help | ||
70 | Say Y if you want to add support for SoC audio on the | ||
71 | toshiba e740 PDA | ||
72 | |||
73 | config SND_PXA2XX_SOC_E750 | ||
74 | tristate "SoC AC97 Audio support for e750" | ||
75 | depends on SND_PXA2XX_SOC && MACH_E750 | ||
76 | select SND_SOC_WM9705 | ||
77 | select SND_PXA2XX_SOC_AC97 | ||
78 | help | ||
79 | Say Y if you want to add support for SoC audio on the | ||
80 | toshiba e750 PDA | ||
81 | |||
64 | config SND_PXA2XX_SOC_E800 | 82 | config SND_PXA2XX_SOC_E800 |
65 | tristate "SoC AC97 Audio support for e800" | 83 | tristate "SoC AC97 Audio support for e800" |
66 | depends on SND_PXA2XX_SOC && MACH_E800 | 84 | depends on SND_PXA2XX_SOC && MACH_E800 |
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 08a9f2797729..97a51a8c936c 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile | |||
@@ -13,6 +13,8 @@ obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o | |||
13 | snd-soc-corgi-objs := corgi.o | 13 | snd-soc-corgi-objs := corgi.o |
14 | snd-soc-poodle-objs := poodle.o | 14 | snd-soc-poodle-objs := poodle.o |
15 | snd-soc-tosa-objs := tosa.o | 15 | snd-soc-tosa-objs := tosa.o |
16 | snd-soc-e740-objs := e740_wm9705.o | ||
17 | snd-soc-e750-objs := e750_wm9705.o | ||
16 | snd-soc-e800-objs := e800_wm9712.o | 18 | snd-soc-e800-objs := e800_wm9712.o |
17 | snd-soc-spitz-objs := spitz.o | 19 | snd-soc-spitz-objs := spitz.o |
18 | snd-soc-em-x270-objs := em-x270.o | 20 | snd-soc-em-x270-objs := em-x270.o |
@@ -22,6 +24,8 @@ snd-soc-zylonite-objs := zylonite.o | |||
22 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o | 24 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o |
23 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o | 25 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o |
24 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o | 26 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o |
27 | obj-$(CONFIG_SND_PXA2XX_SOC_E740) += snd-soc-e740.o | ||
28 | obj-$(CONFIG_SND_PXA2XX_SOC_E750) += snd-soc-e750.o | ||
25 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o | 29 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o |
26 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o | 30 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o |
27 | obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o | 31 | obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o |
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c new file mode 100644 index 000000000000..ac3617651734 --- /dev/null +++ b/sound/soc/pxa/e740_wm9705.c | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | * e740-wm9705.c -- SoC audio for e740 | ||
3 | * | ||
4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; version 2 ONLY. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/gpio.h> | ||
15 | |||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | |||
21 | #include <mach/pxa-regs.h> | ||
22 | #include <mach/hardware.h> | ||
23 | #include <mach/audio.h> | ||
24 | #include <mach/eseries-gpio.h> | ||
25 | |||
26 | #include <asm/mach-types.h> | ||
27 | |||
28 | #include "../codecs/wm9705.h" | ||
29 | #include "pxa2xx-pcm.h" | ||
30 | #include "pxa2xx-ac97.h" | ||
31 | |||
32 | |||
33 | #define E740_AUDIO_OUT 1 | ||
34 | #define E740_AUDIO_IN 2 | ||
35 | |||
36 | static int e740_audio_power; | ||
37 | |||
38 | static void e740_sync_audio_power(int status) | ||
39 | { | ||
40 | gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status); | ||
41 | gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0); | ||
42 | gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0); | ||
43 | } | ||
44 | |||
45 | static int e740_mic_amp_event(struct snd_soc_dapm_widget *w, | ||
46 | struct snd_kcontrol *kcontrol, int event) | ||
47 | { | ||
48 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
49 | e740_audio_power |= E740_AUDIO_IN; | ||
50 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
51 | e740_audio_power &= ~E740_AUDIO_IN; | ||
52 | |||
53 | e740_sync_audio_power(e740_audio_power); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int e740_output_amp_event(struct snd_soc_dapm_widget *w, | ||
59 | struct snd_kcontrol *kcontrol, int event) | ||
60 | { | ||
61 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
62 | e740_audio_power |= E740_AUDIO_OUT; | ||
63 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
64 | e740_audio_power &= ~E740_AUDIO_OUT; | ||
65 | |||
66 | e740_sync_audio_power(e740_audio_power); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static const struct snd_soc_dapm_widget e740_dapm_widgets[] = { | ||
72 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
73 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
74 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | ||
75 | SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
76 | e740_output_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
77 | SND_SOC_DAPM_POST_PMD), | ||
78 | SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
79 | e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
80 | SND_SOC_DAPM_POST_PMD), | ||
81 | }; | ||
82 | |||
83 | static const struct snd_soc_dapm_route audio_map[] = { | ||
84 | {"Output Amp", NULL, "LOUT"}, | ||
85 | {"Output Amp", NULL, "ROUT"}, | ||
86 | {"Output Amp", NULL, "MONOOUT"}, | ||
87 | |||
88 | {"Speaker", NULL, "Output Amp"}, | ||
89 | {"Headphone Jack", NULL, "Output Amp"}, | ||
90 | |||
91 | {"MIC1", NULL, "Mic Amp"}, | ||
92 | {"Mic Amp", NULL, "Mic (Internal)"}, | ||
93 | }; | ||
94 | |||
95 | static int e740_ac97_init(struct snd_soc_codec *codec) | ||
96 | { | ||
97 | snd_soc_dapm_nc_pin(codec, "HPOUTL"); | ||
98 | snd_soc_dapm_nc_pin(codec, "HPOUTR"); | ||
99 | snd_soc_dapm_nc_pin(codec, "PHONE"); | ||
100 | snd_soc_dapm_nc_pin(codec, "LINEINL"); | ||
101 | snd_soc_dapm_nc_pin(codec, "LINEINR"); | ||
102 | snd_soc_dapm_nc_pin(codec, "CDINL"); | ||
103 | snd_soc_dapm_nc_pin(codec, "CDINR"); | ||
104 | snd_soc_dapm_nc_pin(codec, "PCBEEP"); | ||
105 | snd_soc_dapm_nc_pin(codec, "MIC2"); | ||
106 | |||
107 | snd_soc_dapm_new_controls(codec, e740_dapm_widgets, | ||
108 | ARRAY_SIZE(e740_dapm_widgets)); | ||
109 | |||
110 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
111 | |||
112 | snd_soc_dapm_sync(codec); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static struct snd_soc_dai_link e740_dai[] = { | ||
118 | { | ||
119 | .name = "AC97", | ||
120 | .stream_name = "AC97 HiFi", | ||
121 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
122 | .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI], | ||
123 | .init = e740_ac97_init, | ||
124 | }, | ||
125 | { | ||
126 | .name = "AC97 Aux", | ||
127 | .stream_name = "AC97 Aux", | ||
128 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
129 | .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX], | ||
130 | }, | ||
131 | }; | ||
132 | |||
133 | static struct snd_soc_card e740 = { | ||
134 | .name = "Toshiba e740", | ||
135 | .platform = &pxa2xx_soc_platform, | ||
136 | .dai_link = e740_dai, | ||
137 | .num_links = ARRAY_SIZE(e740_dai), | ||
138 | }; | ||
139 | |||
140 | static struct snd_soc_device e740_snd_devdata = { | ||
141 | .card = &e740, | ||
142 | .codec_dev = &soc_codec_dev_wm9705, | ||
143 | }; | ||
144 | |||
145 | static struct platform_device *e740_snd_device; | ||
146 | |||
147 | static int __init e740_init(void) | ||
148 | { | ||
149 | int ret; | ||
150 | |||
151 | if (!machine_is_e740()) | ||
152 | return -ENODEV; | ||
153 | |||
154 | ret = gpio_request(GPIO_E740_MIC_ON, "Mic amp"); | ||
155 | if (ret) | ||
156 | return ret; | ||
157 | |||
158 | ret = gpio_request(GPIO_E740_AMP_ON, "Output amp"); | ||
159 | if (ret) | ||
160 | goto free_mic_amp_gpio; | ||
161 | |||
162 | ret = gpio_request(GPIO_E740_WM9705_nAVDD2, "Audio power"); | ||
163 | if (ret) | ||
164 | goto free_op_amp_gpio; | ||
165 | |||
166 | /* Disable audio */ | ||
167 | ret = gpio_direction_output(GPIO_E740_MIC_ON, 0); | ||
168 | if (ret) | ||
169 | goto free_apwr_gpio; | ||
170 | ret = gpio_direction_output(GPIO_E740_AMP_ON, 0); | ||
171 | if (ret) | ||
172 | goto free_apwr_gpio; | ||
173 | ret = gpio_direction_output(GPIO_E740_WM9705_nAVDD2, 1); | ||
174 | if (ret) | ||
175 | goto free_apwr_gpio; | ||
176 | |||
177 | e740_snd_device = platform_device_alloc("soc-audio", -1); | ||
178 | if (!e740_snd_device) { | ||
179 | ret = -ENOMEM; | ||
180 | goto free_apwr_gpio; | ||
181 | } | ||
182 | |||
183 | platform_set_drvdata(e740_snd_device, &e740_snd_devdata); | ||
184 | e740_snd_devdata.dev = &e740_snd_device->dev; | ||
185 | ret = platform_device_add(e740_snd_device); | ||
186 | |||
187 | if (!ret) | ||
188 | return 0; | ||
189 | |||
190 | /* Fail gracefully */ | ||
191 | platform_device_put(e740_snd_device); | ||
192 | free_apwr_gpio: | ||
193 | gpio_free(GPIO_E740_WM9705_nAVDD2); | ||
194 | free_op_amp_gpio: | ||
195 | gpio_free(GPIO_E740_AMP_ON); | ||
196 | free_mic_amp_gpio: | ||
197 | gpio_free(GPIO_E740_MIC_ON); | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static void __exit e740_exit(void) | ||
203 | { | ||
204 | platform_device_unregister(e740_snd_device); | ||
205 | } | ||
206 | |||
207 | module_init(e740_init); | ||
208 | module_exit(e740_exit); | ||
209 | |||
210 | /* Module information */ | ||
211 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | ||
212 | MODULE_DESCRIPTION("ALSA SoC driver for e740"); | ||
213 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c new file mode 100644 index 000000000000..20fbdcfa9f78 --- /dev/null +++ b/sound/soc/pxa/e750_wm9705.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * e750-wm9705.c -- SoC audio for e750 | ||
3 | * | ||
4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; version 2 ONLY. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/gpio.h> | ||
15 | |||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | |||
21 | #include <mach/pxa-regs.h> | ||
22 | #include <mach/hardware.h> | ||
23 | #include <mach/audio.h> | ||
24 | #include <mach/eseries-gpio.h> | ||
25 | |||
26 | #include <asm/mach-types.h> | ||
27 | |||
28 | #include "../codecs/wm9705.h" | ||
29 | #include "pxa2xx-pcm.h" | ||
30 | #include "pxa2xx-ac97.h" | ||
31 | |||
32 | static int e750_spk_amp_event(struct snd_soc_dapm_widget *w, | ||
33 | struct snd_kcontrol *kcontrol, int event) | ||
34 | { | ||
35 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
36 | gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0); | ||
37 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
38 | gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1); | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static int e750_hp_amp_event(struct snd_soc_dapm_widget *w, | ||
44 | struct snd_kcontrol *kcontrol, int event) | ||
45 | { | ||
46 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
47 | gpio_set_value(GPIO_E750_HP_AMP_OFF, 0); | ||
48 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
49 | gpio_set_value(GPIO_E750_HP_AMP_OFF, 1); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static const struct snd_soc_dapm_widget e750_dapm_widgets[] = { | ||
55 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
56 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
57 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | ||
58 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
59 | e750_hp_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
60 | SND_SOC_DAPM_POST_PMD), | ||
61 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
62 | e750_spk_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
63 | SND_SOC_DAPM_POST_PMD), | ||
64 | }; | ||
65 | |||
66 | static const struct snd_soc_dapm_route audio_map[] = { | ||
67 | {"Headphone Amp", NULL, "HPOUTL"}, | ||
68 | {"Headphone Amp", NULL, "HPOUTR"}, | ||
69 | {"Headphone Jack", NULL, "Headphone Amp"}, | ||
70 | |||
71 | {"Speaker Amp", NULL, "MONOOUT"}, | ||
72 | {"Speaker", NULL, "Speaker Amp"}, | ||
73 | |||
74 | {"MIC1", NULL, "Mic (Internal)"}, | ||
75 | }; | ||
76 | |||
77 | static int e750_ac97_init(struct snd_soc_codec *codec) | ||
78 | { | ||
79 | snd_soc_dapm_nc_pin(codec, "LOUT"); | ||
80 | snd_soc_dapm_nc_pin(codec, "ROUT"); | ||
81 | snd_soc_dapm_nc_pin(codec, "PHONE"); | ||
82 | snd_soc_dapm_nc_pin(codec, "LINEINL"); | ||
83 | snd_soc_dapm_nc_pin(codec, "LINEINR"); | ||
84 | snd_soc_dapm_nc_pin(codec, "CDINL"); | ||
85 | snd_soc_dapm_nc_pin(codec, "CDINR"); | ||
86 | snd_soc_dapm_nc_pin(codec, "PCBEEP"); | ||
87 | snd_soc_dapm_nc_pin(codec, "MIC2"); | ||
88 | |||
89 | snd_soc_dapm_new_controls(codec, e750_dapm_widgets, | ||
90 | ARRAY_SIZE(e750_dapm_widgets)); | ||
91 | |||
92 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
93 | |||
94 | snd_soc_dapm_sync(codec); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static struct snd_soc_dai_link e750_dai[] = { | ||
100 | { | ||
101 | .name = "AC97", | ||
102 | .stream_name = "AC97 HiFi", | ||
103 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
104 | .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI], | ||
105 | .init = e750_ac97_init, | ||
106 | /* use ops to check startup state */ | ||
107 | }, | ||
108 | { | ||
109 | .name = "AC97 Aux", | ||
110 | .stream_name = "AC97 Aux", | ||
111 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
112 | .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX], | ||
113 | }, | ||
114 | }; | ||
115 | |||
116 | static struct snd_soc_card e750 = { | ||
117 | .name = "Toshiba e750", | ||
118 | .platform = &pxa2xx_soc_platform, | ||
119 | .dai_link = e750_dai, | ||
120 | .num_links = ARRAY_SIZE(e750_dai), | ||
121 | }; | ||
122 | |||
123 | static struct snd_soc_device e750_snd_devdata = { | ||
124 | .card = &e750, | ||
125 | .codec_dev = &soc_codec_dev_wm9705, | ||
126 | }; | ||
127 | |||
128 | static struct platform_device *e750_snd_device; | ||
129 | |||
130 | static int __init e750_init(void) | ||
131 | { | ||
132 | int ret; | ||
133 | |||
134 | if (!machine_is_e750()) | ||
135 | return -ENODEV; | ||
136 | |||
137 | ret = gpio_request(GPIO_E750_HP_AMP_OFF, "Headphone amp"); | ||
138 | if (ret) | ||
139 | return ret; | ||
140 | |||
141 | ret = gpio_request(GPIO_E750_SPK_AMP_OFF, "Speaker amp"); | ||
142 | if (ret) | ||
143 | goto free_hp_amp_gpio; | ||
144 | |||
145 | ret = gpio_direction_output(GPIO_E750_HP_AMP_OFF, 1); | ||
146 | if (ret) | ||
147 | goto free_spk_amp_gpio; | ||
148 | |||
149 | ret = gpio_direction_output(GPIO_E750_SPK_AMP_OFF, 1); | ||
150 | if (ret) | ||
151 | goto free_spk_amp_gpio; | ||
152 | |||
153 | e750_snd_device = platform_device_alloc("soc-audio", -1); | ||
154 | if (!e750_snd_device) { | ||
155 | ret = -ENOMEM; | ||
156 | goto free_spk_amp_gpio; | ||
157 | } | ||
158 | |||
159 | platform_set_drvdata(e750_snd_device, &e750_snd_devdata); | ||
160 | e750_snd_devdata.dev = &e750_snd_device->dev; | ||
161 | ret = platform_device_add(e750_snd_device); | ||
162 | |||
163 | if (!ret) | ||
164 | return 0; | ||
165 | |||
166 | /* Fail gracefully */ | ||
167 | platform_device_put(e750_snd_device); | ||
168 | free_spk_amp_gpio: | ||
169 | gpio_free(GPIO_E750_SPK_AMP_OFF); | ||
170 | free_hp_amp_gpio: | ||
171 | gpio_free(GPIO_E750_HP_AMP_OFF); | ||
172 | |||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | static void __exit e750_exit(void) | ||
177 | { | ||
178 | platform_device_unregister(e750_snd_device); | ||
179 | gpio_free(GPIO_E750_SPK_AMP_OFF); | ||
180 | gpio_free(GPIO_E750_HP_AMP_OFF); | ||
181 | } | ||
182 | |||
183 | module_init(e750_init); | ||
184 | module_exit(e750_exit); | ||
185 | |||
186 | /* Module information */ | ||
187 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | ||
188 | MODULE_DESCRIPTION("ALSA SoC driver for e750"); | ||
189 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 2e3386dfa0f0..78a1770b986c 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * e800-wm9712.c -- SoC audio for e800 | 2 | * e800-wm9712.c -- SoC audio for e800 |
3 | * | 3 | * |
4 | * Based on tosa.c | ||
5 | * | ||
6 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | 4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> |
7 | * | 5 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
@@ -13,31 +11,96 @@ | |||
13 | 11 | ||
14 | #include <linux/module.h> | 12 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
16 | #include <linux/device.h> | 14 | #include <linux/gpio.h> |
17 | 15 | ||
18 | #include <sound/core.h> | 16 | #include <sound/core.h> |
19 | #include <sound/pcm.h> | 17 | #include <sound/pcm.h> |
20 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
21 | #include <sound/soc-dapm.h> | 19 | #include <sound/soc-dapm.h> |
22 | 20 | ||
23 | #include <asm/mach-types.h> | ||
24 | #include <mach/pxa-regs.h> | 21 | #include <mach/pxa-regs.h> |
25 | #include <mach/hardware.h> | 22 | #include <mach/hardware.h> |
26 | #include <mach/audio.h> | 23 | #include <mach/audio.h> |
24 | #include <mach/eseries-gpio.h> | ||
25 | |||
26 | #include <asm/mach-types.h> | ||
27 | 27 | ||
28 | #include "../codecs/wm9712.h" | 28 | #include "../codecs/wm9712.h" |
29 | #include "pxa2xx-pcm.h" | 29 | #include "pxa2xx-pcm.h" |
30 | #include "pxa2xx-ac97.h" | 30 | #include "pxa2xx-ac97.h" |
31 | 31 | ||
32 | static struct snd_soc_card e800; | 32 | static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, |
33 | struct snd_kcontrol *kcontrol, int event) | ||
34 | { | ||
35 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
36 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 1); | ||
37 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
38 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 0); | ||
33 | 39 | ||
34 | static struct snd_soc_dai_link e800_dai[] = { | 40 | return 0; |
41 | } | ||
42 | |||
43 | static int e800_hp_amp_event(struct snd_soc_dapm_widget *w, | ||
44 | struct snd_kcontrol *kcontrol, int event) | ||
35 | { | 45 | { |
36 | .name = "AC97 Aux", | 46 | if (event & SND_SOC_DAPM_PRE_PMU) |
37 | .stream_name = "AC97 Aux", | 47 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 0); |
38 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | 48 | else if (event & SND_SOC_DAPM_POST_PMD) |
39 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | 49 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 1); |
40 | }, | 50 | |
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static const struct snd_soc_dapm_widget e800_dapm_widgets[] = { | ||
55 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
56 | SND_SOC_DAPM_MIC("Mic (Internal1)", NULL), | ||
57 | SND_SOC_DAPM_MIC("Mic (Internal2)", NULL), | ||
58 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
59 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
60 | e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
61 | SND_SOC_DAPM_POST_PMD), | ||
62 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
63 | e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
64 | SND_SOC_DAPM_POST_PMD), | ||
65 | }; | ||
66 | |||
67 | static const struct snd_soc_dapm_route audio_map[] = { | ||
68 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
69 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
70 | {"Headphone Jack", NULL, "Headphone Amp"}, | ||
71 | |||
72 | {"Speaker Amp", NULL, "MONOOUT"}, | ||
73 | {"Speaker", NULL, "Speaker Amp"}, | ||
74 | |||
75 | {"MIC1", NULL, "Mic (Internal1)"}, | ||
76 | {"MIC2", NULL, "Mic (Internal2)"}, | ||
77 | }; | ||
78 | |||
79 | static int e800_ac97_init(struct snd_soc_codec *codec) | ||
80 | { | ||
81 | snd_soc_dapm_new_controls(codec, e800_dapm_widgets, | ||
82 | ARRAY_SIZE(e800_dapm_widgets)); | ||
83 | |||
84 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
85 | snd_soc_dapm_sync(codec); | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static struct snd_soc_dai_link e800_dai[] = { | ||
91 | { | ||
92 | .name = "AC97", | ||
93 | .stream_name = "AC97 HiFi", | ||
94 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
95 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], | ||
96 | .init = e800_ac97_init, | ||
97 | }, | ||
98 | { | ||
99 | .name = "AC97 Aux", | ||
100 | .stream_name = "AC97 Aux", | ||
101 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
102 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | ||
103 | }, | ||
41 | }; | 104 | }; |
42 | 105 | ||
43 | static struct snd_soc_card e800 = { | 106 | static struct snd_soc_card e800 = { |
@@ -61,6 +124,22 @@ static int __init e800_init(void) | |||
61 | if (!machine_is_e800()) | 124 | if (!machine_is_e800()) |
62 | return -ENODEV; | 125 | return -ENODEV; |
63 | 126 | ||
127 | ret = gpio_request(GPIO_E800_HP_AMP_OFF, "Headphone amp"); | ||
128 | if (ret) | ||
129 | return ret; | ||
130 | |||
131 | ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp"); | ||
132 | if (ret) | ||
133 | goto free_hp_amp_gpio; | ||
134 | |||
135 | ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1); | ||
136 | if (ret) | ||
137 | goto free_spk_amp_gpio; | ||
138 | |||
139 | ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1); | ||
140 | if (ret) | ||
141 | goto free_spk_amp_gpio; | ||
142 | |||
64 | e800_snd_device = platform_device_alloc("soc-audio", -1); | 143 | e800_snd_device = platform_device_alloc("soc-audio", -1); |
65 | if (!e800_snd_device) | 144 | if (!e800_snd_device) |
66 | return -ENOMEM; | 145 | return -ENOMEM; |
@@ -69,8 +148,15 @@ static int __init e800_init(void) | |||
69 | e800_snd_devdata.dev = &e800_snd_device->dev; | 148 | e800_snd_devdata.dev = &e800_snd_device->dev; |
70 | ret = platform_device_add(e800_snd_device); | 149 | ret = platform_device_add(e800_snd_device); |
71 | 150 | ||
72 | if (ret) | 151 | if (!ret) |
73 | platform_device_put(e800_snd_device); | 152 | return 0; |
153 | |||
154 | /* Fail gracefully */ | ||
155 | platform_device_put(e800_snd_device); | ||
156 | free_spk_amp_gpio: | ||
157 | gpio_free(GPIO_E800_SPK_AMP_ON); | ||
158 | free_hp_amp_gpio: | ||
159 | gpio_free(GPIO_E800_HP_AMP_OFF); | ||
74 | 160 | ||
75 | return ret; | 161 | return ret; |
76 | } | 162 | } |
@@ -78,6 +164,8 @@ static int __init e800_init(void) | |||
78 | static void __exit e800_exit(void) | 164 | static void __exit e800_exit(void) |
79 | { | 165 | { |
80 | platform_device_unregister(e800_snd_device); | 166 | platform_device_unregister(e800_snd_device); |
167 | gpio_free(GPIO_E800_SPK_AMP_ON); | ||
168 | gpio_free(GPIO_E800_HP_AMP_OFF); | ||
81 | } | 169 | } |
82 | 170 | ||
83 | module_init(e800_init); | 171 | module_init(e800_init); |
@@ -86,4 +174,4 @@ module_exit(e800_exit); | |||
86 | /* Module information */ | 174 | /* Module information */ |
87 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | 175 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); |
88 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); | 176 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); |
89 | MODULE_LICENSE("GPL"); | 177 | MODULE_LICENSE("GPL v2"); |
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index f8e9ecd589d3..8541b679f6eb 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/clk.h> | ||
17 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
18 | #include <sound/core.h> | 19 | #include <sound/core.h> |
19 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
@@ -26,6 +27,17 @@ | |||
26 | #include "pxa2xx-ac97.h" | 27 | #include "pxa2xx-ac97.h" |
27 | #include "pxa-ssp.h" | 28 | #include "pxa-ssp.h" |
28 | 29 | ||
30 | /* | ||
31 | * There is a physical switch SW15 on the board which changes the MCLK | ||
32 | * for the WM9713 between the standard AC97 master clock and the | ||
33 | * output of the CLK_POUT signal from the PXA. | ||
34 | */ | ||
35 | static int clk_pout; | ||
36 | module_param(clk_pout, int, 0); | ||
37 | MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board)."); | ||
38 | |||
39 | static struct clk *pout; | ||
40 | |||
29 | static struct snd_soc_card zylonite; | 41 | static struct snd_soc_card zylonite; |
30 | 42 | ||
31 | static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { | 43 | static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { |
@@ -61,10 +73,8 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
61 | 73 | ||
62 | static int zylonite_wm9713_init(struct snd_soc_codec *codec) | 74 | static int zylonite_wm9713_init(struct snd_soc_codec *codec) |
63 | { | 75 | { |
64 | /* Currently we only support use of the AC97 clock here. If | 76 | if (clk_pout) |
65 | * CLK_POUT is selected by SW15 then the clock API will need | 77 | snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0); |
66 | * to be used to request and enable it here. | ||
67 | */ | ||
68 | 78 | ||
69 | snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, | 79 | snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, |
70 | ARRAY_SIZE(zylonite_dapm_widgets)); | 80 | ARRAY_SIZE(zylonite_dapm_widgets)); |
@@ -85,7 +95,6 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | |||
85 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 95 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
86 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 96 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
87 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 97 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
88 | unsigned int pll_out = 0; | ||
89 | unsigned int acds = 0; | 98 | unsigned int acds = 0; |
90 | unsigned int wm9713_div = 0; | 99 | unsigned int wm9713_div = 0; |
91 | int ret = 0; | 100 | int ret = 0; |
@@ -93,16 +102,13 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | |||
93 | switch (params_rate(params)) { | 102 | switch (params_rate(params)) { |
94 | case 8000: | 103 | case 8000: |
95 | wm9713_div = 12; | 104 | wm9713_div = 12; |
96 | pll_out = 2048000; | ||
97 | break; | 105 | break; |
98 | case 16000: | 106 | case 16000: |
99 | wm9713_div = 6; | 107 | wm9713_div = 6; |
100 | pll_out = 4096000; | ||
101 | break; | 108 | break; |
102 | case 48000: | 109 | case 48000: |
103 | default: | 110 | default: |
104 | wm9713_div = 2; | 111 | wm9713_div = 2; |
105 | pll_out = 12288000; | ||
106 | acds = 1; | 112 | acds = 1; |
107 | break; | 113 | break; |
108 | } | 114 | } |
@@ -123,10 +129,6 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | |||
123 | if (ret < 0) | 129 | if (ret < 0) |
124 | return ret; | 130 | return ret; |
125 | 131 | ||
126 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out); | ||
127 | if (ret < 0) | ||
128 | return ret; | ||
129 | |||
130 | ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds); | 132 | ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds); |
131 | if (ret < 0) | 133 | if (ret < 0) |
132 | return ret; | 134 | return ret; |
@@ -135,11 +137,12 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | |||
135 | if (ret < 0) | 137 | if (ret < 0) |
136 | return ret; | 138 | return ret; |
137 | 139 | ||
138 | /* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs | 140 | if (clk_pout) |
139 | * to be set instead. | 141 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV, |
140 | */ | 142 | WM9713_PCMDIV(wm9713_div)); |
141 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, | 143 | else |
142 | WM9713_PCMDIV(wm9713_div)); | 144 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, |
145 | WM9713_PCMDIV(wm9713_div)); | ||
143 | if (ret < 0) | 146 | if (ret < 0) |
144 | return ret; | 147 | return ret; |
145 | 148 | ||
@@ -173,8 +176,72 @@ static struct snd_soc_dai_link zylonite_dai[] = { | |||
173 | }, | 176 | }, |
174 | }; | 177 | }; |
175 | 178 | ||
179 | static int zylonite_probe(struct platform_device *pdev) | ||
180 | { | ||
181 | int ret; | ||
182 | |||
183 | if (clk_pout) { | ||
184 | pout = clk_get(NULL, "CLK_POUT"); | ||
185 | if (IS_ERR(pout)) { | ||
186 | dev_err(&pdev->dev, "Unable to obtain CLK_POUT: %ld\n", | ||
187 | PTR_ERR(pout)); | ||
188 | return PTR_ERR(pout); | ||
189 | } | ||
190 | |||
191 | ret = clk_enable(pout); | ||
192 | if (ret != 0) { | ||
193 | dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n", | ||
194 | ret); | ||
195 | clk_put(pout); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | dev_dbg(&pdev->dev, "MCLK enabled at %luHz\n", | ||
200 | clk_get_rate(pout)); | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int zylonite_remove(struct platform_device *pdev) | ||
207 | { | ||
208 | if (clk_pout) { | ||
209 | clk_disable(pout); | ||
210 | clk_put(pout); | ||
211 | } | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int zylonite_suspend_post(struct platform_device *pdev, | ||
217 | pm_message_t state) | ||
218 | { | ||
219 | if (clk_pout) | ||
220 | clk_disable(pout); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int zylonite_resume_pre(struct platform_device *pdev) | ||
226 | { | ||
227 | int ret = 0; | ||
228 | |||
229 | if (clk_pout) { | ||
230 | ret = clk_enable(pout); | ||
231 | if (ret != 0) | ||
232 | dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n", | ||
233 | ret); | ||
234 | } | ||
235 | |||
236 | return ret; | ||
237 | } | ||
238 | |||
176 | static struct snd_soc_card zylonite = { | 239 | static struct snd_soc_card zylonite = { |
177 | .name = "Zylonite", | 240 | .name = "Zylonite", |
241 | .probe = &zylonite_probe, | ||
242 | .remove = &zylonite_remove, | ||
243 | .suspend_post = &zylonite_suspend_post, | ||
244 | .resume_pre = &zylonite_resume_pre, | ||
178 | .platform = &pxa2xx_soc_platform, | 245 | .platform = &pxa2xx_soc_platform, |
179 | .dai_link = zylonite_dai, | 246 | .dai_link = zylonite_dai, |
180 | .num_links = ARRAY_SIZE(zylonite_dai), | 247 | .num_links = ARRAY_SIZE(zylonite_dai), |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 55fdb4abb179..8313d52a6e8c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1495,6 +1495,37 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | |||
1495 | EXPORT_SYMBOL_GPL(snd_soc_cnew); | 1495 | EXPORT_SYMBOL_GPL(snd_soc_cnew); |
1496 | 1496 | ||
1497 | /** | 1497 | /** |
1498 | * snd_soc_add_controls - add an array of controls to a codec. | ||
1499 | * Convienience function to add a list of controls. Many codecs were | ||
1500 | * duplicating this code. | ||
1501 | * | ||
1502 | * @codec: codec to add controls to | ||
1503 | * @controls: array of controls to add | ||
1504 | * @num_controls: number of elements in the array | ||
1505 | * | ||
1506 | * Return 0 for success, else error. | ||
1507 | */ | ||
1508 | int snd_soc_add_controls(struct snd_soc_codec *codec, | ||
1509 | const struct snd_kcontrol_new *controls, int num_controls) | ||
1510 | { | ||
1511 | struct snd_card *card = codec->card; | ||
1512 | int err, i; | ||
1513 | |||
1514 | for (i = 0; i < num_controls; i++) { | ||
1515 | const struct snd_kcontrol_new *control = &controls[i]; | ||
1516 | err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL)); | ||
1517 | if (err < 0) { | ||
1518 | dev_err(codec->dev, "%s: Failed to add %s\n", | ||
1519 | codec->name, control->name); | ||
1520 | return err; | ||
1521 | } | ||
1522 | } | ||
1523 | |||
1524 | return 0; | ||
1525 | } | ||
1526 | EXPORT_SYMBOL_GPL(snd_soc_add_controls); | ||
1527 | |||
1528 | /** | ||
1498 | * snd_soc_info_enum_double - enumerated double mixer info callback | 1529 | * snd_soc_info_enum_double - enumerated double mixer info callback |
1499 | * @kcontrol: mixer control | 1530 | * @kcontrol: mixer control |
1500 | * @uinfo: control element information | 1531 | * @uinfo: control element information |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a2f1da8b4646..54b4564b82b4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -54,14 +54,15 @@ | |||
54 | static int dapm_up_seq[] = { | 54 | static int dapm_up_seq[] = { |
55 | snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, | 55 | snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, |
56 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, | 56 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, |
57 | snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, | 57 | snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga, |
58 | snd_soc_dapm_spk, snd_soc_dapm_post | 58 | snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post |
59 | }; | 59 | }; |
60 | |||
60 | static int dapm_down_seq[] = { | 61 | static int dapm_down_seq[] = { |
61 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, | 62 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, |
62 | snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, | 63 | snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer, |
63 | snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux, | 64 | snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias, |
64 | snd_soc_dapm_post | 65 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post |
65 | }; | 66 | }; |
66 | 67 | ||
67 | static int dapm_status = 1; | 68 | static int dapm_status = 1; |
@@ -101,7 +102,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
101 | { | 102 | { |
102 | switch (w->id) { | 103 | switch (w->id) { |
103 | case snd_soc_dapm_switch: | 104 | case snd_soc_dapm_switch: |
104 | case snd_soc_dapm_mixer: { | 105 | case snd_soc_dapm_mixer: |
106 | case snd_soc_dapm_mixer_named_ctl: { | ||
105 | int val; | 107 | int val; |
106 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | 108 | struct soc_mixer_control *mc = (struct soc_mixer_control *) |
107 | w->kcontrols[i].private_value; | 109 | w->kcontrols[i].private_value; |
@@ -323,15 +325,33 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, | |||
323 | if (path->name != (char*)w->kcontrols[i].name) | 325 | if (path->name != (char*)w->kcontrols[i].name) |
324 | continue; | 326 | continue; |
325 | 327 | ||
326 | /* add dapm control with long name */ | 328 | /* add dapm control with long name. |
327 | name_len = 2 + strlen(w->name) | 329 | * for dapm_mixer this is the concatenation of the |
328 | + strlen(w->kcontrols[i].name); | 330 | * mixer and kcontrol name. |
331 | * for dapm_mixer_named_ctl this is simply the | ||
332 | * kcontrol name. | ||
333 | */ | ||
334 | name_len = strlen(w->kcontrols[i].name) + 1; | ||
335 | if (w->id == snd_soc_dapm_mixer) | ||
336 | name_len += 1 + strlen(w->name); | ||
337 | |||
329 | path->long_name = kmalloc(name_len, GFP_KERNEL); | 338 | path->long_name = kmalloc(name_len, GFP_KERNEL); |
339 | |||
330 | if (path->long_name == NULL) | 340 | if (path->long_name == NULL) |
331 | return -ENOMEM; | 341 | return -ENOMEM; |
332 | 342 | ||
333 | snprintf(path->long_name, name_len, "%s %s", | 343 | switch (w->id) { |
334 | w->name, w->kcontrols[i].name); | 344 | case snd_soc_dapm_mixer: |
345 | default: | ||
346 | snprintf(path->long_name, name_len, "%s %s", | ||
347 | w->name, w->kcontrols[i].name); | ||
348 | break; | ||
349 | case snd_soc_dapm_mixer_named_ctl: | ||
350 | snprintf(path->long_name, name_len, "%s", | ||
351 | w->kcontrols[i].name); | ||
352 | break; | ||
353 | } | ||
354 | |||
335 | path->long_name[name_len - 1] = '\0'; | 355 | path->long_name[name_len - 1] = '\0'; |
336 | 356 | ||
337 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, | 357 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, |
@@ -687,6 +707,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | |||
687 | case snd_soc_dapm_adc: | 707 | case snd_soc_dapm_adc: |
688 | case snd_soc_dapm_pga: | 708 | case snd_soc_dapm_pga: |
689 | case snd_soc_dapm_mixer: | 709 | case snd_soc_dapm_mixer: |
710 | case snd_soc_dapm_mixer_named_ctl: | ||
690 | if (w->name) { | 711 | if (w->name) { |
691 | in = is_connected_input_ep(w); | 712 | in = is_connected_input_ep(w); |
692 | dapm_clear_walk(w->codec); | 713 | dapm_clear_walk(w->codec); |
@@ -760,6 +781,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
760 | int found = 0; | 781 | int found = 0; |
761 | 782 | ||
762 | if (widget->id != snd_soc_dapm_mixer && | 783 | if (widget->id != snd_soc_dapm_mixer && |
784 | widget->id != snd_soc_dapm_mixer_named_ctl && | ||
763 | widget->id != snd_soc_dapm_switch) | 785 | widget->id != snd_soc_dapm_switch) |
764 | return -ENODEV; | 786 | return -ENODEV; |
765 | 787 | ||
@@ -813,6 +835,7 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
813 | case snd_soc_dapm_adc: | 835 | case snd_soc_dapm_adc: |
814 | case snd_soc_dapm_pga: | 836 | case snd_soc_dapm_pga: |
815 | case snd_soc_dapm_mixer: | 837 | case snd_soc_dapm_mixer: |
838 | case snd_soc_dapm_mixer_named_ctl: | ||
816 | if (w->name) | 839 | if (w->name) |
817 | count += sprintf(buf + count, "%s: %s\n", | 840 | count += sprintf(buf + count, "%s: %s\n", |
818 | w->name, w->power ? "On":"Off"); | 841 | w->name, w->power ? "On":"Off"); |
@@ -876,7 +899,7 @@ static void dapm_free_widgets(struct snd_soc_codec *codec) | |||
876 | } | 899 | } |
877 | 900 | ||
878 | static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, | 901 | static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, |
879 | char *pin, int status) | 902 | const char *pin, int status) |
880 | { | 903 | { |
881 | struct snd_soc_dapm_widget *w; | 904 | struct snd_soc_dapm_widget *w; |
882 | 905 | ||
@@ -991,6 +1014,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
991 | break; | 1014 | break; |
992 | case snd_soc_dapm_switch: | 1015 | case snd_soc_dapm_switch: |
993 | case snd_soc_dapm_mixer: | 1016 | case snd_soc_dapm_mixer: |
1017 | case snd_soc_dapm_mixer_named_ctl: | ||
994 | ret = dapm_connect_mixer(codec, wsource, wsink, path, control); | 1018 | ret = dapm_connect_mixer(codec, wsource, wsink, path, control); |
995 | if (ret != 0) | 1019 | if (ret != 0) |
996 | goto err; | 1020 | goto err; |
@@ -1068,6 +1092,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
1068 | switch(w->id) { | 1092 | switch(w->id) { |
1069 | case snd_soc_dapm_switch: | 1093 | case snd_soc_dapm_switch: |
1070 | case snd_soc_dapm_mixer: | 1094 | case snd_soc_dapm_mixer: |
1095 | case snd_soc_dapm_mixer_named_ctl: | ||
1071 | dapm_new_mixer(codec, w); | 1096 | dapm_new_mixer(codec, w); |
1072 | break; | 1097 | break; |
1073 | case snd_soc_dapm_mux: | 1098 | case snd_soc_dapm_mux: |
@@ -1549,7 +1574,7 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, | |||
1549 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 1574 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
1550 | * do any widget power switching. | 1575 | * do any widget power switching. |
1551 | */ | 1576 | */ |
1552 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin) | 1577 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin) |
1553 | { | 1578 | { |
1554 | return snd_soc_dapm_set_pin(codec, pin, 1); | 1579 | return snd_soc_dapm_set_pin(codec, pin, 1); |
1555 | } | 1580 | } |
@@ -1564,7 +1589,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | |||
1564 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 1589 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
1565 | * do any widget power switching. | 1590 | * do any widget power switching. |
1566 | */ | 1591 | */ |
1567 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin) | 1592 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin) |
1568 | { | 1593 | { |
1569 | return snd_soc_dapm_set_pin(codec, pin, 0); | 1594 | return snd_soc_dapm_set_pin(codec, pin, 0); |
1570 | } | 1595 | } |
@@ -1584,7 +1609,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | |||
1584 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 1609 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
1585 | * do any widget power switching. | 1610 | * do any widget power switching. |
1586 | */ | 1611 | */ |
1587 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin) | 1612 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin) |
1588 | { | 1613 | { |
1589 | return snd_soc_dapm_set_pin(codec, pin, 0); | 1614 | return snd_soc_dapm_set_pin(codec, pin, 0); |
1590 | } | 1615 | } |
@@ -1599,7 +1624,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); | |||
1599 | * | 1624 | * |
1600 | * Returns 1 for connected otherwise 0. | 1625 | * Returns 1 for connected otherwise 0. |
1601 | */ | 1626 | */ |
1602 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin) | 1627 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin) |
1603 | { | 1628 | { |
1604 | struct snd_soc_dapm_widget *w; | 1629 | struct snd_soc_dapm_widget *w; |
1605 | 1630 | ||
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c new file mode 100644 index 000000000000..8cc00c3cdf34 --- /dev/null +++ b/sound/soc/soc-jack.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * soc-jack.c -- ALSA SoC jack handling | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <sound/jack.h> | ||
15 | #include <sound/soc.h> | ||
16 | #include <sound/soc-dapm.h> | ||
17 | |||
18 | /** | ||
19 | * snd_soc_jack_new - Create a new jack | ||
20 | * @card: ASoC card | ||
21 | * @id: an identifying string for this jack | ||
22 | * @type: a bitmask of enum snd_jack_type values that can be detected by | ||
23 | * this jack | ||
24 | * @jack: structure to use for the jack | ||
25 | * | ||
26 | * Creates a new jack object. | ||
27 | * | ||
28 | * Returns zero if successful, or a negative error code on failure. | ||
29 | * On success jack will be initialised. | ||
30 | */ | ||
31 | int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type, | ||
32 | struct snd_soc_jack *jack) | ||
33 | { | ||
34 | jack->card = card; | ||
35 | INIT_LIST_HEAD(&jack->pins); | ||
36 | |||
37 | return snd_jack_new(card->socdev->codec->card, id, type, &jack->jack); | ||
38 | } | ||
39 | EXPORT_SYMBOL_GPL(snd_soc_jack_new); | ||
40 | |||
41 | /** | ||
42 | * snd_soc_jack_report - Report the current status for a jack | ||
43 | * | ||
44 | * @jack: the jack | ||
45 | * @status: a bitmask of enum snd_jack_type values that are currently detected. | ||
46 | * @mask: a bitmask of enum snd_jack_type values that being reported. | ||
47 | * | ||
48 | * If configured using snd_soc_jack_add_pins() then the associated | ||
49 | * DAPM pins will be enabled or disabled as appropriate and DAPM | ||
50 | * synchronised. | ||
51 | * | ||
52 | * Note: This function uses mutexes and should be called from a | ||
53 | * context which can sleep (such as a workqueue). | ||
54 | */ | ||
55 | void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) | ||
56 | { | ||
57 | struct snd_soc_codec *codec = jack->card->socdev->codec; | ||
58 | struct snd_soc_jack_pin *pin; | ||
59 | int enable; | ||
60 | int oldstatus; | ||
61 | |||
62 | if (!jack) { | ||
63 | WARN_ON_ONCE(!jack); | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | mutex_lock(&codec->mutex); | ||
68 | |||
69 | oldstatus = jack->status; | ||
70 | |||
71 | jack->status &= ~mask; | ||
72 | jack->status |= status; | ||
73 | |||
74 | /* The DAPM sync is expensive enough to be worth skipping */ | ||
75 | if (jack->status == oldstatus) | ||
76 | goto out; | ||
77 | |||
78 | list_for_each_entry(pin, &jack->pins, list) { | ||
79 | enable = pin->mask & status; | ||
80 | |||
81 | if (pin->invert) | ||
82 | enable = !enable; | ||
83 | |||
84 | if (enable) | ||
85 | snd_soc_dapm_enable_pin(codec, pin->pin); | ||
86 | else | ||
87 | snd_soc_dapm_disable_pin(codec, pin->pin); | ||
88 | } | ||
89 | |||
90 | snd_soc_dapm_sync(codec); | ||
91 | |||
92 | snd_jack_report(jack->jack, status); | ||
93 | |||
94 | out: | ||
95 | mutex_unlock(&codec->mutex); | ||
96 | } | ||
97 | EXPORT_SYMBOL_GPL(snd_soc_jack_report); | ||
98 | |||
99 | /** | ||
100 | * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack | ||
101 | * | ||
102 | * @jack: ASoC jack | ||
103 | * @count: Number of pins | ||
104 | * @pins: Array of pins | ||
105 | * | ||
106 | * After this function has been called the DAPM pins specified in the | ||
107 | * pins array will have their status updated to reflect the current | ||
108 | * state of the jack whenever the jack status is updated. | ||
109 | */ | ||
110 | int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, | ||
111 | struct snd_soc_jack_pin *pins) | ||
112 | { | ||
113 | int i; | ||
114 | |||
115 | for (i = 0; i < count; i++) { | ||
116 | if (!pins[i].pin) { | ||
117 | printk(KERN_ERR "No name for pin %d\n", i); | ||
118 | return -EINVAL; | ||
119 | } | ||
120 | if (!pins[i].mask) { | ||
121 | printk(KERN_ERR "No mask for pin %d (%s)\n", i, | ||
122 | pins[i].pin); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | |||
126 | INIT_LIST_HEAD(&pins[i].list); | ||
127 | list_add(&(pins[i].list), &jack->pins); | ||
128 | } | ||
129 | |||
130 | /* Update to reflect the last reported status; canned jack | ||
131 | * implementations are likely to set their state before the | ||
132 | * card has an opportunity to associate pins. | ||
133 | */ | ||
134 | snd_soc_jack_report(jack, 0, 0); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins); | ||