mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-18 15:44:02 +08:00
Merge branch 'topic/hda' into for-linus
This commit is contained in:
commit
a91a4aa1ee
@ -124,6 +124,8 @@ ALC882/883/885/888/889
|
||||
asus-a7m ASUS A7M
|
||||
macpro MacPro support
|
||||
mb5 Macbook 5,1
|
||||
macmini3 Macmini 3,1
|
||||
mba21 Macbook Air 2,1
|
||||
mbp3 Macbook Pro rev3
|
||||
imac24 iMac 24'' with jack detection
|
||||
imac91 iMac 9,1
|
||||
@ -279,13 +281,16 @@ Conexant 5051
|
||||
laptop Basic Laptop config (default)
|
||||
hp HP Spartan laptop
|
||||
hp-dv6736 HP dv6736
|
||||
hp-f700 HP Compaq Presario F700
|
||||
lenovo-x200 Lenovo X200 laptop
|
||||
toshiba Toshiba Satellite M300
|
||||
|
||||
Conexant 5066
|
||||
=============
|
||||
laptop Basic Laptop config (default)
|
||||
dell-laptop Dell laptops
|
||||
olpc-xo-1_5 OLPC XO 1.5
|
||||
ideapad Lenovo IdeaPad U150
|
||||
|
||||
STAC9200
|
||||
========
|
||||
|
@ -452,6 +452,33 @@ Similarly, the lines after `[verb]` are parsed as `init_verbs`
|
||||
sysfs entries, and the lines after `[hint]` are parsed as `hints`
|
||||
sysfs entries, respectively.
|
||||
|
||||
Another example to override the codec vendor id from 0x12345678 to
|
||||
0xdeadbeef is like below:
|
||||
------------------------------------------------------------------------
|
||||
[codec]
|
||||
0x12345678 0xabcd1234 2
|
||||
|
||||
[vendor_id]
|
||||
0xdeadbeef
|
||||
------------------------------------------------------------------------
|
||||
|
||||
In the similar way, you can override the codec subsystem_id via
|
||||
`[subsystem_id]`, the revision id via `[revision_id]` line.
|
||||
Also, the codec chip name can be rewritten via `[chip_name]` line.
|
||||
------------------------------------------------------------------------
|
||||
[codec]
|
||||
0x12345678 0xabcd1234 2
|
||||
|
||||
[subsystem_id]
|
||||
0xffff1111
|
||||
|
||||
[revision_id]
|
||||
0x10
|
||||
|
||||
[chip_name]
|
||||
My-own NEWS-0002
|
||||
------------------------------------------------------------------------
|
||||
|
||||
The hd-audio driver reads the file via request_firmware(). Thus,
|
||||
a patch file has to be located on the appropriate firmware path,
|
||||
typically, /lib/firmware. For example, when you pass the option
|
||||
|
@ -2767,7 +2767,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
||||
power_state);
|
||||
/* partial workaround for "azx_get_response timeout" */
|
||||
if (power_state == AC_PWRST_D0)
|
||||
if (power_state == AC_PWRST_D0 &&
|
||||
(codec->vendor_id & 0xffff0000) == 0x14f10000)
|
||||
msleep(10);
|
||||
|
||||
nid = codec->start_nid;
|
||||
@ -2801,7 +2802,6 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
if (power_state == AC_PWRST_D0) {
|
||||
unsigned long end_time;
|
||||
int state;
|
||||
msleep(10);
|
||||
/* wait until the codec reachs to D0 */
|
||||
end_time = jiffies + msecs_to_jiffies(500);
|
||||
do {
|
||||
@ -3275,6 +3275,8 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
|
||||
|
||||
/*
|
||||
* get the empty PCM device number to assign
|
||||
*
|
||||
* note the max device number is limited by HDA_MAX_PCMS, currently 10
|
||||
*/
|
||||
static int get_empty_pcm_device(struct hda_bus *bus, int type)
|
||||
{
|
||||
|
@ -527,6 +527,9 @@ enum {
|
||||
/* max. codec address */
|
||||
#define HDA_MAX_CODEC_ADDRESS 0x0f
|
||||
|
||||
/* max number of PCM devics per card */
|
||||
#define HDA_MAX_PCMS 10
|
||||
|
||||
/*
|
||||
* generic arrays
|
||||
*/
|
||||
|
@ -625,6 +625,10 @@ enum {
|
||||
LINE_MODE_PINCFG,
|
||||
LINE_MODE_VERB,
|
||||
LINE_MODE_HINT,
|
||||
LINE_MODE_VENDOR_ID,
|
||||
LINE_MODE_SUBSYSTEM_ID,
|
||||
LINE_MODE_REVISION_ID,
|
||||
LINE_MODE_CHIP_NAME,
|
||||
NUM_LINE_MODES,
|
||||
};
|
||||
|
||||
@ -654,53 +658,71 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus,
|
||||
}
|
||||
|
||||
/* parse the contents after the other command tags, [pincfg], [verb],
|
||||
* [hint] and [model]
|
||||
* [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
|
||||
* just pass to the sysfs helper (only when any codec was specified)
|
||||
*/
|
||||
static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
if (!*codecp)
|
||||
return;
|
||||
parse_user_pin_configs(*codecp, buf);
|
||||
}
|
||||
|
||||
static void parse_verb_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
if (!*codecp)
|
||||
return;
|
||||
parse_init_verbs(*codecp, buf);
|
||||
}
|
||||
|
||||
static void parse_hint_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
if (!*codecp)
|
||||
return;
|
||||
parse_hints(*codecp, buf);
|
||||
}
|
||||
|
||||
static void parse_model_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
if (!*codecp)
|
||||
return;
|
||||
kfree((*codecp)->modelname);
|
||||
(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
kfree((*codecp)->chip_name);
|
||||
(*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
|
||||
}
|
||||
|
||||
#define DEFINE_PARSE_ID_MODE(name) \
|
||||
static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
|
||||
struct hda_codec **codecp) \
|
||||
{ \
|
||||
unsigned long val; \
|
||||
if (!strict_strtoul(buf, 0, &val)) \
|
||||
(*codecp)->name = val; \
|
||||
}
|
||||
|
||||
DEFINE_PARSE_ID_MODE(vendor_id);
|
||||
DEFINE_PARSE_ID_MODE(subsystem_id);
|
||||
DEFINE_PARSE_ID_MODE(revision_id);
|
||||
|
||||
|
||||
struct hda_patch_item {
|
||||
const char *tag;
|
||||
void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
|
||||
int need_codec;
|
||||
};
|
||||
|
||||
static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
|
||||
[LINE_MODE_CODEC] = { "[codec]", parse_codec_mode },
|
||||
[LINE_MODE_MODEL] = { "[model]", parse_model_mode },
|
||||
[LINE_MODE_VERB] = { "[verb]", parse_verb_mode },
|
||||
[LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode },
|
||||
[LINE_MODE_HINT] = { "[hint]", parse_hint_mode },
|
||||
[LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 },
|
||||
[LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 },
|
||||
[LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 },
|
||||
[LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 },
|
||||
[LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 },
|
||||
[LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 },
|
||||
[LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 },
|
||||
[LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 },
|
||||
[LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 },
|
||||
};
|
||||
|
||||
/* check the line starting with '[' -- change the parser mode accodingly */
|
||||
@ -783,7 +805,8 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
|
||||
continue;
|
||||
if (*buf == '[')
|
||||
line_mode = parse_line_mode(buf, bus);
|
||||
else if (patch_items[line_mode].parser)
|
||||
else if (patch_items[line_mode].parser &&
|
||||
(codec || !patch_items[line_mode].need_codec))
|
||||
patch_items[line_mode].parser(buf, bus, &codec);
|
||||
}
|
||||
release_firmware(fw);
|
||||
|
@ -125,6 +125,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
|
||||
"{Intel, ICH9},"
|
||||
"{Intel, ICH10},"
|
||||
"{Intel, PCH},"
|
||||
"{Intel, CPT},"
|
||||
"{Intel, SCH},"
|
||||
"{ATI, SB450},"
|
||||
"{ATI, SB600},"
|
||||
@ -259,8 +260,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
|
||||
#define AZX_MAX_FRAG 32
|
||||
/* max buffer size - no h/w limit, you can increase as you like */
|
||||
#define AZX_MAX_BUF_SIZE (1024*1024*1024)
|
||||
/* max number of PCM devics per card */
|
||||
#define AZX_MAX_PCMS 8
|
||||
|
||||
/* RIRB int mask: overrun[2], response[0] */
|
||||
#define RIRB_INT_RESPONSE 0x01
|
||||
@ -408,7 +407,7 @@ struct azx {
|
||||
struct azx_dev *azx_dev;
|
||||
|
||||
/* PCM */
|
||||
struct snd_pcm *pcm[AZX_MAX_PCMS];
|
||||
struct snd_pcm *pcm[HDA_MAX_PCMS];
|
||||
|
||||
/* HD codec */
|
||||
unsigned short codec_mask;
|
||||
@ -449,6 +448,7 @@ struct azx {
|
||||
/* driver types */
|
||||
enum {
|
||||
AZX_DRIVER_ICH,
|
||||
AZX_DRIVER_PCH,
|
||||
AZX_DRIVER_SCH,
|
||||
AZX_DRIVER_ATI,
|
||||
AZX_DRIVER_ATIHDMI,
|
||||
@ -463,6 +463,7 @@ enum {
|
||||
|
||||
static char *driver_short_names[] __devinitdata = {
|
||||
[AZX_DRIVER_ICH] = "HDA Intel",
|
||||
[AZX_DRIVER_PCH] = "HDA Intel PCH",
|
||||
[AZX_DRIVER_SCH] = "HDA Intel MID",
|
||||
[AZX_DRIVER_ATI] = "HDA ATI SB",
|
||||
[AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
|
||||
@ -968,8 +969,8 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
|
||||
azx_dev->insufficient = 1;
|
||||
|
||||
/* enable SIE */
|
||||
azx_writeb(chip, INTCTL,
|
||||
azx_readb(chip, INTCTL) | (1 << azx_dev->index));
|
||||
azx_writel(chip, INTCTL,
|
||||
azx_readl(chip, INTCTL) | (1 << azx_dev->index));
|
||||
/* set DMA start and interrupt mask */
|
||||
azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
|
||||
SD_CTL_DMA_START | SD_INT_MASK);
|
||||
@ -988,8 +989,8 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
|
||||
{
|
||||
azx_stream_clear(chip, azx_dev);
|
||||
/* disable SIE */
|
||||
azx_writeb(chip, INTCTL,
|
||||
azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
|
||||
azx_writel(chip, INTCTL,
|
||||
azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
|
||||
}
|
||||
|
||||
|
||||
@ -1065,6 +1066,7 @@ static void azx_init_pci(struct azx *chip)
|
||||
0x01, NVIDIA_HDA_ENABLE_COHBIT);
|
||||
break;
|
||||
case AZX_DRIVER_SCH:
|
||||
case AZX_DRIVER_PCH:
|
||||
pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
|
||||
if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
|
||||
pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
|
||||
@ -1350,7 +1352,7 @@ static void azx_bus_reset(struct hda_bus *bus)
|
||||
if (chip->initialized) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AZX_MAX_PCMS; i++)
|
||||
for (i = 0; i < HDA_MAX_PCMS; i++)
|
||||
snd_pcm_suspend_all(chip->pcm[i]);
|
||||
snd_hda_suspend(chip->bus);
|
||||
snd_hda_resume(chip->bus);
|
||||
@ -1412,7 +1414,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
|
||||
chip->codec_mask &= ~(1 << c);
|
||||
/* More badly, accessing to a non-existing
|
||||
* codec often screws up the controller chip,
|
||||
* and distrubs the further communications.
|
||||
* and disturbs the further communications.
|
||||
* Thus if an error occurs during probing,
|
||||
* better to reset the controller chip to
|
||||
* get back to the sanity state.
|
||||
@ -1983,7 +1985,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
|
||||
int pcm_dev = cpcm->device;
|
||||
int s, err;
|
||||
|
||||
if (pcm_dev >= AZX_MAX_PCMS) {
|
||||
if (pcm_dev >= HDA_MAX_PCMS) {
|
||||
snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
|
||||
pcm_dev);
|
||||
return -EINVAL;
|
||||
@ -2139,7 +2141,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
azx_clear_irq_pending(chip);
|
||||
for (i = 0; i < AZX_MAX_PCMS; i++)
|
||||
for (i = 0; i < HDA_MAX_PCMS; i++)
|
||||
snd_pcm_suspend_all(chip->pcm[i]);
|
||||
if (chip->initialized)
|
||||
snd_hda_suspend(chip->bus);
|
||||
@ -2262,6 +2264,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
|
||||
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
|
||||
{}
|
||||
@ -2418,6 +2421,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
|
||||
if (bdl_pos_adj[dev] < 0) {
|
||||
switch (chip->driver_type) {
|
||||
case AZX_DRIVER_ICH:
|
||||
case AZX_DRIVER_PCH:
|
||||
bdl_pos_adj[dev] = 1;
|
||||
break;
|
||||
default:
|
||||
@ -2696,6 +2700,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
|
||||
{ PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
|
||||
/* PCH */
|
||||
{ PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
|
||||
/* CPT */
|
||||
{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
|
||||
/* SCH */
|
||||
{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
|
||||
/* ATI SB 450/600 */
|
||||
|
@ -1098,7 +1098,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
|
||||
SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
|
||||
SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
|
||||
SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
|
||||
SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
|
||||
SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
|
||||
SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
|
||||
SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
|
||||
|
@ -42,10 +42,12 @@
|
||||
|
||||
/* Conexant 5051 specific */
|
||||
|
||||
#define CXT5051_SPDIF_OUT 0x1C
|
||||
#define CXT5051_SPDIF_OUT 0x12
|
||||
#define CXT5051_PORTB_EVENT 0x38
|
||||
#define CXT5051_PORTC_EVENT 0x39
|
||||
|
||||
#define AUTO_MIC_PORTB (1 << 1)
|
||||
#define AUTO_MIC_PORTC (1 << 2)
|
||||
|
||||
struct conexant_jack {
|
||||
|
||||
@ -74,7 +76,7 @@ struct conexant_spec {
|
||||
*/
|
||||
unsigned int cur_eapd;
|
||||
unsigned int hp_present;
|
||||
unsigned int no_auto_mic;
|
||||
unsigned int auto_mic;
|
||||
unsigned int need_dac_fix;
|
||||
|
||||
/* capture */
|
||||
@ -111,7 +113,8 @@ struct conexant_spec {
|
||||
|
||||
unsigned int dell_automute;
|
||||
unsigned int port_d_mode;
|
||||
unsigned int dell_vostro;
|
||||
unsigned int dell_vostro:1;
|
||||
unsigned int ideapad:1;
|
||||
|
||||
unsigned int ext_mic_present;
|
||||
unsigned int recording;
|
||||
@ -1603,6 +1606,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int pinctl;
|
||||
/* headphone pin */
|
||||
pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0;
|
||||
snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
/* speaker pin */
|
||||
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
|
||||
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
@ -1626,7 +1634,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec)
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int present;
|
||||
|
||||
if (spec->no_auto_mic)
|
||||
if (!(spec->auto_mic & AUTO_MIC_PORTB))
|
||||
return;
|
||||
present = snd_hda_jack_detect(codec, 0x17);
|
||||
snd_hda_codec_write(codec, 0x14, 0,
|
||||
@ -1641,7 +1649,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec)
|
||||
unsigned int present;
|
||||
hda_nid_t new_adc;
|
||||
|
||||
if (spec->no_auto_mic)
|
||||
if (!(spec->auto_mic & AUTO_MIC_PORTC))
|
||||
return;
|
||||
present = snd_hda_jack_detect(codec, 0x18);
|
||||
if (present)
|
||||
@ -1687,13 +1695,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
|
||||
conexant_report_jack(codec, nid);
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new cxt5051_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
|
||||
static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
@ -1703,7 +1705,16 @@ static struct snd_kcontrol_new cxt5051_mixers[] = {
|
||||
.put = cxt5051_hp_master_sw_put,
|
||||
.private_value = 0x1a,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -1712,48 +1723,26 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
|
||||
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5051_hp_master_sw_put,
|
||||
.private_value = 0x1a,
|
||||
},
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5051_hp_master_sw_put,
|
||||
.private_value = 0x1a,
|
||||
},
|
||||
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5051_hp_master_sw_put,
|
||||
.private_value = 0x1a,
|
||||
},
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -1782,8 +1771,6 @@ static struct hda_verb cxt5051_init_verbs[] = {
|
||||
/* EAPD */
|
||||
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
@ -1809,7 +1796,6 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
|
||||
/* EAPD */
|
||||
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
@ -1841,15 +1827,13 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
|
||||
/* EAPD */
|
||||
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
|
||||
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5051_f700_init_verbs[] = {
|
||||
/* Line in, Mic */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03},
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
|
||||
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
|
||||
@ -1869,15 +1853,34 @@ static struct hda_verb cxt5051_f700_init_verbs[] = {
|
||||
/* EAPD */
|
||||
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
|
||||
unsigned int event)
|
||||
{
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | event);
|
||||
#ifdef CONFIG_SND_HDA_INPUT_JACK
|
||||
conexant_add_jack(codec, nid, SND_JACK_MICROPHONE);
|
||||
conexant_report_jack(codec, nid);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* initialize jack-sensing, too */
|
||||
static int cxt5051_init(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
|
||||
conexant_init(codec);
|
||||
conexant_init_jacks(codec);
|
||||
|
||||
if (spec->auto_mic & AUTO_MIC_PORTB)
|
||||
cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT);
|
||||
if (spec->auto_mic & AUTO_MIC_PORTC)
|
||||
cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT);
|
||||
|
||||
if (codec->patch_ops.unsol_event) {
|
||||
cxt5051_hp_automute(codec);
|
||||
cxt5051_portb_automic(codec);
|
||||
@ -1893,6 +1896,7 @@ enum {
|
||||
CXT5051_HP_DV6736, /* HP without mic switch */
|
||||
CXT5051_LENOVO_X200, /* Lenovo X200 laptop */
|
||||
CXT5051_F700, /* HP Compaq Presario F700 */
|
||||
CXT5051_TOSHIBA, /* Toshiba M300 & co */
|
||||
CXT5051_MODELS
|
||||
};
|
||||
|
||||
@ -1901,17 +1905,19 @@ static const char *cxt5051_models[CXT5051_MODELS] = {
|
||||
[CXT5051_HP] = "hp",
|
||||
[CXT5051_HP_DV6736] = "hp-dv6736",
|
||||
[CXT5051_LENOVO_X200] = "lenovo-x200",
|
||||
[CXT5051_F700] = "hp 700"
|
||||
[CXT5051_F700] = "hp-700",
|
||||
[CXT5051_TOSHIBA] = "toshiba",
|
||||
};
|
||||
|
||||
static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
|
||||
SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP),
|
||||
SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
|
||||
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA),
|
||||
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
|
||||
CXT5051_LAPTOP),
|
||||
SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
|
||||
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
|
||||
SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -1935,8 +1941,9 @@ static int patch_cxt5051(struct hda_codec *codec)
|
||||
spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT;
|
||||
spec->num_adc_nids = 1; /* not 2; via auto-mic switch */
|
||||
spec->adc_nids = cxt5051_adc_nids;
|
||||
spec->num_mixers = 1;
|
||||
spec->mixers[0] = cxt5051_mixers;
|
||||
spec->num_mixers = 2;
|
||||
spec->mixers[0] = cxt5051_capture_mixers;
|
||||
spec->mixers[1] = cxt5051_playback_mixers;
|
||||
spec->num_init_verbs = 1;
|
||||
spec->init_verbs[0] = cxt5051_init_verbs;
|
||||
spec->spdif_route = 0;
|
||||
@ -1950,6 +1957,7 @@ static int patch_cxt5051(struct hda_codec *codec)
|
||||
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
|
||||
cxt5051_models,
|
||||
cxt5051_cfg_tbl);
|
||||
spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
|
||||
switch (board_config) {
|
||||
case CXT5051_HP:
|
||||
spec->mixers[0] = cxt5051_hp_mixers;
|
||||
@ -1957,7 +1965,7 @@ static int patch_cxt5051(struct hda_codec *codec)
|
||||
case CXT5051_HP_DV6736:
|
||||
spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs;
|
||||
spec->mixers[0] = cxt5051_hp_dv6736_mixers;
|
||||
spec->no_auto_mic = 1;
|
||||
spec->auto_mic = 0;
|
||||
break;
|
||||
case CXT5051_LENOVO_X200:
|
||||
spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
|
||||
@ -1965,7 +1973,11 @@ static int patch_cxt5051(struct hda_codec *codec)
|
||||
case CXT5051_F700:
|
||||
spec->init_verbs[0] = cxt5051_f700_init_verbs;
|
||||
spec->mixers[0] = cxt5051_f700_mixers;
|
||||
spec->no_auto_mic = 1;
|
||||
spec->auto_mic = 0;
|
||||
break;
|
||||
case CXT5051_TOSHIBA:
|
||||
spec->mixers[0] = cxt5051_toshiba_mixers;
|
||||
spec->auto_mic = AUTO_MIC_PORTB;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2156,6 +2168,34 @@ static void cxt5066_vostro_automic(struct hda_codec *codec)
|
||||
}
|
||||
}
|
||||
|
||||
/* toggle input of built-in digital mic and mic jack appropriately */
|
||||
static void cxt5066_ideapad_automic(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present;
|
||||
|
||||
struct hda_verb ext_mic_present[] = {
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 0},
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{}
|
||||
};
|
||||
static struct hda_verb ext_mic_absent[] = {
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 2},
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{}
|
||||
};
|
||||
|
||||
present = snd_hda_jack_detect(codec, 0x1b);
|
||||
if (present) {
|
||||
snd_printdd("CXT5066: external microphone detected\n");
|
||||
snd_hda_sequence_write(codec, ext_mic_present);
|
||||
} else {
|
||||
snd_printdd("CXT5066: external microphone absent\n");
|
||||
snd_hda_sequence_write(codec, ext_mic_absent);
|
||||
}
|
||||
}
|
||||
|
||||
/* mute internal speaker if HP is plugged */
|
||||
static void cxt5066_hp_automute(struct hda_codec *codec)
|
||||
{
|
||||
@ -2205,6 +2245,20 @@ static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res)
|
||||
}
|
||||
}
|
||||
|
||||
/* unsolicited event for jack sensing */
|
||||
static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
|
||||
{
|
||||
snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26);
|
||||
switch (res >> 26) {
|
||||
case CONEXANT_HP_EVENT:
|
||||
cxt5066_hp_automute(codec);
|
||||
break;
|
||||
case CONEXANT_MIC_EVENT:
|
||||
cxt5066_ideapad_automic(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hda_input_mux cxt5066_analog_mic_boost = {
|
||||
.num_items = 5,
|
||||
.items = {
|
||||
@ -2216,13 +2270,21 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = {
|
||||
},
|
||||
};
|
||||
|
||||
static int cxt5066_set_mic_boost(struct hda_codec *codec)
|
||||
static void cxt5066_set_mic_boost(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
return snd_hda_codec_write_cache(codec, 0x17, 0,
|
||||
snd_hda_codec_write_cache(codec, 0x17, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
|
||||
cxt5066_analog_mic_boost.items[spec->mic_boost].index);
|
||||
if (spec->ideapad) {
|
||||
/* adjust the internal mic as well...it is not through 0x17 */
|
||||
snd_hda_codec_write_cache(codec, 0x23, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT |
|
||||
cxt5066_analog_mic_boost.
|
||||
items[spec->mic_boost].index);
|
||||
}
|
||||
}
|
||||
|
||||
static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
|
||||
@ -2653,6 +2715,56 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = {
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5066_init_verbs_ideapad[] = {
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
|
||||
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
|
||||
|
||||
/* Speakers */
|
||||
{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
/* HP, Amp */
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
/* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */
|
||||
|
||||
/* Audio input selector */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2},
|
||||
{0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */
|
||||
|
||||
/* SPDIF route: PCM */
|
||||
{0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
{0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
|
||||
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
|
||||
/* internal microphone */
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
|
||||
|
||||
/* EAPD */
|
||||
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
|
||||
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
|
||||
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{ } /* end */
|
||||
@ -2669,6 +2781,8 @@ static int cxt5066_init(struct hda_codec *codec)
|
||||
cxt5066_hp_automute(codec);
|
||||
if (spec->dell_vostro)
|
||||
cxt5066_vostro_automic(codec);
|
||||
else if (spec->ideapad)
|
||||
cxt5066_ideapad_automic(codec);
|
||||
}
|
||||
cxt5066_set_mic_boost(codec);
|
||||
return 0;
|
||||
@ -2694,6 +2808,7 @@ enum {
|
||||
CXT5066_DELL_LAPTOP, /* Dell Laptop */
|
||||
CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
|
||||
CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */
|
||||
CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
|
||||
CXT5066_MODELS
|
||||
};
|
||||
|
||||
@ -2701,7 +2816,8 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
|
||||
[CXT5066_LAPTOP] = "laptop",
|
||||
[CXT5066_DELL_LAPTOP] = "dell-laptop",
|
||||
[CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
|
||||
[CXT5066_DELL_VOSTO] = "dell-vostro"
|
||||
[CXT5066_DELL_VOSTO] = "dell-vostro",
|
||||
[CXT5066_IDEAPAD] = "ideapad",
|
||||
};
|
||||
|
||||
static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
|
||||
@ -2711,6 +2827,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
|
||||
CXT5066_DELL_LAPTOP),
|
||||
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
|
||||
SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -2799,6 +2916,22 @@ static int patch_cxt5066(struct hda_codec *codec)
|
||||
/* no S/PDIF out */
|
||||
spec->multiout.dig_out_nid = 0;
|
||||
|
||||
/* input source automatically selected */
|
||||
spec->input_mux = NULL;
|
||||
break;
|
||||
case CXT5066_IDEAPAD:
|
||||
codec->patch_ops.init = cxt5066_init;
|
||||
codec->patch_ops.unsol_event = cxt5066_ideapad_event;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
|
||||
spec->init_verbs[0] = cxt5066_init_verbs_ideapad;
|
||||
spec->port_d_mode = 0;
|
||||
spec->ideapad = 1;
|
||||
spec->mic_boost = 2; /* default 20dB gain */
|
||||
|
||||
/* no S/PDIF out */
|
||||
spec->multiout.dig_out_nid = 0;
|
||||
|
||||
/* input source automatically selected */
|
||||
spec->input_mux = NULL;
|
||||
break;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -568,6 +568,11 @@ static hda_nid_t stac92hd83xxx_pin_nids[10] = {
|
||||
0x0f, 0x10, 0x11, 0x1f, 0x20,
|
||||
};
|
||||
|
||||
static hda_nid_t stac92hd88xxx_pin_nids[10] = {
|
||||
0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0f, 0x11, 0x1f, 0x20,
|
||||
};
|
||||
|
||||
#define STAC92HD71BXX_NUM_PINS 13
|
||||
static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
|
||||
0x0a, 0x0b, 0x0c, 0x0d, 0x00,
|
||||
@ -2873,6 +2878,13 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
|
||||
|
||||
conn_len = snd_hda_get_connections(codec, nid, conn,
|
||||
HDA_MAX_CONNECTIONS);
|
||||
/* 92HD88: trace back up the link of nids to find the DAC */
|
||||
while (conn_len == 1 && (get_wcaps_type(get_wcaps(codec, conn[0]))
|
||||
!= AC_WID_AUD_OUT)) {
|
||||
nid = conn[0];
|
||||
conn_len = snd_hda_get_connections(codec, nid, conn,
|
||||
HDA_MAX_CONNECTIONS);
|
||||
}
|
||||
for (j = 0; j < conn_len; j++) {
|
||||
wcaps = get_wcaps(codec, conn[j]);
|
||||
wtype = get_wcaps_type(wcaps);
|
||||
@ -4351,6 +4363,12 @@ static int stac92xx_init(struct hda_codec *codec)
|
||||
if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
|
||||
stac_issue_unsol_event(codec, nid);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
/* sync mute LED */
|
||||
if (spec->gpio_led && codec->patch_ops.check_power_status)
|
||||
codec->patch_ops.check_power_status(codec, 0x01);
|
||||
#endif
|
||||
if (spec->dac_list)
|
||||
stac92xx_power_down(codec);
|
||||
return 0;
|
||||
@ -4742,19 +4760,14 @@ static int hp_blike_system(u32 subsystem_id);
|
||||
static void set_hp_led_gpio(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
switch (codec->vendor_id) {
|
||||
case 0x111d7608:
|
||||
/* GPIO 0 */
|
||||
spec->gpio_led = 0x01;
|
||||
break;
|
||||
case 0x111d7600:
|
||||
case 0x111d7601:
|
||||
case 0x111d7602:
|
||||
case 0x111d7603:
|
||||
/* GPIO 3 */
|
||||
spec->gpio_led = 0x08;
|
||||
break;
|
||||
}
|
||||
unsigned int gpio;
|
||||
|
||||
gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
|
||||
gpio &= AC_GPIO_IO_COUNT;
|
||||
if (gpio > 3)
|
||||
spec->gpio_led = 0x08; /* GPIO 3 */
|
||||
else
|
||||
spec->gpio_led = 0x01; /* GPIO 0 */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4777,7 +4790,7 @@ static void set_hp_led_gpio(struct hda_codec *codec)
|
||||
* Need more information on whether it is true across the entire series.
|
||||
* -- kunal
|
||||
*/
|
||||
static int find_mute_led_gpio(struct hda_codec *codec)
|
||||
static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
const struct dmi_device *dev = NULL;
|
||||
@ -4804,7 +4817,7 @@ static int find_mute_led_gpio(struct hda_codec *codec)
|
||||
*/
|
||||
if (!hp_blike_system(codec->subsystem_id)) {
|
||||
set_hp_led_gpio(codec);
|
||||
spec->gpio_led_polarity = 1;
|
||||
spec->gpio_led_polarity = default_polarity;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -4902,6 +4915,11 @@ static int stac92xx_resume(struct hda_codec *codec)
|
||||
stac_issue_unsol_event(codec,
|
||||
spec->autocfg.line_out_pins[0]);
|
||||
}
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
/* sync mute LED */
|
||||
if (spec->gpio_led && codec->patch_ops.check_power_status)
|
||||
codec->patch_ops.check_power_status(codec, 0x01);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4921,43 +4939,29 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
int i, muted = 1;
|
||||
|
||||
if (nid == 0x10) {
|
||||
if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
|
||||
HDA_AMP_MUTE)
|
||||
spec->gpio_data &= ~spec->gpio_led; /* orange */
|
||||
else
|
||||
spec->gpio_data |= spec->gpio_led; /* white */
|
||||
|
||||
if (!spec->gpio_led_polarity) {
|
||||
/* LED state is inverted on these systems */
|
||||
spec->gpio_data ^= spec->gpio_led;
|
||||
for (i = 0; i < spec->multiout.num_dacs; i++) {
|
||||
nid = spec->multiout.dac_nids[i];
|
||||
if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
|
||||
HDA_AMP_MUTE)) {
|
||||
muted = 0; /* something heard */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (muted)
|
||||
spec->gpio_data &= ~spec->gpio_led; /* orange */
|
||||
else
|
||||
spec->gpio_data |= spec->gpio_led; /* white */
|
||||
|
||||
stac_gpio_set(codec, spec->gpio_mask,
|
||||
spec->gpio_dir,
|
||||
spec->gpio_data);
|
||||
if (!spec->gpio_led_polarity) {
|
||||
/* LED state is inverted on these systems */
|
||||
spec->gpio_data ^= spec->gpio_led;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idt92hd83xxx_hp_check_power_status(struct hda_codec *codec,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
||||
if (nid != 0x13)
|
||||
return 0;
|
||||
if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE)
|
||||
spec->gpio_data |= spec->gpio_led; /* mute LED on */
|
||||
else
|
||||
spec->gpio_data &= ~spec->gpio_led; /* mute LED off */
|
||||
stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
|
||||
@ -5279,7 +5283,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
|
||||
hda_nid_t conn[STAC92HD83_DAC_COUNT + 1];
|
||||
int err;
|
||||
int num_dacs;
|
||||
hda_nid_t nid;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
@ -5318,7 +5321,18 @@ again:
|
||||
stac92hd83xxx_brd_tbl[spec->board_config]);
|
||||
|
||||
switch (codec->vendor_id) {
|
||||
case 0x111d7666:
|
||||
case 0x111d7667:
|
||||
case 0x111d7668:
|
||||
case 0x111d7669:
|
||||
spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
|
||||
spec->pin_nids = stac92hd88xxx_pin_nids;
|
||||
spec->mono_nid = 0;
|
||||
spec->digbeep_nid = 0;
|
||||
spec->num_pwrs = 0;
|
||||
break;
|
||||
case 0x111d7604:
|
||||
case 0x111d76d4:
|
||||
case 0x111d7605:
|
||||
case 0x111d76d5:
|
||||
if (spec->board_config == STAC_92HD83XXX_PWR_REF)
|
||||
@ -5329,8 +5343,10 @@ again:
|
||||
|
||||
codec->patch_ops = stac92xx_patch_ops;
|
||||
|
||||
if (spec->board_config == STAC_92HD83XXX_HP)
|
||||
spec->gpio_led = 0x01;
|
||||
if (find_mute_led_gpio(codec, 0))
|
||||
snd_printd("mute LED gpio %d polarity %d\n",
|
||||
spec->gpio_led,
|
||||
spec->gpio_led_polarity);
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (spec->gpio_led) {
|
||||
@ -5339,7 +5355,7 @@ again:
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
/* register check_power_status callback. */
|
||||
codec->patch_ops.check_power_status =
|
||||
idt92hd83xxx_hp_check_power_status;
|
||||
stac92xx_hp_check_power_status;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -5359,24 +5375,21 @@ again:
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (spec->board_config) {
|
||||
case STAC_DELL_S14:
|
||||
nid = 0xf;
|
||||
break;
|
||||
default:
|
||||
nid = 0xe;
|
||||
break;
|
||||
}
|
||||
|
||||
num_dacs = snd_hda_get_connections(codec, nid,
|
||||
/* docking output support */
|
||||
num_dacs = snd_hda_get_connections(codec, 0xF,
|
||||
conn, STAC92HD83_DAC_COUNT + 1) - 1;
|
||||
if (num_dacs < 0)
|
||||
num_dacs = STAC92HD83_DAC_COUNT;
|
||||
|
||||
/* set port X to select the last DAC
|
||||
*/
|
||||
snd_hda_codec_write_cache(codec, nid, 0,
|
||||
/* skip non-DAC connections */
|
||||
while (num_dacs >= 0 &&
|
||||
(get_wcaps_type(get_wcaps(codec, conn[num_dacs]))
|
||||
!= AC_WID_AUD_OUT))
|
||||
num_dacs--;
|
||||
/* set port E and F to select the last DAC */
|
||||
if (num_dacs >= 0) {
|
||||
snd_hda_codec_write_cache(codec, 0xE, 0,
|
||||
AC_VERB_SET_CONNECT_SEL, num_dacs);
|
||||
snd_hda_codec_write_cache(codec, 0xF, 0,
|
||||
AC_VERB_SET_CONNECT_SEL, num_dacs);
|
||||
}
|
||||
|
||||
codec->proc_widget_hook = stac92hd_proc_hook;
|
||||
|
||||
@ -5657,7 +5670,6 @@ again:
|
||||
*/
|
||||
spec->num_smuxes = 1;
|
||||
spec->num_dmuxes = 1;
|
||||
spec->gpio_led = 0x01;
|
||||
/* fallthrough */
|
||||
case STAC_HP_DV5:
|
||||
snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
|
||||
@ -5672,8 +5684,6 @@ again:
|
||||
spec->num_dmics = 1;
|
||||
spec->num_dmuxes = 1;
|
||||
spec->num_smuxes = 1;
|
||||
/* orange/white mute led on GPIO3, orange=0, white=1 */
|
||||
spec->gpio_led = 0x08;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5695,7 +5705,7 @@ again:
|
||||
}
|
||||
}
|
||||
|
||||
if (find_mute_led_gpio(codec))
|
||||
if (find_mute_led_gpio(codec, 1))
|
||||
snd_printd("mute LED gpio %d polarity %d\n",
|
||||
spec->gpio_led,
|
||||
spec->gpio_led_polarity);
|
||||
@ -6236,8 +6246,13 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
|
||||
{ .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
|
||||
{ .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
|
||||
{ .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d7669, .name = "92HD88B4", .patch = patch_stac92hd83xxx},
|
||||
{ .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
|
||||
{ .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
|
||||
{ .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
|
||||
|
Loading…
Reference in New Issue
Block a user