diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/Kconfig | 15 | ||||
-rw-r--r-- | sound/pci/hda/Makefile | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_auto_parser.c | 46 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 14 | ||||
-rw-r--r-- | sound/pci/hda/hda_tegra.c | 588 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 6 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 464 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 4 |
11 files changed, 1110 insertions, 34 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index ac17c3fc9388..ebf4c2fb99df 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -20,6 +20,21 @@ config SND_HDA_INTEL To compile this driver as a module, choose M here: the module will be called snd-hda-intel. +config SND_HDA_TEGRA + tristate "NVIDIA Tegra HD Audio" + depends on ARCH_TEGRA + select SND_HDA + help + Say Y here to support the HDA controller present in NVIDIA + Tegra SoCs + + This options enables support for the HD Audio controller + present in some NVIDIA Tegra SoCs, used to communicate audio + to the HDMI output. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-tegra. + if SND_HDA config SND_HDA_DSP_LOADER diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index d0d0c19ddfc2..194f30935e77 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,5 +1,6 @@ snd-hda-intel-objs := hda_intel.o snd-hda-controller-objs := hda_controller.o +snd-hda-tegra-objs := hda_tegra.o # for haswell power well snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o @@ -47,3 +48,4 @@ obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o # otherwise the codec patches won't be hooked before the PCI probe # when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o +obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 90d2fda6c8f9..b684c6e4f301 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -839,6 +839,43 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action) } EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); +static bool pin_config_match(struct hda_codec *codec, + const struct hda_pintbl *pins) +{ + for (; pins->nid; pins++) { + u32 def_conf = snd_hda_codec_get_pincfg(codec, pins->nid); + if (pins->val != def_conf) + return false; + } + return true; +} + +void snd_hda_pick_pin_fixup(struct hda_codec *codec, + const struct snd_hda_pin_quirk *pin_quirk, + const struct hda_fixup *fixlist) +{ + const struct snd_hda_pin_quirk *pq; + + if (codec->fixup_forced) + return; + + for (pq = pin_quirk; pq->subvendor; pq++) { + if ((codec->subsystem_id & 0xffff0000) != (pq->subvendor << 16)) + continue; + if (codec->vendor_id != pq->codec) + continue; + if (pin_config_match(codec, pq->pins)) { + codec->fixup_id = pq->value; +#ifdef CONFIG_SND_DEBUG_VERBOSE + codec->fixup_name = pq->name; +#endif + codec->fixup_list = fixlist; + return; + } + } +} +EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); + void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, const struct snd_pci_quirk *quirk, @@ -852,15 +889,17 @@ void snd_hda_pick_fixup(struct hda_codec *codec, if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { codec->fixup_list = NULL; codec->fixup_id = -1; + codec->fixup_forced = 1; return; } if (codec->modelname && models) { while (models->name) { if (!strcmp(codec->modelname, models->name)) { - id = models->id; - name = models->name; - break; + codec->fixup_id = models->id; + codec->fixup_name = models->name; + codec->fixup_forced = 1; + return; } models++; } @@ -889,6 +928,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec, } } + codec->fixup_forced = 0; codec->fixup_id = id; if (id >= 0) { codec->fixup_list = fixlist; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index a4233136cb93..5825aa17d8e3 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -402,6 +402,7 @@ struct hda_codec { /* fix-up list */ int fixup_id; + unsigned int fixup_forced:1; /* fixup explicitly set by user */ const struct hda_fixup *fixup_list; const char *fixup_name; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 16133881e967..589e47c5aeb3 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3722,7 +3722,7 @@ static void parse_digital(struct hda_codec *codec) } else { spec->multiout.slave_dig_outs = spec->slave_dig_outs; if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) - break; + break; spec->slave_dig_outs[nums - 1] = dig_nid; } nums++; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6cc3cf285558..cd77b9b19b73 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1730,7 +1730,7 @@ static void azx_remove(struct pci_dev *pci) } /* PCI IDs */ -static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { +static const struct pci_device_id azx_ids[] = { /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index e51d15529215..ebd1fa6f015c 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -407,6 +407,16 @@ struct hda_fixup { } v; }; +struct snd_hda_pin_quirk { + unsigned int codec; /* Codec vendor/device ID */ + unsigned short subvendor; /* PCI subvendor ID */ + const struct hda_pintbl *pins; /* list of matching pins */ +#ifdef CONFIG_SND_DEBUG_VERBOSE + const char *name; +#endif + int value; /* quirk value */ +}; + /* fixup types */ enum { HDA_FIXUP_INVALID, @@ -434,6 +444,10 @@ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, const struct snd_pci_quirk *quirk, const struct hda_fixup *fixlist); +void snd_hda_pick_pin_fixup(struct hda_codec *codec, + const struct snd_hda_pin_quirk *pin_quirk, + const struct hda_fixup *fixlist); + /* * unsolicited event handler diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c new file mode 100644 index 000000000000..a366ba9293a8 --- /dev/null +++ b/sound/pci/hda/hda_tegra.c @@ -0,0 +1,588 @@ +/* + * + * Implementation of primary ALSA driver code base for NVIDIA Tegra HDA. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/clk.h> +#include <linux/clocksource.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mutex.h> +#include <linux/of_device.h> +#include <linux/reboot.h> +#include <linux/slab.h> +#include <linux/time.h> + +#include <sound/core.h> +#include <sound/initval.h> + +#include "hda_codec.h" +#include "hda_controller.h" +#include "hda_priv.h" + +/* Defines for Nvidia Tegra HDA support */ +#define HDA_BAR0 0x8000 + +#define HDA_CFG_CMD 0x1004 +#define HDA_CFG_BAR0 0x1010 + +#define HDA_ENABLE_IO_SPACE (1 << 0) +#define HDA_ENABLE_MEM_SPACE (1 << 1) +#define HDA_ENABLE_BUS_MASTER (1 << 2) +#define HDA_ENABLE_SERR (1 << 8) +#define HDA_DISABLE_INTR (1 << 10) +#define HDA_BAR0_INIT_PROGRAM 0xFFFFFFFF +#define HDA_BAR0_FINAL_PROGRAM (1 << 14) + +/* IPFS */ +#define HDA_IPFS_CONFIG 0x180 +#define HDA_IPFS_EN_FPCI 0x1 + +#define HDA_IPFS_FPCI_BAR0 0x80 +#define HDA_FPCI_BAR0_START 0x40 + +#define HDA_IPFS_INTR_MASK 0x188 +#define HDA_IPFS_EN_INTR (1 << 16) + +/* max number of SDs */ +#define NUM_CAPTURE_SD 1 +#define NUM_PLAYBACK_SD 1 + +struct hda_tegra { + struct azx chip; + struct device *dev; + struct clk *hda_clk; + struct clk *hda2codec_2x_clk; + struct clk *hda2hdmi_clk; + void __iomem *regs; +}; + +#ifdef CONFIG_PM +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +module_param(power_save, bint, 0644); +MODULE_PARM_DESC(power_save, + "Automatic power-saving timeout (in seconds, 0 = disable)."); +#else +static int power_save = 0; +#endif + +/* + * DMA page allocation ops. + */ +static int dma_alloc_pages(struct azx *chip, int type, size_t size, + struct snd_dma_buffer *buf) +{ + return snd_dma_alloc_pages(type, chip->card->dev, size, buf); +} + +static void dma_free_pages(struct azx *chip, struct snd_dma_buffer *buf) +{ + snd_dma_free_pages(buf); +} + +static int substream_alloc_pages(struct azx *chip, + struct snd_pcm_substream *substream, + size_t size) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + + azx_dev->bufsize = 0; + azx_dev->period_bytes = 0; + azx_dev->format_val = 0; + return snd_pcm_lib_malloc_pages(substream, size); +} + +static int substream_free_pages(struct azx *chip, + struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +/* + * Register access ops. Tegra HDA register access is DWORD only. + */ +static void hda_tegra_writel(u32 value, u32 *addr) +{ + writel(value, addr); +} + +static u32 hda_tegra_readl(u32 *addr) +{ + return readl(addr); +} + +static void hda_tegra_writew(u16 value, u16 *addr) +{ + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + void *dword_addr = (void *)((unsigned long)(addr) & ~0x3); + u32 v; + + v = readl(dword_addr); + v &= ~(0xffff << shift); + v |= value << shift; + writel(v, dword_addr); +} + +static u16 hda_tegra_readw(u16 *addr) +{ + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + void *dword_addr = (void *)((unsigned long)(addr) & ~0x3); + u32 v; + + v = readl(dword_addr); + return (v >> shift) & 0xffff; +} + +static void hda_tegra_writeb(u8 value, u8 *addr) +{ + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + void *dword_addr = (void *)((unsigned long)(addr) & ~0x3); + u32 v; + + v = readl(dword_addr); + v &= ~(0xff << shift); + v |= value << shift; + writel(v, dword_addr); +} + +static u8 hda_tegra_readb(u8 *addr) +{ + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + void *dword_addr = (void *)((unsigned long)(addr) & ~0x3); + u32 v; + + v = readl(dword_addr); + return (v >> shift) & 0xff; +} + +static const struct hda_controller_ops hda_tegra_ops = { + .reg_writel = hda_tegra_writel, + .reg_readl = hda_tegra_readl, + .reg_writew = hda_tegra_writew, + .reg_readw = hda_tegra_readw, + .reg_writeb = hda_tegra_writeb, + .reg_readb = hda_tegra_readb, + .dma_alloc_pages = dma_alloc_pages, + .dma_free_pages = dma_free_pages, + .substream_alloc_pages = substream_alloc_pages, + .substream_free_pages = substream_free_pages, +}; + +static void hda_tegra_init(struct hda_tegra *hda) +{ + u32 v; + + /* Enable PCI access */ + v = readl(hda->regs + HDA_IPFS_CONFIG); + v |= HDA_IPFS_EN_FPCI; + writel(v, hda->regs + HDA_IPFS_CONFIG); + + /* Enable MEM/IO space and bus master */ + v = readl(hda->regs + HDA_CFG_CMD); + v &= ~HDA_DISABLE_INTR; + v |= HDA_ENABLE_MEM_SPACE | HDA_ENABLE_IO_SPACE | + HDA_ENABLE_BUS_MASTER | HDA_ENABLE_SERR; + writel(v, hda->regs + HDA_CFG_CMD); + + writel(HDA_BAR0_INIT_PROGRAM, hda->regs + HDA_CFG_BAR0); + writel(HDA_BAR0_FINAL_PROGRAM, hda->regs + HDA_CFG_BAR0); + writel(HDA_FPCI_BAR0_START, hda->regs + HDA_IPFS_FPCI_BAR0); + + v = readl(hda->regs + HDA_IPFS_INTR_MASK); + v |= HDA_IPFS_EN_INTR; + writel(v, hda->regs + HDA_IPFS_INTR_MASK); +} + +static int hda_tegra_enable_clocks(struct hda_tegra *data) +{ + int rc; + + rc = clk_prepare_enable(data->hda_clk); + if (rc) + return rc; + rc = clk_prepare_enable(data->hda2codec_2x_clk); + if (rc) + goto disable_hda; + rc = clk_prepare_enable(data->hda2hdmi_clk); + if (rc) + goto disable_codec_2x; + + return 0; + +disable_codec_2x: + clk_disable_unprepare(data->hda2codec_2x_clk); +disable_hda: + clk_disable_unprepare(data->hda_clk); + return rc; +} + +static void hda_tegra_disable_clocks(struct hda_tegra *data) +{ + clk_disable_unprepare(data->hda2hdmi_clk); + clk_disable_unprepare(data->hda2codec_2x_clk); + clk_disable_unprepare(data->hda_clk); +} + +#ifdef CONFIG_PM_SLEEP +/* + * power management + */ +static int hda_tegra_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct azx_pcm *p; + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + list_for_each_entry(p, &chip->pcm_list, list) + snd_pcm_suspend_all(p->pcm); + if (chip->initialized) + snd_hda_suspend(chip->bus); + + azx_stop_chip(chip); + azx_enter_link_reset(chip); + hda_tegra_disable_clocks(hda); + + return 0; +} + +static int hda_tegra_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + int status; + + hda_tegra_enable_clocks(hda); + + /* Read STATESTS before controller reset */ + status = azx_readw(chip, STATESTS); + + hda_tegra_init(hda); + + azx_init_chip(chip, 1); + + snd_hda_resume(chip->bus); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops hda_tegra_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) +}; + +/* + * reboot notifier for hang-up problem at power-down + */ +static int hda_tegra_halt(struct notifier_block *nb, unsigned long event, + void *buf) +{ + struct azx *chip = container_of(nb, struct azx, reboot_notifier); + snd_hda_bus_reboot_notify(chip->bus); + azx_stop_chip(chip); + return NOTIFY_OK; +} + +static void hda_tegra_notifier_register(struct azx *chip) +{ + chip->reboot_notifier.notifier_call = hda_tegra_halt; + register_reboot_notifier(&chip->reboot_notifier); +} + +static void hda_tegra_notifier_unregister(struct azx *chip) +{ + if (chip->reboot_notifier.notifier_call) + unregister_reboot_notifier(&chip->reboot_notifier); +} + +/* + * destructor + */ +static int hda_tegra_dev_free(struct snd_device *device) +{ + int i; + struct azx *chip = device->device_data; + + hda_tegra_notifier_unregister(chip); + + if (chip->initialized) { + for (i = 0; i < chip->num_streams; i++) + azx_stream_stop(chip, &chip->azx_dev[i]); + azx_stop_chip(chip); + } + + azx_free_stream_pages(chip); + + return 0; +} + +static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) +{ + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + struct device *dev = hda->dev; + struct resource *res; + int err; + + hda->hda_clk = devm_clk_get(dev, "hda"); + if (IS_ERR(hda->hda_clk)) + return PTR_ERR(hda->hda_clk); + hda->hda2codec_2x_clk = devm_clk_get(dev, "hda2codec_2x"); + if (IS_ERR(hda->hda2codec_2x_clk)) + return PTR_ERR(hda->hda2codec_2x_clk); + hda->hda2hdmi_clk = devm_clk_get(dev, "hda2hdmi"); + if (IS_ERR(hda->hda2hdmi_clk)) + return PTR_ERR(hda->hda2hdmi_clk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hda->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(chip->remap_addr)) + return PTR_ERR(chip->remap_addr); + + chip->remap_addr = hda->regs + HDA_BAR0; + chip->addr = res->start + HDA_BAR0; + + err = hda_tegra_enable_clocks(hda); + if (err) + return err; + + hda_tegra_init(hda); + + return 0; +} + +/* + * The codecs were powered up in snd_hda_codec_new(). + * Now all initialization done, so turn them down if possible + */ +static void power_down_all_codecs(struct azx *chip) +{ + struct hda_codec *codec; + list_for_each_entry(codec, &chip->bus->codec_list, list) + snd_hda_power_down(codec); +} + +static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) +{ + struct snd_card *card = chip->card; + int err; + unsigned short gcap; + int irq_id = platform_get_irq(pdev, 0); + + err = hda_tegra_init_chip(chip, pdev); + if (err) + return err; + + err = devm_request_irq(chip->card->dev, irq_id, azx_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip); + if (err) { + dev_err(chip->card->dev, + "unable to request IRQ %d, disabling device\n", + irq_id); + return err; + } + chip->irq = irq_id; + + synchronize_irq(chip->irq); + + gcap = azx_readw(chip, GCAP); + dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); + + /* read number of streams from GCAP register instead of using + * hardcoded value + */ + chip->capture_streams = (gcap >> 8) & 0x0f; + chip->playback_streams = (gcap >> 12) & 0x0f; + if (!chip->playback_streams && !chip->capture_streams) { + /* gcap didn't give any info, switching to old method */ + chip->playback_streams = NUM_PLAYBACK_SD; + chip->capture_streams = NUM_CAPTURE_SD; + } + chip->capture_index_offset = 0; + chip->playback_index_offset = chip->capture_streams; + chip->num_streams = chip->playback_streams + chip->capture_streams; + chip->azx_dev = devm_kcalloc(card->dev, chip->num_streams, + sizeof(*chip->azx_dev), GFP_KERNEL); + if (!chip->azx_dev) + return -ENOMEM; + + err = azx_alloc_stream_pages(chip); + if (err < 0) + return err; + + /* initialize streams */ + azx_init_stream(chip); + + /* initialize chip */ + azx_init_chip(chip, 1); + + /* codec detection */ + if (!chip->codec_mask) { + dev_err(card->dev, "no codecs found!\n"); + return -ENODEV; + } + + strcpy(card->driver, "tegra-hda"); + strcpy(card->shortname, "tegra-hda"); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", + card->shortname, chip->addr, chip->irq); + + return 0; +} + +/* + * constructor + */ +static int hda_tegra_create(struct snd_card *card, + unsigned int driver_caps, + const struct hda_controller_ops *hda_ops, + struct hda_tegra *hda) +{ + static struct snd_device_ops ops = { + .dev_free = hda_tegra_dev_free, + }; + struct azx *chip; + int err; + + chip = &hda->chip; + + spin_lock_init(&chip->reg_lock); + mutex_init(&chip->open_mutex); + chip->card = card; + chip->ops = hda_ops; + chip->irq = -1; + chip->driver_caps = driver_caps; + chip->driver_type = driver_caps & 0xff; + chip->dev_index = 0; + INIT_LIST_HEAD(&chip->pcm_list); + INIT_LIST_HEAD(&chip->list); + + chip->position_fix[0] = POS_FIX_AUTO; + chip->position_fix[1] = POS_FIX_AUTO; + chip->codec_probe_mask = -1; + + chip->single_cmd = false; + chip->snoop = true; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + dev_err(card->dev, "Error creating device\n"); + return err; + } + + return 0; +} + +static const struct of_device_id hda_tegra_match[] = { + { .compatible = "nvidia,tegra30-hda" }, + {}, +}; +MODULE_DEVICE_TABLE(of, hda_tegra_match); + +static int hda_tegra_probe(struct platform_device *pdev) +{ + struct snd_card *card; + struct azx *chip; + struct hda_tegra *hda; + int err; + const unsigned int driver_flags = AZX_DCAPS_RIRB_DELAY; + + hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); + if (!hda) + return -ENOMEM; + hda->dev = &pdev->dev; + chip = &hda->chip; + + err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &card); + if (err < 0) { + dev_err(&pdev->dev, "Error creating card!\n"); + return err; + } + + err = hda_tegra_create(card, driver_flags, &hda_tegra_ops, hda); + if (err < 0) + goto out_free; + card->private_data = chip; + + dev_set_drvdata(&pdev->dev, card); + + err = hda_tegra_first_init(chip, pdev); + if (err < 0) + goto out_free; + + /* create codec instances */ + err = azx_codec_create(chip, NULL, 0, &power_save); + if (err < 0) + goto out_free; + + err = azx_codec_configure(chip); + if (err < 0) + goto out_free; + + /* create PCM streams */ + err = snd_hda_build_pcms(chip->bus); + if (err < 0) + goto out_free; + + /* create mixer controls */ + err = azx_mixer_create(chip); + if (err < 0) + goto out_free; + + err = snd_card_register(chip->card); + if (err < 0) + goto out_free; + + chip->running = 1; + power_down_all_codecs(chip); + hda_tegra_notifier_register(chip); + + return 0; + +out_free: + snd_card_free(card); + return err; +} + +static int hda_tegra_remove(struct platform_device *pdev) +{ + return snd_card_free(dev_get_drvdata(&pdev->dev)); +} + +static struct platform_driver tegra_platform_hda = { + .driver = { + .name = "tegra-hda", + .pm = &hda_tegra_pm, + .of_match_table = hda_tegra_match, + }, + .probe = hda_tegra_probe, + .remove = hda_tegra_remove, +}; +module_platform_driver(tegra_platform_hda); + +MODULE_DESCRIPTION("Tegra HDA bus driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index b4218a19df22..be0a9ee0b804 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1127,10 +1127,6 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, AMP_OUT_UNMUTE); eld = &per_pin->sink_eld; - if (!eld->monitor_present) { - hdmi_set_channel_count(codec, per_pin->cvt_nid, channels); - return; - } if (!non_pcm && per_pin->chmap_set) ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); @@ -3324,6 +3320,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi }, { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi }, { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0028, .name = "Tegra12x HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi }, { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi }, { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi }, @@ -3380,6 +3377,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0019"); MODULE_ALIAS("snd-hda-codec-id:10de001a"); MODULE_ALIAS("snd-hda-codec-id:10de001b"); MODULE_ALIAS("snd-hda-codec-id:10de001c"); +MODULE_ALIAS("snd-hda-codec-id:10de0028"); MODULE_ALIAS("snd-hda-codec-id:10de0040"); MODULE_ALIAS("snd-hda-codec-id:10de0041"); MODULE_ALIAS("snd-hda-codec-id:10de0042"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d943508a7f48..12fb411adf77 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -951,7 +951,9 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { { 0x10ec0280, 0x1028, 0, "ALC3220" }, { 0x10ec0282, 0x1028, 0, "ALC3221" }, { 0x10ec0283, 0x1028, 0, "ALC3223" }, + { 0x10ec0288, 0x1028, 0, "ALC3263" }, { 0x10ec0292, 0x1028, 0, "ALC3226" }, + { 0x10ec0293, 0x1028, 0, "ALC3235" }, { 0x10ec0255, 0x1028, 0, "ALC3234" }, { 0x10ec0668, 0x1028, 0, "ALC3661" }, { } /* terminator */ @@ -3520,6 +3522,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) /* Direct Drive HP Amp control */ alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6); break; + case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x1b, 0x0c0b); alc_write_coef_idx(codec, 0x45, 0xc429); @@ -3536,6 +3539,25 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) alc_write_coef_idx(codec, 0x18, 0x7308); alc_write_coef_idx(codec, 0x6b, 0xc429); break; + case 0x10ec0293: + /* SET Line1 JD to 0 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 6<<8); + /* SET charge pump by verb */ + val = alc_read_coefex_idx(codec, 0x57, 0x05); + alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | 0x0); + /* SET EN_OSW to 1 */ + val = alc_read_coefex_idx(codec, 0x57, 0x03); + alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | (1<<10) ); + /* Combo JD gating with LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | (1<<3)); + /* Set to TRS type */ + alc_write_coef_idx(codec, 0x45, 0xc429); + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x15, 0x0d40); alc_write_coef_idx(codec, 0xb7, 0x802b); @@ -3559,6 +3581,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_write_coef_idx(codec, 0x06, 0x6100); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; + case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); @@ -3574,6 +3597,21 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_write_coef_idx(codec, 0x19, 0xa208); alc_write_coef_idx(codec, 0x2e, 0xacf0); break; + case 0x10ec0293: + /* Set to TRS mode */ + alc_write_coef_idx(codec, 0x45, 0xc429); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + /* SET charge pump by verb */ + val = alc_read_coefex_idx(codec, 0x57, 0x05); + alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | (1<<15|1<<13)); + /* SET EN_OSW to 0 */ + val = alc_read_coefex_idx(codec, 0x57, 0x03); + alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | 0x0); + /* Combo JD gating without LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); @@ -3589,6 +3627,8 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, static void alc_headset_mode_default(struct hda_codec *codec) { + int val; + switch (codec->vendor_id) { case 0x10ec0255: alc_write_coef_idx(codec, 0x45, 0xc089); @@ -3596,6 +3636,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); alc_write_coef_idx(codec, 0x49, 0x0049); break; + case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x06, 0x2100); alc_write_coef_idx(codec, 0x32, 0x4ea3); @@ -3606,6 +3647,16 @@ static void alc_headset_mode_default(struct hda_codec *codec) alc_write_coef_idx(codec, 0x6b, 0xc429); alc_write_coef_idx(codec, 0x18, 0x7308); break; + case 0x10ec0293: + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + /* Set to TRS type */ + alc_write_coef_idx(codec, 0x45, 0xC429); + /* Combo JD gating without LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0041); alc_write_coef_idx(codec, 0x15, 0x0d40); @@ -3618,6 +3669,8 @@ static void alc_headset_mode_default(struct hda_codec *codec) /* Iphone type */ static void alc_headset_mode_ctia(struct hda_codec *codec) { + int val; + switch (codec->vendor_id) { case 0x10ec0255: /* Set to CTIA type */ @@ -3625,6 +3678,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) alc_write_coef_idx(codec, 0x1b, 0x0c2b); alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); break; + case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xd429); alc_write_coef_idx(codec, 0x1b, 0x0c2b); @@ -3635,6 +3689,13 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) alc_write_coef_idx(codec, 0x76, 0x0008); alc_write_coef_idx(codec, 0x18, 0x7388); break; + case 0x10ec0293: + /* Set to ctia type */ + alc_write_coef_idx(codec, 0x45, 0xd429); + /* SET Line1 JD to 1 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); alc_write_coef_idx(codec, 0x15, 0x0d60); @@ -3647,6 +3708,8 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) /* Nokia type */ static void alc_headset_mode_omtp(struct hda_codec *codec) { + int val; + switch (codec->vendor_id) { case 0x10ec0255: /* Set to OMTP Type */ @@ -3654,6 +3717,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) alc_write_coef_idx(codec, 0x1b, 0x0c2b); alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); break; + case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xe429); alc_write_coef_idx(codec, 0x1b, 0x0c2b); @@ -3664,6 +3728,13 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) alc_write_coef_idx(codec, 0x76, 0x0008); alc_write_coef_idx(codec, 0x18, 0x7388); break; + case 0x10ec0293: + /* Set to omtp type */ + alc_write_coef_idx(codec, 0x45, 0xe429); + /* SET Line1 JD to 1 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); alc_write_coef_idx(codec, 0x15, 0x0d50); @@ -3689,6 +3760,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; break; + case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xd029); msleep(300); @@ -3701,6 +3773,16 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x6c); is_ctia = (val & 0x001c) == 0x001c; break; + case 0x10ec0293: + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x0008); + /* Set to ctia type */ + alc_write_coef_idx(codec, 0x45, 0xD429); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); alc_write_coef_idx(codec, 0xb7, 0x802b); @@ -3892,6 +3974,39 @@ static void alc_fixup_no_shutup(struct hda_codec *codec, } } +static void alc_fixup_disable_aamix(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + /* Disable AA-loopback as it causes white noise */ + spec->gen.mixer_nid = 0; + } +} + +static unsigned int alc_power_filter_xps13(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + struct alc_spec *spec = codec->spec; + + /* Avoid pop noises when headphones are plugged in */ + if (spec->gen.hp_jack_present) + if (nid == codec->afg || nid == 0x02) + return AC_PWRST_D0; + return power_state; +} + +static void alc_fixup_dell_xps13(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PROBE) { + struct alc_spec *spec = codec->spec; + spec->shutup = alc_no_shutup; + codec->power_filter = alc_power_filter_xps13; + } +} + static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -4108,6 +4223,7 @@ enum { ALC269_FIXUP_ASUS_G73JW, ALC269_FIXUP_LENOVO_EAPD, ALC275_FIXUP_SONY_HWEQ, + ALC275_FIXUP_SONY_DISABLE_AAMIX, ALC271_FIXUP_DMIC, ALC269_FIXUP_PCM_44K, ALC269_FIXUP_STEREO_DMIC, @@ -4157,6 +4273,8 @@ enum { ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, ALC255_FIXUP_HEADSET_MODE, ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, + ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC292_FIXUP_TPT440_DOCK, }; static const struct hda_fixup alc269_fixups[] = { @@ -4211,6 +4329,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 }, + [ALC275_FIXUP_SONY_DISABLE_AAMIX] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC269_FIXUP_SONY_VAIO + }, [ALC271_FIXUP_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc271_fixup_dmic, @@ -4550,6 +4674,26 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode_alc255_no_hp_mic, }, + [ALC293_FIXUP_DELL1_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x01a1913d }, /* use as headphone mic, without its own jack detect */ + { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, + [ALC292_FIXUP_TPT440_DOCK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x21211010 }, /* dock headphone */ + { 0x19, 0x21a11010 }, /* dock mic */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4593,31 +4737,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x060f, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), - SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0629, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x062c, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x062e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0632, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), - SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0640, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064d, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x065c, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0667, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0674, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -4627,6 +4756,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0684, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4700,6 +4831,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), + SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), @@ -4713,7 +4845,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -4791,9 +4924,215 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"}, {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"}, {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"}, + {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, {} }; +static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + { + .codec = 0x10ec0255, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60140}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211020}, + }, + .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0255, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60160}, + {0x14, 0x90170120}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211030}, + }, + .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0255, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60160}, + {0x14, 0x90170130}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211040}, + }, + .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0255, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60160}, + {0x14, 0x90170140}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211050}, + }, + .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0255, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60170}, + {0x14, 0x90170120}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211030}, + }, + .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0255, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60170}, + {0x14, 0x90170130}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211040}, + }, + .value = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0283, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60130}, + {0x14, 0x90170110}, + {0x17, 0x40020008}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40e00001}, + {0x1e, 0x411111f0}, + {0x21, 0x0321101f}, + }, + .value = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0283, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60160}, + {0x14, 0x90170120}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211030}, + }, + .value = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0292, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x90a60140}, + {0x13, 0x411111f0}, + {0x14, 0x90170110}, + {0x15, 0x0221401f}, + {0x16, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + }, + .value = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, + }, + { + .codec = 0x10ec0293, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x40000000}, + {0x13, 0x90a60140}, + {0x14, 0x90170110}, + {0x15, 0x0221401f}, + {0x16, 0x21014020}, + {0x18, 0x411111f0}, + {0x19, 0x21a19030}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + }, + .value = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + }, + {} +}; static void alc269_fill_coef(struct hda_codec *codec) { @@ -4855,6 +5194,7 @@ static int patch_alc269(struct hda_codec *codec) snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); + snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); @@ -5311,6 +5651,8 @@ enum { ALC662_FIXUP_BASS_1A, ALC662_FIXUP_BASS_CHMAP, ALC668_FIXUP_AUTO_MUTE, + ALC668_FIXUP_DELL_DISABLE_AAMIX, + ALC668_FIXUP_DELL_XPS13, }; static const struct hda_fixup alc662_fixups[] = { @@ -5477,6 +5819,18 @@ static const struct hda_fixup alc662_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, + [ALC668_FIXUP_DELL_XPS13] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_dell_xps13, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX + }, + [ALC668_FIXUP_DELL_DISABLE_AAMIX] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE + }, [ALC668_FIXUP_AUTO_MUTE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_auto_mute_via_amp, @@ -5537,13 +5891,9 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0623, "Dell", ALC668_FIXUP_AUTO_MUTE), - SND_PCI_QUIRK(0x1028, 0x0624, "Dell", ALC668_FIXUP_AUTO_MUTE), + SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE), - SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE), SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), @@ -5635,6 +5985,73 @@ static const struct hda_model_fixup alc662_fixup_models[] = { {} }; +static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { + { + .codec = 0x10ec0668, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}, + {0x18, 0x40000008}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41000001}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}, + }, + .value = ALC668_FIXUP_AUTO_MUTE, + }, + { + .codec = 0x10ec0668, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x99a30150}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}, + {0x18, 0x40000008}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41000001}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}, + }, + .value = ALC668_FIXUP_AUTO_MUTE, + }, + { + .codec = 0x10ec0668, + .subvendor = 0x1028, +#ifdef CONFIG_SND_DEBUG_VERBOSE + .name = "Dell", +#endif + .pins = (const struct hda_pintbl[]) { + {0x12, 0x411111f0}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}, + {0x18, 0x40000008}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41000001}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}, + }, + .value = ALC668_FIXUP_AUTO_MUTE, + }, + {} +}; + static void alc662_fill_coef(struct hda_codec *codec) { int val, coef; @@ -5684,6 +6101,7 @@ static int patch_alc662(struct hda_codec *codec) snd_hda_pick_fixup(codec, alc662_fixup_models, alc662_fixup_tbl, alc662_fixups); + snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 75515b494034..7f40a150899c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -795,7 +795,7 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) } while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { - if (sscanf(dev->name, "HP_Mute_LED_%d_%x", + if (sscanf(dev->name, "HP_Mute_LED_%u_%x", &spec->gpio_led_polarity, &spec->gpio_led) == 2) { unsigned int max_gpio; @@ -808,7 +808,7 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) spec->vref_mute_led_nid = spec->gpio_led; return 1; } - if (sscanf(dev->name, "HP_Mute_LED_%d", + if (sscanf(dev->name, "HP_Mute_LED_%u", &spec->gpio_led_polarity) == 1) { set_hp_led_gpio(codec); return 1; |