cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

patch_cirrus.c (32591B)


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