mirror of https://gitee.com/openkylin/linux.git
Merge branch 'topic/hda' into for-linus
This commit is contained in:
commit
84a3bd061c
|
@ -255,9 +255,13 @@ enum {
|
||||||
* in HD-audio specification
|
* in HD-audio specification
|
||||||
*/
|
*/
|
||||||
#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */
|
#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */
|
||||||
|
#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can
|
||||||
|
* coexist with AC_PINCAP_HDMI
|
||||||
|
*/
|
||||||
#define AC_PINCAP_VREF (0x37<<8)
|
#define AC_PINCAP_VREF (0x37<<8)
|
||||||
#define AC_PINCAP_VREF_SHIFT 8
|
#define AC_PINCAP_VREF_SHIFT 8
|
||||||
#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */
|
#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */
|
||||||
|
#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */
|
||||||
/* Vref status (used in pin cap) */
|
/* Vref status (used in pin cap) */
|
||||||
#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */
|
#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */
|
||||||
#define AC_PINCAP_VREF_50 (1<<1) /* 50% */
|
#define AC_PINCAP_VREF_50 (1<<1) /* 50% */
|
||||||
|
@ -635,6 +639,7 @@ struct hda_bus {
|
||||||
unsigned int rirb_error:1; /* error in codec communication */
|
unsigned int rirb_error:1; /* error in codec communication */
|
||||||
unsigned int response_reset:1; /* controller was reset */
|
unsigned int response_reset:1; /* controller was reset */
|
||||||
unsigned int in_reset:1; /* during reset operation */
|
unsigned int in_reset:1; /* during reset operation */
|
||||||
|
unsigned int power_keep_link_on:1; /* don't power off HDA link */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2082,7 +2082,8 @@ static void azx_power_notify(struct hda_bus *bus)
|
||||||
}
|
}
|
||||||
if (power_on)
|
if (power_on)
|
||||||
azx_init_chip(chip);
|
azx_init_chip(chip);
|
||||||
else if (chip->running && power_save_controller)
|
else if (chip->running && power_save_controller &&
|
||||||
|
!bus->power_keep_link_on)
|
||||||
azx_stop_chip(chip);
|
azx_stop_chip(chip);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SND_HDA_POWER_SAVE */
|
#endif /* CONFIG_SND_HDA_POWER_SAVE */
|
||||||
|
|
|
@ -240,9 +240,14 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
|
||||||
/* Realtek uses this bit as a different meaning */
|
/* Realtek uses this bit as a different meaning */
|
||||||
if ((codec->vendor_id >> 16) == 0x10ec)
|
if ((codec->vendor_id >> 16) == 0x10ec)
|
||||||
snd_iprintf(buffer, " R/L");
|
snd_iprintf(buffer, " R/L");
|
||||||
else
|
else {
|
||||||
|
if (caps & AC_PINCAP_HBR)
|
||||||
|
snd_iprintf(buffer, " HBR");
|
||||||
snd_iprintf(buffer, " HDMI");
|
snd_iprintf(buffer, " HDMI");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (caps & AC_PINCAP_DP)
|
||||||
|
snd_iprintf(buffer, " DP");
|
||||||
if (caps & AC_PINCAP_TRIG_REQ)
|
if (caps & AC_PINCAP_TRIG_REQ)
|
||||||
snd_iprintf(buffer, " Trigger");
|
snd_iprintf(buffer, " Trigger");
|
||||||
if (caps & AC_PINCAP_IMP_SENSE)
|
if (caps & AC_PINCAP_IMP_SENSE)
|
||||||
|
|
|
@ -145,6 +145,42 @@ struct cea_channel_speaker_allocation {
|
||||||
int spk_mask;
|
int spk_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ALSA sequence is:
|
||||||
|
*
|
||||||
|
* surround40 surround41 surround50 surround51 surround71
|
||||||
|
* ch0 front left = = = =
|
||||||
|
* ch1 front right = = = =
|
||||||
|
* ch2 rear left = = = =
|
||||||
|
* ch3 rear right = = = =
|
||||||
|
* ch4 LFE center center center
|
||||||
|
* ch5 LFE LFE
|
||||||
|
* ch6 side left
|
||||||
|
* ch7 side right
|
||||||
|
*
|
||||||
|
* surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR}
|
||||||
|
*/
|
||||||
|
static int hdmi_channel_mapping[0x32][8] = {
|
||||||
|
/* stereo */
|
||||||
|
[0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
|
||||||
|
/* 2.1 */
|
||||||
|
[0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
|
||||||
|
/* Dolby Surround */
|
||||||
|
[0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 },
|
||||||
|
/* surround40 */
|
||||||
|
[0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 },
|
||||||
|
/* 4ch */
|
||||||
|
[0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
|
||||||
|
/* surround41 */
|
||||||
|
[0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 },
|
||||||
|
/* surround50 */
|
||||||
|
[0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
|
||||||
|
/* surround51 */
|
||||||
|
[0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 },
|
||||||
|
/* 7.1 */
|
||||||
|
[0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 },
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is an ordered list!
|
* This is an ordered list!
|
||||||
*
|
*
|
||||||
|
@ -152,32 +188,36 @@ struct cea_channel_speaker_allocation {
|
||||||
* hdmi_setup_channel_allocation().
|
* hdmi_setup_channel_allocation().
|
||||||
*/
|
*/
|
||||||
static struct cea_channel_speaker_allocation channel_allocations[] = {
|
static struct cea_channel_speaker_allocation channel_allocations[] = {
|
||||||
/* channel: 8 7 6 5 4 3 2 1 */
|
/* channel: 7 6 5 4 3 2 1 0 */
|
||||||
{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
|
{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
|
||||||
/* 2.1 */
|
/* 2.1 */
|
||||||
{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
|
{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
|
||||||
/* Dolby Surround */
|
/* Dolby Surround */
|
||||||
{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
|
{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
|
||||||
|
/* surround40 */
|
||||||
|
{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
|
||||||
|
/* surround41 */
|
||||||
|
{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
|
||||||
|
/* surround50 */
|
||||||
|
{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
|
||||||
|
/* surround51 */
|
||||||
|
{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
|
||||||
|
/* 6.1 */
|
||||||
|
{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
|
||||||
|
/* surround71 */
|
||||||
|
{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
|
||||||
|
|
||||||
{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
|
{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
|
||||||
{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
|
{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
|
||||||
{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
|
{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
|
||||||
{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
|
{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
|
||||||
{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
|
{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
|
||||||
{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
|
|
||||||
{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
|
|
||||||
{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
|
|
||||||
/* 5.1 */
|
|
||||||
{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
|
|
||||||
{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
|
{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
|
||||||
{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
|
{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
|
||||||
{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
|
{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
|
||||||
/* 6.1 */
|
|
||||||
{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
|
|
||||||
{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
|
{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
|
||||||
{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
|
{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
|
||||||
{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
|
{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
|
||||||
/* 7.1 */
|
|
||||||
{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
|
|
||||||
{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
|
{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
|
||||||
{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
|
{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
|
||||||
{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
|
{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
|
||||||
|
@ -210,7 +250,6 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
|
||||||
{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
|
{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HDA/HDMI auto parsing
|
* HDA/HDMI auto parsing
|
||||||
*/
|
*/
|
||||||
|
@ -344,7 +383,7 @@ static int intel_hdmi_parse_codec(struct hda_codec *codec)
|
||||||
break;
|
break;
|
||||||
case AC_WID_PIN:
|
case AC_WID_PIN:
|
||||||
caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
|
caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
|
||||||
if (!(caps & AC_PINCAP_HDMI))
|
if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
|
||||||
continue;
|
continue;
|
||||||
if (intel_hdmi_add_pin(codec, nid) < 0)
|
if (intel_hdmi_add_pin(codec, nid) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -352,6 +391,17 @@ static int intel_hdmi_parse_codec(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
|
||||||
|
* can be lost and presence sense verb will become inaccurate if the
|
||||||
|
* HDA link is powered off at hot plug or hw initialization time.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||||
|
if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
|
||||||
|
AC_PWRST_EPSS))
|
||||||
|
codec->bus->power_keep_link_on = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,14 +486,15 @@ static void hdmi_set_channel_count(struct hda_codec *codec,
|
||||||
AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
|
AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid)
|
static void hdmi_debug_channel_mapping(struct hda_codec *codec,
|
||||||
|
hda_nid_t pin_nid)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||||
int i;
|
int i;
|
||||||
int slot;
|
int slot;
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
slot = snd_hda_codec_read(codec, nid, 0,
|
slot = snd_hda_codec_read(codec, pin_nid, 0,
|
||||||
AC_VERB_GET_HDMI_CHAN_SLOT, i);
|
AC_VERB_GET_HDMI_CHAN_SLOT, i);
|
||||||
printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
|
printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
|
||||||
slot >> 4, slot & 0xf);
|
slot >> 4, slot & 0xf);
|
||||||
|
@ -619,25 +670,32 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
|
||||||
return ai->CA;
|
return ai->CA;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid,
|
static void hdmi_setup_channel_mapping(struct hda_codec *codec,
|
||||||
|
hda_nid_t pin_nid,
|
||||||
struct hdmi_audio_infoframe *ai)
|
struct hdmi_audio_infoframe *ai)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int ca = ai->CA;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!ai->CA)
|
if (hdmi_channel_mapping[ca][1] == 0) {
|
||||||
return;
|
for (i = 0; i < channel_allocations[ca].channels; i++)
|
||||||
|
hdmi_channel_mapping[ca][i] = i | (i << 4);
|
||||||
|
for (; i < 8; i++)
|
||||||
|
hdmi_channel_mapping[ca][i] = 0xf | (i << 4);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
for (i = 0; i < 8; i++) {
|
||||||
* TODO: adjust channel mapping if necessary
|
err = snd_hda_codec_write(codec, pin_nid, 0,
|
||||||
* ALSA sequence is front/surr/clfe/side?
|
AC_VERB_SET_HDMI_CHAN_SLOT,
|
||||||
*/
|
hdmi_channel_mapping[ca][i]);
|
||||||
|
if (err) {
|
||||||
|
snd_printdd(KERN_INFO "HDMI: channel mapping failed\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
hdmi_debug_channel_mapping(codec, pin_nid);
|
||||||
snd_hda_codec_write(codec, nid, 0,
|
|
||||||
AC_VERB_SET_HDMI_CHAN_SLOT,
|
|
||||||
(i << 4) | i);
|
|
||||||
|
|
||||||
hdmi_debug_channel_mapping(codec, nid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
|
static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
|
||||||
|
@ -676,7 +734,6 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
|
||||||
};
|
};
|
||||||
|
|
||||||
hdmi_setup_channel_allocation(codec, nid, &ai);
|
hdmi_setup_channel_allocation(codec, nid, &ai);
|
||||||
hdmi_setup_channel_mapping(codec, nid, &ai);
|
|
||||||
|
|
||||||
for (i = 0; i < spec->num_pins; i++) {
|
for (i = 0; i < spec->num_pins; i++) {
|
||||||
if (spec->pin_cvt[i] != nid)
|
if (spec->pin_cvt[i] != nid)
|
||||||
|
@ -686,6 +743,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
|
||||||
pin_nid = spec->pin[i];
|
pin_nid = spec->pin[i];
|
||||||
if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
|
if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
|
||||||
|
hdmi_setup_channel_mapping(codec, pin_nid, &ai);
|
||||||
hdmi_stop_infoframe_trans(codec, pin_nid);
|
hdmi_stop_infoframe_trans(codec, pin_nid);
|
||||||
hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
|
hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
|
||||||
hdmi_start_infoframe_trans(codec, pin_nid);
|
hdmi_start_infoframe_trans(codec, pin_nid);
|
||||||
|
|
|
@ -209,6 +209,7 @@ struct sigmatel_spec {
|
||||||
unsigned int gpio_data;
|
unsigned int gpio_data;
|
||||||
unsigned int gpio_mute;
|
unsigned int gpio_mute;
|
||||||
unsigned int gpio_led;
|
unsigned int gpio_led;
|
||||||
|
unsigned int gpio_led_polarity;
|
||||||
|
|
||||||
/* stream */
|
/* stream */
|
||||||
unsigned int stream_delay;
|
unsigned int stream_delay;
|
||||||
|
@ -1538,6 +1539,13 @@ static unsigned int alienware_m17x_pin_configs[13] = {
|
||||||
0x904601b0,
|
0x904601b0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static unsigned int intel_dg45id_pin_configs[14] = {
|
||||||
|
0x02214230, 0x02A19240, 0x01013214, 0x01014210,
|
||||||
|
0x01A19250, 0x01011212, 0x01016211, 0x40f000f0,
|
||||||
|
0x40f000f0, 0x40f000f0, 0x40f000f0, 0x014510A0,
|
||||||
|
0x074510B0, 0x40f000f0
|
||||||
|
};
|
||||||
|
|
||||||
static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
|
static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
|
||||||
[STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
|
[STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
|
||||||
[STAC_DELL_M6_AMIC] = dell_m6_pin_configs,
|
[STAC_DELL_M6_AMIC] = dell_m6_pin_configs,
|
||||||
|
@ -1545,6 +1553,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
|
||||||
[STAC_DELL_M6_BOTH] = dell_m6_pin_configs,
|
[STAC_DELL_M6_BOTH] = dell_m6_pin_configs,
|
||||||
[STAC_DELL_EQ] = dell_m6_pin_configs,
|
[STAC_DELL_EQ] = dell_m6_pin_configs,
|
||||||
[STAC_ALIENWARE_M17X] = alienware_m17x_pin_configs,
|
[STAC_ALIENWARE_M17X] = alienware_m17x_pin_configs,
|
||||||
|
[STAC_92HD73XX_INTEL] = intel_dg45id_pin_configs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
|
static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
|
||||||
|
@ -4724,13 +4733,61 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hp_bseries_system(u32 subsystem_id)
|
/*
|
||||||
|
* This method searches for the mute LED GPIO configuration
|
||||||
|
* provided as OEM string in SMBIOS. The format of that string
|
||||||
|
* is HP_Mute_LED_P_G or HP_Mute_LED_P
|
||||||
|
* where P can be 0 or 1 and defines mute LED GPIO control state (low/high)
|
||||||
|
* that corresponds to the NOT muted state of the master volume
|
||||||
|
* and G is the index of the GPIO to use as the mute LED control (0..9)
|
||||||
|
* If _G portion is missing it is assigned based on the codec ID
|
||||||
|
*
|
||||||
|
* So, HP B-series like systems may have HP_Mute_LED_0 (current models)
|
||||||
|
* or HP_Mute_LED_0_3 (future models) OEM SMBIOS strings
|
||||||
|
*/
|
||||||
|
static int find_mute_led_gpio(struct hda_codec *codec)
|
||||||
|
{
|
||||||
|
struct sigmatel_spec *spec = codec->spec;
|
||||||
|
const struct dmi_device *dev = NULL;
|
||||||
|
|
||||||
|
if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
|
||||||
|
while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
|
||||||
|
NULL, dev))) {
|
||||||
|
if (sscanf(dev->name, "HP_Mute_LED_%d_%d",
|
||||||
|
&spec->gpio_led_polarity,
|
||||||
|
&spec->gpio_led) == 2) {
|
||||||
|
spec->gpio_led = 1 << spec->gpio_led;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (sscanf(dev->name, "HP_Mute_LED_%d",
|
||||||
|
&spec->gpio_led_polarity) == 1) {
|
||||||
|
switch (codec->vendor_id) {
|
||||||
|
case 0x111d7608:
|
||||||
|
/* GPIO 0 */
|
||||||
|
spec->gpio_led = 0x01;
|
||||||
|
return 1;
|
||||||
|
case 0x111d7600:
|
||||||
|
case 0x111d7601:
|
||||||
|
case 0x111d7602:
|
||||||
|
case 0x111d7603:
|
||||||
|
/* GPIO 3 */
|
||||||
|
spec->gpio_led = 0x08;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hp_blike_system(u32 subsystem_id)
|
||||||
{
|
{
|
||||||
switch (subsystem_id) {
|
switch (subsystem_id) {
|
||||||
case 0x103c307e:
|
case 0x103c1520:
|
||||||
case 0x103c307f:
|
case 0x103c1521:
|
||||||
case 0x103c3080:
|
case 0x103c1523:
|
||||||
case 0x103c3081:
|
case 0x103c1524:
|
||||||
|
case 0x103c1525:
|
||||||
case 0x103c1722:
|
case 0x103c1722:
|
||||||
case 0x103c1723:
|
case 0x103c1723:
|
||||||
case 0x103c1724:
|
case 0x103c1724:
|
||||||
|
@ -4739,6 +4796,14 @@ static int hp_bseries_system(u32 subsystem_id)
|
||||||
case 0x103c1727:
|
case 0x103c1727:
|
||||||
case 0x103c1728:
|
case 0x103c1728:
|
||||||
case 0x103c1729:
|
case 0x103c1729:
|
||||||
|
case 0x103c172a:
|
||||||
|
case 0x103c172b:
|
||||||
|
case 0x103c307e:
|
||||||
|
case 0x103c307f:
|
||||||
|
case 0x103c3080:
|
||||||
|
case 0x103c3081:
|
||||||
|
case 0x103c7007:
|
||||||
|
case 0x103c7008:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4833,7 +4898,7 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
|
||||||
else
|
else
|
||||||
spec->gpio_data |= spec->gpio_led; /* white */
|
spec->gpio_data |= spec->gpio_led; /* white */
|
||||||
|
|
||||||
if (hp_bseries_system(codec->subsystem_id)) {
|
if (!spec->gpio_led_polarity) {
|
||||||
/* LED state is inverted on these systems */
|
/* LED state is inverted on these systems */
|
||||||
spec->gpio_data ^= spec->gpio_led;
|
spec->gpio_data ^= spec->gpio_led;
|
||||||
}
|
}
|
||||||
|
@ -5526,7 +5591,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hp_bseries_system(codec->subsystem_id)) {
|
if (hp_blike_system(codec->subsystem_id)) {
|
||||||
pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f);
|
pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f);
|
||||||
if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
|
if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
|
||||||
get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER ||
|
get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER ||
|
||||||
|
@ -5544,26 +5609,10 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
|
if (find_mute_led_gpio(codec))
|
||||||
const struct dmi_device *dev = NULL;
|
snd_printd("mute LED gpio %d polarity %d\n",
|
||||||
while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
|
spec->gpio_led,
|
||||||
NULL, dev))) {
|
spec->gpio_led_polarity);
|
||||||
if (strcmp(dev->name, "HP_Mute_LED_1")) {
|
|
||||||
switch (codec->vendor_id) {
|
|
||||||
case 0x111d7608:
|
|
||||||
spec->gpio_led = 0x01;
|
|
||||||
break;
|
|
||||||
case 0x111d7600:
|
|
||||||
case 0x111d7601:
|
|
||||||
case 0x111d7602:
|
|
||||||
case 0x111d7603:
|
|
||||||
spec->gpio_led = 0x08;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||||
if (spec->gpio_led) {
|
if (spec->gpio_led) {
|
||||||
|
|
Loading…
Reference in New Issue