summaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_auto_parser.c7
-rw-r--r--sound/pci/hda/hda_codec.c2
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_intel.c18
-rw-r--r--sound/pci/hda/hda_jack.c5
-rw-r--r--sound/pci/hda/patch_cirrus.c223
-rw-r--r--sound/pci/hda/patch_sigmatel.c86
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) {