Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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);