From dbd65ca2b3df0298b17a0aa4c8648ebf840cab93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Jul 2009 13:09:08 +0200 Subject: [PATCH] --- yaml --- r: 157850 b: refs/heads/master c: 5207e10ed49c515e7432d0b1a7561ccc7b71f9df h: refs/heads/master v: v3 --- [refs] | 2 +- .../sound/alsa/HD-Audio-Models.txt | 4 - trunk/sound/pci/hda/Kconfig | 13 - trunk/sound/pci/hda/Makefile | 4 - trunk/sound/pci/hda/hda_codec.c | 3 +- trunk/sound/pci/hda/hda_codec.h | 2 +- trunk/sound/pci/hda/hda_eld.c | 4 +- trunk/sound/pci/hda/hda_intel.c | 129 +- trunk/sound/pci/hda/patch_cirrus.c | 1194 ----------------- trunk/sound/pci/hda/patch_intelhdmi.c | 104 +- trunk/sound/pci/hda/patch_realtek.c | 1065 +++++++-------- trunk/sound/pci/hda/patch_sigmatel.c | 259 ++-- 12 files changed, 681 insertions(+), 2102 deletions(-) delete mode 100644 trunk/sound/pci/hda/patch_cirrus.c diff --git a/[refs] b/[refs] index 330d12aa4be1..bcaf3f8787f5 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1c4bdf9be010ae7c2324c0a90dd2296e0d1a775e +refs/heads/master: 5207e10ed49c515e7432d0b1a7561ccc7b71f9df diff --git a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt index 775beea4506d..4c95a6c3f79f 100644 --- a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt @@ -383,7 +383,3 @@ STAC9872 ======== vaio VAIO laptop without SPDIF auto BIOS setup (default) - -Cirrus Logic CS4206/4207 -======================== - mbp55 MacBook Pro 5,5 diff --git a/trunk/sound/pci/hda/Kconfig b/trunk/sound/pci/hda/Kconfig index 55545e0818b5..b8a77f9b0827 100644 --- a/trunk/sound/pci/hda/Kconfig +++ b/trunk/sound/pci/hda/Kconfig @@ -148,19 +148,6 @@ config SND_HDA_ELD def_bool y depends on SND_HDA_CODEC_INTELHDMI -config SND_HDA_CODEC_CIRRUS - bool "Build Cirrus Logic codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Cirrus Logic codec support in - snd-hda-intel driver, such as CS4206. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-cirrus. - This module is automatically loaded at probing. - config SND_HDA_CODEC_CONEXANT bool "Build Conexant HD-audio codec support" default y diff --git a/trunk/sound/pci/hda/Makefile b/trunk/sound/pci/hda/Makefile index 315a1c4f8998..e3081d4586cc 100644 --- a/trunk/sound/pci/hda/Makefile +++ b/trunk/sound/pci/hda/Makefile @@ -13,7 +13,6 @@ snd-hda-codec-analog-objs := patch_analog.o snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-atihdmi-objs := patch_atihdmi.o -snd-hda-codec-cirrus-objs := patch_cirrus.o snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o @@ -42,9 +41,6 @@ endif ifdef CONFIG_SND_HDA_CODEC_ATIHDMI obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o endif -ifdef CONFIG_SND_HDA_CODEC_CIRRUS -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o -endif ifdef CONFIG_SND_HDA_CODEC_CA0110 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o endif diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index 24401d5d3511..3a603cde8cc4 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -44,7 +44,6 @@ struct hda_vendor_id { /* codec vendor labels */ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1002, "ATI" }, - { 0x1013, "Cirrus Logic" }, { 0x1057, "Motorola" }, { 0x1095, "Silicon Image" }, { 0x10de, "Nvidia" }, @@ -185,7 +184,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, mutex_lock(&bus->cmd_mutex); err = bus->ops.command(bus, cmd); if (!err && res) - *res = bus->ops.get_response(bus, codec->addr); + *res = bus->ops.get_response(bus); mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); if (res && *res == -1 && bus->rirb_error) { diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index 99552fb5f756..72c997592eed 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -568,7 +568,7 @@ struct hda_bus_ops { /* send a single command */ int (*command)(struct hda_bus *bus, unsigned int cmd); /* get a response from the last command */ - unsigned int (*get_response)(struct hda_bus *bus, unsigned int addr); + unsigned int (*get_response)(struct hda_bus *bus); /* free the private data */ void (*private_free)(struct hda_bus *); /* attach a PCM stream */ diff --git a/trunk/sound/pci/hda/hda_eld.c b/trunk/sound/pci/hda/hda_eld.c index 9446a5abea13..fcad5ec31773 100644 --- a/trunk/sound/pci/hda/hda_eld.c +++ b/trunk/sound/pci/hda/hda_eld.c @@ -508,7 +508,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry, char name[64]; char *sname; long long val; - unsigned int n; + int n; while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%s %llx", name, &val) != 2) @@ -539,7 +539,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry, sname++; n = 10 * n + name[4] - '0'; } - if (n >= ELD_MAX_SAD) + if (n < 0 || n > 31) /* double the CEA limit */ continue; if (!strcmp(sname, "_coding_type")) e->sad[n].format = val; diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index 20a66f85f0a4..4db854b43e6b 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -260,7 +260,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* STATESTS int mask: S3,SD2,SD1,SD0 */ #define AZX_MAX_CODECS 4 -#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) +#define STATESTS_INT_MASK 0x0f /* SD_CTL bits */ #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ @@ -368,8 +368,8 @@ struct azx_rb { dma_addr_t addr; /* physical address of CORB/RIRB buffer */ /* for RIRB */ unsigned short rp, wp; /* read/write pointers */ - int cmds[AZX_MAX_CODECS]; /* number of pending requests */ - u32 res[AZX_MAX_CODECS]; /* last read value */ + int cmds; /* number of pending requests */ + u32 res; /* last read value */ }; struct azx { @@ -425,7 +425,7 @@ struct azx { unsigned int probing :1; /* codec probing phase */ /* for debugging */ - unsigned int last_cmd[AZX_MAX_CODECS]; + unsigned int last_cmd; /* last issued command (to sync) */ /* for pending irqs */ struct work_struct irq_pending_work; @@ -520,7 +520,6 @@ static int azx_alloc_cmd_io(struct azx *chip) static void azx_init_cmd_io(struct azx *chip) { - spin_lock_irq(&chip->reg_lock); /* CORB set up */ chip->corb.addr = chip->rb.addr; chip->corb.buf = (u32 *)chip->rb.area; @@ -539,8 +538,7 @@ static void azx_init_cmd_io(struct azx *chip) /* RIRB set up */ chip->rirb.addr = chip->rb.addr + 2048; chip->rirb.buf = (u32 *)(chip->rb.area + 2048); - chip->rirb.wp = chip->rirb.rp = 0; - memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds)); + chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0; azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); @@ -552,60 +550,30 @@ static void azx_init_cmd_io(struct azx *chip) azx_writew(chip, RINTCNT, 1); /* enable rirb dma and response irq */ azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); - spin_unlock_irq(&chip->reg_lock); } static void azx_free_cmd_io(struct azx *chip) { - spin_lock_irq(&chip->reg_lock); /* disable ringbuffer DMAs */ azx_writeb(chip, RIRBCTL, 0); azx_writeb(chip, CORBCTL, 0); - spin_unlock_irq(&chip->reg_lock); -} - -static unsigned int azx_command_addr(u32 cmd) -{ - unsigned int addr = cmd >> 28; - - if (addr >= AZX_MAX_CODECS) { - snd_BUG(); - addr = 0; - } - - return addr; -} - -static unsigned int azx_response_addr(u32 res) -{ - unsigned int addr = res & 0xf; - - if (addr >= AZX_MAX_CODECS) { - snd_BUG(); - addr = 0; - } - - return addr; } /* send a command */ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) { struct azx *chip = bus->private_data; - unsigned int addr = azx_command_addr(val); unsigned int wp; - spin_lock_irq(&chip->reg_lock); - /* add command to corb */ wp = azx_readb(chip, CORBWP); wp++; wp %= ICH6_MAX_CORB_ENTRIES; - chip->rirb.cmds[addr]++; + spin_lock_irq(&chip->reg_lock); + chip->rirb.cmds++; chip->corb.buf[wp] = cpu_to_le32(val); azx_writel(chip, CORBWP, wp); - spin_unlock_irq(&chip->reg_lock); return 0; @@ -617,14 +585,13 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) static void azx_update_rirb(struct azx *chip) { unsigned int rp, wp; - unsigned int addr; u32 res, res_ex; wp = azx_readb(chip, RIRBWP); if (wp == chip->rirb.wp) return; chip->rirb.wp = wp; - + while (chip->rirb.rp != wp) { chip->rirb.rp++; chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; @@ -632,24 +599,18 @@ static void azx_update_rirb(struct azx *chip) rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); res = le32_to_cpu(chip->rirb.buf[rp]); - addr = azx_response_addr(res_ex); if (res_ex & ICH6_RIRB_EX_UNSOL_EV) snd_hda_queue_unsol_event(chip->bus, res, res_ex); - else if (chip->rirb.cmds[addr]) { - chip->rirb.res[addr] = res; + else if (chip->rirb.cmds) { + chip->rirb.res = res; smp_wmb(); - chip->rirb.cmds[addr]--; - } else - snd_printk(KERN_ERR SFX "spurious response %#x:%#x, " - "last cmd=%#08x\n", - res, res_ex, - chip->last_cmd[addr]); + chip->rirb.cmds--; + } } } /* receive a response */ -static unsigned int azx_rirb_get_response(struct hda_bus *bus, - unsigned int addr) +static unsigned int azx_rirb_get_response(struct hda_bus *bus) { struct azx *chip = bus->private_data; unsigned long timeout; @@ -662,10 +623,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, azx_update_rirb(chip); spin_unlock_irq(&chip->reg_lock); } - if (!chip->rirb.cmds[addr]) { + if (!chip->rirb.cmds) { smp_rmb(); bus->rirb_error = 0; - return chip->rirb.res[addr]; /* the last value */ + return chip->rirb.res; /* the last value */ } if (time_after(jiffies, timeout)) break; @@ -679,8 +640,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (chip->msi) { snd_printk(KERN_WARNING SFX "No response from codec, " - "disabling MSI: last cmd=0x%08x\n", - chip->last_cmd[addr]); + "disabling MSI: last cmd=0x%08x\n", chip->last_cmd); free_irq(chip->irq, chip); chip->irq = -1; pci_disable_msi(chip->pci); @@ -695,7 +655,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (!chip->polling_mode) { snd_printk(KERN_WARNING SFX "azx_get_response timeout, " "switching to polling mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); + chip->last_cmd); chip->polling_mode = 1; goto again; } @@ -719,7 +679,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " "switching to single_cmd mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); + chip->last_cmd); chip->single_cmd = 1; bus->response_reset = 0; /* re-initialize CORB/RIRB */ @@ -739,7 +699,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, */ /* receive a response */ -static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) +static int azx_single_wait_for_response(struct azx *chip) { int timeout = 50; @@ -747,7 +707,7 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) /* check IRV busy bit */ if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { /* reuse rirb.res as the response return value */ - chip->rirb.res[addr] = azx_readl(chip, IR); + chip->rirb.res = azx_readl(chip, IR); return 0; } udelay(1); @@ -755,7 +715,7 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) if (printk_ratelimit()) snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); - chip->rirb.res[addr] = -1; + chip->rirb.res = -1; return -EIO; } @@ -763,7 +723,6 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) static int azx_single_send_cmd(struct hda_bus *bus, u32 val) { struct azx *chip = bus->private_data; - unsigned int addr = azx_command_addr(val); int timeout = 50; bus->rirb_error = 0; @@ -776,7 +735,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) azx_writel(chip, IC, val); azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); - return azx_single_wait_for_response(chip, addr); + return azx_single_wait_for_response(chip); } udelay(1); } @@ -787,11 +746,10 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) } /* receive a response */ -static unsigned int azx_single_get_response(struct hda_bus *bus, - unsigned int addr) +static unsigned int azx_single_get_response(struct hda_bus *bus) { struct azx *chip = bus->private_data; - return chip->rirb.res[addr]; + return chip->rirb.res; } /* @@ -806,7 +764,7 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val) { struct azx *chip = bus->private_data; - chip->last_cmd[azx_command_addr(val)] = val; + chip->last_cmd = val; if (chip->single_cmd) return azx_single_send_cmd(bus, val); else @@ -814,14 +772,13 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val) } /* get a response */ -static unsigned int azx_get_response(struct hda_bus *bus, - unsigned int addr) +static unsigned int azx_get_response(struct hda_bus *bus) { struct azx *chip = bus->private_data; if (chip->single_cmd) - return azx_single_get_response(bus, addr); + return azx_single_get_response(bus); else - return azx_rirb_get_response(bus, addr); + return azx_rirb_get_response(bus); } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -1293,12 +1250,10 @@ static int probe_codec(struct azx *chip, int addr) (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res; - mutex_lock(&chip->bus->cmd_mutex); chip->probing = 1; azx_send_cmd(chip->bus, cmd); - res = azx_get_response(chip->bus, addr); + res = azx_get_response(chip->bus); chip->probing = 0; - mutex_unlock(&chip->bus->cmd_mutex); if (res == -1) return -EIO; snd_printdd(SFX "codec #%d probed OK\n", addr); @@ -2299,30 +2254,6 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) } } -/* - * white-list for enable_msi - */ -static struct snd_pci_quirk msi_white_list[] __devinitdata = { - SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1), - {} -}; - -static void __devinit check_msi(struct azx *chip) -{ - const struct snd_pci_quirk *q; - - chip->msi = enable_msi; - if (chip->msi) - return; - q = snd_pci_quirk_lookup(chip->pci, msi_white_list); - if (q) { - printk(KERN_INFO - "hda_intel: msi for device %04x:%04x set to %d\n", - q->subvendor, q->subdevice, q->value); - chip->msi = q->value; - } -} - /* * constructor @@ -2357,7 +2288,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->pci = pci; chip->irq = -1; chip->driver_type = driver_type; - check_msi(chip); + chip->msi = enable_msi; chip->dev_index = dev; INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); diff --git a/trunk/sound/pci/hda/patch_cirrus.c b/trunk/sound/pci/hda/patch_cirrus.c deleted file mode 100644 index 8ba306856d38..000000000000 --- a/trunk/sound/pci/hda/patch_cirrus.c +++ /dev/null @@ -1,1194 +0,0 @@ -/* - * HD audio interface patch for Cirrus Logic CS420x chip - * - * Copyright (c) 2009 Takashi Iwai - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -/* - */ - -struct cs_spec { - int board_config; - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - struct snd_kcontrol *vmaster_sw; - struct snd_kcontrol *vmaster_vol; - - hda_nid_t dac_nid[AUTO_CFG_MAX_OUTS]; - hda_nid_t slave_dig_outs[2]; - - unsigned int input_idx[AUTO_PIN_LAST]; - unsigned int capsrc_idx[AUTO_PIN_LAST]; - hda_nid_t adc_nid[AUTO_PIN_LAST]; - unsigned int adc_idx[AUTO_PIN_LAST]; - unsigned int num_inputs; - unsigned int cur_input; - unsigned int automic_idx; - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - hda_nid_t dig_in; - - struct hda_bind_ctls *capture_bind[2]; - - unsigned int gpio_mask; - unsigned int gpio_dir; - unsigned int gpio_data; - - struct hda_pcm pcm_rec[2]; /* PCM information */ - - unsigned int hp_detect:1; - unsigned int mic_detect:1; -}; - -/* available models */ -enum { - CS420X_MBP55, - CS420X_AUTO, - CS420X_MODELS -}; - -/* Vendor-specific processing widget */ -#define CS420X_VENDOR_NID 0x11 -#define CS_DIG_OUT1_PIN_NID 0x10 -#define CS_DIG_OUT2_PIN_NID 0x15 -#define CS_DMIC1_PIN_NID 0x12 -#define CS_DMIC2_PIN_NID 0x0e - -/* coef indices */ -#define IDX_SPDIF_STAT 0x0000 -#define IDX_SPDIF_CTL 0x0001 -#define IDX_ADC_CFG 0x0002 -/* SZC bitmask, 4 modes below: - * 0 = immediate, - * 1 = digital immediate, analog zero-cross - * 2 = digtail & analog soft-ramp - * 3 = digital soft-ramp, analog zero-cross - */ -#define CS_COEF_ADC_SZC_MASK (3 << 0) -#define CS_COEF_ADC_MIC_SZC_MODE (3 << 0) /* SZC setup for mic */ -#define CS_COEF_ADC_LI_SZC_MODE (3 << 0) /* SZC setup for line-in */ -/* PGA mode: 0 = differential, 1 = signle-ended */ -#define CS_COEF_ADC_MIC_PGA_MODE (1 << 5) /* PGA setup for mic */ -#define CS_COEF_ADC_LI_PGA_MODE (1 << 6) /* PGA setup for line-in */ -#define IDX_DAC_CFG 0x0003 -/* SZC bitmask, 4 modes below: - * 0 = Immediate - * 1 = zero-cross - * 2 = soft-ramp - * 3 = soft-ramp on zero-cross - */ -#define CS_COEF_DAC_HP_SZC_MODE (3 << 0) /* nid 0x02 */ -#define CS_COEF_DAC_LO_SZC_MODE (3 << 2) /* nid 0x03 */ -#define CS_COEF_DAC_SPK_SZC_MODE (3 << 4) /* nid 0x04 */ - -#define IDX_BEEP_CFG 0x0004 -/* 0x0008 - test reg key */ -/* 0x0009 - 0x0014 -> 12 test regs */ -/* 0x0015 - visibility reg */ - - -static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) -{ - snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, - AC_VERB_SET_COEF_INDEX, idx); - return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0, - AC_VERB_GET_PROC_COEF, 0); -} - -static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, - unsigned int coef) -{ - snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, - AC_VERB_SET_COEF_INDEX, idx); - snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, - AC_VERB_SET_PROC_COEF, coef); -} - - -#define HP_EVENT 1 -#define MIC_EVENT 2 - -/* - * PCM callbacks - */ -static int cs_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int cs_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int cs_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int cs_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int cs_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int cs_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); -} - -/* - * Analog capture - */ -static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nid[spec->cur_input]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; -} - -static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -/* - */ -static struct hda_pcm_stream cs_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = cs_playback_pcm_open, - .prepare = cs_playback_pcm_prepare, - .cleanup = cs_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream cs_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = cs_capture_pcm_prepare, - .cleanup = cs_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream cs_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = cs_dig_playback_pcm_open, - .close = cs_dig_playback_pcm_close, - .prepare = cs_dig_playback_pcm_prepare, - .cleanup = cs_dig_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream cs_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int cs_build_pcms(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "Cirrus Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cs_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dac_nid[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nid[spec->cur_input]; - codec->num_pcms++; - - if (!spec->multiout.dig_out_nid && !spec->dig_in) - return 0; - - info++; - info->name = "Cirrus Digital"; - info->pcm_type = spec->autocfg.dig_out_type[0]; - if (!info->pcm_type) - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - cs_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - cs_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -/* - * parse codec topology - */ - -static hda_nid_t get_dac(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t dac; - if (!pin) - return 0; - if (snd_hda_get_connections(codec, pin, &dac, 1) != 1) - return 0; - return dac; -} - -static int is_ext_mic(struct hda_codec *codec, unsigned int idx) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t pin = cfg->input_pins[idx]; - unsigned int val = snd_hda_query_pin_caps(codec, pin); - if (!(val & AC_PINCAP_PRES_DETECT)) - return 0; - val = snd_hda_codec_get_pincfg(codec, pin); - return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX); -} - -static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, - unsigned int *idxp) -{ - int i; - hda_nid_t nid; - - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - hda_nid_t pins[2]; - unsigned int type; - int j, nums; - type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) - >> AC_WCAP_TYPE_SHIFT; - if (type != AC_WID_AUD_IN) - continue; - nums = snd_hda_get_connections(codec, nid, pins, - ARRAY_SIZE(pins)); - if (nums <= 0) - continue; - for (j = 0; j < nums; j++) { - if (pins[j] == pin) { - *idxp = j; - return nid; - } - } - } - return 0; -} - -static int is_active_pin(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val; - val = snd_hda_codec_get_pincfg(codec, nid); - return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); -} - -static int parse_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, extra_nids; - hda_nid_t dac; - - for (i = 0; i < cfg->line_outs; i++) { - dac = get_dac(codec, cfg->line_out_pins[i]); - if (!dac) - break; - spec->dac_nid[i] = dac; - } - spec->multiout.num_dacs = i; - spec->multiout.dac_nids = spec->dac_nid; - spec->multiout.max_channels = i * 2; - - /* add HP and speakers */ - extra_nids = 0; - for (i = 0; i < cfg->hp_outs; i++) { - dac = get_dac(codec, cfg->hp_pins[i]); - if (!dac) - break; - if (!i) - spec->multiout.hp_nid = dac; - else - spec->multiout.extra_out_nid[extra_nids++] = dac; - } - for (i = 0; i < cfg->speaker_outs; i++) { - dac = get_dac(codec, cfg->speaker_pins[i]); - if (!dac) - break; - spec->multiout.extra_out_nid[extra_nids++] = dac; - } - - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = 0; - } - - return 0; -} - -static int parse_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t pin = cfg->input_pins[i]; - if (!pin) - continue; - spec->input_idx[spec->num_inputs] = i; - spec->capsrc_idx[i] = spec->num_inputs++; - spec->cur_input = i; - spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); - } - if (!spec->num_inputs) - return 0; - - /* check whether the automatic mic switch is available */ - if (spec->num_inputs == 2 && - spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) { - if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) { - if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { - spec->mic_detect = 1; - spec->automic_idx = AUTO_PIN_FRONT_MIC; - } - } else { - if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { - spec->mic_detect = 1; - spec->automic_idx = AUTO_PIN_MIC; - } - } - } - return 0; -} - - -static int parse_digital_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - - if (!cfg->dig_outs) - return 0; - if (snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) < 1) - return 0; - spec->multiout.dig_out_nid = nid; - spec->multiout.share_spdif = 1; - if (cfg->dig_outs > 1 && - snd_hda_get_connections(codec, cfg->dig_out_pins[1], &nid, 1) > 0) { - spec->slave_dig_outs[0] = nid; - codec->slave_dig_outs = spec->slave_dig_outs; - } - return 0; -} - -static int parse_digital_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int idx; - - if (cfg->dig_in_pin) - spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); - return 0; -} - -/* - * create mixer controls - */ - -static const char *dir_sfx[2] = { "Playback", "Capture" }; - -static int add_mute(struct hda_codec *codec, const char *name, int index, - unsigned int pval, int dir, struct snd_kcontrol **kctlp) -{ - char tmp[44]; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_IDX(tmp, index, 0, 0, HDA_OUTPUT); - knew.private_value = pval; - snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); - *kctlp = snd_ctl_new1(&knew, codec); - return snd_hda_ctl_add(codec, *kctlp); -} - -static int add_volume(struct hda_codec *codec, const char *name, - int index, unsigned int pval, int dir, - struct snd_kcontrol **kctlp) -{ - char tmp[32]; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT); - knew.private_value = pval; - snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); - *kctlp = snd_ctl_new1(&knew, codec); - return snd_hda_ctl_add(codec, *kctlp); -} - -static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) -{ - unsigned int caps; - - /* set the upper-limit for mixer amp to 0dB */ - caps = query_amp_caps(codec, dac, HDA_OUTPUT); - caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); - caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) - << AC_AMPCAP_NUM_STEPS_SHIFT; - snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); -} - -static int add_vmaster(struct hda_codec *codec, hda_nid_t dac) -{ - struct cs_spec *spec = codec->spec; - unsigned int tlv[4]; - int err; - - spec->vmaster_sw = - snd_ctl_make_virtual_master("Master Playback Switch", NULL); - err = snd_hda_ctl_add(codec, spec->vmaster_sw); - if (err < 0) - return err; - - snd_hda_set_vmaster_tlv(codec, dac, HDA_OUTPUT, tlv); - spec->vmaster_vol = - snd_ctl_make_virtual_master("Master Playback Volume", tlv); - err = snd_hda_ctl_add(codec, spec->vmaster_vol); - if (err < 0) - return err; - return 0; -} - -static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, - int num_ctls, int type) -{ - struct cs_spec *spec = codec->spec; - const char *name; - int err, index; - struct snd_kcontrol *kctl; - static char *speakers[] = { - "Front Speaker", "Surround Speaker", "Bass Speaker" - }; - static char *line_outs[] = { - "Front Line-Out", "Surround Line-Out", "Bass Line-Out" - }; - - fix_volume_caps(codec, dac); - if (!spec->vmaster_sw) { - err = add_vmaster(codec, dac); - if (err < 0) - return err; - } - - index = 0; - switch (type) { - case AUTO_PIN_HP_OUT: - name = "Headphone"; - index = idx; - break; - case AUTO_PIN_SPEAKER_OUT: - if (num_ctls > 1) - name = speakers[idx]; - else - name = "Speaker"; - break; - default: - if (num_ctls > 1) - name = line_outs[idx]; - else - name = "Line-Out"; - break; - } - - err = add_mute(codec, name, index, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = snd_ctl_add_slave(spec->vmaster_sw, kctl); - if (err < 0) - return err; - - err = add_volume(codec, name, index, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = snd_ctl_add_slave(spec->vmaster_vol, kctl); - if (err < 0) - return err; - - return 0; -} - -static int build_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - - for (i = 0; i < cfg->line_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->line_out_pins[i]), - i, cfg->line_outs, cfg->line_out_type); - if (err < 0) - return err; - } - for (i = 0; i < cfg->hp_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->hp_pins[i]), - i, cfg->hp_outs, AUTO_PIN_HP_OUT); - if (err < 0) - return err; - } - for (i = 0; i < cfg->speaker_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->speaker_pins[i]), - i, cfg->speaker_outs, AUTO_PIN_SPEAKER_OUT); - if (err < 0) - return err; - } - return 0; -} - -/* - */ - -static struct snd_kcontrol_new cs_capture_ctls[] = { - HDA_BIND_SW("Capture Switch", 0), - HDA_BIND_VOL("Capture Volume", 0), -}; - -static int change_cur_input(struct hda_codec *codec, unsigned int idx, - int force) -{ - struct cs_spec *spec = codec->spec; - - if (spec->cur_input == idx && !force) - return 0; - if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { - /* stream is running, let's swap the current ADC */ - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = spec->adc_nid[idx]; - snd_hda_codec_setup_stream(codec, spec->cur_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } - snd_hda_codec_write(codec, spec->cur_adc, 0, - AC_VERB_SET_CONNECT_SEL, - spec->adc_idx[idx]); - spec->cur_input = idx; - return 1; -} - -static int cs_capture_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - unsigned int idx; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->num_inputs; - if (uinfo->value.enumerated.item >= spec->num_inputs) - uinfo->value.enumerated.item = spec->num_inputs - 1; - idx = spec->input_idx[uinfo->value.enumerated.item]; - strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]); - return 0; -} - -static int cs_capture_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->capsrc_idx[spec->cur_input]; - return 0; -} - -static int cs_capture_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - unsigned int idx = ucontrol->value.enumerated.item[0]; - - if (idx >= spec->num_inputs) - return -EINVAL; - idx = spec->input_idx[idx]; - return change_cur_input(codec, idx, 0); -} - -static struct snd_kcontrol_new cs_capture_source = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = cs_capture_source_info, - .get = cs_capture_source_get, - .put = cs_capture_source_put, -}; - -static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, - struct hda_ctl_ops *ops) -{ - struct cs_spec *spec = codec->spec; - struct hda_bind_ctls *bind; - int i, n; - - bind = kzalloc(sizeof(*bind) + sizeof(long) * (spec->num_inputs + 1), - GFP_KERNEL); - if (!bind) - return NULL; - bind->ops = ops; - n = 0; - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!spec->adc_nid[i]) - continue; - bind->values[n++] = - HDA_COMPOSE_AMP_VAL(spec->adc_nid[i], 3, - spec->adc_idx[i], HDA_INPUT); - } - return bind; -} - -static int build_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int i, err; - - if (!spec->num_inputs) - return 0; - - /* make bind-capture */ - spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); - spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); - for (i = 0; i < 2; i++) { - struct snd_kcontrol *kctl; - if (!spec->capture_bind[i]) - return -ENOMEM; - kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = (long)spec->capture_bind[i]; - err = snd_hda_ctl_add(codec, kctl); - if (err < 0) - return err; - } - - if (spec->num_inputs > 1 && !spec->mic_detect) { - err = snd_hda_ctl_add(codec, - snd_ctl_new1(&cs_capture_source, codec)); - if (err < 0) - return err; - } - - return 0; -} - -/* - */ - -static int build_digital_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - if (!spec->multiout.dig_out_nid) - return 0; - - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); - if (err < 0) - return err; - return 0; -} - -static int build_digital_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - if (spec->dig_in) - return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - return 0; -} - -/* - * auto-mute and auto-mic switching - */ - -static void cs_automute(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int caps, present, hp_present; - hda_nid_t nid; - int i; - - hp_present = 0; - for (i = 0; i < cfg->hp_outs; i++) { - nid = cfg->hp_pins[i]; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_PRES_DETECT)) - continue; - if (caps & AC_PINCAP_TRIG_REQ) - snd_hda_codec_read(codec, nid, 0, - AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - hp_present |= (present & AC_PINSENSE_PRESENCE) != 0; - if (hp_present) - break; - } - for (i = 0; i < cfg->speaker_outs; i++) { - nid = cfg->speaker_pins[i]; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - hp_present ? 0 : PIN_OUT); - } - if (spec->board_config == CS420X_MBP55) { - unsigned int gpio = hp_present ? 0x02 : 0x08; - snd_hda_codec_write(codec, 0x01, 0, - AC_VERB_SET_GPIO_DATA, gpio); - } -} - -static void cs_automic(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - unsigned int caps, present; - - nid = cfg->input_pins[spec->automic_idx]; - caps = snd_hda_query_pin_caps(codec, nid); - if (caps & AC_PINCAP_TRIG_REQ) - snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - if (present & AC_PINSENSE_PRESENCE) - change_cur_input(codec, spec->automic_idx, 0); - else { - unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? - AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC; - change_cur_input(codec, imic, 0); - } -} - -/* - */ - -static void init_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - /* mute first */ - for (i = 0; i < spec->multiout.num_dacs; i++) - snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (spec->multiout.hp_nid) - snd_hda_codec_write(codec, spec->multiout.hp_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { - if (!spec->multiout.extra_out_nid[i]) - break; - snd_hda_codec_write(codec, spec->multiout.extra_out_nid[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - } - - /* set appropriate pin controls */ - for (i = 0; i < cfg->line_outs; i++) - snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - if (!cfg->speaker_outs) - continue; - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | HP_EVENT); - spec->hp_detect = 1; - } - } - for (i = 0; i < cfg->speaker_outs; i++) - snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - if (spec->hp_detect) - cs_automute(codec); -} - -static void init_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int coef; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - unsigned int ctl; - hda_nid_t pin = cfg->input_pins[i]; - if (!pin || !spec->adc_nid[i]) - continue; - /* set appropriate pin control and mute first */ - ctl = PIN_IN; - if (i <= AUTO_PIN_FRONT_MIC) { - unsigned int caps = snd_hda_query_pin_caps(codec, pin); - caps >>= AC_PINCAP_VREF_SHIFT; - if (caps & AC_PINCAP_VREF_80) - ctl = PIN_VREF80; - } - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); - snd_hda_codec_write(codec, spec->adc_nid[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(spec->adc_idx[i])); - if (spec->mic_detect && spec->automic_idx == i) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | MIC_EVENT); - } - change_cur_input(codec, spec->cur_input, 1); - if (spec->mic_detect) - cs_automic(codec); - - coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ - if (is_active_pin(codec, CS_DMIC2_PIN_NID)) - coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */ - if (is_active_pin(codec, CS_DMIC1_PIN_NID)) - coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 - * No effect if SPDIF_OUT2 is slected in - * IDX_SPDIF_CTL. - */ - cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); -} - -static struct hda_verb cs_coef_init_verbs[] = { - {0x11, AC_VERB_SET_PROC_STATE, 1}, - {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, - {0x11, AC_VERB_SET_PROC_COEF, - (0x002a /* DAC1/2/3 SZCMode Soft Ramp */ - | 0x0040 /* Mute DACs on FIFO error */ - | 0x1000 /* Enable DACs High Pass Filter */ - | 0x0400 /* Disable Coefficient Auto increment */ - )}, - /* Beep */ - {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, - {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */ - - {} /* terminator */ -}; - -/* SPDIF setup */ -static void init_digital(struct hda_codec *codec) -{ - unsigned int coef; - - coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */ - coef |= 0x0008; /* Replace with mute on error */ - if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID)) - coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2 - * SPDIF_OUT2 is shared with GPIO1 and - * DMIC_SDA2. - */ - cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef); -} - -static int cs_init(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - - snd_hda_sequence_write(codec, cs_coef_init_verbs); - - if (spec->gpio_mask) { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, - spec->gpio_mask); - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, - spec->gpio_dir); - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->gpio_data); - } - - init_output(codec); - init_input(codec); - init_digital(codec); - return 0; -} - -static int cs_build_controls(struct hda_codec *codec) -{ - int err; - - err = build_output(codec); - if (err < 0) - return err; - err = build_input(codec); - if (err < 0) - return err; - err = build_digital_output(codec); - if (err < 0) - return err; - err = build_digital_input(codec); - if (err < 0) - return err; - return cs_init(codec); -} - -static void cs_free(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - kfree(spec->capture_bind[0]); - kfree(spec->capture_bind[1]); - kfree(codec->spec); -} - -static void cs_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch ((res >> 26) & 0x7f) { - case HP_EVENT: - cs_automute(codec); - break; - case MIC_EVENT: - cs_automic(codec); - break; - } -} - -static struct hda_codec_ops cs_patch_ops = { - .build_controls = cs_build_controls, - .build_pcms = cs_build_pcms, - .init = cs_init, - .free = cs_free, - .unsol_event = cs_unsol_event, -}; - -static int cs_parse_auto_config(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - - err = parse_output(codec); - if (err < 0) - return err; - err = parse_input(codec); - if (err < 0) - return err; - err = parse_digital_output(codec); - if (err < 0) - return err; - err = parse_digital_input(codec); - if (err < 0) - return err; - return 0; -} - -static const char *cs420x_models[CS420X_MODELS] = { - [CS420X_MBP55] = "mbp55", - [CS420X_AUTO] = "auto", -}; - - -static struct snd_pci_quirk cs420x_cfg_tbl[] = { - SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), - {} /* terminator */ -}; - -struct cs_pincfg { - hda_nid_t nid; - u32 val; -}; - -static struct cs_pincfg mbp55_pincfgs[] = { - { 0x09, 0x012b4030 }, - { 0x0a, 0x90100121 }, - { 0x0b, 0x90100120 }, - { 0x0c, 0x400000f0 }, - { 0x0d, 0x90a00110 }, - { 0x0e, 0x400000f0 }, - { 0x0f, 0x400000f0 }, - { 0x10, 0x014be040 }, - { 0x12, 0x400000f0 }, - { 0x15, 0x400000f0 }, - {} /* terminator */ -}; - -static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { - [CS420X_MBP55] = mbp55_pincfgs, -}; - -static void fix_pincfg(struct hda_codec *codec, int model) -{ - const struct cs_pincfg *cfg = cs_pincfgs[model]; - if (!cfg) - return; - for (; cfg->nid; cfg++) - snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); -} - - -static int patch_cs420x(struct hda_codec *codec) -{ - struct cs_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - spec->board_config = - snd_hda_check_board_config(codec, CS420X_MODELS, - cs420x_models, cs420x_cfg_tbl); - if (spec->board_config >= 0) - fix_pincfg(codec, spec->board_config); - - switch (spec->board_config) { - case CS420X_MBP55: - /* GPIO1 = headphones */ - /* GPIO3 = speakers */ - spec->gpio_mask = 0x0a; - spec->gpio_dir = 0x0a; - break; - } - - err = cs_parse_auto_config(codec); - if (err < 0) - goto error; - - codec->patch_ops = cs_patch_ops; - - return 0; - - error: - kfree(codec->spec); - codec->spec = NULL; - return err; -} - - -/* - * patch entries - */ -static struct hda_codec_preset snd_hda_preset_cirrus[] = { - { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, - { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, - {} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:10134206"); -MODULE_ALIAS("snd-hda-codec-id:10134207"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); - -static struct hda_codec_preset_list cirrus_list = { - .preset = snd_hda_preset_cirrus, - .owner = THIS_MODULE, -}; - -static int __init patch_cirrus_init(void) -{ - return snd_hda_add_codec_preset(&cirrus_list); -} - -static void __exit patch_cirrus_exit(void) -{ - snd_hda_delete_codec_preset(&cirrus_list); -} - -module_init(patch_cirrus_init) -module_exit(patch_cirrus_exit) diff --git a/trunk/sound/pci/hda/patch_intelhdmi.c b/trunk/sound/pci/hda/patch_intelhdmi.c index 01a18ed475ac..032850eba369 100644 --- a/trunk/sound/pci/hda/patch_intelhdmi.c +++ b/trunk/sound/pci/hda/patch_intelhdmi.c @@ -33,8 +33,8 @@ #include "hda_codec.h" #include "hda_local.h" -static hda_nid_t cvt_nid; /* audio converter */ -static hda_nid_t pin_nid; /* HDMI output pin */ +#define CVT_NID 0x02 /* audio converter */ +#define PIN_NID 0x03 /* HDMI output pin */ #define INTEL_HDMI_EVENT_TAG 0x08 @@ -44,6 +44,30 @@ struct intel_hdmi_spec { struct hdmi_eld sink_eld; }; +static struct hda_verb pinout_enable_verb[] = { + {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {} /* terminator */ +}; + +static struct hda_verb unsolicited_response_verb[] = { + {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | + INTEL_HDMI_EVENT_TAG}, + {} +}; + +static struct hda_verb def_chan_map[] = { + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77}, + {} +}; + + struct hdmi_audio_infoframe { u8 type; /* 0x84 */ u8 ver; /* 0x01 */ @@ -220,12 +244,11 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, static void hdmi_enable_output(struct hda_codec *codec) { /* Unmute */ - if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin_nid, 0, + if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); /* Enable pin out */ - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + snd_hda_sequence_write(codec, pinout_enable_verb); } /* @@ -233,8 +256,8 @@ static void hdmi_enable_output(struct hda_codec *codec) */ static void hdmi_start_infoframe_trans(struct hda_codec *codec) { - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); } @@ -243,20 +266,20 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec) */ static void hdmi_stop_infoframe_trans(struct hda_codec *codec) { - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); } static int hdmi_get_channel_count(struct hda_codec *codec) { - return 1 + snd_hda_codec_read(codec, cvt_nid, 0, + return 1 + snd_hda_codec_read(codec, CVT_NID, 0, AC_VERB_GET_CVT_CHAN_COUNT, 0); } static void hdmi_set_channel_count(struct hda_codec *codec, int chs) { - snd_hda_codec_write(codec, cvt_nid, 0, + snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); if (chs != hdmi_get_channel_count(codec)) @@ -271,7 +294,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) int slot; for (i = 0; i < 8; i++) { - slot = snd_hda_codec_read(codec, cvt_nid, 0, + slot = snd_hda_codec_read(codec, CVT_NID, 0, AC_VERB_GET_HDMI_CHAN_SLOT, i); printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", slot >> 4, slot & 0x7); @@ -284,7 +307,7 @@ static void hdmi_parse_eld(struct hda_codec *codec) struct intel_hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->sink_eld; - if (!snd_hdmi_get_eld(eld, codec, pin_nid)) + if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) snd_hdmi_show_eld(eld); } @@ -299,11 +322,11 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) int i; int size; - size = snd_hdmi_get_eld_size(codec, pin_nid); + size = snd_hdmi_get_eld_size(codec, PIN_NID); printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, pin_nid, 0, + size = snd_hda_codec_read(codec, PIN_NID, 0, AC_VERB_GET_HDMI_DIP_SIZE, i); printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); } @@ -317,15 +340,15 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) int size; int pi, bi; for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, pin_nid, 0, + size = snd_hda_codec_read(codec, PIN_NID, 0, AC_VERB_GET_HDMI_DIP_SIZE, i); if (size == 0) continue; - hdmi_set_dip_index(codec, pin_nid, i, 0x0); + hdmi_set_dip_index(codec, PIN_NID, i, 0x0); for (j = 1; j < 1000; j++) { - hdmi_write_dip_byte(codec, pin_nid, 0x0); - hdmi_get_dip_index(codec, pin_nid, &pi, &bi); + hdmi_write_dip_byte(codec, PIN_NID, 0x0); + hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); if (pi != i) snd_printd(KERN_INFO "dip index %d: %d != %d\n", bi, pi, i); @@ -353,9 +376,9 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec, sum += params[i]; ai->checksum = - sum; - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); for (i = 0; i < sizeof(ai); i++) - hdmi_write_dip_byte(codec, pin_nid, params[i]); + hdmi_write_dip_byte(codec, PIN_NID, params[i]); } /* @@ -442,8 +465,6 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, static void hdmi_setup_channel_mapping(struct hda_codec *codec, struct hdmi_audio_infoframe *ai) { - int i; - if (!ai->CA) return; @@ -452,11 +473,7 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, * ALSA sequence is front/surr/clfe/side? */ - for (i = 0; i < 8; i++) - snd_hda_codec_write(codec, cvt_nid, 0, - AC_VERB_SET_HDMI_CHAN_SLOT, - (i << 4) | i); - + snd_hda_sequence_write(codec, def_chan_map); hdmi_debug_channel_mapping(codec); } @@ -580,6 +597,7 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, + .nid = CVT_NID, /* NID to query formats and rates and setup streams */ .ops = { .open = intel_hdmi_playback_pcm_open, .close = intel_hdmi_playback_pcm_close, @@ -595,9 +613,6 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec) codec->num_pcms = 1; codec->pcm_info = info; - /* NID to query formats and rates and setup streams */ - intel_hdmi_pcm_playback.nid = cvt_nid; - info->name = "INTEL HDMI"; info->pcm_type = HDA_PCM_TYPE_HDMI; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; @@ -621,9 +636,8 @@ static int intel_hdmi_init(struct hda_codec *codec) { hdmi_enable_output(codec); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | INTEL_HDMI_EVENT_TAG); + snd_hda_sequence_write(codec, unsolicited_response_verb); + return 0; } @@ -643,7 +657,7 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { .unsol_event = intel_hdmi_unsol_event, }; -static int do_patch_intel_hdmi(struct hda_codec *codec) +static int patch_intel_hdmi(struct hda_codec *codec) { struct intel_hdmi_spec *spec; @@ -653,7 +667,7 @@ static int do_patch_intel_hdmi(struct hda_codec *codec) spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 8; - spec->multiout.dig_out_nid = cvt_nid; + spec->multiout.dig_out_nid = CVT_NID; codec->spec = spec; codec->patch_ops = intel_hdmi_patch_ops; @@ -665,27 +679,13 @@ static int do_patch_intel_hdmi(struct hda_codec *codec) return 0; } -static int patch_intel_hdmi(struct hda_codec *codec) -{ - cvt_nid = 0x02; - pin_nid = 0x03; - return do_patch_intel_hdmi(codec); -} - -static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec) -{ - cvt_nid = 0x02; - pin_nid = 0x04; - return do_patch_intel_hdmi(codec); -} - static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, - { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, + { .id = 0x80860054, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 7ff293458f6f..587d94f869be 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -258,14 +258,6 @@ enum { ALC_INIT_GPIO3, }; -struct alc_mic_route { - hda_nid_t pin; - unsigned char mux_idx; - unsigned char amix_idx; -}; - -#define MUX_IDX_UNDEF ((unsigned char)-1) - struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -279,13 +271,13 @@ struct alc_spec { */ unsigned int num_init_verbs; - char stream_name_analog[32]; /* analog PCM stream */ + char stream_name_analog[16]; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; struct hda_pcm_stream *stream_analog_capture; struct hda_pcm_stream *stream_analog_alt_playback; struct hda_pcm_stream *stream_analog_alt_capture; - char stream_name_digital[32]; /* digital PCM stream */ + char stream_name_digital[16]; /* digital PCM stream */ struct hda_pcm_stream *stream_digital_playback; struct hda_pcm_stream *stream_digital_capture; @@ -308,8 +300,6 @@ struct alc_spec { unsigned int num_mux_defs; const struct hda_input_mux *input_mux; unsigned int cur_mux[3]; - struct alc_mic_route ext_mic; - struct alc_mic_route int_mic; /* channel model */ const struct hda_channel_mode *channel_mode; @@ -337,7 +327,6 @@ struct alc_spec { unsigned int sense_updated: 1; unsigned int jack_present: 1; unsigned int master_sw: 1; - unsigned int auto_mic:1; /* other flags */ unsigned int no_analog :1; /* digital I/O only */ @@ -379,7 +368,6 @@ struct alc_config_preset { unsigned int num_mux_defs; const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); - void (*setup)(struct hda_codec *); void (*init_hook)(struct hda_codec *); #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_amp_list *loopbacks; @@ -569,7 +557,7 @@ static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, /* Find enumerated value for current pinctl setting */ i = alc_pin_mode_min(dir); - while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl) + while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir)) i++; *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir); return 0; @@ -852,10 +840,9 @@ static void print_realtek_coef(struct snd_info_buffer *buffer, /* * set up from the preset table */ -static void setup_preset(struct hda_codec *codec, +static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *preset) { - struct alc_spec *spec = codec->spec; int i; for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) @@ -897,9 +884,6 @@ static void setup_preset(struct hda_codec *codec, #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = preset->loopbacks; #endif - - if (preset->setup) - preset->setup(codec); } /* Enable GPIO mask and set output */ @@ -979,64 +963,30 @@ static void alc_automute_pin(struct hda_codec *codec) } } -static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t nid) -{ - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; - int i, nums; - - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) - if (conn[i] == nid) - return i; - return -1; -} - +#if 0 /* it's broken in some cases -- temporarily disabled */ static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct alc_mic_route *dead, *alive; - unsigned int present, type; - hda_nid_t cap_nid; - - if (!spec->auto_mic) - return; - if (!spec->int_mic.pin || !spec->ext_mic.pin) - return; - if (snd_BUG_ON(!spec->adc_nids)) - return; - - cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; - - present = snd_hda_codec_read(codec, spec->ext_mic.pin, 0, - AC_VERB_GET_PIN_SENSE, 0); - present &= AC_PINSENSE_PRESENCE; - if (present) { - alive = &spec->ext_mic; - dead = &spec->int_mic; - } else { - alive = &spec->int_mic; - dead = &spec->ext_mic; - } - - type = get_wcaps_type(get_wcaps(codec, cap_nid)); - if (type == AC_WID_AUD_MIX) { - /* Matrix-mixer style (e.g. ALC882) */ - snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, - alive->mux_idx, - HDA_AMP_MUTE, 0); - snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, - dead->mux_idx, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - /* MUX style (e.g. ALC880) */ - snd_hda_codec_write_cache(codec, cap_nid, 0, - AC_VERB_SET_CONNECT_SEL, - alive->mux_idx); - } - - /* FIXME: analog mixer */ + unsigned int present; + unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; + unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; + unsigned int mix_nid = spec->capsrc_nids[0]; + unsigned int capsrc_idx_mic, capsrc_idx_fmic; + + capsrc_idx_mic = mic_nid - 0x18; + capsrc_idx_fmic = fmic_nid - 0x18; + present = snd_hda_codec_read(codec, mic_nid, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0)); + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } +#else +#define alc_mic_automute(codec) do {} while(0) /* NOP */ +#endif /* disabled */ /* unsolicited event for HP jack sensing */ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) @@ -1192,55 +1142,6 @@ static void alc_init_auto_hp(struct hda_codec *codec) spec->unsol_event = alc_sku_unsol_event; } -static void alc_init_auto_mic(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t fixed, ext; - int i; - - /* there must be only two mic inputs exclusively */ - for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) - if (cfg->input_pins[i]) - return; - - fixed = ext = 0; - for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) { - hda_nid_t nid = cfg->input_pins[i]; - unsigned int defcfg; - if (!nid) - return; - defcfg = snd_hda_codec_get_pincfg(codec, nid); - switch (get_defcfg_connect(defcfg)) { - case AC_JACK_PORT_FIXED: - if (fixed) - return; /* already occupied */ - fixed = nid; - break; - case AC_JACK_PORT_COMPLEX: - if (ext) - return; /* already occupied */ - ext = nid; - break; - default: - return; /* invalid entry */ - } - } - if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) - return; /* no unsol support */ - snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n", - ext, fixed); - spec->ext_mic.pin = ext; - spec->int_mic.pin = fixed; - spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ - spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ - spec->auto_mic = 1; - snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC880_MIC_EVENT); - spec->unsol_event = alc_sku_unsol_event; -} - /* check subsystem ID and set up device-specific initialization; * return 1 if initialized, 0 if invalid SSID */ @@ -1342,7 +1243,6 @@ static int alc_subsystem_id(struct hda_codec *codec, } alc_init_auto_hp(codec); - alc_init_auto_mic(codec); return 1; } @@ -1355,7 +1255,6 @@ static void alc_ssid_check(struct hda_codec *codec, "Enable default setup for auto mode as fallback\n"); spec->init_amp = ALC_INIT_DEFAULT; alc_init_auto_hp(codec); - alc_init_auto_mic(codec); } } @@ -1537,7 +1436,7 @@ static void alc_automute_amp_unsol_event(struct hda_codec *codec, alc_automute_amp(codec); } -static void alc889_automute_setup(struct hda_codec *codec) +static void alc889_automute_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1547,15 +1446,16 @@ static void alc889_automute_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x17; spec->autocfg.speaker_pins[3] = 0x19; spec->autocfg.speaker_pins[4] = 0x1a; + alc_automute_amp(codec); } static void alc889_intel_init_hook(struct hda_codec *codec) { alc889_coef_init(codec); - alc_automute_amp(codec); + alc889_automute_init(codec); } -static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) +static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1563,6 +1463,7 @@ static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) spec->autocfg.hp_pins[1] = 0x1b; /* hp */ spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ spec->autocfg.speaker_pins[1] = 0x15; /* bass */ + alc_automute_amp(codec); } /* @@ -1761,15 +1662,16 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { { } /* end */ }; -static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) +static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } -static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) +static void alc888_acer_aspire_6530g_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1777,9 +1679,10 @@ static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; + alc_automute_amp(codec); } -static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) +static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1787,6 +1690,7 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x1b; + alc_automute_amp(codec); } /* @@ -2766,17 +2670,13 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } -static void alc880_uniwill_setup(struct hda_codec *codec) +static void alc880_uniwill_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x16; -} - -static void alc880_uniwill_init_hook(struct hda_codec *codec) -{ alc_automute_amp(codec); alc880_uniwill_mic_automute(codec); } @@ -2797,12 +2697,13 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, } } -static void alc880_uniwill_p53_setup(struct hda_codec *codec) +static void alc880_uniwill_p53_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + alc_automute_amp(codec); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -3065,12 +2966,13 @@ static struct hda_verb alc880_lg_init_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_setup(struct hda_codec *codec) +static void alc880_lg_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x17; + alc_automute_amp(codec); } /* @@ -3149,12 +3051,13 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_lw_setup(struct hda_codec *codec) +static void alc880_lg_lw_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { @@ -3220,12 +3123,13 @@ static void alc880_medion_rim_unsol_event(struct hda_codec *codec, alc880_medion_rim_automute(codec); } -static void alc880_medion_rim_setup(struct hda_codec *codec) +static void alc880_medion_rim_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; + alc880_medion_rim_automute(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -4092,8 +3996,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_f1734_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc880_uniwill_p53_init_hook, }, [ALC880_ASUS] = { .mixers = { alc880_asus_mixer }, @@ -4170,7 +4073,6 @@ static struct alc_config_preset alc880_presets[] = { .need_dac_fix = 1, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_unsol_event, - .setup = alc880_uniwill_setup, .init_hook = alc880_uniwill_init_hook, }, [ALC880_UNIWILL_P53] = { @@ -4183,8 +4085,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc880_uniwill_p53_init_hook, }, [ALC880_FUJITSU] = { .mixers = { alc880_fujitsu_mixer }, @@ -4198,8 +4099,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .setup = alc880_uniwill_p53_setup, - .init_hook = alc_automute_amp, + .init_hook = alc880_uniwill_p53_init_hook, }, [ALC880_CLEVO] = { .mixers = { alc880_three_stack_mixer }, @@ -4225,8 +4125,7 @@ static struct alc_config_preset alc880_presets[] = { .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc880_lg_setup, - .init_hook = alc_automute_amp, + .init_hook = alc880_lg_init_hook, #ifdef CONFIG_SND_HDA_POWER_SAVE .loopbacks = alc880_lg_loopbacks, #endif @@ -4242,8 +4141,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_lg_lw_modes, .input_mux = &alc880_lg_lw_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc880_lg_lw_setup, - .init_hook = alc_automute_amp, + .init_hook = alc880_lg_lw_init_hook, }, [ALC880_MEDION_RIM] = { .mixers = { alc880_medion_rim_mixer }, @@ -4257,8 +4155,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_medion_rim_capture_source, .unsol_event = alc880_medion_rim_unsol_event, - .setup = alc880_medion_rim_setup, - .init_hook = alc880_medion_rim_automute, + .init_hook = alc880_medion_rim_init_hook, }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { @@ -4663,42 +4560,8 @@ static void alc880_auto_init(struct hda_codec *codec) alc_inithook(codec); } -/* check the ADC/MUX contains all input pins; some ADC/MUX contains only - * one of two digital mic pins, e.g. on ALC272 - */ -static void fixup_automic_adc(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t cap = spec->capsrc_nids ? - spec->capsrc_nids[i] : spec->adc_nids[i]; - int iidx, eidx; - - iidx = get_connection_index(codec, cap, spec->int_mic.pin); - if (iidx < 0) - continue; - eidx = get_connection_index(codec, cap, spec->ext_mic.pin); - if (eidx < 0) - continue; - spec->int_mic.mux_idx = iidx; - spec->ext_mic.mux_idx = eidx; - if (spec->capsrc_nids) - spec->capsrc_nids += i; - spec->adc_nids += i; - spec->num_adc_nids = 1; - return; - } - snd_printd(KERN_INFO "hda_codec: %s: " - "No ADC/MUX containing both 0x%x and 0x%x pins\n", - codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin); - spec->auto_mic = 0; /* disable auto-mic to be sure */ -} - -static void set_capture_mixer(struct hda_codec *codec) +static void set_capture_mixer(struct alc_spec *spec) { - struct alc_spec *spec = codec->spec; static struct snd_kcontrol_new *caps[2][3] = { { alc_capture_mixer_nosrc1, alc_capture_mixer_nosrc2, @@ -4709,10 +4572,7 @@ static void set_capture_mixer(struct hda_codec *codec) }; if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { int mux; - if (spec->auto_mic) { - mux = 0; - fixup_automic_adc(codec); - } else if (spec->input_mux && spec->input_mux->num_items > 1) + if (spec->input_mux && spec->input_mux->num_items > 1) mux = 1; else mux = 0; @@ -4769,7 +4629,7 @@ static int patch_alc880(struct hda_codec *codec) } if (board_config != ALC880_AUTO) - setup_preset(codec, &alc880_presets[board_config]); + setup_preset(spec, &alc880_presets[board_config]); spec->stream_analog_playback = &alc880_pcm_analog_playback; spec->stream_analog_capture = &alc880_pcm_analog_capture; @@ -4791,7 +4651,7 @@ static int patch_alc880(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); } } - set_capture_mixer(codec); + set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -6413,7 +6273,7 @@ static int patch_alc260(struct hda_codec *codec) } if (board_config != ALC260_AUTO) - setup_preset(codec, &alc260_presets[board_config]); + setup_preset(spec, &alc260_presets[board_config]); spec->stream_analog_playback = &alc260_pcm_analog_playback; spec->stream_analog_capture = &alc260_pcm_analog_capture; @@ -6434,7 +6294,7 @@ static int patch_alc260(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); } } - set_capture_mixer(codec); + set_capture_mixer(spec); set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); spec->vmaster_nid = 0x08; @@ -7453,21 +7313,23 @@ static struct hda_verb alc885_imac24_init_verbs[] = { }; /* Toggle speaker-output according to the hp-jack state */ -static void alc885_imac24_setup(struct hda_codec *codec) +static void alc885_imac24_automute_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; spec->autocfg.speaker_pins[1] = 0x1a; + alc_automute_amp(codec); } -static void alc885_mbp3_setup(struct hda_codec *codec) +static void alc885_mbp3_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } @@ -7495,12 +7357,13 @@ static void alc882_targa_automute(struct hda_codec *codec) spec->jack_present ? 1 : 3); } -static void alc882_targa_setup(struct hda_codec *codec) +static void alc882_targa_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; + alc882_targa_automute(codec); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -7588,7 +7451,7 @@ static void alc885_macpro_init_hook(struct hda_codec *codec) static void alc885_imac24_init_hook(struct hda_codec *codec) { alc885_macpro_init_hook(codec); - alc_automute_amp(codec); + alc885_imac24_automute_init_hook(codec); } /* @@ -8078,13 +7941,14 @@ static struct snd_kcontrol_new alc883_chmode_mixer[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_mitac_setup(struct hda_codec *codec) +static void alc883_mitac_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; + alc_automute_amp(codec); } /* auto-toggle front mic */ @@ -8239,7 +8103,7 @@ static struct hda_verb alc883_vaiott_verbs[] = { { } /* end */ }; -static void alc888_3st_hp_setup(struct hda_codec *codec) +static void alc888_3st_hp_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8247,6 +8111,7 @@ static void alc888_3st_hp_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x18; + alc_automute_amp(codec); } static struct hda_verb alc888_3st_hp_verbs[] = { @@ -8343,12 +8208,13 @@ static struct hda_verb alc883_medion_md2_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_medion_md2_setup(struct hda_codec *codec) +static void alc883_medion_md2_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + alc_automute_amp(codec); } /* toggle speaker-output according to the hp-jack state */ @@ -8365,16 +8231,12 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc883_clevo_m720_setup(struct hda_codec *codec) +static void alc883_clevo_m720_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; -} - -static void alc883_clevo_m720_init_hook(struct hda_codec *codec) -{ alc_automute_amp(codec); alc883_clevo_m720_mic_automute(codec); } @@ -8393,20 +8255,22 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, } /* toggle speaker-output according to the hp-jack state */ -static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) +static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; + alc_automute_amp(codec); } -static void alc883_haier_w66_setup(struct hda_codec *codec) +static void alc883_haier_w66_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) @@ -8445,13 +8309,14 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, } /* toggle speaker-output according to the hp-jack state */ -static void alc883_acer_aspire_setup(struct hda_codec *codec) +static void alc883_acer_aspire_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[1] = 0x16; + alc_automute_amp(codec); } static struct hda_verb alc883_acer_eapd_verbs[] = { @@ -8472,7 +8337,7 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { { } }; -static void alc888_6st_dell_setup(struct hda_codec *codec) +static void alc888_6st_dell_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8481,9 +8346,10 @@ static void alc888_6st_dell_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[1] = 0x15; spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; + alc_automute_amp(codec); } -static void alc888_lenovo_sky_setup(struct hda_codec *codec) +static void alc888_lenovo_sky_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8493,15 +8359,17 @@ static void alc888_lenovo_sky_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; spec->autocfg.speaker_pins[4] = 0x1a; + alc_automute_amp(codec); } -static void alc883_vaiott_setup(struct hda_codec *codec) +static void alc883_vaiott_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; + alc_automute_amp(codec); } static struct hda_verb alc888_asus_m90v_verbs[] = { @@ -8514,7 +8382,19 @@ static struct hda_verb alc888_asus_m90v_verbs[] = { { } /* end */ }; -static void alc883_mode2_setup(struct hda_codec *codec) +static void alc883_nb_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); +} + +static void alc883_M90V_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8522,11 +8402,26 @@ static void alc883_mode2_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x15; spec->autocfg.speaker_pins[2] = 0x16; - spec->ext_mic.pin = 0x18; - spec->int_mic.pin = 0x19; - spec->ext_mic.mux_idx = 0; - spec->int_mic.mux_idx = 1; - spec->auto_mic = 1; + alc_automute_pin(codec); +} + +static void alc883_mode2_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_MIC_EVENT: + alc883_nb_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } +} + +static void alc883_mode2_inithook(struct hda_codec *codec) +{ + alc883_M90V_init_hook(codec); + alc883_nb_mic_automute(codec); } static struct hda_verb alc888_asus_eee1601_verbs[] = { @@ -8857,8 +8752,7 @@ static struct alc_config_preset alc882_presets[] = { .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc885_mbp3_setup, - .init_hook = alc_automute_amp, + .init_hook = alc885_mbp3_init_hook, }, [ALC885_MB5] = { .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, @@ -8895,7 +8789,6 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc885_imac24_setup, .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { @@ -8913,8 +8806,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc882_capture_source, .unsol_event = alc882_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, + .init_hook = alc882_targa_init_hook, }, [ALC882_ASUS_A7J] = { .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, @@ -9005,8 +8897,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc889_8ch_intel_modes, .capsrc_nids = alc889_capsrc_nids, .input_mux = &alc889_capture_source, - .setup = alc889_automute_setup, - .init_hook = alc_automute_amp, + .init_hook = alc889_automute_init, .unsol_event = alc_automute_amp_unsol_event, .need_dac_fix = 1, }, @@ -9025,7 +8916,6 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc889_8ch_intel_modes, .capsrc_nids = alc889_capsrc_nids, .input_mux = &alc889_capture_source, - .setup = alc889_automute_setup, .init_hook = alc889_intel_init_hook, .unsol_event = alc_automute_amp_unsol_event, .need_dac_fix = 1, @@ -9053,8 +8943,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_capture_source, .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, + .init_hook = alc883_targa_init_hook, }, [ALC883_TARGA_2ch_DIG] = { .mixers = { alc883_targa_2ch_mixer}, @@ -9069,8 +8958,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, + .init_hook = alc883_targa_init_hook, }, [ALC883_TARGA_8ch_DIG] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -9088,8 +8976,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_capture_source, .unsol_event = alc883_targa_unsol_event, - .setup = alc882_targa_setup, - .init_hook = alc882_targa_automute, + .init_hook = alc883_targa_init_hook, }, [ALC883_ACER] = { .mixers = { alc883_base_mixer }, @@ -9115,8 +9002,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_acer_aspire_setup, - .init_hook = alc_automute_amp, + .init_hook = alc883_acer_aspire_init_hook, }, [ALC888_ACER_ASPIRE_4930G] = { .mixers = { alc888_base_mixer, @@ -9136,8 +9022,7 @@ static struct alc_config_preset alc882_presets[] = { ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc888_acer_aspire_4930g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc888_acer_aspire_4930g_init_hook, }, [ALC888_ACER_ASPIRE_6530G] = { .mixers = { alc888_acer_aspire_6530_mixer }, @@ -9155,8 +9040,7 @@ static struct alc_config_preset alc882_presets[] = { ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_acer_aspire_6530_sources, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc888_acer_aspire_6530g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc888_acer_aspire_6530g_init_hook, }, [ALC888_ACER_ASPIRE_8930G] = { .mixers = { alc888_base_mixer, @@ -9177,8 +9061,7 @@ static struct alc_config_preset alc882_presets[] = { ARRAY_SIZE(alc889_capture_sources), .input_mux = alc889_capture_sources, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc889_acer_aspire_8930g_setup, - .init_hook = alc_automute_amp, + .init_hook = alc889_acer_aspire_8930g_init_hook, }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, @@ -9203,8 +9086,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_medion_md2_setup, - .init_hook = alc_automute_amp, + .init_hook = alc883_medion_md2_init_hook, }, [ALC883_LAPTOP_EAPD] = { .mixers = { alc883_base_mixer }, @@ -9225,7 +9107,6 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc883_clevo_m720_unsol_event, - .setup = alc883_clevo_m720_setup, .init_hook = alc883_clevo_m720_init_hook, }, [ALC883_LENOVO_101E_2ch] = { @@ -9251,8 +9132,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_lenovo_nb0763_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_medion_md2_setup, - .init_hook = alc_automute_amp, + .init_hook = alc883_medion_md2_init_hook, }, [ALC888_LENOVO_MS7195_DIG] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9277,8 +9157,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_haier_w66_setup, - .init_hook = alc_automute_amp, + .init_hook = alc883_haier_w66_init_hook, }, [ALC888_3ST_HP] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9290,8 +9169,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc888_3st_hp_setup, - .init_hook = alc_automute_amp, + .init_hook = alc888_3st_hp_init_hook, }, [ALC888_6ST_DELL] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -9304,8 +9182,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc888_6st_dell_setup, - .init_hook = alc_automute_amp, + .init_hook = alc888_6st_dell_init_hook, }, [ALC883_MITAC] = { .mixers = { alc883_mitac_mixer }, @@ -9316,8 +9193,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_mitac_setup, - .init_hook = alc_automute_amp, + .init_hook = alc883_mitac_init_hook, }, [ALC883_FUJITSU_PI2515] = { .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, @@ -9330,8 +9206,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_fujitsu_pi2515_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_2ch_fujitsu_pi2515_setup, - .init_hook = alc_automute_amp, + .init_hook = alc883_2ch_fujitsu_pi2515_init_hook, }, [ALC888_FUJITSU_XA3530] = { .mixers = { alc888_base_mixer, alc883_chmode_mixer }, @@ -9349,8 +9224,7 @@ static struct alc_config_preset alc882_presets[] = { ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc888_fujitsu_xa3530_setup, - .init_hook = alc_automute_amp, + .init_hook = alc888_fujitsu_xa3530_init_hook, }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, @@ -9363,8 +9237,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_lenovo_sky_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc888_lenovo_sky_setup, - .init_hook = alc_automute_amp, + .init_hook = alc888_lenovo_sky_init_hook, }, [ALC888_ASUS_M90V] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9377,9 +9250,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_6ch_modes, .need_dac_fix = 1, .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc883_mode2_setup, - .init_hook = alc_inithook, + .unsol_event = alc883_mode2_unsol_event, + .init_hook = alc883_mode2_inithook, }, [ALC888_ASUS_EEE1601] = { .mixers = { alc883_asus_eee1601_mixer }, @@ -9432,8 +9304,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc883_vaiott_setup, - .init_hook = alc_automute_amp, + .init_hook = alc883_vaiott_init_hook, }, }; @@ -9716,7 +9587,7 @@ static int patch_alc882(struct hda_codec *codec) } if (board_config != ALC882_AUTO) - setup_preset(codec, &alc882_presets[board_config]); + setup_preset(spec, &alc882_presets[board_config]); spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; @@ -9752,7 +9623,7 @@ static int patch_alc882(struct hda_codec *codec) spec->capsrc_nids = spec->private_capsrc_nids; } - set_capture_mixer(codec); + set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -9945,12 +9816,13 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hp_t5735_setup(struct hda_codec *codec) +static void alc262_hp_t5735_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */ + alc_automute_amp(codec); } static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { @@ -10107,20 +9979,22 @@ static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res) alc262_hippo_automute(codec); } -static void alc262_hippo_setup(struct hda_codec *codec) +static void alc262_hippo_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + alc262_hippo_automute(codec); } -static void alc262_hippo1_setup(struct hda_codec *codec) +static void alc262_hippo1_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; + alc262_hippo_automute(codec); } @@ -10177,12 +10051,13 @@ static struct hda_verb alc262_tyan_verbs[] = { }; /* unsolicited event for HP jack sensing */ -static void alc262_tyan_setup(struct hda_codec *codec) +static void alc262_tyan_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x15; + alc_automute_amp(codec); } @@ -10294,6 +10169,14 @@ static struct hda_verb alc262_sony_unsol_verbs[] = { {} }; +static struct hda_input_mux alc262_dmic_capture_source = { + .num_items = 2, + .items = { + { "Int DMic", 0x9 }, + { "Mic", 0x0 }, + }, +}; + static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -10315,17 +10198,35 @@ static struct hda_verb alc262_toshiba_s06_verbs[] = { {} }; -static void alc262_toshiba_s06_setup(struct hda_codec *codec) +static void alc262_dmic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x22, 0, + AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09); +} + + +/* unsolicited event for HP jack sensing */ +static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_MIC_EVENT) + alc262_dmic_automute(codec); + else + alc_sku_unsol_event(codec, res); +} + +static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x12; - spec->int_mic.mux_idx = 9; - spec->auto_mic = 1; + alc_automute_pin(codec); + alc262_dmic_automute(codec); } /* @@ -11298,8 +11199,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo_init_hook, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -11312,8 +11212,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .setup = alc262_hippo1_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo1_init_hook, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -11376,8 +11275,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc262_hp_t5735_setup, - .init_hook = alc_automute_amp, + .init_hook = alc262_hp_t5735_init_hook, }, [ALC262_HP_RP5700] = { .mixers = { alc262_hp_rp5700_mixer }, @@ -11408,8 +11306,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo_init_hook, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -11422,8 +11319,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo_init_hook, }, [ALC262_ULTRA] = { .mixers = { alc262_ultra_mixer }, @@ -11475,9 +11371,9 @@ static struct alc_config_preset alc262_presets[] = { .dig_out_nid = ALC262_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, - .unsol_event = alc_sku_unsol_event, - .setup = alc262_toshiba_s06_setup, - .init_hook = alc_inithook, + .input_mux = &alc262_dmic_capture_source, + .unsol_event = alc262_toshiba_s06_unsol_event, + .init_hook = alc262_toshiba_s06_init_hook, }, [ALC262_TOSHIBA_RX1] = { .mixers = { alc262_toshiba_rx1_mixer }, @@ -11489,8 +11385,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .setup = alc262_hippo_setup, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo_init_hook, }, [ALC262_TYAN] = { .mixers = { alc262_tyan_mixer }, @@ -11503,8 +11398,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc262_tyan_setup, - .init_hook = alc_automute_amp, + .init_hook = alc262_tyan_init_hook, }, }; @@ -11567,7 +11461,7 @@ static int patch_alc262(struct hda_codec *codec) } if (board_config != ALC262_AUTO) - setup_preset(codec, &alc262_presets[board_config]); + setup_preset(spec, &alc262_presets[board_config]); spec->stream_analog_playback = &alc262_pcm_analog_playback; spec->stream_analog_capture = &alc262_pcm_analog_capture; @@ -11608,7 +11502,7 @@ static int patch_alc262(struct hda_codec *codec) } } if (!spec->cap_mixer && !spec->no_analog) - set_capture_mixer(codec); + set_capture_mixer(spec); if (!spec->no_analog) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -11700,6 +11594,14 @@ static struct hda_verb alc268_toshiba_verbs[] = { { } /* end */ }; +static struct hda_input_mux alc268_acer_lc_capture_source = { + .num_items = 2, + .items = { + { "i-Mic", 0x6 }, + { "E-Mic", 0x0 }, + }, +}; + /* Acer specific */ /* bind volumes of both NID 0x02 and 0x03 */ static struct hda_bind_ctls alc268_acer_bind_master_vol = { @@ -11818,8 +11720,7 @@ static struct hda_verb alc268_acer_verbs[] = { /* unsolicited event for HP jack sensing */ #define alc268_toshiba_unsol_event alc262_hippo_unsol_event -#define alc268_toshiba_setup alc262_hippo_setup -#define alc268_toshiba_automute alc262_hippo_automute +#define alc268_toshiba_init_hook alc262_hippo_init_hook static void alc268_acer_unsol_event(struct hda_codec *codec, unsigned int res) @@ -11849,33 +11750,30 @@ static void alc268_aspire_one_speaker_automute(struct hda_codec *codec) AMP_IN_MUTE(0), bits); } -static void alc268_acer_lc_unsol_event(struct hda_codec *codec, - unsigned int res) + +static void alc268_acer_mic_automute(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc268_aspire_one_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL, + present ? 0x0 : 0x6); } -static void alc268_acer_lc_setup(struct hda_codec *codec) +static void alc268_acer_lc_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x12; - spec->int_mic.mux_idx = 6; - spec->auto_mic = 1; + if ((res >> 26) == ALC880_HP_EVENT) + alc268_aspire_one_speaker_automute(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc268_acer_mic_automute(codec); } static void alc268_acer_lc_init_hook(struct hda_codec *codec) { alc268_aspire_one_speaker_automute(codec); - alc_mic_automute(codec); + alc268_acer_mic_automute(codec); } static struct snd_kcontrol_new alc268_dell_mixer[] = { @@ -11893,22 +11791,17 @@ static struct hda_verb alc268_dell_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, { } }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_dell_setup(struct hda_codec *codec) +static void alc268_dell_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x19; - spec->int_mic.mux_idx = 1; - spec->auto_mic = 1; + alc_automute_pin(codec); } static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { @@ -11929,16 +11822,38 @@ static struct hda_verb alc267_quanta_il1_verbs[] = { { } }; -static void alc267_quanta_il1_setup(struct hda_codec *codec) +static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, + present ? 0x00 : 0x01); +} + +static void alc267_quanta_il1_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x19; - spec->int_mic.mux_idx = 1; - spec->auto_mic = 1; + alc_automute_pin(codec); + alc267_quanta_il1_mic_automute(codec); +} + +static void alc267_quanta_il1_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_MIC_EVENT: + alc267_quanta_il1_mic_automute(codec); + break; + default: + alc_sku_unsol_event(codec, res); + break; + } } /* @@ -12232,40 +12147,32 @@ static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { struct hda_input_mux *imux = &spec->private_imux[0]; - int i, idx1, dmic_nid; - - dmic_nid = 0x12; - while (dmic_nid <= 0x13) { - for (i = 0; i < AUTO_PIN_LAST; i++) { - switch (cfg->input_pins[i]) { - case 0x18: - idx1 = 0; /* Mic 1 */ - break; - case 0x19: - idx1 = 1; /* Mic 2 */ - break; - case 0x1a: - idx1 = 2; /* Line In */ - break; - case 0x1c: - idx1 = 3; /* CD */ - break; - case 0x12: - case 0x13: - if (cfg->input_pins[i] != dmic_nid) - continue; - idx1 = 6; /* digital mics */ - break; - default: - continue; - } - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx1; - imux->num_items++; + int i, idx1; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + switch(cfg->input_pins[i]) { + case 0x18: + idx1 = 0; /* Mic 1 */ + break; + case 0x19: + idx1 = 1; /* Mic 2 */ + break; + case 0x1a: + idx1 = 2; /* Line In */ + break; + case 0x1c: + idx1 = 3; /* CD */ + break; + case 0x12: + case 0x13: + idx1 = 6; /* digital mics */ + break; + default: + continue; } - imux++; - dmic_nid++; + imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; + imux->items[imux->num_items].index = idx1; + imux->num_items++; } return 0; } @@ -12363,7 +12270,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) add_mixer(spec, alc268_beep_mixer); add_verb(spec, alc268_volume_init_verbs); - spec->num_mux_defs = 2; + spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; err = alc_auto_add_mic_boost(codec); @@ -12445,9 +12352,8 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, - .unsol_event = alc_sku_unsol_event, - .setup = alc267_quanta_il1_setup, - .init_hook = alc_inithook, + .unsol_event = alc267_quanta_il1_unsol_event, + .init_hook = alc267_quanta_il1_init_hook, }, [ALC268_3ST] = { .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, @@ -12479,8 +12385,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_toshiba_unsol_event, - .setup = alc268_toshiba_setup, - .init_hook = alc268_toshiba_automute, + .init_hook = alc268_toshiba_init_hook, }, [ALC268_ACER] = { .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, @@ -12530,8 +12435,8 @@ static struct alc_config_preset alc268_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, + .input_mux = &alc268_acer_lc_capture_source, .unsol_event = alc268_acer_lc_unsol_event, - .setup = alc268_acer_lc_setup, .init_hook = alc268_acer_lc_init_hook, }, [ALC268_DELL] = { @@ -12544,8 +12449,8 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .unsol_event = alc_sku_unsol_event, - .setup = alc268_dell_setup, - .init_hook = alc_inithook, + .init_hook = alc268_dell_init_hook, + .input_mux = &alc268_capture_source, }, [ALC268_ZEPTO] = { .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, @@ -12562,8 +12467,8 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, - .setup = alc268_toshiba_setup, - .init_hook = alc268_toshiba_automute, + .unsol_event = alc268_toshiba_unsol_event, + .init_hook = alc268_toshiba_init_hook }, #ifdef CONFIG_SND_DEBUG [ALC268_TEST] = { @@ -12621,7 +12526,7 @@ static int patch_alc268(struct hda_codec *codec) } if (board_config != ALC268_AUTO) - setup_preset(codec, &alc268_presets[board_config]); + setup_preset(spec, &alc268_presets[board_config]); spec->stream_analog_playback = &alc268_pcm_analog_playback; spec->stream_analog_capture = &alc268_pcm_analog_capture; @@ -12673,8 +12578,6 @@ static int patch_alc268(struct hda_codec *codec) for (i = 0; i < spec->num_adc_nids; i++) snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i], 0, AC_VERB_SET_CONNECT_SEL, - i < spec->num_mux_defs ? - spec->input_mux[i].items[0].index : spec->input_mux->items[0].index); } @@ -12709,6 +12612,22 @@ static hda_nid_t alc269_capsrc_nids[1] = { * not a mux! */ +static struct hda_input_mux alc269_eeepc_dmic_capture_source = { + .num_items = 2, + .items = { + { "i-Mic", 0x5 }, + { "e-Mic", 0x0 }, + }, +}; + +static struct hda_input_mux alc269_eeepc_amic_capture_source = { + .num_items = 2, + .items = { + { "i-Mic", 0x1 }, + { "e-Mic", 0x0 }, + }, +}; + #define alc269_modes alc260_modes #define alc269_capture_source alc880_lg_lw_capture_source @@ -12870,6 +12789,16 @@ static void alc269_lifebook_speaker_automute(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x480); } +static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1); +} + static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) { unsigned int present_laptop; @@ -12896,14 +12825,10 @@ static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, unsigned int res) { - switch (res >> 26) { - case ALC880_HP_EVENT: + if ((res >> 26) == ALC880_HP_EVENT) alc269_quanta_fl1_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + if ((res >> 26) == ALC880_MIC_EVENT) + alc269_quanta_fl1_mic_automute(codec); } static void alc269_lifebook_unsol_event(struct hda_codec *codec, @@ -12915,20 +12840,10 @@ static void alc269_lifebook_unsol_event(struct hda_codec *codec, alc269_lifebook_mic_autoswitch(codec); } -static void alc269_quanta_fl1_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x19; - spec->int_mic.mux_idx = 1; - spec->auto_mic = 1; -} - static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) { alc269_quanta_fl1_speaker_automute(codec); - alc_mic_automute(codec); + alc269_quanta_fl1_mic_automute(codec); } static void alc269_lifebook_init_hook(struct hda_codec *codec) @@ -12973,44 +12888,60 @@ static void alc269_speaker_automute(struct hda_codec *codec) AMP_IN_MUTE(0), bits); } +static void alc269_eeepc_dmic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5)); +} + +static void alc269_eeepc_amic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); +} + /* unsolicited event for HP jack sensing */ -static void alc269_eeepc_unsol_event(struct hda_codec *codec, +static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec, unsigned int res) { - switch (res >> 26) { - case ALC880_HP_EVENT: + if ((res >> 26) == ALC880_HP_EVENT) alc269_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc_mic_automute(codec); - break; - } + + if ((res >> 26) == ALC880_MIC_EVENT) + alc269_eeepc_dmic_automute(codec); } -static void alc269_eeepc_dmic_setup(struct hda_codec *codec) +static void alc269_eeepc_dmic_inithook(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x12; - spec->int_mic.mux_idx = 5; - spec->auto_mic = 1; + alc269_speaker_automute(codec); + alc269_eeepc_dmic_automute(codec); } -static void alc269_eeepc_amic_setup(struct hda_codec *codec) +/* unsolicited event for HP jack sensing */ +static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x19; - spec->int_mic.mux_idx = 1; - spec->auto_mic = 1; + if ((res >> 26) == ALC880_HP_EVENT) + alc269_speaker_automute(codec); + + if ((res >> 26) == ALC880_MIC_EVENT) + alc269_eeepc_amic_automute(codec); } -static void alc269_eeepc_inithook(struct hda_codec *codec) +static void alc269_eeepc_amic_inithook(struct hda_codec *codec) { alc269_speaker_automute(codec); - alc_mic_automute(codec); + alc269_eeepc_amic_automute(codec); } /* @@ -13240,7 +13171,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) return err; if (!spec->cap_mixer && !spec->no_analog) - set_capture_mixer(codec); + set_capture_mixer(spec); alc_ssid_check(codec, 0x15, 0x1b, 0x14); @@ -13316,7 +13247,6 @@ static struct alc_config_preset alc269_presets[] = { .channel_mode = alc269_modes, .input_mux = &alc269_capture_source, .unsol_event = alc269_quanta_fl1_unsol_event, - .setup = alc269_quanta_fl1_setup, .init_hook = alc269_quanta_fl1_init_hook, }, [ALC269_ASUS_EEEPC_P703] = { @@ -13329,9 +13259,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_eeepc_unsol_event, - .setup = alc269_eeepc_amic_setup, - .init_hook = alc269_eeepc_inithook, + .input_mux = &alc269_eeepc_amic_capture_source, + .unsol_event = alc269_eeepc_amic_unsol_event, + .init_hook = alc269_eeepc_amic_inithook, }, [ALC269_ASUS_EEEPC_P901] = { .mixers = { alc269_eeepc_mixer }, @@ -13343,9 +13273,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_eeepc_unsol_event, - .setup = alc269_eeepc_dmic_setup, - .init_hook = alc269_eeepc_inithook, + .input_mux = &alc269_eeepc_dmic_capture_source, + .unsol_event = alc269_eeepc_dmic_unsol_event, + .init_hook = alc269_eeepc_dmic_inithook, }, [ALC269_FUJITSU] = { .mixers = { alc269_fujitsu_mixer }, @@ -13357,9 +13287,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .unsol_event = alc269_eeepc_unsol_event, - .setup = alc269_eeepc_dmic_setup, - .init_hook = alc269_eeepc_inithook, + .input_mux = &alc269_eeepc_dmic_capture_source, + .unsol_event = alc269_eeepc_dmic_unsol_event, + .init_hook = alc269_eeepc_dmic_inithook, }, [ALC269_LIFEBOOK] = { .mixers = { alc269_lifebook_mixer }, @@ -13420,7 +13350,7 @@ static int patch_alc269(struct hda_codec *codec) } if (board_config != ALC269_AUTO) - setup_preset(codec, &alc269_presets[board_config]); + setup_preset(spec, &alc269_presets[board_config]); if (codec->subsystem_id == 0x17aa3bf8) { /* Due to a hardware problem on Lenovo Ideadpad, we need to @@ -13439,11 +13369,9 @@ static int patch_alc269(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); spec->capsrc_nids = alc269_capsrc_nids; if (!spec->cap_mixer) - set_capture_mixer(codec); + set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); - spec->vmaster_nid = 0x02; - codec->patch_ops = alc_patch_ops; if (board_config == ALC269_AUTO) spec->init_hook = alc269_auto_init; @@ -14354,7 +14282,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->adc_nids = alc861_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); - set_capture_mixer(codec); + set_capture_mixer(spec); alc_ssid_check(codec, 0x0e, 0x0f, 0x0b); @@ -14573,7 +14501,7 @@ static int patch_alc861(struct hda_codec *codec) } if (board_config != ALC861_AUTO) - setup_preset(codec, &alc861_presets[board_config]); + setup_preset(spec, &alc861_presets[board_config]); spec->stream_analog_playback = &alc861_pcm_analog_playback; spec->stream_analog_capture = &alc861_pcm_analog_capture; @@ -14976,15 +14904,12 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, bits); } -static void alc861vd_lenovo_setup(struct hda_codec *codec) +static void alc861vd_lenovo_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; -} - -static void alc861vd_lenovo_init_hook(struct hda_codec *codec) -{ alc_automute_amp(codec); alc861vd_lenovo_mic_automute(codec); } @@ -15048,12 +14973,13 @@ static struct hda_verb alc861vd_dallas_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc861vd_dallas_setup(struct hda_codec *codec) +static void alc861vd_dallas_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -15092,7 +15018,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ - SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS), SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), @@ -15167,7 +15093,6 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, - .setup = alc861vd_lenovo_setup, .init_hook = alc861vd_lenovo_init_hook, }, [ALC861VD_DALLAS] = { @@ -15179,8 +15104,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_dallas_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc861vd_dallas_setup, - .init_hook = alc_automute_amp, + .init_hook = alc861vd_dallas_init_hook, }, [ALC861VD_HP] = { .mixers = { alc861vd_hp_mixer }, @@ -15192,8 +15116,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_hp_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc861vd_dallas_setup, - .init_hook = alc_automute_amp, + .init_hook = alc861vd_dallas_init_hook, }, [ALC660VD_ASUS_V1S] = { .mixers = { alc861vd_lenovo_mixer }, @@ -15208,7 +15131,6 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, - .setup = alc861vd_lenovo_setup, .init_hook = alc861vd_lenovo_init_hook, }, }; @@ -15503,7 +15425,7 @@ static int patch_alc861vd(struct hda_codec *codec) } if (board_config != ALC861VD_AUTO) - setup_preset(codec, &alc861vd_presets[board_config]); + setup_preset(spec, &alc861vd_presets[board_config]); if (codec->vendor_id == 0x10ec0660) { /* always turn on EAPD */ @@ -15516,14 +15438,11 @@ static int patch_alc861vd(struct hda_codec *codec) spec->stream_digital_playback = &alc861vd_pcm_digital_playback; spec->stream_digital_capture = &alc861vd_pcm_digital_capture; - if (!spec->adc_nids) { - spec->adc_nids = alc861vd_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); - } - if (!spec->capsrc_nids) - spec->capsrc_nids = alc861vd_capsrc_nids; + spec->adc_nids = alc861vd_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); + spec->capsrc_nids = alc861vd_capsrc_nids; - set_capture_mixer(codec); + set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x02; @@ -15564,9 +15483,9 @@ static hda_nid_t alc272_dac_nids[2] = { 0x02, 0x03 }; -static hda_nid_t alc662_adc_nids[2] = { +static hda_nid_t alc662_adc_nids[1] = { /* ADC1-2 */ - 0x09, 0x08 + 0x09, }; static hda_nid_t alc272_adc_nids[1] = { @@ -15574,7 +15493,7 @@ static hda_nid_t alc272_adc_nids[1] = { 0x08, }; -static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; +static hda_nid_t alc662_capsrc_nids[1] = { 0x22 }; static hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; @@ -15598,6 +15517,14 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = { }, }; +static struct hda_input_mux alc662_eeepc_capture_source = { + .num_items = 2, + .items = { + { "i-Mic", 0x1 }, + { "e-Mic", 0x0 }, + }, +}; + static struct hda_input_mux alc663_capture_source = { .num_items = 3, .items = { @@ -15607,7 +15534,23 @@ static struct hda_input_mux alc663_capture_source = { }, }; -#if 0 /* set to 1 for testing other input sources below */ +static struct hda_input_mux alc663_m51va_capture_source = { + .num_items = 2, + .items = { + { "Ext-Mic", 0x0 }, + { "D-Mic", 0x9 }, + }, +}; + +#if 1 /* set to 0 for testing other input sources below */ +static struct hda_input_mux alc272_nc10_capture_source = { + .num_items = 2, + .items = { + { "Autoselect Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; +#else static struct hda_input_mux alc272_nc10_capture_source = { .num_items = 16, .items = { @@ -16276,44 +16219,47 @@ static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, alc662_lenovo_101e_ispeaker_automute(codec); } +static void alc662_eeepc_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); +} + /* unsolicited event for HP jack sensing */ static void alc662_eeepc_unsol_event(struct hda_codec *codec, unsigned int res) { if ((res >> 26) == ALC880_MIC_EVENT) - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); else alc262_hippo_unsol_event(codec, res); } -static void alc662_eeepc_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - alc262_hippo1_setup(codec); - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x19; - spec->int_mic.mux_idx = 1; - spec->auto_mic = 1; -} - static void alc662_eeepc_inithook(struct hda_codec *codec) { - alc262_hippo_automute(codec); - alc_mic_automute(codec); + alc262_hippo1_init_hook(codec); + alc662_eeepc_mic_automute(codec); } -static void alc662_eeepc_ep20_setup(struct hda_codec *codec) +static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; + alc262_hippo_master_update(codec); } -#define alc662_eeepc_ep20_inithook alc262_hippo_master_update - static void alc663_m51va_speaker_automute(struct hda_codec *codec) { unsigned int present; @@ -16424,6 +16370,23 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) } } +static void alc663_m51va_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); + snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); +} + static void alc663_m51va_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -16432,32 +16395,36 @@ static void alc663_m51va_unsol_event(struct hda_codec *codec, alc663_m51va_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc_mic_automute(codec); + alc663_m51va_mic_automute(codec); break; } } -static void alc663_m51va_setup(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - spec->ext_mic.pin = 0x18; - spec->ext_mic.mux_idx = 0; - spec->int_mic.pin = 0x12; - spec->int_mic.mux_idx = 1; - spec->auto_mic = 1; -} - static void alc663_m51va_inithook(struct hda_codec *codec) { alc663_m51va_speaker_automute(codec); - alc_mic_automute(codec); + alc663_m51va_mic_automute(codec); } /* ***************** Mode1 ******************************/ -#define alc663_mode1_unsol_event alc663_m51va_unsol_event -#define alc663_mode1_setup alc663_m51va_setup -#define alc663_mode1_inithook alc663_m51va_inithook +static void alc663_mode1_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc663_m51va_speaker_automute(codec); + break; + case ALC880_MIC_EVENT: + alc662_eeepc_mic_automute(codec); + break; + } +} +static void alc663_mode1_inithook(struct hda_codec *codec) +{ + alc663_m51va_speaker_automute(codec); + alc662_eeepc_mic_automute(codec); +} /* ***************** Mode2 ******************************/ static void alc662_mode2_unsol_event(struct hda_codec *codec, unsigned int res) @@ -16467,17 +16434,15 @@ static void alc662_mode2_unsol_event(struct hda_codec *codec, alc662_f5z_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); break; } } -#define alc662_mode2_setup alc663_m51va_setup - static void alc662_mode2_inithook(struct hda_codec *codec) { alc662_f5z_speaker_automute(codec); - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); } /* ***************** Mode3 ******************************/ static void alc663_mode3_unsol_event(struct hda_codec *codec, @@ -16488,17 +16453,15 @@ static void alc663_mode3_unsol_event(struct hda_codec *codec, alc663_two_hp_m1_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); break; } } -#define alc663_mode3_setup alc663_m51va_setup - static void alc663_mode3_inithook(struct hda_codec *codec) { alc663_two_hp_m1_speaker_automute(codec); - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); } /* ***************** Mode4 ******************************/ static void alc663_mode4_unsol_event(struct hda_codec *codec, @@ -16509,17 +16472,15 @@ static void alc663_mode4_unsol_event(struct hda_codec *codec, alc663_21jd_two_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); break; } } -#define alc663_mode4_setup alc663_m51va_setup - static void alc663_mode4_inithook(struct hda_codec *codec) { alc663_21jd_two_speaker_automute(codec); - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); } /* ***************** Mode5 ******************************/ static void alc663_mode5_unsol_event(struct hda_codec *codec, @@ -16530,17 +16491,15 @@ static void alc663_mode5_unsol_event(struct hda_codec *codec, alc663_15jd_two_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); break; } } -#define alc663_mode5_setup alc663_m51va_setup - static void alc663_mode5_inithook(struct hda_codec *codec) { alc663_15jd_two_speaker_automute(codec); - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); } /* ***************** Mode6 ******************************/ static void alc663_mode6_unsol_event(struct hda_codec *codec, @@ -16551,17 +16510,15 @@ static void alc663_mode6_unsol_event(struct hda_codec *codec, alc663_two_hp_m2_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); break; } } -#define alc663_mode6_setup alc663_m51va_setup - static void alc663_mode6_inithook(struct hda_codec *codec) { alc663_two_hp_m2_speaker_automute(codec); - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); } static void alc663_g71v_hp_automute(struct hda_codec *codec) @@ -16603,18 +16560,16 @@ static void alc663_g71v_unsol_event(struct hda_codec *codec, alc663_g71v_front_automute(codec); break; case ALC880_MIC_EVENT: - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); break; } } -#define alc663_g71v_setup alc663_m51va_setup - static void alc663_g71v_inithook(struct hda_codec *codec) { alc663_g71v_front_automute(codec); alc663_g71v_hp_automute(codec); - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); } static void alc663_g50v_unsol_event(struct hda_codec *codec, @@ -16625,17 +16580,15 @@ static void alc663_g50v_unsol_event(struct hda_codec *codec, alc663_m51va_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); break; } } -#define alc663_g50v_setup alc663_m51va_setup - static void alc663_g50v_inithook(struct hda_codec *codec) { alc663_m51va_speaker_automute(codec); - alc_mic_automute(codec); + alc662_eeepc_mic_automute(codec); } static struct snd_kcontrol_new alc662_ecs_mixer[] = { @@ -16839,8 +16792,8 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc662_eeepc_unsol_event, - .setup = alc662_eeepc_setup, .init_hook = alc662_eeepc_inithook, }, [ALC662_ASUS_EEEPC_EP20] = { @@ -16854,7 +16807,6 @@ static struct alc_config_preset alc662_presets[] = { .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, .unsol_event = alc662_eeepc_unsol_event, - .setup = alc662_eeepc_ep20_setup, .init_hook = alc662_eeepc_ep20_inithook, }, [ALC662_ECS] = { @@ -16865,8 +16817,8 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc662_eeepc_unsol_event, - .setup = alc662_eeepc_setup, .init_hook = alc662_eeepc_inithook, }, [ALC663_ASUS_M51VA] = { @@ -16877,8 +16829,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc663_m51va_capture_source, .unsol_event = alc663_m51va_unsol_event, - .setup = alc663_m51va_setup, .init_hook = alc663_m51va_inithook, }, [ALC663_ASUS_G71V] = { @@ -16889,8 +16841,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_g71v_unsol_event, - .setup = alc663_g71v_setup, .init_hook = alc663_g71v_inithook, }, [ALC663_ASUS_H13] = { @@ -16900,6 +16852,7 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc663_m51va_capture_source, .unsol_event = alc663_m51va_unsol_event, .init_hook = alc663_m51va_inithook, }, @@ -16913,7 +16866,6 @@ static struct alc_config_preset alc662_presets[] = { .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc663_capture_source, .unsol_event = alc663_g50v_unsol_event, - .setup = alc663_g50v_setup, .init_hook = alc663_g50v_inithook, }, [ALC663_ASUS_MODE1] = { @@ -16927,8 +16879,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode1_unsol_event, - .setup = alc663_mode1_setup, .init_hook = alc663_mode1_inithook, }, [ALC662_ASUS_MODE2] = { @@ -16941,8 +16893,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc662_mode2_unsol_event, - .setup = alc662_mode2_setup, .init_hook = alc662_mode2_inithook, }, [ALC663_ASUS_MODE3] = { @@ -16956,8 +16908,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode3_unsol_event, - .setup = alc663_mode3_setup, .init_hook = alc663_mode3_inithook, }, [ALC663_ASUS_MODE4] = { @@ -16971,8 +16923,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode4_unsol_event, - .setup = alc663_mode4_setup, .init_hook = alc663_mode4_inithook, }, [ALC663_ASUS_MODE5] = { @@ -16986,8 +16938,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode5_unsol_event, - .setup = alc663_mode5_setup, .init_hook = alc663_mode5_inithook, }, [ALC663_ASUS_MODE6] = { @@ -17001,8 +16953,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode6_unsol_event, - .setup = alc663_mode6_setup, .init_hook = alc663_mode6_inithook, }, [ALC272_DELL] = { @@ -17016,8 +16968,8 @@ static struct alc_config_preset alc662_presets[] = { .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), .capsrc_nids = alc272_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc663_m51va_capture_source, .unsol_event = alc663_m51va_unsol_event, - .setup = alc663_m51va_setup, .init_hook = alc663_m51va_inithook, }, [ALC272_DELL_ZM1] = { @@ -17028,11 +16980,11 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .adc_nids = alc662_adc_nids, - .num_adc_nids = 1, + .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), .capsrc_nids = alc662_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc663_m51va_capture_source, .unsol_event = alc663_m51va_unsol_event, - .setup = alc663_m51va_setup, .init_hook = alc663_m51va_inithook, }, [ALC272_SAMSUNG_NC10] = { @@ -17043,9 +16995,8 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - /*.input_mux = &alc272_nc10_capture_source,*/ + .input_mux = &alc272_nc10_capture_source, .unsol_event = alc663_mode4_unsol_event, - .setup = alc663_mode4_setup, .init_hook = alc663_mode4_inithook, }, }; @@ -17165,6 +17116,25 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, return 0; } +/* return the index of the src widget from the connection list of the nid. + * return -1 if not found + */ +static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t src) +{ + hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; + int i, conns; + + conns = snd_hda_get_connections(codec, nid, conn_list, + ARRAY_SIZE(conn_list)); + if (conns < 0) + return -1; + for (i = 0; i < conns; i++) + if (conn_list[i] == src) + return i; + return -1; +} + static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid) { unsigned int pincap = snd_hda_query_pin_caps(codec, nid); @@ -17181,7 +17151,7 @@ static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec, for (i = 0; i < AUTO_PIN_LAST; i++) { if (alc662_is_input_pin(codec, cfg->input_pins[i])) { - idx = get_connection_index(codec, 0x0b, + idx = alc662_input_pin_idx(codec, 0x0b, cfg->input_pins[i]); if (idx >= 0) { err = new_analog_input(spec, cfg->input_pins[i], @@ -17190,7 +17160,7 @@ static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec, if (err < 0) return err; } - idx = get_connection_index(codec, 0x22, + idx = alc662_input_pin_idx(codec, 0x22, cfg->input_pins[i]); if (idx >= 0) { imux->items[imux->num_items].label = @@ -17379,7 +17349,7 @@ static int patch_alc662(struct hda_codec *codec) } if (board_config != ALC662_AUTO) - setup_preset(codec, &alc662_presets[board_config]); + setup_preset(spec, &alc662_presets[board_config]); spec->stream_analog_playback = &alc662_pcm_analog_playback; spec->stream_analog_capture = &alc662_pcm_analog_capture; @@ -17387,15 +17357,12 @@ static int patch_alc662(struct hda_codec *codec) spec->stream_digital_playback = &alc662_pcm_digital_playback; spec->stream_digital_capture = &alc662_pcm_digital_capture; - if (!spec->adc_nids) { - spec->adc_nids = alc662_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); - } - if (!spec->capsrc_nids) - spec->capsrc_nids = alc662_capsrc_nids; + spec->adc_nids = alc662_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); + spec->capsrc_nids = alc662_capsrc_nids; if (!spec->cap_mixer) - set_capture_mixer(codec); + set_capture_mixer(spec); if (codec->vendor_id == 0x10ec0662) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); else diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index 3ac0112566b1..3457f619bad1 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -40,7 +40,6 @@ enum { STAC_INSERT_EVENT, STAC_PWR_EVENT, STAC_HP_EVENT, - STAC_LO_EVENT, STAC_MIC_EVENT, }; @@ -247,6 +246,7 @@ struct sigmatel_spec { unsigned int num_dmuxes; hda_nid_t *smux_nids; unsigned int num_smuxes; + unsigned int num_analog_muxes; unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ @@ -766,9 +766,35 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); + const struct hda_input_mux *imux = spec->input_mux; + unsigned int idx, prev_idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + prev_idx = spec->cur_mux[adc_idx]; + if (prev_idx == idx) + return 0; + if (idx < spec->num_analog_muxes) { + snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[idx].index); + if (prev_idx >= spec->num_analog_muxes) { + imux = spec->dinput_mux; + /* 0 = analog */ + snd_hda_codec_write_cache(codec, + spec->dmux_nids[adc_idx], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[0].index); + } + } else { + imux = spec->dinput_mux; + snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[idx - 1].index); + } + spec->cur_mux[adc_idx] = idx; + return 1; } static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol, @@ -1205,21 +1231,6 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { - HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT), - - HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT), - - HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT), - - HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT), - { } /* end */ -}; - static struct snd_kcontrol_new stac92hd71bxx_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) }; @@ -1303,7 +1314,8 @@ static int stac92xx_build_controls(struct hda_codec *codec) if (err < 0) return err; } - if (!spec->auto_mic && spec->num_dmuxes > 0) { + if (!spec->auto_mic && spec->num_dmuxes > 0 && + snd_hda_get_bool_hint(codec, "separate_dmux") == 1) { stac_dmux_mixer.count = spec->num_dmuxes; err = snd_hda_ctl_add(codec, snd_ctl_new1(&stac_dmux_mixer, codec)); @@ -1794,8 +1806,6 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { "Dell Studio 1537", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0, "Dell Studio 17", STAC_DELL_M6_DMIC), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be, - "Dell Studio 1555", STAC_DELL_M6_DMIC), {} /* terminator */ }; @@ -1906,8 +1916,6 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP mini 1000", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b, "HP HDX", STAC_HP_HDX), /* HDX16 */ - SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, - "HP", STAC_HP_DV5), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, "unknown Dell", STAC_DELL_M4_1), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234, @@ -2253,7 +2261,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS), @@ -3312,11 +3320,11 @@ static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, { int err; err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, - "Capture Volume", vol); + "Captuer Volume", vol); if (err < 0) return err; err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx, - "Capture Switch", sw); + "Captuer Switch", sw); if (err < 0) return err; return 0; @@ -3580,19 +3588,28 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux; struct hda_input_mux *dimux = &spec->private_dimux; - int err, i; + int err, i, active_mics; + unsigned int def_conf; char name[32]; dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; dimux->items[dimux->num_items].index = 0; dimux->num_items++; + active_mics = 0; + for (i = 0; i < spec->num_dmics; i++) { + def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); + if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) + active_mics++; + } + for (i = 0; i < spec->num_dmics; i++) { hda_nid_t nid; int index; unsigned int wcaps; - unsigned int def_conf; + const char *label; def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) @@ -3603,12 +3620,16 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, if (index < 0) continue; + if (active_mics == 1) + label = "Digital Mic"; + else + label = stac92xx_dmic_labels[dimux->num_items]; + wcaps = get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); if (wcaps) { - sprintf(name, "%s Capture Volume", - stac92xx_dmic_labels[dimux->num_items]); + sprintf(name, "%s Capture Volume", label); err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, @@ -3620,10 +3641,14 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, return err; } - dimux->items[dimux->num_items].label = - stac92xx_dmic_labels[dimux->num_items]; + dimux->items[dimux->num_items].label = label; dimux->items[dimux->num_items].index = index; dimux->num_items++; + if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) { + imux->items[imux->num_items].label = label; + imux->items[imux->num_items].index = index; + imux->num_items++; + } } return 0; @@ -3671,7 +3696,7 @@ static int set_mic_route(struct hda_codec *codec, if (i < 0) return -1; mic->mux_idx = i; - } else if (spec->dmux_nids) { + } else { /* digital pin */ mic->mux_idx = 0; i = get_connection_index(codec, spec->dmux_nids[0], pin); @@ -3743,6 +3768,7 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const imux->items[imux->num_items].index = index; imux->num_items++; } + spec->num_analog_muxes = imux->num_items; if (imux->num_items) { /* @@ -4350,15 +4376,6 @@ static int stac92xx_init(struct hda_codec *codec) hda_nid_t nid = cfg->hp_pins[i]; enable_pin_detect(codec, nid, STAC_HP_EVENT); } - if (cfg->line_out_type == AUTO_PIN_LINE_OUT && - cfg->speaker_outs > 0) { - /* enable pin-detect for line-outs as well */ - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t nid = cfg->line_out_pins[i]; - enable_pin_detect(codec, nid, STAC_LO_EVENT); - } - } - /* force to enable the first line-out; the others are set up * in unsol_event */ @@ -4374,8 +4391,7 @@ static int stac92xx_init(struct hda_codec *codec) } if (spec->auto_mic) { /* initialize connection to analog input */ - if (spec->dmux_nids) - snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, + snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, AC_VERB_SET_CONNECT_SEL, 0); if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) stac_issue_unsol_event(codec, spec->ext_mic.pin); @@ -4558,48 +4574,6 @@ static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) return 0; } -static void stac92xx_line_out_detect(struct hda_codec *codec, - int presence) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < cfg->line_outs; i++) { - if (presence) - break; - presence = get_pin_presence(codec, cfg->line_out_pins[i]); - if (presence) { - unsigned int pinctl; - pinctl = snd_hda_codec_read(codec, - cfg->line_out_pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pinctl & AC_PINCTL_IN_EN) - presence = 0; /* mic- or line-input */ - } - } - - if (presence) { - /* disable speakers */ - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - if (spec->eapd_mask && spec->eapd_switch) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data & - ~spec->eapd_mask); - } else { - /* enable speakers */ - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_set_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - if (spec->eapd_mask && spec->eapd_switch) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data | - spec->eapd_mask); - } -} - /* return non-zero if the hp-pin of the given array index isn't * a jack-detection target */ @@ -4652,6 +4626,13 @@ static void stac92xx_hp_detect(struct hda_codec *codec) for (i = 0; i < cfg->line_outs; i++) stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], AC_PINCTL_OUT_EN); + for (i = 0; i < cfg->speaker_outs; i++) + stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], + AC_PINCTL_OUT_EN); + if (spec->eapd_mask && spec->eapd_switch) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); } else { /* enable lineouts */ if (spec->hp_switch) @@ -4660,8 +4641,14 @@ static void stac92xx_hp_detect(struct hda_codec *codec) for (i = 0; i < cfg->line_outs; i++) stac92xx_set_pinctl(codec, cfg->line_out_pins[i], AC_PINCTL_OUT_EN); + for (i = 0; i < cfg->speaker_outs; i++) + stac92xx_set_pinctl(codec, cfg->speaker_pins[i], + AC_PINCTL_OUT_EN); + if (spec->eapd_mask && spec->eapd_switch) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data | + spec->eapd_mask); } - stac92xx_line_out_detect(codec, presence); /* toggle hp outs */ for (i = 0; i < cfg->hp_outs; i++) { unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; @@ -4786,7 +4773,6 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) switch (event->type) { case STAC_HP_EVENT: - case STAC_LO_EVENT: stac92xx_hp_detect(codec); break; case STAC_MIC_EVENT: @@ -4796,7 +4782,6 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) switch (event->type) { case STAC_HP_EVENT: - case STAC_LO_EVENT: case STAC_MIC_EVENT: case STAC_INSERT_EVENT: case STAC_PWR_EVENT: @@ -5105,16 +5090,6 @@ static int patch_stac925x(struct hda_codec *codec) return 0; } -static struct hda_input_mux stac92hd73xx_dmux = { - .num_items = 4, - .items = { - { "Analog Inputs", 0x0b }, - { "Digital Mic 1", 0x09 }, - { "Digital Mic 2", 0x0a }, - { "CD", 0x08 }, - } -}; - static int patch_stac92hd73xx(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -5184,8 +5159,6 @@ static int patch_stac92hd73xx(struct hda_codec *codec) spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids); - memcpy(&spec->private_dimux, &stac92hd73xx_dmux, - sizeof(stac92hd73xx_dmux)); spec->num_caps = STAC92HD73XX_NUM_CAPS; spec->capvols = stac92hd73xx_capvols; @@ -5210,18 +5183,15 @@ static int patch_stac92hd73xx(struct hda_codec *codec) case STAC_DELL_M6_AMIC: /* Analog Mics */ snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); spec->num_dmics = 0; - spec->private_dimux.num_items = 1; break; case STAC_DELL_M6_DMIC: /* Digital Mics */ snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); spec->num_dmics = 1; - spec->private_dimux.num_items = 2; break; case STAC_DELL_M6_BOTH: /* Both */ snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); spec->num_dmics = 1; - spec->private_dimux.num_items = 2; break; } break; @@ -5229,13 +5199,13 @@ static int patch_stac92hd73xx(struct hda_codec *codec) spec->num_dmics = STAC92HD73XX_NUM_DMICS; spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); spec->eapd_switch = 1; + break; } if (spec->board_config > STAC_92HD73XX_REF) { /* GPIO0 High = Enable EAPD */ spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; spec->gpio_data = 0x01; } - spec->dinput_mux = &spec->private_dimux; spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); spec->pwr_nids = stac92hd73xx_pwr_nids; @@ -5267,15 +5237,6 @@ static int patch_stac92hd73xx(struct hda_codec *codec) return 0; } -static struct hda_input_mux stac92hd83xxx_dmux = { - .num_items = 3, - .items = { - { "Analog Inputs", 0x03 }, - { "Digital Mic 1", 0x04 }, - { "Digital Mic 2", 0x05 }, - } -}; - static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -5308,7 +5269,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids); spec->num_dmics = STAC92HD83XXX_NUM_DMICS; - spec->dinput_mux = &stac92hd83xxx_dmux; spec->pin_nids = stac92hd83xxx_pin_nids; spec->num_caps = STAC92HD83XXX_NUM_CAPS; spec->capvols = stac92hd83xxx_capvols; @@ -5378,25 +5338,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) return 0; } -static struct hda_input_mux stac92hd71bxx_dmux_nomixer = { - .num_items = 3, - .items = { - { "Analog Inputs", 0x00 }, - { "Digital Mic 1", 0x02 }, - { "Digital Mic 2", 0x03 }, - } -}; - -static struct hda_input_mux stac92hd71bxx_dmux_amixer = { - .num_items = 4, - .items = { - { "Analog Inputs", 0x00 }, - { "Mixer", 0x01 }, - { "Digital Mic 1", 0x02 }, - { "Digital Mic 2", 0x03 }, - } -}; - /* get the pin connection (fixed, none, etc) */ static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) { @@ -5457,7 +5398,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) struct sigmatel_spec *spec; struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; int err = 0; - unsigned int ndmic_nids = 0; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5513,21 +5453,13 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) /* fallthru */ case 0x111d76b4: /* 6 Port without Analog Mixer */ case 0x111d76b5: - memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer, - sizeof(stac92hd71bxx_dmux_nomixer)); spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS); - if (spec->num_dmics) { - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - spec->dinput_mux = &spec->private_dimux; - ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1; - } break; case 0x111d7608: /* 5 Port with Analog Mixer */ - spec->private_dimux.num_items--; switch (spec->board_config) { case STAC_HP_M4: /* Enable VREF power saving on GPIO1 detect */ @@ -5549,15 +5481,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) /* no output amps */ spec->num_pwrs = 0; - if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) { - spec->mixer = stac92hd71bxx_analog_mixer; - memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, - sizeof(stac92hd71bxx_dmux_amixer)); - } else { - memcpy(&spec->private_dimux, - &stac92hd71bxx_dmux_nomixer, - sizeof(stac92hd71bxx_dmux_nomixer)); - } /* disable VSW */ spec->init = stac92hd71bxx_core_init; unmute_init++; @@ -5567,11 +5490,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS - 1); - if (spec->num_dmics) { - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - spec->dinput_mux = &spec->private_dimux; - ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2; - } break; case 0x111d7603: /* 6 Port with Analog Mixer */ if ((codec->revision_id & 0xf) == 1) @@ -5581,25 +5499,12 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->num_pwrs = 0; /* fallthru */ default: - if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) { - spec->mixer = stac92hd71bxx_analog_mixer; - memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, - sizeof(stac92hd71bxx_dmux_amixer)); - } else { - memcpy(&spec->private_dimux, - &stac92hd71bxx_dmux_nomixer, - sizeof(stac92hd71bxx_dmux_nomixer)); - } spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS); - if (spec->num_dmics) { - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - spec->dinput_mux = &spec->private_dimux; - ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1; - } + break; } if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) @@ -5627,6 +5532,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); + spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e); switch (spec->board_config) { @@ -5681,8 +5587,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) #endif spec->multiout.dac_nids = spec->dac_nids; - if (spec->dinput_mux) - spec->private_dimux.num_items += spec->num_dmics - ndmic_nids; err = stac92xx_parse_auto_config(codec, 0x21, 0); if (!err) { @@ -5872,13 +5776,6 @@ static int patch_stac927x(struct hda_codec *codec) /* GPIO2 High = Enable EAPD */ spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04; spec->gpio_data = 0x04; - switch (codec->subsystem_id) { - case 0x1028022f: - /* correct EAPD to be GPIO0 */ - spec->eapd_mask = spec->gpio_mask = 0x01; - spec->gpio_dir = spec->gpio_data = 0x01; - break; - }; spec->dmic_nids = stac927x_dmic_nids; spec->num_dmics = STAC927X_NUM_DMICS;