Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * HD audio interface patch for Cirrus Logic CS420x chip
0004  *
0005  * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
0006  */
0007 
0008 #include <linux/init.h>
0009 #include <linux/slab.h>
0010 #include <linux/module.h>
0011 #include <sound/core.h>
0012 #include <linux/pci.h>
0013 #include <sound/tlv.h>
0014 #include <sound/hda_codec.h>
0015 #include "hda_local.h"
0016 #include "hda_auto_parser.h"
0017 #include "hda_jack.h"
0018 #include "hda_generic.h"
0019 
0020 /*
0021  */
0022 
0023 struct cs_spec {
0024     struct hda_gen_spec gen;
0025 
0026     unsigned int gpio_mask;
0027     unsigned int gpio_dir;
0028     unsigned int gpio_data;
0029     unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
0030     unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
0031 
0032     /* CS421x */
0033     unsigned int spdif_detect:1;
0034     unsigned int spdif_present:1;
0035     unsigned int sense_b:1;
0036     hda_nid_t vendor_nid;
0037 
0038     /* for MBP SPDIF control */
0039     int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
0040                 struct snd_ctl_elem_value *ucontrol);
0041 };
0042 
0043 /* available models with CS420x */
0044 enum {
0045     CS420X_MBP53,
0046     CS420X_MBP55,
0047     CS420X_IMAC27,
0048     CS420X_GPIO_13,
0049     CS420X_GPIO_23,
0050     CS420X_MBP101,
0051     CS420X_MBP81,
0052     CS420X_MBA42,
0053     CS420X_AUTO,
0054     /* aliases */
0055     CS420X_IMAC27_122 = CS420X_GPIO_23,
0056     CS420X_APPLE = CS420X_GPIO_13,
0057 };
0058 
0059 /* CS421x boards */
0060 enum {
0061     CS421X_CDB4210,
0062     CS421X_SENSE_B,
0063     CS421X_STUMPY,
0064 };
0065 
0066 /* Vendor-specific processing widget */
0067 #define CS420X_VENDOR_NID   0x11
0068 #define CS_DIG_OUT1_PIN_NID 0x10
0069 #define CS_DIG_OUT2_PIN_NID 0x15
0070 #define CS_DMIC1_PIN_NID    0x0e
0071 #define CS_DMIC2_PIN_NID    0x12
0072 
0073 /* coef indices */
0074 #define IDX_SPDIF_STAT      0x0000
0075 #define IDX_SPDIF_CTL       0x0001
0076 #define IDX_ADC_CFG     0x0002
0077 /* SZC bitmask, 4 modes below:
0078  * 0 = immediate,
0079  * 1 = digital immediate, analog zero-cross
0080  * 2 = digtail & analog soft-ramp
0081  * 3 = digital soft-ramp, analog zero-cross
0082  */
0083 #define   CS_COEF_ADC_SZC_MASK      (3 << 0)
0084 #define   CS_COEF_ADC_MIC_SZC_MODE  (3 << 0) /* SZC setup for mic */
0085 #define   CS_COEF_ADC_LI_SZC_MODE   (3 << 0) /* SZC setup for line-in */
0086 /* PGA mode: 0 = differential, 1 = signle-ended */
0087 #define   CS_COEF_ADC_MIC_PGA_MODE  (1 << 5) /* PGA setup for mic */
0088 #define   CS_COEF_ADC_LI_PGA_MODE   (1 << 6) /* PGA setup for line-in */
0089 #define IDX_DAC_CFG     0x0003
0090 /* SZC bitmask, 4 modes below:
0091  * 0 = Immediate
0092  * 1 = zero-cross
0093  * 2 = soft-ramp
0094  * 3 = soft-ramp on zero-cross
0095  */
0096 #define   CS_COEF_DAC_HP_SZC_MODE   (3 << 0) /* nid 0x02 */
0097 #define   CS_COEF_DAC_LO_SZC_MODE   (3 << 2) /* nid 0x03 */
0098 #define   CS_COEF_DAC_SPK_SZC_MODE  (3 << 4) /* nid 0x04 */
0099 
0100 #define IDX_BEEP_CFG        0x0004
0101 /* 0x0008 - test reg key */
0102 /* 0x0009 - 0x0014 -> 12 test regs */
0103 /* 0x0015 - visibility reg */
0104 
0105 /* Cirrus Logic CS4208 */
0106 #define CS4208_VENDOR_NID   0x24
0107 
0108 /*
0109  * Cirrus Logic CS4210
0110  *
0111  * 1 DAC => HP(sense) / Speakers,
0112  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
0113  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
0114  */
0115 #define CS4210_DAC_NID      0x02
0116 #define CS4210_ADC_NID      0x03
0117 #define CS4210_VENDOR_NID   0x0B
0118 #define CS421X_DMIC_PIN_NID 0x09 /* Port E */
0119 #define CS421X_SPDIF_PIN_NID    0x0A /* Port H */
0120 
0121 #define CS421X_IDX_DEV_CFG  0x01
0122 #define CS421X_IDX_ADC_CFG  0x02
0123 #define CS421X_IDX_DAC_CFG  0x03
0124 #define CS421X_IDX_SPK_CTL  0x04
0125 
0126 /* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
0127 #define CS4213_VENDOR_NID   0x09
0128 
0129 
0130 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
0131 {
0132     struct cs_spec *spec = codec->spec;
0133 
0134     snd_hda_codec_write(codec, spec->vendor_nid, 0,
0135                 AC_VERB_SET_COEF_INDEX, idx);
0136     return snd_hda_codec_read(codec, spec->vendor_nid, 0,
0137                   AC_VERB_GET_PROC_COEF, 0);
0138 }
0139 
0140 static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
0141                       unsigned int coef)
0142 {
0143     struct cs_spec *spec = codec->spec;
0144 
0145     snd_hda_codec_write(codec, spec->vendor_nid, 0,
0146                 AC_VERB_SET_COEF_INDEX, idx);
0147     snd_hda_codec_write(codec, spec->vendor_nid, 0,
0148                 AC_VERB_SET_PROC_COEF, coef);
0149 }
0150 
0151 /*
0152  * auto-mute and auto-mic switching
0153  * CS421x auto-output redirecting
0154  * HP/SPK/SPDIF
0155  */
0156 
0157 static void cs_automute(struct hda_codec *codec)
0158 {
0159     struct cs_spec *spec = codec->spec;
0160 
0161     /* mute HPs if spdif jack (SENSE_B) is present */
0162     spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b);
0163 
0164     snd_hda_gen_update_outputs(codec);
0165 
0166     if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
0167         if (spec->gen.automute_speaker)
0168             spec->gpio_data = spec->gen.hp_jack_present ?
0169                 spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
0170         else
0171             spec->gpio_data =
0172                 spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
0173         snd_hda_codec_write(codec, 0x01, 0,
0174                     AC_VERB_SET_GPIO_DATA, spec->gpio_data);
0175     }
0176 }
0177 
0178 static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
0179 {
0180     unsigned int val;
0181 
0182     val = snd_hda_codec_get_pincfg(codec, nid);
0183     return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
0184 }
0185 
0186 static void init_input_coef(struct hda_codec *codec)
0187 {
0188     struct cs_spec *spec = codec->spec;
0189     unsigned int coef;
0190 
0191     /* CS420x has multiple ADC, CS421x has single ADC */
0192     if (spec->vendor_nid == CS420X_VENDOR_NID) {
0193         coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG);
0194         if (is_active_pin(codec, CS_DMIC2_PIN_NID))
0195             coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */
0196         if (is_active_pin(codec, CS_DMIC1_PIN_NID))
0197             coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
0198                      * No effect if SPDIF_OUT2 is
0199                      * selected in IDX_SPDIF_CTL.
0200                      */
0201 
0202         cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
0203     }
0204 }
0205 
0206 static const struct hda_verb cs_coef_init_verbs[] = {
0207     {0x11, AC_VERB_SET_PROC_STATE, 1},
0208     {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
0209     {0x11, AC_VERB_SET_PROC_COEF,
0210      (0x002a /* DAC1/2/3 SZCMode Soft Ramp */
0211       | 0x0040 /* Mute DACs on FIFO error */
0212       | 0x1000 /* Enable DACs High Pass Filter */
0213       | 0x0400 /* Disable Coefficient Auto increment */
0214       )},
0215     /* ADC1/2 - Digital and Analog Soft Ramp */
0216     {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG},
0217     {0x11, AC_VERB_SET_PROC_COEF, 0x000a},
0218     /* Beep */
0219     {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG},
0220     {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */
0221 
0222     {} /* terminator */
0223 };
0224 
0225 static const struct hda_verb cs4208_coef_init_verbs[] = {
0226     {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
0227     {0x24, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
0228     {0x24, AC_VERB_SET_COEF_INDEX, 0x0033},
0229     {0x24, AC_VERB_SET_PROC_COEF, 0x0001}, /* A1 ICS */
0230     {0x24, AC_VERB_SET_COEF_INDEX, 0x0034},
0231     {0x24, AC_VERB_SET_PROC_COEF, 0x1C01}, /* A1 Enable, A Thresh = 300mV */
0232     {} /* terminator */
0233 };
0234 
0235 /* Errata: CS4207 rev C0/C1/C2 Silicon
0236  *
0237  * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf
0238  *
0239  * 6. At high temperature (TA > +85°C), the digital supply current (IVD)
0240  * may be excessive (up to an additional 200 μA), which is most easily
0241  * observed while the part is being held in reset (RESET# active low).
0242  *
0243  * Root Cause: At initial powerup of the device, the logic that drives
0244  * the clock and write enable to the S/PDIF SRC RAMs is not properly
0245  * initialized.
0246  * Certain random patterns will cause a steady leakage current in those
0247  * RAM cells. The issue will resolve once the SRCs are used (turned on).
0248  *
0249  * Workaround: The following verb sequence briefly turns on the S/PDIF SRC
0250  * blocks, which will alleviate the issue.
0251  */
0252 
0253 static const struct hda_verb cs_errata_init_verbs[] = {
0254     {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
0255     {0x11, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
0256 
0257     {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
0258     {0x11, AC_VERB_SET_PROC_COEF, 0x9999},
0259     {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
0260     {0x11, AC_VERB_SET_PROC_COEF, 0xa412},
0261     {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
0262     {0x11, AC_VERB_SET_PROC_COEF, 0x0009},
0263 
0264     {0x07, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Rx: D0 */
0265     {0x08, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Tx: D0 */
0266 
0267     {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
0268     {0x11, AC_VERB_SET_PROC_COEF, 0x2412},
0269     {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
0270     {0x11, AC_VERB_SET_PROC_COEF, 0x0000},
0271     {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
0272     {0x11, AC_VERB_SET_PROC_COEF, 0x0008},
0273     {0x11, AC_VERB_SET_PROC_STATE, 0x00},
0274     {} /* terminator */
0275 };
0276 
0277 /* SPDIF setup */
0278 static void init_digital_coef(struct hda_codec *codec)
0279 {
0280     unsigned int coef;
0281 
0282     coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */
0283     coef |= 0x0008; /* Replace with mute on error */
0284     if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID))
0285         coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2
0286                  * SPDIF_OUT2 is shared with GPIO1 and
0287                  * DMIC_SDA2.
0288                  */
0289     cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef);
0290 }
0291 
0292 static int cs_init(struct hda_codec *codec)
0293 {
0294     struct cs_spec *spec = codec->spec;
0295 
0296     if (spec->vendor_nid == CS420X_VENDOR_NID) {
0297         /* init_verb sequence for C0/C1/C2 errata*/
0298         snd_hda_sequence_write(codec, cs_errata_init_verbs);
0299         snd_hda_sequence_write(codec, cs_coef_init_verbs);
0300     } else if (spec->vendor_nid == CS4208_VENDOR_NID) {
0301         snd_hda_sequence_write(codec, cs4208_coef_init_verbs);
0302     }
0303 
0304     snd_hda_gen_init(codec);
0305 
0306     if (spec->gpio_mask) {
0307         snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
0308                     spec->gpio_mask);
0309         snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
0310                     spec->gpio_dir);
0311         snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
0312                     spec->gpio_data);
0313     }
0314 
0315     if (spec->vendor_nid == CS420X_VENDOR_NID) {
0316         init_input_coef(codec);
0317         init_digital_coef(codec);
0318     }
0319 
0320     return 0;
0321 }
0322 
0323 static int cs_build_controls(struct hda_codec *codec)
0324 {
0325     int err;
0326 
0327     err = snd_hda_gen_build_controls(codec);
0328     if (err < 0)
0329         return err;
0330     snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
0331     return 0;
0332 }
0333 
0334 #define cs_free     snd_hda_gen_free
0335 
0336 static const struct hda_codec_ops cs_patch_ops = {
0337     .build_controls = cs_build_controls,
0338     .build_pcms = snd_hda_gen_build_pcms,
0339     .init = cs_init,
0340     .free = cs_free,
0341     .unsol_event = snd_hda_jack_unsol_event,
0342 };
0343 
0344 static int cs_parse_auto_config(struct hda_codec *codec)
0345 {
0346     struct cs_spec *spec = codec->spec;
0347     int err;
0348     int i;
0349 
0350     err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
0351     if (err < 0)
0352         return err;
0353 
0354     err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
0355     if (err < 0)
0356         return err;
0357 
0358     /* keep the ADCs powered up when it's dynamically switchable */
0359     if (spec->gen.dyn_adc_switch) {
0360         unsigned int done = 0;
0361 
0362         for (i = 0; i < spec->gen.input_mux.num_items; i++) {
0363             int idx = spec->gen.dyn_adc_idx[i];
0364 
0365             if (done & (1 << idx))
0366                 continue;
0367             snd_hda_gen_fix_pin_power(codec,
0368                           spec->gen.adc_nids[idx]);
0369             done |= 1 << idx;
0370         }
0371     }
0372 
0373     return 0;
0374 }
0375 
0376 static const struct hda_model_fixup cs420x_models[] = {
0377     { .id = CS420X_MBP53, .name = "mbp53" },
0378     { .id = CS420X_MBP55, .name = "mbp55" },
0379     { .id = CS420X_IMAC27, .name = "imac27" },
0380     { .id = CS420X_IMAC27_122, .name = "imac27_122" },
0381     { .id = CS420X_APPLE, .name = "apple" },
0382     { .id = CS420X_MBP101, .name = "mbp101" },
0383     { .id = CS420X_MBP81, .name = "mbp81" },
0384     { .id = CS420X_MBA42, .name = "mba42" },
0385     {}
0386 };
0387 
0388 static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
0389     SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
0390     SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
0391     SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
0392     SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
0393     /* this conflicts with too many other models */
0394     /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
0395 
0396     /* codec SSID */
0397     SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122),
0398     SND_PCI_QUIRK(0x106b, 0x0900, "iMac 12,1", CS420X_IMAC27_122),
0399     SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
0400     SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
0401     SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
0402     SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81),
0403     SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
0404     SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
0405     {} /* terminator */
0406 };
0407 
0408 static const struct hda_pintbl mbp53_pincfgs[] = {
0409     { 0x09, 0x012b4050 },
0410     { 0x0a, 0x90100141 },
0411     { 0x0b, 0x90100140 },
0412     { 0x0c, 0x018b3020 },
0413     { 0x0d, 0x90a00110 },
0414     { 0x0e, 0x400000f0 },
0415     { 0x0f, 0x01cbe030 },
0416     { 0x10, 0x014be060 },
0417     { 0x12, 0x400000f0 },
0418     { 0x15, 0x400000f0 },
0419     {} /* terminator */
0420 };
0421 
0422 static const struct hda_pintbl mbp55_pincfgs[] = {
0423     { 0x09, 0x012b4030 },
0424     { 0x0a, 0x90100121 },
0425     { 0x0b, 0x90100120 },
0426     { 0x0c, 0x400000f0 },
0427     { 0x0d, 0x90a00110 },
0428     { 0x0e, 0x400000f0 },
0429     { 0x0f, 0x400000f0 },
0430     { 0x10, 0x014be040 },
0431     { 0x12, 0x400000f0 },
0432     { 0x15, 0x400000f0 },
0433     {} /* terminator */
0434 };
0435 
0436 static const struct hda_pintbl imac27_pincfgs[] = {
0437     { 0x09, 0x012b4050 },
0438     { 0x0a, 0x90100140 },
0439     { 0x0b, 0x90100142 },
0440     { 0x0c, 0x018b3020 },
0441     { 0x0d, 0x90a00110 },
0442     { 0x0e, 0x400000f0 },
0443     { 0x0f, 0x01cbe030 },
0444     { 0x10, 0x014be060 },
0445     { 0x12, 0x01ab9070 },
0446     { 0x15, 0x400000f0 },
0447     {} /* terminator */
0448 };
0449 
0450 static const struct hda_pintbl mbp101_pincfgs[] = {
0451     { 0x0d, 0x40ab90f0 },
0452     { 0x0e, 0x90a600f0 },
0453     { 0x12, 0x50a600f0 },
0454     {} /* terminator */
0455 };
0456 
0457 static const struct hda_pintbl mba42_pincfgs[] = {
0458     { 0x09, 0x012b4030 }, /* HP */
0459     { 0x0a, 0x400000f0 },
0460     { 0x0b, 0x90100120 }, /* speaker */
0461     { 0x0c, 0x400000f0 },
0462     { 0x0d, 0x90a00110 }, /* mic */
0463     { 0x0e, 0x400000f0 },
0464     { 0x0f, 0x400000f0 },
0465     { 0x10, 0x400000f0 },
0466     { 0x12, 0x400000f0 },
0467     { 0x15, 0x400000f0 },
0468     {} /* terminator */
0469 };
0470 
0471 static const struct hda_pintbl mba6_pincfgs[] = {
0472     { 0x10, 0x032120f0 }, /* HP */
0473     { 0x11, 0x500000f0 },
0474     { 0x12, 0x90100010 }, /* Speaker */
0475     { 0x13, 0x500000f0 },
0476     { 0x14, 0x500000f0 },
0477     { 0x15, 0x770000f0 },
0478     { 0x16, 0x770000f0 },
0479     { 0x17, 0x430000f0 },
0480     { 0x18, 0x43ab9030 }, /* Mic */
0481     { 0x19, 0x770000f0 },
0482     { 0x1a, 0x770000f0 },
0483     { 0x1b, 0x770000f0 },
0484     { 0x1c, 0x90a00090 },
0485     { 0x1d, 0x500000f0 },
0486     { 0x1e, 0x500000f0 },
0487     { 0x1f, 0x500000f0 },
0488     { 0x20, 0x500000f0 },
0489     { 0x21, 0x430000f0 },
0490     { 0x22, 0x430000f0 },
0491     {} /* terminator */
0492 };
0493 
0494 static void cs420x_fixup_gpio_13(struct hda_codec *codec,
0495                  const struct hda_fixup *fix, int action)
0496 {
0497     if (action == HDA_FIXUP_ACT_PRE_PROBE) {
0498         struct cs_spec *spec = codec->spec;
0499 
0500         spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
0501         spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
0502         spec->gpio_mask = spec->gpio_dir =
0503             spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
0504     }
0505 }
0506 
0507 static void cs420x_fixup_gpio_23(struct hda_codec *codec,
0508                  const struct hda_fixup *fix, int action)
0509 {
0510     if (action == HDA_FIXUP_ACT_PRE_PROBE) {
0511         struct cs_spec *spec = codec->spec;
0512 
0513         spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
0514         spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
0515         spec->gpio_mask = spec->gpio_dir =
0516             spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
0517     }
0518 }
0519 
0520 static const struct hda_fixup cs420x_fixups[] = {
0521     [CS420X_MBP53] = {
0522         .type = HDA_FIXUP_PINS,
0523         .v.pins = mbp53_pincfgs,
0524         .chained = true,
0525         .chain_id = CS420X_APPLE,
0526     },
0527     [CS420X_MBP55] = {
0528         .type = HDA_FIXUP_PINS,
0529         .v.pins = mbp55_pincfgs,
0530         .chained = true,
0531         .chain_id = CS420X_GPIO_13,
0532     },
0533     [CS420X_IMAC27] = {
0534         .type = HDA_FIXUP_PINS,
0535         .v.pins = imac27_pincfgs,
0536         .chained = true,
0537         .chain_id = CS420X_GPIO_13,
0538     },
0539     [CS420X_GPIO_13] = {
0540         .type = HDA_FIXUP_FUNC,
0541         .v.func = cs420x_fixup_gpio_13,
0542     },
0543     [CS420X_GPIO_23] = {
0544         .type = HDA_FIXUP_FUNC,
0545         .v.func = cs420x_fixup_gpio_23,
0546     },
0547     [CS420X_MBP101] = {
0548         .type = HDA_FIXUP_PINS,
0549         .v.pins = mbp101_pincfgs,
0550         .chained = true,
0551         .chain_id = CS420X_GPIO_13,
0552     },
0553     [CS420X_MBP81] = {
0554         .type = HDA_FIXUP_VERBS,
0555         .v.verbs = (const struct hda_verb[]) {
0556             /* internal mic ADC2: right only, single ended */
0557             {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG},
0558             {0x11, AC_VERB_SET_PROC_COEF, 0x102a},
0559             {}
0560         },
0561         .chained = true,
0562         .chain_id = CS420X_GPIO_13,
0563     },
0564     [CS420X_MBA42] = {
0565         .type = HDA_FIXUP_PINS,
0566         .v.pins = mba42_pincfgs,
0567         .chained = true,
0568         .chain_id = CS420X_GPIO_13,
0569     },
0570 };
0571 
0572 static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
0573 {
0574     struct cs_spec *spec;
0575 
0576     spec = kzalloc(sizeof(*spec), GFP_KERNEL);
0577     if (!spec)
0578         return NULL;
0579     codec->spec = spec;
0580     spec->vendor_nid = vendor_nid;
0581     codec->power_save_node = 1;
0582     snd_hda_gen_spec_init(&spec->gen);
0583 
0584     return spec;
0585 }
0586 
0587 static int patch_cs420x(struct hda_codec *codec)
0588 {
0589     struct cs_spec *spec;
0590     int err;
0591 
0592     spec = cs_alloc_spec(codec, CS420X_VENDOR_NID);
0593     if (!spec)
0594         return -ENOMEM;
0595 
0596     codec->patch_ops = cs_patch_ops;
0597     spec->gen.automute_hook = cs_automute;
0598     codec->single_adc_amp = 1;
0599 
0600     snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
0601                cs420x_fixups);
0602     snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
0603 
0604     err = cs_parse_auto_config(codec);
0605     if (err < 0)
0606         goto error;
0607 
0608     snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
0609 
0610     return 0;
0611 
0612  error:
0613     cs_free(codec);
0614     return err;
0615 }
0616 
0617 /*
0618  * CS4208 support:
0619  * Its layout is no longer compatible with CS4206/CS4207
0620  */
0621 enum {
0622     CS4208_MAC_AUTO,
0623     CS4208_MBA6,
0624     CS4208_MBP11,
0625     CS4208_MACMINI,
0626     CS4208_GPIO0,
0627 };
0628 
0629 static const struct hda_model_fixup cs4208_models[] = {
0630     { .id = CS4208_GPIO0, .name = "gpio0" },
0631     { .id = CS4208_MBA6, .name = "mba6" },
0632     { .id = CS4208_MBP11, .name = "mbp11" },
0633     { .id = CS4208_MACMINI, .name = "macmini" },
0634     {}
0635 };
0636 
0637 static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
0638     SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO),
0639     {} /* terminator */
0640 };
0641 
0642 /* codec SSID matching */
0643 static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = {
0644     SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
0645     SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI),
0646     SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
0647     SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
0648     SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11),
0649     {} /* terminator */
0650 };
0651 
0652 static void cs4208_fixup_gpio0(struct hda_codec *codec,
0653                    const struct hda_fixup *fix, int action)
0654 {
0655     if (action == HDA_FIXUP_ACT_PRE_PROBE) {
0656         struct cs_spec *spec = codec->spec;
0657 
0658         spec->gpio_eapd_hp = 0;
0659         spec->gpio_eapd_speaker = 1;
0660         spec->gpio_mask = spec->gpio_dir =
0661             spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
0662     }
0663 }
0664 
0665 static const struct hda_fixup cs4208_fixups[];
0666 
0667 /* remap the fixup from codec SSID and apply it */
0668 static void cs4208_fixup_mac(struct hda_codec *codec,
0669                  const struct hda_fixup *fix, int action)
0670 {
0671     if (action != HDA_FIXUP_ACT_PRE_PROBE)
0672         return;
0673 
0674     codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
0675     snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups);
0676     if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET)
0677         codec->fixup_id = CS4208_GPIO0; /* default fixup */
0678     snd_hda_apply_fixup(codec, action);
0679 }
0680 
0681 /* MacMini 7,1 has the inverted jack detection */
0682 static void cs4208_fixup_macmini(struct hda_codec *codec,
0683                  const struct hda_fixup *fix, int action)
0684 {
0685     static const struct hda_pintbl pincfgs[] = {
0686         { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */
0687         { 0x21, 0x004be140 }, /* SPDIF: disable detect */
0688         { }
0689     };
0690 
0691     if (action == HDA_FIXUP_ACT_PRE_PROBE) {
0692         /* HP pin (0x10) has an inverted detection */
0693         codec->inv_jack_detect = 1;
0694         /* disable the bogus Mic and SPDIF jack detections */
0695         snd_hda_apply_pincfgs(codec, pincfgs);
0696     }
0697 }
0698 
0699 static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol,
0700                    struct snd_ctl_elem_value *ucontrol)
0701 {
0702     struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
0703     struct cs_spec *spec = codec->spec;
0704     hda_nid_t pin = spec->gen.autocfg.dig_out_pins[0];
0705     int pinctl = ucontrol->value.integer.value[0] ? PIN_OUT : 0;
0706 
0707     snd_hda_set_pin_ctl_cache(codec, pin, pinctl);
0708     return spec->spdif_sw_put(kcontrol, ucontrol);
0709 }
0710 
0711 /* hook the SPDIF switch */
0712 static void cs4208_fixup_spdif_switch(struct hda_codec *codec,
0713                       const struct hda_fixup *fix, int action)
0714 {
0715     if (action == HDA_FIXUP_ACT_BUILD) {
0716         struct cs_spec *spec = codec->spec;
0717         struct snd_kcontrol *kctl;
0718 
0719         if (!spec->gen.autocfg.dig_out_pins[0])
0720             return;
0721         kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch");
0722         if (!kctl)
0723             return;
0724         spec->spdif_sw_put = kctl->put;
0725         kctl->put = cs4208_spdif_sw_put;
0726     }
0727 }
0728 
0729 static const struct hda_fixup cs4208_fixups[] = {
0730     [CS4208_MBA6] = {
0731         .type = HDA_FIXUP_PINS,
0732         .v.pins = mba6_pincfgs,
0733         .chained = true,
0734         .chain_id = CS4208_GPIO0,
0735     },
0736     [CS4208_MBP11] = {
0737         .type = HDA_FIXUP_FUNC,
0738         .v.func = cs4208_fixup_spdif_switch,
0739         .chained = true,
0740         .chain_id = CS4208_GPIO0,
0741     },
0742     [CS4208_MACMINI] = {
0743         .type = HDA_FIXUP_FUNC,
0744         .v.func = cs4208_fixup_macmini,
0745         .chained = true,
0746         .chain_id = CS4208_GPIO0,
0747     },
0748     [CS4208_GPIO0] = {
0749         .type = HDA_FIXUP_FUNC,
0750         .v.func = cs4208_fixup_gpio0,
0751     },
0752     [CS4208_MAC_AUTO] = {
0753         .type = HDA_FIXUP_FUNC,
0754         .v.func = cs4208_fixup_mac,
0755     },
0756 };
0757 
0758 /* correct the 0dB offset of input pins */
0759 static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc)
0760 {
0761     unsigned int caps;
0762 
0763     caps = query_amp_caps(codec, adc, HDA_INPUT);
0764     caps &= ~(AC_AMPCAP_OFFSET);
0765     caps |= 0x02;
0766     snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps);
0767 }
0768 
0769 static int patch_cs4208(struct hda_codec *codec)
0770 {
0771     struct cs_spec *spec;
0772     int err;
0773 
0774     spec = cs_alloc_spec(codec, CS4208_VENDOR_NID);
0775     if (!spec)
0776         return -ENOMEM;
0777 
0778     codec->patch_ops = cs_patch_ops;
0779     spec->gen.automute_hook = cs_automute;
0780     /* exclude NID 0x10 (HP) from output volumes due to different steps */
0781     spec->gen.out_vol_mask = 1ULL << 0x10;
0782 
0783     snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl,
0784                cs4208_fixups);
0785     snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
0786 
0787     snd_hda_override_wcaps(codec, 0x18,
0788                    get_wcaps(codec, 0x18) | AC_WCAP_STEREO);
0789     cs4208_fix_amp_caps(codec, 0x18);
0790     cs4208_fix_amp_caps(codec, 0x1b);
0791     cs4208_fix_amp_caps(codec, 0x1c);
0792 
0793     err = cs_parse_auto_config(codec);
0794     if (err < 0)
0795         goto error;
0796 
0797     snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
0798 
0799     return 0;
0800 
0801  error:
0802     cs_free(codec);
0803     return err;
0804 }
0805 
0806 /*
0807  * Cirrus Logic CS4210
0808  *
0809  * 1 DAC => HP(sense) / Speakers,
0810  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
0811  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
0812  */
0813 
0814 /* CS4210 board names */
0815 static const struct hda_model_fixup cs421x_models[] = {
0816     { .id = CS421X_CDB4210, .name = "cdb4210" },
0817     { .id = CS421X_STUMPY, .name = "stumpy" },
0818     {}
0819 };
0820 
0821 static const struct snd_pci_quirk cs421x_fixup_tbl[] = {
0822     /* Test Intel board + CDB2410  */
0823     SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
0824     {} /* terminator */
0825 };
0826 
0827 /* CS4210 board pinconfigs */
0828 /* Default CS4210 (CDB4210)*/
0829 static const struct hda_pintbl cdb4210_pincfgs[] = {
0830     { 0x05, 0x0321401f },
0831     { 0x06, 0x90170010 },
0832     { 0x07, 0x03813031 },
0833     { 0x08, 0xb7a70037 },
0834     { 0x09, 0xb7a6003e },
0835     { 0x0a, 0x034510f0 },
0836     {} /* terminator */
0837 };
0838 
0839 /* Stumpy ChromeBox */
0840 static const struct hda_pintbl stumpy_pincfgs[] = {
0841     { 0x05, 0x022120f0 },
0842     { 0x06, 0x901700f0 },
0843     { 0x07, 0x02a120f0 },
0844     { 0x08, 0x77a70037 },
0845     { 0x09, 0x77a6003e },
0846     { 0x0a, 0x434510f0 },
0847     {} /* terminator */
0848 };
0849 
0850 /* Setup GPIO/SENSE for each board (if used) */
0851 static void cs421x_fixup_sense_b(struct hda_codec *codec,
0852                  const struct hda_fixup *fix, int action)
0853 {
0854     struct cs_spec *spec = codec->spec;
0855 
0856     if (action == HDA_FIXUP_ACT_PRE_PROBE)
0857         spec->sense_b = 1;
0858 }
0859 
0860 static const struct hda_fixup cs421x_fixups[] = {
0861     [CS421X_CDB4210] = {
0862         .type = HDA_FIXUP_PINS,
0863         .v.pins = cdb4210_pincfgs,
0864         .chained = true,
0865         .chain_id = CS421X_SENSE_B,
0866     },
0867     [CS421X_SENSE_B] = {
0868         .type = HDA_FIXUP_FUNC,
0869         .v.func = cs421x_fixup_sense_b,
0870     },
0871     [CS421X_STUMPY] = {
0872         .type = HDA_FIXUP_PINS,
0873         .v.pins = stumpy_pincfgs,
0874     },
0875 };
0876 
0877 static const struct hda_verb cs421x_coef_init_verbs[] = {
0878     {0x0B, AC_VERB_SET_PROC_STATE, 1},
0879     {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
0880     /*
0881      *  Disable Coefficient Index Auto-Increment(DAI)=1,
0882      *  PDREF=0
0883      */
0884     {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
0885 
0886     {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
0887     /* ADC SZCMode = Digital Soft Ramp */
0888     {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
0889 
0890     {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
0891     {0x0B, AC_VERB_SET_PROC_COEF,
0892      (0x0002 /* DAC SZCMode = Digital Soft Ramp */
0893       | 0x0004 /* Mute DAC on FIFO error */
0894       | 0x0008 /* Enable DAC High Pass Filter */
0895       )},
0896     {} /* terminator */
0897 };
0898 
0899 /* Errata: CS4210 rev A1 Silicon
0900  *
0901  * http://www.cirrus.com/en/pubs/errata/
0902  *
0903  * Description:
0904  * 1. Performance degredation is present in the ADC.
0905  * 2. Speaker output is not completely muted upon HP detect.
0906  * 3. Noise is present when clipping occurs on the amplified
0907  *    speaker outputs.
0908  *
0909  * Workaround:
0910  * The following verb sequence written to the registers during
0911  * initialization will correct the issues listed above.
0912  */
0913 
0914 static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
0915     {0x0B, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
0916 
0917     {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
0918     {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
0919 
0920     {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
0921     {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
0922 
0923     {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
0924     {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
0925 
0926     {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
0927     {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
0928 
0929     {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
0930     {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
0931 
0932     {} /* terminator */
0933 };
0934 
0935 /* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
0936 static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
0937 
0938 static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
0939                 struct snd_ctl_elem_info *uinfo)
0940 {
0941     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0942     uinfo->count = 1;
0943     uinfo->value.integer.min = 0;
0944     uinfo->value.integer.max = 3;
0945     return 0;
0946 }
0947 
0948 static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
0949                 struct snd_ctl_elem_value *ucontrol)
0950 {
0951     struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
0952 
0953     ucontrol->value.integer.value[0] =
0954         cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
0955     return 0;
0956 }
0957 
0958 static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
0959                 struct snd_ctl_elem_value *ucontrol)
0960 {
0961     struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
0962 
0963     unsigned int vol = ucontrol->value.integer.value[0];
0964     unsigned int coef =
0965         cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
0966     unsigned int original_coef = coef;
0967 
0968     coef &= ~0x0003;
0969     coef |= (vol & 0x0003);
0970     if (original_coef != coef) {
0971         cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
0972         return 1;
0973     }
0974 
0975     return 0;
0976 }
0977 
0978 static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = {
0979 
0980     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0981     .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
0982             SNDRV_CTL_ELEM_ACCESS_TLV_READ),
0983     .name = "Speaker Boost Playback Volume",
0984     .info = cs421x_boost_vol_info,
0985     .get = cs421x_boost_vol_get,
0986     .put = cs421x_boost_vol_put,
0987     .tlv = { .p = cs421x_speaker_boost_db_scale },
0988 };
0989 
0990 static void cs4210_pinmux_init(struct hda_codec *codec)
0991 {
0992     struct cs_spec *spec = codec->spec;
0993     unsigned int def_conf, coef;
0994 
0995     /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
0996     coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
0997 
0998     if (spec->gpio_mask)
0999         coef |= 0x0008; /* B1,B2 are GPIOs */
1000     else
1001         coef &= ~0x0008;
1002 
1003     if (spec->sense_b)
1004         coef |= 0x0010; /* B2 is SENSE_B, not inverted  */
1005     else
1006         coef &= ~0x0010;
1007 
1008     cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
1009 
1010     if ((spec->gpio_mask || spec->sense_b) &&
1011         is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
1012 
1013         /*
1014          *  GPIO or SENSE_B forced - disconnect the DMIC pin.
1015          */
1016         def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
1017         def_conf &= ~AC_DEFCFG_PORT_CONN;
1018         def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
1019         snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
1020     }
1021 }
1022 
1023 static void cs4210_spdif_automute(struct hda_codec *codec,
1024                   struct hda_jack_callback *tbl)
1025 {
1026     struct cs_spec *spec = codec->spec;
1027     bool spdif_present = false;
1028     hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0];
1029 
1030     /* detect on spdif is specific to CS4210 */
1031     if (!spec->spdif_detect ||
1032         spec->vendor_nid != CS4210_VENDOR_NID)
1033         return;
1034 
1035     spdif_present = snd_hda_jack_detect(codec, spdif_pin);
1036     if (spdif_present == spec->spdif_present)
1037         return;
1038 
1039     spec->spdif_present = spdif_present;
1040     /* SPDIF TX on/off */
1041     snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
1042 
1043     cs_automute(codec);
1044 }
1045 
1046 static void parse_cs421x_digital(struct hda_codec *codec)
1047 {
1048     struct cs_spec *spec = codec->spec;
1049     struct auto_pin_cfg *cfg = &spec->gen.autocfg;
1050     int i;
1051 
1052     for (i = 0; i < cfg->dig_outs; i++) {
1053         hda_nid_t nid = cfg->dig_out_pins[i];
1054 
1055         if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
1056             spec->spdif_detect = 1;
1057             snd_hda_jack_detect_enable_callback(codec, nid,
1058                                 cs4210_spdif_automute);
1059         }
1060     }
1061 }
1062 
1063 static int cs421x_init(struct hda_codec *codec)
1064 {
1065     struct cs_spec *spec = codec->spec;
1066 
1067     if (spec->vendor_nid == CS4210_VENDOR_NID) {
1068         snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
1069         snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
1070         cs4210_pinmux_init(codec);
1071     }
1072 
1073     snd_hda_gen_init(codec);
1074 
1075     if (spec->gpio_mask) {
1076         snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
1077                     spec->gpio_mask);
1078         snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
1079                     spec->gpio_dir);
1080         snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
1081                     spec->gpio_data);
1082     }
1083 
1084     init_input_coef(codec);
1085 
1086     cs4210_spdif_automute(codec, NULL);
1087 
1088     return 0;
1089 }
1090 
1091 static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
1092 {
1093     unsigned int caps;
1094 
1095     /* set the upper-limit for mixer amp to 0dB */
1096     caps = query_amp_caps(codec, dac, HDA_OUTPUT);
1097     caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
1098     caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
1099         << AC_AMPCAP_NUM_STEPS_SHIFT;
1100     snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
1101 }
1102 
1103 static int cs421x_parse_auto_config(struct hda_codec *codec)
1104 {
1105     struct cs_spec *spec = codec->spec;
1106     hda_nid_t dac = CS4210_DAC_NID;
1107     int err;
1108 
1109     fix_volume_caps(codec, dac);
1110 
1111     err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
1112     if (err < 0)
1113         return err;
1114 
1115     err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
1116     if (err < 0)
1117         return err;
1118 
1119     parse_cs421x_digital(codec);
1120 
1121     if (spec->gen.autocfg.speaker_outs &&
1122         spec->vendor_nid == CS4210_VENDOR_NID) {
1123         if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
1124                       &cs421x_speaker_boost_ctl))
1125             return -ENOMEM;
1126     }
1127 
1128     return 0;
1129 }
1130 
1131 #ifdef CONFIG_PM
1132 /*
1133  *  Manage PDREF, when transitioning to D3hot
1134  *  (DAC,ADC) -> D3, PDREF=1, AFG->D3
1135  */
1136 static int cs421x_suspend(struct hda_codec *codec)
1137 {
1138     struct cs_spec *spec = codec->spec;
1139     unsigned int coef;
1140 
1141     snd_hda_shutup_pins(codec);
1142 
1143     snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
1144                 AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
1145     snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
1146                 AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
1147 
1148     if (spec->vendor_nid == CS4210_VENDOR_NID) {
1149         coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
1150         coef |= 0x0004; /* PDREF */
1151         cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
1152     }
1153 
1154     return 0;
1155 }
1156 #endif
1157 
1158 static const struct hda_codec_ops cs421x_patch_ops = {
1159     .build_controls = snd_hda_gen_build_controls,
1160     .build_pcms = snd_hda_gen_build_pcms,
1161     .init = cs421x_init,
1162     .free = cs_free,
1163     .unsol_event = snd_hda_jack_unsol_event,
1164 #ifdef CONFIG_PM
1165     .suspend = cs421x_suspend,
1166 #endif
1167 };
1168 
1169 static int patch_cs4210(struct hda_codec *codec)
1170 {
1171     struct cs_spec *spec;
1172     int err;
1173 
1174     spec = cs_alloc_spec(codec, CS4210_VENDOR_NID);
1175     if (!spec)
1176         return -ENOMEM;
1177 
1178     codec->patch_ops = cs421x_patch_ops;
1179     spec->gen.automute_hook = cs_automute;
1180 
1181     snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
1182                cs421x_fixups);
1183     snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1184 
1185     /*
1186      *  Update the GPIO/DMIC/SENSE_B pinmux before the configuration
1187      *   is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
1188      *   is disabled.
1189      */
1190     cs4210_pinmux_init(codec);
1191 
1192     err = cs421x_parse_auto_config(codec);
1193     if (err < 0)
1194         goto error;
1195 
1196     snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1197 
1198     return 0;
1199 
1200  error:
1201     cs_free(codec);
1202     return err;
1203 }
1204 
1205 static int patch_cs4213(struct hda_codec *codec)
1206 {
1207     struct cs_spec *spec;
1208     int err;
1209 
1210     spec = cs_alloc_spec(codec, CS4213_VENDOR_NID);
1211     if (!spec)
1212         return -ENOMEM;
1213 
1214     codec->patch_ops = cs421x_patch_ops;
1215 
1216     err = cs421x_parse_auto_config(codec);
1217     if (err < 0)
1218         goto error;
1219 
1220     return 0;
1221 
1222  error:
1223     cs_free(codec);
1224     return err;
1225 }
1226 
1227 /*
1228  * patch entries
1229  */
1230 static const struct hda_device_id snd_hda_id_cirrus[] = {
1231     HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x),
1232     HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x),
1233     HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
1234     HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
1235     HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
1236     {} /* terminator */
1237 };
1238 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
1239 
1240 MODULE_LICENSE("GPL");
1241 MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
1242 
1243 static struct hda_codec_driver cirrus_driver = {
1244     .id = snd_hda_id_cirrus,
1245 };
1246 
1247 module_hda_codec_driver(cirrus_driver);