Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * wm9712.c  --  ALSA Soc WM9712 codec support
0004  *
0005  * Copyright 2006-12 Wolfson Microelectronics PLC.
0006  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
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 /* We have to create a fake left and right HP mixers because
0212  * the codec only has a single control that is shared by both channels.
0213  * This makes it impossible to determine the audio path.
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 /* Left Headphone Mixers */
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 /* Right Headphone Mixers */
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 /* Speaker Mixer */
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 /* Phone Mixer */
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 /* ALC headphone mux */
0326 static const struct snd_kcontrol_new wm9712_alc_mux_controls =
0327 SOC_DAPM_ENUM("Route", wm9712_enum[1]);
0328 
0329 /* out 3 mux */
0330 static const struct snd_kcontrol_new wm9712_out3_mux_controls =
0331 SOC_DAPM_ENUM("Route", wm9712_enum[2]);
0332 
0333 /* spk mux */
0334 static const struct snd_kcontrol_new wm9712_spk_mux_controls =
0335 SOC_DAPM_ENUM("Route", wm9712_enum[3]);
0336 
0337 /* Capture to Phone mux */
0338 static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls =
0339 SOC_DAPM_ENUM("Route", wm9712_enum[4]);
0340 
0341 /* Capture left select */
0342 static const struct snd_kcontrol_new wm9712_capture_selectl_controls =
0343 SOC_DAPM_ENUM("Route", wm9712_enum[8]);
0344 
0345 /* Capture right select */
0346 static const struct snd_kcontrol_new wm9712_capture_selectr_controls =
0347 SOC_DAPM_ENUM("Route", wm9712_enum[9]);
0348 
0349 /* Mic select */
0350 static const struct snd_kcontrol_new wm9712_mic_src_controls =
0351 SOC_DAPM_ENUM("Mic Source Select", wm9712_enum[7]);
0352 
0353 /* diff select */
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     /* virtual mixer - mixes left & right channels for spk and mono */
0416     {"AC97 Mixer", NULL, "Left DAC"},
0417     {"AC97 Mixer", NULL, "Right DAC"},
0418 
0419     /* Left HP mixer */
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     /* Right HP mixer */
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     /* speaker mixer */
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     /* Phone mixer */
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     /* inputs */
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     /* microphones */
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     /* left capture selector */
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     /* right capture selector */
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     /* ALC Sidetone */
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     /* ADC's */
0494     {"Left ADC", NULL, "Left Capture Select"},
0495     {"Right ADC", NULL, "Right Capture Select"},
0496 
0497     /* outputs */
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     /* mono mixer */
0505     {"Mono Mixer", NULL, "Left HP Mixer"},
0506     {"Mono Mixer", NULL, "Right HP Mixer"},
0507 
0508     /* Out3 Mux */
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     /* speaker Mux */
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         /* disable everything including AC link */
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     /* set alc mux to none */
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");