root/sound/soc/codecs/wm9712.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wm9712_volatile_reg
  2. wm9712_hp_mixer_put
  3. wm9712_hp_mixer_get
  4. ac97_prepare
  5. ac97_aux_prepare
  6. wm9712_set_bias_level
  7. wm9712_soc_resume
  8. wm9712_soc_probe
  9. wm9712_soc_remove
  10. wm9712_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * wm9712.c  --  ALSA Soc WM9712 codec support
   4  *
   5  * Copyright 2006-12 Wolfson Microelectronics PLC.
   6  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
   7  */
   8 
   9 #include <linux/init.h>
  10 #include <linux/slab.h>
  11 #include <linux/mfd/wm97xx.h>
  12 #include <linux/module.h>
  13 #include <linux/kernel.h>
  14 #include <linux/device.h>
  15 #include <linux/regmap.h>
  16 #include <sound/core.h>
  17 #include <sound/pcm.h>
  18 #include <sound/ac97_codec.h>
  19 #include <sound/ac97/codec.h>
  20 #include <sound/ac97/compat.h>
  21 #include <sound/initval.h>
  22 #include <sound/soc.h>
  23 #include <sound/tlv.h>
  24 
  25 #define WM9712_VENDOR_ID 0x574d4c12
  26 #define WM9712_VENDOR_ID_MASK 0xffffffff
  27 
  28 struct wm9712_priv {
  29         struct snd_ac97 *ac97;
  30         unsigned int hp_mixer[2];
  31         struct mutex lock;
  32         struct wm97xx_platform_data *mfd_pdata;
  33 };
  34 
  35 static const struct reg_default wm9712_reg_defaults[] = {
  36         { 0x02, 0x8000 },
  37         { 0x04, 0x8000 },
  38         { 0x06, 0x8000 },
  39         { 0x08, 0x0f0f },
  40         { 0x0a, 0xaaa0 },
  41         { 0x0c, 0xc008 },
  42         { 0x0e, 0x6808 },
  43         { 0x10, 0xe808 },
  44         { 0x12, 0xaaa0 },
  45         { 0x14, 0xad00 },
  46         { 0x16, 0x8000 },
  47         { 0x18, 0xe808 },
  48         { 0x1a, 0x3000 },
  49         { 0x1c, 0x8000 },
  50         { 0x20, 0x0000 },
  51         { 0x22, 0x0000 },
  52         { 0x26, 0x000f },
  53         { 0x28, 0x0605 },
  54         { 0x2a, 0x0410 },
  55         { 0x2c, 0xbb80 },
  56         { 0x2e, 0xbb80 },
  57         { 0x32, 0xbb80 },
  58         { 0x34, 0x2000 },
  59         { 0x4c, 0xf83e },
  60         { 0x4e, 0xffff },
  61         { 0x50, 0x0000 },
  62         { 0x52, 0x0000 },
  63         { 0x56, 0xf83e },
  64         { 0x58, 0x0008 },
  65         { 0x5c, 0x0000 },
  66         { 0x60, 0xb032 },
  67         { 0x62, 0x3e00 },
  68         { 0x64, 0x0000 },
  69         { 0x76, 0x0006 },
  70         { 0x78, 0x0001 },
  71         { 0x7a, 0x0000 },
  72 };
  73 
  74 static bool wm9712_volatile_reg(struct device *dev, unsigned int reg)
  75 {
  76         switch (reg) {
  77         case AC97_REC_GAIN:
  78                 return true;
  79         default:
  80                 return regmap_ac97_default_volatile(dev, reg);
  81         }
  82 }
  83 
  84 static const struct regmap_config wm9712_regmap_config = {
  85         .reg_bits = 16,
  86         .reg_stride = 2,
  87         .val_bits = 16,
  88         .max_register = 0x7e,
  89         .cache_type = REGCACHE_RBTREE,
  90 
  91         .volatile_reg = wm9712_volatile_reg,
  92 
  93         .reg_defaults = wm9712_reg_defaults,
  94         .num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults),
  95 };
  96 
  97 #define HPL_MIXER       0x0
  98 #define HPR_MIXER       0x1
  99 
 100 static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"};
 101 static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"};
 102 static const char *wm9712_out3_src[] = {"Left", "VREF", "Left + Right",
 103         "Mono"};
 104 static const char *wm9712_spk_src[] = {"Speaker Mix", "Headphone Mix"};
 105 static const char *wm9712_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
 106 static const char *wm9712_base[] = {"Linear Control", "Adaptive Boost"};
 107 static const char *wm9712_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
 108 static const char *wm9712_mic[] = {"Mic 1", "Differential", "Mic 2",
 109         "Stereo"};
 110 static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer",
 111         "Line", "Headphone Mixer", "Phone Mixer", "Phone"};
 112 static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"};
 113 static const char *wm9712_diff_sel[] = {"Mic", "Line"};
 114 
 115 static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0);
 116 static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 2000, 0);
 117 
 118 static const struct soc_enum wm9712_enum[] = {
 119 SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select),
 120 SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux),
 121 SOC_ENUM_SINGLE(AC97_AUX, 9, 4, wm9712_out3_src),
 122 SOC_ENUM_SINGLE(AC97_AUX, 8, 2, wm9712_spk_src),
 123 SOC_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9712_rec_adc),
 124 SOC_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9712_base),
 125 SOC_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9712_rec_gain),
 126 SOC_ENUM_SINGLE(AC97_MIC, 5, 4, wm9712_mic),
 127 SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9712_rec_sel),
 128 SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9712_rec_sel),
 129 SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9712_ng_type),
 130 SOC_ENUM_SINGLE(0x5c, 8, 2, wm9712_diff_sel),
 131 };
 132 
 133 static const struct snd_kcontrol_new wm9712_snd_ac97_controls[] = {
 134 SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
 135 SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1),
 136 SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
 137 SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
 138 SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
 139 
 140 SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
 141 SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0),
 142 SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0),
 143 SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
 144 SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
 145 SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
 146 
 147 SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
 148 SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
 149 SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
 150 SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
 151 SOC_ENUM("ALC Function", wm9712_enum[0]),
 152 SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
 153 SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
 154 SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
 155 SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
 156 SOC_ENUM("ALC NG Type", wm9712_enum[10]),
 157 SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
 158 
 159 SOC_SINGLE("Mic Headphone  Volume", AC97_VIDEO, 12, 7, 1),
 160 SOC_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
 161 
 162 SOC_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
 163 SOC_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
 164 SOC_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
 165 
 166 SOC_SINGLE("PCBeep Bypass Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
 167 SOC_SINGLE("PCBeep Bypass Speaker Volume", AC97_PC_BEEP, 8, 7, 1),
 168 SOC_SINGLE("PCBeep Bypass Phone Volume", AC97_PC_BEEP, 4, 7, 1),
 169 
 170 SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1),
 171 SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1),
 172 SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
 173 
 174 SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1),
 175 SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
 176 
 177 SOC_SINGLE_TLV("Capture Boost Switch", AC97_REC_SEL, 14, 1, 0, boost_tlv),
 178 SOC_SINGLE_TLV("Capture to Phone Boost Switch", AC97_REC_SEL, 11, 1, 1,
 179                boost_tlv),
 180 
 181 SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
 182 SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
 183 SOC_SINGLE("3D Playback Volume", AC97_3D_CONTROL, 0, 15, 0),
 184 
 185 SOC_ENUM("Bass Control", wm9712_enum[5]),
 186 SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
 187 SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
 188 SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
 189 SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),
 190 SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
 191 
 192 SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
 193 SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
 194 SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 0),
 195 SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
 196 
 197 SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv),
 198 SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv),
 199 SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv),
 200 };
 201 
 202 static const unsigned int wm9712_mixer_mute_regs[] = {
 203         AC97_VIDEO,
 204         AC97_PCM,
 205         AC97_LINE,
 206         AC97_PHONE,
 207         AC97_CD,
 208         AC97_PC_BEEP,
 209 };
 210 
 211 /* We have to create a fake left and right HP mixers because
 212  * the codec only has a single control that is shared by both channels.
 213  * This makes it impossible to determine the audio path.
 214  */
 215 static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
 216         struct snd_ctl_elem_value *ucontrol)
 217 {
 218         struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
 219         struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
 220         struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 221         unsigned int val = ucontrol->value.integer.value[0];
 222         struct soc_mixer_control *mc =
 223                 (struct soc_mixer_control *)kcontrol->private_value;
 224         unsigned int mixer, mask, shift, old;
 225         struct snd_soc_dapm_update update = {};
 226         bool change;
 227 
 228         mixer = mc->shift >> 8;
 229         shift = mc->shift & 0xff;
 230         mask = 1 << shift;
 231 
 232         mutex_lock(&wm9712->lock);
 233         old = wm9712->hp_mixer[mixer];
 234         if (ucontrol->value.integer.value[0])
 235                 wm9712->hp_mixer[mixer] |= mask;
 236         else
 237                 wm9712->hp_mixer[mixer] &= ~mask;
 238 
 239         change = old != wm9712->hp_mixer[mixer];
 240         if (change) {
 241                 update.kcontrol = kcontrol;
 242                 update.reg = wm9712_mixer_mute_regs[shift];
 243                 update.mask = 0x8000;
 244                 if ((wm9712->hp_mixer[0] & mask) ||
 245                     (wm9712->hp_mixer[1] & mask))
 246                         update.val = 0x0;
 247                 else
 248                         update.val = 0x8000;
 249 
 250                 snd_soc_dapm_mixer_update_power(dapm, kcontrol, val,
 251                         &update);
 252         }
 253 
 254         mutex_unlock(&wm9712->lock);
 255 
 256         return change;
 257 }
 258 
 259 static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
 260         struct snd_ctl_elem_value *ucontrol)
 261 {
 262         struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
 263         struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
 264         struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 265         struct soc_mixer_control *mc =
 266                 (struct soc_mixer_control *)kcontrol->private_value;
 267         unsigned int shift, mixer;
 268 
 269         mixer = mc->shift >> 8;
 270         shift = mc->shift & 0xff;
 271 
 272         ucontrol->value.integer.value[0] =
 273                 (wm9712->hp_mixer[mixer] >> shift) & 1;
 274 
 275         return 0;
 276 }
 277 
 278 #define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \
 279         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 280         .info = snd_soc_info_volsw, \
 281         .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \
 282         .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \
 283                 (xmixer << 8) | xshift, 1, 0, 0) \
 284 }
 285 
 286 /* Left Headphone Mixers */
 287 static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
 288         WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPL_MIXER, 5),
 289         WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 4),
 290         WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPL_MIXER, 3),
 291         WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPL_MIXER, 2),
 292         WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 1),
 293         WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPL_MIXER, 0),
 294 };
 295 
 296 /* Right Headphone Mixers */
 297 static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = {
 298         WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPR_MIXER, 5),
 299         WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 4),
 300         WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPR_MIXER, 3),
 301         WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPR_MIXER, 2),
 302         WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 1),
 303         WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPR_MIXER, 0),
 304 };
 305 
 306 /* Speaker Mixer */
 307 static const struct snd_kcontrol_new wm9712_speaker_mixer_controls[] = {
 308         SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 11, 1, 1),
 309         SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 11, 1, 1),
 310         SOC_DAPM_SINGLE("Phone Bypass Switch", AC97_PHONE, 14, 1, 1),
 311         SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 14, 1, 1),
 312         SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 14, 1, 1),
 313 };
 314 
 315 /* Phone Mixer */
 316 static const struct snd_kcontrol_new wm9712_phone_mixer_controls[] = {
 317         SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 7, 1, 1),
 318         SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 7, 1, 1),
 319         SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 13, 1, 1),
 320         SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 13, 1, 1),
 321         SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_MIC, 14, 1, 1),
 322         SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_MIC, 13, 1, 1),
 323 };
 324 
 325 /* ALC headphone mux */
 326 static const struct snd_kcontrol_new wm9712_alc_mux_controls =
 327 SOC_DAPM_ENUM("Route", wm9712_enum[1]);
 328 
 329 /* out 3 mux */
 330 static const struct snd_kcontrol_new wm9712_out3_mux_controls =
 331 SOC_DAPM_ENUM("Route", wm9712_enum[2]);
 332 
 333 /* spk mux */
 334 static const struct snd_kcontrol_new wm9712_spk_mux_controls =
 335 SOC_DAPM_ENUM("Route", wm9712_enum[3]);
 336 
 337 /* Capture to Phone mux */
 338 static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls =
 339 SOC_DAPM_ENUM("Route", wm9712_enum[4]);
 340 
 341 /* Capture left select */
 342 static const struct snd_kcontrol_new wm9712_capture_selectl_controls =
 343 SOC_DAPM_ENUM("Route", wm9712_enum[8]);
 344 
 345 /* Capture right select */
 346 static const struct snd_kcontrol_new wm9712_capture_selectr_controls =
 347 SOC_DAPM_ENUM("Route", wm9712_enum[9]);
 348 
 349 /* Mic select */
 350 static const struct snd_kcontrol_new wm9712_mic_src_controls =
 351 SOC_DAPM_ENUM("Mic Source Select", wm9712_enum[7]);
 352 
 353 /* diff select */
 354 static const struct snd_kcontrol_new wm9712_diff_sel_controls =
 355 SOC_DAPM_ENUM("Route", wm9712_enum[11]);
 356 
 357 static const struct snd_soc_dapm_widget wm9712_dapm_widgets[] = {
 358 SND_SOC_DAPM_MUX("ALC Sidetone Mux", SND_SOC_NOPM, 0, 0,
 359         &wm9712_alc_mux_controls),
 360 SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0,
 361         &wm9712_out3_mux_controls),
 362 SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0,
 363         &wm9712_spk_mux_controls),
 364 SND_SOC_DAPM_MUX("Capture Phone Mux", SND_SOC_NOPM, 0, 0,
 365         &wm9712_capture_phone_mux_controls),
 366 SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0,
 367         &wm9712_capture_selectl_controls),
 368 SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0,
 369         &wm9712_capture_selectr_controls),
 370 SND_SOC_DAPM_MUX("Left Mic Select Source", SND_SOC_NOPM, 0, 0,
 371         &wm9712_mic_src_controls),
 372 SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0,
 373         &wm9712_mic_src_controls),
 374 SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
 375         &wm9712_diff_sel_controls),
 376 SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 377 SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_INT_PAGING, 9, 1,
 378         &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls)),
 379 SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_INT_PAGING, 8, 1,
 380         &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls)),
 381 SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1,
 382         &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)),
 383 SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1,
 384         &wm9712_speaker_mixer_controls[0],
 385         ARRAY_SIZE(wm9712_speaker_mixer_controls)),
 386 SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 387 SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_INT_PAGING, 14, 1),
 388 SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_INT_PAGING, 13, 1),
 389 SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", SND_SOC_NOPM, 0, 0),
 390 SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_INT_PAGING, 12, 1),
 391 SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_INT_PAGING, 11, 1),
 392 SND_SOC_DAPM_PGA("Headphone PGA", AC97_INT_PAGING, 4, 1, NULL, 0),
 393 SND_SOC_DAPM_PGA("Speaker PGA", AC97_INT_PAGING, 3, 1, NULL, 0),
 394 SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0),
 395 SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0),
 396 SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0),
 397 SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0),
 398 SND_SOC_DAPM_PGA("Differential Mic", SND_SOC_NOPM, 0, 0, NULL, 0),
 399 SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1),
 400 SND_SOC_DAPM_OUTPUT("MONOOUT"),
 401 SND_SOC_DAPM_OUTPUT("HPOUTL"),
 402 SND_SOC_DAPM_OUTPUT("HPOUTR"),
 403 SND_SOC_DAPM_OUTPUT("LOUT2"),
 404 SND_SOC_DAPM_OUTPUT("ROUT2"),
 405 SND_SOC_DAPM_OUTPUT("OUT3"),
 406 SND_SOC_DAPM_INPUT("LINEINL"),
 407 SND_SOC_DAPM_INPUT("LINEINR"),
 408 SND_SOC_DAPM_INPUT("PHONE"),
 409 SND_SOC_DAPM_INPUT("PCBEEP"),
 410 SND_SOC_DAPM_INPUT("MIC1"),
 411 SND_SOC_DAPM_INPUT("MIC2"),
 412 };
 413 
 414 static const struct snd_soc_dapm_route wm9712_audio_map[] = {
 415         /* virtual mixer - mixes left & right channels for spk and mono */
 416         {"AC97 Mixer", NULL, "Left DAC"},
 417         {"AC97 Mixer", NULL, "Right DAC"},
 418 
 419         /* Left HP mixer */
 420         {"Left HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
 421         {"Left HP Mixer", "Aux Playback Switch",  "Aux DAC"},
 422         {"Left HP Mixer", "Phone Bypass Switch",  "Phone PGA"},
 423         {"Left HP Mixer", "Line Bypass Switch",   "Line PGA"},
 424         {"Left HP Mixer", "PCM Playback Switch",  "Left DAC"},
 425         {"Left HP Mixer", "Mic Sidetone Switch",  "Mic PGA"},
 426         {"Left HP Mixer", NULL,  "ALC Sidetone Mux"},
 427 
 428         /* Right HP mixer */
 429         {"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
 430         {"Right HP Mixer", "Aux Playback Switch",  "Aux DAC"},
 431         {"Right HP Mixer", "Phone Bypass Switch",  "Phone PGA"},
 432         {"Right HP Mixer", "Line Bypass Switch",   "Line PGA"},
 433         {"Right HP Mixer", "PCM Playback Switch",  "Right DAC"},
 434         {"Right HP Mixer", "Mic Sidetone Switch",  "Mic PGA"},
 435         {"Right HP Mixer", NULL,  "ALC Sidetone Mux"},
 436 
 437         /* speaker mixer */
 438         {"Speaker Mixer", "PCBeep Bypass Switch", "PCBEEP"},
 439         {"Speaker Mixer", "Line Bypass Switch",   "Line PGA"},
 440         {"Speaker Mixer", "PCM Playback Switch",  "AC97 Mixer"},
 441         {"Speaker Mixer", "Phone Bypass Switch",  "Phone PGA"},
 442         {"Speaker Mixer", "Aux Playback Switch",  "Aux DAC"},
 443 
 444         /* Phone mixer */
 445         {"Phone Mixer", "PCBeep Bypass Switch",  "PCBEEP"},
 446         {"Phone Mixer", "Line Bypass Switch",    "Line PGA"},
 447         {"Phone Mixer", "Aux Playback Switch",   "Aux DAC"},
 448         {"Phone Mixer", "PCM Playback Switch",   "AC97 Mixer"},
 449         {"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"},
 450         {"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"},
 451 
 452         /* inputs */
 453         {"Line PGA", NULL, "LINEINL"},
 454         {"Line PGA", NULL, "LINEINR"},
 455         {"Phone PGA", NULL, "PHONE"},
 456         {"Mic PGA", NULL, "MIC1"},
 457         {"Mic PGA", NULL, "MIC2"},
 458 
 459         /* microphones */
 460         {"Differential Mic", NULL, "MIC1"},
 461         {"Differential Mic", NULL, "MIC2"},
 462         {"Left Mic Select Source", "Mic 1", "MIC1"},
 463         {"Left Mic Select Source", "Mic 2", "MIC2"},
 464         {"Left Mic Select Source", "Stereo", "MIC1"},
 465         {"Left Mic Select Source", "Differential", "Differential Mic"},
 466         {"Right Mic Select Source", "Mic 1", "MIC1"},
 467         {"Right Mic Select Source", "Mic 2", "MIC2"},
 468         {"Right Mic Select Source", "Stereo", "MIC2"},
 469         {"Right Mic Select Source", "Differential", "Differential Mic"},
 470 
 471         /* left capture selector */
 472         {"Left Capture Select", "Mic", "MIC1"},
 473         {"Left Capture Select", "Speaker Mixer", "Speaker Mixer"},
 474         {"Left Capture Select", "Line", "LINEINL"},
 475         {"Left Capture Select", "Headphone Mixer", "Left HP Mixer"},
 476         {"Left Capture Select", "Phone Mixer", "Phone Mixer"},
 477         {"Left Capture Select", "Phone", "PHONE"},
 478 
 479         /* right capture selector */
 480         {"Right Capture Select", "Mic", "MIC2"},
 481         {"Right Capture Select", "Speaker Mixer", "Speaker Mixer"},
 482         {"Right Capture Select", "Line", "LINEINR"},
 483         {"Right Capture Select", "Headphone Mixer", "Right HP Mixer"},
 484         {"Right Capture Select", "Phone Mixer", "Phone Mixer"},
 485         {"Right Capture Select", "Phone", "PHONE"},
 486 
 487         /* ALC Sidetone */
 488         {"ALC Sidetone Mux", "Stereo", "Left Capture Select"},
 489         {"ALC Sidetone Mux", "Stereo", "Right Capture Select"},
 490         {"ALC Sidetone Mux", "Left", "Left Capture Select"},
 491         {"ALC Sidetone Mux", "Right", "Right Capture Select"},
 492 
 493         /* ADC's */
 494         {"Left ADC", NULL, "Left Capture Select"},
 495         {"Right ADC", NULL, "Right Capture Select"},
 496 
 497         /* outputs */
 498         {"MONOOUT", NULL, "Phone Mixer"},
 499         {"HPOUTL", NULL, "Headphone PGA"},
 500         {"Headphone PGA", NULL, "Left HP Mixer"},
 501         {"HPOUTR", NULL, "Headphone PGA"},
 502         {"Headphone PGA", NULL, "Right HP Mixer"},
 503 
 504         /* mono mixer */
 505         {"Mono Mixer", NULL, "Left HP Mixer"},
 506         {"Mono Mixer", NULL, "Right HP Mixer"},
 507 
 508         /* Out3 Mux */
 509         {"Out3 Mux", "Left", "Left HP Mixer"},
 510         {"Out3 Mux", "Mono", "Phone Mixer"},
 511         {"Out3 Mux", "Left + Right", "Mono Mixer"},
 512         {"Out 3 PGA", NULL, "Out3 Mux"},
 513         {"OUT3", NULL, "Out 3 PGA"},
 514 
 515         /* speaker Mux */
 516         {"Speaker Mux", "Speaker Mix", "Speaker Mixer"},
 517         {"Speaker Mux", "Headphone Mix", "Mono Mixer"},
 518         {"Speaker PGA", NULL, "Speaker Mux"},
 519         {"LOUT2", NULL, "Speaker PGA"},
 520         {"ROUT2", NULL, "Speaker PGA"},
 521 };
 522 
 523 static int ac97_prepare(struct snd_pcm_substream *substream,
 524                         struct snd_soc_dai *dai)
 525 {
 526         struct snd_soc_component *component = dai->component;
 527         int reg;
 528         struct snd_pcm_runtime *runtime = substream->runtime;
 529 
 530         snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
 531 
 532         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 533                 reg = AC97_PCM_FRONT_DAC_RATE;
 534         else
 535                 reg = AC97_PCM_LR_ADC_RATE;
 536 
 537         return snd_soc_component_write(component, reg, runtime->rate);
 538 }
 539 
 540 static int ac97_aux_prepare(struct snd_pcm_substream *substream,
 541                             struct snd_soc_dai *dai)
 542 {
 543         struct snd_soc_component *component = dai->component;
 544         struct snd_pcm_runtime *runtime = substream->runtime;
 545 
 546         snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
 547         snd_soc_component_update_bits(component, AC97_PCI_SID, 0x8000, 0x8000);
 548 
 549         if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 550                 return -ENODEV;
 551 
 552         return snd_soc_component_write(component, AC97_PCM_SURR_DAC_RATE, runtime->rate);
 553 }
 554 
 555 #define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
 556                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
 557                 SNDRV_PCM_RATE_48000)
 558 
 559 static const struct snd_soc_dai_ops wm9712_dai_ops_hifi = {
 560         .prepare        = ac97_prepare,
 561 };
 562 
 563 static const struct snd_soc_dai_ops wm9712_dai_ops_aux = {
 564         .prepare        = ac97_aux_prepare,
 565 };
 566 
 567 static struct snd_soc_dai_driver wm9712_dai[] = {
 568 {
 569         .name = "wm9712-hifi",
 570         .playback = {
 571                 .stream_name = "HiFi Playback",
 572                 .channels_min = 1,
 573                 .channels_max = 2,
 574                 .rates = WM9712_AC97_RATES,
 575                 .formats = SND_SOC_STD_AC97_FMTS,},
 576         .capture = {
 577                 .stream_name = "HiFi Capture",
 578                 .channels_min = 1,
 579                 .channels_max = 2,
 580                 .rates = WM9712_AC97_RATES,
 581                 .formats = SND_SOC_STD_AC97_FMTS,},
 582         .ops = &wm9712_dai_ops_hifi,
 583 },
 584 {
 585         .name = "wm9712-aux",
 586         .playback = {
 587                 .stream_name = "Aux Playback",
 588                 .channels_min = 1,
 589                 .channels_max = 1,
 590                 .rates = WM9712_AC97_RATES,
 591                 .formats = SND_SOC_STD_AC97_FMTS,},
 592         .ops = &wm9712_dai_ops_aux,
 593 }
 594 };
 595 
 596 static int wm9712_set_bias_level(struct snd_soc_component *component,
 597                                  enum snd_soc_bias_level level)
 598 {
 599         switch (level) {
 600         case SND_SOC_BIAS_ON:
 601         case SND_SOC_BIAS_PREPARE:
 602                 break;
 603         case SND_SOC_BIAS_STANDBY:
 604                 snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
 605                 break;
 606         case SND_SOC_BIAS_OFF:
 607                 /* disable everything including AC link */
 608                 snd_soc_component_write(component, AC97_EXTENDED_MSTATUS, 0xffff);
 609                 snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
 610                 break;
 611         }
 612         return 0;
 613 }
 614 
 615 static int wm9712_soc_resume(struct snd_soc_component *component)
 616 {
 617         struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 618         int ret;
 619 
 620         ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID,
 621                 WM9712_VENDOR_ID_MASK);
 622         if (ret < 0)
 623                 return ret;
 624 
 625         snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 626 
 627         if (ret == 0)
 628                 snd_soc_component_cache_sync(component);
 629 
 630         return ret;
 631 }
 632 
 633 static int wm9712_soc_probe(struct snd_soc_component *component)
 634 {
 635         struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 636         struct regmap *regmap;
 637 
 638         if (wm9712->mfd_pdata) {
 639                 wm9712->ac97 = wm9712->mfd_pdata->ac97;
 640                 regmap = wm9712->mfd_pdata->regmap;
 641         } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
 642                 int ret;
 643 
 644                 wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
 645                                                       WM9712_VENDOR_ID_MASK);
 646                 if (IS_ERR(wm9712->ac97)) {
 647                         ret = PTR_ERR(wm9712->ac97);
 648                         dev_err(component->dev,
 649                                 "Failed to register AC97 codec: %d\n", ret);
 650                         return ret;
 651                 }
 652 
 653                 regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config);
 654                 if (IS_ERR(regmap)) {
 655                         snd_soc_free_ac97_component(wm9712->ac97);
 656                         return PTR_ERR(regmap);
 657                 }
 658         } else {
 659                 return -ENXIO;
 660         }
 661 
 662         snd_soc_component_init_regmap(component, regmap);
 663 
 664         /* set alc mux to none */
 665         snd_soc_component_update_bits(component, AC97_VIDEO, 0x3000, 0x3000);
 666 
 667         return 0;
 668 }
 669 
 670 static void wm9712_soc_remove(struct snd_soc_component *component)
 671 {
 672         struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 673 
 674         if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) {
 675                 snd_soc_component_exit_regmap(component);
 676                 snd_soc_free_ac97_component(wm9712->ac97);
 677         }
 678 }
 679 
 680 static const struct snd_soc_component_driver soc_component_dev_wm9712 = {
 681         .probe                  = wm9712_soc_probe,
 682         .remove                 = wm9712_soc_remove,
 683         .resume                 = wm9712_soc_resume,
 684         .set_bias_level         = wm9712_set_bias_level,
 685         .controls               = wm9712_snd_ac97_controls,
 686         .num_controls           = ARRAY_SIZE(wm9712_snd_ac97_controls),
 687         .dapm_widgets           = wm9712_dapm_widgets,
 688         .num_dapm_widgets       = ARRAY_SIZE(wm9712_dapm_widgets),
 689         .dapm_routes            = wm9712_audio_map,
 690         .num_dapm_routes        = ARRAY_SIZE(wm9712_audio_map),
 691         .suspend_bias_off       = 1,
 692         .idle_bias_on           = 1,
 693         .use_pmdown_time        = 1,
 694         .endianness             = 1,
 695         .non_legacy_dai_naming  = 1,
 696 };
 697 
 698 static int wm9712_probe(struct platform_device *pdev)
 699 {
 700         struct wm9712_priv *wm9712;
 701 
 702         wm9712 = devm_kzalloc(&pdev->dev, sizeof(*wm9712), GFP_KERNEL);
 703         if (wm9712 == NULL)
 704                 return -ENOMEM;
 705 
 706         mutex_init(&wm9712->lock);
 707 
 708         wm9712->mfd_pdata = dev_get_platdata(&pdev->dev);
 709         platform_set_drvdata(pdev, wm9712);
 710 
 711         return devm_snd_soc_register_component(&pdev->dev,
 712                         &soc_component_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
 713 }
 714 
 715 static struct platform_driver wm9712_component_driver = {
 716         .driver = {
 717                 .name = "wm9712-codec",
 718         },
 719 
 720         .probe = wm9712_probe,
 721 };
 722 
 723 module_platform_driver(wm9712_component_driver);
 724 
 725 MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
 726 MODULE_AUTHOR("Liam Girdwood");
 727 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */