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