From af9f341a94482594ac28cb5b07c655b458bfe84e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 10:38:56 +0100 Subject: [PATCH] ALSA: hda - Fix restore of pin configs at resume for STAC/IDT codecs Fixed the restore of pin configs at resume for some STAC/IDT codec models. These models set explicitly the pin configs after the default init configs, and these aren't restored properly at resume. This patch introduces two changes: - Allocate always pin_configs array in stac_spec so that the driver can overwrite the value freely - Introduce stac_change_pin_config() to change the pin config value Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 178 ++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 82 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bf9a40ee789e..3029f5b1419a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -210,7 +210,6 @@ struct sigmatel_spec { hda_nid_t *pin_nids; unsigned int num_pins; unsigned int *pin_configs; - unsigned int *bios_pin_configs; /* codec specific stuff */ struct hda_verb *init; @@ -2219,12 +2218,11 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec) int i; struct sigmatel_spec *spec = codec->spec; - if (! spec->bios_pin_configs) { - spec->bios_pin_configs = kcalloc(spec->num_pins, - sizeof(*spec->bios_pin_configs), GFP_KERNEL); - if (! spec->bios_pin_configs) - return -ENOMEM; - } + kfree(spec->pin_configs); + spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs), + GFP_KERNEL); + if (!spec->pin_configs) + return -ENOMEM; for (i = 0; i < spec->num_pins; i++) { hda_nid_t nid = spec->pin_nids[i]; @@ -2234,7 +2232,7 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec) AC_VERB_GET_CONFIG_DEFAULT, 0x00); snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n", nid, pin_cfg); - spec->bios_pin_configs[i] = pin_cfg; + spec->pin_configs[i] = pin_cfg; } return 0; @@ -2276,6 +2274,39 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) spec->pin_configs[i]); } +static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins) +{ + struct sigmatel_spec *spec = codec->spec; + + if (!pins) + return stac92xx_save_bios_config_regs(codec); + + kfree(spec->pin_configs); + spec->pin_configs = kmemdup(pins, + spec->num_pins * sizeof(*pins), + GFP_KERNEL); + if (!spec->pin_configs) + return -ENOMEM; + + stac92xx_set_config_regs(codec); + return 0; +} + +static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid, + unsigned int cfg) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_nids[i] == nid) { + spec->pin_configs[i] = cfg; + stac92xx_set_config_reg(codec, nid, cfg); + break; + } + } +} + /* * Analog playback callbacks */ @@ -3906,8 +3937,7 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; - if (spec->bios_pin_configs) - kfree(spec->bios_pin_configs); + kfree(spec->pin_configs); stac92xx_free_jacks(codec); snd_array_free(&spec->events); @@ -4182,14 +4212,12 @@ static int patch_stac9200(struct hda_codec *codec) if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac9200_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac9200_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.max_channels = 2; @@ -4245,14 +4273,12 @@ static int patch_stac925x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac925x_brd_tbl[spec->board_config] != NULL){ - spec->pin_configs = stac925x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac925x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.max_channels = 2; @@ -4334,14 +4360,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD73XX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd73xx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, @@ -4517,14 +4541,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD83XXX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd83xxx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } err = stac92xx_parse_auto_config(codec, 0x1d, 0); @@ -4631,14 +4653,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD71BXX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd71bxx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } switch (codec->vendor_id) { @@ -4680,7 +4700,7 @@ again: /* disable VSW */ spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; - stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); + stac_change_pin_config(codec, 0xf, 0x40f000f0); break; case 0x111d7603: /* 6 Port with Analog Mixer */ if ((codec->revision_id & 0xf) == 1) { @@ -4729,7 +4749,7 @@ again: spec->num_dmuxes = 0; /* enable internal microphone */ - stac92xx_set_config_reg(codec, 0x0e, 0x01813040); + stac_change_pin_config(codec, 0x0e, 0x01813040); stac92xx_auto_set_pinctl(codec, 0x0e, AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); break; @@ -4824,14 +4844,12 @@ static int patch_stac922x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac922x_brd_tbl[spec->board_config] != NULL) { - spec->pin_configs = stac922x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac922x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->adc_nids = stac922x_adc_nids; @@ -4894,14 +4912,12 @@ static int patch_stac927x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for" "STAC927x, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac927x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac927x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->digbeep_nid = 0x23; @@ -4931,15 +4947,15 @@ static int patch_stac927x(struct hda_codec *codec) case 0x10280209: case 0x1028022e: /* correct the device field to SPDIF out */ - stac92xx_set_config_reg(codec, 0x21, 0x01442070); + stac_change_pin_config(codec, 0x21, 0x01442070); break; }; /* configure the analog microphone on some laptops */ - stac92xx_set_config_reg(codec, 0x0c, 0x90a79130); + stac_change_pin_config(codec, 0x0c, 0x90a79130); /* correct the front output jack as a hp out */ - stac92xx_set_config_reg(codec, 0x0f, 0x0227011f); + stac_change_pin_config(codec, 0x0f, 0x0227011f); /* correct the front input jack as a mic */ - stac92xx_set_config_reg(codec, 0x0e, 0x02a79130); + stac_change_pin_config(codec, 0x0e, 0x02a79130); /* fallthru */ case STAC_DELL_3ST: /* GPIO2 High = Enable EAPD */ @@ -5021,14 +5037,12 @@ static int patch_stac9205(struct hda_codec *codec) if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac9205_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac9205_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->digbeep_nid = 0x23; @@ -5055,8 +5069,8 @@ static int patch_stac9205(struct hda_codec *codec) switch (spec->board_config){ case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ - stac92xx_set_config_reg(codec, 0x1f, 0x01441030); - stac92xx_set_config_reg(codec, 0x20, 0x1c410030); + stac_change_pin_config(codec, 0x1f, 0x01441030); + stac_change_pin_config(codec, 0x20, 0x1c410030); /* Enable unsol response for GPIO4/Dock HP connection */ snd_hda_codec_write(codec, codec->afg, 0, -- 2.34.1