diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_auto_parser.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 18 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.c | 5 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 223 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 86 |
7 files changed, 225 insertions, 117 deletions
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 4f7d2dfcef7b..a98e25ebfd63 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -141,7 +141,6 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, memset(sequences_hp, 0, sizeof(sequences_hp)); assoc_line_out = 0; - codec->ignore_misc_bit = true; end_nid = codec->start_nid + codec->num_nodes; for (nid = codec->start_nid; nid < end_nid; nid++) { unsigned int wid_caps = get_wcaps(codec, nid); @@ -157,9 +156,6 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & - AC_DEFCFG_MISC_NO_PRESENCE)) - codec->ignore_misc_bit = false; conn = get_defcfg_connect(def_conf); if (conn == AC_JACK_PORT_NONE) continue; @@ -739,7 +735,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, for (q = quirk; q->subvendor; q++) { unsigned int vendorid = q->subdevice | (q->subvendor << 16); - if (vendorid == codec->subsystem_id) { + unsigned int mask = 0xffff0000 | q->subdevice_mask; + if ((codec->subsystem_id & mask) == (vendorid & mask)) { id = q->value; #ifdef CONFIG_SND_DEBUG_VERBOSE name = q->name; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c4c62edca556..960800b862ab 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2368,6 +2368,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) } if (codec->patch_ops.free) codec->patch_ops.free(codec); + memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); snd_hda_jack_tbl_clear(codec); codec->proc_widget_hook = NULL; codec->spec = NULL; @@ -2383,7 +2384,6 @@ int snd_hda_codec_reset(struct hda_codec *codec) codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; - memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); codec->slave_dig_outs = NULL; codec->spdif_status_reset = 0; module_put(codec->owner); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ed3de8d151c8..507fe8a917b6 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -862,7 +862,6 @@ struct hda_codec { unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */ unsigned int pins_shutup:1; /* pins are shut up */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ - unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */ unsigned int no_jack_detect:1; /* Machine has no jack-detection */ unsigned int pcm_format_first:1; /* PCM format must be set first */ unsigned int epss:1; /* supporting EPSS? */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6a19f6af9517..195d84726187 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -64,7 +64,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; static char *model[SNDRV_CARDS]; -static int position_fix[SNDRV_CARDS]; +static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_only[SNDRV_CARDS]; @@ -88,7 +88,7 @@ module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param_array(position_fix, int, NULL, 0444); MODULE_PARM_DESC(position_fix, "DMA pointer read method." - "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO)."); + "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO)."); module_param_array(bdl_pos_adj, int, NULL, 0644); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); module_param_array(probe_mask, int, NULL, 0444); @@ -415,6 +415,7 @@ struct azx_dev { */ unsigned int insufficient :1; unsigned int wc_marked:1; + unsigned int no_period_wakeup:1; }; /* CORB/RIRB */ @@ -1419,7 +1420,7 @@ static int azx_setup_periods(struct azx *chip, ofs = 0; azx_dev->frags = 0; pos_adj = bdl_pos_adj[chip->dev_index]; - if (pos_adj > 0) { + if (!azx_dev->no_period_wakeup && pos_adj > 0) { struct snd_pcm_runtime *runtime = substream->runtime; int pos_align = pos_adj; pos_adj = (pos_adj * runtime->rate + 47999) / 48000; @@ -1435,8 +1436,7 @@ static int azx_setup_periods(struct azx *chip, pos_adj = 0; } else { ofs = setup_bdle(chip, substream, azx_dev, - &bdl, ofs, pos_adj, - !substream->runtime->no_period_wakeup); + &bdl, ofs, pos_adj, true); if (ofs < 0) goto error; } @@ -1449,7 +1449,7 @@ static int azx_setup_periods(struct azx *chip, else ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs, period_bytes, - !substream->runtime->no_period_wakeup); + !azx_dev->no_period_wakeup); if (ofs < 0) goto error; } @@ -1922,10 +1922,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) if (bufsize != azx_dev->bufsize || period_bytes != azx_dev->period_bytes || - format_val != azx_dev->format_val) { + format_val != azx_dev->format_val || + runtime->no_period_wakeup != azx_dev->no_period_wakeup) { azx_dev->bufsize = bufsize; azx_dev->period_bytes = period_bytes; azx_dev->format_val = format_val; + azx_dev->no_period_wakeup = runtime->no_period_wakeup; err = azx_setup_periods(chip, substream, azx_dev); if (err < 0) return err; @@ -2794,6 +2796,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x1b43, "ASUS K53E", POS_FIX_POSBUF), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x10de, 0xcb89, "Macbook Pro 7,1", POS_FIX_LPIB), SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB), @@ -2810,6 +2813,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix) const struct snd_pci_quirk *q; switch (fix) { + case POS_FIX_AUTO: case POS_FIX_LPIB: case POS_FIX_POSBUF: case POS_FIX_VIACOMBO: diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index aaccc0236bda..c9333c9688fb 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -26,9 +26,8 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) return false; if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) return false; - if (!codec->ignore_misc_bit && - (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & - AC_DEFCFG_MISC_NO_PRESENCE)) + if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & + AC_DEFCFG_MISC_NO_PRESENCE) return false; if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) return false; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 0bddb3ee1101..fcfc9f0a056b 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -34,7 +34,8 @@ */ struct cs_spec { - int board_config; + struct hda_gen_spec gen; + struct auto_pin_cfg autocfg; struct hda_multi_out multiout; struct snd_kcontrol *vmaster_sw; @@ -80,16 +81,20 @@ enum { CS420X_MBP53, CS420X_MBP55, CS420X_IMAC27, - CS420X_IMAC27_122, - CS420X_APPLE, + CS420X_GPIO_13, + CS420X_GPIO_23, + CS420X_MBP101, + CS420X_MBP101_COEF, CS420X_AUTO, - CS420X_MODELS + /* aliases */ + CS420X_IMAC27_122 = CS420X_GPIO_23, + CS420X_APPLE = CS420X_GPIO_13, }; /* CS421x boards */ enum { CS421X_CDB4210, - CS421X_MODELS + CS421X_SENSE_B, }; /* Vendor-specific processing widget */ @@ -1157,6 +1162,14 @@ static const struct hda_verb cs_errata_init_verbs[] = { {} /* terminator */ }; +static const struct hda_verb mbp101_init_verbs[] = { + {0x11, AC_VERB_SET_COEF_INDEX, 0x0002}, + {0x11, AC_VERB_SET_PROC_COEF, 0x100a}, + {0x11, AC_VERB_SET_COEF_INDEX, 0x0004}, + {0x11, AC_VERB_SET_PROC_COEF, 0x000f}, + {} +}; + /* SPDIF setup */ static void init_digital(struct hda_codec *codec) { @@ -1278,38 +1291,32 @@ static int cs_parse_auto_config(struct hda_codec *codec) return 0; } -static const char * const cs420x_models[CS420X_MODELS] = { - [CS420X_MBP53] = "mbp53", - [CS420X_MBP55] = "mbp55", - [CS420X_IMAC27] = "imac27", - [CS420X_IMAC27_122] = "imac27_122", - [CS420X_APPLE] = "apple", - [CS420X_AUTO] = "auto", +static const struct hda_model_fixup cs420x_models[] = { + { .id = CS420X_MBP53, .name = "mbp53" }, + { .id = CS420X_MBP55, .name = "mbp55" }, + { .id = CS420X_IMAC27, .name = "imac27" }, + { .id = CS420X_IMAC27_122, .name = "imac27_122" }, + { .id = CS420X_APPLE, .name = "apple" }, + { .id = CS420X_MBP101, .name = "mbp101" }, + {} }; - -static const struct snd_pci_quirk cs420x_cfg_tbl[] = { +static const struct snd_pci_quirk cs420x_fixup_tbl[] = { SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55), /* this conflicts with too many other models */ /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/ - {} /* terminator */ -}; -static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = { + /* codec SSID */ SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), + SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), {} /* terminator */ }; -struct cs_pincfg { - hda_nid_t nid; - u32 val; -}; - -static const struct cs_pincfg mbp53_pincfgs[] = { +static const struct hda_pintbl mbp53_pincfgs[] = { { 0x09, 0x012b4050 }, { 0x0a, 0x90100141 }, { 0x0b, 0x90100140 }, @@ -1323,7 +1330,7 @@ static const struct cs_pincfg mbp53_pincfgs[] = { {} /* terminator */ }; -static const struct cs_pincfg mbp55_pincfgs[] = { +static const struct hda_pintbl mbp55_pincfgs[] = { { 0x09, 0x012b4030 }, { 0x0a, 0x90100121 }, { 0x0b, 0x90100120 }, @@ -1337,7 +1344,7 @@ static const struct cs_pincfg mbp55_pincfgs[] = { {} /* terminator */ }; -static const struct cs_pincfg imac27_pincfgs[] = { +static const struct hda_pintbl imac27_pincfgs[] = { { 0x09, 0x012b4050 }, { 0x0a, 0x90100140 }, { 0x0b, 0x90100142 }, @@ -1351,22 +1358,78 @@ static const struct cs_pincfg imac27_pincfgs[] = { {} /* terminator */ }; -static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { - [CS420X_MBP53] = mbp53_pincfgs, - [CS420X_MBP55] = mbp55_pincfgs, - [CS420X_IMAC27] = imac27_pincfgs, +static const struct hda_pintbl mbp101_pincfgs[] = { + { 0x0d, 0x40ab90f0 }, + { 0x0e, 0x90a600f0 }, + { 0x12, 0x50a600f0 }, + {} /* terminator */ }; -static void fix_pincfg(struct hda_codec *codec, int model, - const struct cs_pincfg **pin_configs) +static void cs420x_fixup_gpio_13(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */ + spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ + spec->gpio_mask = spec->gpio_dir = + spec->gpio_eapd_hp | spec->gpio_eapd_speaker; + } +} + +static void cs420x_fixup_gpio_23(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - const struct cs_pincfg *cfg = pin_configs[model]; - if (!cfg) - return; - for (; cfg->nid; cfg++) - snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */ + spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ + spec->gpio_mask = spec->gpio_dir = + spec->gpio_eapd_hp | spec->gpio_eapd_speaker; + } } +static const struct hda_fixup cs420x_fixups[] = { + [CS420X_MBP53] = { + .type = HDA_FIXUP_PINS, + .v.pins = mbp53_pincfgs, + .chained = true, + .chain_id = CS420X_APPLE, + }, + [CS420X_MBP55] = { + .type = HDA_FIXUP_PINS, + .v.pins = mbp55_pincfgs, + .chained = true, + .chain_id = CS420X_GPIO_13, + }, + [CS420X_IMAC27] = { + .type = HDA_FIXUP_PINS, + .v.pins = imac27_pincfgs, + .chained = true, + .chain_id = CS420X_GPIO_13, + }, + [CS420X_GPIO_13] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs420x_fixup_gpio_13, + }, + [CS420X_GPIO_23] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs420x_fixup_gpio_23, + }, + [CS420X_MBP101] = { + .type = HDA_FIXUP_PINS, + .v.pins = mbp101_pincfgs, + .chained = true, + .chain_id = CS420X_MBP101_COEF, + }, + [CS420X_MBP101_COEF] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = mbp101_init_verbs, + .chained = true, + .chain_id = CS420X_GPIO_13, + }, +}; + static int patch_cs420x(struct hda_codec *codec) { struct cs_spec *spec; @@ -1379,33 +1442,9 @@ static int patch_cs420x(struct hda_codec *codec) spec->vendor_nid = CS420X_VENDOR_NID; - spec->board_config = - snd_hda_check_board_config(codec, CS420X_MODELS, - cs420x_models, cs420x_cfg_tbl); - if (spec->board_config < 0) - spec->board_config = - snd_hda_check_board_codec_sid_config(codec, - CS420X_MODELS, NULL, cs420x_codec_cfg_tbl); - if (spec->board_config >= 0) - fix_pincfg(codec, spec->board_config, cs_pincfgs); - - switch (spec->board_config) { - case CS420X_IMAC27: - case CS420X_MBP53: - case CS420X_MBP55: - case CS420X_APPLE: - spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */ - spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ - spec->gpio_mask = spec->gpio_dir = - spec->gpio_eapd_hp | spec->gpio_eapd_speaker; - break; - case CS420X_IMAC27_122: - spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */ - spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ - spec->gpio_mask = spec->gpio_dir = - spec->gpio_eapd_hp | spec->gpio_eapd_speaker; - break; - } + snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, + cs420x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); err = cs_parse_auto_config(codec); if (err < 0) @@ -1413,6 +1452,8 @@ static int patch_cs420x(struct hda_codec *codec) codec->patch_ops = cs_patch_ops; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; error: @@ -1430,11 +1471,12 @@ static int patch_cs420x(struct hda_codec *codec) */ /* CS4210 board names */ -static const char *cs421x_models[CS421X_MODELS] = { - [CS421X_CDB4210] = "cdb4210", +static const struct hda_model_fixup cs421x_models[] = { + { .id = CS421X_CDB4210, .name = "cdb4210" }, + {} }; -static const struct snd_pci_quirk cs421x_cfg_tbl[] = { +static const struct snd_pci_quirk cs421x_fixup_tbl[] = { /* Test Intel board + CDB2410 */ SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), {} /* terminator */ @@ -1442,7 +1484,7 @@ static const struct snd_pci_quirk cs421x_cfg_tbl[] = { /* CS4210 board pinconfigs */ /* Default CS4210 (CDB4210)*/ -static const struct cs_pincfg cdb4210_pincfgs[] = { +static const struct hda_pintbl cdb4210_pincfgs[] = { { 0x05, 0x0321401f }, { 0x06, 0x90170010 }, { 0x07, 0x03813031 }, @@ -1452,8 +1494,26 @@ static const struct cs_pincfg cdb4210_pincfgs[] = { {} /* terminator */ }; -static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = { - [CS421X_CDB4210] = cdb4210_pincfgs, +/* Setup GPIO/SENSE for each board (if used) */ +static void cs421x_fixup_sense_b(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct cs_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->sense_b = 1; +} + +static const struct hda_fixup cs421x_fixups[] = { + [CS421X_CDB4210] = { + .type = HDA_FIXUP_PINS, + .v.pins = cdb4210_pincfgs, + .chained = true, + .chain_id = CS421X_SENSE_B, + }, + [CS421X_SENSE_B] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs421x_fixup_sense_b, + } }; static const struct hda_verb cs421x_coef_init_verbs[] = { @@ -1935,26 +1995,9 @@ static int patch_cs4210(struct hda_codec *codec) spec->vendor_nid = CS4210_VENDOR_NID; - spec->board_config = - snd_hda_check_board_config(codec, CS421X_MODELS, - cs421x_models, cs421x_cfg_tbl); - if (spec->board_config >= 0) - fix_pincfg(codec, spec->board_config, cs421x_pincfgs); - /* - Setup GPIO/SENSE for each board (if used) - */ - switch (spec->board_config) { - case CS421X_CDB4210: - snd_printd("CS4210 board: %s\n", - cs421x_models[spec->board_config]); -/* spec->gpio_mask = 3; - spec->gpio_dir = 3; - spec->gpio_data = 3; -*/ - spec->sense_b = 1; - - break; - } + snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, + cs421x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* Update the GPIO/DMIC/SENSE_B pinmux before the configuration @@ -1969,6 +2012,8 @@ static int patch_cs4210(struct hda_codec *codec) codec->patch_ops = cs421x_patch_ops; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; error: diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c16d0f822b5b..bb6c50e7b5da 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -103,6 +103,7 @@ enum { STAC_HP_ZEPHYR, STAC_92HD83XXX_HP_LED, STAC_92HD83XXX_HP_INV_LED, + STAC_92HD83XXX_HP_MIC_LED, STAC_92HD83XXX_MODELS }; @@ -215,6 +216,9 @@ struct sigmatel_spec { unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */ unsigned int vref_led; + unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */ + bool mic_mute_led_on; /* current mic mute state */ + /* stream */ unsigned int stream_delay; @@ -1075,7 +1079,7 @@ static struct snd_kcontrol_new stac_smux_mixer = { static const char * const slave_pfxs[] = { "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "IEC958", + "Headphone", "Speaker", "IEC958", "PCM", NULL }; @@ -1679,6 +1683,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_HP_ZEPHYR] = "hp-zephyr", [STAC_92HD83XXX_HP_LED] = "hp-led", [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", + [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led", }; static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -1703,6 +1708,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, + "HP Folio", STAC_92HD83XXX_HP_MIC_LED), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, @@ -2791,18 +2798,27 @@ stac_control_new(struct sigmatel_spec *spec, return knew; } -static int stac92xx_add_control_temp(struct sigmatel_spec *spec, - const struct snd_kcontrol_new *ktemp, - int idx, const char *name, - unsigned long val) +static struct snd_kcontrol_new * +add_control_temp(struct sigmatel_spec *spec, + const struct snd_kcontrol_new *ktemp, + int idx, const char *name, + unsigned long val) { struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, HDA_SUBDEV_AMP_FLAG); if (!knew) - return -ENOMEM; + return NULL; knew->index = idx; knew->private_value = val; - return 0; + return knew; +} + +static int stac92xx_add_control_temp(struct sigmatel_spec *spec, + const struct snd_kcontrol_new *ktemp, + int idx, const char *name, + unsigned long val) +{ + return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM; } static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, @@ -3245,18 +3261,56 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, return 0; } +static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, + unsigned int dir_mask, unsigned int data); + +/* hook for controlling mic-mute LED GPIO */ +static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + int err; + bool mute; + + err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + if (err <= 0) + return err; + mute = !(ucontrol->value.integer.value[0] && + ucontrol->value.integer.value[1]); + if (spec->mic_mute_led_on != mute) { + spec->mic_mute_led_on = mute; + if (mute) + spec->gpio_data |= spec->mic_mute_led_gpio; + else + spec->gpio_data &= ~spec->mic_mute_led_gpio; + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data); + } + return err; +} + static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, unsigned long sw, int idx) { + struct sigmatel_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; int err; + err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, "Capture Volume", vol); if (err < 0) return err; - err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx, - "Capture Switch", sw); - if (err < 0) - return err; + + knew = add_control_temp(spec, + &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE], + idx, "Capture Switch", sw); + if (!knew) + return -ENOMEM; + /* add a LED hook for some HP laptops */ + if (spec->mic_mute_led_gpio) + knew->put = stac92xx_capture_sw_put_led; + return 0; } @@ -5579,6 +5633,9 @@ again: case STAC_92HD83XXX_HP_INV_LED: default_polarity = 1; break; + case STAC_92HD83XXX_HP_MIC_LED: + spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ + break; } if (find_mute_led_cfg(codec, default_polarity)) @@ -5597,6 +5654,13 @@ again: } } + if (spec->mic_mute_led_gpio) { + spec->gpio_mask |= spec->mic_mute_led_gpio; + spec->gpio_dir |= spec->mic_mute_led_gpio; + spec->mic_mute_led_on = true; + spec->gpio_data |= spec->mic_mute_led_gpio; + } + err = stac92xx_parse_auto_config(codec); if (!err) { if (spec->board_config < 0) { |