Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: Add initial driver for the WM8400 CODEC

The WM8400 is a highly integrated audio CODEC and power management unit
intended for mobile multimedia application. This driver supports the
primary audio CODEC features, including:

- 1W speaker driver
- Fully differential headphone output
- Up to 4 differential microphone inputs

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

+1548
+1
include/linux/mfd/wm8400-audio.h
··· 1181 1181 #define WM8400_FLL_OUTDIV_SHIFT 0 /* FLL_OUTDIV - [2:0] */ 1182 1182 #define WM8400_FLL_OUTDIV_WIDTH 3 /* FLL_OUTDIV - [2:0] */ 1183 1183 1184 + struct wm8400; 1184 1185 void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400); 1185 1186 1186 1187 #endif
+4
sound/soc/codecs/Kconfig
··· 26 26 select SND_SOC_UDA134X 27 27 select SND_SOC_UDA1380 if I2C 28 28 select SND_SOC_WM8350 if MFD_WM8350 29 + select SND_SOC_WM8400 if MFD_WM8400 29 30 select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI 30 31 select SND_SOC_WM8580 if I2C 31 32 select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI ··· 109 108 tristate 110 109 111 110 config SND_SOC_WM8350 111 + tristate 112 + 113 + config SND_SOC_WM8400 112 114 tristate 113 115 114 116 config SND_SOC_WM8510
+2
sound/soc/codecs/Makefile
··· 14 14 snd-soc-uda134x-objs := uda134x.o 15 15 snd-soc-uda1380-objs := uda1380.o 16 16 snd-soc-wm8350-objs := wm8350.o 17 + snd-soc-wm8400-objs := wm8400.o 17 18 snd-soc-wm8510-objs := wm8510.o 18 19 snd-soc-wm8580-objs := wm8580.o 19 20 snd-soc-wm8728-objs := wm8728.o ··· 45 44 obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o 46 45 obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o 47 46 obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o 47 + obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o 48 48 obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o 49 49 obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o 50 50 obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
+1479
sound/soc/codecs/wm8400.c
··· 1 + /* 2 + * wm8400.c -- WM8400 ALSA Soc Audio driver 3 + * 4 + * Copyright 2008, 2009 Wolfson Microelectronics PLC. 5 + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License as published by the 9 + * Free Software Foundation; either version 2 of the License, or (at your 10 + * option) any later version. 11 + * 12 + */ 13 + 14 + #include <linux/module.h> 15 + #include <linux/moduleparam.h> 16 + #include <linux/kernel.h> 17 + #include <linux/init.h> 18 + #include <linux/delay.h> 19 + #include <linux/pm.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/regulator/consumer.h> 22 + #include <linux/mfd/wm8400-audio.h> 23 + #include <linux/mfd/wm8400-private.h> 24 + #include <sound/core.h> 25 + #include <sound/pcm.h> 26 + #include <sound/pcm_params.h> 27 + #include <sound/soc.h> 28 + #include <sound/soc-dapm.h> 29 + #include <sound/initval.h> 30 + #include <sound/tlv.h> 31 + 32 + #include "wm8400.h" 33 + 34 + /* Fake register for internal state */ 35 + #define WM8400_INTDRIVBITS (WM8400_REGISTER_COUNT + 1) 36 + #define WM8400_INMIXL_PWR 0 37 + #define WM8400_AINLMUX_PWR 1 38 + #define WM8400_INMIXR_PWR 2 39 + #define WM8400_AINRMUX_PWR 3 40 + 41 + static struct regulator_bulk_data power[] = { 42 + { 43 + .supply = "I2S1VDD", 44 + }, 45 + { 46 + .supply = "I2S2VDD", 47 + }, 48 + { 49 + .supply = "DCVDD", 50 + }, 51 + { 52 + .supply = "FLLVDD", 53 + }, 54 + { 55 + .supply = "HPVDD", 56 + }, 57 + { 58 + .supply = "SPKVDD", 59 + }, 60 + }; 61 + 62 + /* codec private data */ 63 + struct wm8400_priv { 64 + struct snd_soc_codec codec; 65 + struct wm8400 *wm8400; 66 + u16 fake_register; 67 + unsigned int sysclk; 68 + unsigned int pcmclk; 69 + struct work_struct work; 70 + }; 71 + 72 + static inline unsigned int wm8400_read(struct snd_soc_codec *codec, 73 + unsigned int reg) 74 + { 75 + struct wm8400_priv *wm8400 = codec->private_data; 76 + 77 + if (reg == WM8400_INTDRIVBITS) 78 + return wm8400->fake_register; 79 + else 80 + return wm8400_reg_read(wm8400->wm8400, reg); 81 + } 82 + 83 + /* 84 + * write to the wm8400 register space 85 + */ 86 + static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg, 87 + unsigned int value) 88 + { 89 + struct wm8400_priv *wm8400 = codec->private_data; 90 + 91 + if (reg == WM8400_INTDRIVBITS) { 92 + wm8400->fake_register = value; 93 + return 0; 94 + } else 95 + return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value); 96 + } 97 + 98 + static void wm8400_codec_reset(struct snd_soc_codec *codec) 99 + { 100 + struct wm8400_priv *wm8400 = codec->private_data; 101 + 102 + wm8400_reset_codec_reg_cache(wm8400->wm8400); 103 + } 104 + 105 + static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); 106 + 107 + static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); 108 + 109 + static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, -2100, 0); 110 + 111 + static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); 112 + 113 + static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); 114 + 115 + static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); 116 + 117 + static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); 118 + 119 + static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); 120 + 121 + static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, 122 + struct snd_ctl_elem_value *ucontrol) 123 + { 124 + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 125 + struct soc_mixer_control *mc = 126 + (struct soc_mixer_control *)kcontrol->private_value; 127 + int reg = mc->reg; 128 + int ret; 129 + u16 val; 130 + 131 + ret = snd_soc_put_volsw(kcontrol, ucontrol); 132 + if (ret < 0) 133 + return ret; 134 + 135 + /* now hit the volume update bits (always bit 8) */ 136 + val = wm8400_read(codec, reg); 137 + return wm8400_write(codec, reg, val | 0x0100); 138 + } 139 + 140 + #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \ 141 + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ 142 + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ 143 + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ 144 + .tlv.p = (tlv_array), \ 145 + .info = snd_soc_info_volsw, \ 146 + .get = snd_soc_get_volsw, .put = wm8400_outpga_put_volsw_vu, \ 147 + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } 148 + 149 + 150 + static const char *wm8400_digital_sidetone[] = 151 + {"None", "Left ADC", "Right ADC", "Reserved"}; 152 + 153 + static const struct soc_enum wm8400_left_digital_sidetone_enum = 154 + SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, 155 + WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone); 156 + 157 + static const struct soc_enum wm8400_right_digital_sidetone_enum = 158 + SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, 159 + WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone); 160 + 161 + static const char *wm8400_adcmode[] = 162 + {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; 163 + 164 + static const struct soc_enum wm8400_right_adcmode_enum = 165 + SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode); 166 + 167 + static const struct snd_kcontrol_new wm8400_snd_controls[] = { 168 + /* INMIXL */ 169 + SOC_SINGLE("LIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L12MNBST_SHIFT, 170 + 1, 0), 171 + SOC_SINGLE("LIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L34MNBST_SHIFT, 172 + 1, 0), 173 + /* INMIXR */ 174 + SOC_SINGLE("RIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R12MNBST_SHIFT, 175 + 1, 0), 176 + SOC_SINGLE("RIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R34MNBST_SHIFT, 177 + 1, 0), 178 + 179 + /* LOMIX */ 180 + SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER3, 181 + WM8400_LLI3LOVOL_SHIFT, 7, 0, out_mix_tlv), 182 + SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3, 183 + WM8400_LR12LOVOL_SHIFT, 7, 0, out_mix_tlv), 184 + SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3, 185 + WM8400_LL12LOVOL_SHIFT, 7, 0, out_mix_tlv), 186 + SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER5, 187 + WM8400_LRI3LOVOL_SHIFT, 7, 0, out_mix_tlv), 188 + SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER5, 189 + WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv), 190 + SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER5, 191 + WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv), 192 + 193 + /* ROMIX */ 194 + SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER4, 195 + WM8400_RRI3ROVOL_SHIFT, 7, 0, out_mix_tlv), 196 + SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4, 197 + WM8400_RL12ROVOL_SHIFT, 7, 0, out_mix_tlv), 198 + SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4, 199 + WM8400_RR12ROVOL_SHIFT, 7, 0, out_mix_tlv), 200 + SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER6, 201 + WM8400_RLI3ROVOL_SHIFT, 7, 0, out_mix_tlv), 202 + SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER6, 203 + WM8400_RLBROVOL_SHIFT, 7, 0, out_mix_tlv), 204 + SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER6, 205 + WM8400_RRBROVOL_SHIFT, 7, 0, out_mix_tlv), 206 + 207 + /* LOUT */ 208 + WM8400_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8400_LEFT_OUTPUT_VOLUME, 209 + WM8400_LOUTVOL_SHIFT, WM8400_LOUTVOL_MASK, 0, out_pga_tlv), 210 + SOC_SINGLE("LOUT ZC", WM8400_LEFT_OUTPUT_VOLUME, WM8400_LOZC_SHIFT, 1, 0), 211 + 212 + /* ROUT */ 213 + WM8400_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8400_RIGHT_OUTPUT_VOLUME, 214 + WM8400_ROUTVOL_SHIFT, WM8400_ROUTVOL_MASK, 0, out_pga_tlv), 215 + SOC_SINGLE("ROUT ZC", WM8400_RIGHT_OUTPUT_VOLUME, WM8400_ROZC_SHIFT, 1, 0), 216 + 217 + /* LOPGA */ 218 + WM8400_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8400_LEFT_OPGA_VOLUME, 219 + WM8400_LOPGAVOL_SHIFT, WM8400_LOPGAVOL_MASK, 0, out_pga_tlv), 220 + SOC_SINGLE("LOPGA ZC Switch", WM8400_LEFT_OPGA_VOLUME, 221 + WM8400_LOPGAZC_SHIFT, 1, 0), 222 + 223 + /* ROPGA */ 224 + WM8400_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8400_RIGHT_OPGA_VOLUME, 225 + WM8400_ROPGAVOL_SHIFT, WM8400_ROPGAVOL_MASK, 0, out_pga_tlv), 226 + SOC_SINGLE("ROPGA ZC Switch", WM8400_RIGHT_OPGA_VOLUME, 227 + WM8400_ROPGAZC_SHIFT, 1, 0), 228 + 229 + SOC_SINGLE("LON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME, 230 + WM8400_LONMUTE_SHIFT, 1, 0), 231 + SOC_SINGLE("LOP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME, 232 + WM8400_LOPMUTE_SHIFT, 1, 0), 233 + SOC_SINGLE("LOP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME, 234 + WM8400_LOATTN_SHIFT, 1, 0), 235 + SOC_SINGLE("RON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME, 236 + WM8400_RONMUTE_SHIFT, 1, 0), 237 + SOC_SINGLE("ROP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME, 238 + WM8400_ROPMUTE_SHIFT, 1, 0), 239 + SOC_SINGLE("ROP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME, 240 + WM8400_ROATTN_SHIFT, 1, 0), 241 + 242 + SOC_SINGLE("OUT3 Mute Switch", WM8400_OUT3_4_VOLUME, 243 + WM8400_OUT3MUTE_SHIFT, 1, 0), 244 + SOC_SINGLE("OUT3 Attenuation Switch", WM8400_OUT3_4_VOLUME, 245 + WM8400_OUT3ATTN_SHIFT, 1, 0), 246 + 247 + SOC_SINGLE("OUT4 Mute Switch", WM8400_OUT3_4_VOLUME, 248 + WM8400_OUT4MUTE_SHIFT, 1, 0), 249 + SOC_SINGLE("OUT4 Attenuation Switch", WM8400_OUT3_4_VOLUME, 250 + WM8400_OUT4ATTN_SHIFT, 1, 0), 251 + 252 + SOC_SINGLE("Speaker Mode Switch", WM8400_CLASSD1, 253 + WM8400_CDMODE_SHIFT, 1, 0), 254 + 255 + SOC_SINGLE("Speaker Output Attenuation Volume", WM8400_SPEAKER_VOLUME, 256 + WM8400_SPKATTN_SHIFT, WM8400_SPKATTN_MASK, 0), 257 + SOC_SINGLE("Speaker DC Boost Volume", WM8400_CLASSD3, 258 + WM8400_DCGAIN_SHIFT, 6, 0), 259 + SOC_SINGLE("Speaker AC Boost Volume", WM8400_CLASSD3, 260 + WM8400_ACGAIN_SHIFT, 6, 0), 261 + 262 + WM8400_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", 263 + WM8400_LEFT_DAC_DIGITAL_VOLUME, WM8400_DACL_VOL_SHIFT, 264 + 127, 0, out_dac_tlv), 265 + 266 + WM8400_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", 267 + WM8400_RIGHT_DAC_DIGITAL_VOLUME, WM8400_DACR_VOL_SHIFT, 268 + 127, 0, out_dac_tlv), 269 + 270 + SOC_ENUM("Left Digital Sidetone", wm8400_left_digital_sidetone_enum), 271 + SOC_ENUM("Right Digital Sidetone", wm8400_right_digital_sidetone_enum), 272 + 273 + SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE, 274 + WM8400_ADCL_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv), 275 + SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE, 276 + WM8400_ADCR_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv), 277 + 278 + SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8400_ADC_CTRL, 279 + WM8400_ADC_HPF_ENA_SHIFT, 1, 0), 280 + 281 + SOC_ENUM("ADC HPF Mode", wm8400_right_adcmode_enum), 282 + 283 + WM8400_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", 284 + WM8400_LEFT_ADC_DIGITAL_VOLUME, 285 + WM8400_ADCL_VOL_SHIFT, 286 + WM8400_ADCL_VOL_MASK, 287 + 0, 288 + in_adc_tlv), 289 + 290 + WM8400_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", 291 + WM8400_RIGHT_ADC_DIGITAL_VOLUME, 292 + WM8400_ADCR_VOL_SHIFT, 293 + WM8400_ADCR_VOL_MASK, 294 + 0, 295 + in_adc_tlv), 296 + 297 + WM8400_OUTPGA_SINGLE_R_TLV("LIN12 Volume", 298 + WM8400_LEFT_LINE_INPUT_1_2_VOLUME, 299 + WM8400_LIN12VOL_SHIFT, 300 + WM8400_LIN12VOL_MASK, 301 + 0, 302 + in_pga_tlv), 303 + 304 + SOC_SINGLE("LIN12 ZC Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME, 305 + WM8400_LI12ZC_SHIFT, 1, 0), 306 + 307 + SOC_SINGLE("LIN12 Mute Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME, 308 + WM8400_LI12MUTE_SHIFT, 1, 0), 309 + 310 + WM8400_OUTPGA_SINGLE_R_TLV("LIN34 Volume", 311 + WM8400_LEFT_LINE_INPUT_3_4_VOLUME, 312 + WM8400_LIN34VOL_SHIFT, 313 + WM8400_LIN34VOL_MASK, 314 + 0, 315 + in_pga_tlv), 316 + 317 + SOC_SINGLE("LIN34 ZC Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME, 318 + WM8400_LI34ZC_SHIFT, 1, 0), 319 + 320 + SOC_SINGLE("LIN34 Mute Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME, 321 + WM8400_LI34MUTE_SHIFT, 1, 0), 322 + 323 + WM8400_OUTPGA_SINGLE_R_TLV("RIN12 Volume", 324 + WM8400_RIGHT_LINE_INPUT_1_2_VOLUME, 325 + WM8400_RIN12VOL_SHIFT, 326 + WM8400_RIN12VOL_MASK, 327 + 0, 328 + in_pga_tlv), 329 + 330 + SOC_SINGLE("RIN12 ZC Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME, 331 + WM8400_RI12ZC_SHIFT, 1, 0), 332 + 333 + SOC_SINGLE("RIN12 Mute Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME, 334 + WM8400_RI12MUTE_SHIFT, 1, 0), 335 + 336 + WM8400_OUTPGA_SINGLE_R_TLV("RIN34 Volume", 337 + WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, 338 + WM8400_RIN34VOL_SHIFT, 339 + WM8400_RIN34VOL_MASK, 340 + 0, 341 + in_pga_tlv), 342 + 343 + SOC_SINGLE("RIN34 ZC Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, 344 + WM8400_RI34ZC_SHIFT, 1, 0), 345 + 346 + SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, 347 + WM8400_RI34MUTE_SHIFT, 1, 0), 348 + 349 + }; 350 + 351 + /* add non dapm controls */ 352 + static int wm8400_add_controls(struct snd_soc_codec *codec) 353 + { 354 + int err, i; 355 + 356 + for (i = 0; i < ARRAY_SIZE(wm8400_snd_controls); i++) { 357 + err = snd_ctl_add(codec->card, 358 + snd_soc_cnew(&wm8400_snd_controls[i],codec, 359 + NULL)); 360 + if (err < 0) 361 + return err; 362 + } 363 + return 0; 364 + } 365 + 366 + /* 367 + * _DAPM_ Controls 368 + */ 369 + 370 + static int inmixer_event (struct snd_soc_dapm_widget *w, 371 + struct snd_kcontrol *kcontrol, int event) 372 + { 373 + u16 reg, fakepower; 374 + 375 + reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2); 376 + fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS); 377 + 378 + if (fakepower & ((1 << WM8400_INMIXL_PWR) | 379 + (1 << WM8400_AINLMUX_PWR))) { 380 + reg |= WM8400_AINL_ENA; 381 + } else { 382 + reg &= ~WM8400_AINL_ENA; 383 + } 384 + 385 + if (fakepower & ((1 << WM8400_INMIXR_PWR) | 386 + (1 << WM8400_AINRMUX_PWR))) { 387 + reg |= WM8400_AINR_ENA; 388 + } else { 389 + reg &= ~WM8400_AINL_ENA; 390 + } 391 + wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg); 392 + 393 + return 0; 394 + } 395 + 396 + static int outmixer_event (struct snd_soc_dapm_widget *w, 397 + struct snd_kcontrol * kcontrol, int event) 398 + { 399 + struct soc_mixer_control *mc = 400 + (struct soc_mixer_control *)kcontrol->private_value; 401 + u32 reg_shift = mc->shift; 402 + int ret = 0; 403 + u16 reg; 404 + 405 + switch (reg_shift) { 406 + case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) : 407 + reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1); 408 + if (reg & WM8400_LDLO) { 409 + printk(KERN_WARNING 410 + "Cannot set as Output Mixer 1 LDLO Set\n"); 411 + ret = -1; 412 + } 413 + break; 414 + case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8): 415 + reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2); 416 + if (reg & WM8400_RDRO) { 417 + printk(KERN_WARNING 418 + "Cannot set as Output Mixer 2 RDRO Set\n"); 419 + ret = -1; 420 + } 421 + break; 422 + case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8): 423 + reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER); 424 + if (reg & WM8400_LDSPK) { 425 + printk(KERN_WARNING 426 + "Cannot set as Speaker Mixer LDSPK Set\n"); 427 + ret = -1; 428 + } 429 + break; 430 + case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8): 431 + reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER); 432 + if (reg & WM8400_RDSPK) { 433 + printk(KERN_WARNING 434 + "Cannot set as Speaker Mixer RDSPK Set\n"); 435 + ret = -1; 436 + } 437 + break; 438 + } 439 + 440 + return ret; 441 + } 442 + 443 + /* INMIX dB values */ 444 + static const unsigned int in_mix_tlv[] = { 445 + TLV_DB_RANGE_HEAD(1), 446 + 0,7, TLV_DB_LINEAR_ITEM(-1200, 600), 447 + }; 448 + 449 + /* Left In PGA Connections */ 450 + static const struct snd_kcontrol_new wm8400_dapm_lin12_pga_controls[] = { 451 + SOC_DAPM_SINGLE("LIN1 Switch", WM8400_INPUT_MIXER2, WM8400_LMN1_SHIFT, 1, 0), 452 + SOC_DAPM_SINGLE("LIN2 Switch", WM8400_INPUT_MIXER2, WM8400_LMP2_SHIFT, 1, 0), 453 + }; 454 + 455 + static const struct snd_kcontrol_new wm8400_dapm_lin34_pga_controls[] = { 456 + SOC_DAPM_SINGLE("LIN3 Switch", WM8400_INPUT_MIXER2, WM8400_LMN3_SHIFT, 1, 0), 457 + SOC_DAPM_SINGLE("LIN4 Switch", WM8400_INPUT_MIXER2, WM8400_LMP4_SHIFT, 1, 0), 458 + }; 459 + 460 + /* Right In PGA Connections */ 461 + static const struct snd_kcontrol_new wm8400_dapm_rin12_pga_controls[] = { 462 + SOC_DAPM_SINGLE("RIN1 Switch", WM8400_INPUT_MIXER2, WM8400_RMN1_SHIFT, 1, 0), 463 + SOC_DAPM_SINGLE("RIN2 Switch", WM8400_INPUT_MIXER2, WM8400_RMP2_SHIFT, 1, 0), 464 + }; 465 + 466 + static const struct snd_kcontrol_new wm8400_dapm_rin34_pga_controls[] = { 467 + SOC_DAPM_SINGLE("RIN3 Switch", WM8400_INPUT_MIXER2, WM8400_RMN3_SHIFT, 1, 0), 468 + SOC_DAPM_SINGLE("RIN4 Switch", WM8400_INPUT_MIXER2, WM8400_RMP4_SHIFT, 1, 0), 469 + }; 470 + 471 + /* INMIXL */ 472 + static const struct snd_kcontrol_new wm8400_dapm_inmixl_controls[] = { 473 + SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8400_INPUT_MIXER3, 474 + WM8400_LDBVOL_SHIFT, WM8400_LDBVOL_MASK, 0, in_mix_tlv), 475 + SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8400_INPUT_MIXER5, WM8400_LI2BVOL_SHIFT, 476 + 7, 0, in_mix_tlv), 477 + SOC_DAPM_SINGLE("LINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT, 478 + 1, 0), 479 + SOC_DAPM_SINGLE("LINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT, 480 + 1, 0), 481 + }; 482 + 483 + /* INMIXR */ 484 + static const struct snd_kcontrol_new wm8400_dapm_inmixr_controls[] = { 485 + SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8400_INPUT_MIXER4, 486 + WM8400_RDBVOL_SHIFT, WM8400_RDBVOL_MASK, 0, in_mix_tlv), 487 + SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8400_INPUT_MIXER6, WM8400_RI2BVOL_SHIFT, 488 + 7, 0, in_mix_tlv), 489 + SOC_DAPM_SINGLE("RINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT, 490 + 1, 0), 491 + SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT, 492 + 1, 0), 493 + }; 494 + 495 + /* AINLMUX */ 496 + static const char *wm8400_ainlmux[] = 497 + {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; 498 + 499 + static const struct soc_enum wm8400_ainlmux_enum = 500 + SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT, 501 + ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux); 502 + 503 + static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls = 504 + SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); 505 + 506 + /* DIFFINL */ 507 + 508 + /* AINRMUX */ 509 + static const char *wm8400_ainrmux[] = 510 + {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; 511 + 512 + static const struct soc_enum wm8400_ainrmux_enum = 513 + SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT, 514 + ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux); 515 + 516 + static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls = 517 + SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum); 518 + 519 + /* RXVOICE */ 520 + static const struct snd_kcontrol_new wm8400_dapm_rxvoice_controls[] = { 521 + SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8400_INPUT_MIXER5, WM8400_LR4BVOL_SHIFT, 522 + WM8400_LR4BVOL_MASK, 0, in_mix_tlv), 523 + SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8400_INPUT_MIXER6, WM8400_RL4BVOL_SHIFT, 524 + WM8400_RL4BVOL_MASK, 0, in_mix_tlv), 525 + }; 526 + 527 + /* LOMIX */ 528 + static const struct snd_kcontrol_new wm8400_dapm_lomix_controls[] = { 529 + SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER1, 530 + WM8400_LRBLO_SHIFT, 1, 0), 531 + SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER1, 532 + WM8400_LLBLO_SHIFT, 1, 0), 533 + SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER1, 534 + WM8400_LRI3LO_SHIFT, 1, 0), 535 + SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER1, 536 + WM8400_LLI3LO_SHIFT, 1, 0), 537 + SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1, 538 + WM8400_LR12LO_SHIFT, 1, 0), 539 + SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1, 540 + WM8400_LL12LO_SHIFT, 1, 0), 541 + SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8400_OUTPUT_MIXER1, 542 + WM8400_LDLO_SHIFT, 1, 0), 543 + }; 544 + 545 + /* ROMIX */ 546 + static const struct snd_kcontrol_new wm8400_dapm_romix_controls[] = { 547 + SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER2, 548 + WM8400_RLBRO_SHIFT, 1, 0), 549 + SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER2, 550 + WM8400_RRBRO_SHIFT, 1, 0), 551 + SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER2, 552 + WM8400_RLI3RO_SHIFT, 1, 0), 553 + SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER2, 554 + WM8400_RRI3RO_SHIFT, 1, 0), 555 + SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2, 556 + WM8400_RL12RO_SHIFT, 1, 0), 557 + SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2, 558 + WM8400_RR12RO_SHIFT, 1, 0), 559 + SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8400_OUTPUT_MIXER2, 560 + WM8400_RDRO_SHIFT, 1, 0), 561 + }; 562 + 563 + /* LONMIX */ 564 + static const struct snd_kcontrol_new wm8400_dapm_lonmix_controls[] = { 565 + SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1, 566 + WM8400_LLOPGALON_SHIFT, 1, 0), 567 + SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER1, 568 + WM8400_LROPGALON_SHIFT, 1, 0), 569 + SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8400_LINE_MIXER1, 570 + WM8400_LOPLON_SHIFT, 1, 0), 571 + }; 572 + 573 + /* LOPMIX */ 574 + static const struct snd_kcontrol_new wm8400_dapm_lopmix_controls[] = { 575 + SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER1, 576 + WM8400_LR12LOP_SHIFT, 1, 0), 577 + SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER1, 578 + WM8400_LL12LOP_SHIFT, 1, 0), 579 + SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1, 580 + WM8400_LLOPGALOP_SHIFT, 1, 0), 581 + }; 582 + 583 + /* RONMIX */ 584 + static const struct snd_kcontrol_new wm8400_dapm_ronmix_controls[] = { 585 + SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2, 586 + WM8400_RROPGARON_SHIFT, 1, 0), 587 + SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER2, 588 + WM8400_RLOPGARON_SHIFT, 1, 0), 589 + SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8400_LINE_MIXER2, 590 + WM8400_ROPRON_SHIFT, 1, 0), 591 + }; 592 + 593 + /* ROPMIX */ 594 + static const struct snd_kcontrol_new wm8400_dapm_ropmix_controls[] = { 595 + SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER2, 596 + WM8400_RL12ROP_SHIFT, 1, 0), 597 + SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER2, 598 + WM8400_RR12ROP_SHIFT, 1, 0), 599 + SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2, 600 + WM8400_RROPGAROP_SHIFT, 1, 0), 601 + }; 602 + 603 + /* OUT3MIX */ 604 + static const struct snd_kcontrol_new wm8400_dapm_out3mix_controls[] = { 605 + SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER, 606 + WM8400_LI4O3_SHIFT, 1, 0), 607 + SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8400_OUT3_4_MIXER, 608 + WM8400_LPGAO3_SHIFT, 1, 0), 609 + }; 610 + 611 + /* OUT4MIX */ 612 + static const struct snd_kcontrol_new wm8400_dapm_out4mix_controls[] = { 613 + SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8400_OUT3_4_MIXER, 614 + WM8400_RPGAO4_SHIFT, 1, 0), 615 + SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER, 616 + WM8400_RI4O4_SHIFT, 1, 0), 617 + }; 618 + 619 + /* SPKMIX */ 620 + static const struct snd_kcontrol_new wm8400_dapm_spkmix_controls[] = { 621 + SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8400_SPEAKER_MIXER, 622 + WM8400_LI2SPK_SHIFT, 1, 0), 623 + SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8400_SPEAKER_MIXER, 624 + WM8400_LB2SPK_SHIFT, 1, 0), 625 + SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8400_SPEAKER_MIXER, 626 + WM8400_LOPGASPK_SHIFT, 1, 0), 627 + SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8400_SPEAKER_MIXER, 628 + WM8400_LDSPK_SHIFT, 1, 0), 629 + SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8400_SPEAKER_MIXER, 630 + WM8400_RDSPK_SHIFT, 1, 0), 631 + SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8400_SPEAKER_MIXER, 632 + WM8400_ROPGASPK_SHIFT, 1, 0), 633 + SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8400_SPEAKER_MIXER, 634 + WM8400_RL12ROP_SHIFT, 1, 0), 635 + SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8400_SPEAKER_MIXER, 636 + WM8400_RI2SPK_SHIFT, 1, 0), 637 + }; 638 + 639 + static const struct snd_soc_dapm_widget wm8400_dapm_widgets[] = { 640 + /* Input Side */ 641 + /* Input Lines */ 642 + SND_SOC_DAPM_INPUT("LIN1"), 643 + SND_SOC_DAPM_INPUT("LIN2"), 644 + SND_SOC_DAPM_INPUT("LIN3"), 645 + SND_SOC_DAPM_INPUT("LIN4/RXN"), 646 + SND_SOC_DAPM_INPUT("RIN3"), 647 + SND_SOC_DAPM_INPUT("RIN4/RXP"), 648 + SND_SOC_DAPM_INPUT("RIN1"), 649 + SND_SOC_DAPM_INPUT("RIN2"), 650 + SND_SOC_DAPM_INPUT("Internal ADC Source"), 651 + 652 + /* DACs */ 653 + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8400_POWER_MANAGEMENT_2, 654 + WM8400_ADCL_ENA_SHIFT, 0), 655 + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8400_POWER_MANAGEMENT_2, 656 + WM8400_ADCR_ENA_SHIFT, 0), 657 + 658 + /* Input PGAs */ 659 + SND_SOC_DAPM_MIXER("LIN12 PGA", WM8400_POWER_MANAGEMENT_2, 660 + WM8400_LIN12_ENA_SHIFT, 661 + 0, &wm8400_dapm_lin12_pga_controls[0], 662 + ARRAY_SIZE(wm8400_dapm_lin12_pga_controls)), 663 + SND_SOC_DAPM_MIXER("LIN34 PGA", WM8400_POWER_MANAGEMENT_2, 664 + WM8400_LIN34_ENA_SHIFT, 665 + 0, &wm8400_dapm_lin34_pga_controls[0], 666 + ARRAY_SIZE(wm8400_dapm_lin34_pga_controls)), 667 + SND_SOC_DAPM_MIXER("RIN12 PGA", WM8400_POWER_MANAGEMENT_2, 668 + WM8400_RIN12_ENA_SHIFT, 669 + 0, &wm8400_dapm_rin12_pga_controls[0], 670 + ARRAY_SIZE(wm8400_dapm_rin12_pga_controls)), 671 + SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2, 672 + WM8400_RIN34_ENA_SHIFT, 673 + 0, &wm8400_dapm_rin34_pga_controls[0], 674 + ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)), 675 + 676 + /* INMIXL */ 677 + SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0, 678 + &wm8400_dapm_inmixl_controls[0], 679 + ARRAY_SIZE(wm8400_dapm_inmixl_controls), 680 + inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 681 + 682 + /* AINLMUX */ 683 + SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0, 684 + &wm8400_dapm_ainlmux_controls, inmixer_event, 685 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 686 + 687 + /* INMIXR */ 688 + SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0, 689 + &wm8400_dapm_inmixr_controls[0], 690 + ARRAY_SIZE(wm8400_dapm_inmixr_controls), 691 + inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 692 + 693 + /* AINRMUX */ 694 + SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0, 695 + &wm8400_dapm_ainrmux_controls, inmixer_event, 696 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 697 + 698 + /* Output Side */ 699 + /* DACs */ 700 + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8400_POWER_MANAGEMENT_3, 701 + WM8400_DACL_ENA_SHIFT, 0), 702 + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8400_POWER_MANAGEMENT_3, 703 + WM8400_DACR_ENA_SHIFT, 0), 704 + 705 + /* LOMIX */ 706 + SND_SOC_DAPM_MIXER_E("LOMIX", WM8400_POWER_MANAGEMENT_3, 707 + WM8400_LOMIX_ENA_SHIFT, 708 + 0, &wm8400_dapm_lomix_controls[0], 709 + ARRAY_SIZE(wm8400_dapm_lomix_controls), 710 + outmixer_event, SND_SOC_DAPM_PRE_REG), 711 + 712 + /* LONMIX */ 713 + SND_SOC_DAPM_MIXER("LONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LON_ENA_SHIFT, 714 + 0, &wm8400_dapm_lonmix_controls[0], 715 + ARRAY_SIZE(wm8400_dapm_lonmix_controls)), 716 + 717 + /* LOPMIX */ 718 + SND_SOC_DAPM_MIXER("LOPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LOP_ENA_SHIFT, 719 + 0, &wm8400_dapm_lopmix_controls[0], 720 + ARRAY_SIZE(wm8400_dapm_lopmix_controls)), 721 + 722 + /* OUT3MIX */ 723 + SND_SOC_DAPM_MIXER("OUT3MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT3_ENA_SHIFT, 724 + 0, &wm8400_dapm_out3mix_controls[0], 725 + ARRAY_SIZE(wm8400_dapm_out3mix_controls)), 726 + 727 + /* SPKMIX */ 728 + SND_SOC_DAPM_MIXER_E("SPKMIX", WM8400_POWER_MANAGEMENT_1, WM8400_SPK_ENA_SHIFT, 729 + 0, &wm8400_dapm_spkmix_controls[0], 730 + ARRAY_SIZE(wm8400_dapm_spkmix_controls), outmixer_event, 731 + SND_SOC_DAPM_PRE_REG), 732 + 733 + /* OUT4MIX */ 734 + SND_SOC_DAPM_MIXER("OUT4MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT4_ENA_SHIFT, 735 + 0, &wm8400_dapm_out4mix_controls[0], 736 + ARRAY_SIZE(wm8400_dapm_out4mix_controls)), 737 + 738 + /* ROPMIX */ 739 + SND_SOC_DAPM_MIXER("ROPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_ROP_ENA_SHIFT, 740 + 0, &wm8400_dapm_ropmix_controls[0], 741 + ARRAY_SIZE(wm8400_dapm_ropmix_controls)), 742 + 743 + /* RONMIX */ 744 + SND_SOC_DAPM_MIXER("RONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_RON_ENA_SHIFT, 745 + 0, &wm8400_dapm_ronmix_controls[0], 746 + ARRAY_SIZE(wm8400_dapm_ronmix_controls)), 747 + 748 + /* ROMIX */ 749 + SND_SOC_DAPM_MIXER_E("ROMIX", WM8400_POWER_MANAGEMENT_3, 750 + WM8400_ROMIX_ENA_SHIFT, 751 + 0, &wm8400_dapm_romix_controls[0], 752 + ARRAY_SIZE(wm8400_dapm_romix_controls), 753 + outmixer_event, SND_SOC_DAPM_PRE_REG), 754 + 755 + /* LOUT PGA */ 756 + SND_SOC_DAPM_PGA("LOUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_LOUT_ENA_SHIFT, 757 + 0, NULL, 0), 758 + 759 + /* ROUT PGA */ 760 + SND_SOC_DAPM_PGA("ROUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_ROUT_ENA_SHIFT, 761 + 0, NULL, 0), 762 + 763 + /* LOPGA */ 764 + SND_SOC_DAPM_PGA("LOPGA", WM8400_POWER_MANAGEMENT_3, WM8400_LOPGA_ENA_SHIFT, 0, 765 + NULL, 0), 766 + 767 + /* ROPGA */ 768 + SND_SOC_DAPM_PGA("ROPGA", WM8400_POWER_MANAGEMENT_3, WM8400_ROPGA_ENA_SHIFT, 0, 769 + NULL, 0), 770 + 771 + /* MICBIAS */ 772 + SND_SOC_DAPM_MICBIAS("MICBIAS", WM8400_POWER_MANAGEMENT_1, 773 + WM8400_MIC1BIAS_ENA_SHIFT, 0), 774 + 775 + SND_SOC_DAPM_OUTPUT("LON"), 776 + SND_SOC_DAPM_OUTPUT("LOP"), 777 + SND_SOC_DAPM_OUTPUT("OUT3"), 778 + SND_SOC_DAPM_OUTPUT("LOUT"), 779 + SND_SOC_DAPM_OUTPUT("SPKN"), 780 + SND_SOC_DAPM_OUTPUT("SPKP"), 781 + SND_SOC_DAPM_OUTPUT("ROUT"), 782 + SND_SOC_DAPM_OUTPUT("OUT4"), 783 + SND_SOC_DAPM_OUTPUT("ROP"), 784 + SND_SOC_DAPM_OUTPUT("RON"), 785 + 786 + SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), 787 + }; 788 + 789 + static const struct snd_soc_dapm_route audio_map[] = { 790 + /* Make DACs turn on when playing even if not mixed into any outputs */ 791 + {"Internal DAC Sink", NULL, "Left DAC"}, 792 + {"Internal DAC Sink", NULL, "Right DAC"}, 793 + 794 + /* Make ADCs turn on when recording 795 + * even if not mixed from any inputs */ 796 + {"Left ADC", NULL, "Internal ADC Source"}, 797 + {"Right ADC", NULL, "Internal ADC Source"}, 798 + 799 + /* Input Side */ 800 + /* LIN12 PGA */ 801 + {"LIN12 PGA", "LIN1 Switch", "LIN1"}, 802 + {"LIN12 PGA", "LIN2 Switch", "LIN2"}, 803 + /* LIN34 PGA */ 804 + {"LIN34 PGA", "LIN3 Switch", "LIN3"}, 805 + {"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"}, 806 + /* INMIXL */ 807 + {"INMIXL", "Record Left Volume", "LOMIX"}, 808 + {"INMIXL", "LIN2 Volume", "LIN2"}, 809 + {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, 810 + {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, 811 + /* AILNMUX */ 812 + {"AILNMUX", "INMIXL Mix", "INMIXL"}, 813 + {"AILNMUX", "DIFFINL Mix", "LIN12 PGA"}, 814 + {"AILNMUX", "DIFFINL Mix", "LIN34 PGA"}, 815 + {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"}, 816 + {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"}, 817 + /* ADC */ 818 + {"Left ADC", NULL, "AILNMUX"}, 819 + 820 + /* RIN12 PGA */ 821 + {"RIN12 PGA", "RIN1 Switch", "RIN1"}, 822 + {"RIN12 PGA", "RIN2 Switch", "RIN2"}, 823 + /* RIN34 PGA */ 824 + {"RIN34 PGA", "RIN3 Switch", "RIN3"}, 825 + {"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"}, 826 + /* INMIXL */ 827 + {"INMIXR", "Record Right Volume", "ROMIX"}, 828 + {"INMIXR", "RIN2 Volume", "RIN2"}, 829 + {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, 830 + {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, 831 + /* AIRNMUX */ 832 + {"AIRNMUX", "INMIXR Mix", "INMIXR"}, 833 + {"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"}, 834 + {"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"}, 835 + {"AIRNMUX", "RXVOICE Mix", "LIN4/RXN"}, 836 + {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"}, 837 + /* ADC */ 838 + {"Right ADC", NULL, "AIRNMUX"}, 839 + 840 + /* LOMIX */ 841 + {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, 842 + {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, 843 + {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, 844 + {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, 845 + {"LOMIX", "LOMIX Right ADC Bypass Switch", "AIRNMUX"}, 846 + {"LOMIX", "LOMIX Left ADC Bypass Switch", "AILNMUX"}, 847 + {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, 848 + 849 + /* ROMIX */ 850 + {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, 851 + {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, 852 + {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, 853 + {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, 854 + {"ROMIX", "ROMIX Right ADC Bypass Switch", "AIRNMUX"}, 855 + {"ROMIX", "ROMIX Left ADC Bypass Switch", "AILNMUX"}, 856 + {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, 857 + 858 + /* SPKMIX */ 859 + {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, 860 + {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, 861 + {"SPKMIX", "SPKMIX LADC Bypass Switch", "AILNMUX"}, 862 + {"SPKMIX", "SPKMIX RADC Bypass Switch", "AIRNMUX"}, 863 + {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, 864 + {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, 865 + {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, 866 + {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"}, 867 + 868 + /* LONMIX */ 869 + {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, 870 + {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, 871 + {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, 872 + 873 + /* LOPMIX */ 874 + {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, 875 + {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, 876 + {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, 877 + 878 + /* OUT3MIX */ 879 + {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXN"}, 880 + {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, 881 + 882 + /* OUT4MIX */ 883 + {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, 884 + {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"}, 885 + 886 + /* RONMIX */ 887 + {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, 888 + {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, 889 + {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, 890 + 891 + /* ROPMIX */ 892 + {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, 893 + {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, 894 + {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, 895 + 896 + /* Out Mixer PGAs */ 897 + {"LOPGA", NULL, "LOMIX"}, 898 + {"ROPGA", NULL, "ROMIX"}, 899 + 900 + {"LOUT PGA", NULL, "LOMIX"}, 901 + {"ROUT PGA", NULL, "ROMIX"}, 902 + 903 + /* Output Pins */ 904 + {"LON", NULL, "LONMIX"}, 905 + {"LOP", NULL, "LOPMIX"}, 906 + {"OUT3", NULL, "OUT3MIX"}, 907 + {"LOUT", NULL, "LOUT PGA"}, 908 + {"SPKN", NULL, "SPKMIX"}, 909 + {"ROUT", NULL, "ROUT PGA"}, 910 + {"OUT4", NULL, "OUT4MIX"}, 911 + {"ROP", NULL, "ROPMIX"}, 912 + {"RON", NULL, "RONMIX"}, 913 + }; 914 + 915 + static int wm8400_add_widgets(struct snd_soc_codec *codec) 916 + { 917 + snd_soc_dapm_new_controls(codec, wm8400_dapm_widgets, 918 + ARRAY_SIZE(wm8400_dapm_widgets)); 919 + 920 + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 921 + 922 + snd_soc_dapm_new_widgets(codec); 923 + return 0; 924 + } 925 + 926 + /* 927 + * Clock after FLL and dividers 928 + */ 929 + static int wm8400_set_dai_sysclk(struct snd_soc_dai *codec_dai, 930 + int clk_id, unsigned int freq, int dir) 931 + { 932 + struct snd_soc_codec *codec = codec_dai->codec; 933 + struct wm8400_priv *wm8400 = codec->private_data; 934 + 935 + wm8400->sysclk = freq; 936 + return 0; 937 + } 938 + 939 + /* 940 + * Sets ADC and Voice DAC format. 941 + */ 942 + static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai, 943 + unsigned int fmt) 944 + { 945 + struct snd_soc_codec *codec = codec_dai->codec; 946 + u16 audio1, audio3; 947 + 948 + audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1); 949 + audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3); 950 + 951 + /* set master/slave audio interface */ 952 + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 953 + case SND_SOC_DAIFMT_CBS_CFS: 954 + audio3 &= ~WM8400_AIF_MSTR1; 955 + break; 956 + case SND_SOC_DAIFMT_CBM_CFM: 957 + audio3 |= WM8400_AIF_MSTR1; 958 + break; 959 + default: 960 + return -EINVAL; 961 + } 962 + 963 + audio1 &= ~WM8400_AIF_FMT_MASK; 964 + 965 + /* interface format */ 966 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 967 + case SND_SOC_DAIFMT_I2S: 968 + audio1 |= WM8400_AIF_FMT_I2S; 969 + audio1 &= ~WM8400_AIF_LRCLK_INV; 970 + break; 971 + case SND_SOC_DAIFMT_RIGHT_J: 972 + audio1 |= WM8400_AIF_FMT_RIGHTJ; 973 + audio1 &= ~WM8400_AIF_LRCLK_INV; 974 + break; 975 + case SND_SOC_DAIFMT_LEFT_J: 976 + audio1 |= WM8400_AIF_FMT_LEFTJ; 977 + audio1 &= ~WM8400_AIF_LRCLK_INV; 978 + break; 979 + case SND_SOC_DAIFMT_DSP_A: 980 + audio1 |= WM8400_AIF_FMT_DSP; 981 + audio1 &= ~WM8400_AIF_LRCLK_INV; 982 + break; 983 + case SND_SOC_DAIFMT_DSP_B: 984 + audio1 |= WM8400_AIF_FMT_DSP | WM8400_AIF_LRCLK_INV; 985 + break; 986 + default: 987 + return -EINVAL; 988 + } 989 + 990 + wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1); 991 + wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3); 992 + return 0; 993 + } 994 + 995 + static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai, 996 + int div_id, int div) 997 + { 998 + struct snd_soc_codec *codec = codec_dai->codec; 999 + u16 reg; 1000 + 1001 + switch (div_id) { 1002 + case WM8400_MCLK_DIV: 1003 + reg = wm8400_read(codec, WM8400_CLOCKING_2) & 1004 + ~WM8400_MCLK_DIV_MASK; 1005 + wm8400_write(codec, WM8400_CLOCKING_2, reg | div); 1006 + break; 1007 + case WM8400_DACCLK_DIV: 1008 + reg = wm8400_read(codec, WM8400_CLOCKING_2) & 1009 + ~WM8400_DAC_CLKDIV_MASK; 1010 + wm8400_write(codec, WM8400_CLOCKING_2, reg | div); 1011 + break; 1012 + case WM8400_ADCCLK_DIV: 1013 + reg = wm8400_read(codec, WM8400_CLOCKING_2) & 1014 + ~WM8400_ADC_CLKDIV_MASK; 1015 + wm8400_write(codec, WM8400_CLOCKING_2, reg | div); 1016 + break; 1017 + case WM8400_BCLK_DIV: 1018 + reg = wm8400_read(codec, WM8400_CLOCKING_1) & 1019 + ~WM8400_BCLK_DIV_MASK; 1020 + wm8400_write(codec, WM8400_CLOCKING_1, reg | div); 1021 + break; 1022 + default: 1023 + return -EINVAL; 1024 + } 1025 + 1026 + return 0; 1027 + } 1028 + 1029 + /* 1030 + * Set PCM DAI bit size and sample rate. 1031 + */ 1032 + static int wm8400_hw_params(struct snd_pcm_substream *substream, 1033 + struct snd_pcm_hw_params *params, 1034 + struct snd_soc_dai *dai) 1035 + { 1036 + struct snd_soc_pcm_runtime *rtd = substream->private_data; 1037 + struct snd_soc_device *socdev = rtd->socdev; 1038 + struct snd_soc_codec *codec = socdev->card->codec; 1039 + u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1); 1040 + 1041 + audio1 &= ~WM8400_AIF_WL_MASK; 1042 + /* bit size */ 1043 + switch (params_format(params)) { 1044 + case SNDRV_PCM_FORMAT_S16_LE: 1045 + break; 1046 + case SNDRV_PCM_FORMAT_S20_3LE: 1047 + audio1 |= WM8400_AIF_WL_20BITS; 1048 + break; 1049 + case SNDRV_PCM_FORMAT_S24_LE: 1050 + audio1 |= WM8400_AIF_WL_24BITS; 1051 + break; 1052 + case SNDRV_PCM_FORMAT_S32_LE: 1053 + audio1 |= WM8400_AIF_WL_32BITS; 1054 + break; 1055 + } 1056 + 1057 + wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1); 1058 + return 0; 1059 + } 1060 + 1061 + static int wm8400_mute(struct snd_soc_dai *dai, int mute) 1062 + { 1063 + struct snd_soc_codec *codec = dai->codec; 1064 + u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE; 1065 + 1066 + if (mute) 1067 + wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE); 1068 + else 1069 + wm8400_write(codec, WM8400_DAC_CTRL, val); 1070 + 1071 + return 0; 1072 + } 1073 + 1074 + /* TODO: set bias for best performance at standby */ 1075 + static int wm8400_set_bias_level(struct snd_soc_codec *codec, 1076 + enum snd_soc_bias_level level) 1077 + { 1078 + struct wm8400_priv *wm8400 = codec->private_data; 1079 + u16 val; 1080 + int ret; 1081 + 1082 + switch (level) { 1083 + case SND_SOC_BIAS_ON: 1084 + break; 1085 + 1086 + case SND_SOC_BIAS_PREPARE: 1087 + /* VMID=2*50k */ 1088 + val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) & 1089 + ~WM8400_VMID_MODE_MASK; 1090 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2); 1091 + break; 1092 + 1093 + case SND_SOC_BIAS_STANDBY: 1094 + if (codec->bias_level == SND_SOC_BIAS_OFF) { 1095 + ret = regulator_bulk_enable(ARRAY_SIZE(power), 1096 + &power[0]); 1097 + if (ret != 0) { 1098 + dev_err(wm8400->wm8400->dev, 1099 + "Failed to enable regulators: %d\n", 1100 + ret); 1101 + return ret; 1102 + } 1103 + 1104 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, 1105 + WM8400_CODEC_ENA | WM8400_SYSCLK_ENA); 1106 + 1107 + /* Enable all output discharge bits */ 1108 + wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE | 1109 + WM8400_DIS_RLINE | WM8400_DIS_OUT3 | 1110 + WM8400_DIS_OUT4 | WM8400_DIS_LOUT | 1111 + WM8400_DIS_ROUT); 1112 + 1113 + /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ 1114 + wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST | 1115 + WM8400_BUFDCOPEN | WM8400_POBCTRL); 1116 + 1117 + msleep(500); 1118 + 1119 + /* Enable outputs */ 1120 + val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1); 1121 + val |= WM8400_SPK_ENA | WM8400_OUT3_ENA | 1122 + WM8400_OUT4_ENA | WM8400_LOUT_ENA | 1123 + WM8400_ROUT_ENA; 1124 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); 1125 + 1126 + /* disable all output discharge bits */ 1127 + wm8400_write(codec, WM8400_ANTIPOP1, 0); 1128 + 1129 + /* Enable VREF & VMID at 2x50k */ 1130 + val |= 0x2 | WM8400_VREF_ENA; 1131 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); 1132 + 1133 + msleep(600); 1134 + 1135 + /* Enable BUFIOEN */ 1136 + wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST | 1137 + WM8400_BUFDCOPEN | WM8400_POBCTRL | 1138 + WM8400_BUFIOEN); 1139 + 1140 + /* Disable outputs */ 1141 + val &= ~(WM8400_SPK_ENA | WM8400_OUT3_ENA | 1142 + WM8400_OUT4_ENA | WM8400_LOUT_ENA | 1143 + WM8400_ROUT_ENA); 1144 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); 1145 + 1146 + /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ 1147 + wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN); 1148 + } 1149 + 1150 + /* VMID=2*300k */ 1151 + val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) & 1152 + ~WM8400_VMID_MODE_MASK; 1153 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4); 1154 + break; 1155 + 1156 + case SND_SOC_BIAS_OFF: 1157 + /* Enable POBCTRL and SOFT_ST */ 1158 + wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST | 1159 + WM8400_POBCTRL | WM8400_BUFIOEN); 1160 + 1161 + /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ 1162 + wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST | 1163 + WM8400_BUFDCOPEN | WM8400_POBCTRL | 1164 + WM8400_BUFIOEN); 1165 + 1166 + /* mute DAC */ 1167 + val = wm8400_read(codec, WM8400_DAC_CTRL); 1168 + wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE); 1169 + 1170 + /* Enable any disabled outputs */ 1171 + val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1); 1172 + val |= WM8400_SPK_ENA | WM8400_OUT3_ENA | 1173 + WM8400_OUT4_ENA | WM8400_LOUT_ENA | 1174 + WM8400_ROUT_ENA; 1175 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); 1176 + 1177 + /* Disable VMID */ 1178 + val &= ~WM8400_VMID_MODE_MASK; 1179 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); 1180 + 1181 + msleep(300); 1182 + 1183 + /* Enable all output discharge bits */ 1184 + wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE | 1185 + WM8400_DIS_RLINE | WM8400_DIS_OUT3 | 1186 + WM8400_DIS_OUT4 | WM8400_DIS_LOUT | 1187 + WM8400_DIS_ROUT); 1188 + 1189 + /* Disable VREF */ 1190 + val &= ~WM8400_VREF_ENA; 1191 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val); 1192 + 1193 + /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ 1194 + wm8400_write(codec, WM8400_ANTIPOP2, 0x0); 1195 + 1196 + ret = regulator_bulk_disable(ARRAY_SIZE(power), 1197 + &power[0]); 1198 + if (ret != 0) 1199 + return ret; 1200 + 1201 + break; 1202 + } 1203 + 1204 + codec->bias_level = level; 1205 + return 0; 1206 + } 1207 + 1208 + #define WM8400_RATES SNDRV_PCM_RATE_8000_96000 1209 + 1210 + #define WM8400_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 1211 + SNDRV_PCM_FMTBIT_S24_LE) 1212 + 1213 + /* 1214 + * The WM8400 supports 2 different and mutually exclusive DAI 1215 + * configurations. 1216 + * 1217 + * 1. ADC/DAC on Primary Interface 1218 + * 2. ADC on Primary Interface/DAC on secondary 1219 + */ 1220 + struct snd_soc_dai wm8400_dai = { 1221 + /* ADC/DAC on primary */ 1222 + .name = "WM8400 ADC/DAC Primary", 1223 + .id = 1, 1224 + .playback = { 1225 + .stream_name = "Playback", 1226 + .channels_min = 1, 1227 + .channels_max = 2, 1228 + .rates = WM8400_RATES, 1229 + .formats = WM8400_FORMATS, 1230 + }, 1231 + .capture = { 1232 + .stream_name = "Capture", 1233 + .channels_min = 1, 1234 + .channels_max = 2, 1235 + .rates = WM8400_RATES, 1236 + .formats = WM8400_FORMATS, 1237 + }, 1238 + .ops = { 1239 + .hw_params = wm8400_hw_params, 1240 + .digital_mute = wm8400_mute, 1241 + .set_fmt = wm8400_set_dai_fmt, 1242 + .set_clkdiv = wm8400_set_dai_clkdiv, 1243 + .set_sysclk = wm8400_set_dai_sysclk, 1244 + }, 1245 + }; 1246 + EXPORT_SYMBOL_GPL(wm8400_dai); 1247 + 1248 + static int wm8400_suspend(struct platform_device *pdev, pm_message_t state) 1249 + { 1250 + struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1251 + struct snd_soc_codec *codec = socdev->card->codec; 1252 + 1253 + wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); 1254 + 1255 + return 0; 1256 + } 1257 + 1258 + static int wm8400_resume(struct platform_device *pdev) 1259 + { 1260 + struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1261 + struct snd_soc_codec *codec = socdev->card->codec; 1262 + 1263 + wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1264 + 1265 + return 0; 1266 + } 1267 + 1268 + static struct snd_soc_codec *wm8400_codec; 1269 + 1270 + static int wm8400_probe(struct platform_device *pdev) 1271 + { 1272 + struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1273 + struct snd_soc_codec *codec; 1274 + int ret; 1275 + 1276 + if (!wm8400_codec) { 1277 + dev_err(&pdev->dev, "wm8400 not yet discovered\n"); 1278 + return -ENODEV; 1279 + } 1280 + codec = wm8400_codec; 1281 + 1282 + socdev->card->codec = codec; 1283 + 1284 + /* register pcms */ 1285 + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 1286 + if (ret < 0) { 1287 + dev_err(&pdev->dev, "failed to create pcms\n"); 1288 + goto pcm_err; 1289 + } 1290 + 1291 + wm8400_add_controls(codec); 1292 + wm8400_add_widgets(codec); 1293 + 1294 + ret = snd_soc_init_card(socdev); 1295 + if (ret < 0) { 1296 + dev_err(&pdev->dev, "failed to register card\n"); 1297 + goto card_err; 1298 + } 1299 + 1300 + return ret; 1301 + 1302 + card_err: 1303 + snd_soc_free_pcms(socdev); 1304 + snd_soc_dapm_free(socdev); 1305 + pcm_err: 1306 + return ret; 1307 + } 1308 + 1309 + /* power down chip */ 1310 + static int wm8400_remove(struct platform_device *pdev) 1311 + { 1312 + struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1313 + 1314 + snd_soc_free_pcms(socdev); 1315 + snd_soc_dapm_free(socdev); 1316 + 1317 + return 0; 1318 + } 1319 + 1320 + struct snd_soc_codec_device soc_codec_dev_wm8400 = { 1321 + .probe = wm8400_probe, 1322 + .remove = wm8400_remove, 1323 + .suspend = wm8400_suspend, 1324 + .resume = wm8400_resume, 1325 + }; 1326 + 1327 + static void wm8400_probe_deferred(struct work_struct *work) 1328 + { 1329 + struct wm8400_priv *priv = container_of(work, struct wm8400_priv, 1330 + work); 1331 + struct snd_soc_codec *codec = &priv->codec; 1332 + int ret; 1333 + 1334 + /* charge output caps */ 1335 + wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1336 + 1337 + /* We're done, tell the subsystem. */ 1338 + ret = snd_soc_register_codec(codec); 1339 + if (ret != 0) { 1340 + dev_err(priv->wm8400->dev, 1341 + "Failed to register codec: %d\n", ret); 1342 + goto err; 1343 + } 1344 + 1345 + ret = snd_soc_register_dai(&wm8400_dai); 1346 + if (ret != 0) { 1347 + dev_err(priv->wm8400->dev, 1348 + "Failed to register DAI: %d\n", ret); 1349 + goto err_codec; 1350 + } 1351 + 1352 + return; 1353 + 1354 + err_codec: 1355 + snd_soc_unregister_codec(codec); 1356 + err: 1357 + wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); 1358 + } 1359 + 1360 + static int wm8400_codec_probe(struct platform_device *dev) 1361 + { 1362 + struct wm8400_priv *priv; 1363 + int ret; 1364 + u16 reg; 1365 + struct snd_soc_codec *codec; 1366 + 1367 + priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL); 1368 + if (priv == NULL) 1369 + return -ENOMEM; 1370 + 1371 + codec = &priv->codec; 1372 + codec->private_data = priv; 1373 + codec->control_data = dev->dev.driver_data; 1374 + priv->wm8400 = dev->dev.driver_data; 1375 + 1376 + ret = regulator_bulk_get(priv->wm8400->dev, 1377 + ARRAY_SIZE(power), &power[0]); 1378 + if (ret != 0) { 1379 + dev_err(&dev->dev, "Failed to get regulators: %d\n", ret); 1380 + goto err; 1381 + } 1382 + 1383 + codec->dev = &dev->dev; 1384 + wm8400_dai.dev = &dev->dev; 1385 + 1386 + codec->name = "WM8400"; 1387 + codec->owner = THIS_MODULE; 1388 + codec->read = wm8400_read; 1389 + codec->write = wm8400_write; 1390 + codec->bias_level = SND_SOC_BIAS_OFF; 1391 + codec->set_bias_level = wm8400_set_bias_level; 1392 + codec->dai = &wm8400_dai; 1393 + codec->num_dai = 1; 1394 + codec->reg_cache_size = WM8400_REGISTER_COUNT; 1395 + mutex_init(&codec->mutex); 1396 + INIT_LIST_HEAD(&codec->dapm_widgets); 1397 + INIT_LIST_HEAD(&codec->dapm_paths); 1398 + INIT_WORK(&priv->work, wm8400_probe_deferred); 1399 + 1400 + wm8400_codec_reset(codec); 1401 + 1402 + reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1); 1403 + wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA); 1404 + 1405 + /* Latch volume update bits */ 1406 + reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME); 1407 + wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME, 1408 + reg & WM8400_IPVU); 1409 + reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME); 1410 + wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME, 1411 + reg & WM8400_IPVU); 1412 + 1413 + wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); 1414 + wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); 1415 + 1416 + wm8400_codec = codec; 1417 + 1418 + if (!schedule_work(&priv->work)) { 1419 + ret = -EINVAL; 1420 + goto err_regulator; 1421 + } 1422 + 1423 + return 0; 1424 + 1425 + err_regulator: 1426 + wm8400_codec = NULL; 1427 + regulator_bulk_free(ARRAY_SIZE(power), power); 1428 + err: 1429 + kfree(priv); 1430 + return ret; 1431 + } 1432 + 1433 + static int __exit wm8400_codec_remove(struct platform_device *dev) 1434 + { 1435 + struct wm8400_priv *priv = wm8400_codec->private_data; 1436 + u16 reg; 1437 + 1438 + snd_soc_unregister_dai(&wm8400_dai); 1439 + snd_soc_unregister_codec(wm8400_codec); 1440 + 1441 + reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1); 1442 + wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1, 1443 + reg & (~WM8400_CODEC_ENA)); 1444 + 1445 + regulator_bulk_free(ARRAY_SIZE(power), power); 1446 + kfree(priv); 1447 + 1448 + wm8400_codec = NULL; 1449 + 1450 + return 0; 1451 + } 1452 + 1453 + static struct platform_driver wm8400_codec_driver = { 1454 + .driver = { 1455 + .name = "wm8400-codec", 1456 + .owner = THIS_MODULE, 1457 + }, 1458 + .probe = wm8400_codec_probe, 1459 + .remove = __exit_p(wm8400_codec_remove), 1460 + }; 1461 + 1462 + static int __init wm8400_codec_init(void) 1463 + { 1464 + return platform_driver_register(&wm8400_codec_driver); 1465 + } 1466 + module_init(wm8400_codec_init); 1467 + 1468 + static void __exit wm8400_codec_exit(void) 1469 + { 1470 + platform_driver_unregister(&wm8400_codec_driver); 1471 + } 1472 + module_exit(wm8400_codec_exit); 1473 + 1474 + EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400); 1475 + 1476 + MODULE_DESCRIPTION("ASoC WM8400 driver"); 1477 + MODULE_AUTHOR("Mark Brown"); 1478 + MODULE_LICENSE("GPL"); 1479 + MODULE_ALIAS("platform:wm8400-codec");
+62
sound/soc/codecs/wm8400.h
··· 1 + /* 2 + * wm8400.h -- audio driver for WM8400 3 + * 4 + * Copyright 2008 Wolfson Microelectronics PLC. 5 + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License as published by the 9 + * Free Software Foundation; either version 2 of the License, or (at your 10 + * option) any later version. 11 + * 12 + */ 13 + 14 + #ifndef _WM8400_CODEC_H 15 + #define _WM8400_CODEC_H 16 + 17 + #define WM8400_MCLK_DIV 0 18 + #define WM8400_DACCLK_DIV 1 19 + #define WM8400_ADCCLK_DIV 2 20 + #define WM8400_BCLK_DIV 3 21 + 22 + #define WM8400_MCLK_DIV_1 0x400 23 + #define WM8400_MCLK_DIV_2 0x800 24 + 25 + #define WM8400_DAC_CLKDIV_1 0x00 26 + #define WM8400_DAC_CLKDIV_1_5 0x04 27 + #define WM8400_DAC_CLKDIV_2 0x08 28 + #define WM8400_DAC_CLKDIV_3 0x0c 29 + #define WM8400_DAC_CLKDIV_4 0x10 30 + #define WM8400_DAC_CLKDIV_5_5 0x14 31 + #define WM8400_DAC_CLKDIV_6 0x18 32 + 33 + #define WM8400_ADC_CLKDIV_1 0x00 34 + #define WM8400_ADC_CLKDIV_1_5 0x20 35 + #define WM8400_ADC_CLKDIV_2 0x40 36 + #define WM8400_ADC_CLKDIV_3 0x60 37 + #define WM8400_ADC_CLKDIV_4 0x80 38 + #define WM8400_ADC_CLKDIV_5_5 0xa0 39 + #define WM8400_ADC_CLKDIV_6 0xc0 40 + 41 + 42 + #define WM8400_BCLK_DIV_1 (0x0 << 1) 43 + #define WM8400_BCLK_DIV_1_5 (0x1 << 1) 44 + #define WM8400_BCLK_DIV_2 (0x2 << 1) 45 + #define WM8400_BCLK_DIV_3 (0x3 << 1) 46 + #define WM8400_BCLK_DIV_4 (0x4 << 1) 47 + #define WM8400_BCLK_DIV_5_5 (0x5 << 1) 48 + #define WM8400_BCLK_DIV_6 (0x6 << 1) 49 + #define WM8400_BCLK_DIV_8 (0x7 << 1) 50 + #define WM8400_BCLK_DIV_11 (0x8 << 1) 51 + #define WM8400_BCLK_DIV_12 (0x9 << 1) 52 + #define WM8400_BCLK_DIV_16 (0xA << 1) 53 + #define WM8400_BCLK_DIV_22 (0xB << 1) 54 + #define WM8400_BCLK_DIV_24 (0xC << 1) 55 + #define WM8400_BCLK_DIV_32 (0xD << 1) 56 + #define WM8400_BCLK_DIV_44 (0xE << 1) 57 + #define WM8400_BCLK_DIV_48 (0xF << 1) 58 + 59 + extern struct snd_soc_dai wm8400_dai; 60 + extern struct snd_soc_codec_device soc_codec_dev_wm8400; 61 + 62 + #endif