Merge tag 'sound-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound into next
Pull sound updates from Takashi Iwai: "At this time, majority of changes come from ASoC world while we got a few new drivers in other places for FireWire and USB. There have been lots of ASoC core cleanups / refactoring, but very little visible to external users. ASoC: - Support for specifying aux CODECs in DT - Removal of the deprecated mux and enum macros - More moves towards full componentisation - Removal of some unused I/O code - Lots of cleanups, fixes and enhancements to the davinci, Freescale, Haswell and Realtek drivers - Several drivers exposed directly in Kconfig for use with simple-card - GPIO descriptor support for jacks - More updates and fixes to the Freescale SSI, Intel and rsnd drivers - New drivers for Cirrus CS42L56, Realtek RT5639, RT5642 and RT5651 and ST STA350, Analog Devices ADAU1361, ADAU1381, ADAU1761 and ADAU1781, and Realtek RT5677 HD-audio: - Clean up Dell headset quirks - Noise fixes for Dell and Sony laptops - Thinkpad T440 dock fix - Realtek codec updates (ALC293,ALC233,ALC3235) - Tegra HD-audio HDMI support FireWire-audio: - FireWire audio stack enhancement (AMDTP, MIDI), support for incoming isochronous stream and duplex streams with timestamp synchronization - BeBoB-based devices support - Fireworks-based device support USB-audio: - Behringer BCD2000 USB device support Misc: - Clean up of a few old drivers, atmel, fm801, etc" * tag 'sound-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (480 commits) ASoC: Fix wrong argument for card remove callbacks ASoC: free jack GPIOs before the sound card is freed ALSA: firewire-lib: Remove a comment about restriction of asynchronous operation ASoC: cache: Fix error code when not using ASoC level cache ALSA: hda/realtek - Fix COEF widget NID for ALC260 replacer fixup ALSA: hda/realtek - Correction of fixup codes for PB V7900 laptop ALSA: firewire-lib: Use IEC 61883-6 compliant labels for Raw Audio data ASoC: add RT5677 CODEC driver ASoC: intel: The Baytrail/MAX98090 driver depends on I2C ASoC: rt5640: Add the function "get_clk_info" to RL6231 shared support ASoC: rt5640: Add the function of the PLL clock calculation to RL6231 shared support ASoC: rt5640: Add RL6231 class device shared support for RT5640, RT5645 and RT5651 ASoC: cache: Fix possible ZERO_SIZE_PTR pointer dereferencing error. ASoC: Add helper functions to cast from DAPM context to CODEC/platform ALSA: bebob: sizeof() vs ARRAY_SIZE() typo ASoC: wm9713: correct mono out PGA sources ALSA: synth: emux: soundfont.c: Cleaning up memory leak ASoC: fsl: Remove dependencies of boards for SND_SOC_EUKREA_TLV320 ASoC: fsl-ssi: Use regmap ASoC: fsl-ssi: reorder and document fsl_ssi_private ...
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
@@ -34,8 +35,6 @@
|
||||
#include <sound/opl3.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifdef CONFIG_SND_FM801_TEA575X_BOOL
|
||||
#include <media/tea575x.h>
|
||||
#endif
|
||||
@@ -80,7 +79,10 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers");
|
||||
* Direct registers
|
||||
*/
|
||||
|
||||
#define FM801_REG(chip, reg) (chip->port + FM801_##reg)
|
||||
#define fm801_writew(chip,reg,value) outw((value), chip->port + FM801_##reg)
|
||||
#define fm801_readw(chip,reg) inw(chip->port + FM801_##reg)
|
||||
|
||||
#define fm801_writel(chip,reg,value) outl((value), chip->port + FM801_##reg)
|
||||
|
||||
#define FM801_PCM_VOL 0x00 /* PCM Output Volume */
|
||||
#define FM801_FM_VOL 0x02 /* FM Output Volume */
|
||||
@@ -156,21 +158,27 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers");
|
||||
#define FM801_GPIO_GS3 (1<<15)
|
||||
#define FM801_GPIO_GS(x) (1<<(12+(x)))
|
||||
|
||||
/*
|
||||
|
||||
/**
|
||||
* struct fm801 - describes FM801 chip
|
||||
* @port: I/O port number
|
||||
* @multichannel: multichannel support
|
||||
* @secondary: secondary codec
|
||||
* @secondary_addr: address of the secondary codec
|
||||
* @tea575x_tuner: tuner access method & flags
|
||||
* @ply_ctrl: playback control
|
||||
* @cap_ctrl: capture control
|
||||
*/
|
||||
|
||||
struct fm801 {
|
||||
int irq;
|
||||
|
||||
unsigned long port; /* I/O port number */
|
||||
unsigned int multichannel: 1, /* multichannel support */
|
||||
secondary: 1; /* secondary codec */
|
||||
unsigned char secondary_addr; /* address of the secondary codec */
|
||||
unsigned int tea575x_tuner; /* tuner access method & flags */
|
||||
unsigned long port;
|
||||
unsigned int multichannel: 1,
|
||||
secondary: 1;
|
||||
unsigned char secondary_addr;
|
||||
unsigned int tea575x_tuner;
|
||||
|
||||
unsigned short ply_ctrl; /* playback control */
|
||||
unsigned short cap_ctrl; /* capture control */
|
||||
unsigned short ply_ctrl;
|
||||
unsigned short cap_ctrl;
|
||||
|
||||
unsigned long ply_buffer;
|
||||
unsigned int ply_buf;
|
||||
@@ -222,6 +230,30 @@ MODULE_DEVICE_TABLE(pci, snd_fm801_ids);
|
||||
* common I/O routines
|
||||
*/
|
||||
|
||||
static bool fm801_ac97_is_ready(struct fm801 *chip, unsigned int iterations)
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
for (idx = 0; idx < iterations; idx++) {
|
||||
if (!(fm801_readw(chip, AC97_CMD) & FM801_AC97_BUSY))
|
||||
return true;
|
||||
udelay(10);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool fm801_ac97_is_valid(struct fm801 *chip, unsigned int iterations)
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
for (idx = 0; idx < iterations; idx++) {
|
||||
if (fm801_readw(chip, AC97_CMD) & FM801_AC97_VALID)
|
||||
return true;
|
||||
udelay(10);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg,
|
||||
unsigned short mask, unsigned short value)
|
||||
{
|
||||
@@ -244,73 +276,54 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97,
|
||||
unsigned short val)
|
||||
{
|
||||
struct fm801 *chip = ac97->private_data;
|
||||
int idx;
|
||||
|
||||
/*
|
||||
* Wait until the codec interface is not ready..
|
||||
*/
|
||||
for (idx = 0; idx < 100; idx++) {
|
||||
if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY))
|
||||
goto ok1;
|
||||
udelay(10);
|
||||
if (!fm801_ac97_is_ready(chip, 100)) {
|
||||
dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
|
||||
return;
|
||||
}
|
||||
dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
|
||||
return;
|
||||
|
||||
ok1:
|
||||
/* write data and address */
|
||||
outw(val, FM801_REG(chip, AC97_DATA));
|
||||
outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT), FM801_REG(chip, AC97_CMD));
|
||||
fm801_writew(chip, AC97_DATA, val);
|
||||
fm801_writew(chip, AC97_CMD, reg | (ac97->addr << FM801_AC97_ADDR_SHIFT));
|
||||
/*
|
||||
* Wait until the write command is not completed..
|
||||
*/
|
||||
for (idx = 0; idx < 1000; idx++) {
|
||||
if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY))
|
||||
return;
|
||||
udelay(10);
|
||||
}
|
||||
dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num);
|
||||
*/
|
||||
if (!fm801_ac97_is_ready(chip, 1000))
|
||||
dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n",
|
||||
ac97->num);
|
||||
}
|
||||
|
||||
static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short reg)
|
||||
{
|
||||
struct fm801 *chip = ac97->private_data;
|
||||
int idx;
|
||||
|
||||
/*
|
||||
* Wait until the codec interface is not ready..
|
||||
*/
|
||||
for (idx = 0; idx < 100; idx++) {
|
||||
if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY))
|
||||
goto ok1;
|
||||
udelay(10);
|
||||
if (!fm801_ac97_is_ready(chip, 100)) {
|
||||
dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
|
||||
return 0;
|
||||
}
|
||||
dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
|
||||
return 0;
|
||||
|
||||
ok1:
|
||||
/* read command */
|
||||
outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ,
|
||||
FM801_REG(chip, AC97_CMD));
|
||||
for (idx = 0; idx < 100; idx++) {
|
||||
if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY))
|
||||
goto ok2;
|
||||
udelay(10);
|
||||
fm801_writew(chip, AC97_CMD,
|
||||
reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ);
|
||||
if (!fm801_ac97_is_ready(chip, 100)) {
|
||||
dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n",
|
||||
ac97->num);
|
||||
return 0;
|
||||
}
|
||||
dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num);
|
||||
return 0;
|
||||
|
||||
ok2:
|
||||
for (idx = 0; idx < 1000; idx++) {
|
||||
if (inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_VALID)
|
||||
goto ok3;
|
||||
udelay(10);
|
||||
if (!fm801_ac97_is_valid(chip, 1000)) {
|
||||
dev_err(chip->card->dev,
|
||||
"AC'97 interface #%d is not valid (2)\n", ac97->num);
|
||||
return 0;
|
||||
}
|
||||
dev_err(chip->card->dev, "AC'97 interface #%d is not valid (2)\n", ac97->num);
|
||||
return 0;
|
||||
|
||||
ok3:
|
||||
return inw(FM801_REG(chip, AC97_DATA));
|
||||
return fm801_readw(chip, AC97_DATA);
|
||||
}
|
||||
|
||||
static unsigned int rates[] = {
|
||||
@@ -384,7 +397,7 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream,
|
||||
snd_BUG();
|
||||
return -EINVAL;
|
||||
}
|
||||
outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL));
|
||||
fm801_writew(chip, PLY_CTRL, chip->ply_ctrl);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -419,7 +432,7 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream,
|
||||
snd_BUG();
|
||||
return -EINVAL;
|
||||
}
|
||||
outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL));
|
||||
fm801_writew(chip, CAP_CTRL, chip->cap_ctrl);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -457,12 +470,13 @@ static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream)
|
||||
}
|
||||
chip->ply_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT;
|
||||
chip->ply_buf = 0;
|
||||
outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL));
|
||||
outw(chip->ply_count - 1, FM801_REG(chip, PLY_COUNT));
|
||||
fm801_writew(chip, PLY_CTRL, chip->ply_ctrl);
|
||||
fm801_writew(chip, PLY_COUNT, chip->ply_count - 1);
|
||||
chip->ply_buffer = runtime->dma_addr;
|
||||
chip->ply_pos = 0;
|
||||
outl(chip->ply_buffer, FM801_REG(chip, PLY_BUF1));
|
||||
outl(chip->ply_buffer + (chip->ply_count % chip->ply_size), FM801_REG(chip, PLY_BUF2));
|
||||
fm801_writel(chip, PLY_BUF1, chip->ply_buffer);
|
||||
fm801_writel(chip, PLY_BUF2,
|
||||
chip->ply_buffer + (chip->ply_count % chip->ply_size));
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -483,12 +497,13 @@ static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream)
|
||||
chip->cap_ctrl |= FM801_STEREO;
|
||||
chip->cap_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT;
|
||||
chip->cap_buf = 0;
|
||||
outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL));
|
||||
outw(chip->cap_count - 1, FM801_REG(chip, CAP_COUNT));
|
||||
fm801_writew(chip, CAP_CTRL, chip->cap_ctrl);
|
||||
fm801_writew(chip, CAP_COUNT, chip->cap_count - 1);
|
||||
chip->cap_buffer = runtime->dma_addr;
|
||||
chip->cap_pos = 0;
|
||||
outl(chip->cap_buffer, FM801_REG(chip, CAP_BUF1));
|
||||
outl(chip->cap_buffer + (chip->cap_count % chip->cap_size), FM801_REG(chip, CAP_BUF2));
|
||||
fm801_writel(chip, CAP_BUF1, chip->cap_buffer);
|
||||
fm801_writel(chip, CAP_BUF2,
|
||||
chip->cap_buffer + (chip->cap_count % chip->cap_size));
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -501,8 +516,8 @@ static snd_pcm_uframes_t snd_fm801_playback_pointer(struct snd_pcm_substream *su
|
||||
if (!(chip->ply_ctrl & FM801_START))
|
||||
return 0;
|
||||
spin_lock(&chip->reg_lock);
|
||||
ptr = chip->ply_pos + (chip->ply_count - 1) - inw(FM801_REG(chip, PLY_COUNT));
|
||||
if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_PLAYBACK) {
|
||||
ptr = chip->ply_pos + (chip->ply_count - 1) - fm801_readw(chip, PLY_COUNT);
|
||||
if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_PLAYBACK) {
|
||||
ptr += chip->ply_count;
|
||||
ptr %= chip->ply_size;
|
||||
}
|
||||
@@ -518,8 +533,8 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub
|
||||
if (!(chip->cap_ctrl & FM801_START))
|
||||
return 0;
|
||||
spin_lock(&chip->reg_lock);
|
||||
ptr = chip->cap_pos + (chip->cap_count - 1) - inw(FM801_REG(chip, CAP_COUNT));
|
||||
if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_CAPTURE) {
|
||||
ptr = chip->cap_pos + (chip->cap_count - 1) - fm801_readw(chip, CAP_COUNT);
|
||||
if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_CAPTURE) {
|
||||
ptr += chip->cap_count;
|
||||
ptr %= chip->cap_size;
|
||||
}
|
||||
@@ -533,12 +548,12 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
|
||||
unsigned short status;
|
||||
unsigned int tmp;
|
||||
|
||||
status = inw(FM801_REG(chip, IRQ_STATUS));
|
||||
status = fm801_readw(chip, IRQ_STATUS);
|
||||
status &= FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU|FM801_IRQ_VOLUME;
|
||||
if (! status)
|
||||
return IRQ_NONE;
|
||||
/* ack first */
|
||||
outw(status, FM801_REG(chip, IRQ_STATUS));
|
||||
fm801_writew(chip, IRQ_STATUS, status);
|
||||
if (chip->pcm && (status & FM801_IRQ_PLAYBACK) && chip->playback_substream) {
|
||||
spin_lock(&chip->reg_lock);
|
||||
chip->ply_buf++;
|
||||
@@ -546,10 +561,10 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
|
||||
chip->ply_pos %= chip->ply_size;
|
||||
tmp = chip->ply_pos + chip->ply_count;
|
||||
tmp %= chip->ply_size;
|
||||
outl(chip->ply_buffer + tmp,
|
||||
(chip->ply_buf & 1) ?
|
||||
FM801_REG(chip, PLY_BUF1) :
|
||||
FM801_REG(chip, PLY_BUF2));
|
||||
if (chip->ply_buf & 1)
|
||||
fm801_writel(chip, PLY_BUF1, chip->ply_buffer + tmp);
|
||||
else
|
||||
fm801_writel(chip, PLY_BUF2, chip->ply_buffer + tmp);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
snd_pcm_period_elapsed(chip->playback_substream);
|
||||
}
|
||||
@@ -560,10 +575,10 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
|
||||
chip->cap_pos %= chip->cap_size;
|
||||
tmp = chip->cap_pos + chip->cap_count;
|
||||
tmp %= chip->cap_size;
|
||||
outl(chip->cap_buffer + tmp,
|
||||
(chip->cap_buf & 1) ?
|
||||
FM801_REG(chip, CAP_BUF1) :
|
||||
FM801_REG(chip, CAP_BUF2));
|
||||
if (chip->cap_buf & 1)
|
||||
fm801_writel(chip, CAP_BUF1, chip->cap_buffer + tmp);
|
||||
else
|
||||
fm801_writel(chip, CAP_BUF2, chip->cap_buffer + tmp);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
snd_pcm_period_elapsed(chip->capture_substream);
|
||||
}
|
||||
@@ -747,7 +762,7 @@ static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = {
|
||||
static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
|
||||
{
|
||||
struct fm801 *chip = tea->private_data;
|
||||
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
|
||||
unsigned short reg = fm801_readw(chip, GPIO_CTRL);
|
||||
struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
|
||||
|
||||
reg &= ~(FM801_GPIO_GP(gpio.data) |
|
||||
@@ -759,13 +774,13 @@ static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
|
||||
/* WRITE_ENABLE is inverted */
|
||||
reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren);
|
||||
|
||||
outw(reg, FM801_REG(chip, GPIO_CTRL));
|
||||
fm801_writew(chip, GPIO_CTRL, reg);
|
||||
}
|
||||
|
||||
static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
|
||||
{
|
||||
struct fm801 *chip = tea->private_data;
|
||||
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
|
||||
unsigned short reg = fm801_readw(chip, GPIO_CTRL);
|
||||
struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
|
||||
u8 ret;
|
||||
|
||||
@@ -780,7 +795,7 @@ static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
|
||||
static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output)
|
||||
{
|
||||
struct fm801 *chip = tea->private_data;
|
||||
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
|
||||
unsigned short reg = fm801_readw(chip, GPIO_CTRL);
|
||||
struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
|
||||
|
||||
/* use GPIO lines and set write enable bit */
|
||||
@@ -811,7 +826,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output
|
||||
FM801_GPIO_GP(gpio.clk));
|
||||
}
|
||||
|
||||
outw(reg, FM801_REG(chip, GPIO_CTRL));
|
||||
fm801_writew(chip, GPIO_CTRL, reg);
|
||||
}
|
||||
|
||||
static struct snd_tea575x_ops snd_fm801_tea_ops = {
|
||||
@@ -962,7 +977,7 @@ static int snd_fm801_get_mux(struct snd_kcontrol *kcontrol,
|
||||
struct fm801 *chip = snd_kcontrol_chip(kcontrol);
|
||||
unsigned short val;
|
||||
|
||||
val = inw(FM801_REG(chip, REC_SRC)) & 7;
|
||||
val = fm801_readw(chip, REC_SRC) & 7;
|
||||
if (val > 4)
|
||||
val = 4;
|
||||
ucontrol->value.enumerated.item[0] = val;
|
||||
@@ -1073,12 +1088,12 @@ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id,
|
||||
{
|
||||
unsigned long timeout = jiffies + waits;
|
||||
|
||||
outw(FM801_AC97_READ | (codec_id << FM801_AC97_ADDR_SHIFT) | reg,
|
||||
FM801_REG(chip, AC97_CMD));
|
||||
fm801_writew(chip, AC97_CMD,
|
||||
reg | (codec_id << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ);
|
||||
udelay(5);
|
||||
do {
|
||||
if ((inw(FM801_REG(chip, AC97_CMD)) & (FM801_AC97_VALID|FM801_AC97_BUSY))
|
||||
== FM801_AC97_VALID)
|
||||
if ((fm801_readw(chip, AC97_CMD) &
|
||||
(FM801_AC97_VALID | FM801_AC97_BUSY)) == FM801_AC97_VALID)
|
||||
return 0;
|
||||
schedule_timeout_uninterruptible(1);
|
||||
} while (time_after(timeout, jiffies));
|
||||
@@ -1093,10 +1108,10 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||
goto __ac97_ok;
|
||||
|
||||
/* codec cold reset + AC'97 warm reset */
|
||||
outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL));
|
||||
inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */
|
||||
fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6));
|
||||
fm801_readw(chip, CODEC_CTRL); /* flush posting data */
|
||||
udelay(100);
|
||||
outw(0, FM801_REG(chip, CODEC_CTRL));
|
||||
fm801_writew(chip, CODEC_CTRL, 0);
|
||||
|
||||
if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
|
||||
if (!resume) {
|
||||
@@ -1117,7 +1132,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||
for (i = 3; i > 0; i--) {
|
||||
if (!wait_for_codec(chip, i, AC97_VENDOR_ID1,
|
||||
msecs_to_jiffies(50))) {
|
||||
cmdw = inw(FM801_REG(chip, AC97_DATA));
|
||||
cmdw = fm801_readw(chip, AC97_DATA);
|
||||
if (cmdw != 0xffff && cmdw != 0) {
|
||||
chip->secondary = 1;
|
||||
chip->secondary_addr = i;
|
||||
@@ -1135,23 +1150,24 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
|
||||
__ac97_ok:
|
||||
|
||||
/* init volume */
|
||||
outw(0x0808, FM801_REG(chip, PCM_VOL));
|
||||
outw(0x9f1f, FM801_REG(chip, FM_VOL));
|
||||
outw(0x8808, FM801_REG(chip, I2S_VOL));
|
||||
fm801_writew(chip, PCM_VOL, 0x0808);
|
||||
fm801_writew(chip, FM_VOL, 0x9f1f);
|
||||
fm801_writew(chip, I2S_VOL, 0x8808);
|
||||
|
||||
/* I2S control - I2S mode */
|
||||
outw(0x0003, FM801_REG(chip, I2S_MODE));
|
||||
fm801_writew(chip, I2S_MODE, 0x0003);
|
||||
|
||||
/* interrupt setup */
|
||||
cmdw = inw(FM801_REG(chip, IRQ_MASK));
|
||||
cmdw = fm801_readw(chip, IRQ_MASK);
|
||||
if (chip->irq < 0)
|
||||
cmdw |= 0x00c3; /* mask everything, no PCM nor MPU */
|
||||
else
|
||||
cmdw &= ~0x0083; /* unmask MPU, PLAYBACK & CAPTURE */
|
||||
outw(cmdw, FM801_REG(chip, IRQ_MASK));
|
||||
fm801_writew(chip, IRQ_MASK, cmdw);
|
||||
|
||||
/* interrupt clear */
|
||||
outw(FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU, FM801_REG(chip, IRQ_STATUS));
|
||||
fm801_writew(chip, IRQ_STATUS,
|
||||
FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1165,9 +1181,9 @@ static int snd_fm801_free(struct fm801 *chip)
|
||||
goto __end_hw;
|
||||
|
||||
/* interrupt setup - mask everything */
|
||||
cmdw = inw(FM801_REG(chip, IRQ_MASK));
|
||||
cmdw = fm801_readw(chip, IRQ_MASK);
|
||||
cmdw |= 0x00c3;
|
||||
outw(cmdw, FM801_REG(chip, IRQ_MASK));
|
||||
fm801_writew(chip, IRQ_MASK, cmdw);
|
||||
|
||||
__end_hw:
|
||||
#ifdef CONFIG_SND_FM801_TEA575X_BOOL
|
||||
@@ -1339,15 +1355,15 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
|
||||
return err;
|
||||
}
|
||||
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801,
|
||||
FM801_REG(chip, MPU401_DATA),
|
||||
chip->port + FM801_MPU401_DATA,
|
||||
MPU401_INFO_INTEGRATED |
|
||||
MPU401_INFO_IRQ_HOOK,
|
||||
-1, &chip->rmidi)) < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
if ((err = snd_opl3_create(card, FM801_REG(chip, OPL3_BANK0),
|
||||
FM801_REG(chip, OPL3_BANK1),
|
||||
if ((err = snd_opl3_create(card, chip->port + FM801_OPL3_BANK0,
|
||||
chip->port + FM801_OPL3_BANK1,
|
||||
OPL3_HW_OPL3_FM801, 1, &opl3)) < 0) {
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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++;
|
||||
|
@@ -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 },
|
||||
|
@@ -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
|
||||
|
588
sound/pci/hda/hda_tegra.c
Normal file
588
sound/pci/hda/hda_tegra.c
Normal file
@@ -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");
|
@@ -332,6 +332,7 @@ static const struct hda_fixup ad1986a_fixups[] = {
|
||||
|
||||
static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
|
||||
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
|
||||
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
|
||||
SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
|
||||
|
@@ -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");
|
||||
|
@@ -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 */
|
||||
@@ -1647,12 +1649,10 @@ static const struct hda_fixup alc260_fixups[] = {
|
||||
[ALC260_FIXUP_COEF] = {
|
||||
.type = HDA_FIXUP_VERBS,
|
||||
.v.verbs = (const struct hda_verb[]) {
|
||||
{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
|
||||
{ 0x20, AC_VERB_SET_PROC_COEF, 0x3040 },
|
||||
{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
|
||||
{ 0x1a, AC_VERB_SET_PROC_COEF, 0x3040 },
|
||||
{ }
|
||||
},
|
||||
.chained = true,
|
||||
.chain_id = ALC260_FIXUP_HP_PIN_0F,
|
||||
},
|
||||
[ALC260_FIXUP_GPIO1] = {
|
||||
.type = HDA_FIXUP_VERBS,
|
||||
@@ -1667,8 +1667,8 @@ static const struct hda_fixup alc260_fixups[] = {
|
||||
[ALC260_FIXUP_REPLACER] = {
|
||||
.type = HDA_FIXUP_VERBS,
|
||||
.v.verbs = (const struct hda_verb[]) {
|
||||
{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
|
||||
{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
|
||||
{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
|
||||
{ 0x1a, AC_VERB_SET_PROC_COEF, 0x3050 },
|
||||
{ }
|
||||
},
|
||||
.chained = true,
|
||||
@@ -3522,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);
|
||||
@@ -3538,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);
|
||||
@@ -3561,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);
|
||||
@@ -3576,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);
|
||||
@@ -3591,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);
|
||||
@@ -3598,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);
|
||||
@@ -3608,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);
|
||||
@@ -3620,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 */
|
||||
@@ -3627,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);
|
||||
@@ -3637,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);
|
||||
@@ -3649,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 */
|
||||
@@ -3656,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);
|
||||
@@ -3666,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);
|
||||
@@ -3691,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);
|
||||
@@ -3703,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);
|
||||
@@ -3894,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)
|
||||
{
|
||||
@@ -4110,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,
|
||||
@@ -4159,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[] = {
|
||||
@@ -4213,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,
|
||||
@@ -4552,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[] = {
|
||||
@@ -4595,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),
|
||||
@@ -4629,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),
|
||||
@@ -4702,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),
|
||||
@@ -4715,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),
|
||||
@@ -4793,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)
|
||||
{
|
||||
@@ -4857,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);
|
||||
@@ -5313,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[] = {
|
||||
@@ -5479,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,
|
||||
@@ -5539,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),
|
||||
@@ -5637,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;
|
||||
@@ -5686,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);
|
||||
|
@@ -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;
|
||||
|
@@ -151,7 +151,7 @@ static void lola_proc_codec_rw_write(struct snd_info_entry *entry,
|
||||
char line[64];
|
||||
unsigned int id, verb, data, extdata;
|
||||
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||
if (sscanf(line, "%i %i %i %i", &id, &verb, &data, &extdata) != 4)
|
||||
if (sscanf(line, "%u %u %u %u", &id, &verb, &data, &extdata) != 4)
|
||||
continue;
|
||||
lola_codec_read(chip, id, verb, data, extdata,
|
||||
&chip->debug_res,
|
||||
|
@@ -24,6 +24,7 @@
|
||||
|
||||
/* #define RMH_DEBUG 1 */
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -429,11 +430,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CSES_TIMEOUT 100 /* microseconds */
|
||||
#define CSES_CE 0x0001
|
||||
#define CSES_BROADCAST 0x0002
|
||||
#define CSES_UPDATE_LDSV 0x0004
|
||||
|
||||
#define PIPE_INFO_TO_CMD(capture, pipe) \
|
||||
((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET)
|
||||
|
||||
@@ -519,7 +515,6 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
|
||||
*r_needed += 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
dev_dbg(chip->card->dev,
|
||||
"CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
|
||||
*r_needed, *r_freed);
|
||||
@@ -530,7 +525,6 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
|
||||
chip->rmh.stat[i],
|
||||
chip->rmh.stat[i] & MASK_DATA_SIZE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&chip->msg_lock, flags);
|
||||
@@ -971,9 +965,9 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
|
||||
|
||||
/* interrupt handling */
|
||||
#define PCX_IRQ_NONE 0
|
||||
#define IRQCS_ACTIVE_PCIDB 0x00002000L /* Bit nø 13 */
|
||||
#define IRQCS_ENABLE_PCIIRQ 0x00000100L /* Bit nø 08 */
|
||||
#define IRQCS_ENABLE_PCIDB 0x00000200L /* Bit nø 09 */
|
||||
#define IRQCS_ACTIVE_PCIDB BIT(13)
|
||||
#define IRQCS_ENABLE_PCIIRQ BIT(8)
|
||||
#define IRQCS_ENABLE_PCIDB BIT(9)
|
||||
|
||||
static u32 lx_interrupt_test_ack(struct lx6464es *chip)
|
||||
{
|
||||
@@ -1030,25 +1024,21 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
|
||||
int err;
|
||||
u32 stat[9]; /* answer from CMD_04_GET_EVENT */
|
||||
|
||||
/* On peut optimiser pour ne pas lire les evenements vides
|
||||
* les mots de réponse sont dans l'ordre suivant :
|
||||
* Stat[0] mot de status général
|
||||
* Stat[1] fin de buffer OUT pF
|
||||
* Stat[2] fin de buffer OUT pf
|
||||
* Stat[3] fin de buffer IN pF
|
||||
* Stat[4] fin de buffer IN pf
|
||||
* Stat[5] underrun poid fort
|
||||
* Stat[6] underrun poid faible
|
||||
* Stat[7] overrun poid fort
|
||||
* Stat[8] overrun poid faible
|
||||
/* We can optimize this to not read dumb events.
|
||||
* Answer words are in the following order:
|
||||
* Stat[0] general status
|
||||
* Stat[1] end of buffer OUT pF
|
||||
* Stat[2] end of buffer OUT pf
|
||||
* Stat[3] end of buffer IN pF
|
||||
* Stat[4] end of buffer IN pf
|
||||
* Stat[5] MSB underrun
|
||||
* Stat[6] LSB underrun
|
||||
* Stat[7] MSB overrun
|
||||
* Stat[8] LSB overrun
|
||||
* */
|
||||
|
||||
u64 orun_mask;
|
||||
u64 urun_mask;
|
||||
#if 0
|
||||
int has_underrun = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0;
|
||||
int has_overrun = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0;
|
||||
#endif
|
||||
int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0;
|
||||
int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0;
|
||||
|
||||
@@ -1199,9 +1189,8 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
|
||||
if (irqsrc & MASK_SYS_STATUS_CMD_DONE)
|
||||
goto exit;
|
||||
|
||||
#if 0
|
||||
if (irqsrc & MASK_SYS_STATUS_EOBI)
|
||||
dev_dgg(chip->card->dev, "interrupt: EOBI\n");
|
||||
dev_dbg(chip->card->dev, "interrupt: EOBI\n");
|
||||
|
||||
if (irqsrc & MASK_SYS_STATUS_EOBO)
|
||||
dev_dbg(chip->card->dev, "interrupt: EOBO\n");
|
||||
@@ -1211,7 +1200,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
|
||||
|
||||
if (irqsrc & MASK_SYS_STATUS_ORUN)
|
||||
dev_dbg(chip->card->dev, "interrupt: ORUN\n");
|
||||
#endif
|
||||
|
||||
if (async_pending) {
|
||||
u64 notified_in_pipe_mask = 0;
|
||||
@@ -1238,7 +1226,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
if (async_escmd) {
|
||||
#if 0
|
||||
/* backdoor for ethersound commands
|
||||
*
|
||||
* for now, we do not need this
|
||||
@@ -1246,7 +1233,6 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
|
||||
* */
|
||||
|
||||
dev_dbg(chip->card->dev, "interrupt requests escmd handling\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
exit:
|
||||
|
Reference in New Issue
Block a user