diff options
54 files changed, 1568 insertions, 453 deletions
diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt index 46f9684d0b29..9e6763264a2e 100644 --- a/Documentation/sound/alsa/soc/dapm.txt +++ b/Documentation/sound/alsa/soc/dapm.txt | |||
| @@ -116,6 +116,9 @@ SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), | |||
| 116 | SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls, | 116 | SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls, |
| 117 | ARRAY_SIZE(wm8731_output_mixer_controls)), | 117 | ARRAY_SIZE(wm8731_output_mixer_controls)), |
| 118 | 118 | ||
| 119 | If you dont want the mixer elements prefixed with the name of the mixer widget, | ||
| 120 | you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead. the parameters are the same | ||
| 121 | as for SND_SOC_DAPM_MIXER. | ||
| 119 | 122 | ||
| 120 | 2.3 Platform/Machine domain Widgets | 123 | 2.3 Platform/Machine domain Widgets |
| 121 | ----------------------------------- | 124 | ----------------------------------- |
diff --git a/arch/arm/mach-pxa/e740.c b/arch/arm/mach-pxa/e740.c index 6d48e00f4f0b..a6fff782e7a8 100644 --- a/arch/arm/mach-pxa/e740.c +++ b/arch/arm/mach-pxa/e740.c | |||
| @@ -135,6 +135,11 @@ static unsigned long e740_pin_config[] __initdata = { | |||
| 135 | /* IrDA */ | 135 | /* IrDA */ |
| 136 | GPIO38_GPIO | MFP_LPM_DRIVE_HIGH, | 136 | GPIO38_GPIO | MFP_LPM_DRIVE_HIGH, |
| 137 | 137 | ||
| 138 | /* Audio power control */ | ||
| 139 | GPIO16_GPIO, /* AC97 codec AVDD2 supply (analogue power) */ | ||
| 140 | GPIO40_GPIO, /* Mic amp power */ | ||
| 141 | GPIO41_GPIO, /* Headphone amp power */ | ||
| 142 | |||
| 138 | /* PC Card */ | 143 | /* PC Card */ |
| 139 | GPIO8_GPIO, /* CD0 */ | 144 | GPIO8_GPIO, /* CD0 */ |
| 140 | GPIO44_GPIO, /* CD1 */ | 145 | GPIO44_GPIO, /* CD1 */ |
diff --git a/arch/arm/mach-pxa/e750.c b/arch/arm/mach-pxa/e750.c index be1ab8edb973..665066fd280e 100644 --- a/arch/arm/mach-pxa/e750.c +++ b/arch/arm/mach-pxa/e750.c | |||
| @@ -133,6 +133,11 @@ static unsigned long e750_pin_config[] __initdata = { | |||
| 133 | /* IrDA */ | 133 | /* IrDA */ |
| 134 | GPIO38_GPIO | MFP_LPM_DRIVE_HIGH, | 134 | GPIO38_GPIO | MFP_LPM_DRIVE_HIGH, |
| 135 | 135 | ||
| 136 | /* Audio power control */ | ||
| 137 | GPIO4_GPIO, /* Headphone amp power */ | ||
| 138 | GPIO7_GPIO, /* Speaker amp power */ | ||
| 139 | GPIO37_GPIO, /* Headphone detect */ | ||
| 140 | |||
| 136 | /* PC Card */ | 141 | /* PC Card */ |
| 137 | GPIO8_GPIO, /* CD0 */ | 142 | GPIO8_GPIO, /* CD0 */ |
| 138 | GPIO44_GPIO, /* CD1 */ | 143 | GPIO44_GPIO, /* CD1 */ |
diff --git a/arch/arm/mach-pxa/include/mach/eseries-gpio.h b/arch/arm/mach-pxa/include/mach/eseries-gpio.h index efbd2aa9ecec..f3e5509820d7 100644 --- a/arch/arm/mach-pxa/include/mach/eseries-gpio.h +++ b/arch/arm/mach-pxa/include/mach/eseries-gpio.h | |||
| @@ -45,6 +45,21 @@ | |||
| 45 | /* e7xx IrDA power control */ | 45 | /* e7xx IrDA power control */ |
| 46 | #define GPIO_E7XX_IR_OFF 38 | 46 | #define GPIO_E7XX_IR_OFF 38 |
| 47 | 47 | ||
| 48 | /* e740 audio control GPIOs */ | ||
| 49 | #define GPIO_E740_WM9705_nAVDD2 16 | ||
| 50 | #define GPIO_E740_MIC_ON 40 | ||
| 51 | #define GPIO_E740_AMP_ON 41 | ||
| 52 | |||
| 53 | /* e750 audio control GPIOs */ | ||
| 54 | #define GPIO_E750_HP_AMP_OFF 4 | ||
| 55 | #define GPIO_E750_SPK_AMP_OFF 7 | ||
| 56 | #define GPIO_E750_HP_DETECT 37 | ||
| 57 | |||
| 58 | /* e800 audio control GPIOs */ | ||
| 59 | #define GPIO_E800_HP_DETECT 81 | ||
| 60 | #define GPIO_E800_HP_AMP_OFF 82 | ||
| 61 | #define GPIO_E800_SPK_AMP_ON 83 | ||
| 62 | |||
| 48 | /* ASIC related GPIOs */ | 63 | /* ASIC related GPIOs */ |
| 49 | #define GPIO_ESERIES_TMIO_IRQ 5 | 64 | #define GPIO_ESERIES_TMIO_IRQ 5 |
| 50 | #define GPIO_ESERIES_TMIO_PCLR 19 | 65 | #define GPIO_ESERIES_TMIO_PCLR 19 |
diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h index af95a1d2f3a1..d899dc0223ba 100644 --- a/include/linux/mfd/wm8350/audio.h +++ b/include/linux/mfd/wm8350/audio.h | |||
| @@ -490,6 +490,7 @@ | |||
| 490 | /* | 490 | /* |
| 491 | * R231 (0xE7) - Jack Status | 491 | * R231 (0xE7) - Jack Status |
| 492 | */ | 492 | */ |
| 493 | #define WM8350_JACK_L_LVL 0x0800 | ||
| 493 | #define WM8350_JACK_R_LVL 0x0400 | 494 | #define WM8350_JACK_R_LVL 0x0400 |
| 494 | 495 | ||
| 495 | /* | 496 | /* |
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 93a4edb148b5..0accdba211f9 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
| @@ -76,6 +76,11 @@ | |||
| 76 | wcontrols, wncontrols)\ | 76 | wcontrols, wncontrols)\ |
| 77 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 77 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ |
| 78 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} | 78 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols} |
| 79 | #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ | ||
| 80 | wcontrols, wncontrols)\ | ||
| 81 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ | ||
| 82 | .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \ | ||
| 83 | .num_kcontrols = wncontrols} | ||
| 79 | #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ | 84 | #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ |
| 80 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ | 85 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ |
| 81 | .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0} | 86 | .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0} |
| @@ -101,6 +106,11 @@ | |||
| 101 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 106 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ |
| 102 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ | 107 | .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \ |
| 103 | .event = wevent, .event_flags = wflags} | 108 | .event = wevent, .event_flags = wflags} |
| 109 | #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \ | ||
| 110 | wcontrols, wncontrols, wevent, wflags) \ | ||
| 111 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | ||
| 112 | .invert = winvert, .kcontrols = wcontrols, \ | ||
| 113 | .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags} | ||
| 104 | #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \ | 114 | #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \ |
| 105 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ | 115 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ |
| 106 | .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \ | 116 | .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \ |
| @@ -250,10 +260,10 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, | |||
| 250 | int snd_soc_dapm_sys_add(struct device *dev); | 260 | int snd_soc_dapm_sys_add(struct device *dev); |
| 251 | 261 | ||
| 252 | /* dapm audio pin control and status */ | 262 | /* dapm audio pin control and status */ |
| 253 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin); | 263 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin); |
| 254 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin); | 264 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin); |
| 255 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin); | 265 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin); |
| 256 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin); | 266 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin); |
| 257 | int snd_soc_dapm_sync(struct snd_soc_codec *codec); | 267 | int snd_soc_dapm_sync(struct snd_soc_codec *codec); |
| 258 | 268 | ||
| 259 | /* dapm widget types */ | 269 | /* dapm widget types */ |
| @@ -263,6 +273,7 @@ enum snd_soc_dapm_type { | |||
| 263 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ | 273 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ |
| 264 | snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */ | 274 | snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */ |
| 265 | snd_soc_dapm_mixer, /* mixes several analog signals together */ | 275 | snd_soc_dapm_mixer, /* mixes several analog signals together */ |
| 276 | snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */ | ||
| 266 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ | 277 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ |
| 267 | snd_soc_dapm_adc, /* analog to digital converter */ | 278 | snd_soc_dapm_adc, /* analog to digital converter */ |
| 268 | snd_soc_dapm_dac, /* digital to analog converter */ | 279 | snd_soc_dapm_dac, /* digital to analog converter */ |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 24593ac3ea19..7039343e8a78 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
| @@ -154,6 +154,8 @@ enum snd_soc_bias_level { | |||
| 154 | SND_SOC_BIAS_OFF, | 154 | SND_SOC_BIAS_OFF, |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | struct snd_jack; | ||
| 158 | struct snd_soc_card; | ||
| 157 | struct snd_soc_device; | 159 | struct snd_soc_device; |
| 158 | struct snd_soc_pcm_stream; | 160 | struct snd_soc_pcm_stream; |
| 159 | struct snd_soc_ops; | 161 | struct snd_soc_ops; |
| @@ -164,6 +166,8 @@ struct snd_soc_platform; | |||
| 164 | struct snd_soc_codec; | 166 | struct snd_soc_codec; |
| 165 | struct soc_enum; | 167 | struct soc_enum; |
| 166 | struct snd_soc_ac97_ops; | 168 | struct snd_soc_ac97_ops; |
| 169 | struct snd_soc_jack; | ||
| 170 | struct snd_soc_jack_pin; | ||
| 167 | 171 | ||
| 168 | typedef int (*hw_write_t)(void *,const char* ,int); | 172 | typedef int (*hw_write_t)(void *,const char* ,int); |
| 169 | typedef int (*hw_read_t)(void *,char* ,int); | 173 | typedef int (*hw_read_t)(void *,char* ,int); |
| @@ -184,6 +188,13 @@ int snd_soc_init_card(struct snd_soc_device *socdev); | |||
| 184 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, | 188 | int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, |
| 185 | const struct snd_pcm_hardware *hw); | 189 | const struct snd_pcm_hardware *hw); |
| 186 | 190 | ||
| 191 | /* Jack reporting */ | ||
| 192 | int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type, | ||
| 193 | struct snd_soc_jack *jack); | ||
| 194 | void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask); | ||
| 195 | int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, | ||
| 196 | struct snd_soc_jack_pin *pins); | ||
| 197 | |||
| 187 | /* codec IO */ | 198 | /* codec IO */ |
| 188 | #define snd_soc_read(codec, reg) codec->read(codec, reg) | 199 | #define snd_soc_read(codec, reg) codec->read(codec, reg) |
| 189 | #define snd_soc_write(codec, reg, value) codec->write(codec, reg, value) | 200 | #define snd_soc_write(codec, reg, value) codec->write(codec, reg, value) |
| @@ -203,6 +214,8 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); | |||
| 203 | */ | 214 | */ |
| 204 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | 215 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, |
| 205 | void *data, char *long_name); | 216 | void *data, char *long_name); |
| 217 | int snd_soc_add_controls(struct snd_soc_codec *codec, | ||
| 218 | const struct snd_kcontrol_new *controls, int num_controls); | ||
| 206 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | 219 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, |
| 207 | struct snd_ctl_elem_info *uinfo); | 220 | struct snd_ctl_elem_info *uinfo); |
| 208 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | 221 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, |
| @@ -237,6 +250,27 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | |||
| 237 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | 250 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, |
| 238 | struct snd_ctl_elem_value *ucontrol); | 251 | struct snd_ctl_elem_value *ucontrol); |
| 239 | 252 | ||
| 253 | /** | ||
| 254 | * struct snd_soc_jack_pin - Describes a pin to update based on jack detection | ||
| 255 | * | ||
| 256 | * @pin: name of the pin to update | ||
| 257 | * @mask: bits to check for in reported jack status | ||
| 258 | * @invert: if non-zero then pin is enabled when status is not reported | ||
| 259 | */ | ||
| 260 | struct snd_soc_jack_pin { | ||
| 261 | struct list_head list; | ||
| 262 | const char *pin; | ||
| 263 | int mask; | ||
| 264 | bool invert; | ||
| 265 | }; | ||
| 266 | |||
| 267 | struct snd_soc_jack { | ||
| 268 | struct snd_jack *jack; | ||
| 269 | struct snd_soc_card *card; | ||
| 270 | struct list_head pins; | ||
| 271 | int status; | ||
| 272 | }; | ||
| 273 | |||
| 240 | /* SoC PCM stream information */ | 274 | /* SoC PCM stream information */ |
| 241 | struct snd_soc_pcm_stream { | 275 | struct snd_soc_pcm_stream { |
| 242 | char *stream_name; | 276 | char *stream_name; |
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); | ||
