diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-06 20:09:51 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-06 20:09:51 -0500 |
commit | 932adbed6d99cc373fc3433d701b3a594fea872c (patch) | |
tree | d3495817d158f2678c38235b05102ea93d6795be | |
parent | ce519e2327bff01d0eb54071e7044e6291a52aa6 (diff) | |
parent | 167968199089435c63ad1140ccfb8c6179274a0a (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6:
ASoC: Fix SND_SOC_ALL_CODECS handling of dual SPI and I2C control buses
ASoC: Use snd_soc_dapm_nc_pin() in at91sam9g20ek
ASoC: TWL4030: Convert the bitfield enums to VALUE_ENUM type
ASoC: New enum type: value_enum
pxa2xx-ac97: switch AC unit to correct state before probing
ASoC: Clocking fixes for davinci-evm.c
ASoC: Mark non-connected TWL4030 pins for pandora
ASoC: OMAP: Select OMAP pin multiplexing when using Nokia N810 ASoC drivers
-rw-r--r-- | include/sound/soc-dapm.h | 15 | ||||
-rw-r--r-- | include/sound/soc.h | 30 | ||||
-rw-r--r-- | sound/arm/pxa2xx-ac97-lib.c | 25 | ||||
-rw-r--r-- | sound/soc/atmel/sam9g20_wm8731.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Kconfig | 20 | ||||
-rw-r--r-- | sound/soc/codecs/twl4030.c | 118 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-evm.c | 19 | ||||
-rw-r--r-- | sound/soc/omap/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/omap/omap3pandora.c | 13 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 107 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 197 |
11 files changed, 464 insertions, 85 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 7ee2f70ca42e..4af1083e3287 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -85,6 +85,10 @@ | |||
85 | #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 85 | #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
86 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 86 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ |
87 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} | 87 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1} |
88 | #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ | ||
89 | { .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \ | ||
90 | .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \ | ||
91 | .num_kcontrols = 1} | ||
88 | 92 | ||
89 | /* path domain with event - event handler must return 0 for success */ | 93 | /* path domain with event - event handler must return 0 for success */ |
90 | #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ | 94 | #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ |
@@ -172,6 +176,12 @@ | |||
172 | .get = snd_soc_dapm_get_enum_double, \ | 176 | .get = snd_soc_dapm_get_enum_double, \ |
173 | .put = snd_soc_dapm_put_enum_double, \ | 177 | .put = snd_soc_dapm_put_enum_double, \ |
174 | .private_value = (unsigned long)&xenum } | 178 | .private_value = (unsigned long)&xenum } |
179 | #define SOC_DAPM_VALUE_ENUM(xname, xenum) \ | ||
180 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
181 | .info = snd_soc_info_value_enum_double, \ | ||
182 | .get = snd_soc_dapm_get_value_enum_double, \ | ||
183 | .put = snd_soc_dapm_put_value_enum_double, \ | ||
184 | .private_value = (unsigned long)&xenum } | ||
175 | 185 | ||
176 | /* dapm stream operations */ | 186 | /* dapm stream operations */ |
177 | #define SND_SOC_DAPM_STREAM_NOP 0x0 | 187 | #define SND_SOC_DAPM_STREAM_NOP 0x0 |
@@ -214,6 +224,10 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
214 | struct snd_ctl_elem_value *ucontrol); | 224 | struct snd_ctl_elem_value *ucontrol); |
215 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 225 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
216 | struct snd_ctl_elem_value *ucontrol); | 226 | struct snd_ctl_elem_value *ucontrol); |
227 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
228 | struct snd_ctl_elem_value *ucontrol); | ||
229 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
230 | struct snd_ctl_elem_value *ucontrol); | ||
217 | int snd_soc_dapm_new_control(struct snd_soc_codec *codec, | 231 | int snd_soc_dapm_new_control(struct snd_soc_codec *codec, |
218 | const struct snd_soc_dapm_widget *widget); | 232 | const struct snd_soc_dapm_widget *widget); |
219 | int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, | 233 | int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, |
@@ -247,6 +261,7 @@ enum snd_soc_dapm_type { | |||
247 | snd_soc_dapm_input = 0, /* input pin */ | 261 | snd_soc_dapm_input = 0, /* input pin */ |
248 | snd_soc_dapm_output, /* output pin */ | 262 | snd_soc_dapm_output, /* output pin */ |
249 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ | 263 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ |
264 | snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */ | ||
250 | snd_soc_dapm_mixer, /* mixes several analog signals together */ | 265 | snd_soc_dapm_mixer, /* mixes several analog signals together */ |
251 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ | 266 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ |
252 | snd_soc_dapm_adc, /* analog to digital converter */ | 267 | snd_soc_dapm_adc, /* analog to digital converter */ |
diff --git a/include/sound/soc.h b/include/sound/soc.h index f86e455d3828..9b930d342116 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -94,11 +94,22 @@ | |||
94 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts) | 94 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts) |
95 | #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ | 95 | #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ |
96 | { .max = xmax, .texts = xtexts } | 96 | { .max = xmax, .texts = xtexts } |
97 | #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \ | ||
98 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | ||
99 | .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues} | ||
100 | #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \ | ||
101 | SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues) | ||
97 | #define SOC_ENUM(xname, xenum) \ | 102 | #define SOC_ENUM(xname, xenum) \ |
98 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | 103 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ |
99 | .info = snd_soc_info_enum_double, \ | 104 | .info = snd_soc_info_enum_double, \ |
100 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ | 105 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ |
101 | .private_value = (unsigned long)&xenum } | 106 | .private_value = (unsigned long)&xenum } |
107 | #define SOC_VALUE_ENUM(xname, xenum) \ | ||
108 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | ||
109 | .info = snd_soc_info_value_enum_double, \ | ||
110 | .get = snd_soc_get_value_enum_double, \ | ||
111 | .put = snd_soc_put_value_enum_double, \ | ||
112 | .private_value = (unsigned long)&xenum } | ||
102 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ | 113 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ |
103 | xhandler_get, xhandler_put) \ | 114 | xhandler_get, xhandler_put) \ |
104 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 115 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
@@ -200,6 +211,12 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
200 | struct snd_ctl_elem_value *ucontrol); | 211 | struct snd_ctl_elem_value *ucontrol); |
201 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | 212 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, |
202 | struct snd_ctl_elem_value *ucontrol); | 213 | struct snd_ctl_elem_value *ucontrol); |
214 | int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol, | ||
215 | struct snd_ctl_elem_info *uinfo); | ||
216 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
217 | struct snd_ctl_elem_value *ucontrol); | ||
218 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
219 | struct snd_ctl_elem_value *ucontrol); | ||
203 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | 220 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, |
204 | struct snd_ctl_elem_info *uinfo); | 221 | struct snd_ctl_elem_info *uinfo); |
205 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | 222 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, |
@@ -406,6 +423,19 @@ struct soc_enum { | |||
406 | void *dapm; | 423 | void *dapm; |
407 | }; | 424 | }; |
408 | 425 | ||
426 | /* semi enumerated kcontrol */ | ||
427 | struct soc_value_enum { | ||
428 | unsigned short reg; | ||
429 | unsigned short reg2; | ||
430 | unsigned char shift_l; | ||
431 | unsigned char shift_r; | ||
432 | unsigned int max; | ||
433 | unsigned int mask; | ||
434 | const char **texts; | ||
435 | const unsigned int *values; | ||
436 | void *dapm; | ||
437 | }; | ||
438 | |||
409 | #include <sound/soc-dai.h> | 439 | #include <sound/soc-dai.h> |
410 | 440 | ||
411 | #endif | 441 | #endif |
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index ef6539eea579..35afd0c33be5 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c | |||
@@ -321,10 +321,6 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) | |||
321 | { | 321 | { |
322 | int ret; | 322 | int ret; |
323 | 323 | ||
324 | ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); | ||
325 | if (ret < 0) | ||
326 | goto err; | ||
327 | |||
328 | if (cpu_is_pxa25x() || cpu_is_pxa27x()) { | 324 | if (cpu_is_pxa25x() || cpu_is_pxa27x()) { |
329 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | 325 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); |
330 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | 326 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); |
@@ -339,7 +335,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) | |||
339 | if (IS_ERR(ac97conf_clk)) { | 335 | if (IS_ERR(ac97conf_clk)) { |
340 | ret = PTR_ERR(ac97conf_clk); | 336 | ret = PTR_ERR(ac97conf_clk); |
341 | ac97conf_clk = NULL; | 337 | ac97conf_clk = NULL; |
342 | goto err_irq; | 338 | goto err_conf; |
343 | } | 339 | } |
344 | } | 340 | } |
345 | 341 | ||
@@ -347,19 +343,30 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) | |||
347 | if (IS_ERR(ac97_clk)) { | 343 | if (IS_ERR(ac97_clk)) { |
348 | ret = PTR_ERR(ac97_clk); | 344 | ret = PTR_ERR(ac97_clk); |
349 | ac97_clk = NULL; | 345 | ac97_clk = NULL; |
350 | goto err_irq; | 346 | goto err_clk; |
351 | } | 347 | } |
352 | 348 | ||
353 | return clk_enable(ac97_clk); | 349 | ret = clk_enable(ac97_clk); |
350 | if (ret) | ||
351 | goto err_clk2; | ||
352 | |||
353 | ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL); | ||
354 | if (ret < 0) | ||
355 | goto err_irq; | ||
356 | |||
357 | return 0; | ||
354 | 358 | ||
355 | err_irq: | 359 | err_irq: |
356 | GCR |= GCR_ACLINK_OFF; | 360 | GCR |= GCR_ACLINK_OFF; |
361 | err_clk2: | ||
362 | clk_put(ac97_clk); | ||
363 | ac97_clk = NULL; | ||
364 | err_clk: | ||
357 | if (ac97conf_clk) { | 365 | if (ac97conf_clk) { |
358 | clk_put(ac97conf_clk); | 366 | clk_put(ac97conf_clk); |
359 | ac97conf_clk = NULL; | 367 | ac97conf_clk = NULL; |
360 | } | 368 | } |
361 | free_irq(IRQ_AC97, NULL); | 369 | err_conf: |
362 | err: | ||
363 | return ret; | 370 | return ret; |
364 | } | 371 | } |
365 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); | 372 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); |
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 1fb59a9d3719..6ea04be911d0 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c | |||
@@ -221,8 +221,8 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) | |||
221 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | 221 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
222 | 222 | ||
223 | /* not connected */ | 223 | /* not connected */ |
224 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); | 224 | snd_soc_dapm_nc_pin(codec, "RLINEIN"); |
225 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); | 225 | snd_soc_dapm_nc_pin(codec, "LLINEIN"); |
226 | 226 | ||
227 | /* always connected */ | 227 | /* always connected */ |
228 | snd_soc_dapm_enable_pin(codec, "Int Mic"); | 228 | snd_soc_dapm_enable_pin(codec, "Int Mic"); |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c41289b5f586..d0e0d691ae51 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -1,3 +1,13 @@ | |||
1 | # Helper to resolve issues with configs that have SPI enabled but I2C | ||
2 | # modular, meaning we can't build the codec driver in with I2C support. | ||
3 | # We use an ordered list of conditional defaults to pick the appropriate | ||
4 | # setting - SPI can't be modular so that case doesn't need to be covered. | ||
5 | config SND_SOC_I2C_AND_SPI | ||
6 | tristate | ||
7 | default m if I2C=m | ||
8 | default y if I2C=y | ||
9 | default y if SPI_MASTER=y | ||
10 | |||
1 | config SND_SOC_ALL_CODECS | 11 | config SND_SOC_ALL_CODECS |
2 | tristate "Build all ASoC CODEC drivers" | 12 | tristate "Build all ASoC CODEC drivers" |
3 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS | 13 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS |
@@ -14,12 +24,12 @@ config SND_SOC_ALL_CODECS | |||
14 | select SND_SOC_UDA134X | 24 | select SND_SOC_UDA134X |
15 | select SND_SOC_UDA1380 if I2C | 25 | select SND_SOC_UDA1380 if I2C |
16 | select SND_SOC_WM8350 if MFD_WM8350 | 26 | select SND_SOC_WM8350 if MFD_WM8350 |
17 | select SND_SOC_WM8510 if (I2C || SPI_MASTER) | 27 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI |
18 | select SND_SOC_WM8580 if I2C | 28 | select SND_SOC_WM8580 if I2C |
19 | select SND_SOC_WM8728 if (I2C || SPI_MASTER) | 29 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI |
20 | select SND_SOC_WM8731 if (I2C || SPI_MASTER) | 30 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI |
21 | select SND_SOC_WM8750 if (I2C || SPI_MASTER) | 31 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI |
22 | select SND_SOC_WM8753 if (I2C || SPI_MASTER) | 32 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI |
23 | select SND_SOC_WM8900 if I2C | 33 | select SND_SOC_WM8900 if I2C |
24 | select SND_SOC_WM8903 if I2C | 34 | select SND_SOC_WM8903 if I2C |
25 | select SND_SOC_WM8971 if I2C | 35 | select SND_SOC_WM8971 if I2C |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 31e44e346dc8..fd0f338374a7 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -192,39 +192,51 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) | |||
192 | 192 | ||
193 | /* Earpiece */ | 193 | /* Earpiece */ |
194 | static const char *twl4030_earpiece_texts[] = | 194 | static const char *twl4030_earpiece_texts[] = |
195 | {"Off", "DACL1", "DACL2", "Invalid", "DACR1"}; | 195 | {"Off", "DACL1", "DACL2", "DACR1"}; |
196 | 196 | ||
197 | static const struct soc_enum twl4030_earpiece_enum = | 197 | static const unsigned int twl4030_earpiece_values[] = |
198 | SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, | 198 | {0x0, 0x1, 0x2, 0x4}; |
199 | |||
200 | static const struct soc_value_enum twl4030_earpiece_enum = | ||
201 | SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7, | ||
199 | ARRAY_SIZE(twl4030_earpiece_texts), | 202 | ARRAY_SIZE(twl4030_earpiece_texts), |
200 | twl4030_earpiece_texts); | 203 | twl4030_earpiece_texts, |
204 | twl4030_earpiece_values); | ||
201 | 205 | ||
202 | static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = | 206 | static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = |
203 | SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); | 207 | SOC_DAPM_VALUE_ENUM("Route", twl4030_earpiece_enum); |
204 | 208 | ||
205 | /* PreDrive Left */ | 209 | /* PreDrive Left */ |
206 | static const char *twl4030_predrivel_texts[] = | 210 | static const char *twl4030_predrivel_texts[] = |
207 | {"Off", "DACL1", "DACL2", "Invalid", "DACR2"}; | 211 | {"Off", "DACL1", "DACL2", "DACR2"}; |
212 | |||
213 | static const unsigned int twl4030_predrivel_values[] = | ||
214 | {0x0, 0x1, 0x2, 0x4}; | ||
208 | 215 | ||
209 | static const struct soc_enum twl4030_predrivel_enum = | 216 | static const struct soc_value_enum twl4030_predrivel_enum = |
210 | SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, | 217 | SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7, |
211 | ARRAY_SIZE(twl4030_predrivel_texts), | 218 | ARRAY_SIZE(twl4030_predrivel_texts), |
212 | twl4030_predrivel_texts); | 219 | twl4030_predrivel_texts, |
220 | twl4030_predrivel_values); | ||
213 | 221 | ||
214 | static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = | 222 | static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = |
215 | SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); | 223 | SOC_DAPM_VALUE_ENUM("Route", twl4030_predrivel_enum); |
216 | 224 | ||
217 | /* PreDrive Right */ | 225 | /* PreDrive Right */ |
218 | static const char *twl4030_predriver_texts[] = | 226 | static const char *twl4030_predriver_texts[] = |
219 | {"Off", "DACR1", "DACR2", "Invalid", "DACL2"}; | 227 | {"Off", "DACR1", "DACR2", "DACL2"}; |
220 | 228 | ||
221 | static const struct soc_enum twl4030_predriver_enum = | 229 | static const unsigned int twl4030_predriver_values[] = |
222 | SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, | 230 | {0x0, 0x1, 0x2, 0x4}; |
231 | |||
232 | static const struct soc_value_enum twl4030_predriver_enum = | ||
233 | SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7, | ||
223 | ARRAY_SIZE(twl4030_predriver_texts), | 234 | ARRAY_SIZE(twl4030_predriver_texts), |
224 | twl4030_predriver_texts); | 235 | twl4030_predriver_texts, |
236 | twl4030_predriver_values); | ||
225 | 237 | ||
226 | static const struct snd_kcontrol_new twl4030_dapm_predriver_control = | 238 | static const struct snd_kcontrol_new twl4030_dapm_predriver_control = |
227 | SOC_DAPM_ENUM("Route", twl4030_predriver_enum); | 239 | SOC_DAPM_VALUE_ENUM("Route", twl4030_predriver_enum); |
228 | 240 | ||
229 | /* Headset Left */ | 241 | /* Headset Left */ |
230 | static const char *twl4030_hsol_texts[] = | 242 | static const char *twl4030_hsol_texts[] = |
@@ -300,28 +312,35 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); | |||
300 | 312 | ||
301 | /* Left analog microphone selection */ | 313 | /* Left analog microphone selection */ |
302 | static const char *twl4030_analoglmic_texts[] = | 314 | static const char *twl4030_analoglmic_texts[] = |
303 | {"Off", "Main mic", "Headset mic", "Invalid", "AUXL", | 315 | {"Off", "Main mic", "Headset mic", "AUXL", "Carkit mic"}; |
304 | "Invalid", "Invalid", "Invalid", "Carkit mic"}; | 316 | |
317 | static const unsigned int twl4030_analoglmic_values[] = | ||
318 | {0x0, 0x1, 0x2, 0x4, 0x8}; | ||
305 | 319 | ||
306 | static const struct soc_enum twl4030_analoglmic_enum = | 320 | static const struct soc_value_enum twl4030_analoglmic_enum = |
307 | SOC_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, | 321 | SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf, |
308 | ARRAY_SIZE(twl4030_analoglmic_texts), | 322 | ARRAY_SIZE(twl4030_analoglmic_texts), |
309 | twl4030_analoglmic_texts); | 323 | twl4030_analoglmic_texts, |
324 | twl4030_analoglmic_values); | ||
310 | 325 | ||
311 | static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control = | 326 | static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control = |
312 | SOC_DAPM_ENUM("Route", twl4030_analoglmic_enum); | 327 | SOC_DAPM_VALUE_ENUM("Route", twl4030_analoglmic_enum); |
313 | 328 | ||
314 | /* Right analog microphone selection */ | 329 | /* Right analog microphone selection */ |
315 | static const char *twl4030_analogrmic_texts[] = | 330 | static const char *twl4030_analogrmic_texts[] = |
316 | {"Off", "Sub mic", "Invalid", "Invalid", "AUXR"}; | 331 | {"Off", "Sub mic", "AUXR"}; |
317 | 332 | ||
318 | static const struct soc_enum twl4030_analogrmic_enum = | 333 | static const unsigned int twl4030_analogrmic_values[] = |
319 | SOC_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, | 334 | {0x0, 0x1, 0x4}; |
335 | |||
336 | static const struct soc_value_enum twl4030_analogrmic_enum = | ||
337 | SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5, | ||
320 | ARRAY_SIZE(twl4030_analogrmic_texts), | 338 | ARRAY_SIZE(twl4030_analogrmic_texts), |
321 | twl4030_analogrmic_texts); | 339 | twl4030_analogrmic_texts, |
340 | twl4030_analogrmic_values); | ||
322 | 341 | ||
323 | static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control = | 342 | static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control = |
324 | SOC_DAPM_ENUM("Route", twl4030_analogrmic_enum); | 343 | SOC_DAPM_VALUE_ENUM("Route", twl4030_analogrmic_enum); |
325 | 344 | ||
326 | /* TX1 L/R Analog/Digital microphone selection */ | 345 | /* TX1 L/R Analog/Digital microphone selection */ |
327 | static const char *twl4030_micpathtx1_texts[] = | 346 | static const char *twl4030_micpathtx1_texts[] = |
@@ -347,28 +366,6 @@ static const struct soc_enum twl4030_micpathtx2_enum = | |||
347 | static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = | 366 | static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = |
348 | SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); | 367 | SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); |
349 | 368 | ||
350 | /* | ||
351 | * This function filters out the non valid mux settings, named as "Invalid" | ||
352 | * in the enum texts. | ||
353 | * Just refuse to set an invalid mux mode. | ||
354 | */ | ||
355 | static int twl4030_enum_event(struct snd_soc_dapm_widget *w, | ||
356 | struct snd_kcontrol *kcontrol, int event) | ||
357 | { | ||
358 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
359 | int ret = 0; | ||
360 | int val; | ||
361 | |||
362 | val = w->value >> e->shift_l; | ||
363 | if (!strcmp("Invalid", e->texts[val])) { | ||
364 | printk(KERN_WARNING "Invalid MUX setting on 0x%02x (%d)\n", | ||
365 | e->reg, val); | ||
366 | ret = -1; | ||
367 | } | ||
368 | |||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | static int micpath_event(struct snd_soc_dapm_widget *w, | 369 | static int micpath_event(struct snd_soc_dapm_widget *w, |
373 | struct snd_kcontrol *kcontrol, int event) | 370 | struct snd_kcontrol *kcontrol, int event) |
374 | { | 371 | { |
@@ -737,16 +734,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
737 | 734 | ||
738 | /* Output MUX controls */ | 735 | /* Output MUX controls */ |
739 | /* Earpiece */ | 736 | /* Earpiece */ |
740 | SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, | 737 | SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0, |
741 | &twl4030_dapm_earpiece_control, twl4030_enum_event, | 738 | &twl4030_dapm_earpiece_control), |
742 | SND_SOC_DAPM_PRE_REG), | ||
743 | /* PreDrivL/R */ | 739 | /* PreDrivL/R */ |
744 | SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0, | 740 | SND_SOC_DAPM_VALUE_MUX("PredriveL Mux", SND_SOC_NOPM, 0, 0, |
745 | &twl4030_dapm_predrivel_control, twl4030_enum_event, | 741 | &twl4030_dapm_predrivel_control), |
746 | SND_SOC_DAPM_PRE_REG), | 742 | SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0, |
747 | SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, | 743 | &twl4030_dapm_predriver_control), |
748 | &twl4030_dapm_predriver_control, twl4030_enum_event, | ||
749 | SND_SOC_DAPM_PRE_REG), | ||
750 | /* HeadsetL/R */ | 744 | /* HeadsetL/R */ |
751 | SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, | 745 | SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, |
752 | &twl4030_dapm_hsol_control), | 746 | &twl4030_dapm_hsol_control), |
@@ -789,12 +783,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
789 | SND_SOC_DAPM_POST_REG), | 783 | SND_SOC_DAPM_POST_REG), |
790 | 784 | ||
791 | /* Analog input muxes with power switch for the physical ADCL/R */ | 785 | /* Analog input muxes with power switch for the physical ADCL/R */ |
792 | SND_SOC_DAPM_MUX_E("Analog Left Capture Route", | 786 | SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route", |
793 | TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control, | 787 | TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control), |
794 | twl4030_enum_event, SND_SOC_DAPM_PRE_REG), | 788 | SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route", |
795 | SND_SOC_DAPM_MUX_E("Analog Right Capture Route", | 789 | TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control), |
796 | TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control, | ||
797 | twl4030_enum_event, SND_SOC_DAPM_PRE_REG), | ||
798 | 790 | ||
799 | SND_SOC_DAPM_PGA("Analog Left Amplifier", | 791 | SND_SOC_DAPM_PGA("Analog Left Amplifier", |
800 | TWL4030_REG_ANAMICL, 4, 0, NULL, 0), | 792 | TWL4030_REG_ANAMICL, 4, 0, NULL, 0), |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 01b948bb55a1..54851f318568 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include "davinci-pcm.h" | 26 | #include "davinci-pcm.h" |
27 | #include "davinci-i2s.h" | 27 | #include "davinci-i2s.h" |
28 | 28 | ||
29 | #define EVM_CODEC_CLOCK 22579200 | ||
30 | 29 | ||
31 | #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ | 30 | #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ |
32 | SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) | 31 | SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) |
@@ -37,6 +36,21 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
37 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 36 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
38 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 37 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
39 | int ret = 0; | 38 | int ret = 0; |
39 | unsigned sysclk; | ||
40 | |||
41 | /* ASP1 on DM355 EVM is clocked by an external oscillator */ | ||
42 | if (machine_is_davinci_dm355_evm()) | ||
43 | sysclk = 27000000; | ||
44 | |||
45 | /* ASP0 in DM6446 EVM is clocked by U55, as configured by | ||
46 | * board-dm644x-evm.c using GPIOs from U18. There are six | ||
47 | * options; here we "know" we use a 48 KHz sample rate. | ||
48 | */ | ||
49 | else if (machine_is_davinci_evm()) | ||
50 | sysclk = 12288000; | ||
51 | |||
52 | else | ||
53 | return -EINVAL; | ||
40 | 54 | ||
41 | /* set codec DAI configuration */ | 55 | /* set codec DAI configuration */ |
42 | ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); | 56 | ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); |
@@ -49,8 +63,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
49 | return ret; | 63 | return ret; |
50 | 64 | ||
51 | /* set the codec system clock */ | 65 | /* set the codec system clock */ |
52 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, | 66 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); |
53 | SND_SOC_CLOCK_OUT); | ||
54 | if (ret < 0) | 67 | if (ret < 0) |
55 | return ret; | 68 | return ret; |
56 | 69 | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a7b1d77b2105..4f7f04014585 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -10,6 +10,7 @@ config SND_OMAP_SOC_N810 | |||
10 | tristate "SoC Audio support for Nokia N810" | 10 | tristate "SoC Audio support for Nokia N810" |
11 | depends on SND_OMAP_SOC && MACH_NOKIA_N810 | 11 | depends on SND_OMAP_SOC && MACH_NOKIA_N810 |
12 | select SND_OMAP_SOC_MCBSP | 12 | select SND_OMAP_SOC_MCBSP |
13 | select OMAP_MUX | ||
13 | select SND_SOC_TLV320AIC3X | 14 | select SND_SOC_TLV320AIC3X |
14 | help | 15 | help |
15 | Say Y if you want to add support for SoC audio on Nokia N810. | 16 | Say Y if you want to add support for SoC audio on Nokia N810. |
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index bd91594496b1..fcc2f5d9a878 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c | |||
@@ -180,6 +180,19 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec) | |||
180 | { | 180 | { |
181 | int ret; | 181 | int ret; |
182 | 182 | ||
183 | /* All TWL4030 output pins are floating */ | ||
184 | snd_soc_dapm_nc_pin(codec, "OUTL"), | ||
185 | snd_soc_dapm_nc_pin(codec, "OUTR"), | ||
186 | snd_soc_dapm_nc_pin(codec, "EARPIECE"), | ||
187 | snd_soc_dapm_nc_pin(codec, "PREDRIVEL"), | ||
188 | snd_soc_dapm_nc_pin(codec, "PREDRIVER"), | ||
189 | snd_soc_dapm_nc_pin(codec, "HSOL"), | ||
190 | snd_soc_dapm_nc_pin(codec, "HSOR"), | ||
191 | snd_soc_dapm_nc_pin(codec, "CARKITL"), | ||
192 | snd_soc_dapm_nc_pin(codec, "CARKITR"), | ||
193 | snd_soc_dapm_nc_pin(codec, "HFL"), | ||
194 | snd_soc_dapm_nc_pin(codec, "HFR"), | ||
195 | |||
183 | ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, | 196 | ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, |
184 | ARRAY_SIZE(omap3pandora_in_dapm_widgets)); | 197 | ARRAY_SIZE(omap3pandora_in_dapm_widgets)); |
185 | if (ret < 0) | 198 | if (ret < 0) |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f73c1341437c..6cbe7e82f238 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1585,6 +1585,113 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1585 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | 1585 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); |
1586 | 1586 | ||
1587 | /** | 1587 | /** |
1588 | * snd_soc_info_value_enum_double - semi enumerated double mixer info callback | ||
1589 | * @kcontrol: mixer control | ||
1590 | * @uinfo: control element information | ||
1591 | * | ||
1592 | * Callback to provide information about a double semi enumerated | ||
1593 | * mixer control. | ||
1594 | * | ||
1595 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
1596 | * used for handling bitfield coded enumeration for example. | ||
1597 | * | ||
1598 | * Returns 0 for success. | ||
1599 | */ | ||
1600 | int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol, | ||
1601 | struct snd_ctl_elem_info *uinfo) | ||
1602 | { | ||
1603 | struct soc_value_enum *e = (struct soc_value_enum *) | ||
1604 | kcontrol->private_value; | ||
1605 | |||
1606 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1607 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | ||
1608 | uinfo->value.enumerated.items = e->max; | ||
1609 | |||
1610 | if (uinfo->value.enumerated.item > e->max - 1) | ||
1611 | uinfo->value.enumerated.item = e->max - 1; | ||
1612 | strcpy(uinfo->value.enumerated.name, | ||
1613 | e->texts[uinfo->value.enumerated.item]); | ||
1614 | return 0; | ||
1615 | } | ||
1616 | EXPORT_SYMBOL_GPL(snd_soc_info_value_enum_double); | ||
1617 | |||
1618 | /** | ||
1619 | * snd_soc_get_value_enum_double - semi enumerated double mixer get callback | ||
1620 | * @kcontrol: mixer control | ||
1621 | * @ucontrol: control element information | ||
1622 | * | ||
1623 | * Callback to get the value of a double semi enumerated mixer. | ||
1624 | * | ||
1625 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
1626 | * used for handling bitfield coded enumeration for example. | ||
1627 | * | ||
1628 | * Returns 0 for success. | ||
1629 | */ | ||
1630 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
1631 | struct snd_ctl_elem_value *ucontrol) | ||
1632 | { | ||
1633 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1634 | struct soc_value_enum *e = (struct soc_value_enum *) | ||
1635 | kcontrol->private_value; | ||
1636 | unsigned short reg_val, val, mux; | ||
1637 | |||
1638 | reg_val = snd_soc_read(codec, e->reg); | ||
1639 | val = (reg_val >> e->shift_l) & e->mask; | ||
1640 | for (mux = 0; mux < e->max; mux++) { | ||
1641 | if (val == e->values[mux]) | ||
1642 | break; | ||
1643 | } | ||
1644 | ucontrol->value.enumerated.item[0] = mux; | ||
1645 | if (e->shift_l != e->shift_r) { | ||
1646 | val = (reg_val >> e->shift_r) & e->mask; | ||
1647 | for (mux = 0; mux < e->max; mux++) { | ||
1648 | if (val == e->values[mux]) | ||
1649 | break; | ||
1650 | } | ||
1651 | ucontrol->value.enumerated.item[1] = mux; | ||
1652 | } | ||
1653 | |||
1654 | return 0; | ||
1655 | } | ||
1656 | EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); | ||
1657 | |||
1658 | /** | ||
1659 | * snd_soc_put_value_enum_double - semi enumerated double mixer put callback | ||
1660 | * @kcontrol: mixer control | ||
1661 | * @ucontrol: control element information | ||
1662 | * | ||
1663 | * Callback to set the value of a double semi enumerated mixer. | ||
1664 | * | ||
1665 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
1666 | * used for handling bitfield coded enumeration for example. | ||
1667 | * | ||
1668 | * Returns 0 for success. | ||
1669 | */ | ||
1670 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
1671 | struct snd_ctl_elem_value *ucontrol) | ||
1672 | { | ||
1673 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1674 | struct soc_value_enum *e = (struct soc_value_enum *) | ||
1675 | kcontrol->private_value; | ||
1676 | unsigned short val; | ||
1677 | unsigned short mask; | ||
1678 | |||
1679 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | ||
1680 | return -EINVAL; | ||
1681 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | ||
1682 | mask = e->mask << e->shift_l; | ||
1683 | if (e->shift_l != e->shift_r) { | ||
1684 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
1685 | return -EINVAL; | ||
1686 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | ||
1687 | mask |= e->mask << e->shift_r; | ||
1688 | } | ||
1689 | |||
1690 | return snd_soc_update_bits(codec, e->reg, mask, val); | ||
1691 | } | ||
1692 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); | ||
1693 | |||
1694 | /** | ||
1588 | * snd_soc_info_enum_ext - external enumerated single mixer info callback | 1695 | * snd_soc_info_enum_ext - external enumerated single mixer info callback |
1589 | * @kcontrol: mixer control | 1696 | * @kcontrol: mixer control |
1590 | * @uinfo: control element information | 1697 | * @uinfo: control element information |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6c79ca6df0bf..ad0d801677c1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -53,13 +53,15 @@ | |||
53 | /* dapm power sequences - make this per codec in the future */ | 53 | /* dapm power sequences - make this per codec in the future */ |
54 | static int dapm_up_seq[] = { | 54 | static int dapm_up_seq[] = { |
55 | snd_soc_dapm_pre, snd_soc_dapm_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_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga, | 56 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, |
57 | snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post | 57 | snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, |
58 | snd_soc_dapm_spk, snd_soc_dapm_post | ||
58 | }; | 59 | }; |
59 | static int dapm_down_seq[] = { | 60 | static int dapm_down_seq[] = { |
60 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, | 61 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, |
61 | snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, | 62 | snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, |
62 | snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post | 63 | snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux, |
64 | snd_soc_dapm_post | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | static int dapm_status = 1; | 67 | static int dapm_status = 1; |
@@ -134,6 +136,25 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
134 | } | 136 | } |
135 | } | 137 | } |
136 | break; | 138 | break; |
139 | case snd_soc_dapm_value_mux: { | ||
140 | struct soc_value_enum *e = (struct soc_value_enum *) | ||
141 | w->kcontrols[i].private_value; | ||
142 | int val, item; | ||
143 | |||
144 | val = snd_soc_read(w->codec, e->reg); | ||
145 | val = (val >> e->shift_l) & e->mask; | ||
146 | for (item = 0; item < e->max; item++) { | ||
147 | if (val == e->values[item]) | ||
148 | break; | ||
149 | } | ||
150 | |||
151 | p->connect = 0; | ||
152 | for (i = 0; i < e->max; i++) { | ||
153 | if (!(strcmp(p->name, e->texts[i])) && item == i) | ||
154 | p->connect = 1; | ||
155 | } | ||
156 | } | ||
157 | break; | ||
137 | /* does not effect routing - always connected */ | 158 | /* does not effect routing - always connected */ |
138 | case snd_soc_dapm_pga: | 159 | case snd_soc_dapm_pga: |
139 | case snd_soc_dapm_output: | 160 | case snd_soc_dapm_output: |
@@ -179,6 +200,30 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, | |||
179 | return -ENODEV; | 200 | return -ENODEV; |
180 | } | 201 | } |
181 | 202 | ||
203 | /* connect value_mux widget to it's interconnecting audio paths */ | ||
204 | static int dapm_connect_value_mux(struct snd_soc_codec *codec, | ||
205 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
206 | struct snd_soc_dapm_path *path, const char *control_name, | ||
207 | const struct snd_kcontrol_new *kcontrol) | ||
208 | { | ||
209 | struct soc_value_enum *e = (struct soc_value_enum *) | ||
210 | kcontrol->private_value; | ||
211 | int i; | ||
212 | |||
213 | for (i = 0; i < e->max; i++) { | ||
214 | if (!(strcmp(control_name, e->texts[i]))) { | ||
215 | list_add(&path->list, &codec->dapm_paths); | ||
216 | list_add(&path->list_sink, &dest->sources); | ||
217 | list_add(&path->list_source, &src->sinks); | ||
218 | path->name = (char *)e->texts[i]; | ||
219 | dapm_set_path_status(dest, path, 0); | ||
220 | return 0; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | return -ENODEV; | ||
225 | } | ||
226 | |||
182 | /* connect mixer widget to it's interconnecting audio paths */ | 227 | /* connect mixer widget to it's interconnecting audio paths */ |
183 | static int dapm_connect_mixer(struct snd_soc_codec *codec, | 228 | static int dapm_connect_mixer(struct snd_soc_codec *codec, |
184 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 229 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
@@ -653,6 +698,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | |||
653 | case snd_soc_dapm_vmid: | 698 | case snd_soc_dapm_vmid: |
654 | continue; | 699 | continue; |
655 | case snd_soc_dapm_mux: | 700 | case snd_soc_dapm_mux: |
701 | case snd_soc_dapm_value_mux: | ||
656 | case snd_soc_dapm_output: | 702 | case snd_soc_dapm_output: |
657 | case snd_soc_dapm_input: | 703 | case snd_soc_dapm_input: |
658 | case snd_soc_dapm_switch: | 704 | case snd_soc_dapm_switch: |
@@ -728,6 +774,45 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
728 | return 0; | 774 | return 0; |
729 | } | 775 | } |
730 | 776 | ||
777 | /* test and update the power status of a value_mux widget */ | ||
778 | static int dapm_value_mux_update_power(struct snd_soc_dapm_widget *widget, | ||
779 | struct snd_kcontrol *kcontrol, int mask, | ||
780 | int mux, int val, struct soc_value_enum *e) | ||
781 | { | ||
782 | struct snd_soc_dapm_path *path; | ||
783 | int found = 0; | ||
784 | |||
785 | if (widget->id != snd_soc_dapm_value_mux) | ||
786 | return -ENODEV; | ||
787 | |||
788 | if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) | ||
789 | return 0; | ||
790 | |||
791 | /* find dapm widget path assoc with kcontrol */ | ||
792 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | ||
793 | if (path->kcontrol != kcontrol) | ||
794 | continue; | ||
795 | |||
796 | if (!path->name || !e->texts[mux]) | ||
797 | continue; | ||
798 | |||
799 | found = 1; | ||
800 | /* we now need to match the string in the enum to the path */ | ||
801 | if (!(strcmp(path->name, e->texts[mux]))) | ||
802 | path->connect = 1; /* new connection */ | ||
803 | else | ||
804 | path->connect = 0; /* old connection must be | ||
805 | powered down */ | ||
806 | } | ||
807 | |||
808 | if (found) { | ||
809 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | ||
810 | dump_dapm(widget->codec, "mux power update"); | ||
811 | } | ||
812 | |||
813 | return 0; | ||
814 | } | ||
815 | |||
731 | /* test and update the power status of a mixer or switch widget */ | 816 | /* test and update the power status of a mixer or switch widget */ |
732 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 817 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, |
733 | struct snd_kcontrol *kcontrol, int reg, | 818 | struct snd_kcontrol *kcontrol, int reg, |
@@ -965,6 +1050,12 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
965 | if (ret != 0) | 1050 | if (ret != 0) |
966 | goto err; | 1051 | goto err; |
967 | break; | 1052 | break; |
1053 | case snd_soc_dapm_value_mux: | ||
1054 | ret = dapm_connect_value_mux(codec, wsource, wsink, path, | ||
1055 | control, &wsink->kcontrols[0]); | ||
1056 | if (ret != 0) | ||
1057 | goto err; | ||
1058 | break; | ||
968 | case snd_soc_dapm_switch: | 1059 | case snd_soc_dapm_switch: |
969 | case snd_soc_dapm_mixer: | 1060 | case snd_soc_dapm_mixer: |
970 | ret = dapm_connect_mixer(codec, wsource, wsink, path, control); | 1061 | ret = dapm_connect_mixer(codec, wsource, wsink, path, control); |
@@ -1047,6 +1138,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
1047 | dapm_new_mixer(codec, w); | 1138 | dapm_new_mixer(codec, w); |
1048 | break; | 1139 | break; |
1049 | case snd_soc_dapm_mux: | 1140 | case snd_soc_dapm_mux: |
1141 | case snd_soc_dapm_value_mux: | ||
1050 | dapm_new_mux(codec, w); | 1142 | dapm_new_mux(codec, w); |
1051 | break; | 1143 | break; |
1052 | case snd_soc_dapm_adc: | 1144 | case snd_soc_dapm_adc: |
@@ -1274,6 +1366,105 @@ out: | |||
1274 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 1366 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
1275 | 1367 | ||
1276 | /** | 1368 | /** |
1369 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get | ||
1370 | * callback | ||
1371 | * @kcontrol: mixer control | ||
1372 | * @ucontrol: control element information | ||
1373 | * | ||
1374 | * Callback to get the value of a dapm semi enumerated double mixer control. | ||
1375 | * | ||
1376 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
1377 | * used for handling bitfield coded enumeration for example. | ||
1378 | * | ||
1379 | * Returns 0 for success. | ||
1380 | */ | ||
1381 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
1382 | struct snd_ctl_elem_value *ucontrol) | ||
1383 | { | ||
1384 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1385 | struct soc_value_enum *e = (struct soc_value_enum *) | ||
1386 | kcontrol->private_value; | ||
1387 | unsigned short reg_val, val, mux; | ||
1388 | |||
1389 | reg_val = snd_soc_read(widget->codec, e->reg); | ||
1390 | val = (reg_val >> e->shift_l) & e->mask; | ||
1391 | for (mux = 0; mux < e->max; mux++) { | ||
1392 | if (val == e->values[mux]) | ||
1393 | break; | ||
1394 | } | ||
1395 | ucontrol->value.enumerated.item[0] = mux; | ||
1396 | if (e->shift_l != e->shift_r) { | ||
1397 | val = (reg_val >> e->shift_r) & e->mask; | ||
1398 | for (mux = 0; mux < e->max; mux++) { | ||
1399 | if (val == e->values[mux]) | ||
1400 | break; | ||
1401 | } | ||
1402 | ucontrol->value.enumerated.item[1] = mux; | ||
1403 | } | ||
1404 | |||
1405 | return 0; | ||
1406 | } | ||
1407 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | ||
1408 | |||
1409 | /** | ||
1410 | * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set | ||
1411 | * callback | ||
1412 | * @kcontrol: mixer control | ||
1413 | * @ucontrol: control element information | ||
1414 | * | ||
1415 | * Callback to set the value of a dapm semi enumerated double mixer control. | ||
1416 | * | ||
1417 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
1418 | * used for handling bitfield coded enumeration for example. | ||
1419 | * | ||
1420 | * Returns 0 for success. | ||
1421 | */ | ||
1422 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
1423 | struct snd_ctl_elem_value *ucontrol) | ||
1424 | { | ||
1425 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1426 | struct soc_value_enum *e = (struct soc_value_enum *) | ||
1427 | kcontrol->private_value; | ||
1428 | unsigned short val, mux; | ||
1429 | unsigned short mask; | ||
1430 | int ret = 0; | ||
1431 | |||
1432 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | ||
1433 | return -EINVAL; | ||
1434 | mux = ucontrol->value.enumerated.item[0]; | ||
1435 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | ||
1436 | mask = e->mask << e->shift_l; | ||
1437 | if (e->shift_l != e->shift_r) { | ||
1438 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
1439 | return -EINVAL; | ||
1440 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | ||
1441 | mask |= e->mask << e->shift_r; | ||
1442 | } | ||
1443 | |||
1444 | mutex_lock(&widget->codec->mutex); | ||
1445 | widget->value = val; | ||
1446 | dapm_value_mux_update_power(widget, kcontrol, mask, mux, val, e); | ||
1447 | if (widget->event) { | ||
1448 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | ||
1449 | ret = widget->event(widget, | ||
1450 | kcontrol, SND_SOC_DAPM_PRE_REG); | ||
1451 | if (ret < 0) | ||
1452 | goto out; | ||
1453 | } | ||
1454 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | ||
1455 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | ||
1456 | ret = widget->event(widget, | ||
1457 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1458 | } else | ||
1459 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | ||
1460 | |||
1461 | out: | ||
1462 | mutex_unlock(&widget->codec->mutex); | ||
1463 | return ret; | ||
1464 | } | ||
1465 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | ||
1466 | |||
1467 | /** | ||
1277 | * snd_soc_dapm_new_control - create new dapm control | 1468 | * snd_soc_dapm_new_control - create new dapm control |
1278 | * @codec: audio codec | 1469 | * @codec: audio codec |
1279 | * @widget: widget template | 1470 | * @widget: widget template |