[ALSA] hda-codec - restore HDA sigmatel pin configs on resume
authorRichard Fish <bigfish@asmallpond.org>
Wed, 23 Aug 2006 16:31:34 +0000 (18:31 +0200)
committerJaroslav Kysela <perex@suse.cz>
Sat, 23 Sep 2006 08:43:51 +0000 (10:43 +0200)
This patch restores the Intel HDA Sigmatel codec pin configuration on
resume.  Most of it is dedicated to saving the BIOS pin configuration
if necessary, so that even unrecognized chips can be resumed correctly.

Signed-off-by: Richard Fish <bigfish@asmallpond.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
sound/pci/hda/patch_sigmatel.c

index 139d73e18a3c98ccbaa60a2f192199e6a388a935..239ae3fad05408a7fc0fb3cf5920bcd3e474c89e 100644 (file)
@@ -73,6 +73,7 @@ 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;
@@ -584,13 +585,42 @@ static struct hda_board_config stac9205_cfg_tbl[] = {
        {} /* terminator */
 };
 
+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;
+       }
+       
+       for (i = 0; i < spec->num_pins; i++) {
+               hda_nid_t nid = spec->pin_nids[i];
+               unsigned int pin_cfg;
+               
+               pin_cfg = snd_hda_codec_read(codec, nid, 0, 
+                       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;
+       }
+       
+       return 0;
+}
+
 static void stac92xx_set_config_regs(struct hda_codec *codec)
 {
        int i;
        struct sigmatel_spec *spec = codec->spec;
        unsigned int pin_cfg;
 
-       for (i=0; i < spec->num_pins; i++) {
+       if (! spec->pin_nids || ! spec->pin_configs)
+               return;
+
+       for (i = 0; i < spec->num_pins; i++) {
                snd_hda_codec_write(codec, spec->pin_nids[i], 0,
                                    AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
                                    spec->pin_configs[i] & 0x000000ff);
@@ -1302,6 +1332,9 @@ static void stac92xx_free(struct hda_codec *codec)
                kfree(spec->kctl_alloc);
        }
 
+       if (spec->bios_pin_configs)
+               kfree(spec->bios_pin_configs);
+
        kfree(spec);
 }
 
@@ -1359,6 +1392,7 @@ static int stac92xx_resume(struct hda_codec *codec)
        int i;
 
        stac92xx_init(codec);
+       stac92xx_set_config_regs(codec);
        for (i = 0; i < spec->num_mixers; i++)
                snd_hda_resume_ctls(codec, spec->mixers[i]);
        if (spec->multiout.dig_out_nid)
@@ -1391,12 +1425,18 @@ static int patch_stac9200(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       spec->num_pins = 8;
+       spec->pin_nids = stac9200_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl);
-       if (spec->board_config < 0)
-                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
-       else {
-               spec->num_pins = 8;
-               spec->pin_nids = stac9200_pin_nids;
+       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);
        }
@@ -1432,13 +1472,19 @@ static int patch_stac922x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       spec->num_pins = 10;
+       spec->pin_nids = stac922x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
-       if (spec->board_config < 0)
-                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
-                           "using BIOS defaults\n");
-       else if (stac922x_brd_tbl[spec->board_config] != NULL) {
-               spec->num_pins = 10;
-               spec->pin_nids = stac922x_pin_nids;
+       if (spec->board_config < 0) {
+               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);
        }
@@ -1476,12 +1522,18 @@ static int patch_stac927x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       spec->num_pins = 14;
+       spec->pin_nids = stac927x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl);
-       if (spec->board_config < 0)
+       if (spec->board_config < 0) {
                 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
-       else if (stac927x_brd_tbl[spec->board_config] != NULL) {
-               spec->num_pins = 14;
-               spec->pin_nids = stac927x_pin_nids;
+               err = stac92xx_save_bios_config_regs(codec);
+               if (err < 0) {
+                       stac92xx_free(codec);
+                       return err;
+               }
+               spec->pin_configs = spec->bios_pin_configs;
+       } else if (stac927x_brd_tbl[spec->board_config] != NULL) {
                spec->pin_configs = stac927x_brd_tbl[spec->board_config];
                stac92xx_set_config_regs(codec);
        }
@@ -1532,12 +1584,18 @@ static int patch_stac9205(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       spec->num_pins = 14;
+       spec->pin_nids = stac9205_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl);
-       if (spec->board_config < 0)
-                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
-       else {
-               spec->num_pins = 14;
-               spec->pin_nids = stac9205_pin_nids;
+       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);
        }