enum {
STAC_9205_REF,
- STAC_M43xx,
+ STAC_9205_DELL_M43,
+ STAC_9205_DELL_M44,
+ STAC_9205_M43xx,
STAC_9205_MODELS
};
STAC_D965_REF,
STAC_D965_3ST,
STAC_D965_5ST,
+ STAC_DELL_3ST,
STAC_927X_MODELS
};
unsigned int hp_detect: 1;
unsigned int gpio_mute: 1;
+ unsigned int gpio_mask, gpio_data;
+
/* playback */
struct hda_multi_out multiout;
hda_nid_t dac_nids[5];
0x40000100, 0x40000100
};
+static unsigned int dell_3st_pin_configs[14] = {
+ 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
+ 0x01111212, 0x01116211, 0x01813050, 0x01112214,
+ 0x403003fa, 0x40000100, 0x40000100, 0x404003fb,
+ 0x40c003fc, 0x40000100
+};
+
static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
[STAC_D965_REF] = ref927x_pin_configs,
[STAC_D965_3ST] = d965_3st_pin_configs,
[STAC_D965_5ST] = d965_5st_pin_configs,
+ [STAC_DELL_3ST] = dell_3st_pin_configs,
};
static const char *stac927x_models[STAC_927X_MODELS] = {
[STAC_D965_REF] = "ref",
[STAC_D965_3ST] = "3stack",
[STAC_D965_5ST] = "5stack",
+ [STAC_DELL_3ST] = "dell-3stack",
};
static struct snd_pci_quirk stac927x_cfg_tbl[] = {
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
+ /* Dell 3 stack systems */
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell E520", STAC_DELL_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
/* 965 based 5 stack systems */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
};
+static unsigned int dell_m43_9205_pin_configs[12] = {
+ 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
+ 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
+ 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
+};
+
+static unsigned int dell_m44_9205_pin_configs[12] = {
+ 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
+ 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
+ 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
+};
+
+
static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
- [STAC_REF] = ref9205_pin_configs,
- [STAC_M43xx] = NULL,
+ [STAC_9205_REF] = ref9205_pin_configs,
+ [STAC_9205_DELL_M43] = dell_m43_9205_pin_configs,
+ [STAC_9205_DELL_M44] = dell_m44_9205_pin_configs,
+ [STAC_9205_M43xx] = NULL,
};
static const char *stac9205_models[STAC_9205_MODELS] = {
[STAC_9205_REF] = "ref",
+ [STAC_9205_DELL_M43] = "dell-m43",
+ [STAC_9205_DELL_M44] = "dell-m44",
};
static struct snd_pci_quirk stac9205_cfg_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_9205_REF),
- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8,
- "Dell Precision", STAC_M43xx),
- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff,
- "Dell Precision", STAC_M43xx),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
+ "Dell Precision", STAC_9205_M43xx),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
+ "Dell Precision", STAC_9205_DELL_M43),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
+ "Dell Precision", STAC_9205_DELL_M43),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
+ "Dell Precision", STAC_9205_DELL_M43),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
+ "Dell Precision", STAC_9205_DELL_M43),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
+ "Dell Precision", STAC_9205_DELL_M43),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
+ "Dell Inspiron", STAC_9205_DELL_M44),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
+ "Dell Inspiron", STAC_9205_DELL_M44),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
+ "Dell Inspiron", STAC_9205_DELL_M44),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
+ "Dell Inspiron", STAC_9205_DELL_M44),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
+ "Dell Inspiron", STAC_9205_DELL_M44),
{} /* terminator */
};
spec->pin_configs[i]);
}
-static void stac92xx_enable_gpio_mask(struct hda_codec *codec,
- int gpio_mask, int gpio_data)
+static void stac92xx_enable_gpio_mask(struct hda_codec *codec)
{
+ struct sigmatel_spec *spec = codec->spec;
/* Configure GPIOx as output */
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_DIRECTION, gpio_mask);
+ snd_hda_codec_write_cache(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask);
/* Configure GPIOx as CMOS */
- snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
+ snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000);
/* Assert GPIOx */
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_DATA, gpio_data);
+ snd_hda_codec_write_cache(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DATA, spec->gpio_data);
/* Enable GPIOx */
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_MASK, gpio_mask);
+ snd_hda_codec_write_cache(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
}
/*
static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
{
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
}
-static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
spec->multiout.num_dacs++;
if (conn_len > 1) {
/* select this DAC in the pin's input mux */
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, j);
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_CONNECT_SEL, j);
}
}
* NID lists. Hopefully this won't get confused.
*/
for (i = 0; i < spec->num_muxes; i++) {
- snd_hda_codec_write(codec, spec->mux_nids[i], 0,
- AC_VERB_SET_CONNECT_SEL,
- imux->items[0].index);
+ snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ imux->items[0].index);
}
}
if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
- snd_hda_codec_write(codec, nid, 0,
+ snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
pin_ctl | flag);
}
{
unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
- snd_hda_codec_write(codec, nid, 0,
+ snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
pin_ctl & ~flag);
}
}
}
-#ifdef CONFIG_PM
+#ifdef SND_HDA_NEEDS_RESUME
static int stac92xx_resume(struct hda_codec *codec)
{
- struct sigmatel_spec *spec = codec->spec;
- int i;
-
- stac92xx_init(codec);
stac92xx_set_config_regs(codec);
- snd_hda_resume_ctls(codec, spec->mixer);
- for (i = 0; i < spec->num_mixers; i++)
- snd_hda_resume_ctls(codec, spec->mixers[i]);
- if (spec->multiout.dig_out_nid)
- snd_hda_resume_spdif_out(codec);
- if (spec->dig_in_nid)
- snd_hda_resume_spdif_in(codec);
-
+ stac92xx_init(codec);
+ snd_hda_codec_resume_amp(codec);
+ snd_hda_codec_resume_cache(codec);
return 0;
}
#endif
.init = stac92xx_init,
.free = stac92xx_free,
.unsol_event = stac92xx_unsol_event,
-#ifdef CONFIG_PM
+#ifdef SND_HDA_NEEDS_RESUME
.resume = stac92xx_resume,
#endif
};
spec->multiout.dac_nids = spec->dac_nids;
/* GPIO0 High = Enable EAPD */
- stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001);
+ spec->gpio_mask = spec->gpio_data = 0x00000001;
+ stac92xx_enable_gpio_mask(codec);
err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
if (!err) {
static int patch_stac9205(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
- int err, gpio_mask, gpio_data;
+ int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
spec->multiout.dac_nids = spec->dac_nids;
- if (spec->board_config == STAC_M43xx) {
+ switch (spec->board_config){
+ case STAC_9205_M43xx:
+ case STAC_9205_DELL_M43:
/* Enable SPDIF in/out */
stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
- gpio_mask = 0x00000007; /* GPIO0-2 */
+ spec->gpio_mask = 0x00000007; /* GPIO0-2 */
/* GPIO0 High = EAPD, GPIO1 Low = DRM,
* GPIO2 High = Headphone Mute
*/
- gpio_data = 0x00000005;
- } else
- gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */
+ spec->gpio_data = 0x00000005;
+ break;
+ default:
+ /* GPIO0 High = EAPD */
+ spec->gpio_mask = spec->gpio_data = 0x00000001;
+ break;
+ }
- stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data);
+ stac92xx_enable_gpio_mask(codec);
err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
if (!err) {
if (spec->board_config < 0) {
static struct hda_verb vaio_init[] = {
{0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
+ {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
{0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
{0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
};
/* bind volumes of both NID 0x02 and 0x05 */
-static int vaio_master_vol_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- long *valp = ucontrol->value.integer.value;
- int change;
-
- change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0,
- 0x7f, valp[0] & 0x7f);
- change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0,
- 0x7f, valp[1] & 0x7f);
- snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
- 0x7f, valp[0] & 0x7f);
- snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
- 0x7f, valp[1] & 0x7f);
- return change;
-}
+static struct hda_bind_ctls vaio_bind_master_vol = {
+ .ops = &snd_hda_bind_vol,
+ .values = {
+ HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+ HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
+ 0
+ },
+};
/* bind volumes of both NID 0x02 and 0x05 */
-static int vaio_master_sw_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- long *valp = ucontrol->value.integer.value;
- int change;
-
- change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0,
- 0x80, (valp[0] ? 0 : 0x80));
- change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0,
- 0x80, (valp[1] ? 0 : 0x80));
- snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
- 0x80, (valp[0] ? 0 : 0x80));
- snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
- 0x80, (valp[1] ? 0 : 0x80));
- return change;
-}
+static struct hda_bind_ctls vaio_bind_master_sw = {
+ .ops = &snd_hda_bind_sw,
+ .values = {
+ HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+ HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
+ 0,
+ },
+};
static struct snd_kcontrol_new vaio_mixer[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Volume",
- .info = snd_hda_mixer_amp_volume_info,
- .get = snd_hda_mixer_amp_volume_get,
- .put = vaio_master_vol_put,
- .tlv = { .c = snd_hda_mixer_amp_tlv },
- .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .info = snd_hda_mixer_amp_switch_info,
- .get = snd_hda_mixer_amp_switch_get,
- .put = vaio_master_sw_put,
- .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- },
+ HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
+ HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
};
static struct snd_kcontrol_new vaio_ar_mixer[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Volume",
- .info = snd_hda_mixer_amp_volume_info,
- .get = snd_hda_mixer_amp_volume_get,
- .put = vaio_master_vol_put,
- .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .info = snd_hda_mixer_amp_switch_info,
- .get = snd_hda_mixer_amp_switch_get,
- .put = vaio_master_sw_put,
- .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- },
+ HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
+ HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
.build_pcms = stac92xx_build_pcms,
.init = stac92xx_init,
.free = stac92xx_free,
+#ifdef SND_HDA_NEEDS_RESUME
+ .resume = stac92xx_resume,
+#endif
+};
+
+static int stac9872_vaio_init(struct hda_codec *codec)
+{
+ int err;
+
+ err = stac92xx_init(codec);
+ if (err < 0)
+ return err;
+ if (codec->patch_ops.unsol_event)
+ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ return 0;
+}
+
+static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
+{
+ if (get_pin_presence(codec, 0x0a)) {
+ stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
+ stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
+ } else {
+ stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
+ stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
+ }
+}
+
+static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ switch (res >> 26) {
+ case STAC_HP_EVENT:
+ stac9872_vaio_hp_detect(codec, res);
+ break;
+ }
+}
+
+static struct hda_codec_ops stac9872_vaio_patch_ops = {
+ .build_controls = stac92xx_build_controls,
+ .build_pcms = stac92xx_build_pcms,
+ .init = stac9872_vaio_init,
+ .free = stac92xx_free,
+ .unsol_event = stac9872_vaio_unsol_event,
#ifdef CONFIG_PM
.resume = stac92xx_resume,
#endif
spec->adc_nids = vaio_adcs;
spec->input_mux = &vaio_mux;
spec->mux_nids = vaio_mux_nids;
+ codec->patch_ops = stac9872_vaio_patch_ops;
break;
case CXD9872AKD_VAIO:
spec->adc_nids = vaio_adcs;
spec->input_mux = &vaio_mux;
spec->mux_nids = vaio_mux_nids;
+ codec->patch_ops = stac9872_patch_ops;
break;
}
- codec->patch_ops = stac9872_patch_ops;
return 0;
}