0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/init.h>
0010 #include <linux/slab.h>
0011 #include <linux/mfd/wm97xx.h>
0012 #include <linux/module.h>
0013 #include <linux/kernel.h>
0014 #include <linux/device.h>
0015 #include <linux/regmap.h>
0016 #include <sound/core.h>
0017 #include <sound/pcm.h>
0018 #include <sound/ac97_codec.h>
0019 #include <sound/ac97/codec.h>
0020 #include <sound/ac97/compat.h>
0021 #include <sound/initval.h>
0022 #include <sound/soc.h>
0023 #include <sound/tlv.h>
0024
0025 #define WM9712_VENDOR_ID 0x574d4c12
0026 #define WM9712_VENDOR_ID_MASK 0xffffffff
0027
0028 struct wm9712_priv {
0029 struct snd_ac97 *ac97;
0030 unsigned int hp_mixer[2];
0031 struct mutex lock;
0032 struct wm97xx_platform_data *mfd_pdata;
0033 };
0034
0035 static const struct reg_default wm9712_reg_defaults[] = {
0036 { 0x02, 0x8000 },
0037 { 0x04, 0x8000 },
0038 { 0x06, 0x8000 },
0039 { 0x08, 0x0f0f },
0040 { 0x0a, 0xaaa0 },
0041 { 0x0c, 0xc008 },
0042 { 0x0e, 0x6808 },
0043 { 0x10, 0xe808 },
0044 { 0x12, 0xaaa0 },
0045 { 0x14, 0xad00 },
0046 { 0x16, 0x8000 },
0047 { 0x18, 0xe808 },
0048 { 0x1a, 0x3000 },
0049 { 0x1c, 0x8000 },
0050 { 0x20, 0x0000 },
0051 { 0x22, 0x0000 },
0052 { 0x26, 0x000f },
0053 { 0x28, 0x0605 },
0054 { 0x2a, 0x0410 },
0055 { 0x2c, 0xbb80 },
0056 { 0x2e, 0xbb80 },
0057 { 0x32, 0xbb80 },
0058 { 0x34, 0x2000 },
0059 { 0x4c, 0xf83e },
0060 { 0x4e, 0xffff },
0061 { 0x50, 0x0000 },
0062 { 0x52, 0x0000 },
0063 { 0x56, 0xf83e },
0064 { 0x58, 0x0008 },
0065 { 0x5c, 0x0000 },
0066 { 0x60, 0xb032 },
0067 { 0x62, 0x3e00 },
0068 { 0x64, 0x0000 },
0069 { 0x76, 0x0006 },
0070 { 0x78, 0x0001 },
0071 { 0x7a, 0x0000 },
0072 };
0073
0074 static bool wm9712_volatile_reg(struct device *dev, unsigned int reg)
0075 {
0076 switch (reg) {
0077 case AC97_REC_GAIN:
0078 return true;
0079 default:
0080 return regmap_ac97_default_volatile(dev, reg);
0081 }
0082 }
0083
0084 static const struct regmap_config wm9712_regmap_config = {
0085 .reg_bits = 16,
0086 .reg_stride = 2,
0087 .val_bits = 16,
0088 .max_register = 0x7e,
0089 .cache_type = REGCACHE_RBTREE,
0090
0091 .volatile_reg = wm9712_volatile_reg,
0092
0093 .reg_defaults = wm9712_reg_defaults,
0094 .num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults),
0095 };
0096
0097 #define HPL_MIXER 0x0
0098 #define HPR_MIXER 0x1
0099
0100 static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"};
0101 static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"};
0102 static const char *wm9712_out3_src[] = {"Left", "VREF", "Left + Right",
0103 "Mono"};
0104 static const char *wm9712_spk_src[] = {"Speaker Mix", "Headphone Mix"};
0105 static const char *wm9712_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
0106 static const char *wm9712_base[] = {"Linear Control", "Adaptive Boost"};
0107 static const char *wm9712_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
0108 static const char *wm9712_mic[] = {"Mic 1", "Differential", "Mic 2",
0109 "Stereo"};
0110 static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer",
0111 "Line", "Headphone Mixer", "Phone Mixer", "Phone"};
0112 static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"};
0113 static const char *wm9712_diff_sel[] = {"Mic", "Line"};
0114
0115 static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0);
0116 static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 2000, 0);
0117
0118 static const struct soc_enum wm9712_enum[] = {
0119 SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select),
0120 SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux),
0121 SOC_ENUM_SINGLE(AC97_AUX, 9, 4, wm9712_out3_src),
0122 SOC_ENUM_SINGLE(AC97_AUX, 8, 2, wm9712_spk_src),
0123 SOC_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9712_rec_adc),
0124 SOC_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9712_base),
0125 SOC_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9712_rec_gain),
0126 SOC_ENUM_SINGLE(AC97_MIC, 5, 4, wm9712_mic),
0127 SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9712_rec_sel),
0128 SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9712_rec_sel),
0129 SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9712_ng_type),
0130 SOC_ENUM_SINGLE(0x5c, 8, 2, wm9712_diff_sel),
0131 };
0132
0133 static const struct snd_kcontrol_new wm9712_snd_ac97_controls[] = {
0134 SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
0135 SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1),
0136 SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
0137 SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
0138 SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
0139
0140 SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
0141 SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0),
0142 SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0),
0143 SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
0144 SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
0145 SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
0146
0147 SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
0148 SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
0149 SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
0150 SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
0151 SOC_ENUM("ALC Function", wm9712_enum[0]),
0152 SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
0153 SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
0154 SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
0155 SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
0156 SOC_ENUM("ALC NG Type", wm9712_enum[10]),
0157 SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
0158
0159 SOC_SINGLE("Mic Headphone Volume", AC97_VIDEO, 12, 7, 1),
0160 SOC_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
0161
0162 SOC_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
0163 SOC_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
0164 SOC_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
0165
0166 SOC_SINGLE("PCBeep Bypass Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
0167 SOC_SINGLE("PCBeep Bypass Speaker Volume", AC97_PC_BEEP, 8, 7, 1),
0168 SOC_SINGLE("PCBeep Bypass Phone Volume", AC97_PC_BEEP, 4, 7, 1),
0169
0170 SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1),
0171 SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1),
0172 SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
0173
0174 SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1),
0175 SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
0176
0177 SOC_SINGLE_TLV("Capture Boost Switch", AC97_REC_SEL, 14, 1, 0, boost_tlv),
0178 SOC_SINGLE_TLV("Capture to Phone Boost Switch", AC97_REC_SEL, 11, 1, 1,
0179 boost_tlv),
0180
0181 SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
0182 SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
0183 SOC_SINGLE("3D Playback Volume", AC97_3D_CONTROL, 0, 15, 0),
0184
0185 SOC_ENUM("Bass Control", wm9712_enum[5]),
0186 SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
0187 SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
0188 SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
0189 SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),
0190 SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
0191
0192 SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
0193 SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
0194 SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 0),
0195 SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
0196
0197 SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv),
0198 SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv),
0199 SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv),
0200 };
0201
0202 static const unsigned int wm9712_mixer_mute_regs[] = {
0203 AC97_VIDEO,
0204 AC97_PCM,
0205 AC97_LINE,
0206 AC97_PHONE,
0207 AC97_CD,
0208 AC97_PC_BEEP,
0209 };
0210
0211
0212
0213
0214
0215 static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
0216 struct snd_ctl_elem_value *ucontrol)
0217 {
0218 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
0219 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
0220 struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
0221 unsigned int val = ucontrol->value.integer.value[0];
0222 struct soc_mixer_control *mc =
0223 (struct soc_mixer_control *)kcontrol->private_value;
0224 unsigned int mixer, mask, shift, old;
0225 struct snd_soc_dapm_update update = {};
0226 bool change;
0227
0228 mixer = mc->shift >> 8;
0229 shift = mc->shift & 0xff;
0230 mask = 1 << shift;
0231
0232 mutex_lock(&wm9712->lock);
0233 old = wm9712->hp_mixer[mixer];
0234 if (ucontrol->value.integer.value[0])
0235 wm9712->hp_mixer[mixer] |= mask;
0236 else
0237 wm9712->hp_mixer[mixer] &= ~mask;
0238
0239 change = old != wm9712->hp_mixer[mixer];
0240 if (change) {
0241 update.kcontrol = kcontrol;
0242 update.reg = wm9712_mixer_mute_regs[shift];
0243 update.mask = 0x8000;
0244 if ((wm9712->hp_mixer[0] & mask) ||
0245 (wm9712->hp_mixer[1] & mask))
0246 update.val = 0x0;
0247 else
0248 update.val = 0x8000;
0249
0250 snd_soc_dapm_mixer_update_power(dapm, kcontrol, val,
0251 &update);
0252 }
0253
0254 mutex_unlock(&wm9712->lock);
0255
0256 return change;
0257 }
0258
0259 static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
0260 struct snd_ctl_elem_value *ucontrol)
0261 {
0262 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
0263 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
0264 struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
0265 struct soc_mixer_control *mc =
0266 (struct soc_mixer_control *)kcontrol->private_value;
0267 unsigned int shift, mixer;
0268
0269 mixer = mc->shift >> 8;
0270 shift = mc->shift & 0xff;
0271
0272 ucontrol->value.integer.value[0] =
0273 (wm9712->hp_mixer[mixer] >> shift) & 1;
0274
0275 return 0;
0276 }
0277
0278 #define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \
0279 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
0280 .info = snd_soc_info_volsw, \
0281 .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \
0282 .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \
0283 (xmixer << 8) | xshift, 1, 0, 0) \
0284 }
0285
0286
0287 static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
0288 WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPL_MIXER, 5),
0289 WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 4),
0290 WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPL_MIXER, 3),
0291 WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPL_MIXER, 2),
0292 WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 1),
0293 WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPL_MIXER, 0),
0294 };
0295
0296
0297 static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = {
0298 WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPR_MIXER, 5),
0299 WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 4),
0300 WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPR_MIXER, 3),
0301 WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPR_MIXER, 2),
0302 WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 1),
0303 WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPR_MIXER, 0),
0304 };
0305
0306
0307 static const struct snd_kcontrol_new wm9712_speaker_mixer_controls[] = {
0308 SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 11, 1, 1),
0309 SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 11, 1, 1),
0310 SOC_DAPM_SINGLE("Phone Bypass Switch", AC97_PHONE, 14, 1, 1),
0311 SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 14, 1, 1),
0312 SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 14, 1, 1),
0313 };
0314
0315
0316 static const struct snd_kcontrol_new wm9712_phone_mixer_controls[] = {
0317 SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 7, 1, 1),
0318 SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 7, 1, 1),
0319 SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 13, 1, 1),
0320 SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 13, 1, 1),
0321 SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_MIC, 14, 1, 1),
0322 SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_MIC, 13, 1, 1),
0323 };
0324
0325
0326 static const struct snd_kcontrol_new wm9712_alc_mux_controls =
0327 SOC_DAPM_ENUM("Route", wm9712_enum[1]);
0328
0329
0330 static const struct snd_kcontrol_new wm9712_out3_mux_controls =
0331 SOC_DAPM_ENUM("Route", wm9712_enum[2]);
0332
0333
0334 static const struct snd_kcontrol_new wm9712_spk_mux_controls =
0335 SOC_DAPM_ENUM("Route", wm9712_enum[3]);
0336
0337
0338 static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls =
0339 SOC_DAPM_ENUM("Route", wm9712_enum[4]);
0340
0341
0342 static const struct snd_kcontrol_new wm9712_capture_selectl_controls =
0343 SOC_DAPM_ENUM("Route", wm9712_enum[8]);
0344
0345
0346 static const struct snd_kcontrol_new wm9712_capture_selectr_controls =
0347 SOC_DAPM_ENUM("Route", wm9712_enum[9]);
0348
0349
0350 static const struct snd_kcontrol_new wm9712_mic_src_controls =
0351 SOC_DAPM_ENUM("Mic Source Select", wm9712_enum[7]);
0352
0353
0354 static const struct snd_kcontrol_new wm9712_diff_sel_controls =
0355 SOC_DAPM_ENUM("Route", wm9712_enum[11]);
0356
0357 static const struct snd_soc_dapm_widget wm9712_dapm_widgets[] = {
0358 SND_SOC_DAPM_MUX("ALC Sidetone Mux", SND_SOC_NOPM, 0, 0,
0359 &wm9712_alc_mux_controls),
0360 SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0,
0361 &wm9712_out3_mux_controls),
0362 SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0,
0363 &wm9712_spk_mux_controls),
0364 SND_SOC_DAPM_MUX("Capture Phone Mux", SND_SOC_NOPM, 0, 0,
0365 &wm9712_capture_phone_mux_controls),
0366 SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0,
0367 &wm9712_capture_selectl_controls),
0368 SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0,
0369 &wm9712_capture_selectr_controls),
0370 SND_SOC_DAPM_MUX("Left Mic Select Source", SND_SOC_NOPM, 0, 0,
0371 &wm9712_mic_src_controls),
0372 SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0,
0373 &wm9712_mic_src_controls),
0374 SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
0375 &wm9712_diff_sel_controls),
0376 SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
0377 SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_INT_PAGING, 9, 1,
0378 &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls)),
0379 SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_INT_PAGING, 8, 1,
0380 &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls)),
0381 SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1,
0382 &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)),
0383 SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1,
0384 &wm9712_speaker_mixer_controls[0],
0385 ARRAY_SIZE(wm9712_speaker_mixer_controls)),
0386 SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
0387 SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_INT_PAGING, 14, 1),
0388 SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_INT_PAGING, 13, 1),
0389 SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", SND_SOC_NOPM, 0, 0),
0390 SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_INT_PAGING, 12, 1),
0391 SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_INT_PAGING, 11, 1),
0392 SND_SOC_DAPM_PGA("Headphone PGA", AC97_INT_PAGING, 4, 1, NULL, 0),
0393 SND_SOC_DAPM_PGA("Speaker PGA", AC97_INT_PAGING, 3, 1, NULL, 0),
0394 SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0),
0395 SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0),
0396 SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0),
0397 SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0),
0398 SND_SOC_DAPM_PGA("Differential Mic", SND_SOC_NOPM, 0, 0, NULL, 0),
0399 SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1),
0400 SND_SOC_DAPM_OUTPUT("MONOOUT"),
0401 SND_SOC_DAPM_OUTPUT("HPOUTL"),
0402 SND_SOC_DAPM_OUTPUT("HPOUTR"),
0403 SND_SOC_DAPM_OUTPUT("LOUT2"),
0404 SND_SOC_DAPM_OUTPUT("ROUT2"),
0405 SND_SOC_DAPM_OUTPUT("OUT3"),
0406 SND_SOC_DAPM_INPUT("LINEINL"),
0407 SND_SOC_DAPM_INPUT("LINEINR"),
0408 SND_SOC_DAPM_INPUT("PHONE"),
0409 SND_SOC_DAPM_INPUT("PCBEEP"),
0410 SND_SOC_DAPM_INPUT("MIC1"),
0411 SND_SOC_DAPM_INPUT("MIC2"),
0412 };
0413
0414 static const struct snd_soc_dapm_route wm9712_audio_map[] = {
0415
0416 {"AC97 Mixer", NULL, "Left DAC"},
0417 {"AC97 Mixer", NULL, "Right DAC"},
0418
0419
0420 {"Left HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
0421 {"Left HP Mixer", "Aux Playback Switch", "Aux DAC"},
0422 {"Left HP Mixer", "Phone Bypass Switch", "Phone PGA"},
0423 {"Left HP Mixer", "Line Bypass Switch", "Line PGA"},
0424 {"Left HP Mixer", "PCM Playback Switch", "Left DAC"},
0425 {"Left HP Mixer", "Mic Sidetone Switch", "Mic PGA"},
0426 {"Left HP Mixer", NULL, "ALC Sidetone Mux"},
0427
0428
0429 {"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
0430 {"Right HP Mixer", "Aux Playback Switch", "Aux DAC"},
0431 {"Right HP Mixer", "Phone Bypass Switch", "Phone PGA"},
0432 {"Right HP Mixer", "Line Bypass Switch", "Line PGA"},
0433 {"Right HP Mixer", "PCM Playback Switch", "Right DAC"},
0434 {"Right HP Mixer", "Mic Sidetone Switch", "Mic PGA"},
0435 {"Right HP Mixer", NULL, "ALC Sidetone Mux"},
0436
0437
0438 {"Speaker Mixer", "PCBeep Bypass Switch", "PCBEEP"},
0439 {"Speaker Mixer", "Line Bypass Switch", "Line PGA"},
0440 {"Speaker Mixer", "PCM Playback Switch", "AC97 Mixer"},
0441 {"Speaker Mixer", "Phone Bypass Switch", "Phone PGA"},
0442 {"Speaker Mixer", "Aux Playback Switch", "Aux DAC"},
0443
0444
0445 {"Phone Mixer", "PCBeep Bypass Switch", "PCBEEP"},
0446 {"Phone Mixer", "Line Bypass Switch", "Line PGA"},
0447 {"Phone Mixer", "Aux Playback Switch", "Aux DAC"},
0448 {"Phone Mixer", "PCM Playback Switch", "AC97 Mixer"},
0449 {"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"},
0450 {"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"},
0451
0452
0453 {"Line PGA", NULL, "LINEINL"},
0454 {"Line PGA", NULL, "LINEINR"},
0455 {"Phone PGA", NULL, "PHONE"},
0456 {"Mic PGA", NULL, "MIC1"},
0457 {"Mic PGA", NULL, "MIC2"},
0458
0459
0460 {"Differential Mic", NULL, "MIC1"},
0461 {"Differential Mic", NULL, "MIC2"},
0462 {"Left Mic Select Source", "Mic 1", "MIC1"},
0463 {"Left Mic Select Source", "Mic 2", "MIC2"},
0464 {"Left Mic Select Source", "Stereo", "MIC1"},
0465 {"Left Mic Select Source", "Differential", "Differential Mic"},
0466 {"Right Mic Select Source", "Mic 1", "MIC1"},
0467 {"Right Mic Select Source", "Mic 2", "MIC2"},
0468 {"Right Mic Select Source", "Stereo", "MIC2"},
0469 {"Right Mic Select Source", "Differential", "Differential Mic"},
0470
0471
0472 {"Left Capture Select", "Mic", "MIC1"},
0473 {"Left Capture Select", "Speaker Mixer", "Speaker Mixer"},
0474 {"Left Capture Select", "Line", "LINEINL"},
0475 {"Left Capture Select", "Headphone Mixer", "Left HP Mixer"},
0476 {"Left Capture Select", "Phone Mixer", "Phone Mixer"},
0477 {"Left Capture Select", "Phone", "PHONE"},
0478
0479
0480 {"Right Capture Select", "Mic", "MIC2"},
0481 {"Right Capture Select", "Speaker Mixer", "Speaker Mixer"},
0482 {"Right Capture Select", "Line", "LINEINR"},
0483 {"Right Capture Select", "Headphone Mixer", "Right HP Mixer"},
0484 {"Right Capture Select", "Phone Mixer", "Phone Mixer"},
0485 {"Right Capture Select", "Phone", "PHONE"},
0486
0487
0488 {"ALC Sidetone Mux", "Stereo", "Left Capture Select"},
0489 {"ALC Sidetone Mux", "Stereo", "Right Capture Select"},
0490 {"ALC Sidetone Mux", "Left", "Left Capture Select"},
0491 {"ALC Sidetone Mux", "Right", "Right Capture Select"},
0492
0493
0494 {"Left ADC", NULL, "Left Capture Select"},
0495 {"Right ADC", NULL, "Right Capture Select"},
0496
0497
0498 {"MONOOUT", NULL, "Phone Mixer"},
0499 {"HPOUTL", NULL, "Headphone PGA"},
0500 {"Headphone PGA", NULL, "Left HP Mixer"},
0501 {"HPOUTR", NULL, "Headphone PGA"},
0502 {"Headphone PGA", NULL, "Right HP Mixer"},
0503
0504
0505 {"Mono Mixer", NULL, "Left HP Mixer"},
0506 {"Mono Mixer", NULL, "Right HP Mixer"},
0507
0508
0509 {"Out3 Mux", "Left", "Left HP Mixer"},
0510 {"Out3 Mux", "Mono", "Phone Mixer"},
0511 {"Out3 Mux", "Left + Right", "Mono Mixer"},
0512 {"Out 3 PGA", NULL, "Out3 Mux"},
0513 {"OUT3", NULL, "Out 3 PGA"},
0514
0515
0516 {"Speaker Mux", "Speaker Mix", "Speaker Mixer"},
0517 {"Speaker Mux", "Headphone Mix", "Mono Mixer"},
0518 {"Speaker PGA", NULL, "Speaker Mux"},
0519 {"LOUT2", NULL, "Speaker PGA"},
0520 {"ROUT2", NULL, "Speaker PGA"},
0521 };
0522
0523 static int ac97_prepare(struct snd_pcm_substream *substream,
0524 struct snd_soc_dai *dai)
0525 {
0526 struct snd_soc_component *component = dai->component;
0527 int reg;
0528 struct snd_pcm_runtime *runtime = substream->runtime;
0529
0530 snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
0531
0532 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0533 reg = AC97_PCM_FRONT_DAC_RATE;
0534 else
0535 reg = AC97_PCM_LR_ADC_RATE;
0536
0537 return snd_soc_component_write(component, reg, runtime->rate);
0538 }
0539
0540 static int ac97_aux_prepare(struct snd_pcm_substream *substream,
0541 struct snd_soc_dai *dai)
0542 {
0543 struct snd_soc_component *component = dai->component;
0544 struct snd_pcm_runtime *runtime = substream->runtime;
0545
0546 snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
0547 snd_soc_component_update_bits(component, AC97_PCI_SID, 0x8000, 0x8000);
0548
0549 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
0550 return -ENODEV;
0551
0552 return snd_soc_component_write(component, AC97_PCM_SURR_DAC_RATE, runtime->rate);
0553 }
0554
0555 #define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
0556 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
0557 SNDRV_PCM_RATE_48000)
0558
0559 static const struct snd_soc_dai_ops wm9712_dai_ops_hifi = {
0560 .prepare = ac97_prepare,
0561 };
0562
0563 static const struct snd_soc_dai_ops wm9712_dai_ops_aux = {
0564 .prepare = ac97_aux_prepare,
0565 };
0566
0567 static struct snd_soc_dai_driver wm9712_dai[] = {
0568 {
0569 .name = "wm9712-hifi",
0570 .playback = {
0571 .stream_name = "HiFi Playback",
0572 .channels_min = 1,
0573 .channels_max = 2,
0574 .rates = WM9712_AC97_RATES,
0575 .formats = SND_SOC_STD_AC97_FMTS,},
0576 .capture = {
0577 .stream_name = "HiFi Capture",
0578 .channels_min = 1,
0579 .channels_max = 2,
0580 .rates = WM9712_AC97_RATES,
0581 .formats = SND_SOC_STD_AC97_FMTS,},
0582 .ops = &wm9712_dai_ops_hifi,
0583 },
0584 {
0585 .name = "wm9712-aux",
0586 .playback = {
0587 .stream_name = "Aux Playback",
0588 .channels_min = 1,
0589 .channels_max = 1,
0590 .rates = WM9712_AC97_RATES,
0591 .formats = SND_SOC_STD_AC97_FMTS,},
0592 .ops = &wm9712_dai_ops_aux,
0593 }
0594 };
0595
0596 static int wm9712_set_bias_level(struct snd_soc_component *component,
0597 enum snd_soc_bias_level level)
0598 {
0599 switch (level) {
0600 case SND_SOC_BIAS_ON:
0601 case SND_SOC_BIAS_PREPARE:
0602 break;
0603 case SND_SOC_BIAS_STANDBY:
0604 snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
0605 break;
0606 case SND_SOC_BIAS_OFF:
0607
0608 snd_soc_component_write(component, AC97_EXTENDED_MSTATUS, 0xffff);
0609 snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
0610 break;
0611 }
0612 return 0;
0613 }
0614
0615 static int wm9712_soc_resume(struct snd_soc_component *component)
0616 {
0617 struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
0618 int ret;
0619
0620 ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID,
0621 WM9712_VENDOR_ID_MASK);
0622 if (ret < 0)
0623 return ret;
0624
0625 snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
0626
0627 if (ret == 0)
0628 snd_soc_component_cache_sync(component);
0629
0630 return ret;
0631 }
0632
0633 static int wm9712_soc_probe(struct snd_soc_component *component)
0634 {
0635 struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
0636 struct regmap *regmap;
0637
0638 if (wm9712->mfd_pdata) {
0639 wm9712->ac97 = wm9712->mfd_pdata->ac97;
0640 regmap = wm9712->mfd_pdata->regmap;
0641 } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
0642 int ret;
0643
0644 wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
0645 WM9712_VENDOR_ID_MASK);
0646 if (IS_ERR(wm9712->ac97)) {
0647 ret = PTR_ERR(wm9712->ac97);
0648 dev_err(component->dev,
0649 "Failed to register AC97 codec: %d\n", ret);
0650 return ret;
0651 }
0652
0653 regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config);
0654 if (IS_ERR(regmap)) {
0655 snd_soc_free_ac97_component(wm9712->ac97);
0656 return PTR_ERR(regmap);
0657 }
0658 } else {
0659 return -ENXIO;
0660 }
0661
0662 snd_soc_component_init_regmap(component, regmap);
0663
0664
0665 snd_soc_component_update_bits(component, AC97_VIDEO, 0x3000, 0x3000);
0666
0667 return 0;
0668 }
0669
0670 static void wm9712_soc_remove(struct snd_soc_component *component)
0671 {
0672 struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
0673
0674 if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) {
0675 snd_soc_component_exit_regmap(component);
0676 snd_soc_free_ac97_component(wm9712->ac97);
0677 }
0678 }
0679
0680 static const struct snd_soc_component_driver soc_component_dev_wm9712 = {
0681 .probe = wm9712_soc_probe,
0682 .remove = wm9712_soc_remove,
0683 .resume = wm9712_soc_resume,
0684 .set_bias_level = wm9712_set_bias_level,
0685 .controls = wm9712_snd_ac97_controls,
0686 .num_controls = ARRAY_SIZE(wm9712_snd_ac97_controls),
0687 .dapm_widgets = wm9712_dapm_widgets,
0688 .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets),
0689 .dapm_routes = wm9712_audio_map,
0690 .num_dapm_routes = ARRAY_SIZE(wm9712_audio_map),
0691 .suspend_bias_off = 1,
0692 .idle_bias_on = 1,
0693 .use_pmdown_time = 1,
0694 .endianness = 1,
0695 };
0696
0697 static int wm9712_probe(struct platform_device *pdev)
0698 {
0699 struct wm9712_priv *wm9712;
0700
0701 wm9712 = devm_kzalloc(&pdev->dev, sizeof(*wm9712), GFP_KERNEL);
0702 if (wm9712 == NULL)
0703 return -ENOMEM;
0704
0705 mutex_init(&wm9712->lock);
0706
0707 wm9712->mfd_pdata = dev_get_platdata(&pdev->dev);
0708 platform_set_drvdata(pdev, wm9712);
0709
0710 return devm_snd_soc_register_component(&pdev->dev,
0711 &soc_component_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
0712 }
0713
0714 static struct platform_driver wm9712_component_driver = {
0715 .driver = {
0716 .name = "wm9712-codec",
0717 },
0718
0719 .probe = wm9712_probe,
0720 };
0721
0722 module_platform_driver(wm9712_component_driver);
0723
0724 MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
0725 MODULE_AUTHOR("Liam Girdwood");
0726 MODULE_LICENSE("GPL");