diff options
Diffstat (limited to 'sound/pci')
72 files changed, 717 insertions, 219 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index d37c683cfd7..445ca481d8d 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1296,7 +1296,7 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, struct snd_ac97 *ac97) { int err; - char name[44]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; unsigned char lo_max, hi_max; if (! snd_ac97_valid_reg(ac97, reg)) diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index ad8a3117393..d2b9d617aee 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -1046,7 +1046,6 @@ static void snd_ad1889_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 53754f5edeb..3dfa12b670e 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -2298,7 +2298,6 @@ static int snd_ali_probe(struct pci_dev *pci, static void snd_ali_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver ali5451_driver = { diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 864c4310366..591efb6eef0 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -282,7 +282,6 @@ static void snd_als300_remove(struct pci_dev *pci) { snd_als300_dbgcallenter(); snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); snd_als300_dbgcallleave(); } diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 61efda2a4d9..ffc821b0139 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -984,7 +984,6 @@ out: static void snd_card_als4000_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index fbc17203613..185d54a5cb1 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -1278,7 +1278,7 @@ struct hpi_control { u16 dst_node_type; u16 dst_node_index; u16 band; - char name[44]; /* copied to snd_ctl_elem_id.name[44]; */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* copied to snd_ctl_elem_id.name[44]; */ }; static const char * const asihpi_tuner_band_names[] = { diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index ef5019fe519..7f0272032fb 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -445,7 +445,6 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) if (pa->p_buffer) vfree(pa->p_buffer); - pci_set_drvdata(pci_dev, NULL); if (1) dev_info(&pci_dev->dev, "remove %04x:%04x,%04x:%04x,%04x, HPI index %d\n", diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 6e78c678985..fe4c61bdb8b 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1714,7 +1714,6 @@ static int snd_atiixp_probe(struct pci_dev *pci, static void snd_atiixp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver atiixp_driver = { diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index d0bec7ba3b0..cf29b9a1d65 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1334,7 +1334,6 @@ static int snd_atiixp_probe(struct pci_dev *pci, static void snd_atiixp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver atiixp_modem_driver = { diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index b157e1fadd8..7059dd69e5e 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -371,7 +371,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) static void snd_vortex_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } // pci_driver definition diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 08e9a4702cb..2925220d3fc 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -392,7 +392,6 @@ static int snd_aw2_probe(struct pci_dev *pci, static void snd_aw2_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } /* open callback */ diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 1204a0fa336..c8e12161159 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -2725,7 +2725,6 @@ snd_azf3328_remove(struct pci_dev *pci) { snd_azf3328_dbgcallenter(); snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); snd_azf3328_dbgcallleave(); } diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 9febe550974..18802039497 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -953,7 +953,6 @@ _error: static void snd_bt87x_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } /* default entries for all Bt87x cards - it's not exported */ diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 1610a570597..f4db5587e86 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1896,7 +1896,6 @@ static int snd_ca0106_probe(struct pci_dev *pci, static void snd_ca0106_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index c617435db6e..2755ec5bcc2 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -3317,7 +3317,6 @@ static int snd_cmipci_probe(struct pci_dev *pci, static void snd_cmipci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 6a869506994..1dc793e742d 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1312,7 +1312,7 @@ static int snd_cs4281_free(struct cs4281 *chip) /* Sound System Power Management - Turn Everything OFF */ snd_cs4281_pokeBA0(chip, BA0_SSPM, 0); /* PCI interface - D3 state */ - pci_set_power_state(chip->pci, 3); + pci_set_power_state(chip->pci, PCI_D3hot); if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1971,7 +1971,6 @@ static int snd_cs4281_probe(struct pci_dev *pci, static void snd_cs4281_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } /* diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 6b0d8b50a30..b03498325d6 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -158,7 +158,6 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, static void snd_card_cs46xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver cs46xx_driver = { diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index dace827b45d..c6b82c85e04 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -91,7 +91,6 @@ static int snd_cs5530_dev_free(struct snd_device *device) static void snd_cs5530_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg) diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 7e4b13e2d12..902bebd3b3f 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -391,7 +391,6 @@ static void snd_cs5535audio_remove(struct pci_dev *pci) { olpc_quirks_cleanup(); snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver cs5535audio_driver = { diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index d01ffcb2b2f..d464ad2fc7b 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -122,7 +122,6 @@ error: static void ct_card_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 760cbff5321..05cfe551ce4 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -2323,7 +2323,6 @@ static void snd_echo_remove(struct pci_dev *pci) chip = pci_get_drvdata(pci); if (chip) snd_card_free(chip->card); - pci_set_drvdata(pci, NULL); } diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 8c5010f7889..9e1bd0c39a8 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -202,7 +202,6 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, static void snd_card_emu10k1_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index cdff11d48eb..56ad9d6f200 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1623,7 +1623,6 @@ static int snd_emu10k1x_probe(struct pci_dev *pci, static void snd_emu10k1x_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } // PCI IDs diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index db2dc835171..ca8929b9a5d 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1939,7 +1939,7 @@ static int snd_ensoniq_free(struct ensoniq *ensoniq) #endif if (ensoniq->irq >= 0) synchronize_irq(ensoniq->irq); - pci_set_power_state(ensoniq->pci, 3); + pci_set_power_state(ensoniq->pci, PCI_D3hot); __hw_end: #ifdef CHIP1370 if (ensoniq->dma_bug.area) @@ -2497,7 +2497,6 @@ static int snd_audiopci_probe(struct pci_dev *pci, static void snd_audiopci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver ens137x_driver = { diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 8423403954a..9213fb38921 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1881,7 +1881,6 @@ static int snd_es1938_probe(struct pci_dev *pci, static void snd_es1938_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver es1938_driver = { diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index a1f32b5ae0d..5e2ec968773 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -564,6 +564,7 @@ struct es1968 { #ifdef CONFIG_SND_ES1968_RADIO struct v4l2_device v4l2_dev; struct snd_tea575x tea; + unsigned int tea575x_tuner; #endif }; @@ -2557,37 +2558,47 @@ static int snd_es1968_input_register(struct es1968 *chip) bits 1=unmask write to given bit */ #define IO_DIR 8 /* direction register offset from GPIO_DATA bits 0/1=read/write direction */ -/* mask bits for GPIO lines */ -#define STR_DATA 0x0040 /* GPIO6 */ -#define STR_CLK 0x0080 /* GPIO7 */ -#define STR_WREN 0x0100 /* GPIO8 */ -#define STR_MOST 0x0200 /* GPIO9 */ + +/* GPIO to TEA575x maps */ +struct snd_es1968_tea575x_gpio { + u8 data, clk, wren, most; + char *name; +}; + +static struct snd_es1968_tea575x_gpio snd_es1968_tea575x_gpios[] = { + { .data = 6, .clk = 7, .wren = 8, .most = 9, .name = "SF64-PCE2" }, + { .data = 7, .clk = 8, .wren = 6, .most = 10, .name = "M56VAP" }, +}; + +#define get_tea575x_gpio(chip) \ + (&snd_es1968_tea575x_gpios[(chip)->tea575x_tuner]) + static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) { struct es1968 *chip = tea->private_data; - unsigned long io = chip->io_port + GPIO_DATA; + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip); u16 val = 0; - val |= (pins & TEA575X_DATA) ? STR_DATA : 0; - val |= (pins & TEA575X_CLK) ? STR_CLK : 0; - val |= (pins & TEA575X_WREN) ? STR_WREN : 0; + val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0; + val |= (pins & TEA575X_CLK) ? (1 << gpio.clk) : 0; + val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0; - outw(val, io); + outw(val, chip->io_port + GPIO_DATA); } static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea) { struct es1968 *chip = tea->private_data; - unsigned long io = chip->io_port + GPIO_DATA; - u16 val = inw(io); - u8 ret; + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip); + u16 val = inw(chip->io_port + GPIO_DATA); + u8 ret = 0; - ret = 0; - if (val & STR_DATA) + if (val & (1 << gpio.data)) ret |= TEA575X_DATA; - if (val & STR_MOST) + if (val & (1 << gpio.most)) ret |= TEA575X_MOST; + return ret; } @@ -2596,13 +2607,18 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu struct es1968 *chip = tea->private_data; unsigned long io = chip->io_port + GPIO_DATA; u16 odir = inw(io + IO_DIR); + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip); if (output) { - outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); - outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR); + outw(~((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren)), + io + IO_MASK); + outw(odir | (1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren), + io + IO_DIR); } else { - outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK); - outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR); + outw(~((1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) | (1 << gpio.most)), + io + IO_MASK); + outw((odir & ~((1 << gpio.data) | (1 << gpio.most))) + | (1 << gpio.clk) | (1 << gpio.wren), io + IO_DIR); } } @@ -2772,6 +2788,9 @@ static int snd_es1968_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); #ifdef CONFIG_SND_ES1968_RADIO + /* don't play with GPIOs on laptops */ + if (chip->pci->subsystem_vendor != 0x125d) + goto no_radio; err = v4l2_device_register(&pci->dev, &chip->v4l2_dev); if (err < 0) { snd_es1968_free(chip); @@ -2781,10 +2800,18 @@ static int snd_es1968_create(struct snd_card *card, chip->tea.private_data = chip; chip->tea.radio_nr = radio_nr; chip->tea.ops = &snd_es1968_tea_ops; - strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card)); sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); - if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) - printk(KERN_INFO "es1968: detected TEA575x radio\n"); + for (i = 0; i < ARRAY_SIZE(snd_es1968_tea575x_gpios); i++) { + chip->tea575x_tuner = i; + if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) { + snd_printk(KERN_INFO "es1968: detected TEA575x radio type %s\n", + get_tea575x_gpio(chip)->name); + strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name, + sizeof(chip->tea.card)); + break; + } + } +no_radio: #endif *chip_ret = chip; @@ -2909,7 +2936,6 @@ static int snd_es1968_probe(struct pci_dev *pci, static void snd_es1968_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver es1968_driver = { diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 4f07fda5adf..706c5b67b70 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1370,7 +1370,6 @@ static int snd_card_fm801_probe(struct pci_dev *pci, static void snd_card_fm801_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 80a7d44bcf8..59c5e9c03d5 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -140,7 +140,6 @@ config SND_HDA_CODEC_VIA config SND_HDA_CODEC_HDMI bool "Build HDMI/DisplayPort HD-audio codec support" - select SND_DYNAMIC_MINORS default y help Say Y here to include HDMI and DisplayPort HD-audio codec @@ -152,6 +151,16 @@ config SND_HDA_CODEC_HDMI snd-hda-codec-hdmi. This module is automatically loaded at probing. +config SND_HDA_I915 + bool "Build Display HD-audio controller/codec power well support for i915 cards" + depends on DRM_I915 + help + Say Y here to include full HDMI and DisplayPort HD-audio controller/codec + power-well support for Intel Haswell graphics cards based on the i915 driver. + + Note that this option must be enabled for Intel Haswell C+ stepping machines, otherwise + the GPU audio controller/codecs will not be initialized or damaged when exit from S3 mode. + config SND_HDA_CODEC_CIRRUS bool "Build Cirrus Logic codec support" default y diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 24a251497a1..c091438286a 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,4 +1,6 @@ snd-hda-intel-objs := hda_intel.o +# for haswell power well +snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 55108b5fb29..8a005f0e5ca 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -185,20 +185,19 @@ EXPORT_SYMBOL_HDA(snd_hda_get_jack_type); * Compose a 32bit command word to be sent to the HD-audio controller */ static inline unsigned int -make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, +make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags, unsigned int verb, unsigned int parm) { u32 val; - if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) || + if ((codec->addr & ~0xf) || (nid & ~0x7f) || (verb & ~0xfff) || (parm & ~0xffff)) { - printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n", - codec->addr, direct, nid, verb, parm); + printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x\n", + codec->addr, nid, verb, parm); return ~0; } val = (u32)codec->addr << 28; - val |= (u32)direct << 27; val |= (u32)nid << 20; val |= verb << 8; val |= parm; @@ -209,7 +208,7 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, * Send and receive a verb */ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, - unsigned int *res) + int flags, unsigned int *res) { struct hda_bus *bus = codec->bus; int err; @@ -222,6 +221,8 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, again: snd_hda_power_up(codec); mutex_lock(&bus->cmd_mutex); + if (flags & HDA_RW_NO_RESPONSE_FALLBACK) + bus->no_response_fallback = 1; for (;;) { trace_hda_send_cmd(codec, cmd); err = bus->ops.command(bus, cmd); @@ -234,6 +235,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, *res = bus->ops.get_response(bus, codec->addr); trace_hda_get_response(codec, *res); } + bus->no_response_fallback = 0; mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) { @@ -255,7 +257,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec * @nid: NID to send the command - * @direct: direct flag + * @flags: optional bit flags * @verb: the verb to send * @parm: the parameter for the verb * @@ -264,12 +266,12 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, * Returns the obtained response value, or -1 for an error. */ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, - int direct, + int flags, unsigned int verb, unsigned int parm) { - unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); + unsigned cmd = make_codec_cmd(codec, nid, flags, verb, parm); unsigned int res; - if (codec_exec_verb(codec, cmd, &res)) + if (codec_exec_verb(codec, cmd, flags, &res)) return -1; return res; } @@ -279,7 +281,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read); * snd_hda_codec_write - send a single command without waiting for response * @codec: the HDA codec * @nid: NID to send the command - * @direct: direct flag + * @flags: optional bit flags * @verb: the verb to send * @parm: the parameter for the verb * @@ -287,12 +289,12 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read); * * Returns 0 if successful, or a negative error code. */ -int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm) +int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags, + unsigned int verb, unsigned int parm) { - unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); + unsigned int cmd = make_codec_cmd(codec, nid, flags, verb, parm); unsigned int res; - return codec_exec_verb(codec, cmd, + return codec_exec_verb(codec, cmd, flags, codec->bus->sync_write ? &res : NULL); } EXPORT_SYMBOL_HDA(snd_hda_codec_write); @@ -2523,7 +2525,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) flush_workqueue(bus->workq); #endif snd_hda_ctls_clear(codec); - /* relase PCMs */ + /* release PCMs */ for (i = 0; i < codec->num_pcms; i++) { if (codec->pcm_info[i].pcm) { snd_device_free(card, codec->pcm_info[i].pcm); @@ -3582,7 +3584,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); * snd_hda_codec_write_cache - send a single command with caching * @codec: the HDA codec * @nid: NID to send the command - * @direct: direct flag + * @flags: optional bit flags * @verb: the verb to send * @parm: the parameter for the verb * @@ -3591,7 +3593,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); * Returns 0 if successful, or a negative error code. */ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, unsigned int parm) + int flags, unsigned int verb, unsigned int parm) { int err; struct hda_cache_head *c; @@ -3600,7 +3602,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, cache_only = codec->cached_write; if (!cache_only) { - err = snd_hda_codec_write(codec, nid, direct, verb, parm); + err = snd_hda_codec_write(codec, nid, flags, verb, parm); if (err < 0) return err; } @@ -3624,7 +3626,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); * snd_hda_codec_update_cache - check cache and write the cmd only when needed * @codec: the HDA codec * @nid: NID to send the command - * @direct: direct flag + * @flags: optional bit flags * @verb: the verb to send * @parm: the parameter for the verb * @@ -3635,7 +3637,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); * Returns 0 if successful, or a negative error code. */ int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, unsigned int parm) + int flags, unsigned int verb, unsigned int parm) { struct hda_cache_head *c; u32 key; @@ -3651,7 +3653,7 @@ int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, return 0; } mutex_unlock(&codec->bus->cmd_mutex); - return snd_hda_codec_write_cache(codec, nid, direct, verb, parm); + return snd_hda_codec_write_cache(codec, nid, flags, verb, parm); } EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache); @@ -3806,11 +3808,13 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, hda_nid_t fg = codec->afg ? codec->afg : codec->mfg; int count; unsigned int state; + int flags = 0; /* this delay seems necessary to avoid click noise at power-down */ if (power_state == AC_PWRST_D3) { /* transition time less than 10ms for power down */ msleep(codec->epss ? 10 : 100); + flags = HDA_RW_NO_RESPONSE_FALLBACK; } /* repeat power states setting at most 10 times*/ @@ -3819,7 +3823,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, codec->patch_ops.set_power_state(codec, fg, power_state); else { - snd_hda_codec_read(codec, fg, 0, + snd_hda_codec_read(codec, fg, flags, AC_VERB_SET_POWER_STATE, power_state); snd_hda_codec_set_power_to_all(codec, fg, power_state); @@ -4461,12 +4465,13 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { /* * get the empty PCM device number to assign - * - * note the max device number is limited by HDA_MAX_PCMS, currently 10 */ -static int get_empty_pcm_device(struct hda_bus *bus, int type) +static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type) { /* audio device indices; not linear to keep compatibility */ + /* assigned to static slots up to dev#10; if more needed, assign + * the later slot dynamically (when CONFIG_SND_DYNAMIC_MINORS=y) + */ static int audio_idx[HDA_PCM_NTYPES][5] = { [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 }, [HDA_PCM_TYPE_SPDIF] = { 1, -1 }, @@ -4480,18 +4485,28 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) return -EINVAL; } - for (i = 0; audio_idx[type][i] >= 0 ; i++) + for (i = 0; audio_idx[type][i] >= 0; i++) { +#ifndef CONFIG_SND_DYNAMIC_MINORS + if (audio_idx[type][i] >= 8) + break; +#endif if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits)) return audio_idx[type][i]; + } +#ifdef CONFIG_SND_DYNAMIC_MINORS /* non-fixed slots starting from 10 */ for (i = 10; i < 32; i++) { if (!test_and_set_bit(i, bus->pcm_dev_bits)) return i; } +#endif snd_printk(KERN_WARNING "Too many %s devices\n", snd_hda_pcm_type_name[type]); +#ifndef CONFIG_SND_DYNAMIC_MINORS + snd_printk(KERN_WARNING "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n"); +#endif return -EAGAIN; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c93f9021f45..701c2e069b1 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -679,6 +679,7 @@ struct hda_bus { unsigned int response_reset:1; /* controller was reset */ unsigned int in_reset:1; /* during reset operation */ unsigned int power_keep_link_on:1; /* don't power off HDA link */ + unsigned int no_response_fallback:1; /* don't fallback at RIRB error */ int primary_dig_out_type; /* primary digital out PCM type */ }; @@ -930,6 +931,8 @@ enum { HDA_INPUT, HDA_OUTPUT }; +/* snd_hda_codec_read/write optional flags */ +#define HDA_RW_NO_RESPONSE_FALLBACK (1 << 0) /* * constructors @@ -945,9 +948,9 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec); * low level functions */ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, - int direct, + int flags, unsigned int verb, unsigned int parm); -int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, +int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags, unsigned int verb, unsigned int parm); #define snd_hda_param_read(codec, nid, param) \ snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) @@ -986,11 +989,11 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); /* cached write */ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, unsigned int parm); + int flags, unsigned int verb, unsigned int parm); void snd_hda_sequence_write_cache(struct hda_codec *codec, const struct hda_verb *seq); int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, unsigned int parm); + int flags, unsigned int verb, unsigned int parm); void snd_hda_codec_resume_cache(struct hda_codec *codec); /* both for cmd & amp caches */ void snd_hda_codec_flush_cache(struct hda_codec *codec); diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 4b1524a861f..8e77cbbad87 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -133,6 +133,9 @@ static void parse_user_hints(struct hda_codec *codec) val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); if (val >= 0) spec->line_in_auto_switch = !!val; + val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp"); + if (val >= 0) + spec->auto_mute_via_amp = !!val; val = snd_hda_get_bool_hint(codec, "need_dac_fix"); if (val >= 0) spec->need_dac_fix = !!val; @@ -808,6 +811,9 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx) * Helper functions for creating mixer ctl elements */ +static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + enum { HDA_CTL_WIDGET_VOL, HDA_CTL_WIDGET_MUTE, @@ -815,7 +821,15 @@ enum { }; static const struct snd_kcontrol_new control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), + /* only the put callback is replaced for handling the special mute */ + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = hda_gen_mixer_mute_put, /* replaced */ + .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), + }, HDA_BIND_MUTE(NULL, 0, 0, 0), }; @@ -840,7 +854,7 @@ static int add_control_with_pfx(struct hda_gen_spec *spec, int type, const char *pfx, const char *dir, const char *sfx, int cidx, unsigned long val) { - char name[32]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); if (!add_control(spec, type, name, cidx, val)) return -ENOMEM; @@ -922,6 +936,23 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx, return add_sw_ctl(codec, pfx, cidx, chs, path); } +/* playback mute control with the software mute bit check */ +static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + + if (spec->auto_mute_via_amp) { + hda_nid_t nid = get_amp_nid(kcontrol); + bool enabled = !((spec->mute_bits >> nid) & 1); + ucontrol->value.integer.value[0] &= enabled; + ucontrol->value.integer.value[1] &= enabled; + } + + return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); +} + /* any ctl assigned to the path with the given index? */ static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) { @@ -1900,7 +1931,7 @@ static int create_extra_outs(struct hda_codec *codec, int num_pins, for (i = 0; i < num_pins; i++) { const char *name; - char tmp[44]; + char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int err, idx = 0; if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) @@ -2453,7 +2484,7 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins, } if (get_out_jack_num_items(codec, pin) > 1) { struct snd_kcontrol_new *knew; - char name[44]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; get_jack_mode_name(codec, pin, name, sizeof(name)); knew = snd_hda_gen_add_kctl(spec, name, &out_jack_mode_enum); @@ -2585,7 +2616,7 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) { struct hda_gen_spec *spec = codec->spec; struct snd_kcontrol_new *knew; - char name[44]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; unsigned int defcfg; if (pin == spec->hp_mic_pin) @@ -3285,7 +3316,7 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label, bool inv_dmic) { struct hda_gen_spec *spec = codec->spec; - char tmpname[44]; + char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; const char *sfx = is_switch ? "Switch" : "Volume"; unsigned int chs = inv_dmic ? 1 : 3; @@ -3547,7 +3578,7 @@ static int parse_mic_boost(struct hda_codec *codec) struct nid_path *path; unsigned int val; int idx; - char boost_label[44]; + char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; idx = imux->items[i].index; if (idx >= imux->num_items) @@ -3719,6 +3750,16 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, unsigned int val, oldval; if (!nid) break; + + if (spec->auto_mute_via_amp) { + if (mute) + spec->mute_bits |= (1ULL << nid); + else + spec->mute_bits &= ~(1ULL << nid); + set_pin_eapd(codec, nid, !mute); + continue; + } + oldval = snd_hda_codec_get_pin_target(codec, nid); if (oldval & PIN_IN) continue; /* no mute for inputs */ @@ -3786,6 +3827,10 @@ static void call_update_outputs(struct hda_codec *codec) spec->automute_hook(codec); else snd_hda_gen_update_outputs(codec); + + /* sync the whole vmaster slaves to reflect the new auto-mute status */ + if (spec->auto_mute_via_amp && !codec->bus->shutdown) + snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); } /* standard HP-automute helper */ diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 76200314ee9..e199a852388 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -209,6 +209,7 @@ struct hda_gen_spec { unsigned int master_mute:1; /* master mute over all */ unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ unsigned int line_in_auto_switch:1; /* allow line-in auto switch */ + unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */ /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */ unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */ @@ -237,6 +238,9 @@ struct hda_gen_spec { unsigned int have_aamix_ctl:1; unsigned int hp_mic_jack_modes:1; + /* additional mute flags (only effective with auto_mute_via_amp=1) */ + u64 mute_bits; + /* badness tables for output path evaluations */ const struct badness_table *main_out_badness; const struct badness_table *extra_out_badness; diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c new file mode 100644 index 00000000000..76c13d5b3ca --- /dev/null +++ b/sound/pci/hda/hda_i915.c @@ -0,0 +1,75 @@ +/* + * hda_i915.c - routines for Haswell HDA controller power well support + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <sound/core.h> +#include <drm/i915_powerwell.h> +#include "hda_i915.h" + +static void (*get_power)(void); +static void (*put_power)(void); + +void hda_display_power(bool enable) +{ + if (!get_power || !put_power) + return; + + snd_printdd("HDA display power %s \n", + enable ? "Enable" : "Disable"); + if (enable) + get_power(); + else + put_power(); +} + +int hda_i915_init(void) +{ + int err = 0; + + get_power = symbol_request(i915_request_power_well); + if (!get_power) { + snd_printk(KERN_WARNING "hda-i915: get_power symbol get fail\n"); + return -ENODEV; + } + + put_power = symbol_request(i915_release_power_well); + if (!put_power) { + symbol_put(i915_request_power_well); + get_power = NULL; + return -ENODEV; + } + + snd_printd("HDA driver get symbol successfully from i915 module\n"); + + return err; +} + +int hda_i915_exit(void) +{ + if (get_power) { + symbol_put(i915_request_power_well); + get_power = NULL; + } + if (put_power) { + symbol_put(i915_release_power_well); + put_power = NULL; + } + + return 0; +} diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h new file mode 100644 index 00000000000..5a63da2c53e --- /dev/null +++ b/sound/pci/hda/hda_i915.h @@ -0,0 +1,35 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __SOUND_HDA_I915_H +#define __SOUND_HDA_I915_H + +#ifdef CONFIG_SND_HDA_I915 +void hda_display_power(bool enable); +int hda_i915_init(void); +int hda_i915_exit(void); +#else +static inline void hda_display_power(bool enable) {} +static inline int hda_i915_init(void) +{ + return -ENODEV; +} +static inline int hda_i915_exit(void) +{ + return 0; +} +#endif + +#endif diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index de18722c487..8860dd52952 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -62,6 +62,7 @@ #include <linux/vga_switcheroo.h> #include <linux/firmware.h> #include "hda_codec.h" +#include "hda_i915.h" static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; @@ -541,6 +542,10 @@ struct azx { /* for pending irqs */ struct work_struct irq_pending_work; +#ifdef CONFIG_SND_HDA_I915 + struct work_struct probe_work; +#endif + /* reboot notifier (for mysterious hangup problem at power-down) */ struct notifier_block reboot_notifier; @@ -594,6 +599,7 @@ enum { #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ +#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 power well support */ /* quirks for Intel PCH */ #define AZX_DCAPS_INTEL_PCH_NOPM \ @@ -942,6 +948,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, } } + if (!bus->no_response_fallback) + return -1; + if (!chip->polling_mode && chip->poll_count < 2) { snd_printdd(SFX "%s: azx_get_response timeout, " "polling the codec once: last cmd=0x%08x\n", @@ -1117,37 +1126,52 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus, struct snd_dma_buffer *dmab); #endif -/* reset codec link */ -static int azx_reset(struct azx *chip, int full_reset) +/* enter link reset */ +static void azx_enter_link_reset(struct azx *chip) { unsigned long timeout; - if (!full_reset) - goto __skip; - - /* clear STATESTS */ - azx_writeb(chip, STATESTS, STATESTS_INT_MASK); - /* reset controller */ azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); - while (azx_readb(chip, GCTL) && + while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) && time_before(jiffies, timeout)) usleep_range(500, 1000); +} - /* delay for >= 100us for codec PLL to settle per spec - * Rev 0.9 section 5.5.1 - */ - usleep_range(500, 1000); +/* exit link reset */ +static void azx_exit_link_reset(struct azx *chip) +{ + unsigned long timeout; - /* Bring controller out of reset */ azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); while (!azx_readb(chip, GCTL) && time_before(jiffies, timeout)) usleep_range(500, 1000); +} + +/* reset codec link */ +static int azx_reset(struct azx *chip, int full_reset) +{ + if (!full_reset) + goto __skip; + + /* clear STATESTS */ + azx_writeb(chip, STATESTS, STATESTS_INT_MASK); + + /* reset controller */ + azx_enter_link_reset(chip); + + /* delay for >= 100us for codec PLL to settle per spec + * Rev 0.9 section 5.5.1 + */ + usleep_range(500, 1000); + + /* Bring controller out of reset */ + azx_exit_link_reset(chip); /* Brent Chartrand said to wait >= 540us for codecs to initialize */ usleep_range(1000, 1200); @@ -2891,6 +2915,7 @@ static int azx_suspend(struct device *dev) if (chip->initialized) snd_hda_suspend(chip->bus); azx_stop_chip(chip); + azx_enter_link_reset(chip); if (chip->irq >= 0) { free_irq(chip->irq, chip); chip->irq = -1; @@ -2900,6 +2925,8 @@ static int azx_suspend(struct device *dev) pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, PCI_D3hot); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + hda_display_power(false); return 0; } @@ -2912,6 +2939,8 @@ static int azx_resume(struct device *dev) if (chip->disabled) return 0; + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + hda_display_power(true); pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { @@ -2943,7 +2972,10 @@ static int azx_runtime_suspend(struct device *dev) struct azx *chip = card->private_data; azx_stop_chip(chip); + azx_enter_link_reset(chip); azx_clear_irq_pending(chip); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + hda_display_power(false); return 0; } @@ -2952,6 +2984,8 @@ static int azx_runtime_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + hda_display_power(true); azx_init_pci(chip); azx_init_chip(chip, 1); return 0; @@ -3006,7 +3040,6 @@ static void azx_notifier_unregister(struct azx *chip) unregister_reboot_notifier(&chip->reboot_notifier); } -static int azx_first_init(struct azx *chip); static int azx_probe_continue(struct azx *chip); #ifdef SUPPORT_VGA_SWITCHEROO @@ -3033,8 +3066,7 @@ static void azx_vs_set_state(struct pci_dev *pci, snd_printk(KERN_INFO SFX "%s: Start delayed initialization\n", pci_name(chip->pci)); - if (azx_first_init(chip) < 0 || - azx_probe_continue(chip) < 0) { + if (azx_probe_continue(chip) < 0) { snd_printk(KERN_ERR SFX "%s: initialization error\n", pci_name(chip->pci)); @@ -3120,8 +3152,13 @@ static int register_vga_switcheroo(struct azx *chip) */ static int azx_free(struct azx *chip) { + struct pci_dev *pci = chip->pci; int i; + if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) + && chip->running) + pm_runtime_get_noresume(&pci->dev); + azx_del_card_list(chip); azx_notifier_unregister(chip); @@ -3173,6 +3210,10 @@ static int azx_free(struct azx *chip) if (chip->fw) release_firmware(chip->fw); #endif + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + hda_display_power(false); + hda_i915_exit(); + } kfree(chip); return 0; @@ -3398,6 +3439,13 @@ static void azx_check_snoop_available(struct azx *chip) } } +#ifdef CONFIG_SND_HDA_I915 +static void azx_probe_work(struct work_struct *work) +{ + azx_probe_continue(container_of(work, struct azx, probe_work)); +} +#endif + /* * constructor */ @@ -3473,7 +3521,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, return err; } +#ifdef CONFIG_SND_HDA_I915 + /* continue probing in work context as may trigger request module */ + INIT_WORK(&chip->probe_work, azx_probe_work); +#endif + *rchip = chip; + return 0; } @@ -3730,11 +3784,6 @@ static int azx_probe(struct pci_dev *pci, } probe_now = !chip->disabled; - if (probe_now) { - err = azx_first_init(chip); - if (err < 0) - goto out_free; - } #ifdef CONFIG_SND_HDA_PATCH_LOADER if (patch[dev] && *patch[dev]) { @@ -3749,30 +3798,51 @@ static int azx_probe(struct pci_dev *pci, } #endif /* CONFIG_SND_HDA_PATCH_LOADER */ + /* continue probing in work context, avoid request_module deadlock */ + if (probe_now && (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)) { +#ifdef CONFIG_SND_HDA_I915 + probe_now = false; + schedule_work(&chip->probe_work); +#else + snd_printk(KERN_ERR SFX "Haswell must build in CONFIG_SND_HDA_I915\n"); +#endif + } + if (probe_now) { err = azx_probe_continue(chip); if (err < 0) goto out_free; } - if (pci_dev_run_wake(pci)) - pm_runtime_put_noidle(&pci->dev); - dev++; complete_all(&chip->probe_wait); return 0; out_free: snd_card_free(card); - pci_set_drvdata(pci, NULL); return err; } static int azx_probe_continue(struct azx *chip) { + struct pci_dev *pci = chip->pci; int dev = chip->dev_index; int err; + /* Request power well for Haswell HDA controller and codec */ + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + err = hda_i915_init(); + if (err < 0) { + snd_printk(KERN_ERR SFX "Error request power-well from i915\n"); + goto out_free; + } + hda_display_power(true); + } + + err = azx_first_init(chip); + if (err < 0) + goto out_free; + #ifdef CONFIG_SND_HDA_INPUT_BEEP chip->beep_mode = beep_mode[dev]; #endif @@ -3817,6 +3887,8 @@ static int azx_probe_continue(struct azx *chip) power_down_all_codecs(chip); azx_notifier_register(chip); azx_add_card_list(chip); + if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME) + pm_runtime_put_noidle(&pci->dev); return 0; @@ -3829,12 +3901,8 @@ static void azx_remove(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); - if (pci_dev_run_wake(pci)) - pm_runtime_get_noresume(&pci->dev); - if (card) snd_card_free(card); - pci_set_drvdata(pci, NULL); } /* PCI IDs */ @@ -3864,11 +3932,14 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0a0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH | + AZX_DCAPS_I915_POWERWELL }, { PCI_DEVICE(0x8086, 0x0c0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH | + AZX_DCAPS_I915_POWERWELL }, { PCI_DEVICE(0x8086, 0x0d0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH | + AZX_DCAPS_I915_POWERWELL }, /* 5 Series/3400 */ { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, @@ -3878,6 +3949,9 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* Oaktrail */ { PCI_DEVICE(0x8086, 0x080a), .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + /* BayTrail */ + { PCI_DEVICE(0x8086, 0x0f04), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* ICH */ { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 9e0a95288f4..3fd2973183e 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -398,7 +398,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, const char *base_name) { unsigned int def_conf, conn; - char name[44]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int idx, err; bool phantom_jack; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index e0bf7534fa1..2e7493ef8ee 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -562,6 +562,14 @@ static inline unsigned int get_wcaps_channels(u32 wcaps) return chans; } +static inline void snd_hda_override_wcaps(struct hda_codec *codec, + hda_nid_t nid, u32 val) +{ + if (nid >= codec->start_nid && + nid < codec->start_nid + codec->num_nodes) + codec->wcaps[nid - codec->start_nid] = val; +} + u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); @@ -667,7 +675,7 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid, if (state & AC_PWRST_ERROR) return true; state = (state >> 4) & 0x0f; - return (state != target_state); + return (state == target_state); } unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 0fee8fae590..9760f001916 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -504,6 +504,8 @@ static void print_conn_list(struct snd_info_buffer *buffer, int conn_len) { int c, curr = -1; + const hda_nid_t *list; + int cache_len; if (conn_len > 1 && wid_type != AC_WID_AUD_MIX && @@ -521,6 +523,19 @@ static void print_conn_list(struct snd_info_buffer *buffer, } snd_iprintf(buffer, "\n"); } + + /* Get Cache connections info */ + cache_len = snd_hda_get_conn_list(codec, nid, &list); + if (cache_len != conn_len + || memcmp(list, conn, conn_len)) { + snd_iprintf(buffer, " In-driver Connection: %d\n", cache_len); + if (cache_len > 0) { + snd_iprintf(buffer, " "); + for (c = 0; c < cache_len; c++) + snd_iprintf(buffer, " 0x%02x", list[c]); + snd_iprintf(buffer, "\n"); + } + } } static void print_gpio(struct snd_info_buffer *buffer, diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 977b0d878da..d97f0d61a15 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2112,6 +2112,9 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled) { struct hda_codec *codec = private_data; struct ad198x_spec *spec = codec->spec; + + if (!spec->eapd_nid) + return; snd_hda_codec_update_cache(codec, spec->eapd_nid, 0, AC_VERB_SET_EAPD_BTLENABLE, enabled ? 0x02 : 0x00); @@ -3601,13 +3604,16 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec, { struct ad198x_spec *spec = codec->spec; - if (action == HDA_FIXUP_ACT_PRE_PROBE) { + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; + break; + case HDA_FIXUP_ACT_PROBE: if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) spec->eapd_nid = spec->gen.autocfg.line_out_pins[0]; else spec->eapd_nid = spec->gen.autocfg.speaker_pins[0]; - if (spec->eapd_nid) - spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; + break; } } diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 90ff7a3f72d..6e9876f27d9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -139,7 +139,7 @@ enum { #define DSP_SPEAKER_OUT_LATENCY 7 struct ct_effect { - char name[44]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; hda_nid_t nid; int mid; /*effect module ID*/ int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/ @@ -270,7 +270,7 @@ enum { }; struct ct_tuning_ctl { - char name[44]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; hda_nid_t parent_nid; hda_nid_t nid; int mid; /*effect module ID*/ @@ -3103,7 +3103,7 @@ static int add_tuning_control(struct hda_codec *codec, hda_nid_t pnid, hda_nid_t nid, const char *name, int dir) { - char namestr[44]; + char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int type = dir ? HDA_INPUT : HDA_OUTPUT; struct snd_kcontrol_new knew = HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type); @@ -3935,7 +3935,7 @@ static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, int dir) { - char namestr[44]; + char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int type = dir ? HDA_INPUT : HDA_OUTPUT; struct snd_kcontrol_new knew = CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index b314d3e6d7f..de00ce16647 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2947,7 +2947,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), {} @@ -3318,6 +3317,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410), + SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index e12f7a030c5..540bdef2f90 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1018,13 +1018,18 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) hdmi_non_intrinsic_event(codec, res); } -static void haswell_verify_pin_D0(struct hda_codec *codec, hda_nid_t nid) +static void haswell_verify_pin_D0(struct hda_codec *codec, + hda_nid_t cvt_nid, hda_nid_t nid) { int pwr, lamp, ramp; - pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); - pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT; - if (pwr != AC_PWRST_D0) { + /* For Haswell, the converter 1/2 may keep in D3 state after bootup, + * thus pins could only choose converter 0 for use. Make sure the + * converters are in correct power state */ + if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0)) + snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) { snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); msleep(40); @@ -1068,7 +1073,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, int new_pinctl = 0; if (codec->vendor_id == 0x80862807) - haswell_verify_pin_D0(codec, pin_nid); + haswell_verify_pin_D0(codec, cvt_nid, pin_nid); if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) { pinctl = snd_hda_codec_read(codec, pin_nid, 0, @@ -1101,26 +1106,15 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, return 0; } -/* - * HDA PCM callbacks - */ -static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static int hdmi_choose_cvt(struct hda_codec *codec, + int pin_idx, int *cvt_id, int *mux_id) { struct hdmi_spec *spec = codec->spec; - struct snd_pcm_runtime *runtime = substream->runtime; - int pin_idx, cvt_idx, mux_idx = 0; struct hdmi_spec_per_pin *per_pin; - struct hdmi_eld *eld; struct hdmi_spec_per_cvt *per_cvt = NULL; + int cvt_idx, mux_idx = 0; - /* Validate hinfo */ - pin_idx = hinfo_to_pin_index(spec, hinfo); - if (snd_BUG_ON(pin_idx < 0)) - return -EINVAL; per_pin = get_pin(spec, pin_idx); - eld = &per_pin->sink_eld; /* Dynamically assign converter to stream */ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { @@ -1138,17 +1132,89 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, continue; break; } + /* No free converters */ if (cvt_idx == spec->num_cvts) return -ENODEV; + if (cvt_id) + *cvt_id = cvt_idx; + if (mux_id) + *mux_id = mux_idx; + + return 0; +} + +static void haswell_config_cvts(struct hda_codec *codec, + int pin_id, int mux_id) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin; + int pin_idx, mux_idx; + int curr; + int err; + + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + per_pin = get_pin(spec, pin_idx); + + if (pin_idx == pin_id) + continue; + + curr = snd_hda_codec_read(codec, per_pin->pin_nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + + /* Choose another unused converter */ + if (curr == mux_id) { + err = hdmi_choose_cvt(codec, pin_idx, NULL, &mux_idx); + if (err < 0) + return; + snd_printdd("HDMI: choose converter %d for pin %d\n", mux_idx, pin_idx); + snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0, + AC_VERB_SET_CONNECT_SEL, + mux_idx); + } + } +} + +/* + * HDA PCM callbacks + */ +static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + struct snd_pcm_runtime *runtime = substream->runtime; + int pin_idx, cvt_idx, mux_idx = 0; + struct hdmi_spec_per_pin *per_pin; + struct hdmi_eld *eld; + struct hdmi_spec_per_cvt *per_cvt = NULL; + int err; + + /* Validate hinfo */ + pin_idx = hinfo_to_pin_index(spec, hinfo); + if (snd_BUG_ON(pin_idx < 0)) + return -EINVAL; + per_pin = get_pin(spec, pin_idx); + eld = &per_pin->sink_eld; + + err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx); + if (err < 0) + return err; + + per_cvt = get_cvt(spec, cvt_idx); /* Claim converter */ per_cvt->assigned = 1; hinfo->nid = per_cvt->cvt_nid; - snd_hda_codec_write(codec, per_pin->pin_nid, 0, + snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0, AC_VERB_SET_CONNECT_SEL, mux_idx); + + /* configure unused pins to choose other converters */ + if (codec->vendor_id == 0x80862807) + haswell_config_cvts(codec, pin_idx, mux_idx); + snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); /* Initially set the converter's capabilities */ @@ -1798,12 +1864,33 @@ static void generic_hdmi_free(struct hda_codec *codec) kfree(spec); } +#ifdef CONFIG_PM +static int generic_hdmi_resume(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int pin_idx; + + generic_hdmi_init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + hdmi_present_sense(per_pin, 1); + } + return 0; +} +#endif + static const struct hda_codec_ops generic_hdmi_patch_ops = { .init = generic_hdmi_init, .free = generic_hdmi_free, .build_pcms = generic_hdmi_build_pcms, .build_controls = generic_hdmi_build_controls, .unsol_event = hdmi_unsol_event, +#ifdef CONFIG_PM + .resume = generic_hdmi_resume, +#endif }; @@ -1821,7 +1908,6 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec, /* override pins connection list */ snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid); - nconns = max(spec->num_cvts, 4); snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 403010c9e82..8bd22614986 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -37,6 +37,9 @@ #include "hda_jack.h" #include "hda_generic.h" +/* keep halting ALC5505 DSP, for power saving */ +#define HALT_REALTEK_ALC5505 + /* unsol event tags */ #define ALC_DCVOL_EVENT 0x08 @@ -115,6 +118,7 @@ struct alc_spec { int init_amp; int codec_variant; /* flag for other variants */ + bool has_alc5505_dsp; /* for PLL fix */ hda_nid_t pll_nid; @@ -2580,7 +2584,108 @@ static void alc269_shutup(struct hda_codec *codec) } } +static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg, + unsigned int val) +{ + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1); + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val & 0xffff); /* LSB */ + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val >> 16); /* MSB */ +} + +static int alc5505_coef_get(struct hda_codec *codec, unsigned int index_reg) +{ + unsigned int val; + + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1); + val = snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0) + & 0xffff; + val |= snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0) + << 16; + return val; +} + +static void alc5505_dsp_halt(struct hda_codec *codec) +{ + unsigned int val; + + alc5505_coef_set(codec, 0x3000, 0x000c); /* DSP CPU stop */ + alc5505_coef_set(codec, 0x880c, 0x0008); /* DDR enter self refresh */ + alc5505_coef_set(codec, 0x61c0, 0x11110080); /* Clock control for PLL and CPU */ + alc5505_coef_set(codec, 0x6230, 0xfc0d4011); /* Disable Input OP */ + alc5505_coef_set(codec, 0x61b4, 0x040a2b03); /* Stop PLL2 */ + alc5505_coef_set(codec, 0x61b0, 0x00005b17); /* Stop PLL1 */ + alc5505_coef_set(codec, 0x61b8, 0x04133303); /* Stop PLL3 */ + val = alc5505_coef_get(codec, 0x6220); + alc5505_coef_set(codec, 0x6220, (val | 0x3000)); /* switch Ringbuffer clock to DBUS clock */ +} + +static void alc5505_dsp_back_from_halt(struct hda_codec *codec) +{ + alc5505_coef_set(codec, 0x61b8, 0x04133302); + alc5505_coef_set(codec, 0x61b0, 0x00005b16); + alc5505_coef_set(codec, 0x61b4, 0x040a2b02); + alc5505_coef_set(codec, 0x6230, 0xf80d4011); + alc5505_coef_set(codec, 0x6220, 0x2002010f); + alc5505_coef_set(codec, 0x880c, 0x00000004); +} + +static void alc5505_dsp_init(struct hda_codec *codec) +{ + unsigned int val; + + alc5505_dsp_halt(codec); + alc5505_dsp_back_from_halt(codec); + alc5505_coef_set(codec, 0x61b0, 0x5b14); /* PLL1 control */ + alc5505_coef_set(codec, 0x61b0, 0x5b16); + alc5505_coef_set(codec, 0x61b4, 0x04132b00); /* PLL2 control */ + alc5505_coef_set(codec, 0x61b4, 0x04132b02); + alc5505_coef_set(codec, 0x61b8, 0x041f3300); /* PLL3 control*/ + alc5505_coef_set(codec, 0x61b8, 0x041f3302); + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_CODEC_RESET, 0); /* Function reset */ + alc5505_coef_set(codec, 0x61b8, 0x041b3302); + alc5505_coef_set(codec, 0x61b8, 0x04173302); + alc5505_coef_set(codec, 0x61b8, 0x04163302); + alc5505_coef_set(codec, 0x8800, 0x348b328b); /* DRAM control */ + alc5505_coef_set(codec, 0x8808, 0x00020022); /* DRAM control */ + alc5505_coef_set(codec, 0x8818, 0x00000400); /* DRAM control */ + + val = alc5505_coef_get(codec, 0x6200) >> 16; /* Read revision ID */ + if (val <= 3) + alc5505_coef_set(codec, 0x6220, 0x2002010f); /* I/O PAD Configuration */ + else + alc5505_coef_set(codec, 0x6220, 0x6002018f); + + alc5505_coef_set(codec, 0x61ac, 0x055525f0); /**/ + alc5505_coef_set(codec, 0x61c0, 0x12230080); /* Clock control */ + alc5505_coef_set(codec, 0x61b4, 0x040e2b02); /* PLL2 control */ + alc5505_coef_set(codec, 0x61bc, 0x010234f8); /* OSC Control */ + alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */ + alc5505_coef_set(codec, 0x880c, 0x00000003); + alc5505_coef_set(codec, 0x880c, 0x00000010); + +#ifdef HALT_REALTEK_ALC5505 + alc5505_dsp_halt(codec); +#endif +} + +#ifdef HALT_REALTEK_ALC5505 +#define alc5505_dsp_suspend(codec) /* NOP */ +#define alc5505_dsp_resume(codec) /* NOP */ +#else +#define alc5505_dsp_suspend(codec) alc5505_dsp_halt(codec) +#define alc5505_dsp_resume(codec) alc5505_dsp_back_from_halt(codec) +#endif + #ifdef CONFIG_PM +static int alc269_suspend(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec->has_alc5505_dsp) + alc5505_dsp_suspend(codec); + return alc_suspend(codec); +} + static int alc269_resume(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -2603,7 +2708,10 @@ static int alc269_resume(struct hda_codec *codec) snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); + alc_inv_dmic_sync(codec, true); hda_call_check_power_status(codec, 0x01); + if (spec->has_alc5505_dsp) + alc5505_dsp_resume(codec); return 0; } #endif /* CONFIG_PM */ @@ -3225,6 +3333,7 @@ enum { ALC271_FIXUP_HP_GATE_MIC_JACK, ALC269_FIXUP_ACER_AC700, ALC269_FIXUP_LIMIT_INT_MIC_BOOST, + ALC269VB_FIXUP_ORDISSIMO_EVE2, }; static const struct hda_fixup alc269_fixups[] = { @@ -3467,6 +3576,15 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_limit_int_mic_boost, }, + [ALC269VB_FIXUP_ORDISSIMO_EVE2] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x12, 0x99a3092f }, /* int-mic */ + { 0x18, 0x03a11d20 }, /* mic */ + { 0x19, 0x411111f0 }, /* Unused bogus pin */ + { } + }, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -3482,6 +3600,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05ca, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05de, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05e0, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -3495,9 +3615,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05f8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05f9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05fb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), 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, 0x0613, "Dell", ALC269_FIXUP_DELL1_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(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), @@ -3539,6 +3664,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), + SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ #if 0 /* Below is a quirk table taken from the old code. @@ -3718,6 +3844,11 @@ static int patch_alc269(struct hda_codec *codec) break; } + if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) { + spec->has_alc5505_dsp = true; + spec->init_hook = alc5505_dsp_init; + } + /* automatic parse from the BIOS config */ err = alc269_parse_auto_config(codec); if (err < 0) @@ -3728,6 +3859,7 @@ static int patch_alc269(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; #ifdef CONFIG_PM + codec->patch_ops.suspend = alc269_suspend; codec->patch_ops.resume = alc269_resume; #endif spec->shutup = alc269_shutup; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1d9d6427e0b..e2f83591161 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2233,6 +2233,10 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { "HP Folio", STAC_92HD83XXX_HP_MIC_LED), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900, "HP", STAC_92HD83XXX_HP_MIC_LED), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2000, + "HP", STAC_92HD83XXX_HP_MIC_LED), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2100, + "HP", STAC_92HD83XXX_HP_MIC_LED), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, @@ -3707,14 +3711,6 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer, #endif #ifdef CONFIG_PM -static int stac_resume(struct hda_codec *codec) -{ - codec->patch_ops.init(codec); - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - return 0; -} - static int stac_suspend(struct hda_codec *codec) { stac_shutup(codec); @@ -3743,7 +3739,6 @@ static void stac_set_power_state(struct hda_codec *codec, hda_nid_t fg, } #else #define stac_suspend NULL -#define stac_resume NULL #define stac_set_power_state NULL #endif /* CONFIG_PM */ @@ -3755,7 +3750,6 @@ static const struct hda_codec_ops stac_patch_ops = { .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM .suspend = stac_suspend, - .resume = stac_resume, #endif .reboot_notify = stac_shutup, }; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e5245544eb5..e2481baddc7 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -480,14 +480,9 @@ static int via_suspend(struct hda_codec *codec) struct via_spec *spec = codec->spec; vt1708_stop_hp_work(codec); - if (spec->codec_type == VT1802) { - /* Fix pop noise on headphones */ - int i; - for (i = 0; i < spec->gen.autocfg.hp_outs; i++) - snd_hda_codec_write(codec, spec->gen.autocfg.hp_pins[i], - 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - 0x00); - } + /* Fix pop noise on headphones */ + if (spec->codec_type == VT1802) + snd_hda_shutup_pins(codec); return 0; } @@ -746,6 +741,8 @@ static int patch_vt1708(struct hda_codec *codec) /* don't support the input jack switching due to lack of unsol event */ /* (it may work with polling, though, but it needs testing) */ spec->gen.suppress_auto_mic = 1; + /* Some machines show the broken speaker mute */ + spec->gen.auto_mute_via_amp = 1; /* Add HP and CD pin config connect bit re-config action */ vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); @@ -910,6 +907,8 @@ static const struct hda_verb vt1708S_init_verbs[] = { static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, int offset, int num_steps, int step_size) { + snd_hda_override_wcaps(codec, pin, + get_wcaps(codec, pin) | AC_WCAP_IN_AMP); snd_hda_override_amp_caps(codec, pin, HDA_INPUT, (offset << AC_AMPCAP_OFFSET_SHIFT) | (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) | diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 806407a3973..28ec872e54c 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2807,7 +2807,6 @@ static void snd_ice1712_remove(struct pci_dev *pci) if (ice->card_info && ice->card_info->chip_exit) ice->card_info->chip_exit(ice); snd_card_free(card); - pci_set_drvdata(pci, NULL); } static struct pci_driver ice1712_driver = { diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ce70e7f113e..50047177829 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2800,7 +2800,6 @@ static void snd_vt1724_remove(struct pci_dev *pci) if (ice->card_info && ice->card_info->chip_exit) ice->card_info->chip_exit(ice); snd_card_free(card); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b8fe40531b9..59c8aaebb91 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -3364,7 +3364,6 @@ static int snd_intel8x0_probe(struct pci_dev *pci, static void snd_intel8x0_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver intel8x0_driver = { diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index fea09e8ea60..3573c119366 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1328,7 +1328,6 @@ static int snd_intel8x0m_probe(struct pci_dev *pci, static void snd_intel8x0m_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver intel8x0m_driver = { diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 43b4228d9af..9cf9829555d 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2473,7 +2473,6 @@ snd_korg1212_probe(struct pci_dev *pci, static void snd_korg1212_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver korg1212_driver = { diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index 322b638e8ec..7307d97186c 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -759,7 +759,6 @@ out_free: static void lola_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } /* PCI IDs */ diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 298bc9b7299..3230e57f246 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -1139,7 +1139,6 @@ out_free: static void snd_lx6464es_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index c76ac141121..d5417360f51 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2775,7 +2775,6 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) static void snd_m3_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver m3_driver = { diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 934dec98e2c..1e0f6ee193f 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1377,7 +1377,6 @@ static int snd_mixart_probe(struct pci_dev *pci, static void snd_mixart_remove(struct pci_dev *pci) { snd_mixart_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver mixart_driver = { diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 6febedb0593..fe79fff4c6d 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1746,7 +1746,6 @@ static int snd_nm256_probe(struct pci_dev *pci, static void snd_nm256_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 9562dc63ba6..b0cb48adddc 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -722,7 +722,6 @@ EXPORT_SYMBOL(oxygen_pci_probe); void oxygen_pci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } EXPORT_SYMBOL(oxygen_pci_remove); diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index b97384ad946..d379b284955 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1691,7 +1691,6 @@ static int pcxhr_probe(struct pci_dev *pci, static void pcxhr_remove(struct pci_dev *pci) { pcxhr_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver pcxhr_driver = { diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 63c1c804155..56cc891e395 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -2066,7 +2066,6 @@ static void snd_riptide_joystick_remove(struct pci_dev *pci) if (gameport) { release_region(gameport->io, 8); gameport_unregister_port(gameport); - pci_set_drvdata(pci, NULL); } } #endif @@ -2179,7 +2178,6 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) static void snd_card_riptide_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver driver = { diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 0ecd4100713..cc26346ae66 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1981,7 +1981,6 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) static void snd_rme32_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver rme32_driver = { diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 5fb88ac82aa..2a8ad9d1a2a 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -2390,7 +2390,6 @@ snd_rme96_probe(struct pci_dev *pci, static void snd_rme96_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver rme96_driver = { diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 94084cdb130..4f255dfee45 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -5412,7 +5412,6 @@ static int snd_hdsp_probe(struct pci_dev *pci, static void snd_hdsp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver hdsp_driver = { diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 9ea05e95647..bd501931ee2 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -400,8 +400,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ #define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ -#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */ -/* missing Bit for 111=128, 1000=176.4, 1001=192 */ +#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, 111=128 */ +#define HDSPM_wc_freq3 0x800 /* 1000=176.4, 1001=192 */ #define HDSPM_SyncRef0 0x10000 /* Sync Reference */ #define HDSPM_SyncRef1 0x20000 @@ -412,13 +412,17 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) -#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\ + HDSPM_wc_freq3) #define HDSPM_wcFreq32 (HDSPM_wc_freq0) #define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) #define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) #define HDSPM_wcFreq64 (HDSPM_wc_freq2) #define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreq128 (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreq176_4 (HDSPM_wc_freq3) +#define HDSPM_wcFreq192 (HDSPM_wc_freq0|HDSPM_wc_freq3) #define HDSPM_status1_F_0 0x0400000 #define HDSPM_status1_F_1 0x0800000 @@ -1087,6 +1091,26 @@ static int hdspm_round_frequency(int rate) return 48000; } +/* QS and DS rates normally can not be detected + * automatically by the card. Only exception is MADI + * in 96k frame mode. + * + * So if we read SS values (32 .. 48k), check for + * user-provided DS/QS bits in the control register + * and multiply the base frequency accordingly. + */ +static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) +{ + if (rate <= 48000) { + if (hdspm->control_register & HDSPM_QuadSpeed) + return rate * 4; + else if (hdspm->control_register & + HDSPM_DoubleSpeed) + return rate * 2; + }; + return rate; +} + static int hdspm_tco_sync_check(struct hdspm *hdspm); static int hdspm_sync_in_sync_check(struct hdspm *hdspm); @@ -1181,6 +1205,15 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) case HDSPM_wcFreq96: rate = 96000; break; + case HDSPM_wcFreq128: + rate = 128000; + break; + case HDSPM_wcFreq176_4: + rate = 176400; + break; + case HDSPM_wcFreq192: + rate = 192000; + break; default: rate = 0; break; @@ -1192,7 +1225,7 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) */ if (rate != 0 && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) - return rate; + return hdspm_rate_multiplier(hdspm, rate); /* maybe a madi input (which is taken if sel sync is madi) */ if (status & HDSPM_madiLock) { @@ -1255,21 +1288,8 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) } } - /* QS and DS rates normally can not be detected - * automatically by the card. Only exception is MADI - * in 96k frame mode. - * - * So if we read SS values (32 .. 48k), check for - * user-provided DS/QS bits in the control register - * and multiply the base frequency accordingly. - */ - if (rate <= 48000) { - if (hdspm->control_register & HDSPM_QuadSpeed) - rate *= 4; - else if (hdspm->control_register & - HDSPM_DoubleSpeed) - rate *= 2; - } + rate = hdspm_rate_multiplier(hdspm, rate); + break; } @@ -6737,7 +6757,6 @@ static int snd_hdspm_probe(struct pci_dev *pci, static void snd_hdspm_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver hdspm_driver = { diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 773a67fff4c..b96d9e1adf6 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -2628,7 +2628,6 @@ static int snd_rme9652_probe(struct pci_dev *pci, static void snd_rme9652_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver rme9652_driver = { diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 748e82d4d25..e413b4e2c81 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -1482,7 +1482,6 @@ error_out: static void snd_sis7019_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver sis7019_driver = { diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index a2e7686e7ae..2a46bf98af3 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1528,7 +1528,6 @@ static int snd_sonic_probe(struct pci_dev *pci, static void snd_sonic_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver sonicvibes_driver = { diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 1aefd6204a6..b3b588bc94c 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -169,7 +169,6 @@ static int snd_trident_probe(struct pci_dev *pci, static void snd_trident_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver trident_driver = { diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index d756a356270..3c511d0caf9 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2646,7 +2646,6 @@ static int snd_via82xx_probe(struct pci_dev *pci, static void snd_via82xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver via82xx_driver = { diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 4f5fd80b7e5..ca190283cbd 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1227,7 +1227,6 @@ static int snd_via82xx_probe(struct pci_dev *pci, static void snd_via82xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver via82xx_modem_driver = { diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index e2f1ab37e15..ab8a9b1bfb8 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -254,7 +254,6 @@ static int snd_vx222_probe(struct pci_dev *pci, static void snd_vx222_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 01c49655a3c..e8932b2e4a5 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -347,7 +347,6 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, static void snd_card_ymfpci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver ymfpci_driver = { diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 22056c50fe3..d591c154fc5 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2258,7 +2258,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) /* FIXME: temporarily disabled, otherwise we cannot fire up * the chip again unless reboot. ACPI bug? */ - pci_set_power_state(chip->pci, 3); + pci_set_power_state(chip->pci, PCI_D3hot); #endif #ifdef CONFIG_PM_SLEEP |