^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * HD audio interface patch for Cirrus Logic CS420x chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sound/tlv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sound/hda_codec.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "hda_local.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "hda_auto_parser.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "hda_jack.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "hda_generic.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct cs_spec {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct hda_gen_spec gen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned int gpio_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) unsigned int gpio_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) unsigned int gpio_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* CS421x */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) unsigned int spdif_detect:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned int spdif_present:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned int sense_b:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) hda_nid_t vendor_nid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* for MBP SPDIF control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct snd_ctl_elem_value *ucontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* available models with CS420x */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) CS420X_MBP53,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) CS420X_MBP55,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) CS420X_IMAC27,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) CS420X_GPIO_13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) CS420X_GPIO_23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) CS420X_MBP101,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) CS420X_MBP81,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) CS420X_MBA42,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) CS420X_AUTO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /* aliases */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) CS420X_IMAC27_122 = CS420X_GPIO_23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) CS420X_APPLE = CS420X_GPIO_13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* CS421x boards */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) CS421X_CDB4210,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) CS421X_SENSE_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) CS421X_STUMPY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* Vendor-specific processing widget */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define CS420X_VENDOR_NID 0x11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define CS_DIG_OUT1_PIN_NID 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define CS_DIG_OUT2_PIN_NID 0x15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define CS_DMIC1_PIN_NID 0x0e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define CS_DMIC2_PIN_NID 0x12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* coef indices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define IDX_SPDIF_STAT 0x0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define IDX_SPDIF_CTL 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define IDX_ADC_CFG 0x0002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* SZC bitmask, 4 modes below:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * 0 = immediate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * 1 = digital immediate, analog zero-cross
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * 2 = digtail & analog soft-ramp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * 3 = digital soft-ramp, analog zero-cross
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define CS_COEF_ADC_SZC_MASK (3 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define CS_COEF_ADC_MIC_SZC_MODE (3 << 0) /* SZC setup for mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define CS_COEF_ADC_LI_SZC_MODE (3 << 0) /* SZC setup for line-in */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* PGA mode: 0 = differential, 1 = signle-ended */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define CS_COEF_ADC_MIC_PGA_MODE (1 << 5) /* PGA setup for mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define CS_COEF_ADC_LI_PGA_MODE (1 << 6) /* PGA setup for line-in */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define IDX_DAC_CFG 0x0003
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* SZC bitmask, 4 modes below:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * 0 = Immediate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * 1 = zero-cross
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * 2 = soft-ramp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * 3 = soft-ramp on zero-cross
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define CS_COEF_DAC_HP_SZC_MODE (3 << 0) /* nid 0x02 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define CS_COEF_DAC_LO_SZC_MODE (3 << 2) /* nid 0x03 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define CS_COEF_DAC_SPK_SZC_MODE (3 << 4) /* nid 0x04 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define IDX_BEEP_CFG 0x0004
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* 0x0008 - test reg key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* 0x0009 - 0x0014 -> 12 test regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* 0x0015 - visibility reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* Cirrus Logic CS4208 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define CS4208_VENDOR_NID 0x24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * Cirrus Logic CS4210
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * 1 DAC => HP(sense) / Speakers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * 1 SPDIF OUT => SPDIF Trasmitter(sense)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define CS4210_DAC_NID 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define CS4210_ADC_NID 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define CS4210_VENDOR_NID 0x0B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define CS421X_DMIC_PIN_NID 0x09 /* Port E */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define CS421X_SPDIF_PIN_NID 0x0A /* Port H */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define CS421X_IDX_DEV_CFG 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define CS421X_IDX_ADC_CFG 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define CS421X_IDX_DAC_CFG 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define CS421X_IDX_SPK_CTL 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #define CS4213_VENDOR_NID 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) snd_hda_codec_write(codec, spec->vendor_nid, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) AC_VERB_SET_COEF_INDEX, idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return snd_hda_codec_read(codec, spec->vendor_nid, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) AC_VERB_GET_PROC_COEF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) unsigned int coef)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) snd_hda_codec_write(codec, spec->vendor_nid, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) AC_VERB_SET_COEF_INDEX, idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) snd_hda_codec_write(codec, spec->vendor_nid, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) AC_VERB_SET_PROC_COEF, coef);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * auto-mute and auto-mic switching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * CS421x auto-output redirecting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * HP/SPK/SPDIF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static void cs_automute(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* mute HPs if spdif jack (SENSE_B) is present */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) snd_hda_gen_update_outputs(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (spec->gen.automute_speaker)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) spec->gpio_data = spec->gen.hp_jack_present ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) spec->gpio_data =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) snd_hda_codec_write(codec, 0x01, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) AC_VERB_SET_GPIO_DATA, spec->gpio_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) val = snd_hda_codec_get_pincfg(codec, nid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static void init_input_coef(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) unsigned int coef;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* CS420x has multiple ADC, CS421x has single ADC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (spec->vendor_nid == CS420X_VENDOR_NID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (is_active_pin(codec, CS_DMIC2_PIN_NID))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (is_active_pin(codec, CS_DMIC1_PIN_NID))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * No effect if SPDIF_OUT2 is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * selected in IDX_SPDIF_CTL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static const struct hda_verb cs_coef_init_verbs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {0x11, AC_VERB_SET_PROC_STATE, 1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {0x11, AC_VERB_SET_PROC_COEF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) (0x002a /* DAC1/2/3 SZCMode Soft Ramp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) | 0x0040 /* Mute DACs on FIFO error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) | 0x1000 /* Enable DACs High Pass Filter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) | 0x0400 /* Disable Coefficient Auto increment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) )},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* ADC1/2 - Digital and Analog Soft Ramp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {0x11, AC_VERB_SET_PROC_COEF, 0x000a},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /* Beep */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static const struct hda_verb cs4208_coef_init_verbs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {0x24, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {0x24, AC_VERB_SET_COEF_INDEX, 0x0033},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) {0x24, AC_VERB_SET_PROC_COEF, 0x0001}, /* A1 ICS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) {0x24, AC_VERB_SET_COEF_INDEX, 0x0034},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {0x24, AC_VERB_SET_PROC_COEF, 0x1C01}, /* A1 Enable, A Thresh = 300mV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /* Errata: CS4207 rev C0/C1/C2 Silicon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * 6. At high temperature (TA > +85°C), the digital supply current (IVD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * may be excessive (up to an additional 200 μA), which is most easily
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * observed while the part is being held in reset (RESET# active low).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * Root Cause: At initial powerup of the device, the logic that drives
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * the clock and write enable to the S/PDIF SRC RAMs is not properly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * initialized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * Certain random patterns will cause a steady leakage current in those
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * RAM cells. The issue will resolve once the SRCs are used (turned on).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * Workaround: The following verb sequence briefly turns on the S/PDIF SRC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * blocks, which will alleviate the issue.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static const struct hda_verb cs_errata_init_verbs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {0x11, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) {0x11, AC_VERB_SET_PROC_COEF, 0x9999},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {0x11, AC_VERB_SET_PROC_COEF, 0xa412},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) {0x11, AC_VERB_SET_PROC_COEF, 0x0009},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {0x07, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Rx: D0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) {0x08, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Tx: D0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {0x11, AC_VERB_SET_PROC_COEF, 0x2412},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {0x11, AC_VERB_SET_PROC_COEF, 0x0000},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) {0x11, AC_VERB_SET_PROC_COEF, 0x0008},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {0x11, AC_VERB_SET_PROC_STATE, 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) #if 0 /* Don't to set to D3 as we are in power-up sequence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* SPDIF setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static void init_digital_coef(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) unsigned int coef;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) coef |= 0x0008; /* Replace with mute on error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * SPDIF_OUT2 is shared with GPIO1 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * DMIC_SDA2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static int cs_init(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (spec->vendor_nid == CS420X_VENDOR_NID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /* init_verb sequence for C0/C1/C2 errata*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) snd_hda_sequence_write(codec, cs_errata_init_verbs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) snd_hda_sequence_write(codec, cs_coef_init_verbs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) } else if (spec->vendor_nid == CS4208_VENDOR_NID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) snd_hda_sequence_write(codec, cs4208_coef_init_verbs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) snd_hda_gen_init(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (spec->gpio_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) spec->gpio_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) spec->gpio_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) spec->gpio_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (spec->vendor_nid == CS420X_VENDOR_NID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) init_input_coef(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) init_digital_coef(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static int cs_build_controls(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) err = snd_hda_gen_build_controls(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) #define cs_free snd_hda_gen_free
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static const struct hda_codec_ops cs_patch_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .build_controls = cs_build_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .build_pcms = snd_hda_gen_build_pcms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) .init = cs_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) .free = cs_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) .unsol_event = snd_hda_jack_unsol_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static int cs_parse_auto_config(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /* keep the ADCs powered up when it's dynamically switchable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (spec->gen.dyn_adc_switch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) unsigned int done = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) for (i = 0; i < spec->gen.input_mux.num_items; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) int idx = spec->gen.dyn_adc_idx[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (done & (1 << idx))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) snd_hda_gen_fix_pin_power(codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) spec->gen.adc_nids[idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) done |= 1 << idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static const struct hda_model_fixup cs420x_models[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) { .id = CS420X_MBP53, .name = "mbp53" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) { .id = CS420X_MBP55, .name = "mbp55" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) { .id = CS420X_IMAC27, .name = "imac27" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) { .id = CS420X_IMAC27_122, .name = "imac27_122" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) { .id = CS420X_APPLE, .name = "apple" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) { .id = CS420X_MBP101, .name = "mbp101" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) { .id = CS420X_MBP81, .name = "mbp81" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) { .id = CS420X_MBA42, .name = "mba42" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /* this conflicts with too many other models */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) /* codec SSID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) static const struct hda_pintbl mbp53_pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) { 0x09, 0x012b4050 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) { 0x0a, 0x90100141 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) { 0x0b, 0x90100140 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) { 0x0c, 0x018b3020 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) { 0x0d, 0x90a00110 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) { 0x0e, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) { 0x0f, 0x01cbe030 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) { 0x10, 0x014be060 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) { 0x12, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) { 0x15, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) static const struct hda_pintbl mbp55_pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) { 0x09, 0x012b4030 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) { 0x0a, 0x90100121 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) { 0x0b, 0x90100120 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) { 0x0c, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) { 0x0d, 0x90a00110 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) { 0x0e, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) { 0x0f, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) { 0x10, 0x014be040 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) { 0x12, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) { 0x15, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static const struct hda_pintbl imac27_pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) { 0x09, 0x012b4050 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) { 0x0a, 0x90100140 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) { 0x0b, 0x90100142 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) { 0x0c, 0x018b3020 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) { 0x0d, 0x90a00110 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) { 0x0e, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) { 0x0f, 0x01cbe030 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) { 0x10, 0x014be060 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) { 0x12, 0x01ab9070 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) { 0x15, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) static const struct hda_pintbl mbp101_pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) { 0x0d, 0x40ab90f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) { 0x0e, 0x90a600f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) { 0x12, 0x50a600f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) static const struct hda_pintbl mba42_pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) { 0x09, 0x012b4030 }, /* HP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) { 0x0a, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) { 0x0b, 0x90100120 }, /* speaker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) { 0x0c, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) { 0x0d, 0x90a00110 }, /* mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) { 0x0e, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) { 0x0f, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) { 0x10, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) { 0x12, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) { 0x15, 0x400000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) static const struct hda_pintbl mba6_pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) { 0x10, 0x032120f0 }, /* HP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) { 0x11, 0x500000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) { 0x12, 0x90100010 }, /* Speaker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) { 0x13, 0x500000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) { 0x14, 0x500000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) { 0x15, 0x770000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) { 0x16, 0x770000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) { 0x17, 0x430000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) { 0x18, 0x43ab9030 }, /* Mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) { 0x19, 0x770000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) { 0x1a, 0x770000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) { 0x1b, 0x770000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) { 0x1c, 0x90a00090 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) { 0x1d, 0x500000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) { 0x1e, 0x500000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) { 0x1f, 0x500000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) { 0x20, 0x500000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) { 0x21, 0x430000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) { 0x22, 0x430000f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) static void cs420x_fixup_gpio_13(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) spec->gpio_mask = spec->gpio_dir =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) static void cs420x_fixup_gpio_23(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) spec->gpio_mask = spec->gpio_dir =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) static const struct hda_fixup cs420x_fixups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) [CS420X_MBP53] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) .v.pins = mbp53_pincfgs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) .chain_id = CS420X_APPLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) [CS420X_MBP55] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) .v.pins = mbp55_pincfgs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) .chain_id = CS420X_GPIO_13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) [CS420X_IMAC27] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) .v.pins = imac27_pincfgs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) .chain_id = CS420X_GPIO_13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) [CS420X_GPIO_13] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) .v.func = cs420x_fixup_gpio_13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) [CS420X_GPIO_23] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) .v.func = cs420x_fixup_gpio_23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) [CS420X_MBP101] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) .v.pins = mbp101_pincfgs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) .chain_id = CS420X_GPIO_13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) [CS420X_MBP81] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) .type = HDA_FIXUP_VERBS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) .v.verbs = (const struct hda_verb[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) /* internal mic ADC2: right only, single ended */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) {0x11, AC_VERB_SET_PROC_COEF, 0x102a},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) .chain_id = CS420X_GPIO_13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) [CS420X_MBA42] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) .v.pins = mba42_pincfgs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) .chain_id = CS420X_GPIO_13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) struct cs_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) spec = kzalloc(sizeof(*spec), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (!spec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) codec->spec = spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) spec->vendor_nid = vendor_nid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) codec->power_save_node = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) snd_hda_gen_spec_init(&spec->gen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) static int patch_cs420x(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) struct cs_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) spec = cs_alloc_spec(codec, CS420X_VENDOR_NID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (!spec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) codec->patch_ops = cs_patch_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) spec->gen.automute_hook = cs_automute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) codec->single_adc_amp = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) cs420x_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) err = cs_parse_auto_config(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) cs_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) * CS4208 support:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) * Its layout is no longer compatible with CS4206/CS4207
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) CS4208_MAC_AUTO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) CS4208_MBA6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) CS4208_MBP11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) CS4208_MACMINI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) CS4208_GPIO0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) static const struct hda_model_fixup cs4208_models[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) { .id = CS4208_GPIO0, .name = "gpio0" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) { .id = CS4208_MBA6, .name = "mba6" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) { .id = CS4208_MBP11, .name = "mbp11" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) { .id = CS4208_MACMINI, .name = "macmini" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) /* codec SSID matching */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) static void cs4208_fixup_gpio0(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) spec->gpio_eapd_hp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) spec->gpio_eapd_speaker = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) spec->gpio_mask = spec->gpio_dir =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) static const struct hda_fixup cs4208_fixups[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) /* remap the fixup from codec SSID and apply it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) static void cs4208_fixup_mac(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (action != HDA_FIXUP_ACT_PRE_PROBE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) codec->fixup_id = CS4208_GPIO0; /* default fixup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) snd_hda_apply_fixup(codec, action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) /* MacMini 7,1 has the inverted jack detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) static void cs4208_fixup_macmini(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) static const struct hda_pintbl pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) { 0x21, 0x004be140 }, /* SPDIF: disable detect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) /* HP pin (0x10) has an inverted detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) codec->inv_jack_detect = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) /* disable the bogus Mic and SPDIF jack detections */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) snd_hda_apply_pincfgs(codec, pincfgs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) hda_nid_t pin = spec->gen.autocfg.dig_out_pins[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) int pinctl = ucontrol->value.integer.value[0] ? PIN_OUT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) snd_hda_set_pin_ctl_cache(codec, pin, pinctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) return spec->spdif_sw_put(kcontrol, ucontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) /* hook the SPDIF switch */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) static void cs4208_fixup_spdif_switch(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (action == HDA_FIXUP_ACT_BUILD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) struct snd_kcontrol *kctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) if (!spec->gen.autocfg.dig_out_pins[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) if (!kctl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) spec->spdif_sw_put = kctl->put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) kctl->put = cs4208_spdif_sw_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) static const struct hda_fixup cs4208_fixups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) [CS4208_MBA6] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) .v.pins = mba6_pincfgs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) .chain_id = CS4208_GPIO0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) [CS4208_MBP11] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) .v.func = cs4208_fixup_spdif_switch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) .chain_id = CS4208_GPIO0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) [CS4208_MACMINI] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) .v.func = cs4208_fixup_macmini,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) .chain_id = CS4208_GPIO0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) [CS4208_GPIO0] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) .v.func = cs4208_fixup_gpio0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) [CS4208_MAC_AUTO] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) .v.func = cs4208_fixup_mac,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) /* correct the 0dB offset of input pins */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) unsigned int caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) caps = query_amp_caps(codec, adc, HDA_INPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) caps &= ~(AC_AMPCAP_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) caps |= 0x02;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) static int patch_cs4208(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) struct cs_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) spec = cs_alloc_spec(codec, CS4208_VENDOR_NID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (!spec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) codec->patch_ops = cs_patch_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) spec->gen.automute_hook = cs_automute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) /* exclude NID 0x10 (HP) from output volumes due to different steps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) spec->gen.out_vol_mask = 1ULL << 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) cs4208_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) snd_hda_override_wcaps(codec, 0x18,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) get_wcaps(codec, 0x18) | AC_WCAP_STEREO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) cs4208_fix_amp_caps(codec, 0x18);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) cs4208_fix_amp_caps(codec, 0x1b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) cs4208_fix_amp_caps(codec, 0x1c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) err = cs_parse_auto_config(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) cs_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) * Cirrus Logic CS4210
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) * 1 DAC => HP(sense) / Speakers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) * 1 SPDIF OUT => SPDIF Trasmitter(sense)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) /* CS4210 board names */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) static const struct hda_model_fixup cs421x_models[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) { .id = CS421X_CDB4210, .name = "cdb4210" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) { .id = CS421X_STUMPY, .name = "stumpy" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) static const struct snd_pci_quirk cs421x_fixup_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) /* Test Intel board + CDB2410 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) /* CS4210 board pinconfigs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) /* Default CS4210 (CDB4210)*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) static const struct hda_pintbl cdb4210_pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) { 0x05, 0x0321401f },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) { 0x06, 0x90170010 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) { 0x07, 0x03813031 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) { 0x08, 0xb7a70037 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) { 0x09, 0xb7a6003e },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) { 0x0a, 0x034510f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) /* Stumpy ChromeBox */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) static const struct hda_pintbl stumpy_pincfgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) { 0x05, 0x022120f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) { 0x06, 0x901700f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) { 0x07, 0x02a120f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) { 0x08, 0x77a70037 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) { 0x09, 0x77a6003e },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) { 0x0a, 0x434510f0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) /* Setup GPIO/SENSE for each board (if used) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) static void cs421x_fixup_sense_b(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) if (action == HDA_FIXUP_ACT_PRE_PROBE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) spec->sense_b = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) static const struct hda_fixup cs421x_fixups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) [CS421X_CDB4210] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) .v.pins = cdb4210_pincfgs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) .chain_id = CS421X_SENSE_B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) [CS421X_SENSE_B] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) .v.func = cs421x_fixup_sense_b,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) [CS421X_STUMPY] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) .v.pins = stumpy_pincfgs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) static const struct hda_verb cs421x_coef_init_verbs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) {0x0B, AC_VERB_SET_PROC_STATE, 1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) Disable Coefficient Index Auto-Increment(DAI)=1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) PDREF=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) /* ADC SZCMode = Digital Soft Ramp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) {0x0B, AC_VERB_SET_PROC_COEF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) (0x0002 /* DAC SZCMode = Digital Soft Ramp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) | 0x0004 /* Mute DAC on FIFO error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) | 0x0008 /* Enable DAC High Pass Filter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) )},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) /* Errata: CS4210 rev A1 Silicon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) * http://www.cirrus.com/en/pubs/errata/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) * Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) * 1. Performance degredation is present in the ADC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) * 2. Speaker output is not completely muted upon HP detect.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) * 3. Noise is present when clipping occurs on the amplified
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) * speaker outputs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) * Workaround:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) * The following verb sequence written to the registers during
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) * initialization will correct the issues listed above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) /* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) uinfo->count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) uinfo->value.integer.min = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) uinfo->value.integer.max = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) ucontrol->value.integer.value[0] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) unsigned int vol = ucontrol->value.integer.value[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) unsigned int coef =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) unsigned int original_coef = coef;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) coef &= ~0x0003;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) coef |= (vol & 0x0003);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) if (original_coef == coef)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) SNDRV_CTL_ELEM_ACCESS_TLV_READ),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) .name = "Speaker Boost Playback Volume",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) .info = cs421x_boost_vol_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) .get = cs421x_boost_vol_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) .put = cs421x_boost_vol_put,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) .tlv = { .p = cs421x_speaker_boost_db_scale },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) static void cs4210_pinmux_init(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) unsigned int def_conf, coef;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (spec->gpio_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) coef |= 0x0008; /* B1,B2 are GPIOs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) coef &= ~0x0008;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) if (spec->sense_b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) coef |= 0x0010; /* B2 is SENSE_B, not inverted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) coef &= ~0x0010;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) if ((spec->gpio_mask || spec->sense_b) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) GPIO or SENSE_B forced - disconnect the DMIC pin.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) def_conf &= ~AC_DEFCFG_PORT_CONN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) static void cs4210_spdif_automute(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) struct hda_jack_callback *tbl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) bool spdif_present = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) /* detect on spdif is specific to CS4210 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) if (!spec->spdif_detect ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) spec->vendor_nid != CS4210_VENDOR_NID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) spdif_present = snd_hda_jack_detect(codec, spdif_pin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) if (spdif_present == spec->spdif_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) spec->spdif_present = spdif_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) /* SPDIF TX on/off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) cs_automute(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) static void parse_cs421x_digital(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) struct auto_pin_cfg *cfg = &spec->gen.autocfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) for (i = 0; i < cfg->dig_outs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) hda_nid_t nid = cfg->dig_out_pins[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) spec->spdif_detect = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) snd_hda_jack_detect_enable_callback(codec, nid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) cs4210_spdif_automute);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) static int cs421x_init(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) if (spec->vendor_nid == CS4210_VENDOR_NID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) cs4210_pinmux_init(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) snd_hda_gen_init(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) if (spec->gpio_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) spec->gpio_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) spec->gpio_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) spec->gpio_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) init_input_coef(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) cs4210_spdif_automute(codec, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) unsigned int caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) /* set the upper-limit for mixer amp to 0dB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) caps = query_amp_caps(codec, dac, HDA_OUTPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) << AC_AMPCAP_NUM_STEPS_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) static int cs421x_parse_auto_config(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) hda_nid_t dac = CS4210_DAC_NID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) fix_volume_caps(codec, dac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) parse_cs421x_digital(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) if (spec->gen.autocfg.speaker_outs &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) spec->vendor_nid == CS4210_VENDOR_NID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) &cs421x_speaker_boost_ctl))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) Manage PDREF, when transitioning to D3hot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) (DAC,ADC) -> D3, PDREF=1, AFG->D3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) static int cs421x_suspend(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) struct cs_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) unsigned int coef;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) snd_hda_shutup_pins(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) if (spec->vendor_nid == CS4210_VENDOR_NID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) coef |= 0x0004; /* PDREF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) static const struct hda_codec_ops cs421x_patch_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) .build_controls = snd_hda_gen_build_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) .build_pcms = snd_hda_gen_build_pcms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) .init = cs421x_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) .free = cs_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) .unsol_event = snd_hda_jack_unsol_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) .suspend = cs421x_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) static int patch_cs4210(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) struct cs_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) spec = cs_alloc_spec(codec, CS4210_VENDOR_NID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) if (!spec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) codec->patch_ops = cs421x_patch_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) spec->gen.automute_hook = cs_automute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) cs421x_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) Update the GPIO/DMIC/SENSE_B pinmux before the configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) is disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) cs4210_pinmux_init(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) err = cs421x_parse_auto_config(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) cs_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) static int patch_cs4213(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) struct cs_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) spec = cs_alloc_spec(codec, CS4213_VENDOR_NID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) if (!spec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) codec->patch_ops = cs421x_patch_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) err = cs421x_parse_auto_config(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) cs_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) * patch entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) static const struct hda_device_id snd_hda_id_cirrus[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) static struct hda_codec_driver cirrus_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) .id = snd_hda_id_cirrus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) module_hda_codec_driver(cirrus_driver);