aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-01-06 03:48:51 -0500
committerTakashi Iwai <tiwai@suse.de>2009-01-06 03:48:51 -0500
commit5439e726b54af8fdd958afa2ff42c4821eaf027a (patch)
treee1a62a43f96216fd0d365ca28c0ab2ee5a581e3a /sound
parent238c6d54830c624f34ac9cf123ac04aebfca5013 (diff)
parent2f42357722f7ddc1ec0236fa55ad49ea8a7ce4b0 (diff)
Merge branch 'topic/asoc' into for-linus
Diffstat (limited to 'sound')
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c25
-rw-r--r--sound/soc/codecs/twl4030.c118
-rw-r--r--sound/soc/davinci/davinci-evm.c19
-rw-r--r--sound/soc/omap/Kconfig1
-rw-r--r--sound/soc/omap/omap3pandora.c13
-rw-r--r--sound/soc/soc-core.c107
-rw-r--r--sound/soc/soc-dapm.c197
7 files changed, 402 insertions, 78 deletions
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
355err_irq: 359err_irq:
356 GCR |= GCR_ACLINK_OFF; 360 GCR |= GCR_ACLINK_OFF;
361err_clk2:
362 clk_put(ac97_clk);
363 ac97_clk = NULL;
364err_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); 369err_conf:
362err:
363 return ret; 370 return ret;
364} 371}
365EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); 372EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
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 */
194static const char *twl4030_earpiece_texts[] = 194static const char *twl4030_earpiece_texts[] =
195 {"Off", "DACL1", "DACL2", "Invalid", "DACR1"}; 195 {"Off", "DACL1", "DACL2", "DACR1"};
196 196
197static const struct soc_enum twl4030_earpiece_enum = 197static const unsigned int twl4030_earpiece_values[] =
198 SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 198 {0x0, 0x1, 0x2, 0x4};
199
200static 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
202static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = 206static const struct snd_kcontrol_new twl4030_dapm_earpiece_control =
203SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); 207SOC_DAPM_VALUE_ENUM("Route", twl4030_earpiece_enum);
204 208
205/* PreDrive Left */ 209/* PreDrive Left */
206static const char *twl4030_predrivel_texts[] = 210static const char *twl4030_predrivel_texts[] =
207 {"Off", "DACL1", "DACL2", "Invalid", "DACR2"}; 211 {"Off", "DACL1", "DACL2", "DACR2"};
212
213static const unsigned int twl4030_predrivel_values[] =
214 {0x0, 0x1, 0x2, 0x4};
208 215
209static const struct soc_enum twl4030_predrivel_enum = 216static 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
214static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = 222static const struct snd_kcontrol_new twl4030_dapm_predrivel_control =
215SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); 223SOC_DAPM_VALUE_ENUM("Route", twl4030_predrivel_enum);
216 224
217/* PreDrive Right */ 225/* PreDrive Right */
218static const char *twl4030_predriver_texts[] = 226static const char *twl4030_predriver_texts[] =
219 {"Off", "DACR1", "DACR2", "Invalid", "DACL2"}; 227 {"Off", "DACR1", "DACR2", "DACL2"};
220 228
221static const struct soc_enum twl4030_predriver_enum = 229static const unsigned int twl4030_predriver_values[] =
222 SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 230 {0x0, 0x1, 0x2, 0x4};
231
232static 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
226static const struct snd_kcontrol_new twl4030_dapm_predriver_control = 238static const struct snd_kcontrol_new twl4030_dapm_predriver_control =
227SOC_DAPM_ENUM("Route", twl4030_predriver_enum); 239SOC_DAPM_VALUE_ENUM("Route", twl4030_predriver_enum);
228 240
229/* Headset Left */ 241/* Headset Left */
230static const char *twl4030_hsol_texts[] = 242static 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 */
302static const char *twl4030_analoglmic_texts[] = 314static 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
317static const unsigned int twl4030_analoglmic_values[] =
318 {0x0, 0x1, 0x2, 0x4, 0x8};
305 319
306static const struct soc_enum twl4030_analoglmic_enum = 320static 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
311static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control = 326static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control =
312SOC_DAPM_ENUM("Route", twl4030_analoglmic_enum); 327SOC_DAPM_VALUE_ENUM("Route", twl4030_analoglmic_enum);
313 328
314/* Right analog microphone selection */ 329/* Right analog microphone selection */
315static const char *twl4030_analogrmic_texts[] = 330static const char *twl4030_analogrmic_texts[] =
316 {"Off", "Sub mic", "Invalid", "Invalid", "AUXR"}; 331 {"Off", "Sub mic", "AUXR"};
317 332
318static const struct soc_enum twl4030_analogrmic_enum = 333static const unsigned int twl4030_analogrmic_values[] =
319 SOC_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 334 {0x0, 0x1, 0x4};
335
336static 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
323static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control = 342static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control =
324SOC_DAPM_ENUM("Route", twl4030_analogrmic_enum); 343SOC_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 */
327static const char *twl4030_micpathtx1_texts[] = 346static const char *twl4030_micpathtx1_texts[] =
@@ -347,28 +366,6 @@ static const struct soc_enum twl4030_micpathtx2_enum =
347static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = 366static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control =
348SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); 367SOC_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 */
355static 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
372static int micpath_event(struct snd_soc_dapm_widget *w, 369static 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,
1585EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); 1585EXPORT_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 */
1600int 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}
1616EXPORT_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 */
1630int 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}
1656EXPORT_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 */
1670int 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}
1692EXPORT_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 */
54static int dapm_up_seq[] = { 54static 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};
59static int dapm_down_seq[] = { 60static 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
65static int dapm_status = 1; 67static 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 */
204static 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 */
183static int dapm_connect_mixer(struct snd_soc_codec *codec, 228static 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 */
778static 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 */
732static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 817static 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:
1274EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); 1366EXPORT_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 */
1381int 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}
1407EXPORT_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 */
1422int 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
1461out:
1462 mutex_unlock(&widget->codec->mutex);
1463 return ret;
1464}
1465EXPORT_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