1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Cirrus Logic CS420x HD-audio codec 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 "../generic.h" 19 20 struct cs_spec { 21 struct hda_gen_spec gen; 22 23 unsigned int gpio_mask; 24 unsigned int gpio_dir; 25 unsigned int gpio_data; 26 unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */ 27 unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */ 28 29 hda_nid_t vendor_nid; 30 31 /* for MBP SPDIF control */ 32 int (*spdif_sw_put)(struct snd_kcontrol *kcontrol, 33 struct snd_ctl_elem_value *ucontrol); 34 }; 35 36 /* available models with CS420x */ 37 enum { 38 CS420X_MBP53, 39 CS420X_MBP55, 40 CS420X_IMAC27, 41 CS420X_GPIO_13, 42 CS420X_GPIO_23, 43 CS420X_MBP101, 44 CS420X_MBP81, 45 CS420X_MBA42, 46 CS420X_AUTO, 47 /* aliases */ 48 CS420X_IMAC27_122 = CS420X_GPIO_23, 49 CS420X_APPLE = CS420X_GPIO_13, 50 }; 51 52 /* Vendor-specific processing widget */ 53 #define CS420X_VENDOR_NID 0x11 54 #define CS_DIG_OUT1_PIN_NID 0x10 55 #define CS_DIG_OUT2_PIN_NID 0x15 56 #define CS_DMIC1_PIN_NID 0x0e 57 #define CS_DMIC2_PIN_NID 0x12 58 59 /* coef indices */ 60 #define IDX_SPDIF_STAT 0x0000 61 #define IDX_SPDIF_CTL 0x0001 62 #define IDX_ADC_CFG 0x0002 63 /* SZC bitmask, 4 modes below: 64 * 0 = immediate, 65 * 1 = digital immediate, analog zero-cross 66 * 2 = digtail & analog soft-ramp 67 * 3 = digital soft-ramp, analog zero-cross 68 */ 69 #define CS_COEF_ADC_SZC_MASK (3 << 0) 70 #define CS_COEF_ADC_MIC_SZC_MODE (3 << 0) /* SZC setup for mic */ 71 #define CS_COEF_ADC_LI_SZC_MODE (3 << 0) /* SZC setup for line-in */ 72 /* PGA mode: 0 = differential, 1 = signle-ended */ 73 #define CS_COEF_ADC_MIC_PGA_MODE (1 << 5) /* PGA setup for mic */ 74 #define CS_COEF_ADC_LI_PGA_MODE (1 << 6) /* PGA setup for line-in */ 75 #define IDX_DAC_CFG 0x0003 76 /* SZC bitmask, 4 modes below: 77 * 0 = Immediate 78 * 1 = zero-cross 79 * 2 = soft-ramp 80 * 3 = soft-ramp on zero-cross 81 */ 82 #define CS_COEF_DAC_HP_SZC_MODE (3 << 0) /* nid 0x02 */ 83 #define CS_COEF_DAC_LO_SZC_MODE (3 << 2) /* nid 0x03 */ 84 #define CS_COEF_DAC_SPK_SZC_MODE (3 << 4) /* nid 0x04 */ 85 86 #define IDX_BEEP_CFG 0x0004 87 /* 0x0008 - test reg key */ 88 /* 0x0009 - 0x0014 -> 12 test regs */ 89 /* 0x0015 - visibility reg */ 90 91 /* Cirrus Logic CS4208 */ 92 #define CS4208_VENDOR_NID 0x24 93 94 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) 95 { 96 struct cs_spec *spec = codec->spec; 97 98 snd_hda_codec_write(codec, spec->vendor_nid, 0, 99 AC_VERB_SET_COEF_INDEX, idx); 100 return snd_hda_codec_read(codec, spec->vendor_nid, 0, 101 AC_VERB_GET_PROC_COEF, 0); 102 } 103 104 static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, 105 unsigned int coef) 106 { 107 struct cs_spec *spec = codec->spec; 108 109 snd_hda_codec_write(codec, spec->vendor_nid, 0, 110 AC_VERB_SET_COEF_INDEX, idx); 111 snd_hda_codec_write(codec, spec->vendor_nid, 0, 112 AC_VERB_SET_PROC_COEF, coef); 113 } 114 115 /* 116 * auto-mute and auto-mic switching 117 * CS421x auto-output redirecting 118 * HP/SPK/SPDIF 119 */ 120 121 static void cs_automute(struct hda_codec *codec) 122 { 123 struct cs_spec *spec = codec->spec; 124 125 snd_hda_gen_update_outputs(codec); 126 127 if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) { 128 if (spec->gen.automute_speaker) 129 spec->gpio_data = spec->gen.hp_jack_present ? 130 spec->gpio_eapd_hp : spec->gpio_eapd_speaker; 131 else 132 spec->gpio_data = 133 spec->gpio_eapd_hp | spec->gpio_eapd_speaker; 134 snd_hda_codec_write(codec, 0x01, 0, 135 AC_VERB_SET_GPIO_DATA, spec->gpio_data); 136 } 137 } 138 139 static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid) 140 { 141 unsigned int val; 142 143 val = snd_hda_codec_get_pincfg(codec, nid); 144 return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); 145 } 146 147 static void init_input_coef(struct hda_codec *codec) 148 { 149 struct cs_spec *spec = codec->spec; 150 unsigned int coef; 151 152 /* CS420x has multiple ADC, CS421x has single ADC */ 153 if (spec->vendor_nid == CS420X_VENDOR_NID) { 154 coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG); 155 if (is_active_pin(codec, CS_DMIC2_PIN_NID)) 156 coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */ 157 if (is_active_pin(codec, CS_DMIC1_PIN_NID)) 158 coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off 159 * No effect if SPDIF_OUT2 is 160 * selected in IDX_SPDIF_CTL. 161 */ 162 163 cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef); 164 } 165 } 166 167 static const struct hda_verb cs_coef_init_verbs[] = { 168 {0x11, AC_VERB_SET_PROC_STATE, 1}, 169 {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, 170 {0x11, AC_VERB_SET_PROC_COEF, 171 (0x002a /* DAC1/2/3 SZCMode Soft Ramp */ 172 | 0x0040 /* Mute DACs on FIFO error */ 173 | 0x1000 /* Enable DACs High Pass Filter */ 174 | 0x0400 /* Disable Coefficient Auto increment */ 175 )}, 176 /* ADC1/2 - Digital and Analog Soft Ramp */ 177 {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG}, 178 {0x11, AC_VERB_SET_PROC_COEF, 0x000a}, 179 /* Beep */ 180 {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG}, 181 {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */ 182 183 {} /* terminator */ 184 }; 185 186 static const struct hda_verb cs4208_coef_init_verbs[] = { 187 {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */ 188 {0x24, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ 189 {0x24, AC_VERB_SET_COEF_INDEX, 0x0033}, 190 {0x24, AC_VERB_SET_PROC_COEF, 0x0001}, /* A1 ICS */ 191 {0x24, AC_VERB_SET_COEF_INDEX, 0x0034}, 192 {0x24, AC_VERB_SET_PROC_COEF, 0x1C01}, /* A1 Enable, A Thresh = 300mV */ 193 {} /* terminator */ 194 }; 195 196 /* Errata: CS4207 rev C0/C1/C2 Silicon 197 * 198 * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf 199 * 200 * 6. At high temperature (TA > +85°C), the digital supply current (IVD) 201 * may be excessive (up to an additional 200 μA), which is most easily 202 * observed while the part is being held in reset (RESET# active low). 203 * 204 * Root Cause: At initial powerup of the device, the logic that drives 205 * the clock and write enable to the S/PDIF SRC RAMs is not properly 206 * initialized. 207 * Certain random patterns will cause a steady leakage current in those 208 * RAM cells. The issue will resolve once the SRCs are used (turned on). 209 * 210 * Workaround: The following verb sequence briefly turns on the S/PDIF SRC 211 * blocks, which will alleviate the issue. 212 */ 213 214 static const struct hda_verb cs_errata_init_verbs[] = { 215 {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */ 216 {0x11, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ 217 218 {0x11, AC_VERB_SET_COEF_INDEX, 0x0008}, 219 {0x11, AC_VERB_SET_PROC_COEF, 0x9999}, 220 {0x11, AC_VERB_SET_COEF_INDEX, 0x0017}, 221 {0x11, AC_VERB_SET_PROC_COEF, 0xa412}, 222 {0x11, AC_VERB_SET_COEF_INDEX, 0x0001}, 223 {0x11, AC_VERB_SET_PROC_COEF, 0x0009}, 224 225 {0x07, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Rx: D0 */ 226 {0x08, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Tx: D0 */ 227 228 {0x11, AC_VERB_SET_COEF_INDEX, 0x0017}, 229 {0x11, AC_VERB_SET_PROC_COEF, 0x2412}, 230 {0x11, AC_VERB_SET_COEF_INDEX, 0x0008}, 231 {0x11, AC_VERB_SET_PROC_COEF, 0x0000}, 232 {0x11, AC_VERB_SET_COEF_INDEX, 0x0001}, 233 {0x11, AC_VERB_SET_PROC_COEF, 0x0008}, 234 {0x11, AC_VERB_SET_PROC_STATE, 0x00}, 235 {} /* terminator */ 236 }; 237 238 /* SPDIF setup */ 239 static void init_digital_coef(struct hda_codec *codec) 240 { 241 unsigned int coef; 242 243 coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */ 244 coef |= 0x0008; /* Replace with mute on error */ 245 if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID)) 246 coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2 247 * SPDIF_OUT2 is shared with GPIO1 and 248 * DMIC_SDA2. 249 */ 250 cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef); 251 } 252 253 static int cs_init(struct hda_codec *codec) 254 { 255 struct cs_spec *spec = codec->spec; 256 257 if (spec->vendor_nid == CS420X_VENDOR_NID) { 258 /* init_verb sequence for C0/C1/C2 errata*/ 259 snd_hda_sequence_write(codec, cs_errata_init_verbs); 260 snd_hda_sequence_write(codec, cs_coef_init_verbs); 261 } else if (spec->vendor_nid == CS4208_VENDOR_NID) { 262 snd_hda_sequence_write(codec, cs4208_coef_init_verbs); 263 } 264 265 snd_hda_gen_init(codec); 266 267 if (spec->gpio_mask) 268 snd_hda_codec_set_gpio(codec, spec->gpio_mask, spec->gpio_dir, 269 spec->gpio_data, 0); 270 271 if (spec->vendor_nid == CS420X_VENDOR_NID) { 272 init_input_coef(codec); 273 init_digital_coef(codec); 274 } 275 276 return 0; 277 } 278 279 static int cs_build_controls(struct hda_codec *codec) 280 { 281 int err; 282 283 err = snd_hda_gen_build_controls(codec); 284 if (err < 0) 285 return err; 286 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); 287 return 0; 288 } 289 290 static int cs_parse_auto_config(struct hda_codec *codec) 291 { 292 struct cs_spec *spec = codec->spec; 293 int err; 294 int i; 295 296 err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); 297 if (err < 0) 298 return err; 299 300 err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); 301 if (err < 0) 302 return err; 303 304 /* keep the ADCs powered up when it's dynamically switchable */ 305 if (spec->gen.dyn_adc_switch) { 306 unsigned int done = 0; 307 308 for (i = 0; i < spec->gen.input_mux.num_items; i++) { 309 int idx = spec->gen.dyn_adc_idx[i]; 310 311 if (done & (1 << idx)) 312 continue; 313 snd_hda_gen_fix_pin_power(codec, 314 spec->gen.adc_nids[idx]); 315 done |= 1 << idx; 316 } 317 } 318 319 return 0; 320 } 321 322 static const struct hda_model_fixup cs420x_models[] = { 323 { .id = CS420X_MBP53, .name = "mbp53" }, 324 { .id = CS420X_MBP55, .name = "mbp55" }, 325 { .id = CS420X_IMAC27, .name = "imac27" }, 326 { .id = CS420X_IMAC27_122, .name = "imac27_122" }, 327 { .id = CS420X_APPLE, .name = "apple" }, 328 { .id = CS420X_MBP101, .name = "mbp101" }, 329 { .id = CS420X_MBP81, .name = "mbp81" }, 330 { .id = CS420X_MBA42, .name = "mba42" }, 331 {} 332 }; 333 334 static const struct hda_quirk cs420x_fixup_tbl[] = { 335 SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), 336 SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), 337 SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), 338 SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55), 339 /* this conflicts with too many other models */ 340 /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/ 341 342 /* codec SSID */ 343 SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122), 344 SND_PCI_QUIRK(0x106b, 0x0900, "iMac 12,1", CS420X_IMAC27_122), 345 SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), 346 SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), 347 SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), 348 SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81), 349 SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42), 350 SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), 351 {} /* terminator */ 352 }; 353 354 static const struct hda_pintbl mbp53_pincfgs[] = { 355 { 0x09, 0x012b4050 }, 356 { 0x0a, 0x90100141 }, 357 { 0x0b, 0x90100140 }, 358 { 0x0c, 0x018b3020 }, 359 { 0x0d, 0x90a00110 }, 360 { 0x0e, 0x400000f0 }, 361 { 0x0f, 0x01cbe030 }, 362 { 0x10, 0x014be060 }, 363 { 0x12, 0x400000f0 }, 364 { 0x15, 0x400000f0 }, 365 {} /* terminator */ 366 }; 367 368 static const struct hda_pintbl mbp55_pincfgs[] = { 369 { 0x09, 0x012b4030 }, 370 { 0x0a, 0x90100121 }, 371 { 0x0b, 0x90100120 }, 372 { 0x0c, 0x400000f0 }, 373 { 0x0d, 0x90a00110 }, 374 { 0x0e, 0x400000f0 }, 375 { 0x0f, 0x400000f0 }, 376 { 0x10, 0x014be040 }, 377 { 0x12, 0x400000f0 }, 378 { 0x15, 0x400000f0 }, 379 {} /* terminator */ 380 }; 381 382 static const struct hda_pintbl imac27_pincfgs[] = { 383 { 0x09, 0x012b4050 }, 384 { 0x0a, 0x90100140 }, 385 { 0x0b, 0x90100142 }, 386 { 0x0c, 0x018b3020 }, 387 { 0x0d, 0x90a00110 }, 388 { 0x0e, 0x400000f0 }, 389 { 0x0f, 0x01cbe030 }, 390 { 0x10, 0x014be060 }, 391 { 0x12, 0x01ab9070 }, 392 { 0x15, 0x400000f0 }, 393 {} /* terminator */ 394 }; 395 396 static const struct hda_pintbl mbp101_pincfgs[] = { 397 { 0x0d, 0x40ab90f0 }, 398 { 0x0e, 0x90a600f0 }, 399 { 0x12, 0x50a600f0 }, 400 {} /* terminator */ 401 }; 402 403 static const struct hda_pintbl mba42_pincfgs[] = { 404 { 0x09, 0x012b4030 }, /* HP */ 405 { 0x0a, 0x400000f0 }, 406 { 0x0b, 0x90100120 }, /* speaker */ 407 { 0x0c, 0x400000f0 }, 408 { 0x0d, 0x90a00110 }, /* mic */ 409 { 0x0e, 0x400000f0 }, 410 { 0x0f, 0x400000f0 }, 411 { 0x10, 0x400000f0 }, 412 { 0x12, 0x400000f0 }, 413 { 0x15, 0x400000f0 }, 414 {} /* terminator */ 415 }; 416 417 static const struct hda_pintbl mba6_pincfgs[] = { 418 { 0x10, 0x032120f0 }, /* HP */ 419 { 0x11, 0x500000f0 }, 420 { 0x12, 0x90100010 }, /* Speaker */ 421 { 0x13, 0x500000f0 }, 422 { 0x14, 0x500000f0 }, 423 { 0x15, 0x770000f0 }, 424 { 0x16, 0x770000f0 }, 425 { 0x17, 0x430000f0 }, 426 { 0x18, 0x43ab9030 }, /* Mic */ 427 { 0x19, 0x770000f0 }, 428 { 0x1a, 0x770000f0 }, 429 { 0x1b, 0x770000f0 }, 430 { 0x1c, 0x90a00090 }, 431 { 0x1d, 0x500000f0 }, 432 { 0x1e, 0x500000f0 }, 433 { 0x1f, 0x500000f0 }, 434 { 0x20, 0x500000f0 }, 435 { 0x21, 0x430000f0 }, 436 { 0x22, 0x430000f0 }, 437 {} /* terminator */ 438 }; 439 440 static void cs420x_fixup_gpio_13(struct hda_codec *codec, 441 const struct hda_fixup *fix, int action) 442 { 443 if (action == HDA_FIXUP_ACT_PRE_PROBE) { 444 struct cs_spec *spec = codec->spec; 445 446 spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */ 447 spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ 448 spec->gpio_mask = spec->gpio_dir = 449 spec->gpio_eapd_hp | spec->gpio_eapd_speaker; 450 } 451 } 452 453 static void cs420x_fixup_gpio_23(struct hda_codec *codec, 454 const struct hda_fixup *fix, int action) 455 { 456 if (action == HDA_FIXUP_ACT_PRE_PROBE) { 457 struct cs_spec *spec = codec->spec; 458 459 spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */ 460 spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ 461 spec->gpio_mask = spec->gpio_dir = 462 spec->gpio_eapd_hp | spec->gpio_eapd_speaker; 463 } 464 } 465 466 static const struct hda_fixup cs420x_fixups[] = { 467 [CS420X_MBP53] = { 468 .type = HDA_FIXUP_PINS, 469 .v.pins = mbp53_pincfgs, 470 .chained = true, 471 .chain_id = CS420X_APPLE, 472 }, 473 [CS420X_MBP55] = { 474 .type = HDA_FIXUP_PINS, 475 .v.pins = mbp55_pincfgs, 476 .chained = true, 477 .chain_id = CS420X_GPIO_13, 478 }, 479 [CS420X_IMAC27] = { 480 .type = HDA_FIXUP_PINS, 481 .v.pins = imac27_pincfgs, 482 .chained = true, 483 .chain_id = CS420X_GPIO_13, 484 }, 485 [CS420X_GPIO_13] = { 486 .type = HDA_FIXUP_FUNC, 487 .v.func = cs420x_fixup_gpio_13, 488 }, 489 [CS420X_GPIO_23] = { 490 .type = HDA_FIXUP_FUNC, 491 .v.func = cs420x_fixup_gpio_23, 492 }, 493 [CS420X_MBP101] = { 494 .type = HDA_FIXUP_PINS, 495 .v.pins = mbp101_pincfgs, 496 .chained = true, 497 .chain_id = CS420X_GPIO_13, 498 }, 499 [CS420X_MBP81] = { 500 .type = HDA_FIXUP_VERBS, 501 .v.verbs = (const struct hda_verb[]) { 502 /* internal mic ADC2: right only, single ended */ 503 {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG}, 504 {0x11, AC_VERB_SET_PROC_COEF, 0x102a}, 505 {} 506 }, 507 .chained = true, 508 .chain_id = CS420X_GPIO_13, 509 }, 510 [CS420X_MBA42] = { 511 .type = HDA_FIXUP_PINS, 512 .v.pins = mba42_pincfgs, 513 .chained = true, 514 .chain_id = CS420X_GPIO_13, 515 }, 516 }; 517 518 static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid) 519 { 520 struct cs_spec *spec; 521 522 spec = kzalloc_obj(*spec); 523 if (!spec) 524 return NULL; 525 codec->spec = spec; 526 spec->vendor_nid = vendor_nid; 527 codec->power_save_node = 1; 528 snd_hda_gen_spec_init(&spec->gen); 529 530 return spec; 531 } 532 533 static int cs420x_probe(struct hda_codec *codec) 534 { 535 int err; 536 537 codec->single_adc_amp = 1; 538 539 snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, 540 cs420x_fixups); 541 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); 542 543 err = cs_parse_auto_config(codec); 544 if (err < 0) 545 return err; 546 547 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); 548 549 return 0; 550 } 551 552 /* 553 * CS4208 support: 554 * Its layout is no longer compatible with CS4206/CS4207 555 */ 556 enum { 557 CS4208_MAC_AUTO, 558 CS4208_MBA6, 559 CS4208_MBP11, 560 CS4208_MACMINI, 561 CS4208_GPIO0, 562 }; 563 564 static const struct hda_model_fixup cs4208_models[] = { 565 { .id = CS4208_GPIO0, .name = "gpio0" }, 566 { .id = CS4208_MBA6, .name = "mba6" }, 567 { .id = CS4208_MBP11, .name = "mbp11" }, 568 { .id = CS4208_MACMINI, .name = "macmini" }, 569 {} 570 }; 571 572 static const struct hda_quirk cs4208_fixup_tbl[] = { 573 SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO), 574 {} /* terminator */ 575 }; 576 577 /* codec SSID matching */ 578 static const struct hda_quirk cs4208_mac_fixup_tbl[] = { 579 SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), 580 SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI), 581 SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), 582 SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6), 583 SND_PCI_QUIRK(0x106b, 0x7800, "MacPro 6,1", CS4208_MACMINI), 584 SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11), 585 {} /* terminator */ 586 }; 587 588 static void cs4208_fixup_gpio0(struct hda_codec *codec, 589 const struct hda_fixup *fix, int action) 590 { 591 if (action == HDA_FIXUP_ACT_PRE_PROBE) { 592 struct cs_spec *spec = codec->spec; 593 594 spec->gpio_eapd_hp = 0; 595 spec->gpio_eapd_speaker = 1; 596 spec->gpio_mask = spec->gpio_dir = 597 spec->gpio_eapd_hp | spec->gpio_eapd_speaker; 598 } 599 } 600 601 static const struct hda_fixup cs4208_fixups[]; 602 603 /* remap the fixup from codec SSID and apply it */ 604 static void cs4208_fixup_mac(struct hda_codec *codec, 605 const struct hda_fixup *fix, int action) 606 { 607 if (action != HDA_FIXUP_ACT_PRE_PROBE) 608 return; 609 610 codec->fixup_id = HDA_FIXUP_ID_NOT_SET; 611 snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups); 612 if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET) 613 codec->fixup_id = CS4208_GPIO0; /* default fixup */ 614 snd_hda_apply_fixup(codec, action); 615 } 616 617 /* MacMini 7,1 has the inverted jack detection */ 618 static void cs4208_fixup_macmini(struct hda_codec *codec, 619 const struct hda_fixup *fix, int action) 620 { 621 static const struct hda_pintbl pincfgs[] = { 622 { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */ 623 { 0x21, 0x004be140 }, /* SPDIF: disable detect */ 624 { } 625 }; 626 627 if (action == HDA_FIXUP_ACT_PRE_PROBE) { 628 /* HP pin (0x10) has an inverted detection */ 629 codec->inv_jack_detect = 1; 630 /* disable the bogus Mic and SPDIF jack detections */ 631 snd_hda_apply_pincfgs(codec, pincfgs); 632 } 633 } 634 635 static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol, 636 struct snd_ctl_elem_value *ucontrol) 637 { 638 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 639 struct cs_spec *spec = codec->spec; 640 hda_nid_t pin = spec->gen.autocfg.dig_out_pins[0]; 641 int pinctl = ucontrol->value.integer.value[0] ? PIN_OUT : 0; 642 643 snd_hda_set_pin_ctl_cache(codec, pin, pinctl); 644 return spec->spdif_sw_put(kcontrol, ucontrol); 645 } 646 647 /* hook the SPDIF switch */ 648 static void cs4208_fixup_spdif_switch(struct hda_codec *codec, 649 const struct hda_fixup *fix, int action) 650 { 651 if (action == HDA_FIXUP_ACT_BUILD) { 652 struct cs_spec *spec = codec->spec; 653 struct snd_kcontrol *kctl; 654 655 if (!spec->gen.autocfg.dig_out_pins[0]) 656 return; 657 kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch"); 658 if (!kctl) 659 return; 660 spec->spdif_sw_put = kctl->put; 661 kctl->put = cs4208_spdif_sw_put; 662 } 663 } 664 665 static const struct hda_fixup cs4208_fixups[] = { 666 [CS4208_MBA6] = { 667 .type = HDA_FIXUP_PINS, 668 .v.pins = mba6_pincfgs, 669 .chained = true, 670 .chain_id = CS4208_GPIO0, 671 }, 672 [CS4208_MBP11] = { 673 .type = HDA_FIXUP_FUNC, 674 .v.func = cs4208_fixup_spdif_switch, 675 .chained = true, 676 .chain_id = CS4208_GPIO0, 677 }, 678 [CS4208_MACMINI] = { 679 .type = HDA_FIXUP_FUNC, 680 .v.func = cs4208_fixup_macmini, 681 .chained = true, 682 .chain_id = CS4208_GPIO0, 683 }, 684 [CS4208_GPIO0] = { 685 .type = HDA_FIXUP_FUNC, 686 .v.func = cs4208_fixup_gpio0, 687 }, 688 [CS4208_MAC_AUTO] = { 689 .type = HDA_FIXUP_FUNC, 690 .v.func = cs4208_fixup_mac, 691 }, 692 }; 693 694 /* correct the 0dB offset of input pins */ 695 static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc) 696 { 697 unsigned int caps; 698 699 caps = query_amp_caps(codec, adc, HDA_INPUT); 700 caps &= ~(AC_AMPCAP_OFFSET); 701 caps |= 0x02; 702 snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps); 703 } 704 705 static int cs4208_probe(struct hda_codec *codec) 706 { 707 struct cs_spec *spec = codec->spec; 708 int err; 709 710 /* exclude NID 0x10 (HP) from output volumes due to different steps */ 711 spec->gen.out_vol_mask = 1ULL << 0x10; 712 713 snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl, 714 cs4208_fixups); 715 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); 716 717 snd_hda_override_wcaps(codec, 0x18, 718 get_wcaps(codec, 0x18) | AC_WCAP_STEREO); 719 cs4208_fix_amp_caps(codec, 0x18); 720 cs4208_fix_amp_caps(codec, 0x1b); 721 cs4208_fix_amp_caps(codec, 0x1c); 722 723 err = cs_parse_auto_config(codec); 724 if (err < 0) 725 return err; 726 727 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); 728 729 return 0; 730 } 731 732 static int cs_codec_probe(struct hda_codec *codec, 733 const struct hda_device_id *id) 734 { 735 struct cs_spec *spec; 736 int err; 737 738 spec = cs_alloc_spec(codec, id->driver_data); 739 if (!spec) 740 return -ENOMEM; 741 spec->gen.automute_hook = cs_automute; 742 743 if (spec->vendor_nid == CS4208_VENDOR_NID) 744 err = cs4208_probe(codec); 745 else 746 err = cs420x_probe(codec); 747 if (err < 0) 748 snd_hda_gen_remove(codec); 749 return err; 750 } 751 752 static const struct hda_codec_ops cs_codec_ops = { 753 .probe = cs_codec_probe, 754 .remove = snd_hda_gen_remove, 755 .build_controls = cs_build_controls, 756 .build_pcms = snd_hda_gen_build_pcms, 757 .init = cs_init, 758 .unsol_event = snd_hda_jack_unsol_event, 759 .stream_pm = snd_hda_gen_stream_pm, 760 }; 761 762 /* 763 * driver entries 764 */ 765 static const struct hda_device_id snd_hda_id_cs420x[] = { 766 HDA_CODEC_ID_MODEL(0x10134206, "CS4206", CS420X_VENDOR_NID), 767 HDA_CODEC_ID_MODEL(0x10134207, "CS4207", CS420X_VENDOR_NID), 768 HDA_CODEC_ID_MODEL(0x10134208, "CS4208", CS4208_VENDOR_NID), 769 {} /* terminator */ 770 }; 771 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs420x); 772 773 MODULE_LICENSE("GPL"); 774 MODULE_DESCRIPTION("Cirrus Logic CS420x HD-audio codec"); 775 776 static struct hda_codec_driver cs420x_driver = { 777 .id = snd_hda_id_cs420x, 778 .ops = &cs_codec_ops, 779 }; 780 781 module_hda_codec_driver(cs420x_driver); 782