[ALSA] hda-codec - Fix SKU ID function for realtek codecs

Fixed SKU ID function for realtek codecs.  It's used by the automatic
BIOS configuration mode.  Now it supports the correct jack-detection
mechanism, too.

Signed-off-by: Kailang Yang <kailang@realtek.com.tw>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Kailang Yang 2007-10-16 14:30:01 +02:00 committed by Jaroslav Kysela
parent 291702f017
commit c9b58006be
1 changed files with 168 additions and 25 deletions

View File

@ -662,6 +662,44 @@ static struct hda_verb alc_gpio3_init_verbs[] = {
{ } { }
}; };
static void alc_sku_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
unsigned int mute;
unsigned int present;
unsigned int hp_nid = spec->autocfg.hp_pins[0];
unsigned int sp_nid = spec->autocfg.speaker_pins[0];
/* need to execute and sync at first */
snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
present = snd_hda_codec_read(codec, hp_nid, 0,
AC_VERB_GET_PIN_SENSE, 0);
spec->jack_present = (present & 0x80000000) != 0;
if (spec->jack_present) {
/* mute internal speaker */
snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
HDA_AMP_MUTE, HDA_AMP_MUTE);
} else {
/* unmute internal speaker if necessary */
mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0);
snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
HDA_AMP_MUTE, mute);
}
}
/* unsolicited event for HP jack sensing */
static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
{
if (codec->vendor_id == 0x10ec0880)
res >>= 28;
else
res >>= 26;
if (res != ALC880_HP_EVENT)
return;
alc_sku_automute(codec);
}
/* 32-bit subsystem ID for BIOS loading in HD Audio codec. /* 32-bit subsystem ID for BIOS loading in HD Audio codec.
* 31 ~ 16 : Manufacture ID * 31 ~ 16 : Manufacture ID
* 15 ~ 8 : SKU ID * 15 ~ 8 : SKU ID
@ -672,13 +710,48 @@ static void alc_subsystem_id(struct hda_codec *codec,
unsigned int porta, unsigned int porte, unsigned int porta, unsigned int porte,
unsigned int portd) unsigned int portd)
{ {
unsigned int ass, tmp; unsigned int ass, tmp, i;
unsigned nid;
struct alc_spec *spec = codec->spec;
ass = codec->subsystem_id; ass = codec->subsystem_id & 0xffff;
if (!(ass & 1)) if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
goto do_sku;
/*
* 31~30 : port conetcivity
* 29~21 : reserve
* 20 : PCBEEP input
* 19~16 : Check sum (15:1)
* 15~1 : Custom
* 0 : override
*/
nid = 0x1d;
if (codec->vendor_id == 0x10ec0260)
nid = 0x17;
ass = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONFIG_DEFAULT, 0);
if (!(ass & 1) && !(ass & 0x100000))
return;
if ((ass >> 30) != 1) /* no physical connection */
return; return;
/* Override */ /* check sum */
tmp = 0;
for (i = 1; i < 16; i++) {
if ((ass >> i) && 1)
tmp++;
}
if (((ass >> 16) & 0xf) != tmp)
return;
do_sku:
/*
* 0 : override
* 1 : Swap Jack
* 2 : 0 --> Desktop, 1 --> Laptop
* 3~5 : External Amplifier control
* 7~6 : Reserved
*/
tmp = (ass & 0x38) >> 3; /* external Amp control */ tmp = (ass & 0x38) >> 3; /* external Amp control */
switch (tmp) { switch (tmp) {
case 1: case 1:
@ -690,38 +763,108 @@ static void alc_subsystem_id(struct hda_codec *codec,
case 7: case 7:
snd_hda_sequence_write(codec, alc_gpio3_init_verbs); snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
break; break;
case 5: case 5: /* set EAPD output high */
switch (codec->vendor_id) { switch (codec->vendor_id) {
case 0x10ec0862: case 0x10ec0260:
case 0x10ec0660: snd_hda_codec_write(codec, 0x0f, 0,
case 0x10ec0662: AC_VERB_SET_EAPD_BTLENABLE, 2);
snd_hda_codec_write(codec, 0x10, 0,
AC_VERB_SET_EAPD_BTLENABLE, 2);
break;
case 0x10ec0262:
case 0x10ec0267: case 0x10ec0267:
case 0x10ec0268: case 0x10ec0268:
case 0x10ec0269:
case 0x10ec0862:
case 0x10ec0662:
snd_hda_codec_write(codec, 0x14, 0, snd_hda_codec_write(codec, 0x14, 0,
AC_VERB_SET_EAPD_BTLENABLE, 2); AC_VERB_SET_EAPD_BTLENABLE, 2);
snd_hda_codec_write(codec, 0x15, 0, snd_hda_codec_write(codec, 0x15, 0,
AC_VERB_SET_EAPD_BTLENABLE, 2); AC_VERB_SET_EAPD_BTLENABLE, 2);
return; break;
} }
case 6: switch (codec->vendor_id) {
if (ass & 4) { /* bit 2 : 0 = Desktop, 1 = Laptop */ case 0x10ec0260:
hda_nid_t port = 0; snd_hda_codec_write(codec, 0x1a, 0,
tmp = (ass & 0x1800) >> 11; AC_VERB_SET_COEF_INDEX, 7);
switch (tmp) { tmp = snd_hda_codec_read(codec, 0x1a, 0,
case 0: port = porta; break; AC_VERB_GET_PROC_COEF, 0);
case 1: port = porte; break; snd_hda_codec_write(codec, 0x1a, 0,
case 2: port = portd; break; AC_VERB_SET_COEF_INDEX, 7);
} snd_hda_codec_write(codec, 0x1a, 0,
if (port) AC_VERB_SET_PROC_COEF,
snd_hda_codec_write(codec, port, 0, tmp | 0x2010);
AC_VERB_SET_EAPD_BTLENABLE, break;
2); case 0x10ec0262:
case 0x10ec0880:
case 0x10ec0882:
case 0x10ec0883:
case 0x10ec0885:
case 0x10ec0888:
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_COEF_INDEX, 7);
tmp = snd_hda_codec_read(codec, 0x20, 0,
AC_VERB_GET_PROC_COEF, 0);
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_COEF_INDEX, 7);
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_PROC_COEF,
tmp | 0x2010);
break;
case 0x10ec0267:
case 0x10ec0268:
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_COEF_INDEX, 7);
tmp = snd_hda_codec_read(codec, 0x20, 0,
AC_VERB_GET_PROC_COEF, 0);
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_COEF_INDEX, 7);
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_PROC_COEF,
tmp | 0x3000);
break;
} }
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); default:
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF,
(tmp == 5 ? 0x3040 : 0x3050));
break; break;
} }
/* is laptop and enable the function "Mute internal speaker
* when the external headphone out jack is plugged"
*/
if (!(ass & 0x4) || !(ass & 0x8000))
return;
/*
* 10~8 : Jack location
* 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
* 14~13: Resvered
* 15 : 1 --> enable the function "Mute internal speaker
* when the external headphone out jack is plugged"
*/
if (!spec->autocfg.speaker_pins[0]) {
if (spec->multiout.dac_nids[0])
spec->autocfg.speaker_pins[0] =
spec->multiout.dac_nids[0];
else
return;
}
if (!spec->autocfg.hp_pins[0]) {
tmp = (ass >> 11) & 0x3; /* HP to chassis */
if (tmp == 0)
spec->autocfg.hp_pins[0] = porta;
else if (tmp == 1)
spec->autocfg.hp_pins[0] = porte;
else if (tmp == 2)
spec->autocfg.hp_pins[0] = portd;
else
return;
}
snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | ALC880_HP_EVENT);
spec->unsol_event = alc_sku_unsol_event;
spec->init_hook = alc_sku_automute;
} }
/* /*