diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-09-09 07:57:57 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-09-09 10:09:57 -0400 |
commit | be8cf44526d8972c2dbf6e561162dad924a712a5 (patch) | |
tree | 365ce377f597d8089a31276908c4106e14b5a349 /sound | |
parent | 83f72151352791836a1b9c1542614cc9bf71ac61 (diff) |
ALSA: hda - Add CS4208 codec support for MacBook 6,1 and 6,2
MacBook 6,1 and 6,2 have a CS4208 codec instead of CS4206/CS4207 on
the former models. Most of functions work fine as is, except for the
silent speaker output. After debugging sessions, it turned out that
the machine needs to set GPIO 0 for the speaker amp.
This patch adds the basic support for CS4208 and the fixup for these
MacBooks. Basically the codec works just with the generic parser.
For re-using the existing GPIO amp code and init/free callbacks, a few
places have been changed so that CS4206/4207-specific codes (errata,
etc) won't hit with CS4208.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=60811
Reported-and-tested-by: Imre Kaloz <kaloz@openwrt.org>
Reported-and-tested-by: Ian Munsie <darkstarsword@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 89 |
1 files changed, 82 insertions, 7 deletions
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index cccaf9c7a7bb..b524f89a1f13 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -169,7 +169,7 @@ static void cs_automute(struct hda_codec *codec) | |||
169 | 169 | ||
170 | snd_hda_gen_update_outputs(codec); | 170 | snd_hda_gen_update_outputs(codec); |
171 | 171 | ||
172 | if (spec->gpio_eapd_hp) { | 172 | if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) { |
173 | spec->gpio_data = spec->gen.hp_jack_present ? | 173 | spec->gpio_data = spec->gen.hp_jack_present ? |
174 | spec->gpio_eapd_hp : spec->gpio_eapd_speaker; | 174 | spec->gpio_eapd_hp : spec->gpio_eapd_speaker; |
175 | snd_hda_codec_write(codec, 0x01, 0, | 175 | snd_hda_codec_write(codec, 0x01, 0, |
@@ -291,10 +291,11 @@ static int cs_init(struct hda_codec *codec) | |||
291 | { | 291 | { |
292 | struct cs_spec *spec = codec->spec; | 292 | struct cs_spec *spec = codec->spec; |
293 | 293 | ||
294 | /* init_verb sequence for C0/C1/C2 errata*/ | 294 | if (spec->vendor_nid == CS420X_VENDOR_NID) { |
295 | snd_hda_sequence_write(codec, cs_errata_init_verbs); | 295 | /* init_verb sequence for C0/C1/C2 errata*/ |
296 | 296 | snd_hda_sequence_write(codec, cs_errata_init_verbs); | |
297 | snd_hda_sequence_write(codec, cs_coef_init_verbs); | 297 | snd_hda_sequence_write(codec, cs_coef_init_verbs); |
298 | } | ||
298 | 299 | ||
299 | snd_hda_gen_init(codec); | 300 | snd_hda_gen_init(codec); |
300 | 301 | ||
@@ -307,8 +308,10 @@ static int cs_init(struct hda_codec *codec) | |||
307 | spec->gpio_data); | 308 | spec->gpio_data); |
308 | } | 309 | } |
309 | 310 | ||
310 | init_input_coef(codec); | 311 | if (spec->vendor_nid == CS420X_VENDOR_NID) { |
311 | init_digital_coef(codec); | 312 | init_input_coef(codec); |
313 | init_digital_coef(codec); | ||
314 | } | ||
312 | 315 | ||
313 | return 0; | 316 | return 0; |
314 | } | 317 | } |
@@ -552,6 +555,76 @@ static int patch_cs420x(struct hda_codec *codec) | |||
552 | } | 555 | } |
553 | 556 | ||
554 | /* | 557 | /* |
558 | * CS4208 support: | ||
559 | * Its layout is no longer compatible with CS4206/CS4207, and the generic | ||
560 | * parser seems working fairly well, except for trivial fixups. | ||
561 | */ | ||
562 | enum { | ||
563 | CS4208_GPIO0, | ||
564 | }; | ||
565 | |||
566 | static const struct hda_model_fixup cs4208_models[] = { | ||
567 | { .id = CS4208_GPIO0, .name = "gpio0" }, | ||
568 | {} | ||
569 | }; | ||
570 | |||
571 | static const struct snd_pci_quirk cs4208_fixup_tbl[] = { | ||
572 | /* codec SSID */ | ||
573 | SND_PCI_QUIRK(0x106b, 0x7100, "MacBookPro 6,1", CS4208_GPIO0), | ||
574 | SND_PCI_QUIRK(0x106b, 0x7200, "MacBookPro 6,2", CS4208_GPIO0), | ||
575 | {} /* terminator */ | ||
576 | }; | ||
577 | |||
578 | static void cs4208_fixup_gpio0(struct hda_codec *codec, | ||
579 | const struct hda_fixup *fix, int action) | ||
580 | { | ||
581 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | ||
582 | struct cs_spec *spec = codec->spec; | ||
583 | spec->gpio_eapd_hp = 0; | ||
584 | spec->gpio_eapd_speaker = 1; | ||
585 | spec->gpio_mask = spec->gpio_dir = | ||
586 | spec->gpio_eapd_hp | spec->gpio_eapd_speaker; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | static const struct hda_fixup cs4208_fixups[] = { | ||
591 | [CS4208_GPIO0] = { | ||
592 | .type = HDA_FIXUP_FUNC, | ||
593 | .v.func = cs4208_fixup_gpio0, | ||
594 | }, | ||
595 | }; | ||
596 | |||
597 | static int patch_cs4208(struct hda_codec *codec) | ||
598 | { | ||
599 | struct cs_spec *spec; | ||
600 | int err; | ||
601 | |||
602 | spec = cs_alloc_spec(codec, 0); /* no specific w/a */ | ||
603 | if (!spec) | ||
604 | return -ENOMEM; | ||
605 | |||
606 | spec->gen.automute_hook = cs_automute; | ||
607 | |||
608 | snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl, | ||
609 | cs4208_fixups); | ||
610 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | ||
611 | |||
612 | err = cs_parse_auto_config(codec); | ||
613 | if (err < 0) | ||
614 | goto error; | ||
615 | |||
616 | codec->patch_ops = cs_patch_ops; | ||
617 | |||
618 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | ||
619 | |||
620 | return 0; | ||
621 | |||
622 | error: | ||
623 | cs_free(codec); | ||
624 | return err; | ||
625 | } | ||
626 | |||
627 | /* | ||
555 | * Cirrus Logic CS4210 | 628 | * Cirrus Logic CS4210 |
556 | * | 629 | * |
557 | * 1 DAC => HP(sense) / Speakers, | 630 | * 1 DAC => HP(sense) / Speakers, |
@@ -991,6 +1064,7 @@ static int patch_cs4213(struct hda_codec *codec) | |||
991 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { | 1064 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { |
992 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, | 1065 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, |
993 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, | 1066 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, |
1067 | { .id = 0x10134208, .name = "CS4208", .patch = patch_cs4208 }, | ||
994 | { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 }, | 1068 | { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 }, |
995 | { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 }, | 1069 | { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 }, |
996 | {} /* terminator */ | 1070 | {} /* terminator */ |
@@ -998,6 +1072,7 @@ static const struct hda_codec_preset snd_hda_preset_cirrus[] = { | |||
998 | 1072 | ||
999 | MODULE_ALIAS("snd-hda-codec-id:10134206"); | 1073 | MODULE_ALIAS("snd-hda-codec-id:10134206"); |
1000 | MODULE_ALIAS("snd-hda-codec-id:10134207"); | 1074 | MODULE_ALIAS("snd-hda-codec-id:10134207"); |
1075 | MODULE_ALIAS("snd-hda-codec-id:10134208"); | ||
1001 | MODULE_ALIAS("snd-hda-codec-id:10134210"); | 1076 | MODULE_ALIAS("snd-hda-codec-id:10134210"); |
1002 | MODULE_ALIAS("snd-hda-codec-id:10134213"); | 1077 | MODULE_ALIAS("snd-hda-codec-id:10134213"); |
1003 | 1078 | ||