diff options
Diffstat (limited to 'sound/pci')
153 files changed, 6190 insertions, 3263 deletions
diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 04cac7469139..18b673018dfd 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile @@ -4,30 +4,30 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-ad1889-objs := ad1889.o -snd-als300-objs := als300.o -snd-als4000-objs := als4000.o -snd-atiixp-objs := atiixp.o -snd-atiixp-modem-objs := atiixp_modem.o -snd-azt3328-objs := azt3328.o -snd-bt87x-objs := bt87x.o -snd-cmipci-objs := cmipci.o -snd-cs4281-objs := cs4281.o -snd-cs5530-objs := cs5530.o -snd-ens1370-objs := ens1370.o ak4531_codec.o -snd-ens1371-objs := ens1371.o -snd-es1938-objs := es1938.o -snd-es1968-objs := es1968.o -snd-fm801-objs := fm801.o -snd-intel8x0-objs := intel8x0.o -snd-intel8x0m-objs := intel8x0m.o -snd-maestro3-objs := maestro3.o -snd-rme32-objs := rme32.o -snd-rme96-objs := rme96.o -snd-sis7019-objs := sis7019.o -snd-sonicvibes-objs := sonicvibes.o -snd-via82xx-objs := via82xx.o -snd-via82xx-modem-objs := via82xx_modem.o +snd-ad1889-y := ad1889.o +snd-als300-y := als300.o +snd-als4000-y := als4000.o +snd-atiixp-y := atiixp.o +snd-atiixp-modem-y := atiixp_modem.o +snd-azt3328-y := azt3328.o +snd-bt87x-y := bt87x.o +snd-cmipci-y := cmipci.o +snd-cs4281-y := cs4281.o +snd-cs5530-y := cs5530.o +snd-ens1370-y := ens1370.o ak4531_codec.o +snd-ens1371-y := ens1371.o +snd-es1938-y := es1938.o +snd-es1968-y := es1968.o +snd-fm801-y := fm801.o +snd-intel8x0-y := intel8x0.o +snd-intel8x0m-y := intel8x0m.o +snd-maestro3-y := maestro3.o +snd-rme32-y := rme32.o +snd-rme96-y := rme96.o +snd-sis7019-y := sis7019.o +snd-sonicvibes-y := sonicvibes.o +snd-via82xx-y := via82xx.o +snd-via82xx-modem-y := via82xx_modem.o # Toplevel Module Dependency obj-$(CONFIG_SND_AD1889) += snd-ad1889.o diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 25f93e56cfc7..88ac37739b76 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1864,7 +1864,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m strcat(name, " "); strcat(name, pid->name); if (pid->mask != 0xffffffff) - sprintf(name + strlen(name), " rev %d", id & ~pid->mask); + sprintf(name + strlen(name), " rev %u", id & ~pid->mask); if (ac97 && pid->patch) { if ((modem && (pid->flags & AC97_MODEM_PATCH)) || (! modem && ! (pid->flags & AC97_MODEM_PATCH))) @@ -2461,8 +2461,7 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) * (for avoiding loud click noises for many (OSS) apps * that open/close frequently) */ - schedule_delayed_work(&ac97->power_work, - msecs_to_jiffies(power_save * 1000)); + schedule_delayed_work(&ac97->power_work, secs_to_jiffies(power_save)); else { cancel_delayed_work(&ac97->power_work); update_power_regs(ac97); diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 5426f7bc9884..518834964b7b 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -161,12 +161,12 @@ static void snd_ac97_proc_read_main(struct snd_ac97 *ac97, struct snd_info_buffe "Mic select : %s\n" "ADC/DAC loopback : %s\n", val & 0x8000 ? "post" : "pre", - val & 0x4000 ? "on" : "off", - val & 0x2000 ? "on" : "off", - val & 0x1000 ? "on" : "off", + str_on_off(val & 0x4000), + str_on_off(val & 0x2000), + str_on_off(val & 0x1000), val & 0x0200 ? "Mic" : "MIX", val & 0x0100 ? "Mic2" : "Mic1", - val & 0x0080 ? "on" : "off"); + str_on_off(val & 0x0080)); if (ac97->ext_id & AC97_EI_DRA) snd_iprintf(buffer, "Double rate slots: %s\n", double_rate_slots[(val >> 10) & 3]); diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 50e30704bf6f..ac27a93ce4ff 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -626,7 +626,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe reg = ad1889_readw(chip, AD_DS_WSMC); snd_iprintf(buffer, "Wave output: %s\n", - (reg & AD_DS_WSMC_WAEN) ? "enabled" : "disabled"); + str_enabled_disabled(reg & AD_DS_WSMC_WAEN)); snd_iprintf(buffer, "Wave Channels: %s\n", (reg & AD_DS_WSMC_WAST) ? "stereo" : "mono"); snd_iprintf(buffer, "Wave Quality: %d-bit linear\n", @@ -642,7 +642,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe snd_iprintf(buffer, "Synthesis output: %s\n", - reg & AD_DS_WSMC_SYEN ? "enabled" : "disabled"); + str_enabled_disabled(reg & AD_DS_WSMC_SYEN)); /* SYRQ is at offset 4 */ tmp = (reg & AD_DS_WSMC_SYRQ) ? @@ -654,7 +654,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe reg = ad1889_readw(chip, AD_DS_RAMC); snd_iprintf(buffer, "ADC input: %s\n", - (reg & AD_DS_RAMC_ADEN) ? "enabled" : "disabled"); + str_enabled_disabled(reg & AD_DS_RAMC_ADEN)); snd_iprintf(buffer, "ADC Channels: %s\n", (reg & AD_DS_RAMC_ADST) ? "stereo" : "mono"); snd_iprintf(buffer, "ADC Quality: %d-bit linear\n", @@ -669,7 +669,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe (reg & AD_DS_RAMC_ADST) ? "stereo" : "mono"); snd_iprintf(buffer, "Resampler input: %s\n", - reg & AD_DS_RAMC_REEN ? "enabled" : "disabled"); + str_enabled_disabled(reg & AD_DS_RAMC_REEN)); /* RERQ is at offset 12 */ tmp = (reg & AD_DS_RAMC_RERQ) ? @@ -810,12 +810,11 @@ snd_ad1889_create(struct snd_card *card, struct pci_dev *pci) chip->irq = -1; /* (1) PCI resource allocation */ - err = pcim_iomap_regions(pci, 1 << 0, card->driver); - if (err < 0) - return err; + chip->iobase = pcim_iomap_region(pci, 0, card->driver); + if (IS_ERR(chip->iobase)) + return PTR_ERR(chip->iobase); chip->bar = pci_resource_start(pci, 0); - chip->iobase = pcim_iomap_table(pci)[0]; pci_set_master(pci); diff --git a/sound/pci/ali5451/Makefile b/sound/pci/ali5451/Makefile index 8156198fbaeb..e319a4c1d6b2 100644 --- a/sound/pci/ali5451/Makefile +++ b/sound/pci/ali5451/Makefile @@ -4,7 +4,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-ali5451-objs := ali5451.o +snd-ali5451-y := ali5451.o # Toplevel Module Dependency obj-$(CONFIG_SND_ALI5451) += snd-ali5451.o diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 31e51e2df655..69c02bdd38ce 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -292,7 +292,7 @@ static int snd_ali_codec_ready(struct snd_ali *codec, } snd_ali_5451_poke(codec, port, res & ~0x8000); - dev_dbg(codec->card->dev, "ali_codec_ready: codec is not ready.\n "); + dev_dbg(codec->card->dev, "ali_codec_ready: codec is not ready.\n"); return -EIO; } @@ -1688,7 +1688,7 @@ static int snd_ali_build_pcms(struct snd_ali *codec) static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_ali *codec = kcontrol->private_data; + struct snd_ali *codec = snd_kcontrol_chip(kcontrol); unsigned int spdif_enable; spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0; @@ -1716,7 +1716,7 @@ static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol, static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_ali *codec = kcontrol->private_data; + struct snd_ali *codec = snd_kcontrol_chip(kcontrol); unsigned int change = 0, spdif_enable = 0; spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0; @@ -1989,7 +1989,7 @@ static int snd_ali_resources(struct snd_ali *codec) int err; dev_dbg(codec->card->dev, "resources allocation ...\n"); - err = pci_request_regions(codec->pci, "ALI 5451"); + err = pcim_request_all_regions(codec->pci, "ALI 5451"); if (err < 0) return err; codec->port = pci_resource_start(codec->pci, 0); diff --git a/sound/pci/als300.c b/sound/pci/als300.c index c7c481203ef8..43f98719e61b 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -617,7 +617,7 @@ static int snd_als300_create(struct snd_card *card, chip->chip_type = chip_type; spin_lock_init(&chip->reg_lock); - err = pci_request_regions(pci, "ALS300"); + err = pcim_request_all_regions(pci, "ALS300"); if (err < 0) return err; diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 022473594c73..3f4f3037f71f 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -836,7 +836,7 @@ static int __snd_card_als4000_probe(struct pci_dev *pci, return -ENXIO; } - err = pci_request_regions(pci, "ALS4000"); + err = pcim_request_all_regions(pci, "ALS4000"); if (err < 0) return err; iobase = pci_resource_start(pci, 0); diff --git a/sound/pci/asihpi/Makefile b/sound/pci/asihpi/Makefile index 8351f8f5b523..d558a974fa7e 100644 --- a/sound/pci/asihpi/Makefile +++ b/sound/pci/asihpi/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-asihpi-objs := asihpi.o hpioctl.o hpimsginit.o\ +snd-asihpi-y := asihpi.o hpioctl.o hpimsginit.o\ hpicmn.o hpifunc.o hpidebug.o hpidspcd.o\ hpios.o hpi6000.o hpi6205.o hpimsgx.o diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 001786e2aba1..cbd964f87349 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -36,19 +36,10 @@ MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); MODULE_DESCRIPTION("AudioScience ALSA ASI5xxx ASI6xxx ASI87xx ASI89xx " HPI_VER_STRING); -#if defined CONFIG_SND_DEBUG_VERBOSE -/** - * snd_printddd - very verbose debug printk - * @format: format string - * - * Works like snd_printk() for debugging purposes. - * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set. - * Must set snd module debug parameter to 3 to enable at runtime. - */ -#define snd_printddd(format, args...) \ - __snd_printk(3, __FILE__, __LINE__, format, ##args) +#ifdef ASIHPI_VERBOSE_DEBUG +#define asihpi_dbg(format, args...) pr_debug(format, ##args) #else -#define snd_printddd(format, args...) do { } while (0) +#define asihpi_dbg(format, args...) do { } while (0) #endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */ @@ -260,8 +251,7 @@ static inline u16 hpi_stream_group_reset(u32 h_stream) static u16 handle_error(u16 err, int line, char *filename) { if (err) - printk(KERN_WARNING - "in file %s, line %d: HPI error %d\n", + pr_warn("in file %s, line %d: HPI error %d\n", filename, line, err); return err; } @@ -273,16 +263,18 @@ static u16 handle_error(u16 err, int line, char *filename) static void print_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *p) { + struct device *dev = substream->pcm->card->dev; char name[16]; + snd_pcm_debug_name(substream, name, sizeof(name)); - snd_printdd("%s HWPARAMS\n", name); - snd_printdd(" samplerate=%dHz channels=%d format=%d subformat=%d\n", + dev_dbg(dev, "%s HWPARAMS\n", name); + dev_dbg(dev, " samplerate=%dHz channels=%d format=%d subformat=%d\n", params_rate(p), params_channels(p), params_format(p), params_subformat(p)); - snd_printdd(" buffer=%dB period=%dB period_size=%dB periods=%d\n", + dev_dbg(dev, " buffer=%dB period=%dB period_size=%dB periods=%d\n", params_buffer_bytes(p), params_period_bytes(p), params_period_size(p), params_periods(p)); - snd_printdd(" buffer_size=%d access=%d data_rate=%dB/s\n", + dev_dbg(dev, " buffer_size=%d access=%d data_rate=%dB/s\n", params_buffer_size(p), params_access(p), params_rate(p) * params_channels(p) * snd_pcm_format_width(params_format(p)) / 8); @@ -317,7 +309,8 @@ static const snd_pcm_format_t hpi_to_alsa_formats[] = { }; -static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format, +static int snd_card_asihpi_format_alsa2hpi(struct snd_card_asihpi *asihpi, + snd_pcm_format_t alsa_format, u16 *hpi_format) { u16 format; @@ -330,8 +323,8 @@ static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format, } } - snd_printd(KERN_WARNING "failed match for alsa format %d\n", - alsa_format); + dev_dbg(asihpi->card->dev, "failed match for alsa format %d\n", + alsa_format); *hpi_format = 0; return -EINVAL; } @@ -439,7 +432,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, unsigned int bytes_per_sec; print_hwparams(substream, params); - err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format); + err = snd_card_asihpi_format_alsa2hpi(card, params_format(params), &format); if (err) return err; @@ -461,17 +454,17 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, err = hpi_stream_host_buffer_attach(dpcm->h_stream, params_buffer_bytes(params), runtime->dma_addr); if (err == 0) { - snd_printdd( + dev_dbg(card->card->dev, "stream_host_buffer_attach success %u %lu\n", params_buffer_bytes(params), (unsigned long)runtime->dma_addr); } else { - snd_printd("stream_host_buffer_attach error %d\n", - err); + dev_dbg(card->card->dev, + "stream_host_buffer_attach error %d\n", err); return -ENOMEM; } - err = hpi_stream_get_info_ex(dpcm->h_stream, NULL, + hpi_stream_get_info_ex(dpcm->h_stream, NULL, &dpcm->hpi_buffer_attached, NULL, NULL, NULL); } bytes_per_sec = params_rate(params) * params_channels(params); @@ -525,7 +518,7 @@ static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream) struct snd_card_asihpi_pcm *dpcm = runtime->private_data; dpcm->respawn_timer = 0; - del_timer(&dpcm->timer); + timer_delete(&dpcm->timer); } static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream) @@ -569,7 +562,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_printdd("%s trigger start\n", name); + dev_dbg(card->card->dev, "%s trigger start\n", name); snd_pcm_group_for_each_entry(s, substream) { struct snd_pcm_runtime *runtime = s->runtime; struct snd_card_asihpi_pcm *ds = runtime->private_data; @@ -590,7 +583,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, * data?? */ unsigned int preload = ds->period_bytes * 1; - snd_printddd("%d preload %d\n", s->number, preload); + asihpi_dbg("%d preload %d\n", s->number, preload); hpi_handle_error(hpi_outstream_write_buf( ds->h_stream, &runtime->dma_area[0], @@ -600,7 +593,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, } if (card->support_grouping) { - snd_printdd("%d group\n", s->number); + dev_dbg(card->card->dev, "%d group\n", s->number); e = hpi_stream_group_add( dpcm->h_stream, ds->h_stream); @@ -621,7 +614,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_STOP: - snd_printdd("%s trigger stop\n", name); + dev_dbg(card->card->dev, "%s trigger stop\n", name); card->pcm_stop(substream); snd_pcm_group_for_each_entry(s, substream) { if (snd_pcm_substream_chip(s) != card) @@ -635,7 +628,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, __snd_pcm_set_state(s->runtime, SNDRV_PCM_STATE_SETUP); if (card->support_grouping) { - snd_printdd("%d group\n", s->number); + dev_dbg(card->card->dev, "%d group\n", s->number); snd_pcm_trigger_done(s, substream); } else break; @@ -652,17 +645,17 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_printdd("%s trigger pause release\n", name); + dev_dbg(card->card->dev, "%s trigger pause release\n", name); card->pcm_start(substream); hpi_handle_error(hpi_stream_start(dpcm->h_stream)); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_printdd("%s trigger pause push\n", name); + dev_dbg(card->card->dev, "%s trigger pause push\n", name); card->pcm_stop(substream); hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); break; default: - snd_printd(KERN_ERR "\tINVALID\n"); + dev_dbg(card->card->dev, "\tINVALID\n"); return -EINVAL; } @@ -716,7 +709,7 @@ static inline unsigned int modulo_min(unsigned int a, unsigned int b, */ static void snd_card_asihpi_timer_function(struct timer_list *t) { - struct snd_card_asihpi_pcm *dpcm = from_timer(dpcm, t, timer); + struct snd_card_asihpi_pcm *dpcm = timer_container_of(dpcm, t, timer); struct snd_pcm_substream *substream = dpcm->substream; struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime; @@ -760,12 +753,13 @@ static void snd_card_asihpi_timer_function(struct timer_list *t) if (state == HPI_STATE_STOPPED) { if (bytes_avail == 0) { hpi_handle_error(hpi_stream_start(ds->h_stream)); - snd_printdd("P%d start\n", s->number); + dev_dbg(card->card->dev, + "P%d start\n", s->number); ds->drained_count = 0; } } else if (state == HPI_STATE_DRAINED) { - snd_printd(KERN_WARNING "P%d drained\n", - s->number); + dev_dbg(card->card->dev, + "P%d drained\n", s->number); ds->drained_count++; if (ds->drained_count > 20) { snd_pcm_stop_xrun(s); @@ -790,7 +784,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t) newdata); } - snd_printddd( + asihpi_dbg( "timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n", name, s->number, state, ds->pcm_buf_elapsed_dma_ofs, @@ -821,7 +815,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t) next_jiffies = max(next_jiffies, 1U); dpcm->timer.expires = jiffies + next_jiffies; - snd_printddd("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n", + asihpi_dbg("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n", next_jiffies, pcm_buf_dma_ofs, newdata, xfercount); snd_pcm_group_for_each_entry(s, substream) { @@ -854,7 +848,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t) } if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { - snd_printddd("write1, P=%d, xfer=%d, buf_ofs=%d\n", + asihpi_dbg("write1, P=%d, xfer=%d, buf_ofs=%d\n", s->number, xfer1, buf_ofs); hpi_handle_error( hpi_outstream_write_buf( @@ -864,7 +858,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t) if (xfer2) { pd = s->runtime->dma_area; - snd_printddd("write2, P=%d, xfer=%d, buf_ofs=%d\n", + asihpi_dbg("write2, P=%d, xfer=%d, buf_ofs=%d\n", s->number, xfercount - xfer1, buf_ofs); hpi_handle_error( @@ -874,7 +868,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t) &ds->format)); } } else { - snd_printddd("read1, C=%d, xfer=%d\n", + asihpi_dbg("read1, C=%d, xfer=%d\n", s->number, xfer1); hpi_handle_error( hpi_instream_read_buf( @@ -882,7 +876,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t) pd, xfer1)); if (xfer2) { pd = s->runtime->dma_area; - snd_printddd("read2, C=%d, xfer=%d\n", + asihpi_dbg("read2, C=%d, xfer=%d\n", s->number, xfer2); hpi_handle_error( hpi_instream_read_buf( @@ -919,8 +913,6 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream * struct snd_pcm_runtime *runtime = substream->runtime; struct snd_card_asihpi_pcm *dpcm = runtime->private_data; - snd_printdd("P%d prepare\n", substream->number); - hpi_handle_error(hpi_outstream_reset(dpcm->h_stream)); dpcm->pcm_buf_host_rw_ofs = 0; dpcm->pcm_buf_dma_ofs = 0; @@ -938,7 +930,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_debug_name(substream, name, sizeof(name)); ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes); - snd_printddd("%s, pointer=%ld\n", name, (unsigned long)ptr); + asihpi_dbg("%s, pointer=%ld\n", name, (unsigned long)ptr); return ptr; } @@ -1060,8 +1052,6 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, card->update_interval_frames, UINT_MAX); - snd_printdd("playback open\n"); - return 0; } @@ -1071,8 +1061,6 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream) struct snd_card_asihpi_pcm *dpcm = runtime->private_data; hpi_handle_error(hpi_outstream_close(dpcm->h_stream)); - snd_printdd("playback close\n"); - return 0; } @@ -1095,7 +1083,7 @@ snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream) char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); - snd_printddd("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs); + asihpi_dbg("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs); /* NOTE Unlike playback can't use actual samples_played for the capture position, because those samples aren't yet in the local buffer available for reading. @@ -1113,7 +1101,6 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream) dpcm->pcm_buf_dma_ofs = 0; dpcm->pcm_buf_elapsed_dma_ofs = 0; - snd_printdd("Capture Prepare %d\n", substream->number); return 0; } @@ -1162,8 +1149,9 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) if (dpcm == NULL) return -ENOMEM; - snd_printdd("capture open adapter %d stream %d\n", - card->hpi->adapter->index, substream->number); + + dev_dbg(card->card->dev, "capture open adapter %d stream %d\n", + card->hpi->adapter->index, substream->number); err = hpi_handle_error( hpi_instream_open(card->hpi->adapter->index, @@ -1413,8 +1401,6 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control, hpi_ctl->src_node_index, dir, name); } - /* printk(KERN_INFO "Adding %s %d to %d ", hpi_ctl->name, - hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */ } /*------------------------------------------------------------ @@ -2175,9 +2161,8 @@ static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol, return 0; } } - snd_printd(KERN_WARNING - "Control %x failed to match mux source %hu %hu\n", - h_control, source_type, source_index); + pr_warn("%s: Control %x failed to match mux source %hu %hu\n", + __func__, h_control, source_type, source_index); ucontrol->value.enumerated.item[0] = 0; return 0; } @@ -2315,8 +2300,7 @@ static const char * const sampleclock_sources[] = { static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct snd_card_asihpi *asihpi = - (struct snd_card_asihpi *)(kcontrol->private_data); + struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol); struct clk_cache *clkcache = &asihpi->cc; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -2334,8 +2318,7 @@ static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol, static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_card_asihpi *asihpi = - (struct snd_card_asihpi *)(kcontrol->private_data); + struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol); struct clk_cache *clkcache = &asihpi->cc; u32 h_control = kcontrol->private_value; u16 source, srcindex = 0; @@ -2362,8 +2345,7 @@ static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol, static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_card_asihpi *asihpi = - (struct snd_card_asihpi *)(kcontrol->private_data); + struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol); struct clk_cache *clkcache = &asihpi->cc; unsigned int item; int change; diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c index d0caef299481..b68e6bfbbfba 100644 --- a/sound/pci/asihpi/hpimsgx.c +++ b/sound/pci/asihpi/hpimsgx.c @@ -708,7 +708,7 @@ static u16 HPIMSGX__init(struct hpi_message *phm, phr->error = HPI_ERROR_PROCESSING_MESSAGE; return phr->error; } - if (hr.error == 0) { + if (hr.error == 0 && hr.u.s.adapter_index < HPI_MAX_ADAPTERS) { /* the adapter was created successfully save the mapping for future use */ hpi_entry_points[hr.u.s.adapter_index] = entry_point_func; diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 477a5b4b50bc..9fb0c8e503df 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -356,7 +356,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, memset(&adapter, 0, sizeof(adapter)); - dev_printk(KERN_DEBUG, &pci_dev->dev, + dev_dbg(&pci_dev->dev, "probe %04x:%04x,%04x:%04x,%04x\n", pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor, pci_dev->subsystem_device, pci_dev->devfn); diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index df2fef726d60..427006be240b 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1544,11 +1544,10 @@ static int snd_atiixp_init(struct snd_card *card, struct pci_dev *pci) chip->card = card; chip->pci = pci; chip->irq = -1; - err = pcim_iomap_regions(pci, 1 << 0, "ATI IXP AC97"); - if (err < 0) - return err; + chip->remap_addr = pcim_iomap_region(pci, 0, "ATI IXP AC97"); + if (IS_ERR(chip->remap_addr)) + return PTR_ERR(chip->remap_addr); chip->addr = pci_resource_start(pci, 0); - chip->remap_addr = pcim_iomap_table(pci)[0]; if (devm_request_irq(&pci->dev, pci->irq, snd_atiixp_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index eb569539f322..8d3083b9b024 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1174,11 +1174,10 @@ static int snd_atiixp_init(struct snd_card *card, struct pci_dev *pci) chip->card = card; chip->pci = pci; chip->irq = -1; - err = pcim_iomap_regions(pci, 1 << 0, "ATI IXP MC97"); - if (err < 0) - return err; + chip->remap_addr = pcim_iomap_region(pci, 0, "ATI IXP MC97"); + if (IS_ERR(chip->remap_addr)) + return PTR_ERR(chip->remap_addr); chip->addr = pci_resource_start(pci, 0); - chip->remap_addr = pcim_iomap_table(pci)[0]; if (devm_request_irq(&pci->dev, pci->irq, snd_atiixp_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { diff --git a/sound/pci/au88x0/Makefile b/sound/pci/au88x0/Makefile index 78ab11562f4d..5ec5abdee28d 100644 --- a/sound/pci/au88x0/Makefile +++ b/sound/pci/au88x0/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -snd-au8810-objs := au8810.o -snd-au8820-objs := au8820.o -snd-au8830-objs := au8830.o +snd-au8810-y := au8810.o +snd-au8820-y := au8820.o +snd-au8830-y := au8830.o obj-$(CONFIG_SND_AU8810) += snd-au8810.o obj-$(CONFIG_SND_AU8820) += snd-au8820.o diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 62b10b0e07b1..fd986247331a 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -160,12 +160,11 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci) // (1) PCI resource allocation // Get MMIO area // - err = pcim_iomap_regions(pci, 1 << 0, CARD_NAME_SHORT); - if (err) - return err; + chip->mmio = pcim_iomap_region(pci, 0, KBUILD_MODNAME); + if (IS_ERR(chip->mmio)) + return PTR_ERR(chip->mmio); chip->io = pci_resource_start(pci, 0); - chip->mmio = pcim_iomap_table(pci)[0]; /* Init audio core. * This must be done before we do request_irq otherwise we can get spurious diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index eabaee0463fe..d5cafaa229f1 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -754,7 +754,7 @@ snd_vortex_a3d_filter_info(struct snd_kcontrol *kcontrol, static int snd_vortex_a3d_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - //a3dsrc_t *a = kcontrol->private_data; + //a3dsrc_t *a = snd_kcontrol_chip(kcontrol); /* No read yet. Would this be really useable/needed ? */ return 0; @@ -764,7 +764,7 @@ static int snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - a3dsrc_t *a = kcontrol->private_data; + a3dsrc_t *a = snd_kcontrol_chip(kcontrol); int i; int coord[6]; for (i = 0; i < 6; i++) @@ -781,7 +781,7 @@ static int snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - a3dsrc_t *a = kcontrol->private_data; + a3dsrc_t *a = snd_kcontrol_chip(kcontrol); int coord[6]; int i; for (i = 0; i < 6; i++) @@ -800,7 +800,7 @@ static int snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - a3dsrc_t *a = kcontrol->private_data; + a3dsrc_t *a = snd_kcontrol_chip(kcontrol); int l, r; /* There may be some scale tranlation needed here. */ l = ucontrol->value.integer.value[0]; @@ -816,7 +816,7 @@ static int snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - a3dsrc_t *a = kcontrol->private_data; + a3dsrc_t *a = snd_kcontrol_chip(kcontrol); int i; int params[6]; for (i = 0; i < 6; i++) diff --git a/sound/pci/aw2/Makefile b/sound/pci/aw2/Makefile index f9045afb4cda..c246f7c7f2bf 100644 --- a/sound/pci/aw2/Makefile +++ b/sound/pci/aw2/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-aw2-objs := aw2-alsa.o aw2-saa7146.o +snd-aw2-y := aw2-alsa.o aw2-saa7146.o obj-$(CONFIG_SND_AW2) += snd-aw2.o diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 29a4bcdec237..7b4b8f785517 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -225,11 +225,10 @@ static int snd_aw2_create(struct snd_card *card, chip->irq = -1; /* (1) PCI resource allocation */ - err = pcim_iomap_regions(pci, 1 << 0, "Audiowerk2"); - if (err < 0) - return err; + chip->iobase_virt = pcim_iomap_region(pci, 0, "Audiowerk2"); + if (IS_ERR(chip->iobase_virt)) + return PTR_ERR(chip->iobase_virt); chip->iobase_phys = pci_resource_start(pci, 0); - chip->iobase_virt = pcim_iomap_table(pci)[0]; /* (2) initialization of the chip hardware */ snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt); diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 84989c291cd7..053a18f434bf 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1220,7 +1220,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec, case AZF_FREQ_22050: freq = SOUNDFORMAT_FREQ_22050; break; case AZF_FREQ_32000: freq = SOUNDFORMAT_FREQ_32000; break; default: - snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); + pr_warn("azf3328: unknown bitrate %d, assuming 44.1kHz!\n", bitrate); fallthrough; case AZF_FREQ_44100: freq = SOUNDFORMAT_FREQ_44100; break; case AZF_FREQ_48000: freq = SOUNDFORMAT_FREQ_48000; break; @@ -2347,7 +2347,7 @@ snd_azf3328_create(struct snd_card *card, return -ENXIO; } - err = pci_request_regions(pci, "Aztech AZF3328"); + err = pcim_request_all_regions(pci, "Aztech AZF3328"); if (err < 0) return err; diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 621985bfee5d..91492dd2b38a 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -696,10 +696,9 @@ static int snd_bt87x_create(struct snd_card *card, chip->irq = -1; spin_lock_init(&chip->reg_lock); - err = pcim_iomap_regions(pci, 1 << 0, "Bt87x audio"); - if (err < 0) - return err; - chip->mmio = pcim_iomap_table(pci)[0]; + chip->mmio = pcim_iomap_region(pci, 0, "Bt87x audio"); + if (IS_ERR(chip->mmio)) + return PTR_ERR(chip->mmio); chip->reg_control = CTL_A_PWRDN | CTL_DA_ES2 | CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT); diff --git a/sound/pci/ca0106/Makefile b/sound/pci/ca0106/Makefile index 9e51d3df3ee8..693dc4d80925 100644 --- a/sound/pci/ca0106/Makefile +++ b/sound/pci/ca0106/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-ca0106-objs := ca0106_main.o ca0106_mixer.o ca_midi.o +snd-ca0106-y := ca0106_main.o ca0106_mixer.o ca_midi.o snd-ca0106-$(CONFIG_SND_PROC_FS) += ca0106_proc.o obj-$(CONFIG_SND_CA0106) += snd-ca0106.o diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index cf1bac7a435f..7c7119cad63c 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1593,7 +1593,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card, spin_lock_init(&chip->emu_lock); - err = pci_request_regions(pci, "snd_ca0106"); + err = pcim_request_all_regions(pci, "snd_ca0106"); if (err < 0) return err; chip->port = pci_resource_start(pci, 0); diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 36014501f7ed..b00df0a60d3f 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -1570,14 +1570,6 @@ static const struct snd_pcm_hardware snd_cmipci_capture_spdif = .fifo_size = 0, }; -static const unsigned int rate_constraints[] = { 5512, 8000, 11025, 16000, 22050, - 32000, 44100, 48000, 88200, 96000, 128000 }; -static const struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = ARRAY_SIZE(rate_constraints), - .list = rate_constraints, - .mask = 0, -}; - /* * check device open/close */ @@ -1649,11 +1641,9 @@ static int snd_cmipci_playback_open(struct snd_pcm_substream *substream) SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; } else if (cm->chip_version == 55) { - err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); - if (err < 0) - return err; - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_128000; runtime->hw.rate_max = 128000; } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); @@ -1675,11 +1665,9 @@ static int snd_cmipci_capture_open(struct snd_pcm_substream *substream) runtime->hw.rate_min = 41000; runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; } else if (cm->chip_version == 55) { - err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); - if (err < 0) - return err; - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_128000; runtime->hw.rate_max = 128000; } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); @@ -1715,11 +1703,9 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; } else if (cm->chip_version == 55) { - err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); - if (err < 0) - return err; - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_128000; runtime->hw.rate_max = 128000; } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); @@ -2994,7 +2980,7 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, cm->channel[1].ch = 1; cm->channel[0].is_dac = cm->channel[1].is_dac = 1; /* dual DAC mode */ - err = pci_request_regions(pci, card->driver); + err = pcim_request_all_regions(pci, card->driver); if (err < 0) return err; cm->iobase = pci_resource_start(pci, 0); @@ -3098,7 +3084,7 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, } } } - sprintf(card->shortname, "C-Media CMI%d", val); + sprintf(card->shortname, "C-Media CMI%u", val); if (cm->chip_version < 68) scnprintf(modelstr, sizeof(modelstr), " (model %d)", cm->chip_version); diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 0cc86e73cc62..90958a422b75 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1302,14 +1302,15 @@ static int snd_cs4281_create(struct snd_card *card, } chip->dual_codec = dual_codec; - err = pcim_iomap_regions(pci, 0x03, "CS4281"); /* 2 BARs */ - if (err < 0) - return err; + chip->ba0 = pcim_iomap_region(pci, 0, "CS4281"); + if (IS_ERR(chip->ba0)) + return PTR_ERR(chip->ba0); chip->ba0_addr = pci_resource_start(pci, 0); - chip->ba1_addr = pci_resource_start(pci, 1); - chip->ba0 = pcim_iomap_table(pci)[0]; - chip->ba1 = pcim_iomap_table(pci)[1]; + chip->ba1 = pcim_iomap_region(pci, 1, "CS4281"); + if (IS_ERR(chip->ba1)) + return PTR_ERR(chip->ba1); + chip->ba1_addr = pci_resource_start(pci, 1); if (devm_request_irq(&pci->dev, pci->irq, snd_cs4281_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index f3a94bb537bd..fb733633740b 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3839,7 +3839,7 @@ int snd_cs46xx_create(struct snd_card *card, chip->pci = pci; chip->irq = -1; - err = pci_request_regions(pci, "CS46xx"); + err = pcim_request_all_regions(pci, "CS46xx"); if (err < 0) return err; chip->ba0_addr = pci_resource_start(pci, 0); diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 1f90ca723f4d..28faca268196 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -201,13 +201,6 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * if (ins->scb_highest_frag_index > ins->nscb) { ins->scb_highest_frag_index = ins->nscb; } - -#if 0 - /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */ - for(i = scb->index + 1;i < ins->nscb; ++i) { - ins->scbs[i - 1].index = i - 1; - } -#endif } diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index 93ff029e6583..532891e67c34 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -91,11 +91,10 @@ static int snd_cs5530_create(struct snd_card *card, chip->card = card; chip->pci = pci; - err = pcim_iomap_regions(pci, 1 << 0, "CS5530"); - if (err < 0) - return err; + mem = pcim_iomap_region(pci, 0, "CS5530"); + if (IS_ERR(mem)) + return PTR_ERR(mem); chip->pci_base = pci_resource_start(pci, 0); - mem = pcim_iomap_table(pci)[0]; map = readw(mem + 0x18); /* Map bits diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 440b8f9b40c9..0f319013a2a2 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -262,7 +262,7 @@ static int snd_cs5535audio_create(struct snd_card *card, cs5535au->pci = pci; cs5535au->irq = -1; - err = pci_request_regions(pci, "CS5535 Audio"); + err = pcim_request_all_regions(pci, "CS5535 Audio"); if (err < 0) return err; diff --git a/sound/pci/ctxfi/Makefile b/sound/pci/ctxfi/Makefile index 70888706a0af..ff2b1cba3a3c 100644 --- a/sound/pci/ctxfi/Makefile +++ b/sound/pci/ctxfi/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \ +snd-ctxfi-y := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \ ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \ cthw20k2.o cthw20k1.o diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 83aaf9441ef3..806c4d754387 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -159,7 +159,7 @@ static int dao_set_left_input(struct dao *dao, struct rsc *input) struct daio *daio = &dao->daio; int i; - entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL); + entry = kcalloc(daio->rscl.msr, sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -188,7 +188,7 @@ static int dao_set_right_input(struct dao *dao, struct rsc *input) struct daio *daio = &dao->daio; int i; - entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL); + entry = kcalloc(daio->rscr.msr, sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -211,52 +211,30 @@ static int dao_set_right_input(struct dao *dao, struct rsc *input) return 0; } -static int dao_clear_left_input(struct dao *dao) +static int dao_clear_input(struct dao *dao, unsigned int start, unsigned int end) { - struct imapper *entry; - struct daio *daio = &dao->daio; - int i; + unsigned int i; - if (!dao->imappers[0]) + if (!dao->imappers[start]) return 0; - - entry = dao->imappers[0]; - dao->mgr->imap_delete(dao->mgr, entry); - /* Program conjugate resources */ - for (i = 1; i < daio->rscl.msr; i++) { - entry = dao->imappers[i]; - dao->mgr->imap_delete(dao->mgr, entry); + for (i = start; i < end; i++) { + dao->mgr->imap_delete(dao->mgr, dao->imappers[i]); dao->imappers[i] = NULL; } - kfree(dao->imappers[0]); - dao->imappers[0] = NULL; - return 0; } -static int dao_clear_right_input(struct dao *dao) -{ - struct imapper *entry; - struct daio *daio = &dao->daio; - int i; - if (!dao->imappers[daio->rscl.msr]) - return 0; - - entry = dao->imappers[daio->rscl.msr]; - dao->mgr->imap_delete(dao->mgr, entry); - /* Program conjugate resources */ - for (i = 1; i < daio->rscr.msr; i++) { - entry = dao->imappers[daio->rscl.msr + i]; - dao->mgr->imap_delete(dao->mgr, entry); - dao->imappers[daio->rscl.msr + i] = NULL; - } - - kfree(dao->imappers[daio->rscl.msr]); - dao->imappers[daio->rscl.msr] = NULL; +static int dao_clear_left_input(struct dao *dao) +{ + return dao_clear_input(dao, 0, dao->daio.rscl.msr); +} - return 0; +static int dao_clear_right_input(struct dao *dao) +{ + return dao_clear_input(dao, dao->daio.rscl.msr, + dao->daio.rscl.msr + dao->daio.rscr.msr); } static const struct dao_rsc_ops dao_ops = { diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index 0bb447ccd77c..fa6867adb42b 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -62,7 +62,7 @@ struct ct_timer { static void ct_systimer_callback(struct timer_list *t) { - struct ct_timer_instance *ti = from_timer(ti, t, timer); + struct ct_timer_instance *ti = timer_container_of(ti, t, timer); struct snd_pcm_substream *substream = ti->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct ct_atc_pcm *apcm = ti->apcm; @@ -112,14 +112,14 @@ static void ct_systimer_stop(struct ct_timer_instance *ti) spin_lock_irqsave(&ti->lock, flags); ti->running = 0; - del_timer(&ti->timer); + timer_delete(&ti->timer); spin_unlock_irqrestore(&ti->lock, flags); } static void ct_systimer_prepare(struct ct_timer_instance *ti) { ct_systimer_stop(ti); - try_to_del_timer_sync(&ti->timer); + timer_delete_sync_try(&ti->timer); } #define ct_systimer_free ct_systimer_prepare diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 713d36ea40cb..d8dd84d41c87 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -98,8 +98,8 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (err < 0) goto error; - strcpy(card->driver, "SB-XFi"); - strcpy(card->shortname, "Creative X-Fi"); + strscpy(card->driver, "SB-XFi"); + strscpy(card->shortname, "Creative X-Fi"); snprintf(card->longname, sizeof(card->longname), "%s %s %s", card->shortname, atc->chip_name, atc->model_name); diff --git a/sound/pci/echoaudio/Makefile b/sound/pci/echoaudio/Makefile index 4865b8fe7434..96667641c7cf 100644 --- a/sound/pci/echoaudio/Makefile +++ b/sound/pci/echoaudio/Makefile @@ -4,20 +4,20 @@ # Copyright (c) 2003 by Giuliano Pochini <pochini@shiny.it> # -snd-darla20-objs := darla20.o -snd-gina20-objs := gina20.o -snd-layla20-objs := layla20.o -snd-darla24-objs := darla24.o -snd-gina24-objs := gina24.o -snd-layla24-objs := layla24.o -snd-mona-objs := mona.o -snd-mia-objs := mia.o -snd-echo3g-objs := echo3g.o -snd-indigo-objs := indigo.o -snd-indigoio-objs := indigoio.o -snd-indigodj-objs := indigodj.o -snd-indigoiox-objs := indigoiox.o -snd-indigodjx-objs := indigodjx.o +snd-darla20-y := darla20.o +snd-gina20-y := gina20.o +snd-layla20-y := layla20.o +snd-darla24-y := darla24.o +snd-gina24-y := gina24.o +snd-layla24-y := layla24.o +snd-mona-y := mona.o +snd-mia-y := mia.o +snd-echo3g-y := echo3g.o +snd-indigo-y := indigo.o +snd-indigoio-y := indigoio.o +snd-indigodj-y := indigodj.o +snd-indigoiox-y := indigoiox.o +snd-indigodjx-y := indigodjx.o obj-$(CONFIG_SND_DARLA20) += snd-darla20.o obj-$(CONFIG_SND_GINA20) += snd-gina20.o diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 7484de255a3e..80d8ce75fdbb 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1910,7 +1910,7 @@ static int snd_echo_create(struct snd_card *card, chip->can_set_rate = 1; /* PCI resource allocation */ - err = pci_request_regions(pci, ECHOCARD_NAME); + err = pcim_request_all_regions(pci, ECHOCARD_NAME); if (err < 0) return err; @@ -1966,7 +1966,6 @@ static int __snd_echo_probe(struct pci_dev *pci, struct snd_card *card; struct echoaudio *chip; char *dsp; - __maybe_unused int i; int err; if (dev >= SNDRV_CARDS) @@ -1976,7 +1975,6 @@ static int __snd_echo_probe(struct pci_dev *pci, return -ENOENT; } - i = 0; err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, sizeof(*chip), &card); if (err < 0) @@ -2080,7 +2078,7 @@ static int __snd_echo_probe(struct pci_dev *pci, #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH /* Creates a list of available digital modes */ chip->num_digital_modes = 0; - for (i = 0; i < 6; i++) + for (int i = 0; i < 6; i++) if (chip->digital_modes & (1 << i)) chip->digital_mode_list[chip->num_digital_modes++] = i; @@ -2092,7 +2090,7 @@ static int __snd_echo_probe(struct pci_dev *pci, #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK /* Creates a list of available clock sources */ chip->num_clock_sources = 0; - for (i = 0; i < 10; i++) + for (int i = 0; i < 10; i++) if (chip->input_clock_types & (1 << i)) chip->clock_source_list[chip->num_clock_sources++] = i; diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index 47b2c023ee3d..c3f3c9129561 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -200,7 +200,7 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream) static void snd_echo_midi_output_write(struct timer_list *t) { - struct echoaudio *chip = from_timer(chip, t, timer); + struct echoaudio *chip = timer_container_of(chip, t, timer); unsigned long flags; int bytes, sent, time; unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1]; @@ -264,7 +264,7 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream if (chip->tinuse) { chip->tinuse = 0; spin_unlock_irq(&chip->lock); - del_timer_sync(&chip->timer); + timer_delete_sync(&chip->timer); dev_dbg(chip->card->dev, "Timer removed\n"); return; } diff --git a/sound/pci/emu10k1/Makefile b/sound/pci/emu10k1/Makefile index 17d5527be319..1f325abcb3ef 100644 --- a/sound/pci/emu10k1/Makefile +++ b/sound/pci/emu10k1/Makefile @@ -4,12 +4,12 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-emu10k1-objs := emu10k1.o emu10k1_main.o \ +snd-emu10k1-y := emu10k1.o emu10k1_main.o \ irq.o memory.o voice.o emumpu401.o emupcm.o io.o \ emumixer.o emufx.o timer.o p16v.o snd-emu10k1-$(CONFIG_SND_PROC_FS) += emuproc.o -snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o -snd-emu10k1x-objs := emu10k1x.o +snd-emu10k1-synth-y := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o +snd-emu10k1x-y := emu10k1x.o # Toplevel Module Dependency obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index fe72e7d77241..dadeda7758ce 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -189,8 +189,7 @@ static int snd_emu10k1_suspend(struct device *dev) emu->suspend = 1; - cancel_work_sync(&emu->emu1010.firmware_work); - cancel_work_sync(&emu->emu1010.clock_work); + cancel_work_sync(&emu->emu1010.work); snd_ac97_suspend(emu->ac97); diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index d36234b88fb4..ef26e4d3e2a3 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -255,7 +255,7 @@ lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw, /* check if sample is finished playing (non-looping only) */ if (bp != best + V_OFF && bp != best + V_FREE && (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) { - val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64; + val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64 + 3; if (val >= vp->reg.loopstart) bp = best + V_OFF; } @@ -310,6 +310,7 @@ start_voice(struct snd_emux_voice *vp) { unsigned int temp; int ch; + bool w_16; u32 psst, dsl, map, ccca, vtarget; unsigned int addr, mapped_offset; struct snd_midi_channel *chan; @@ -321,6 +322,7 @@ start_voice(struct snd_emux_voice *vp) if (snd_BUG_ON(ch < 0)) return -EINVAL; chan = vp->chan; + w_16 = !(vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS); emem = (struct snd_emu10k1_memblk *)vp->block; if (emem == NULL) @@ -330,7 +332,7 @@ start_voice(struct snd_emux_voice *vp) /* dev_err(hw->card->devK, "emu: cannot map!\n"); */ return -ENOMEM; } - mapped_offset = snd_emu10k1_memblk_offset(emem) >> 1; + mapped_offset = snd_emu10k1_memblk_offset(emem) >> w_16; vp->reg.start += mapped_offset; vp->reg.end += mapped_offset; vp->reg.loopstart += mapped_offset; @@ -362,7 +364,7 @@ start_voice(struct snd_emux_voice *vp) map = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); - addr = vp->reg.start + 64; + addr = vp->reg.start + 64 - 3; temp = vp->reg.parm.filterQ; ccca = (temp << 28) | addr; if (vp->apitch < 0xe400) @@ -371,7 +373,7 @@ start_voice(struct snd_emux_voice *vp) unsigned int shift = (vp->apitch - 0xe000) >> 10; ccca |= shift << 25; } - if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS) + if (!w_16) ccca |= CCCA_8BITSELECT; vtarget = (unsigned int)vp->vtarget << 16; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index de5c41e578e1..bbe252b8916c 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -652,52 +652,6 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) return 0; } -static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, - const struct firmware *fw_entry) -{ - int n, i; - u16 reg; - u8 value; - __always_unused u16 write_post; - - if (!fw_entry) - return -EIO; - - /* The FPGA is a Xilinx Spartan IIE XC2S50E */ - /* On E-MU 0404b it is a Xilinx Spartan III XC3S50 */ - /* GPIO7 -> FPGA PGMN - * GPIO6 -> FPGA CCLK - * GPIO5 -> FPGA DIN - * FPGA CONFIG OFF -> FPGA PGMN - */ - spin_lock_irq(&emu->emu_lock); - outw(0x00, emu->port + A_GPIO); /* Set PGMN low for 100uS. */ - write_post = inw(emu->port + A_GPIO); - udelay(100); - outw(0x80, emu->port + A_GPIO); /* Leave bit 7 set during netlist setup. */ - write_post = inw(emu->port + A_GPIO); - udelay(100); /* Allow FPGA memory to clean */ - for (n = 0; n < fw_entry->size; n++) { - value = fw_entry->data[n]; - for (i = 0; i < 8; i++) { - reg = 0x80; - if (value & 0x1) - reg = reg | 0x20; - value = value >> 1; - outw(reg, emu->port + A_GPIO); - write_post = inw(emu->port + A_GPIO); - outw(reg | 0x40, emu->port + A_GPIO); - write_post = inw(emu->port + A_GPIO); - } - } - /* After programming, set GPIO bit 4 high again. */ - outw(0x10, emu->port + A_GPIO); - write_post = inw(emu->port + A_GPIO); - spin_unlock_irq(&emu->emu_lock); - - return 0; -} - /* firmware file names, per model, init-fw and dock-fw (optional) */ static const char * const firmware_names[5][2] = { [EMU_MODEL_EMU1010] = { @@ -729,72 +683,68 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock, return err; } - return snd_emu1010_load_firmware_entry(emu, *fw); + snd_emu1010_load_firmware_entry(emu, dock, *fw); + return 0; } -static void emu1010_firmware_work(struct work_struct *work) +static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu) { - struct snd_emu10k1 *emu; - u32 tmp, tmp2, reg; + u32 tmp, tmp2; int err; - emu = container_of(work, struct snd_emu10k1, - emu1010.firmware_work); - if (emu->card->shutdown) + // The docking events clearly arrive prematurely - while the + // Dock's FPGA seems to be successfully programmed, the Dock + // fails to initialize subsequently if we don't give it some + // time to "warm up" here. + msleep(200); + + dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n"); + err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw); + if (err < 0) return; -#ifdef CONFIG_PM_SLEEP - if (emu->suspend) + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); + + snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp); + dev_dbg(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp); + if ((tmp & 0x1f) != 0x15) { + /* FPGA failed to be programmed */ + dev_err(emu->card->dev, + "emu1010: Loading Audio Dock Firmware failed, reg = 0x%x\n", + tmp); return; -#endif + } + dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n"); + + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2); + dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2); + + /* Allow DLL to settle, to sync clocking between 1010 and Dock */ + msleep(10); +} + +static void emu1010_dock_event(struct snd_emu10k1 *emu) +{ + u32 reg; + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { /* Audio Dock attached */ - /* Return to Audio Dock programming mode */ - dev_info(emu->card->dev, - "emu1010: Loading Audio Dock Firmware\n"); - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, - EMU_HANA_FPGA_CONFIG_AUDIODOCK); - err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw); - if (err < 0) - return; - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); - snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp); - dev_info(emu->card->dev, - "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp); - if ((tmp & 0x1f) != 0x15) { - /* FPGA failed to be programmed */ - dev_info(emu->card->dev, - "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", - tmp); - return; - } - dev_info(emu->card->dev, - "emu1010: Audio Dock Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp); - snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2); - dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2); - /* Sync clocking between 1010 and Dock */ - /* Allow DLL to settle */ - msleep(10); + snd_emu1010_load_dock_firmware(emu); /* Unmute all. Default is muted after a firmware load */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + } else if (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) { + /* Audio Dock removed */ + dev_info(emu->card->dev, "emu1010: Audio Dock detached\n"); + /* The hardware auto-mutes all, so we unmute again */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); } } -static void emu1010_clock_work(struct work_struct *work) +static void emu1010_clock_event(struct snd_emu10k1 *emu) { - struct snd_emu10k1 *emu; struct snd_ctl_elem_id id; - emu = container_of(work, struct snd_emu10k1, - emu1010.clock_work); - if (emu->card->shutdown) - return; -#ifdef CONFIG_PM_SLEEP - if (emu->suspend) - return; -#endif - spin_lock_irq(&emu->reg_lock); // This is the only thing that can actually happen. emu->emu1010.clock_source = emu->emu1010.clock_fallback; @@ -805,21 +755,44 @@ static void emu1010_clock_work(struct work_struct *work) snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id); } -static void emu1010_interrupt(struct snd_emu10k1 *emu) +static void emu1010_work(struct work_struct *work) { + struct snd_emu10k1 *emu; u32 sts; + emu = container_of(work, struct snd_emu10k1, emu1010.work); + if (emu->card->shutdown) + return; +#ifdef CONFIG_PM_SLEEP + if (emu->suspend) + return; +#endif + + snd_emu1010_fpga_lock(emu); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts); - if (sts & EMU_HANA_IRQ_DOCK_LOST) { - /* Audio Dock removed */ - dev_info(emu->card->dev, "emu1010: Audio Dock detached\n"); - /* The hardware auto-mutes all, so we unmute again */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); - } else if (sts & EMU_HANA_IRQ_DOCK) { - schedule_work(&emu->emu1010.firmware_work); - } + + // The distinction of the IRQ status bits is unreliable, + // so we dispatch later based on option card status. + if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST)) + emu1010_dock_event(emu); + if (sts & EMU_HANA_IRQ_WCLK_CHANGED) - schedule_work(&emu->emu1010.clock_work); + emu1010_clock_event(emu); + + snd_emu1010_fpga_unlock(emu); +} + +static void emu1010_interrupt(struct snd_emu10k1 *emu) +{ + // We get an interrupt on each GPIO input pin change, but we + // care only about the ones triggered by the dedicated pin. + u16 sts = inw(emu->port + A_GPIO); + u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000; + if (!(sts & bit)) + return; + + schedule_work(&emu->emu1010.work); } /* @@ -841,32 +814,13 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) * Proper init follows in snd_emu10k1_init(). */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); - /* Disable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); - - /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); - dev_dbg(emu->card->dev, "reg1 = 0x%x\n", reg); - if ((reg & 0x3f) == 0x15) { - /* FPGA netlist already present so clear it */ - /* Return to programming mode */ - - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_HANA); - } - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); - dev_dbg(emu->card->dev, "reg2 = 0x%x\n", reg); - if ((reg & 0x3f) == 0x15) { - /* FPGA failed to return to programming mode */ - dev_info(emu->card->dev, - "emu1010: FPGA failed to return to programming mode\n"); - return -ENODEV; - } - dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg); + snd_emu1010_fpga_lock(emu); + dev_info(emu->card->dev, "emu1010: Loading Hana Firmware\n"); err = snd_emu1010_load_firmware(emu, 0, &emu->firmware); if (err < 0) { dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n"); - return err; + goto fail; } /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ @@ -876,7 +830,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) dev_info(emu->card->dev, "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg); - return -ENODEV; + err = -ENODEV; + goto fail; } dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n"); @@ -889,7 +844,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg); if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) - schedule_work(&emu->emu1010.firmware_work); + snd_emu1010_load_dock_firmware(emu); if (emu->card_capabilities->no_adat) { emu->emu1010.optical_in = 0; /* IN_SPDIF */ emu->emu1010.optical_out = 0; /* OUT_SPDIF */ @@ -936,7 +891,9 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) // so it is safe to simply enable the outputs. snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); - return 0; +fail: + snd_emu1010_fpga_unlock(emu); + return err; } /* * Create the EMU10K1 instance @@ -958,10 +915,10 @@ static void snd_emu10k1_free(struct snd_card *card) } if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { /* Disable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_DOCK_PWR, 0); } - cancel_work_sync(&emu->emu1010.firmware_work); - cancel_work_sync(&emu->emu1010.clock_work); + cancel_work_sync(&emu->emu1010.work); + mutex_destroy(&emu->emu1010.lock); release_firmware(emu->firmware); release_firmware(emu->dock_fw); snd_util_memhdr_free(emu->memhdr); @@ -1540,8 +1497,8 @@ int snd_emu10k1_create(struct snd_card *card, emu->irq = -1; emu->synth = NULL; emu->get_synth_voice = NULL; - INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work); - INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_work); + INIT_WORK(&emu->emu1010.work, emu1010_work); + mutex_init(&emu->emu1010.lock); /* read revision & serial */ emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); @@ -1606,7 +1563,7 @@ int snd_emu10k1_create(struct snd_card *card, else emu->gpr_base = FXGPREGBASE; - err = pci_request_regions(pci, "EMU10K1"); + err = pcim_request_all_regions(pci, "EMU10K1"); if (err < 0) return err; emu->port = pci_resource_start(pci, 0); diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c index 89890f24509f..806b4f95cad1 100644 --- a/sound/pci/emu10k1/emu10k1_patch.c +++ b/sound/pci/emu10k1/emu10k1_patch.c @@ -16,7 +16,7 @@ #define BLANK_LOOP_START 4 #define BLANK_LOOP_END 8 #define BLANK_LOOP_SIZE 12 -#define BLANK_HEAD_SIZE 32 +#define BLANK_HEAD_SIZE 3 /* * allocate a sample block and copy data from userspace @@ -26,56 +26,77 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, struct snd_util_memhdr *hdr, const void __user *data, long count) { + u8 fill; + u32 xor; + int shift; int offset; int truesize, size, blocksize; - __maybe_unused int loopsize; - int loopend, sampleend; - unsigned int start_addr; + int loop_start, loop_end, loop_size, data_end, unroll; struct snd_emu10k1 *emu; emu = rec->hw; if (snd_BUG_ON(!sp || !hdr)) return -EINVAL; - if (sp->v.size == 0) { - dev_dbg(emu->card->dev, - "emu: rom font for sample %d\n", sp->v.sample); - return 0; + if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP | SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) { + /* should instead return -ENOTSUPP; but compatibility */ + dev_warn(emu->card->dev, + "Emu10k1 wavetable patch %d with unsupported loop feature\n", + sp->v.sample); } - /* recalculate address offset */ - sp->v.end -= sp->v.start; - sp->v.loopstart -= sp->v.start; - sp->v.loopend -= sp->v.start; - sp->v.start = 0; - - /* some samples have invalid data. the addresses are corrected in voice info */ - sampleend = sp->v.end; - if (sampleend > sp->v.size) - sampleend = sp->v.size; - loopend = sp->v.loopend; - if (loopend > sampleend) - loopend = sampleend; - - /* be sure loop points start < end */ - if (sp->v.loopstart >= sp->v.loopend) - swap(sp->v.loopstart, sp->v.loopend); + if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) { + shift = 0; + fill = 0x80; + xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0 : 0x80808080; + } else { + shift = 1; + fill = 0; + xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0x80008000 : 0; + } /* compute true data size to be loaded */ truesize = sp->v.size + BLANK_HEAD_SIZE; - loopsize = 0; -#if 0 /* not supported */ - if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) - loopsize = sp->v.loopend - sp->v.loopstart; - truesize += loopsize; -#endif - if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) + if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) { truesize += BLANK_LOOP_SIZE; + /* if no blank loop is attached in the sample, add it */ + if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) { + sp->v.loopstart = sp->v.end + BLANK_LOOP_START; + sp->v.loopend = sp->v.end + BLANK_LOOP_END; + } + } + + loop_start = sp->v.loopstart; + loop_end = sp->v.loopend; + loop_size = loop_end - loop_start; + if (!loop_size) + return -EINVAL; + data_end = sp->v.end; + + /* recalculate offset */ + sp->v.start += BLANK_HEAD_SIZE; + sp->v.end += BLANK_HEAD_SIZE; + sp->v.loopstart += BLANK_HEAD_SIZE; + sp->v.loopend += BLANK_HEAD_SIZE; + + // Automatic pre-filling of the cache does not work in the presence + // of loops (*), and we don't want to fill it manually, as that is + // fiddly and slow. So we unroll the loop until the loop end is + // beyond the cache size. + // (*) Strictly speaking, a single iteration is supported (that's + // how it works when the playback engine runs), but handling this + // special case is not worth it. + unroll = 0; + while (sp->v.loopend < 64) { + truesize += loop_size; + sp->v.loopstart += loop_size; + sp->v.loopend += loop_size; + sp->v.end += loop_size; + unroll++; + } /* try to allocate a memory block */ - blocksize = truesize; - if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) - blocksize *= 2; + blocksize = truesize << shift; sp->block = snd_emu10k1_synth_alloc(emu, blocksize); if (sp->block == NULL) { dev_dbg(emu->card->dev, @@ -88,110 +109,43 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, /* write blank samples at head */ offset = 0; - size = BLANK_HEAD_SIZE; - if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) - size *= 2; - if (offset + size > blocksize) - return -EINVAL; - snd_emu10k1_synth_bzero(emu, sp->block, offset, size); - offset += size; - - /* copy start->loopend */ - size = loopend; - if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) - size *= 2; - if (offset + size > blocksize) - return -EINVAL; - if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { - snd_emu10k1_synth_free(emu, sp->block); - sp->block = NULL; - return -EFAULT; - } + size = BLANK_HEAD_SIZE << shift; + snd_emu10k1_synth_memset(emu, sp->block, offset, size, fill); offset += size; - data += size; - -#if 0 /* not supported yet */ - /* handle reverse (or bidirectional) loop */ - if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) { - /* copy loop in reverse */ - if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) { - int woffset; - unsigned short *wblock = (unsigned short*)block; - woffset = offset / 2; - if (offset + loopsize * 2 > blocksize) - return -EINVAL; - for (i = 0; i < loopsize; i++) - wblock[woffset + i] = wblock[woffset - i -1]; - offset += loopsize * 2; - } else { - if (offset + loopsize > blocksize) - return -EINVAL; - for (i = 0; i < loopsize; i++) - block[offset + i] = block[offset - i -1]; - offset += loopsize; - } - /* modify loop pointers */ - if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) { - sp->v.loopend += loopsize; - } else { - sp->v.loopstart += loopsize; - sp->v.loopend += loopsize; + /* copy provided samples */ + if (unroll && loop_end <= data_end) { + size = loop_end << shift; + if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) + goto faulty; + offset += size; + + data += loop_start << shift; + while (--unroll > 0) { + size = loop_size << shift; + if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) + goto faulty; + offset += size; } - /* add sample pointer */ - sp->v.end += loopsize; - } -#endif - /* loopend -> sample end */ - size = sp->v.size - loopend; - if (size < 0) - return -EINVAL; - if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) - size *= 2; - if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { - snd_emu10k1_synth_free(emu, sp->block); - sp->block = NULL; - return -EFAULT; + size = (data_end - loop_start) << shift; + } else { + size = data_end << shift; } + if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) + goto faulty; offset += size; /* clear rest of samples (if any) */ if (offset < blocksize) - snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset); - - if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) { - /* if no blank loop is attached in the sample, add it */ - if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) { - sp->v.loopstart = sp->v.end + BLANK_LOOP_START; - sp->v.loopend = sp->v.end + BLANK_LOOP_END; - } - } - -#if 0 /* not supported yet */ - if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) { - /* unsigned -> signed */ - if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) { - unsigned short *wblock = (unsigned short*)block; - for (i = 0; i < truesize; i++) - wblock[i] ^= 0x8000; - } else { - for (i = 0; i < truesize; i++) - block[i] ^= 0x80; - } - } -#endif - - /* recalculate offset */ - start_addr = BLANK_HEAD_SIZE * 2; - if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) - start_addr >>= 1; - sp->v.start += start_addr; - sp->v.end += start_addr; - sp->v.loopstart += start_addr; - sp->v.loopend += start_addr; + snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill); return 0; + +faulty: + snd_emu10k1_synth_free(emu, sp->block); + sp->block = NULL; + return -EFAULT; } /* diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 89043392f3ec..30ac37b5a214 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -884,7 +884,7 @@ static int snd_emu10k1x_create(struct snd_card *card, spin_lock_init(&chip->emu_lock); spin_lock_init(&chip->voice_lock); - err = pci_request_regions(pci, "EMU10K1X"); + err = pcim_request_all_regions(pci, "EMU10K1X"); if (err < 0) return err; chip->port = pci_resource_start(pci, 0); diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 0a32ea53d8c6..05b98d9b547b 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -661,7 +661,9 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.output_source[channel] != val); if (change) { emu->emu1010.output_source[channel] = val; + snd_emu1010_fpga_lock(emu); snd_emu1010_output_source_apply(emu, channel, val); + snd_emu1010_fpga_unlock(emu); } return change; } @@ -705,7 +707,9 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.input_source[channel] != val); if (change) { emu->emu1010.input_source[channel] = val; + snd_emu1010_fpga_lock(emu); snd_emu1010_input_source_apply(emu, channel, val); + snd_emu1010_fpga_unlock(emu); } return change; } @@ -774,7 +778,7 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct cache = cache & ~mask; change = (cache != emu->emu1010.adc_pads); if (change) { - snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_ADC_PADS, cache ); emu->emu1010.adc_pads = cache; } @@ -832,7 +836,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct cache = cache & ~mask; change = (cache != emu->emu1010.dac_pads); if (change) { - snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_DAC_PADS, cache ); emu->emu1010.dac_pads = cache; } @@ -980,6 +984,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, val = ucontrol->value.enumerated.item[0] ; if (val >= emu_ci->num) return -EINVAL; + snd_emu1010_fpga_lock(emu); spin_lock_irq(&emu->reg_lock); change = (emu->emu1010.clock_source != val); if (change) { @@ -996,6 +1001,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, } else { spin_unlock_irq(&emu->reg_lock); } + snd_emu1010_fpga_unlock(emu); return change; } @@ -1041,7 +1047,7 @@ static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.clock_fallback != val); if (change) { emu->emu1010.clock_fallback = val; - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_DEFCLOCK, 1 - val); } return change; } @@ -1093,7 +1099,7 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, emu->emu1010.optical_out = val; tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp); } return change; } @@ -1144,7 +1150,7 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, emu->emu1010.optical_in = val; tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp); } return change; } @@ -2323,7 +2329,9 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, for (i = 0; i < emu_ri->n_outs; i++) emu->emu1010.output_source[i] = emu1010_map_source(emu_ri, emu_ri->out_dflts[i]); + snd_emu1010_fpga_lock(emu); snd_emu1010_apply_sources(emu); + snd_emu1010_fpga_unlock(emu); kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu); err = snd_ctl_add(card, kctl); diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 7f4c1b38d6ec..1bf6e3d652f8 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -147,16 +147,6 @@ static const struct snd_pcm_hw_constraint_list hw_constraints_capture_buffer_siz .mask = 0 }; -static const unsigned int capture_rates[8] = { - 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 -}; - -static const struct snd_pcm_hw_constraint_list hw_constraints_capture_rates = { - .count = 8, - .list = capture_rates, - .mask = 0 -}; - static unsigned int snd_emu10k1_capture_rate_reg(unsigned int rate) { switch (rate) { @@ -174,16 +164,6 @@ static unsigned int snd_emu10k1_capture_rate_reg(unsigned int rate) } } -static const unsigned int audigy_capture_rates[9] = { - 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 -}; - -static const struct snd_pcm_hw_constraint_list hw_constraints_audigy_capture_rates = { - .count = 9, - .list = audigy_capture_rates, - .mask = 0 -}; - static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate) { switch (rate) { @@ -207,17 +187,16 @@ static void snd_emu10k1_constrain_capture_rates(struct snd_emu10k1 *emu, { if (emu->card_capabilities->emu_model && emu->emu1010.word_clock == 44100) { - // This also sets the rate constraint by deleting SNDRV_PCM_RATE_KNOT runtime->hw.rates = SNDRV_PCM_RATE_11025 | \ SNDRV_PCM_RATE_22050 | \ SNDRV_PCM_RATE_44100; runtime->hw.rate_min = 11025; runtime->hw.rate_max = 44100; - return; + } else if (emu->audigy) { + runtime->hw.rates = SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_12000 | + SNDRV_PCM_RATE_24000; } - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - emu->audigy ? &hw_constraints_audigy_capture_rates : - &hw_constraints_capture_rates); } static void snd_emu1010_constrain_efx_rate(struct snd_emu10k1 *emu, @@ -1053,7 +1032,7 @@ static const struct snd_pcm_hardware snd_emu10k1_capture = SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_24000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 2f80fd91017c..bd4734dc04cd 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/init.h> +#include <linux/string_choices.h> #include <sound/core.h> #include <sound/emu10k1.h> #include "p16v.h" @@ -32,9 +33,9 @@ static void snd_emu10k1_proc_spdif_status(struct snd_emu10k1 * emu, snd_iprintf(buffer, "\n%s\n", title); if (status != 0xffffffff) { - snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); - snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); - snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); + snd_iprintf(buffer, "Professional Mode : %s\n", str_yes_no(status & SPCS_PROFESSIONAL)); + snd_iprintf(buffer, "Not Audio Data : %s\n", str_yes_no(status & SPCS_NOTAUDIODATA)); + snd_iprintf(buffer, "Copyright : %s\n", str_yes_no(status & SPCS_COPYRIGHT)); snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); @@ -46,9 +47,9 @@ static void snd_emu10k1_proc_spdif_status(struct snd_emu10k1 * emu, if (rate_reg > 0) { rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); - snd_iprintf(buffer, "S/PDIF Valid : %s\n", rate & SRCS_SPDIFVALID ? "on" : "off"); - snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); - snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); + snd_iprintf(buffer, "S/PDIF Valid : %s\n", str_on_off(rate & SRCS_SPDIFVALID)); + snd_iprintf(buffer, "S/PDIF Locked : %s\n", str_on_off(rate & SRCS_SPDIFLOCKED)); + snd_iprintf(buffer, "Rate Locked : %s\n", str_on_off(rate & SRCS_RATELOCKED)); /* From ((Rate * 48000 ) / 262144); */ snd_iprintf(buffer, "Estimated Sample Rate : %d\n", ((rate & 0xFFFFF ) * 375) >> 11); } @@ -165,6 +166,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, u32 value2; if (emu->card_capabilities->emu_model) { + snd_emu1010_fpga_lock(emu); + // This represents the S/PDIF lock status on 0404b, which is // kinda weird and unhelpful, because monitoring it via IRQ is // impractical (one gets an IRQ flood as long as it is desynced). @@ -197,6 +200,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\nS/PDIF mode: %s%s\n", value & EMU_HANA_SPDIF_MODE_RX_PRO ? "professional" : "consumer", value & EMU_HANA_SPDIF_MODE_RX_NOCOPY ? ", no copy" : ""); + + snd_emu1010_fpga_unlock(emu); } else { snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); @@ -204,7 +209,7 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, #if 0 val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0); snd_iprintf(buffer, "\nZoomed Video\n"); - snd_iprintf(buffer, "Rate Locked : %s\n", val & SRCS_RATELOCKED ? "on" : "off"); + snd_iprintf(buffer, "Rate Locked : %s\n", str_on_off(val & SRCS_RATELOCKED)); snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", val & SRCS_ESTSAMPLERATE); #endif } @@ -458,6 +463,9 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, struct snd_emu10k1 *emu = entry->private_data; u32 value; int i; + + snd_emu1010_fpga_lock(emu); + snd_iprintf(buffer, "EMU1010 Registers:\n\n"); for(i = 0; i < 0x40; i+=1) { @@ -496,6 +504,8 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, snd_emu_proc_emu1010_link_read(emu, buffer, 0x701); } } + + snd_emu1010_fpga_unlock(emu); } static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 74df2330015f..b60ab5671e00 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -285,24 +285,33 @@ static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32 outw(value, emu->port + A_GPIO); udelay(10); outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ + udelay(10); } void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) { - unsigned long flags; + if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock))) + return; + snd_emu1010_fpga_write_locked(emu, reg, value); +} - spin_lock_irqsave(&emu->emu_lock, flags); +void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value) +{ + snd_emu1010_fpga_lock(emu); snd_emu1010_fpga_write_locked(emu, reg, value); - spin_unlock_irqrestore(&emu->emu_lock, flags); + snd_emu1010_fpga_unlock(emu); } -static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *value) +void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value) { // The higest input pin is used as the designated interrupt trigger, // so it needs to be masked out. // But note that any other input pin change will also cause an IRQ, // so using this function often causes an IRQ as a side effect. u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f; + + if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock))) + return; if (snd_BUG_ON(reg > 0x3f)) return; reg += 0x40; /* 0x40 upwards are registers. */ @@ -313,47 +322,31 @@ static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 * *value = ((inw(emu->port + A_GPIO) >> 8) & mask); } -void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value) -{ - unsigned long flags; - - spin_lock_irqsave(&emu->emu_lock, flags); - snd_emu1010_fpga_read_locked(emu, reg, value); - spin_unlock_irqrestore(&emu->emu_lock, flags); -} - /* Each Destination has one and only one Source, * but one Source can feed any number of Destinations simultaneously. */ void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src) { - unsigned long flags; - if (snd_BUG_ON(dst & ~0x71f)) return; if (snd_BUG_ON(src & ~0x71f)) return; - spin_lock_irqsave(&emu->emu_lock, flags); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCHI, src >> 8); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCLO, src & 0x1f); - spin_unlock_irqrestore(&emu->emu_lock, flags); + snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8); + snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f); + snd_emu1010_fpga_write(emu, EMU_HANA_SRCHI, src >> 8); + snd_emu1010_fpga_write(emu, EMU_HANA_SRCLO, src & 0x1f); } u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst) { - unsigned long flags; u32 hi, lo; if (snd_BUG_ON(dst & ~0x71f)) return 0; - spin_lock_irqsave(&emu->emu_lock, flags); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f); - snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCHI, &hi); - snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCLO, &lo); - spin_unlock_irqrestore(&emu->emu_lock, flags); + snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8); + snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f); + snd_emu1010_fpga_read(emu, EMU_HANA_SRCHI, &hi); + snd_emu1010_fpga_read(emu, EMU_HANA_SRCLO, &lo); return (hi << 8) | lo; } @@ -429,6 +422,59 @@ void snd_emu1010_update_clock(struct snd_emu10k1 *emu) snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, leds); } +void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, int dock, + const struct firmware *fw_entry) +{ + __always_unused u16 write_post; + + // On E-MU 1010 rev1 the FPGA is a Xilinx Spartan IIE XC2S50E. + // On E-MU 0404b it is a Xilinx Spartan III XC3S50. + // The wiring is as follows: + // GPO7 -> FPGA input & 1K resistor -> FPGA /PGMN <- FPGA output + // In normal operation, the active low reset line is held up by + // an FPGA output, while the GPO pin performs its duty as control + // register access strobe signal. Writing the respective bit to + // EMU_HANA_FPGA_CONFIG puts the FPGA output into high-Z mode, at + // which point the GPO pin can control the reset line through the + // resistor. + // GPO6 -> FPGA CCLK & FPGA input + // GPO5 -> FPGA DIN (dual function) + + // If the FPGA is already programmed, return it to programming mode + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, + dock ? EMU_HANA_FPGA_CONFIG_AUDIODOCK : + EMU_HANA_FPGA_CONFIG_HANA); + + // Assert reset line for 100uS + outw(0x00, emu->port + A_GPIO); + write_post = inw(emu->port + A_GPIO); + udelay(100); + outw(0x80, emu->port + A_GPIO); + write_post = inw(emu->port + A_GPIO); + udelay(100); // Allow FPGA memory to clean + + // Upload the netlist. Keep reset line high! + for (int n = 0; n < fw_entry->size; n++) { + u8 value = fw_entry->data[n]; + for (int i = 0; i < 8; i++) { + u16 reg = 0x80; + if (value & 1) + reg |= 0x20; + value >>= 1; + outw(reg, emu->port + A_GPIO); + write_post = inw(emu->port + A_GPIO); + outw(reg | 0x40, emu->port + A_GPIO); + write_post = inw(emu->port + A_GPIO); + } + } + + // After programming, set GPIO bit 4 high again. + // This appears to be a config word that the rev1 Hana + // firmware reads; weird things happen without this. + outw(0x10, emu->port + A_GPIO); + write_post = inw(emu->port + A_GPIO); +} + void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) { unsigned long flags; diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 20b07117574b..f6982bc6ff0d 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -441,7 +441,7 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk) unmap_memblk(emu, blk); spin_unlock_irqrestore(&emu->memblk_lock, flags); synth_free_pages(emu, blk); - __snd_util_mem_free(hdr, memblk); + __snd_util_mem_free(hdr, memblk); mutex_unlock(&hdr->block_mutex); return 0; } @@ -565,15 +565,18 @@ static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset) } /* - * bzero(blk + offset, size) + * memset(blk + offset, value, size) */ -int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, - int offset, int size) +int snd_emu10k1_synth_memset(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, + int offset, int size, u8 value) { int page, nextofs, end_offset, temp, temp1; void *ptr; struct snd_emu10k1_memblk *p = (struct snd_emu10k1_memblk *)blk; + if (snd_BUG_ON(offset + size > p->mem.size)) + return -EFAULT; + offset += blk->offset & (PAGE_SIZE - 1); end_offset = offset + size; page = get_aligned_page(offset); @@ -585,25 +588,55 @@ int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk temp = temp1; ptr = offset_ptr(emu, page + p->first_page, offset); if (ptr) - memset(ptr, 0, temp); + memset(ptr, value, temp); offset = nextofs; page++; } while (offset < end_offset); return 0; } -EXPORT_SYMBOL(snd_emu10k1_synth_bzero); +EXPORT_SYMBOL(snd_emu10k1_synth_memset); + +// Note that the value is assumed to be suitably repetitive. +static void xor_range(void *ptr, int size, u32 value) +{ + if ((long)ptr & 1) { + *(u8 *)ptr ^= (u8)value; + ptr++; + size--; + } + if (size > 1 && ((long)ptr & 2)) { + *(u16 *)ptr ^= (u16)value; + ptr += 2; + size -= 2; + } + while (size > 3) { + *(u32 *)ptr ^= value; + ptr += 4; + size -= 4; + } + if (size > 1) { + *(u16 *)ptr ^= (u16)value; + ptr += 2; + size -= 2; + } + if (size > 0) + *(u8 *)ptr ^= (u8)value; +} /* - * copy_from_user(blk + offset, data, size) + * copy_from_user(blk + offset, data, size) ^ xor */ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, - int offset, const char __user *data, int size) + int offset, const char __user *data, int size, u32 xor) { int page, nextofs, end_offset, temp, temp1; void *ptr; struct snd_emu10k1_memblk *p = (struct snd_emu10k1_memblk *)blk; + if (snd_BUG_ON(offset + size > p->mem.size)) + return -EFAULT; + offset += blk->offset & (PAGE_SIZE - 1); end_offset = offset + size; page = get_aligned_page(offset); @@ -614,8 +647,12 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me if (temp1 < temp) temp = temp1; ptr = offset_ptr(emu, page + p->first_page, offset); - if (ptr && copy_from_user(ptr, data, temp)) - return -EFAULT; + if (ptr) { + if (copy_from_user(ptr, data, temp)) + return -EFAULT; + if (xor) + xor_range(ptr, temp, xor); + } offset = nextofs; data += temp; page++; diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index e7f097cae574..a9a75891f1da 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -174,11 +174,6 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea if (err < 0) return err; - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = 'P'; - runtime->sync.id32[2] = 16; - runtime->sync.id32[3] = 'V'; - return 0; } @@ -226,6 +221,17 @@ static int snd_p16v_pcm_open_capture(struct snd_pcm_substream *substream) return snd_p16v_pcm_open_capture_channel(substream, 0); } +static int snd_p16v_pcm_ioctl_playback(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + if (cmd == SNDRV_PCM_IOCTL1_SYNC_ID) { + static const unsigned char id[4] = { 'P', '1', '6', 'V' }; + snd_pcm_set_sync_per_card(substream, arg, id, 4); + return 0; + } + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + /* prepare playback callback */ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) { @@ -531,6 +537,7 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream) static const struct snd_pcm_ops snd_p16v_playback_front_ops = { .open = snd_p16v_pcm_open_playback_front, .close = snd_p16v_pcm_close_playback, + .ioctl = snd_p16v_pcm_ioctl_playback, .prepare = snd_p16v_pcm_prepare_playback, .trigger = snd_p16v_pcm_trigger_playback, .pointer = snd_p16v_pcm_pointer_playback, diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 18928b905939..1e6adf1ae304 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1850,12 +1850,12 @@ static void snd_ensoniq_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "Ensoniq AudioPCI " CHIP_NAME "\n\n"); snd_iprintf(buffer, "Joystick enable : %s\n", - ensoniq->ctrl & ES_JYSTK_EN ? "on" : "off"); + str_on_off(ensoniq->ctrl & ES_JYSTK_EN)); #ifdef CHIP1370 snd_iprintf(buffer, "MIC +5V bias : %s\n", - ensoniq->ctrl & ES_1370_XCTL1 ? "on" : "off"); + str_on_off(ensoniq->ctrl & ES_1370_XCTL1)); snd_iprintf(buffer, "Line In to AOUT : %s\n", - ensoniq->ctrl & ES_1370_XCTL0 ? "on" : "off"); + str_on_off(ensoniq->ctrl & ES_1370_XCTL0)); #else snd_iprintf(buffer, "Joystick port : 0x%x\n", (ES_1371_JOY_ASELI(ensoniq->ctrl) * 8) + 0x200); @@ -2022,7 +2022,7 @@ static int snd_ensoniq_create(struct snd_card *card, ensoniq->card = card; ensoniq->pci = pci; ensoniq->irq = -1; - err = pci_request_regions(pci, "Ensoniq AudioPCI"); + err = pcim_request_all_regions(pci, "Ensoniq AudioPCI"); if (err < 0) return err; ensoniq->port = pci_resource_start(pci, 0); diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 018a8d53ca53..27728bdfac57 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1531,7 +1531,7 @@ static int snd_es1938_create(struct snd_card *card, chip->card = card; chip->pci = pci; chip->irq = -1; - err = pci_request_regions(pci, "ESS Solo-1"); + err = pcim_request_all_regions(pci, "ESS Solo-1"); if (err < 0) return err; chip->io_port = pci_resource_start(pci, 0); diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index c6c018b40c69..37bac890613e 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1561,7 +1561,7 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es; - int apu1, apu2; + int err, apu1, apu2; apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE); if (apu1 < 0) @@ -1605,7 +1605,9 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream) runtime->hw = snd_es1968_capture; runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = calc_available_memory_size(chip) - 1024; /* keep MIXBUF size */ - snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); + err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES); + if (err < 0) + return err; spin_lock_irq(&chip->substream_lock); list_add(&es->list, &chip->substream_list); @@ -2647,7 +2649,7 @@ static int snd_es1968_create(struct snd_card *card, chip->playback_streams = play_streams; chip->capture_streams = capt_streams; - err = pci_request_regions(pci, "ESS Maestro"); + err = pcim_request_all_regions(pci, "ESS Maestro"); if (err < 0) return err; chip->io_port = pci_resource_start(pci, 0); diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 7f4834c2d5e6..f283256eda0d 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1191,7 +1191,7 @@ static int snd_fm801_create(struct snd_card *card, chip->dev = &pci->dev; chip->irq = -1; chip->tea575x_tuner = tea575x_tuner; - err = pci_request_regions(pci, "FM801"); + err = pcim_request_all_regions(pci, "FM801"); if (err < 0) return err; chip->port = pci_resource_start(pci, 0); diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index f806636242ee..745f120a5cee 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -42,6 +42,17 @@ config SND_HDA_TEGRA To compile this driver as a module, choose M here: the module will be called snd-hda-tegra. +config SND_HDA_ACPI + tristate "HD Audio ACPI" + depends on ACPI + select SND_HDA + help + Say Y here to include support for Azalia-compatible HDA controllers + which are advertised via ACPI objects. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-acpi. + if SND_HDA config SND_HDA_HWDEP @@ -96,9 +107,7 @@ config SND_HDA_CIRRUS_SCODEC config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS - select SND_HDA_CIRRUS_SCODEC - select GPIOLIB - depends on KUNIT + depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT default KUNIT_ALL_TESTS help This builds KUnit tests for the cirrus side-codec library. @@ -111,9 +120,6 @@ config SND_HDA_SCODEC_CS35L41 tristate select SND_HDA_GENERIC select REGMAP_IRQ - -config SND_HDA_CS_DSP_CONTROLS - tristate select FW_CS_DSP config SND_HDA_SCODEC_COMPONENT @@ -127,7 +133,7 @@ config SND_HDA_SCODEC_CS35L41_I2C depends on SND_SOC select SND_SOC_CS35L41_LIB select SND_HDA_SCODEC_CS35L41 - select SND_HDA_CS_DSP_CONTROLS + select SND_SOC_CS_AMP_LIB help Say Y or M here to include CS35L41 I2C HD-audio side codec support in snd-hda-intel driver, such as ALC287. @@ -143,7 +149,7 @@ config SND_HDA_SCODEC_CS35L41_SPI depends on SND_SOC select SND_SOC_CS35L41_LIB select SND_HDA_SCODEC_CS35L41 - select SND_HDA_CS_DSP_CONTROLS + select SND_SOC_CS_AMP_LIB help Say Y or M here to include CS35L41 SPI HD-audio side codec support in snd-hda-intel driver, such as ALC287. @@ -157,14 +163,14 @@ config SND_HDA_SCODEC_CS35L56 config SND_HDA_SCODEC_CS35L56_I2C tristate "Build CS35L56 HD-audio side codec support for I2C Bus" depends on I2C - depends on ACPI || COMPILE_TEST + depends on ACPI depends on SND_SOC select FW_CS_DSP + imply SERIAL_MULTI_INSTANTIATE select SND_HDA_GENERIC select SND_SOC_CS35L56_SHARED select SND_HDA_SCODEC_CS35L56 select SND_HDA_CIRRUS_SCODEC - select SND_HDA_CS_DSP_CONTROLS select SND_SOC_CS_AMP_LIB help Say Y or M here to include CS35L56 amplifier support with @@ -173,28 +179,33 @@ config SND_HDA_SCODEC_CS35L56_I2C config SND_HDA_SCODEC_CS35L56_SPI tristate "Build CS35L56 HD-audio side codec support for SPI Bus" depends on SPI_MASTER - depends on ACPI || COMPILE_TEST + depends on ACPI depends on SND_SOC select FW_CS_DSP + imply SERIAL_MULTI_INSTANTIATE select SND_HDA_GENERIC select SND_SOC_CS35L56_SHARED select SND_HDA_SCODEC_CS35L56 select SND_HDA_CIRRUS_SCODEC - select SND_HDA_CS_DSP_CONTROLS select SND_SOC_CS_AMP_LIB help Say Y or M here to include CS35L56 amplifier support with SPI control. +config SND_HDA_SCODEC_TAS2781 + tristate + select SND_HDA_GENERIC + config SND_HDA_SCODEC_TAS2781_I2C tristate "Build TAS2781 HD-audio side codec support for I2C Bus" depends on I2C depends on ACPI depends on EFI depends on SND_SOC - select SND_SOC_TAS2781_COMLIB + select SND_HDA_SCODEC_TAS2781 + select SND_SOC_TAS2781_COMLIB_I2C select SND_SOC_TAS2781_FMWLIB - select CRC32_SARWATE + select CRC32 help Say Y or M here to include TAS2781 I2C HD-audio side codec support in snd-hda-intel driver, such as ALC287. @@ -202,8 +213,27 @@ config SND_HDA_SCODEC_TAS2781_I2C comment "Set to Y if you want auto-loading the side codec driver" depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m +config SND_HDA_SCODEC_TAS2781_SPI + tristate "Build TAS2781 HD-audio side codec support for SPI Bus" + depends on SPI_MASTER + depends on ACPI + depends on EFI + depends on SND_SOC + select SND_HDA_SCODEC_TAS2781 + select SND_SOC_TAS2781_COMLIB + select SND_SOC_TAS2781_FMWLIB + select CRC8 + select CRC32 + help + Say Y or M here to include TAS2781 SPI HD-audio side codec support + in snd-hda-intel driver, such as ALC287. + +comment "Set to Y if you want auto-loading the side codec driver" + depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m + config SND_HDA_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" + depends on INPUT select SND_HDA_GENERIC select SND_HDA_GENERIC_LEDS select SND_HDA_SCODEC_COMPONENT @@ -248,6 +278,7 @@ comment "Set to Y if you want auto-loading the codec driver" config SND_HDA_CODEC_HDMI tristate "Build HDMI/DisplayPort HD-audio codec support" select SND_DYNAMIC_MINORS + select SND_PCM_ELD help Say Y or M here to include HDMI and DisplayPort HD-audio codec support in snd-hda-intel driver. This includes all AMD/ATI, @@ -290,6 +321,17 @@ config SND_HDA_CODEC_CONEXANT comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m +config SND_HDA_CODEC_SENARYTECH + tristate "Build Senarytech HD-audio codec support" + select SND_HDA_GENERIC + select SND_HDA_GENERIC_LEDS + help + Say Y or M here to include Senarytech HD-audio codec support in + snd-hda-intel driver, such as SN6186. + +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_SENARYTECH=m + config SND_HDA_CODEC_CA0110 tristate "Build Creative CA0110-IBG codec support" select SND_HDA_GENERIC diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 13e04e1f65de..a5ab8ee2d7f9 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -snd-hda-intel-objs := hda_intel.o -snd-hda-tegra-objs := hda_tegra.o +snd-hda-intel-y := hda_intel.o +snd-hda-tegra-y := hda_tegra.o +snd-hda-acpi-y := hda_acpi.o snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-y += hda_controller.o @@ -13,32 +14,34 @@ snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o CFLAGS_hda_controller.o := -I$(src) CFLAGS_hda_intel.o := -I$(src) -snd-hda-codec-generic-objs := hda_generic.o -snd-hda-codec-realtek-objs := patch_realtek.o -snd-hda-codec-cmedia-objs := patch_cmedia.o -snd-hda-codec-analog-objs := patch_analog.o -snd-hda-codec-idt-objs := patch_sigmatel.o -snd-hda-codec-si3054-objs := patch_si3054.o -snd-hda-codec-cirrus-objs := patch_cirrus.o -snd-hda-codec-cs8409-objs := patch_cs8409.o patch_cs8409-tables.o -snd-hda-codec-ca0110-objs := patch_ca0110.o -snd-hda-codec-ca0132-objs := patch_ca0132.o -snd-hda-codec-conexant-objs := patch_conexant.o -snd-hda-codec-via-objs := patch_via.o -snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o +snd-hda-codec-generic-y := hda_generic.o +snd-hda-codec-realtek-y := patch_realtek.o +snd-hda-codec-cmedia-y := patch_cmedia.o +snd-hda-codec-analog-y := patch_analog.o +snd-hda-codec-idt-y := patch_sigmatel.o +snd-hda-codec-si3054-y := patch_si3054.o +snd-hda-codec-cirrus-y := patch_cirrus.o +snd-hda-codec-cs8409-y := patch_cs8409.o patch_cs8409-tables.o +snd-hda-codec-ca0110-y := patch_ca0110.o +snd-hda-codec-ca0132-y := patch_ca0132.o +snd-hda-codec-conexant-y := patch_conexant.o +snd-hda-codec-senarytech-y :=patch_senarytech.o +snd-hda-codec-via-y := patch_via.o +snd-hda-codec-hdmi-y := patch_hdmi.o hda_eld.o # side codecs -snd-hda-cirrus-scodec-objs := cirrus_scodec.o -snd-hda-cirrus-scodec-test-objs := cirrus_scodec_test.o -snd-hda-scodec-cs35l41-objs := cs35l41_hda.o cs35l41_hda_property.o -snd-hda-scodec-cs35l41-i2c-objs := cs35l41_hda_i2c.o -snd-hda-scodec-cs35l41-spi-objs := cs35l41_hda_spi.o -snd-hda-scodec-cs35l56-objs := cs35l56_hda.o -snd-hda-scodec-cs35l56-i2c-objs := cs35l56_hda_i2c.o -snd-hda-scodec-cs35l56-spi-objs := cs35l56_hda_spi.o -snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o -snd-hda-scodec-component-objs := hda_component.o -snd-hda-scodec-tas2781-i2c-objs := tas2781_hda_i2c.o +snd-hda-cirrus-scodec-y := cirrus_scodec.o +snd-hda-cirrus-scodec-test-y := cirrus_scodec_test.o +snd-hda-scodec-cs35l41-y := cs35l41_hda.o cs35l41_hda_property.o +snd-hda-scodec-cs35l41-i2c-y := cs35l41_hda_i2c.o +snd-hda-scodec-cs35l41-spi-y := cs35l41_hda_spi.o +snd-hda-scodec-cs35l56-y := cs35l56_hda.o +snd-hda-scodec-cs35l56-i2c-y := cs35l56_hda_i2c.o +snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o +snd-hda-scodec-component-y := hda_component.o +snd-hda-scodec-tas2781-y := tas2781_hda.o +snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o +snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o # common driver obj-$(CONFIG_SND_HDA) := snd-hda-codec.o @@ -55,6 +58,7 @@ obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o +obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o @@ -67,12 +71,14 @@ obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o -obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o +obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o +obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o # this must be the last entry after codec drivers; # 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 +obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o diff --git a/sound/pci/hda/cirrus_scodec.c b/sound/pci/hda/cirrus_scodec.c index 8de3bc7448fa..3c670207ba30 100644 --- a/sound/pci/hda/cirrus_scodec.c +++ b/sound/pci/hda/cirrus_scodec.c @@ -66,7 +66,7 @@ int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index, return speaker_id; } -EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, SND_HDA_CIRRUS_SCODEC); +EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, "SND_HDA_CIRRUS_SCODEC"); MODULE_DESCRIPTION("HDA Cirrus side-codec library"); MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); diff --git a/sound/pci/hda/cirrus_scodec_test.c b/sound/pci/hda/cirrus_scodec_test.c index 8ae373676bd1..93b9cbf1f08a 100644 --- a/sound/pci/hda/cirrus_scodec_test.c +++ b/sound/pci/hda/cirrus_scodec_test.c @@ -5,20 +5,30 @@ // Copyright (C) 2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. +#include <kunit/platform_device.h> +#include <kunit/resource.h> #include <kunit/test.h> +#include <linux/device.h> +#include <linux/device/faux.h> #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> #include "cirrus_scodec.h" +KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy, + struct faux_device *) +KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper, + device_remove_software_node, + struct device *) + struct cirrus_scodec_test_gpio { unsigned int pin_state; struct gpio_chip chip; }; struct cirrus_scodec_test_priv { - struct platform_device amp_pdev; + struct faux_device *amp_dev; struct platform_device *gpio_pdev; struct cirrus_scodec_test_gpio *gpio_priv; }; @@ -48,9 +58,10 @@ static int cirrus_scodec_test_gpio_direction_out(struct gpio_chip *chip, return -EOPNOTSUPP; } -static void cirrus_scodec_test_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) +static int cirrus_scodec_test_gpio_set(struct gpio_chip *chip, + unsigned int offset, int value) { + return -EOPNOTSUPP; } static int cirrus_scodec_test_gpio_set_config(struct gpio_chip *gc, @@ -75,7 +86,7 @@ static const struct gpio_chip cirrus_scodec_test_gpio_chip = { .direction_input = cirrus_scodec_test_gpio_direction_in, .get = cirrus_scodec_test_gpio_get, .direction_output = cirrus_scodec_test_gpio_direction_out, - .set = cirrus_scodec_test_gpio_set, + .set_rv = cirrus_scodec_test_gpio_set, .set_config = cirrus_scodec_test_gpio_set_config, .base = -1, .ngpio = 32, @@ -103,6 +114,7 @@ static int cirrus_scodec_test_gpio_probe(struct platform_device *pdev) static struct platform_driver cirrus_scodec_test_gpio_driver = { .driver.name = "cirrus_scodec_test_gpio_drv", + .driver.owner = THIS_MODULE, .probe = cirrus_scodec_test_gpio_probe, }; @@ -111,37 +123,28 @@ static const struct software_node cirrus_scodec_test_gpio_swnode = { .name = "cirrus_scodec_test_gpio", }; -static int cirrus_scodec_test_create_gpio(struct kunit *test) +static void cirrus_scodec_test_create_gpio(struct kunit *test) { struct cirrus_scodec_test_priv *priv = test->priv; - int ret; - priv->gpio_pdev = platform_device_alloc(cirrus_scodec_test_gpio_driver.driver.name, -1); - if (!priv->gpio_pdev) - return -ENOMEM; + KUNIT_ASSERT_EQ(test, 0, + kunit_platform_driver_register(test, &cirrus_scodec_test_gpio_driver)); - ret = device_add_software_node(&priv->gpio_pdev->dev, &cirrus_scodec_test_gpio_swnode); - if (ret) { - platform_device_put(priv->gpio_pdev); - KUNIT_FAIL(test, "Failed to add swnode to gpio: %d\n", ret); - return ret; - } + priv->gpio_pdev = kunit_platform_device_alloc(test, + cirrus_scodec_test_gpio_driver.driver.name, + PLATFORM_DEVID_NONE); + KUNIT_ASSERT_NOT_NULL(test, priv->gpio_pdev); - ret = platform_device_add(priv->gpio_pdev); - if (ret) { - platform_device_put(priv->gpio_pdev); - KUNIT_FAIL(test, "Failed to add gpio platform device: %d\n", ret); - return ret; - } + KUNIT_ASSERT_EQ(test, 0, device_add_software_node(&priv->gpio_pdev->dev, + &cirrus_scodec_test_gpio_swnode)); + KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test, + device_remove_software_node_wrapper, + &priv->gpio_pdev->dev)); - priv->gpio_priv = dev_get_drvdata(&priv->gpio_pdev->dev); - if (!priv->gpio_priv) { - platform_device_put(priv->gpio_pdev); - KUNIT_FAIL(test, "Failed to get gpio private data\n"); - return -EINVAL; - } + KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, priv->gpio_pdev)); - return 0; + priv->gpio_priv = dev_get_drvdata(&priv->gpio_pdev->dev); + KUNIT_ASSERT_NOT_NULL(test, priv->gpio_priv); } static void cirrus_scodec_test_set_gpio_ref_arg(struct software_node_ref_args *arg, @@ -191,7 +194,7 @@ static void cirrus_scodec_test_spkid_parse(struct kunit *test) const struct cirrus_scodec_test_spkid_param *param = test->param_value; int num_spk_id_refs = param->num_amps * param->gpios_per_amp; struct software_node_ref_args *refs; - struct device *dev = &priv->amp_pdev.dev; + struct device *dev = &priv->amp_dev->dev; unsigned int v; int i, ret; @@ -234,21 +237,16 @@ static void cirrus_scodec_test_spkid_parse(struct kunit *test) static void cirrus_scodec_test_no_spkid(struct kunit *test) { struct cirrus_scodec_test_priv *priv = test->priv; - struct device *dev = &priv->amp_pdev.dev; + struct device *dev = &priv->amp_dev->dev; int ret; ret = cirrus_scodec_get_speaker_id(dev, 0, 4, -1); KUNIT_EXPECT_EQ(test, ret, -ENOENT); } -static void cirrus_scodec_test_dev_release(struct device *dev) -{ -} - static int cirrus_scodec_test_case_init(struct kunit *test) { struct cirrus_scodec_test_priv *priv; - int ret; priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -257,52 +255,18 @@ static int cirrus_scodec_test_case_init(struct kunit *test) test->priv = priv; /* Create dummy GPIO */ - ret = cirrus_scodec_test_create_gpio(test); - if (ret < 0) - return ret; + cirrus_scodec_test_create_gpio(test); /* Create dummy amp driver dev */ - priv->amp_pdev.name = "cirrus_scodec_test_amp_drv"; - priv->amp_pdev.id = -1; - priv->amp_pdev.dev.release = cirrus_scodec_test_dev_release; - ret = platform_device_register(&priv->amp_pdev); - KUNIT_ASSERT_GE_MSG(test, ret, 0, "Failed to register amp platform device\n"); - - return 0; -} - -static void cirrus_scodec_test_case_exit(struct kunit *test) -{ - struct cirrus_scodec_test_priv *priv = test->priv; - - if (priv->amp_pdev.name) - platform_device_unregister(&priv->amp_pdev); - - if (priv->gpio_pdev) { - device_remove_software_node(&priv->gpio_pdev->dev); - platform_device_unregister(priv->gpio_pdev); - } -} - -static int cirrus_scodec_test_suite_init(struct kunit_suite *suite) -{ - int ret; - - /* Register mock GPIO driver */ - ret = platform_driver_register(&cirrus_scodec_test_gpio_driver); - if (ret < 0) { - kunit_err(suite, "Failed to register gpio platform driver, %d\n", ret); - return ret; - } + priv->amp_dev = faux_device_create("cirrus_scodec_test_amp_drv", NULL, NULL); + KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev); + KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test, + faux_device_destroy_wrapper, + priv->amp_dev)); return 0; } -static void cirrus_scodec_test_suite_exit(struct kunit_suite *suite) -{ - platform_driver_unregister(&cirrus_scodec_test_gpio_driver); -} - static const struct cirrus_scodec_test_spkid_param cirrus_scodec_test_spkid_param_cases[] = { { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 1 }, { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 1 }, @@ -356,15 +320,13 @@ static struct kunit_case cirrus_scodec_test_cases[] = { static struct kunit_suite cirrus_scodec_test_suite = { .name = "snd-hda-scodec-cs35l56-test", - .suite_init = cirrus_scodec_test_suite_init, - .suite_exit = cirrus_scodec_test_suite_exit, .init = cirrus_scodec_test_case_init, - .exit = cirrus_scodec_test_case_exit, .test_cases = cirrus_scodec_test_cases, }; kunit_test_suite(cirrus_scodec_test_suite); -MODULE_IMPORT_NS(SND_HDA_CIRRUS_SCODEC); +MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC"); +MODULE_DESCRIPTION("KUnit test for the Cirrus side-codec library"); MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index d3fa6e136744..d5bc81099d0d 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -13,16 +13,15 @@ #include <sound/soc.h> #include <linux/pm_runtime.h> #include <linux/spi/spi.h> +#include <linux/vmalloc.h> #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" #include "hda_generic.h" #include "hda_component.h" #include "cs35l41_hda.h" -#include "hda_cs_dsp_ctl.h" #include "cs35l41_hda_property.h" -#define CS35L41_FIRMWARE_ROOT "cirrus/" #define CS35L41_PART "cs35l41" #define HALO_STATE_DSP_CTL_NAME "HALO_STATE" @@ -37,6 +36,57 @@ #define CS35L41_UUID "50d90cdc-3de4-4f18-b528-c7fe3b71f40d" #define CS35L41_DSM_GET_MUTE 5 #define CS35L41_NOTIFY_EVENT 0x91 +#define CS35L41_TUNING_SIG 0x109A4A35 + +enum cs35l41_tuning_param_types { + TUNING_PARAM_GAIN, +}; + +struct cs35l41_tuning_param_hdr { + __le32 tuning_index; + __le32 type; + __le32 size; +} __packed; + +struct cs35l41_tuning_param { + struct cs35l41_tuning_param_hdr hdr; + union { + __le32 gain; + }; +} __packed; + +struct cs35l41_tuning_params { + __le32 signature; + __le32 version; + __le32 size; + __le32 num_entries; + u8 data[]; +} __packed; + +/* Firmware calibration controls */ +static const struct cirrus_amp_cal_controls cs35l41_calibration_controls = { + .alg_id = CAL_DSP_CTL_ALG, + .mem_region = CAL_DSP_CTL_TYPE, + .ambient = CAL_AMBIENT_DSP_CTL_NAME, + .calr = CAL_R_DSP_CTL_NAME, + .status = CAL_STATUS_DSP_CTL_NAME, + .checksum = CAL_CHECKSUM_DSP_CTL_NAME, +}; + +enum cs35l41_hda_fw_id { + CS35L41_HDA_FW_SPK_PROT, + CS35L41_HDA_FW_SPK_CALI, + CS35L41_HDA_FW_SPK_DIAG, + CS35L41_HDA_FW_MISC, + CS35L41_HDA_NUM_FW +}; + +static const char * const cs35l41_hda_fw_ids[CS35L41_HDA_NUM_FW] = { + [CS35L41_HDA_FW_SPK_PROT] = "spk-prot", + [CS35L41_HDA_FW_SPK_CALI] = "spk-cali", + [CS35L41_HDA_FW_SPK_DIAG] = "spk-diag", + [CS35L41_HDA_FW_MISC] = "misc", +}; static bool firmware_autostart = 1; module_param(firmware_autostart, bool, 0444); @@ -75,7 +125,7 @@ static const struct reg_sequence cs35l41_hda_config_dsp[] = { { CS35L41_SP_HIZ_CTRL, 0x00000003 }, // Hi-Z unused/disabled { CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot { CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot - { CS35L41_DAC_PCM1_SRC, 0x00000032 }, // DACPCM1_SRC = ERR_VOL + { CS35L41_DAC_PCM1_SRC, 0x00000032 }, // DACPCM1_SRC = DSP1TX1 { CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON { CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON { CS35L41_ASP_TX3_SRC, 0x00000028 }, // ASPTX3 SRC = VPMON @@ -84,7 +134,7 @@ static const struct reg_sequence cs35l41_hda_config_dsp[] = { { CS35L41_DSP1_RX2_SRC, 0x00000008 }, // DSP1RX2 SRC = ASPRX1 { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON - { CS35L41_DSP1_RX5_SRC, 0x00000029 }, // DSP1RX5 SRC = VBSTMON + { CS35L41_DSP1_RX6_SRC, 0x00000029 }, // DSP1RX6 SRC = VBSTMON }; static const struct reg_sequence cs35l41_hda_unmute[] = { @@ -92,34 +142,39 @@ static const struct reg_sequence cs35l41_hda_unmute[] = { { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB }; -static const struct reg_sequence cs35l41_hda_unmute_dsp[] = { - { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB - { CS35L41_AMP_GAIN_CTRL, 0x00000233 }, // AMP_GAIN_PCM = 17.5dB AMP_GAIN_PDM = 19.5dB -}; - static const struct reg_sequence cs35l41_hda_mute[] = { { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, // AMP_GAIN_PCM 0.5 dB { CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM Mute }; -static void cs35l41_add_controls(struct cs35l41_hda *cs35l41) +static const struct cs_dsp_client_ops client_ops = { + /* cs_dsp requires the client to provide this even if it is empty */ +}; + +static int cs35l41_request_tuning_param_file(struct cs35l41_hda *cs35l41, char *tuning_filename, + const struct firmware **firmware, char **filename, + const char *ssid) { - struct hda_cs_dsp_ctl_info info; + int ret = 0; - info.device_name = cs35l41->amp_name; - info.fw_type = cs35l41->firmware_type; - info.card = cs35l41->codec->card; + /* Filename is the same as the tuning file with "cfg" suffix */ + *filename = kasprintf(GFP_KERNEL, "%scfg", tuning_filename); + if (*filename == NULL) + return -ENOMEM; - hda_cs_dsp_add_controls(&cs35l41->cs_dsp, &info); -} + ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev); + if (ret != 0) { + dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename); + kfree(*filename); + *filename = NULL; + } -static const struct cs_dsp_client_ops client_ops = { - .control_remove = hda_cs_dsp_control_remove, -}; + return ret; +} static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41, const struct firmware **firmware, char **filename, - const char *dir, const char *ssid, const char *amp_name, + const char *ssid, const char *amp_name, int spkid, const char *filetype) { const char * const dsp_name = cs35l41->cs_dsp.name; @@ -127,24 +182,24 @@ static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41, int ret = 0; if (spkid > -1 && ssid && amp_name) - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d-%s.%s", dir, CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART, + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], ssid, spkid, amp_name, filetype); else if (spkid > -1 && ssid) - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d.%s", dir, CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d.%s", CS35L41_PART, + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], ssid, spkid, filetype); else if (ssid && amp_name) - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-%s.%s", CS35L41_PART, + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], ssid, amp_name, filetype); else if (ssid) - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s.%s", CS35L41_PART, + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], ssid, filetype); else - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s.%s", CS35L41_PART, + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], filetype); if (*filename == NULL) @@ -184,13 +239,11 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41, /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.wmfw */ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, cs35l41->amp_name, cs35l41->speaker_id, "wmfw"); if (!ret) { /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, cs35l41->amp_name, cs35l41->speaker_id, "bin"); if (ret) @@ -201,12 +254,11 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41, /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->acpi_subsystem_id, cs35l41->amp_name, -1, "wmfw"); if (!ret) { /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, cs35l41->amp_name, cs35l41->speaker_id, "bin"); if (ret) @@ -217,18 +269,17 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41, /* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->acpi_subsystem_id, NULL, cs35l41->speaker_id, "wmfw"); if (!ret) { /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, cs35l41->amp_name, cs35l41->speaker_id, "bin"); if (ret) /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, - coeff_filename, CS35L41_FIRMWARE_ROOT, + coeff_filename, cs35l41->acpi_subsystem_id, NULL, cs35l41->speaker_id, "bin"); if (ret) @@ -239,18 +290,17 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41, /* try cirrus/part-dspN-fwtype-sub.wmfw */ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->acpi_subsystem_id, NULL, -1, "wmfw"); if (!ret) { /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, cs35l41->amp_name, cs35l41->speaker_id, "bin"); if (ret) /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, - coeff_filename, CS35L41_FIRMWARE_ROOT, + coeff_filename, cs35l41->acpi_subsystem_id, NULL, cs35l41->speaker_id, "bin"); if (ret) @@ -277,13 +327,13 @@ static int cs35l41_fallback_firmware_file(struct cs35l41_hda *cs35l41, /* fallback try cirrus/part-dspN-fwtype.wmfw */ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, - CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw"); + NULL, NULL, -1, "wmfw"); if (ret) goto err; /* fallback try cirrus/part-dspN-fwtype.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, - CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin"); + NULL, NULL, -1, "bin"); if (ret) { release_firmware(*wmfw_firmware); kfree(*wmfw_filename); @@ -312,12 +362,11 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41, /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->acpi_subsystem_id, cs35l41->amp_name, -1, "wmfw"); if (!ret) { /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, cs35l41->amp_name, -1, "bin"); if (ret) @@ -328,18 +377,16 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41, /* try cirrus/part-dspN-fwtype-sub.wmfw */ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, + cs35l41->acpi_subsystem_id, NULL, -1, "wmfw"); if (!ret) { /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, cs35l41->amp_name, -1, "bin"); if (ret) /* try cirrus/part-dspN-fwtype-sub.bin */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename, - CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id, NULL, -1, "bin"); if (ret) @@ -361,95 +408,162 @@ fallback: coeff_firmware, coeff_filename); } -#if IS_ENABLED(CONFIG_EFI) -static int cs35l41_apply_calibration(struct cs35l41_hda *cs35l41, __be32 ambient, __be32 r0, - __be32 status, __be32 checksum) + +static void cs35l41_hda_apply_calibration(struct cs35l41_hda *cs35l41) { int ret; - ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_AMBIENT_DSP_CTL_NAME, CAL_DSP_CTL_TYPE, - CAL_DSP_CTL_ALG, &ambient, 4); + if (!cs35l41->cal_data_valid) + return; + + ret = cs_amp_write_cal_coeffs(&cs35l41->cs_dsp, &cs35l41_calibration_controls, + &cs35l41->cal_data); + if (ret < 0) + dev_warn(cs35l41->dev, "Failed to apply calibration: %d\n", ret); + else + dev_info(cs35l41->dev, "Calibration applied: R0=%d\n", cs35l41->cal_data.calR); +} + +static int cs35l41_read_silicon_uid(struct cs35l41_hda *cs35l41, u64 *uid) +{ + u32 tmp; + int ret; + + ret = regmap_read(cs35l41->regmap, CS35L41_DIE_STS2, &tmp); if (ret) { - dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_AMBIENT_DSP_CTL_NAME, - ret); + dev_err(cs35l41->dev, "Cannot obtain CS35L41_DIE_STS2: %d\n", ret); return ret; } - ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_R_DSP_CTL_NAME, CAL_DSP_CTL_TYPE, - CAL_DSP_CTL_ALG, &r0, 4); + + *uid = tmp; + *uid <<= 32; + + ret = regmap_read(cs35l41->regmap, CS35L41_DIE_STS1, &tmp); if (ret) { - dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_R_DSP_CTL_NAME, ret); + dev_err(cs35l41->dev, "Cannot obtain CS35L41_DIE_STS1: %d\n", ret); return ret; } - ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_STATUS_DSP_CTL_NAME, CAL_DSP_CTL_TYPE, - CAL_DSP_CTL_ALG, &status, 4); - if (ret) { - dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_STATUS_DSP_CTL_NAME, - ret); + + *uid |= tmp; + + dev_dbg(cs35l41->dev, "UniqueID = %#llx\n", *uid); + + return 0; +} + +static int cs35l41_get_calibration(struct cs35l41_hda *cs35l41) +{ + u64 silicon_uid; + int ret; + + ret = cs35l41_read_silicon_uid(cs35l41, &silicon_uid); + if (ret < 0) return ret; - } - ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_CHECKSUM_DSP_CTL_NAME, CAL_DSP_CTL_TYPE, - CAL_DSP_CTL_ALG, &checksum, 4); - if (ret) { - dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_CHECKSUM_DSP_CTL_NAME, - ret); + + ret = cs_amp_get_efi_calibration_data(cs35l41->dev, silicon_uid, + cs35l41->index, + &cs35l41->cal_data); + + /* Only return an error status if probe should be aborted */ + if ((ret == -ENOENT) || (ret == -EOVERFLOW)) + return 0; + + if (ret < 0) return ret; - } + + cs35l41->cal_data_valid = true; return 0; } -static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41) + +static void cs35l41_set_default_tuning_params(struct cs35l41_hda *cs35l41) { - static efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, - 0x5a, 0xa3, 0x5d, 0xb3); - static efi_char16_t efi_name[] = L"CirrusSmartAmpCalibrationData"; - const struct cs35l41_amp_efi_data *efi_data; - const struct cs35l41_amp_cal_data *cl; - unsigned long data_size = 0; - efi_status_t status; - int ret = 0; - u8 *data = NULL; - u32 attr; + cs35l41->tuning_gain = DEFAULT_AMP_GAIN_PCM; +} - /* Get real size of UEFI variable */ - status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data); - if (status == EFI_BUFFER_TOO_SMALL) { - ret = -ENODEV; - /* Allocate data buffer of data_size bytes */ - data = vmalloc(data_size); - if (!data) - return -ENOMEM; - /* Get variable contents into buffer */ - status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data); - if (status == EFI_SUCCESS) { - efi_data = (struct cs35l41_amp_efi_data *)data; - dev_dbg(cs35l41->dev, "Calibration: Size=%d, Amp Count=%d\n", - efi_data->size, efi_data->count); - if (efi_data->count > cs35l41->index) { - cl = &efi_data->data[cs35l41->index]; - dev_dbg(cs35l41->dev, - "Calibration: Ambient=%02x, Status=%02x, R0=%d\n", - cl->calAmbient, cl->calStatus, cl->calR); - - /* Calibration can only be applied whilst the DSP is not running */ - ret = cs35l41_apply_calibration(cs35l41, - cpu_to_be32(cl->calAmbient), - cpu_to_be32(cl->calR), - cpu_to_be32(cl->calStatus), - cpu_to_be32(cl->calR + 1)); - } +static int cs35l41_read_tuning_params(struct cs35l41_hda *cs35l41, const struct firmware *firmware) +{ + struct cs35l41_tuning_params *params; + unsigned int offset = 0; + unsigned int end; + int i; + + params = (void *)&firmware->data[0]; + + if (le32_to_cpu(params->size) != firmware->size) { + dev_err(cs35l41->dev, "Wrong Size for Tuning Param file. Expected %d got %zu\n", + le32_to_cpu(params->size), firmware->size); + return -EINVAL; + } + + if (le32_to_cpu(params->version) != 1) { + dev_err(cs35l41->dev, "Unsupported Tuning Param Version: %d\n", + le32_to_cpu(params->version)); + return -EINVAL; + } + + if (le32_to_cpu(params->signature) != CS35L41_TUNING_SIG) { + dev_err(cs35l41->dev, + "Mismatched Signature for Tuning Param file. Expected %#x got %#x\n", + CS35L41_TUNING_SIG, le32_to_cpu(params->signature)); + return -EINVAL; + } + + end = firmware->size - sizeof(struct cs35l41_tuning_params); + + for (i = 0; i < le32_to_cpu(params->num_entries); i++) { + struct cs35l41_tuning_param *param; + + if ((offset >= end) || ((offset + sizeof(struct cs35l41_tuning_param_hdr)) >= end)) + return -EFAULT; + + param = (void *)¶ms->data[offset]; + offset += le32_to_cpu(param->hdr.size); + + if (offset > end) + return -EFAULT; + + switch (le32_to_cpu(param->hdr.type)) { + case TUNING_PARAM_GAIN: + cs35l41->tuning_gain = le32_to_cpu(param->gain); + dev_dbg(cs35l41->dev, "Applying Gain: %d\n", cs35l41->tuning_gain); + break; + default: + break; } - vfree(data); } - return ret; + + return 0; } -#else -static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41) + +static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_filename) { - dev_warn(cs35l41->dev, "Calibration not supported without EFI support.\n"); - return 0; + const struct firmware *tuning_param_file = NULL; + char *tuning_param_filename = NULL; + int ret; + + ret = cs35l41_request_tuning_param_file(cs35l41, tuning_filename, &tuning_param_file, + &tuning_param_filename, cs35l41->acpi_subsystem_id); + if (ret) { + dev_dbg(cs35l41->dev, "Missing Tuning Param for file: %s: %d\n", tuning_filename, + ret); + return 0; + } + + ret = cs35l41_read_tuning_params(cs35l41, tuning_param_file); + if (ret) { + dev_err(cs35l41->dev, "Error reading Tuning Params from file: %s: %d\n", + tuning_param_filename, ret); + /* Reset to default Tuning Parameters */ + cs35l41_set_default_tuning_params(cs35l41); + } + + release_firmware(tuning_param_file); + kfree(tuning_param_filename); + + return ret; } -#endif static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41) { @@ -470,27 +584,33 @@ static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41) cs35l41->halo_initialized = true; } + cs35l41_set_default_tuning_params(cs35l41); + ret = cs35l41_request_firmware_files(cs35l41, &wmfw_firmware, &wmfw_filename, &coeff_firmware, &coeff_filename); if (ret < 0) return ret; dev_dbg(cs35l41->dev, "Loading WMFW Firmware: %s\n", wmfw_filename); - if (coeff_filename) + if (coeff_filename) { dev_dbg(cs35l41->dev, "Loading Coefficient File: %s\n", coeff_filename); - else + ret = cs35l41_load_tuning_params(cs35l41, coeff_filename); + if (ret) + dev_warn(cs35l41->dev, "Unable to load Tuning Parameters: %d\n", ret); + } else { dev_warn(cs35l41->dev, "No Coefficient File available.\n"); + } ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename, - hda_cs_dsp_fw_ids[cs35l41->firmware_type]); + cs35l41_hda_fw_ids[cs35l41->firmware_type]); if (ret) - goto err_release; - - cs35l41_add_controls(cs35l41); + goto err; - ret = cs35l41_save_calibration(cs35l41); + cs35l41_hda_apply_calibration(cs35l41); -err_release: +err: + if (ret) + cs35l41_set_default_tuning_params(cs35l41); release_firmware(wmfw_firmware); release_firmware(coeff_firmware); kfree(wmfw_filename); @@ -503,6 +623,7 @@ static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41) { struct cs_dsp *dsp = &cs35l41->cs_dsp; + cs35l41_set_default_tuning_params(cs35l41); cs_dsp_stop(dsp); cs_dsp_power_down(dsp); dev_dbg(cs35l41->dev, "Unloaded Firmware\n"); @@ -553,6 +674,10 @@ static void cs35l41_hda_play_start(struct device *dev) if (cs35l41->cs_dsp.running) { regmap_multi_reg_write(reg, cs35l41_hda_config_dsp, ARRAY_SIZE(cs35l41_hda_config_dsp)); + if (cs35l41->hw_cfg.bst_type == CS35L41_INT_BOOST) + regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VPMON); + else + regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VBSTMON); regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, 1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT); @@ -570,6 +695,7 @@ static void cs35l41_mute(struct device *dev, bool mute) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); struct regmap *reg = cs35l41->regmap; + unsigned int amp_gain; dev_dbg(dev, "Mute(%d:%d) Playback Started: %d\n", mute, cs35l41->mute_override, cs35l41->playback_started); @@ -581,8 +707,13 @@ static void cs35l41_mute(struct device *dev, bool mute) } else { dev_dbg(dev, "Unmuting\n"); if (cs35l41->cs_dsp.running) { - regmap_multi_reg_write(reg, cs35l41_hda_unmute_dsp, - ARRAY_SIZE(cs35l41_hda_unmute_dsp)); + dev_dbg(dev, "Using Tuned Gain: %d\n", cs35l41->tuning_gain); + amp_gain = (cs35l41->tuning_gain << CS35L41_AMP_GAIN_PCM_SHIFT) | + (DEFAULT_AMP_GAIN_PDM << CS35L41_AMP_GAIN_PDM_SHIFT); + + /* AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB */ + regmap_write(reg, CS35L41_AMP_DIG_VOL_CTRL, 0x00008000); + regmap_write(reg, CS35L41_AMP_GAIN_CTRL, amp_gain); } else { regmap_multi_reg_write(reg, cs35l41_hda_unmute, ARRAY_SIZE(cs35l41_hda_unmute)); @@ -991,6 +1122,18 @@ err: return ret; } +static int cs35l41_hda_read_ctl(struct cs_dsp *dsp, const char *name, int type, + unsigned int alg, void *buf, size_t len) +{ + int ret; + + mutex_lock(&dsp->pwr_lock); + ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len); + mutex_unlock(&dsp->pwr_lock); + + return ret; +} + static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) { unsigned int fw_status; @@ -1020,7 +1163,7 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) goto clean_dsp; } - ret = read_poll_timeout(hda_cs_dsp_read_ctl, ret, + ret = read_poll_timeout(cs35l41_hda_read_ctl, ret, be32_to_cpu(halo_sts) == HALO_STATE_CODE_RUN, 1000, 15000, false, &cs35l41->cs_dsp, HALO_STATE_DSP_CTL_NAME, HALO_STATE_DSP_CTL_TYPE, HALO_STATE_DSP_CTL_ALG, @@ -1056,6 +1199,9 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) goto clean_dsp; } + dev_info(cs35l41->dev, "Firmware Loaded - Type: %s, Gain: %d\n", + cs35l41_hda_fw_ids[cs35l41->firmware_type], cs35l41->tuning_gain); + return 0; clean_dsp: @@ -1156,7 +1302,7 @@ static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol, { struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol); - if (ucontrol->value.enumerated.item[0] < HDA_CS_DSP_NUM_FW) { + if (ucontrol->value.enumerated.item[0] < CS35L41_HDA_NUM_FW) { if (cs35l41->firmware_type != ucontrol->value.enumerated.item[0]) { cs35l41->firmware_type = ucontrol->value.enumerated.item[0]; return 1; @@ -1170,7 +1316,7 @@ static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol, static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(hda_cs_dsp_fw_ids), hda_cs_dsp_fw_ids); + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(cs35l41_hda_fw_ids), cs35l41_hda_fw_ids); } static int cs35l41_create_controls(struct cs35l41_hda *cs35l41) @@ -1286,29 +1432,31 @@ static void cs35l41_acpi_device_notify(acpi_handle handle, u32 event, struct dev static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); - struct hda_component *comps = master_data; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; unsigned int sleep_flags; int ret = 0; - if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS) + comp = hda_component_from_index(parent, cs35l41->index); + if (!comp) return -EINVAL; - comps = &comps[cs35l41->index]; - if (comps->dev) + if (comp->dev) return -EBUSY; pm_runtime_get_sync(dev); mutex_lock(&cs35l41->fw_mutex); - comps->dev = dev; + comp->dev = dev; + cs35l41->codec = parent->codec; if (!cs35l41->acpi_subsystem_id) cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x", - comps->codec->core.subsystem_id); - cs35l41->codec = comps->codec; - strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + cs35l41->codec->core.subsystem_id); + + strscpy(comp->name, dev_name(dev), sizeof(comp->name)); - cs35l41->firmware_type = HDA_CS_DSP_FW_SPK_PROT; + cs35l41->firmware_type = CS35L41_HDA_FW_SPK_PROT; if (firmware_autostart) { dev_dbg(cs35l41->dev, "Firmware Autostart.\n"); @@ -1321,13 +1469,13 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas ret = cs35l41_create_controls(cs35l41); - comps->playback_hook = cs35l41_hda_playback_hook; - comps->pre_playback_hook = cs35l41_hda_pre_playback_hook; - comps->post_playback_hook = cs35l41_hda_post_playback_hook; - comps->acpi_notify = cs35l41_acpi_device_notify; - comps->adev = cs35l41->dacpi; + comp->playback_hook = cs35l41_hda_playback_hook; + comp->pre_playback_hook = cs35l41_hda_pre_playback_hook; + comp->post_playback_hook = cs35l41_hda_post_playback_hook; + comp->acpi_notify = cs35l41_acpi_device_notify; + comp->adev = cs35l41->dacpi; - comps->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comps->adev), + comp->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comp->adev), CS35L41_DSM_GET_MUTE); cs35l41->mute_override = cs35l41_get_acpi_mute_state(cs35l41, @@ -1336,7 +1484,7 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas mutex_unlock(&cs35l41->fw_mutex); sleep_flags = lock_system_sleep(); - if (!device_link_add(&comps->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS)) + if (!device_link_add(&cs35l41->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS)) dev_warn(dev, "Unable to create device link\n"); unlock_system_sleep(sleep_flags); @@ -1356,14 +1504,19 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); - struct hda_component *comps = master_data; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; unsigned int sleep_flags; - if (comps[cs35l41->index].dev == dev) { - memset(&comps[cs35l41->index], 0, sizeof(*comps)); + comp = hda_component_from_index(parent, cs35l41->index); + if (!comp) + return; + + if (comp->dev == dev) { sleep_flags = lock_system_sleep(); - device_link_remove(&comps->codec->core.dev, cs35l41->dev); + device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev); unlock_system_sleep(sleep_flags); + memset(comp, 0, sizeof(*comp)); } } @@ -1450,7 +1603,7 @@ static const struct regmap_irq cs35l41_reg_irqs[] = { CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR), }; -static struct regmap_irq_chip cs35l41_regmap_irq_chip = { +static const struct regmap_irq_chip cs35l41_regmap_irq_chip = { .name = "cs35l41 IRQ1 Controller", .status_base = CS35L41_IRQ1_STATUS1, .mask_base = CS35L41_IRQ1_MASK1, @@ -1461,13 +1614,56 @@ static struct regmap_irq_chip cs35l41_regmap_irq_chip = { .runtime_pm = true, }; +static void cs35l41_configure_interrupt(struct cs35l41_hda *cs35l41, int irq_pol) +{ + int irq; + int ret; + int i; + + if (!cs35l41->irq) { + dev_warn(cs35l41->dev, "No Interrupt Found"); + goto err; + } + + ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq, + IRQF_ONESHOT | IRQF_SHARED | irq_pol, + 0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data); + if (ret) { + dev_dbg(cs35l41->dev, "Unable to add IRQ Chip: %d.", ret); + goto err; + } + + for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) { + irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq); + if (irq < 0) { + ret = irq; + dev_dbg(cs35l41->dev, "Unable to map IRQ %s: %d.", cs35l41_irqs[i].name, + ret); + goto err; + } + + ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL, + cs35l41_irqs[i].handler, + IRQF_ONESHOT | IRQF_SHARED | irq_pol, + cs35l41_irqs[i].name, cs35l41); + if (ret) { + dev_dbg(cs35l41->dev, "Unable to allocate IRQ %s:: %d.", + cs35l41_irqs[i].name, ret); + goto err; + } + } + return; +err: + dev_warn(cs35l41->dev, + "IRQ Config Failed. Amp errors may not be recoverable without reboot."); +} + static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41) { struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; bool using_irq = false; - int irq, irq_pol; + int irq_pol; int ret; - int i; if (!cs35l41->hw_cfg.valid) return -EINVAL; @@ -1510,26 +1706,8 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41) irq_pol = cs35l41_gpio_config(cs35l41->regmap, hw_cfg); - if (cs35l41->irq && using_irq) { - ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq, - IRQF_ONESHOT | IRQF_SHARED | irq_pol, - 0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data); - if (ret) - return ret; - - for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) { - irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq); - if (irq < 0) - return irq; - - ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL, - cs35l41_irqs[i].handler, - IRQF_ONESHOT | IRQF_SHARED | irq_pol, - cs35l41_irqs[i].name, cs35l41); - if (ret) - return ret; - } - } + if (using_irq) + cs35l41_configure_interrupt(cs35l41, irq_pol); return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos); } @@ -1588,38 +1766,14 @@ int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int return speaker_id; } -static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id) +int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id) { struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; u32 values[HDA_MAX_COMPONENTS]; - struct acpi_device *adev; - struct device *physdev; - struct spi_device *spi; - const char *sub; char *property; size_t nval; int i, ret; - adev = acpi_dev_get_first_match_dev(hid, NULL, -1); - if (!adev) { - dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid); - return -ENODEV; - } - - cs35l41->dacpi = adev; - physdev = get_device(acpi_get_first_physical_node(adev)); - - sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); - if (IS_ERR(sub)) - sub = NULL; - cs35l41->acpi_subsystem_id = sub; - - ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid); - if (!ret) { - dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n"); - goto out; - } - property = "cirrus,dev-index"; ret = device_property_count_u32(physdev, property); if (ret <= 0) @@ -1651,8 +1805,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i /* To use the same release code for all laptop variants we can't use devm_ version of * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node */ - cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), "reset", cs35l41->index, - GPIOD_OUT_LOW, "cs35l41-reset"); + cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset", + cs35l41->index, GPIOD_OUT_LOW, + "cs35l41-reset"); property = "cirrus,speaker-position"; ret = device_property_read_u32_array(physdev, property, values, nval); @@ -1708,6 +1863,51 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i hw_cfg->bst_type = CS35L41_EXT_BOOST; hw_cfg->valid = true; + + return 0; +err: + dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret); + hw_cfg->valid = false; + hw_cfg->gpio1.valid = false; + hw_cfg->gpio2.valid = false; + acpi_dev_put(cs35l41->dacpi); + + return ret; +} + +static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id) +{ + struct acpi_device *adev; + struct device *physdev; + struct spi_device *spi; + const char *sub; + int ret; + + adev = acpi_dev_get_first_match_dev(hid, NULL, -1); + if (!adev) { + dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid); + return -ENODEV; + } + + cs35l41->dacpi = adev; + physdev = get_device(acpi_get_first_physical_node(adev)); + + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) + sub = NULL; + cs35l41->acpi_subsystem_id = sub; + + ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid); + if (!ret) { + dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n"); + goto out; + } + + ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id); + if (ret) { + put_device(physdev); + return ret; + } out: put_device(physdev); @@ -1723,16 +1923,6 @@ out: } return 0; - -err: - dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret); - hw_cfg->valid = false; - hw_cfg->gpio1.valid = false; - hw_cfg->gpio2.valid = false; - acpi_dev_put(cs35l41->dacpi); - put_device(physdev); - - return ret; } int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq, @@ -1808,6 +1998,10 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i if (ret) goto err; + ret = cs35l41_get_calibration(cs35l41); + if (ret && ret != -ENOENT) + goto err; + cs35l41_mute(cs35l41->dev, true); INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work); @@ -1851,12 +2045,14 @@ err: return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, SND_HDA_SCODEC_CS35L41); +EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, "SND_HDA_SCODEC_CS35L41"); void cs35l41_hda_remove(struct device *dev) { struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + component_del(cs35l41->dev, &cs35l41_hda_comp_ops); + pm_runtime_get_sync(cs35l41->dev); pm_runtime_dont_use_autosuspend(cs35l41->dev); pm_runtime_disable(cs35l41->dev); @@ -1864,8 +2060,6 @@ void cs35l41_hda_remove(struct device *dev) if (cs35l41->halo_initialized) cs35l41_remove_dsp(cs35l41); - component_del(cs35l41->dev, &cs35l41_hda_comp_ops); - acpi_dev_put(cs35l41->dacpi); pm_runtime_put_noidle(cs35l41->dev); @@ -1876,7 +2070,7 @@ void cs35l41_hda_remove(struct device *dev) gpiod_put(cs35l41->cs_gpio); kfree(cs35l41->acpi_subsystem_id); } -EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41); +EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, "SND_HDA_SCODEC_CS35L41"); const struct dev_pm_ops cs35l41_hda_pm_ops = { RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, @@ -1884,10 +2078,10 @@ const struct dev_pm_ops cs35l41_hda_pm_ops = { .prepare = cs35l41_system_suspend_prep, SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume) }; -EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41); +EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, "SND_HDA_SCODEC_CS35L41"); MODULE_DESCRIPTION("CS35L41 HDA Driver"); -MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS); +MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(FW_CS_DSP); +MODULE_IMPORT_NS("FW_CS_DSP"); diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h index 43d55292b327..c730b3351589 100644 --- a/sound/pci/hda/cs35l41_hda.h +++ b/sound/pci/hda/cs35l41_hda.h @@ -16,11 +16,14 @@ #include <linux/gpio/consumer.h> #include <linux/device.h> #include <sound/cs35l41.h> +#include <sound/cs-amp-lib.h> #include <linux/firmware/cirrus/cs_dsp.h> #include <linux/firmware/cirrus/wmfw.h> #define CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ 1000000 +#define DEFAULT_AMP_GAIN_PCM 17 /* 17.5dB Gain */ +#define DEFAULT_AMP_GAIN_PDM 19 /* 19.5dB Gain */ struct cs35l41_amp_cal_data { u32 calTarget[2]; @@ -83,6 +86,9 @@ struct cs35l41_hda { bool mute_override; enum control_bus control_bus; bool bypass_fw; + unsigned int tuning_gain; + struct cirrus_amp_cal_data cal_data; + bool cal_data_valid; }; @@ -98,5 +104,6 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i struct regmap *regmap, enum control_bus control_bus); void cs35l41_hda_remove(struct device *dev); int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id); +int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id); #endif /*__CS35L41_HDA_H__*/ diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/pci/hda/cs35l41_hda_i2c.c index 603e9bff3a71..e77495413c21 100644 --- a/sound/pci/hda/cs35l41_hda_i2c.c +++ b/sound/pci/hda/cs35l41_hda_i2c.c @@ -39,7 +39,7 @@ static void cs35l41_hda_i2c_remove(struct i2c_client *clt) } static const struct i2c_device_id cs35l41_hda_i2c_id[] = { - { "cs35l41-hda", 0 }, + { "cs35l41-hda" }, {} }; @@ -64,6 +64,6 @@ static struct i2c_driver cs35l41_i2c_driver = { module_i2c_driver(cs35l41_i2c_driver); MODULE_DESCRIPTION("HDA CS35L41 driver"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L41); +MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41"); MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 72ec872afb8d..d8249d997c2a 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -31,6 +31,9 @@ struct cs35l41_config { }; static const struct cs35l41_config cs35l41_config_table[] = { + { "10251826", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, + { "1025182C", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, + { "10251844", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, { "10280B27", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, { "10280B28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, { "10280BEB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 }, @@ -70,6 +73,8 @@ static const struct cs35l41_config cs35l41_config_table[] = { { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 }, { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 }, { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 }, + { "103C8C4D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8C4E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, @@ -95,6 +100,7 @@ static const struct cs35l41_config cs35l41_config_table[] = { { "10431863", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, { "104318D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, { "10431A83", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, + { "10431B93", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, { "10431C9F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, { "10431CAF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, { "10431CCF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, @@ -108,13 +114,27 @@ static const struct cs35l41_config cs35l41_config_table[] = { { "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, { "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 }, { "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 }, + { "10433A20", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10433A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10433A40", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10433A50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "10433A60", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, + { "17AA3865", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, + { "17AA3866", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, + { "17AA386E", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 }, { "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, + { "17AA3877", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, + { "17AA3878", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 }, { "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 }, { "17AA38AB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 }, { "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, { "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, { "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, { "17AA38B7", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 }, + { "17AA38C7", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 }, + { "17AA38C8", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 }, + { "17AA38F9", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 }, + { "17AA38FA", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 }, {} }; @@ -411,6 +431,20 @@ static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *phy return 0; } +static int missing_speaker_id_gpio2(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + int ret; + + ret = cs35l41_add_gpios(cs35l41, physdev, -1, 2, -1, 2); + if (ret) { + dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret); + return ret; + } + + return cs35l41_hda_parse_acpi(cs35l41, physdev, id); +} + struct cs35l41_prop_model { const char *hid; const char *ssid; @@ -421,6 +455,9 @@ struct cs35l41_prop_model { static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CLSA0100", NULL, lenovo_legion_no_acpi }, { "CLSA0101", NULL, lenovo_legion_no_acpi }, + { "CSC3551", "10251826", generic_dsd_config }, + { "CSC3551", "1025182C", generic_dsd_config }, + { "CSC3551", "10251844", generic_dsd_config }, { "CSC3551", "10280B27", generic_dsd_config }, { "CSC3551", "10280B28", generic_dsd_config }, { "CSC3551", "10280BEB", generic_dsd_config }, @@ -454,6 +491,8 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CSC3551", "103C8C15", generic_dsd_config }, { "CSC3551", "103C8C16", generic_dsd_config }, { "CSC3551", "103C8C17", generic_dsd_config }, + { "CSC3551", "103C8C4D", generic_dsd_config }, + { "CSC3551", "103C8C4E", generic_dsd_config }, { "CSC3551", "103C8C4F", generic_dsd_config }, { "CSC3551", "103C8C50", generic_dsd_config }, { "CSC3551", "103C8C51", generic_dsd_config }, @@ -482,7 +521,9 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CSC3551", "104317F3", generic_dsd_config }, { "CSC3551", "10431863", generic_dsd_config }, { "CSC3551", "104318D3", generic_dsd_config }, + { "CSC3551", "10431A63", missing_speaker_id_gpio2 }, { "CSC3551", "10431A83", generic_dsd_config }, + { "CSC3551", "10431B93", generic_dsd_config }, { "CSC3551", "10431C9F", generic_dsd_config }, { "CSC3551", "10431CAF", generic_dsd_config }, { "CSC3551", "10431CCF", generic_dsd_config }, @@ -496,13 +537,27 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CSC3551", "10431F12", generic_dsd_config }, { "CSC3551", "10431F1F", generic_dsd_config }, { "CSC3551", "10431F62", generic_dsd_config }, + { "CSC3551", "10433A20", generic_dsd_config }, + { "CSC3551", "10433A30", generic_dsd_config }, + { "CSC3551", "10433A40", generic_dsd_config }, + { "CSC3551", "10433A50", generic_dsd_config }, + { "CSC3551", "10433A60", generic_dsd_config }, + { "CSC3551", "17AA3865", generic_dsd_config }, + { "CSC3551", "17AA3866", generic_dsd_config }, + { "CSC3551", "17AA386E", generic_dsd_config }, { "CSC3551", "17AA386F", generic_dsd_config }, + { "CSC3551", "17AA3877", generic_dsd_config }, + { "CSC3551", "17AA3878", generic_dsd_config }, { "CSC3551", "17AA38A9", generic_dsd_config }, { "CSC3551", "17AA38AB", generic_dsd_config }, { "CSC3551", "17AA38B4", generic_dsd_config }, { "CSC3551", "17AA38B5", generic_dsd_config }, { "CSC3551", "17AA38B6", generic_dsd_config }, { "CSC3551", "17AA38B7", generic_dsd_config }, + { "CSC3551", "17AA38C7", generic_dsd_config }, + { "CSC3551", "17AA38C8", generic_dsd_config }, + { "CSC3551", "17AA38F9", generic_dsd_config }, + { "CSC3551", "17AA38FA", generic_dsd_config }, {} }; diff --git a/sound/pci/hda/cs35l41_hda_spi.c b/sound/pci/hda/cs35l41_hda_spi.c index b76c0dfd5fef..2acbaf8467a0 100644 --- a/sound/pci/hda/cs35l41_hda_spi.c +++ b/sound/pci/hda/cs35l41_hda_spi.c @@ -38,6 +38,7 @@ static const struct spi_device_id cs35l41_hda_spi_id[] = { { "cs35l41-hda", 0 }, {} }; +MODULE_DEVICE_TABLE(spi, cs35l41_hda_spi_id); static const struct acpi_device_id cs35l41_acpi_hda_match[] = { { "CSC3551", 0 }, @@ -58,6 +59,6 @@ static struct spi_driver cs35l41_spi_driver = { module_spi_driver(cs35l41_spi_driver); MODULE_DESCRIPTION("HDA CS35L41 driver"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L41); +MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41"); MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 41974b3897a7..886c53184fec 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -20,7 +20,6 @@ #include "cirrus_scodec.h" #include "cs35l56_hda.h" #include "hda_component.h" -#include "hda_cs_dsp_ctl.h" #include "hda_generic.h" /* @@ -50,17 +49,25 @@ static const struct reg_sequence cs35l56_hda_dai_config[] = { }; +static void cs35l56_hda_wait_dsp_ready(struct cs35l56_hda *cs35l56) +{ + /* Wait for patching to complete */ + flush_work(&cs35l56->dsp_work); +} + static void cs35l56_hda_play(struct cs35l56_hda *cs35l56) { unsigned int val; int ret; + cs35l56_hda_wait_dsp_ready(cs35l56); + pm_runtime_get_sync(cs35l56->base.dev); ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY); if (ret == 0) { /* Wait for firmware to enter PS0 power state */ ret = regmap_read_poll_timeout(cs35l56->base.regmap, - CS35L56_TRANSDUCER_ACTUAL_PS, + cs35l56->base.fw_reg->transducer_actual_ps, val, (val == CS35L56_PS0), CS35L56_PS0_POLL_US, CS35L56_PS0_TIMEOUT_US); @@ -143,10 +150,6 @@ static int cs35l56_hda_runtime_resume(struct device *dev) } } - ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); - if (ret) - goto err; - return 0; err: @@ -176,10 +179,12 @@ static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol, static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); unsigned int reg_val; int i; + cs35l56_hda_wait_dsp_ready(cs35l56); + regmap_read(cs35l56->base.regmap, kcontrol->private_value, ®_val); reg_val &= CS35L56_ASP_TXn_SRC_MASK; @@ -196,13 +201,15 @@ static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol, static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); unsigned int item = ucontrol->value.enumerated.item[0]; bool changed; if (item >= CS35L56_NUM_INPUT_SRC) return -EINVAL; + cs35l56_hda_wait_dsp_ready(cs35l56); + regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value, CS35L56_INPUT_MASK, cs35l56_tx_input_values[item], &changed); @@ -223,11 +230,14 @@ static int cs35l56_hda_posture_info(struct snd_kcontrol *kcontrol, static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); unsigned int pos; int ret; - ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, &pos); + cs35l56_hda_wait_dsp_ready(cs35l56); + + ret = regmap_read(cs35l56->base.regmap, + cs35l56->base.fw_reg->posture_number, &pos); if (ret) return ret; @@ -239,7 +249,7 @@ static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol, static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); unsigned long pos = ucontrol->value.integer.value[0]; bool changed; int ret; @@ -248,10 +258,10 @@ static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol, (pos > CS35L56_MAIN_POSTURE_MAX)) return -EINVAL; - ret = regmap_update_bits_check(cs35l56->base.regmap, - CS35L56_MAIN_POSTURE_NUMBER, - CS35L56_MAIN_POSTURE_MASK, - pos, &changed); + cs35l56_hda_wait_dsp_ready(cs35l56); + + ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->posture_number, + CS35L56_MAIN_POSTURE_MASK, pos, &changed); if (ret) return ret; @@ -286,12 +296,14 @@ static int cs35l56_hda_vol_info(struct snd_kcontrol *kcontrol, static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); unsigned int raw_vol; int vol; int ret; - ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, &raw_vol); + cs35l56_hda_wait_dsp_ready(cs35l56); + + ret = regmap_read(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume, &raw_vol); if (ret) return ret; @@ -310,7 +322,7 @@ static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol, static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data; + struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); long vol = ucontrol->value.integer.value[0]; unsigned int raw_vol; bool changed; @@ -323,10 +335,10 @@ static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol, raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) << CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT; - ret = regmap_update_bits_check(cs35l56->base.regmap, - CS35L56_MAIN_RENDER_USER_VOLUME, - CS35L56_MAIN_RENDER_USER_VOLUME_MASK, - raw_vol, &changed); + cs35l56_hda_wait_dsp_ready(cs35l56); + + ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume, + CS35L56_MAIN_RENDER_USER_VOLUME_MASK, raw_vol, &changed); if (ret) return ret; @@ -393,7 +405,7 @@ static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56) } static const struct cs_dsp_client_ops cs35l56_hda_client_ops = { - .control_remove = hda_cs_dsp_control_remove, + /* cs_dsp requires the client to provide this even if it is empty */ }; static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56, @@ -530,26 +542,13 @@ static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmw const struct firmware *coeff_firmware, char *coeff_filename) { - if (wmfw_firmware) - release_firmware(wmfw_firmware); + release_firmware(wmfw_firmware); kfree(wmfw_filename); - if (coeff_firmware) - release_firmware(coeff_firmware); + release_firmware(coeff_firmware); kfree(coeff_filename); } -static void cs35l56_hda_add_dsp_controls(struct cs35l56_hda *cs35l56) -{ - struct hda_cs_dsp_ctl_info info; - - info.device_name = cs35l56->amp_name; - info.fw_type = HDA_CS_DSP_FW_MISC; - info.card = cs35l56->codec->card; - - hda_cs_dsp_add_controls(&cs35l56->cs_dsp, &info); -} - static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56) { int ret; @@ -566,7 +565,7 @@ static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56) dev_info(cs35l56->base.dev, "Calibration applied\n"); } -static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) +static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) { const struct firmware *coeff_firmware = NULL; const struct firmware *wmfw_firmware = NULL; @@ -574,15 +573,23 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) char *wmfw_filename = NULL; unsigned int preloaded_fw_ver; bool firmware_missing; - int ret = 0; + int ret; - /* Prepare for a new DSP power-up */ + /* + * Prepare for a new DSP power-up. If the DSP has had firmware + * downloaded previously then it needs to be powered down so that it + * can be updated. + */ if (cs35l56->base.fw_patched) cs_dsp_power_down(&cs35l56->cs_dsp); cs35l56->base.fw_patched = false; - pm_runtime_get_sync(cs35l56->base.dev); + ret = pm_runtime_resume_and_get(cs35l56->base.dev); + if (ret < 0) { + dev_err(cs35l56->base.dev, "Failed to resume and get %d\n", ret); + return; + } /* * The firmware can only be upgraded if it is currently running @@ -606,7 +613,6 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) */ if (!coeff_firmware && firmware_missing) { dev_err(cs35l56->base.dev, ".bin file required but not found\n"); - ret = -ENOENT; goto err_fw_release; } @@ -644,6 +650,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) ret = cs35l56_wait_for_firmware_boot(&cs35l56->base); if (ret) goto err_powered_up; + + regcache_cache_only(cs35l56->base.regmap, false); } /* Disable auto-hibernate so that runtime_pm has control */ @@ -653,7 +661,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) regcache_sync(cs35l56->base.regmap); - regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, + regmap_clear_bits(cs35l56->base.regmap, + cs35l56->base.fw_reg->prot_sts, CS35L56_FIRMWARE_MISSING); cs35l56->base.fw_patched = true; @@ -666,6 +675,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) if (ret) cs_dsp_stop(&cs35l56->cs_dsp); + cs35l56_log_tuning(&cs35l56->base, &cs35l56->cs_dsp); + err_powered_up: if (!cs35l56->base.fw_patched) cs_dsp_power_down(&cs35l56->cs_dsp); @@ -676,34 +687,36 @@ err_fw_release: coeff_firmware, coeff_filename); err_pm_put: pm_runtime_put(cs35l56->base.dev); +} - return ret; +static void cs35l56_hda_dsp_work(struct work_struct *work) +{ + struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, dsp_work); + + cs35l56_hda_fw_load(cs35l56); } static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data) { struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); - struct hda_component *comps = master_data; - int ret; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; - if (!comps || cs35l56->index < 0 || cs35l56->index >= HDA_MAX_COMPONENTS) + comp = hda_component_from_index(parent, cs35l56->index); + if (!comp) return -EINVAL; - comps = &comps[cs35l56->index]; - if (comps->dev) + if (comp->dev) return -EBUSY; - comps->dev = dev; - cs35l56->codec = comps->codec; - strscpy(comps->name, dev_name(dev), sizeof(comps->name)); - comps->playback_hook = cs35l56_hda_playback_hook; + comp->dev = dev; + cs35l56->codec = parent->codec; + strscpy(comp->name, dev_name(dev), sizeof(comp->name)); + comp->playback_hook = cs35l56_hda_playback_hook; - ret = cs35l56_hda_fw_load(cs35l56); - if (ret) - return ret; + queue_work(system_long_wq, &cs35l56->dsp_work); cs35l56_hda_create_controls(cs35l56); - cs35l56_hda_add_dsp_controls(cs35l56); #if IS_ENABLED(CONFIG_SND_DEBUG) cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root); @@ -718,7 +731,10 @@ static int cs35l56_hda_bind(struct device *dev, struct device *master, void *mas static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data) { struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); - struct hda_component *comps = master_data; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; + + cancel_work_sync(&cs35l56->dsp_work); cs35l56_hda_remove_controls(cs35l56); @@ -730,10 +746,11 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void * if (cs35l56->base.fw_patched) cs_dsp_power_down(&cs35l56->cs_dsp); - cs_dsp_remove(&cs35l56->cs_dsp); + comp = hda_component_from_index(parent, cs35l56->index); + if (comp && (comp->dev == dev)) + memset(comp, 0, sizeof(*comp)); - if (comps[cs35l56->index].dev == dev) - memset(&comps[cs35l56->index], 0, sizeof(*comps)); + cs35l56->codec = NULL; dev_dbg(cs35l56->base.dev, "Unbound\n"); } @@ -747,6 +764,8 @@ static int cs35l56_hda_system_suspend(struct device *dev) { struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + cs35l56_hda_wait_dsp_ready(cs35l56); + if (cs35l56->playing) cs35l56_hda_pause(cs35l56); @@ -840,13 +859,13 @@ static int cs35l56_hda_system_resume(struct device *dev) cs35l56->suspended = false; + if (!cs35l56->codec) + return 0; + ret = cs35l56_is_fw_reload_needed(&cs35l56->base); dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret); - if (ret > 0) { - ret = cs35l56_hda_fw_load(cs35l56); - if (ret) - return ret; - } + if (ret > 0) + queue_work(system_long_wq, &cs35l56->dsp_work); if (cs35l56->playing) cs35l56_hda_play(cs35l56); @@ -854,6 +873,52 @@ static int cs35l56_hda_system_resume(struct device *dev) return 0; } +static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr) +{ + /* The cirrus,dev-index property has the wrong values */ + switch (*bus_addr) { + case 0x30: + cs35l56->index = 1; + return 0; + case 0x31: + cs35l56->index = 0; + return 0; + default: + /* There is a pseudo-address for broadcast to both amps - ignore it */ + dev_dbg(cs35l56->base.dev, "Ignoring I2C address %#x\n", *bus_addr); + return 0; + } +} + +static const struct { + const char *sub; + int (*fixup_fn)(struct cs35l56_hda *cs35l56, int *bus_addr); +} cs35l56_hda_fixups[] = { + { + .sub = "17AA390B", /* Lenovo Yoga Book 9i GenX */ + .fixup_fn = cs35l56_hda_fixup_yoga9, + }, +}; + +static int cs35l56_hda_apply_platform_fixups(struct cs35l56_hda *cs35l56, const char *sub, + int *bus_addr) +{ + int i; + + if (IS_ERR(sub)) + return 0; + + for (i = 0; i < ARRAY_SIZE(cs35l56_hda_fixups); i++) { + if (strcasecmp(cs35l56_hda_fixups[i].sub, sub) == 0) { + dev_dbg(cs35l56->base.dev, "Applying fixup for %s\n", + cs35l56_hda_fixups[i].sub); + return (cs35l56_hda_fixups[i].fixup_fn)(cs35l56, bus_addr); + } + } + + return 0; +} + static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) { u32 values[HDA_MAX_COMPONENTS]; @@ -878,39 +943,47 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) ACPI_COMPANION_SET(cs35l56->base.dev, adev); } - property = "cirrus,dev-index"; - ret = device_property_count_u32(cs35l56->base.dev, property); - if (ret <= 0) - goto err; - - if (ret > ARRAY_SIZE(values)) { - ret = -EINVAL; - goto err; - } - nval = ret; + /* Initialize things that could be overwritten by a fixup */ + cs35l56->index = -1; - ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval); + sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev)); + ret = cs35l56_hda_apply_platform_fixups(cs35l56, sub, &id); if (ret) - goto err; + return ret; - cs35l56->index = -1; - for (i = 0; i < nval; i++) { - if (values[i] == id) { - cs35l56->index = i; - break; - } - } - /* - * It's not an error for the ID to be missing: for I2C there can be - * an alias address that is not a real device. So reject silently. - */ if (cs35l56->index == -1) { - dev_dbg(cs35l56->base.dev, "No index found in %s\n", property); - ret = -ENODEV; - goto err; - } + property = "cirrus,dev-index"; + ret = device_property_count_u32(cs35l56->base.dev, property); + if (ret <= 0) + goto err; - sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev)); + if (ret > ARRAY_SIZE(values)) { + ret = -EINVAL; + goto err; + } + nval = ret; + + ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval); + if (ret) + goto err; + + for (i = 0; i < nval; i++) { + if (values[i] == id) { + cs35l56->index = i; + break; + } + } + + /* + * It's not an error for the ID to be missing: for I2C there can be + * an alias address that is not a real device. So reject silently. + */ + if (cs35l56->index == -1) { + dev_dbg(cs35l56->base.dev, "No index found in %s\n", property); + ret = -ENODEV; + goto err; + } + } if (IS_ERR(sub)) { dev_info(cs35l56->base.dev, @@ -964,6 +1037,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) mutex_init(&cs35l56->base.irq_lock); dev_set_drvdata(cs35l56->base.dev, cs35l56); + INIT_WORK(&cs35l56->dsp_work, cs35l56_hda_dsp_work); + ret = cs35l56_hda_read_acpi(cs35l56, hid, id); if (ret) goto err; @@ -975,7 +1050,7 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) goto err; } - cs35l56->base.cal_index = cs35l56->index; + cs35l56->base.cal_index = -1; cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp); cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops; @@ -1002,6 +1077,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) if (ret) goto err; + regcache_cache_only(cs35l56->base.regmap, false); + ret = cs35l56_set_patch(&cs35l56->base); if (ret) goto err; @@ -1024,14 +1101,11 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) goto err; } - dev_dbg(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n", - cs35l56->system_name, cs35l56->amp_name); + dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n", + cs35l56->system_name, cs35l56->amp_name); regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config, ARRAY_SIZE(cs35l56_hda_dai_config)); - ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); - if (ret) - goto err; /* * By default only enable one ASP1TXn, where n=amplifier index, @@ -1045,41 +1119,44 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) pm_runtime_mark_last_busy(cs35l56->base.dev); pm_runtime_enable(cs35l56->base.dev); + cs35l56->base.init_done = true; + ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops); if (ret) { dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret); goto pm_err; } - cs35l56->base.init_done = true; - return 0; pm_err: pm_runtime_disable(cs35l56->base.dev); + cs_dsp_remove(&cs35l56->cs_dsp); err: gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, SND_HDA_SCODEC_CS35L56); +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, "SND_HDA_SCODEC_CS35L56"); void cs35l56_hda_remove(struct device *dev) { struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev); + component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops); + pm_runtime_dont_use_autosuspend(cs35l56->base.dev); pm_runtime_get_sync(cs35l56->base.dev); pm_runtime_disable(cs35l56->base.dev); - component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops); + cs_dsp_remove(&cs35l56->cs_dsp); kfree(cs35l56->system_name); pm_runtime_put_noidle(cs35l56->base.dev); gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); } -EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, SND_HDA_SCODEC_CS35L56); +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, "SND_HDA_SCODEC_CS35L56"); const struct dev_pm_ops cs35l56_hda_pm_ops = { RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL) @@ -1089,14 +1166,13 @@ const struct dev_pm_ops cs35l56_hda_pm_ops = { NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq, cs35l56_hda_system_resume_no_irq) }; -EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, SND_HDA_SCODEC_CS35L56); +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, "SND_HDA_SCODEC_CS35L56"); MODULE_DESCRIPTION("CS35L56 HDA Driver"); -MODULE_IMPORT_NS(FW_CS_DSP); -MODULE_IMPORT_NS(SND_HDA_CIRRUS_SCODEC); -MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); -MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB); +MODULE_IMPORT_NS("FW_CS_DSP"); +MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); +MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h index 464e4aa63cd1..38d94fb213a5 100644 --- a/sound/pci/hda/cs35l56_hda.h +++ b/sound/pci/hda/cs35l56_hda.h @@ -14,6 +14,7 @@ #include <linux/firmware/cirrus/cs_dsp.h> #include <linux/firmware/cirrus/wmfw.h> #include <linux/regulator/consumer.h> +#include <linux/workqueue.h> #include <sound/cs35l56.h> struct dentry; @@ -21,6 +22,7 @@ struct dentry; struct cs35l56_hda { struct cs35l56_base base; struct hda_codec *codec; + struct work_struct dsp_work; int index; const char *system_name; diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c index 13beee807308..d10209e4eddd 100644 --- a/sound/pci/hda/cs35l56_hda_i2c.c +++ b/sound/pci/hda/cs35l56_hda_i2c.c @@ -26,6 +26,9 @@ static int cs35l56_hda_i2c_probe(struct i2c_client *clt) #ifdef CS35L56_WAKE_HOLD_TIME_US cs35l56->base.can_hibernate = true; #endif + + cs35l56->base.fw_reg = &cs35l56_fw_reg; + cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c); if (IS_ERR(cs35l56->base.regmap)) { ret = PTR_ERR(cs35l56->base.regmap); @@ -56,10 +59,19 @@ static const struct i2c_device_id cs35l56_hda_i2c_id[] = { {} }; +static const struct acpi_device_id cs35l56_acpi_hda_match[] = { + { "CSC3554", 0 }, + { "CSC3556", 0 }, + { "CSC3557", 0 }, + {} +}; +MODULE_DEVICE_TABLE(acpi, cs35l56_acpi_hda_match); + static struct i2c_driver cs35l56_hda_i2c_driver = { .driver = { - .name = "cs35l56-hda", - .pm = &cs35l56_hda_pm_ops, + .name = "cs35l56-hda", + .acpi_match_table = cs35l56_acpi_hda_match, + .pm = &cs35l56_hda_pm_ops, }, .id_table = cs35l56_hda_i2c_id, .probe = cs35l56_hda_i2c_probe, @@ -68,8 +80,8 @@ static struct i2c_driver cs35l56_hda_i2c_driver = { module_i2c_driver(cs35l56_hda_i2c_driver); MODULE_DESCRIPTION("HDA CS35L56 I2C driver"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c index a3b2fa76663d..f57533d3d728 100644 --- a/sound/pci/hda/cs35l56_hda_spi.c +++ b/sound/pci/hda/cs35l56_hda_spi.c @@ -22,10 +22,16 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi) return -ENOMEM; cs35l56->base.dev = &spi->dev; + ret = cs35l56_init_config_for_spi(&cs35l56->base, spi); + if (ret) + return ret; #ifdef CS35L56_WAKE_HOLD_TIME_US cs35l56->base.can_hibernate = true; #endif + + cs35l56->base.fw_reg = &cs35l56_fw_reg; + cs35l56->base.regmap = devm_regmap_init_spi(spi, &cs35l56_regmap_spi); if (IS_ERR(cs35l56->base.regmap)) { ret = PTR_ERR(cs35l56->base.regmap); @@ -56,10 +62,19 @@ static const struct spi_device_id cs35l56_hda_spi_id[] = { {} }; +static const struct acpi_device_id cs35l56_acpi_hda_match[] = { + { "CSC3554", 0 }, + { "CSC3556", 0 }, + { "CSC3557", 0 }, + {} +}; +MODULE_DEVICE_TABLE(acpi, cs35l56_acpi_hda_match); + static struct spi_driver cs35l56_hda_spi_driver = { .driver = { - .name = "cs35l56-hda", - .pm = &cs35l56_hda_pm_ops, + .name = "cs35l56-hda", + .acpi_match_table = cs35l56_acpi_hda_match, + .pm = &cs35l56_hda_pm_ops, }, .id_table = cs35l56_hda_spi_id, .probe = cs35l56_hda_spi_probe, @@ -68,8 +83,8 @@ static struct spi_driver cs35l56_hda_spi_driver = { module_spi_driver(cs35l56_hda_spi_driver); MODULE_DESCRIPTION("HDA CS35L56 SPI driver"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_acpi.c b/sound/pci/hda/hda_acpi.c new file mode 100644 index 000000000000..505cc97e0ee9 --- /dev/null +++ b/sound/pci/hda/hda_acpi.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ALSA driver for ACPI-based HDA Controllers. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> + +#include <sound/hda_codec.h> + +#include "hda_controller.h" + +struct hda_acpi { + struct azx azx; + struct snd_card *card; + struct platform_device *pdev; + void __iomem *regs; + struct work_struct probe_work; + const struct hda_data *data; +}; + +/** + * struct hda_data - Optional device-specific data + * @short_name: Used for the ALSA card name; defaults to KBUILD_MODNAME + * @long_name: Used for longer description; defaults to short_name + * @flags: Passed to &azx->driver_caps + * + * A pointer to a record of this type may be stored in the + * &acpi_device_id->driver_data field of an ACPI match table entry in order to + * customize the naming and behavior of a particular device. All fields are + * optional and sensible defaults will be selected in their absence. + */ +struct hda_data { + const char *short_name; + const char *long_name; + unsigned long flags; +}; + +static int hda_acpi_dev_disconnect(struct snd_device *device) +{ + struct azx *chip = device->device_data; + + chip->bus.shutdown = 1; + return 0; +} + +static int hda_acpi_dev_free(struct snd_device *device) +{ + struct azx *azx = device->device_data; + struct hda_acpi *hda = container_of(azx, struct hda_acpi, azx); + + cancel_work_sync(&hda->probe_work); + if (azx_bus(azx)->chip_init) { + azx_stop_all_streams(azx); + azx_stop_chip(azx); + } + + azx_free_stream_pages(azx); + azx_free_streams(azx); + snd_hdac_bus_exit(azx_bus(azx)); + + return 0; +} + +static int hda_acpi_init(struct hda_acpi *hda) +{ + struct hdac_bus *bus = azx_bus(&hda->azx); + struct snd_card *card = hda->azx.card; + struct device *dev = &hda->pdev->dev; + struct azx *azx = &hda->azx; + struct resource *res; + unsigned short gcap; + const char *sname, *lname; + int err, irq; + + /* The base address for the HDA registers and the interrupt are wrapped + * in an ACPI _CRS object which can be parsed by platform_get_irq() and + * devm_platform_get_and_ioremap_resource() + */ + + irq = platform_get_irq(hda->pdev, 0); + if (irq < 0) + return irq; + + hda->regs = devm_platform_get_and_ioremap_resource(hda->pdev, 0, &res); + if (IS_ERR(hda->regs)) + return PTR_ERR(hda->regs); + + bus->remap_addr = hda->regs; + bus->addr = res->start; + + err = devm_request_irq(dev, irq, azx_interrupt, + IRQF_SHARED, KBUILD_MODNAME, azx); + if (err) { + dev_err(dev, "unable to request IRQ %d, disabling device\n", + irq); + return err; + } + bus->irq = irq; + bus->dma_stop_delay = 100; + card->sync_irq = bus->irq; + + gcap = azx_readw(azx, GCAP); + dev_dbg(dev, "chipset global capabilities = 0x%x\n", gcap); + + azx->align_buffer_size = 1; + + azx->capture_streams = (gcap >> 8) & 0x0f; + azx->playback_streams = (gcap >> 12) & 0x0f; + + azx->capture_index_offset = 0; + azx->playback_index_offset = azx->capture_streams; + azx->num_streams = azx->playback_streams + azx->capture_streams; + + err = azx_init_streams(azx); + if (err < 0) { + dev_err(dev, "failed to initialize streams: %d\n", err); + return err; + } + + err = azx_alloc_stream_pages(azx); + if (err < 0) { + dev_err(dev, "failed to allocate stream pages: %d\n", err); + return err; + } + + azx_init_chip(azx, 1); + + if (!bus->codec_mask) { + dev_err(dev, "no codecs found!\n"); + return -ENODEV; + } + + strscpy(card->driver, "hda-acpi"); + + sname = hda->data->short_name ? hda->data->short_name : KBUILD_MODNAME; + + if (strlen(sname) > sizeof(card->shortname)) + dev_info(dev, "truncating shortname for card %s\n", sname); + strscpy(card->shortname, sname); + + lname = hda->data->long_name ? hda->data->long_name : sname; + + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", lname, bus->addr, bus->irq); + + return 0; +} + +static void hda_acpi_probe_work(struct work_struct *work) +{ + struct hda_acpi *hda = container_of(work, struct hda_acpi, probe_work); + struct azx *chip = &hda->azx; + int err; + + err = hda_acpi_init(hda); + if (err < 0) + return; + + err = azx_probe_codecs(chip, 8); + if (err < 0) + return; + + err = azx_codec_configure(chip); + if (err < 0) + return; + + err = snd_card_register(chip->card); + if (err < 0) + return; + + chip->running = 1; +} + +static int hda_acpi_create(struct hda_acpi *hda) +{ + static const struct snd_device_ops ops = { + .dev_disconnect = hda_acpi_dev_disconnect, + .dev_free = hda_acpi_dev_free, + }; + static const struct hda_controller_ops null_ops; + struct azx *azx = &hda->azx; + int err; + + mutex_init(&azx->open_mutex); + azx->card = hda->card; + INIT_LIST_HEAD(&azx->pcm_list); + + azx->ops = &null_ops; + azx->driver_caps = hda->data->flags; + azx->driver_type = hda->data->flags & 0xff; + azx->codec_probe_mask = -1; + + err = azx_bus_init(azx, NULL); + if (err < 0) + return err; + + err = snd_device_new(hda->card, SNDRV_DEV_LOWLEVEL, &hda->azx, &ops); + if (err < 0) { + dev_err(&hda->pdev->dev, "Error creating device\n"); + return err; + } + + return 0; +} + +static int hda_acpi_probe(struct platform_device *pdev) +{ + struct hda_acpi *hda; + int err; + + hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); + if (!hda) + return -ENOMEM; + + hda->pdev = pdev; + hda->data = acpi_device_get_match_data(&pdev->dev); + + /* Fall back to defaults if the table didn't have a *struct hda_data */ + if (!hda->data) + hda->data = devm_kzalloc(&pdev->dev, sizeof(*hda->data), + GFP_KERNEL); + if (!hda->data) + return -ENOMEM; + + err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &hda->card); + if (err < 0) { + dev_err(&pdev->dev, "Error creating card!\n"); + return err; + } + + INIT_WORK(&hda->probe_work, hda_acpi_probe_work); + + err = hda_acpi_create(hda); + if (err < 0) + goto out_free; + hda->card->private_data = &hda->azx; + + dev_set_drvdata(&pdev->dev, hda->card); + + schedule_work(&hda->probe_work); + + return 0; + +out_free: + snd_card_free(hda->card); + return err; +} + +static void hda_acpi_remove(struct platform_device *pdev) +{ + snd_card_free(dev_get_drvdata(&pdev->dev)); +} + +static void hda_acpi_shutdown(struct platform_device *pdev) +{ + struct snd_card *card = dev_get_drvdata(&pdev->dev); + struct azx *chip; + + if (!card) + return; + chip = card->private_data; + if (chip && chip->running) + azx_stop_chip(chip); +} + +static int hda_acpi_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_suspend(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + return 0; +} + +static int hda_acpi_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + int rc; + + rc = pm_runtime_force_resume(dev); + if (rc < 0) + return rc; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static const struct dev_pm_ops hda_acpi_pm = { + SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) +}; + +static const struct hda_data nvidia_hda_data = { + .short_name = "NVIDIA", + .long_name = "NVIDIA HDA Controller", + .flags = AZX_DCAPS_CORBRP_SELF_CLEAR, +}; + +static const struct acpi_device_id hda_acpi_match[] = { + { .id = "NVDA2014", .driver_data = (uintptr_t) &nvidia_hda_data }, + { .id = "NVDA2015", .driver_data = (uintptr_t) &nvidia_hda_data }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, hda_acpi_match); + +static struct platform_driver hda_acpi_platform_driver = { + .driver = { + .name = KBUILD_MODNAME, + .pm = &hda_acpi_pm, + .acpi_match_table = hda_acpi_match, + }, + .probe = hda_acpi_probe, + .remove = hda_acpi_remove, + .shutdown = hda_acpi_shutdown, +}; +module_platform_driver(hda_acpi_platform_driver); + +MODULE_DESCRIPTION("Driver for ACPI-based HDA Controllers"); +MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 7c6b1fe8dfcc..8923813ce424 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -80,7 +80,11 @@ static int compare_input_type(const void *ap, const void *bp) /* In case one has boost and the other one has not, pick the one with boost first. */ - return (int)(b->has_boost_on_pin - a->has_boost_on_pin); + if (a->has_boost_on_pin != b->has_boost_on_pin) + return (int)(b->has_boost_on_pin - a->has_boost_on_pin); + + /* Keep the original order */ + return a->order - b->order; } /* Reorder the surround channels @@ -400,6 +404,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); /* sort inputs in the order of AUTO_PIN_* type */ + for (i = 0; i < cfg->num_inputs; i++) + cfg->inputs[i].order = i; sort(cfg->inputs, cfg->num_inputs, sizeof(cfg->inputs[0]), compare_input_type, NULL); @@ -933,6 +939,7 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, bool match_all_pins) { const struct snd_hda_pin_quirk *pq; + const char *name = NULL; if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) return; @@ -946,9 +953,10 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, codec->fixup_id = pq->value; #ifdef CONFIG_SND_DEBUG_VERBOSE codec->fixup_name = pq->name; - codec_dbg(codec, "%s: picked fixup %s (pin match)\n", - codec->core.chip_name, codec->fixup_name); + name = pq->name; #endif + codec_info(codec, "%s: picked fixup %s (pin match)\n", + codec->core.chip_name, name ? name : ""); codec->fixup_list = fixlist; return; } @@ -956,6 +964,28 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); +/* check whether the given quirk entry matches with vendor/device pair */ +static bool hda_quirk_match(u16 vendor, u16 device, const struct hda_quirk *q) +{ + if (q->subvendor != vendor) + return false; + return !q->subdevice || + (device & q->subdevice_mask) == q->subdevice; +} + +/* look through the quirk list and return the matching entry */ +static const struct hda_quirk * +hda_quirk_lookup_id(u16 vendor, u16 device, const struct hda_quirk *list) +{ + const struct hda_quirk *q; + + for (q = list; q->subvendor || q->subdevice; q++) { + if (hda_quirk_match(vendor, device, q)) + return q; + } + return NULL; +} + /** * snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string * @codec: the HDA codec @@ -975,14 +1005,16 @@ 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, + const struct hda_quirk *quirk, const struct hda_fixup *fixlist) { - const struct snd_pci_quirk *q; + const struct hda_quirk *q; int id = HDA_FIXUP_ID_NOT_SET; const char *name = NULL; const char *type = NULL; unsigned int vendor, device; + u16 pci_vendor, pci_device; + u16 codec_vendor, codec_device; if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) return; @@ -991,8 +1023,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { id = HDA_FIXUP_ID_NO_FIXUP; fixlist = NULL; - codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n", - codec->core.chip_name); + codec_info(codec, "%s: picked no fixup (nofixup specified)\n", + codec->core.chip_name); goto found; } @@ -1002,8 +1034,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, if (!strcmp(codec->modelname, models->name)) { id = models->id; name = models->name; - codec_dbg(codec, "%s: picked fixup %s (model specified)\n", - codec->core.chip_name, codec->fixup_name); + codec_info(codec, "%s: picked fixup %s (model specified)\n", + codec->core.chip_name, name); goto found; } models++; @@ -1013,27 +1045,42 @@ void snd_hda_pick_fixup(struct hda_codec *codec, if (!quirk) return; + if (codec->bus->pci) { + pci_vendor = codec->bus->pci->subsystem_vendor; + pci_device = codec->bus->pci->subsystem_device; + } + + codec_vendor = codec->core.subsystem_id >> 16; + codec_device = codec->core.subsystem_id & 0xffff; + /* match with the SSID alias given by the model string "XXXX:YYYY" */ if (codec->modelname && sscanf(codec->modelname, "%04x:%04x", &vendor, &device) == 2) { - q = snd_pci_quirk_lookup_id(vendor, device, quirk); + q = hda_quirk_lookup_id(vendor, device, quirk); if (q) { type = "alias SSID"; goto found_device; } } - /* match with the PCI SSID */ - q = snd_pci_quirk_lookup(codec->bus->pci, quirk); - if (q) { - type = "PCI SSID"; - goto found_device; + /* match primarily with the PCI SSID */ + for (q = quirk; q->subvendor || q->subdevice; q++) { + /* if the entry is specific to codec SSID, check with it */ + if (!codec->bus->pci || q->match_codec_ssid) { + if (hda_quirk_match(codec_vendor, codec_device, q)) { + type = "codec SSID"; + goto found_device; + } + } else { + if (hda_quirk_match(pci_vendor, pci_device, q)) { + type = "PCI SSID"; + goto found_device; + } + } } /* match with the codec SSID */ - q = snd_pci_quirk_lookup_id(codec->core.subsystem_id >> 16, - codec->core.subsystem_id & 0xffff, - quirk); + q = hda_quirk_lookup_id(codec_vendor, codec_device, quirk); if (q) { type = "codec SSID"; goto found_device; @@ -1046,9 +1093,9 @@ void snd_hda_pick_fixup(struct hda_codec *codec, #ifdef CONFIG_SND_DEBUG_VERBOSE name = q->name; #endif - codec_dbg(codec, "%s: picked fixup %s for %s %04x:%04x\n", - codec->core.chip_name, name ? name : "", - type, q->subvendor, q->subdevice); + codec_info(codec, "%s: picked fixup %s for %s %04x:%04x\n", + codec->core.chip_name, name ? name : "", + type, q->subvendor, q->subdevice); found: codec->fixup_id = id; codec->fixup_list = fixlist; diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index 579b11beac71..87af3d8c02f7 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -37,6 +37,7 @@ struct auto_pin_cfg_item { unsigned int is_headset_mic:1; unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */ unsigned int has_boost_on_pin:1; + int order; }; struct auto_pin_cfg; diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e51d47572557..13a7d92e8d8d 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -31,8 +31,9 @@ static void generate_tone(struct hda_beep *beep, int tone) beep->power_hook(beep, true); beep->playing = 1; } - snd_hda_codec_write(codec, beep->nid, 0, - AC_VERB_SET_BEEP_CONTROL, tone); + if (!codec->beep_just_power_on) + snd_hda_codec_write(codec, beep->nid, 0, + AC_VERB_SET_BEEP_CONTROL, tone); if (!tone && beep->playing) { beep->playing = 0; if (beep->power_hook) @@ -212,10 +213,12 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) struct hda_beep *beep; int err; - if (!snd_hda_get_bool_hint(codec, "beep")) - return 0; /* disabled explicitly by hints */ - if (codec->beep_mode == HDA_BEEP_MODE_OFF) - return 0; /* disabled by module option */ + if (!codec->beep_just_power_on) { + if (!snd_hda_get_bool_hint(codec, "beep")) + return 0; /* disabled explicitly by hints */ + if (codec->beep_mode == HDA_BEEP_MODE_OFF) + return 0; /* disabled by module option */ + } beep = kzalloc(sizeof(*beep), GFP_KERNEL); if (beep == NULL) diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index b7ca2a83fbb0..df8f88beddd0 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -18,10 +18,10 @@ /* * find a matching codec id */ -static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv) +static int hda_codec_match(struct hdac_device *dev, const struct hdac_driver *drv) { struct hda_codec *codec = container_of(dev, struct hda_codec, core); - struct hda_codec_driver *driver = + const struct hda_codec_driver *driver = container_of(drv, struct hda_codec_driver, core); const struct hda_device_id *list; /* check probe_id instead of vendor_id if set */ @@ -44,7 +44,7 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) struct hda_codec *codec = container_of(dev, struct hda_codec, core); /* ignore unsol events during shutdown */ - if (codec->bus->shutdown) + if (codec->card->shutdown || codec->bus->shutdown) return; /* ignore unsol events during system suspend/resume */ @@ -185,7 +185,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, drv->core.driver.probe = hda_codec_driver_probe; drv->core.driver.remove = hda_codec_driver_remove; drv->core.driver.shutdown = hda_codec_driver_shutdown; - drv->core.driver.pm = &hda_codec_driver_pm; + drv->core.driver.pm = pm_ptr(&hda_codec_driver_pm); drv->core.type = HDA_DEV_LEGACY; drv->core.match = hda_codec_match; drv->core.unsol_event = hda_codec_unsol_event; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2cac337f5263..c018beeecd3d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -616,7 +616,6 @@ void snd_hda_shutup_pins(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_shutup_pins); -#ifdef CONFIG_PM /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ static void restore_shutup_pins(struct hda_codec *codec) { @@ -634,7 +633,6 @@ static void restore_shutup_pins(struct hda_codec *codec) } codec->pins_shutup = 0; } -#endif static void hda_jackpoll_work(struct work_struct *work) { @@ -1001,9 +999,7 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, codec->card = card; codec->addr = codec_addr; -#ifdef CONFIG_PM codec->power_jiffies = jiffies; -#endif snd_hda_sysfs_init(codec); @@ -1238,7 +1234,6 @@ static void purify_inactive_streams(struct hda_codec *codec) } } -#ifdef CONFIG_PM /* clean up all streams; called from suspend */ static void hda_cleanup_all_streams(struct hda_codec *codec) { @@ -1250,7 +1245,6 @@ static void hda_cleanup_all_streams(struct hda_codec *codec) really_cleanup_stream(codec, p); } } -#endif /* * amp access functions @@ -1502,7 +1496,7 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, /* ofs = 0: raw max value */ maxval = get_amp_max_value(codec, nid, dir, 0); if (val > maxval) - val = maxval; + return -EINVAL; return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val); } @@ -1553,13 +1547,21 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, unsigned int ofs = get_amp_offset(kcontrol); long *valp = ucontrol->value.integer.value; int change = 0; + int err; if (chs & 1) { - change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); + err = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); + if (err < 0) + return err; + change |= err; valp++; } - if (chs & 2) - change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); + if (chs & 2) { + err = update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); + if (err < 0) + return err; + change |= err; + } return change; } EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); @@ -1730,37 +1732,6 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, EXPORT_SYMBOL_GPL(snd_hda_ctl_add); /** - * snd_hda_add_nid - Assign a NID to a control element - * @codec: HD-audio codec - * @nid: corresponding NID (optional) - * @kctl: the control element to assign - * @index: index to kctl - * - * Add the given control element to an array inside the codec instance. - * This function is used when #snd_hda_ctl_add cannot be used for 1:1 - * NID:KCTL mapping - for example "Capture Source" selector. - */ -int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, - unsigned int index, hda_nid_t nid) -{ - struct hda_nid_item *item; - - if (nid > 0) { - item = snd_array_new(&codec->nids); - if (!item) - return -ENOMEM; - item->kctl = kctl; - item->index = index; - item->nid = nid; - return 0; - } - codec_err(codec, "no NID for mapping control %s:%d:%d\n", - kctl->id.name, kctl->id.index, index); - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_hda_add_nid); - -/** * snd_hda_ctls_clear - Clear all controls assigned to the given codec * @codec: HD-audio codec */ @@ -2155,15 +2126,20 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, int change = 0; if (chs & 1) { + if (*valp < 0 || *valp > 1) + return -EINVAL; change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, HDA_AMP_MUTE, *valp ? 0 : HDA_AMP_MUTE); valp++; } - if (chs & 2) + if (chs & 2) { + if (*valp < 0 || *valp > 1) + return -EINVAL; change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, HDA_AMP_MUTE, *valp ? 0 : HDA_AMP_MUTE); + } hda_call_check_power_status(codec, nid); return change; } @@ -2463,7 +2439,9 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec, break; id = kctl->id; id.index = spdif_index; - snd_ctl_rename_id(codec->card, &kctl->id, &id); + err = snd_ctl_rename_id(codec->card, &kctl->id, &id); + if (err < 0) + return err; } bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI; } @@ -2858,7 +2836,6 @@ static void hda_exec_init_verbs(struct hda_codec *codec) static inline void hda_exec_init_verbs(struct hda_codec *codec) {} #endif -#ifdef CONFIG_PM /* update the power on/off account with the current jiffies */ static void update_power_acct(struct hda_codec *codec, bool on) { @@ -2966,9 +2943,6 @@ static int hda_codec_runtime_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_SLEEP static int hda_codec_pm_prepare(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); @@ -3023,22 +2997,18 @@ static int hda_codec_pm_restore(struct device *dev) dev->power.power_state = PMSG_RESTORE; return pm_runtime_force_resume(dev); } -#endif /* CONFIG_PM_SLEEP */ /* referred in hda_bind.c */ const struct dev_pm_ops hda_codec_driver_pm = { -#ifdef CONFIG_PM_SLEEP - .prepare = hda_codec_pm_prepare, - .complete = hda_codec_pm_complete, - .suspend = hda_codec_pm_suspend, - .resume = hda_codec_pm_resume, - .freeze = hda_codec_pm_freeze, - .thaw = hda_codec_pm_thaw, - .poweroff = hda_codec_pm_suspend, - .restore = hda_codec_pm_restore, -#endif /* CONFIG_PM_SLEEP */ - SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, - NULL) + .prepare = pm_sleep_ptr(hda_codec_pm_prepare), + .complete = pm_sleep_ptr(hda_codec_pm_complete), + .suspend = pm_sleep_ptr(hda_codec_pm_suspend), + .resume = pm_sleep_ptr(hda_codec_pm_resume), + .freeze = pm_sleep_ptr(hda_codec_pm_freeze), + .thaw = pm_sleep_ptr(hda_codec_pm_thaw), + .poweroff = pm_sleep_ptr(hda_codec_pm_suspend), + .restore = pm_sleep_ptr(hda_codec_pm_restore), + RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, NULL) }; /* suspend the codec at shutdown; called from driver's shutdown callback */ @@ -3425,7 +3395,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); -#ifdef CONFIG_PM /** * snd_hda_codec_set_power_save - Configure codec's runtime PM * @codec: codec device to configure @@ -3516,7 +3485,6 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, return 0; } EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); -#endif /* * input MUX helper @@ -4060,12 +4028,10 @@ void snd_hda_bus_reset_codecs(struct hda_bus *bus) /* FIXME: maybe a better way needed for forced reset */ if (current_work() != &codec->jackpoll_work.work) cancel_delayed_work_sync(&codec->jackpoll_work); -#ifdef CONFIG_PM if (hda_codec_is_power_on(codec)) { hda_call_codec_suspend(codec); hda_call_codec_resume(codec); } -#endif } } diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c index cd299d7d84ba..71860e2d6377 100644 --- a/sound/pci/hda/hda_component.c +++ b/sound/pci/hda/hda_component.c @@ -15,35 +15,41 @@ #include "hda_local.h" #ifdef CONFIG_ACPI -void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps, +void hda_component_acpi_device_notify(struct hda_component_parent *parent, acpi_handle handle, u32 event, void *data) { + struct hda_component *comp; int i; - for (i = 0; i < num_comps; i++) { - if (comps[i].dev && comps[i].acpi_notify) - comps[i].acpi_notify(acpi_device_handle(comps[i].adev), event, - comps[i].dev); + mutex_lock(&parent->mutex); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); + if (comp->dev && comp->acpi_notify) + comp->acpi_notify(acpi_device_handle(comp->adev), event, comp->dev); } + mutex_unlock(&parent->mutex); } -EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, "SND_HDA_SCODEC_COMPONENT"); int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, int num_comps, + struct hda_component_parent *parent, acpi_notify_handler handler, void *data) { bool support_notifications = false; struct acpi_device *adev; + struct hda_component *comp; int ret; int i; - adev = comps[0].adev; + adev = parent->comps[0].adev; if (!acpi_device_handle(adev)) return 0; - for (i = 0; i < num_comps; i++) + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); support_notifications = support_notifications || - comps[i].acpi_notifications_supported; + comp->acpi_notifications_supported; + } if (support_notifications) { ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, @@ -58,16 +64,16 @@ int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, return 0; } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT"); void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, + struct hda_component_parent *parent, acpi_notify_handler handler) { struct acpi_device *adev; int ret; - adev = comps[0].adev; + adev = parent->comps[0].adev; if (!acpi_device_handle(adev)) return; @@ -75,27 +81,33 @@ void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, if (ret < 0) codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret); } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT"); #endif /* ifdef CONFIG_ACPI */ -void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, int action) +void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action) { + struct hda_component *comp; int i; - for (i = 0; i < num_comps; i++) { - if (comps[i].dev && comps[i].pre_playback_hook) - comps[i].pre_playback_hook(comps[i].dev, action); + mutex_lock(&parent->mutex); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); + if (comp->dev && comp->pre_playback_hook) + comp->pre_playback_hook(comp->dev, action); } - for (i = 0; i < num_comps; i++) { - if (comps[i].dev && comps[i].playback_hook) - comps[i].playback_hook(comps[i].dev, action); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); + if (comp->dev && comp->playback_hook) + comp->playback_hook(comp->dev, action); } - for (i = 0; i < num_comps; i++) { - if (comps[i].dev && comps[i].post_playback_hook) - comps[i].post_playback_hook(comps[i].dev, action); + for (i = 0; i < ARRAY_SIZE(parent->comps); i++) { + comp = hda_component_from_index(parent, i); + if (comp->dev && comp->post_playback_hook) + comp->post_playback_hook(comp->dev, action); } + mutex_unlock(&parent->mutex); } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, "SND_HDA_SCODEC_COMPONENT"); struct hda_scodec_match { const char *bus; @@ -123,8 +135,24 @@ static int hda_comp_match_dev_name(struct device *dev, void *data) return !strcmp(d + n, tmp); } +int hda_component_manager_bind(struct hda_codec *cdc, + struct hda_component_parent *parent) +{ + int ret; + + /* Init shared and component specific data */ + memset(parent->comps, 0, sizeof(parent->comps)); + + mutex_lock(&parent->mutex); + ret = component_bind_all(hda_codec_dev(cdc), parent); + mutex_unlock(&parent->mutex); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, "SND_HDA_SCODEC_COMPONENT"); + int hda_component_manager_init(struct hda_codec *cdc, - struct hda_component *comps, int count, + struct hda_component_parent *parent, int count, const char *bus, const char *hid, const char *match_str, const struct component_master_ops *ops) @@ -134,6 +162,15 @@ int hda_component_manager_init(struct hda_codec *cdc, struct hda_scodec_match *sm; int ret, i; + if (parent->codec) { + codec_err(cdc, "Component binding already created (SSID: %x)\n", + cdc->core.subsystem_id); + return -EINVAL; + } + parent->codec = cdc; + + mutex_init(&parent->mutex); + for (i = 0; i < count; i++) { sm = devm_kmalloc(dev, sizeof(*sm), GFP_KERNEL); if (!sm) @@ -143,7 +180,6 @@ int hda_component_manager_init(struct hda_codec *cdc, sm->hid = hid; sm->match_str = match_str; sm->index = i; - comps[i].codec = cdc; component_match_add(dev, &match, hda_comp_match_dev_name, sm); } @@ -153,16 +189,23 @@ int hda_component_manager_init(struct hda_codec *cdc, return ret; } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, "SND_HDA_SCODEC_COMPONENT"); -void hda_component_manager_free(struct hda_codec *cdc, +void hda_component_manager_free(struct hda_component_parent *parent, const struct component_master_ops *ops) { - struct device *dev = hda_codec_dev(cdc); + struct device *dev; + + if (!parent->codec) + return; + + dev = hda_codec_dev(parent->codec); component_master_del(dev, ops); + + parent->codec = NULL; } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, "SND_HDA_SCODEC_COMPONENT"); MODULE_DESCRIPTION("HD Audio component binding library"); MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index c80a66691b5d..7ee37154749f 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -11,6 +11,7 @@ #include <linux/acpi.h> #include <linux/component.h> +#include <linux/mutex.h> #include <sound/hda_codec.h> #define HDA_MAX_COMPONENTS 4 @@ -19,7 +20,6 @@ struct hda_component { struct device *dev; char name[HDA_MAX_NAME_SIZE]; - struct hda_codec *codec; struct acpi_device *adev; bool acpi_notifications_supported; void (*acpi_notify)(acpi_handle handle, u32 event, struct device *dev); @@ -28,18 +28,23 @@ struct hda_component { void (*post_playback_hook)(struct device *dev, int action); }; +struct hda_component_parent { + struct mutex mutex; + struct hda_codec *codec; + struct hda_component comps[HDA_MAX_COMPONENTS]; +}; + #ifdef CONFIG_ACPI -void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps, +void hda_component_acpi_device_notify(struct hda_component_parent *parent, acpi_handle handle, u32 event, void *data); int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, int num_comps, + struct hda_component_parent *parent, acpi_notify_handler handler, void *data); void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, + struct hda_component_parent *parent, acpi_notify_handler handler); #else -static inline void hda_component_acpi_device_notify(struct hda_component *comps, - int num_comps, +static inline void hda_component_acpi_device_notify(struct hda_component_parent *parent, acpi_handle handle, u32 event, void *data) @@ -47,8 +52,7 @@ static inline void hda_component_acpi_device_notify(struct hda_component *comps, } static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, - int num_comps, + struct hda_component_parent *parent, acpi_notify_handler handler, void *data) @@ -57,34 +61,43 @@ static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec } static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, - struct hda_component *comps, + struct hda_component_parent *parent, acpi_notify_handler handler) { } #endif /* ifdef CONFIG_ACPI */ -void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, - int action); +void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action); int hda_component_manager_init(struct hda_codec *cdc, - struct hda_component *comps, int count, + struct hda_component_parent *parent, int count, const char *bus, const char *hid, const char *match_str, const struct component_master_ops *ops); -void hda_component_manager_free(struct hda_codec *cdc, +void hda_component_manager_free(struct hda_component_parent *parent, const struct component_master_ops *ops); -static inline int hda_component_manager_bind(struct hda_codec *cdc, - struct hda_component *comps) +int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent); + +static inline struct hda_component *hda_component_from_index(struct hda_component_parent *parent, + int index) { - return component_bind_all(hda_codec_dev(cdc), comps); + if (!parent) + return NULL; + + if (index < 0 || index >= ARRAY_SIZE(parent->comps)) + return NULL; + + return &parent->comps[index]; } static inline void hda_component_manager_unbind(struct hda_codec *cdc, - struct hda_component *comps) + struct hda_component_parent *parent) { - component_unbind_all(hda_codec_dev(cdc), comps); + mutex_lock(&parent->mutex); + component_unbind_all(hda_codec_dev(cdc), parent); + mutex_unlock(&parent->mutex); } #endif /* ifndef __HDA_COMPONENT_H__ */ diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 206306a0eb82..f3330b7e0fcf 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -3,7 +3,7 @@ * * Implementation of primary alsa driver code base for Intel HD Audio. * - * Copyright(c) 2004 Intel Corporation. All rights reserved. + * Copyright(c) 2004 Intel Corporation * * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> * PeiSen Hou <pshou@realtek.com.tw> @@ -275,8 +275,7 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&bus->reg_lock); /* reset SYNC bits */ snd_hdac_stream_sync_trigger(hstr, false, sbits, sync_reg); - if (start) - snd_hdac_stream_timecounter_init(hstr, sbits); + snd_hdac_stream_timecounter_init(hstr, sbits, start); spin_unlock(&bus->reg_lock); return 0; } @@ -463,7 +462,8 @@ static int azx_get_sync_time(ktime_t *device, *device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) / ((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate)); - *system = convert_art_to_tsc(tsc_counter); + system->cycles = tsc_counter; + system->cs_id = CSID_X86_ART; return 0; } @@ -914,7 +914,7 @@ static int azx_send_cmd(struct hdac_bus *bus, unsigned int val) if (chip->disabled) return 0; - if (chip->single_cmd) + if (chip->single_cmd || bus->use_pio_for_commands) return azx_single_send_cmd(bus, val); else return snd_hdac_bus_send_cmd(bus, val); @@ -928,7 +928,7 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr, if (chip->disabled) return 0; - if (chip->single_cmd) + if (chip->single_cmd || bus->use_pio_for_commands) return azx_single_get_response(bus, addr, res); else return azx_rirb_get_response(bus, addr, res); @@ -1075,11 +1075,9 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) bool active, handled = false; int repeat = 0; /* count for avoiding endless loop */ -#ifdef CONFIG_PM if (azx_has_pm_runtime(chip)) if (!pm_runtime_active(chip->card->dev)) return IRQ_NONE; -#endif spin_lock(&bus->reg_lock); @@ -1188,6 +1186,9 @@ int azx_bus_init(struct azx *chip, const char *model) if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) bus->core.align_bdle_4k = true; + if (chip->driver_caps & AZX_DCAPS_PIO_COMMANDS) + bus->core.use_pio_for_commands = true; + /* enable sync_write flag for stable communication as default */ bus->core.sync_write = 1; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 8556031bcd68..c2d0109866e6 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -45,6 +45,7 @@ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ +#define AZX_DCAPS_PIO_COMMANDS (1 << 31) /* Use PIO instead of CORB for commands */ enum { AZX_SNOOP_TYPE_NONE, diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c deleted file mode 100644 index 463ca06036bf..000000000000 --- a/sound/pci/hda/hda_cs_dsp_ctl.c +++ /dev/null @@ -1,252 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// HDA DSP ALSA Control Driver -// -// Copyright 2022 Cirrus Logic, Inc. -// -// Author: Stefan Binding <sbinding@opensource.cirrus.com> - -#include <linux/module.h> -#include <sound/soc.h> -#include <linux/firmware/cirrus/cs_dsp.h> -#include <linux/firmware/cirrus/wmfw.h> -#include "hda_cs_dsp_ctl.h" - -#define ADSP_MAX_STD_CTRL_SIZE 512 - -struct hda_cs_dsp_coeff_ctl { - struct cs_dsp_coeff_ctl *cs_ctl; - struct snd_card *card; - struct snd_kcontrol *kctl; -}; - -static const char * const hda_cs_dsp_fw_text[HDA_CS_DSP_NUM_FW] = { - [HDA_CS_DSP_FW_SPK_PROT] = "Prot", - [HDA_CS_DSP_FW_SPK_CALI] = "Cali", - [HDA_CS_DSP_FW_SPK_DIAG] = "Diag", - [HDA_CS_DSP_FW_MISC] = "Misc", -}; - -const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW] = { - [HDA_CS_DSP_FW_SPK_PROT] = "spk-prot", - [HDA_CS_DSP_FW_SPK_CALI] = "spk-cali", - [HDA_CS_DSP_FW_SPK_DIAG] = "spk-diag", - [HDA_CS_DSP_FW_MISC] = "misc", -}; -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_fw_ids, SND_HDA_CS_DSP_CONTROLS); - -static int hda_cs_dsp_coeff_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) -{ - struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl); - struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = cs_ctl->len; - - return 0; -} - -static int hda_cs_dsp_coeff_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl); - struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; - char *p = ucontrol->value.bytes.data; - int ret = 0; - - mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, p, cs_ctl->len); - mutex_unlock(&cs_ctl->dsp->pwr_lock); - - return ret; -} - -static int hda_cs_dsp_coeff_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl); - struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; - char *p = ucontrol->value.bytes.data; - int ret; - - mutex_lock(&cs_ctl->dsp->pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, p, cs_ctl->len); - mutex_unlock(&cs_ctl->dsp->pwr_lock); - - return ret; -} - -static unsigned int wmfw_convert_flags(unsigned int in) -{ - unsigned int out, rd, wr, vol; - - rd = SNDRV_CTL_ELEM_ACCESS_READ; - wr = SNDRV_CTL_ELEM_ACCESS_WRITE; - vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE; - - out = 0; - - if (in) { - out |= rd; - if (in & WMFW_CTL_FLAG_WRITEABLE) - out |= wr; - if (in & WMFW_CTL_FLAG_VOLATILE) - out |= vol; - } else { - out |= rd | wr | vol; - } - - return out; -} - -static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char *name) -{ - struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; - struct snd_kcontrol_new kcontrol = {0}; - struct snd_kcontrol *kctl; - int ret = 0; - - if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) { - dev_err(cs_ctl->dsp->dev, "KControl %s: length %zu exceeds maximum %d\n", name, - cs_ctl->len, ADSP_MAX_STD_CTRL_SIZE); - return; - } - - kcontrol.name = name; - kcontrol.info = hda_cs_dsp_coeff_info; - kcontrol.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kcontrol.access = wmfw_convert_flags(cs_ctl->flags); - kcontrol.get = hda_cs_dsp_coeff_get; - kcontrol.put = hda_cs_dsp_coeff_put; - - /* Save ctl inside private_data, ctl is owned by cs_dsp, - * and will be freed when cs_dsp removes the control */ - kctl = snd_ctl_new1(&kcontrol, (void *)ctl); - if (!kctl) - return; - - ret = snd_ctl_add(ctl->card, kctl); - if (ret) { - dev_err(cs_ctl->dsp->dev, "Failed to add KControl %s = %d\n", kcontrol.name, ret); - return; - } - - dev_dbg(cs_ctl->dsp->dev, "Added KControl: %s\n", kcontrol.name); - ctl->kctl = kctl; -} - -static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, - const struct hda_cs_dsp_ctl_info *info) -{ - struct cs_dsp *cs_dsp = cs_ctl->dsp; - char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - struct hda_cs_dsp_coeff_ctl *ctl; - const char *region_name; - int ret; - - region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type); - if (!region_name) { - dev_warn(cs_dsp->dev, "Unknown region type: %d\n", cs_ctl->alg_region.type); - return; - } - - ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %.12s %x", info->device_name, - cs_dsp->name, hda_cs_dsp_fw_text[info->fw_type], cs_ctl->alg_region.alg); - - if (cs_ctl->subname) { - int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; - int skip = 0; - - /* Truncate the subname from the start if it is too long */ - if (cs_ctl->subname_len > avail) - skip = cs_ctl->subname_len - avail; - - snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, - " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip); - } - - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); - if (!ctl) - return; - - ctl->cs_ctl = cs_ctl; - ctl->card = info->card; - cs_ctl->priv = ctl; - - hda_cs_dsp_add_kcontrol(ctl, name); -} - -void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info) -{ - struct cs_dsp_coeff_ctl *cs_ctl; - - /* - * pwr_lock would cause mutex inversion with ALSA control lock compared - * to the get/put functions. - * It is safe to walk the list without holding a mutex because entries - * are persistent and only cs_dsp_power_up() or cs_dsp_remove() can - * change the list. - */ - lockdep_assert_not_held(&dsp->pwr_lock); - - list_for_each_entry(cs_ctl, &dsp->ctl_list, list) { - if (cs_ctl->flags & WMFW_CTL_FLAG_SYS) - continue; - - if (cs_ctl->priv) - continue; - - hda_cs_dsp_control_add(cs_ctl, info); - } -} -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_add_controls, SND_HDA_CS_DSP_CONTROLS); - -void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) -{ - struct hda_cs_dsp_coeff_ctl *ctl = cs_ctl->priv; - - kfree(ctl); -} -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS); - -int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type, - unsigned int alg, const void *buf, size_t len) -{ - struct cs_dsp_coeff_ctl *cs_ctl; - struct hda_cs_dsp_coeff_ctl *ctl; - int ret; - - mutex_lock(&dsp->pwr_lock); - cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg); - ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); - mutex_unlock(&dsp->pwr_lock); - if (ret < 0) - return ret; - - if (ret == 0 || (cs_ctl->flags & WMFW_CTL_FLAG_SYS)) - return 0; - - ctl = cs_ctl->priv; - - snd_ctl_notify(ctl->card, SNDRV_CTL_EVENT_MASK_VALUE, &ctl->kctl->id); - - return 0; -} -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_write_ctl, SND_HDA_CS_DSP_CONTROLS); - -int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type, - unsigned int alg, void *buf, size_t len) -{ - int ret; - - mutex_lock(&dsp->pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len); - mutex_unlock(&dsp->pwr_lock); - - return ret; - -} -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, SND_HDA_CS_DSP_CONTROLS); - -MODULE_DESCRIPTION("CS_DSP ALSA Control HDA Library"); -MODULE_AUTHOR("Stefan Binding, <sbinding@opensource.cirrus.com>"); -MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(FW_CS_DSP); diff --git a/sound/pci/hda/hda_cs_dsp_ctl.h b/sound/pci/hda/hda_cs_dsp_ctl.h deleted file mode 100644 index 2cf93359c4f2..000000000000 --- a/sound/pci/hda/hda_cs_dsp_ctl.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * - * HDA DSP ALSA Control Driver - * - * Copyright 2022 Cirrus Logic, Inc. - * - * Author: Stefan Binding <sbinding@opensource.cirrus.com> - */ - -#ifndef __HDA_CS_DSP_CTL_H__ -#define __HDA_CS_DSP_CTL_H__ - -#include <sound/soc.h> -#include <linux/firmware/cirrus/cs_dsp.h> - -enum hda_cs_dsp_fw_id { - HDA_CS_DSP_FW_SPK_PROT, - HDA_CS_DSP_FW_SPK_CALI, - HDA_CS_DSP_FW_SPK_DIAG, - HDA_CS_DSP_FW_MISC, - HDA_CS_DSP_NUM_FW -}; - -struct hda_cs_dsp_ctl_info { - struct snd_card *card; - enum hda_cs_dsp_fw_id fw_type; - const char *device_name; -}; - -extern const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW]; - -void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info); -void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl); -int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type, - unsigned int alg, const void *buf, size_t len); -int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type, - unsigned int alg, void *buf, size_t len); - -#endif /*__HDA_CS_DSP_CTL_H__*/ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 1d108ed5c6f2..d3e87b9c1a4f 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -12,16 +12,11 @@ #include <linux/init.h> #include <linux/slab.h> #include <sound/core.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <sound/hda_chmap.h> #include <sound/hda_codec.h> #include "hda_local.h" -enum eld_versions { - ELD_VER_CEA_861D = 2, - ELD_VER_PARTIAL = 31, -}; - enum cea_edid_versions { CEA_EDID_VER_NONE = 0, CEA_EDID_VER_CEA861 = 1, @@ -30,95 +25,12 @@ enum cea_edid_versions { CEA_EDID_VER_RESERVED = 4, }; -static const char * const eld_connection_type_names[4] = { - "HDMI", - "DisplayPort", - "2-reserved", - "3-reserved" -}; - -enum cea_audio_coding_types { - AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, - AUDIO_CODING_TYPE_LPCM = 1, - AUDIO_CODING_TYPE_AC3 = 2, - AUDIO_CODING_TYPE_MPEG1 = 3, - AUDIO_CODING_TYPE_MP3 = 4, - AUDIO_CODING_TYPE_MPEG2 = 5, - AUDIO_CODING_TYPE_AACLC = 6, - AUDIO_CODING_TYPE_DTS = 7, - AUDIO_CODING_TYPE_ATRAC = 8, - AUDIO_CODING_TYPE_SACD = 9, - AUDIO_CODING_TYPE_EAC3 = 10, - AUDIO_CODING_TYPE_DTS_HD = 11, - AUDIO_CODING_TYPE_MLP = 12, - AUDIO_CODING_TYPE_DST = 13, - AUDIO_CODING_TYPE_WMAPRO = 14, - AUDIO_CODING_TYPE_REF_CXT = 15, - /* also include valid xtypes below */ - AUDIO_CODING_TYPE_HE_AAC = 15, - AUDIO_CODING_TYPE_HE_AAC2 = 16, - AUDIO_CODING_TYPE_MPEG_SURROUND = 17, -}; - -enum cea_audio_coding_xtypes { - AUDIO_CODING_XTYPE_HE_REF_CT = 0, - AUDIO_CODING_XTYPE_HE_AAC = 1, - AUDIO_CODING_XTYPE_HE_AAC2 = 2, - AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, - AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, -}; - -static const char * const cea_audio_coding_type_names[] = { - /* 0 */ "undefined", - /* 1 */ "LPCM", - /* 2 */ "AC-3", - /* 3 */ "MPEG1", - /* 4 */ "MP3", - /* 5 */ "MPEG2", - /* 6 */ "AAC-LC", - /* 7 */ "DTS", - /* 8 */ "ATRAC", - /* 9 */ "DSD (One Bit Audio)", - /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", - /* 11 */ "DTS-HD", - /* 12 */ "MLP (Dolby TrueHD)", - /* 13 */ "DST", - /* 14 */ "WMAPro", - /* 15 */ "HE-AAC", - /* 16 */ "HE-AACv2", - /* 17 */ "MPEG Surround", -}; - /* * The following two lists are shared between * - HDMI audio InfoFrame (source to sink) * - CEA E-EDID Extension (sink to source) */ -/* - * SS1:SS0 index => sample size - */ -static const int cea_sample_sizes[4] = { - 0, /* 0: Refer to Stream Header */ - AC_SUPPCM_BITS_16, /* 1: 16 bits */ - AC_SUPPCM_BITS_20, /* 2: 20 bits */ - AC_SUPPCM_BITS_24, /* 3: 24 bits */ -}; - -/* - * SF2:SF1:SF0 index => sampling frequency - */ -static const int cea_sampling_frequencies[8] = { - 0, /* 0: Refer to Stream Header */ - SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ - SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ - SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ - SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ - SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ - SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ - SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ -}; - static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, int byte_index) { @@ -132,159 +44,6 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, return val; } -#define GRAB_BITS(buf, byte, lowbit, bits) \ -({ \ - BUILD_BUG_ON(lowbit > 7); \ - BUILD_BUG_ON(bits > 8); \ - BUILD_BUG_ON(bits <= 0); \ - \ - (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ -}) - -static void hdmi_update_short_audio_desc(struct hda_codec *codec, - struct cea_sad *a, - const unsigned char *buf) -{ - int i; - int val; - - val = GRAB_BITS(buf, 1, 0, 7); - a->rates = 0; - for (i = 0; i < 7; i++) - if (val & (1 << i)) - a->rates |= cea_sampling_frequencies[i + 1]; - - a->channels = GRAB_BITS(buf, 0, 0, 3); - a->channels++; - - a->sample_bits = 0; - a->max_bitrate = 0; - - a->format = GRAB_BITS(buf, 0, 3, 4); - switch (a->format) { - case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - codec_info(codec, "HDMI: audio coding type 0 not expected\n"); - break; - - case AUDIO_CODING_TYPE_LPCM: - val = GRAB_BITS(buf, 2, 0, 3); - for (i = 0; i < 3; i++) - if (val & (1 << i)) - a->sample_bits |= cea_sample_sizes[i + 1]; - break; - - case AUDIO_CODING_TYPE_AC3: - case AUDIO_CODING_TYPE_MPEG1: - case AUDIO_CODING_TYPE_MP3: - case AUDIO_CODING_TYPE_MPEG2: - case AUDIO_CODING_TYPE_AACLC: - case AUDIO_CODING_TYPE_DTS: - case AUDIO_CODING_TYPE_ATRAC: - a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); - a->max_bitrate *= 8000; - break; - - case AUDIO_CODING_TYPE_SACD: - break; - - case AUDIO_CODING_TYPE_EAC3: - break; - - case AUDIO_CODING_TYPE_DTS_HD: - break; - - case AUDIO_CODING_TYPE_MLP: - break; - - case AUDIO_CODING_TYPE_DST: - break; - - case AUDIO_CODING_TYPE_WMAPRO: - a->profile = GRAB_BITS(buf, 2, 0, 3); - break; - - case AUDIO_CODING_TYPE_REF_CXT: - a->format = GRAB_BITS(buf, 2, 3, 5); - if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || - a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - codec_info(codec, - "HDMI: audio coding xtype %d not expected\n", - a->format); - a->format = 0; - } else - a->format += AUDIO_CODING_TYPE_HE_AAC - - AUDIO_CODING_XTYPE_HE_AAC; - break; - } -} - -/* - * Be careful, ELD buf could be totally rubbish! - */ -int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, - const unsigned char *buf, int size) -{ - int mnl; - int i; - - memset(e, 0, sizeof(*e)); - e->eld_ver = GRAB_BITS(buf, 0, 3, 5); - if (e->eld_ver != ELD_VER_CEA_861D && - e->eld_ver != ELD_VER_PARTIAL) { - codec_info(codec, "HDMI: Unknown ELD version %d\n", e->eld_ver); - goto out_fail; - } - - e->baseline_len = GRAB_BITS(buf, 2, 0, 8); - mnl = GRAB_BITS(buf, 4, 0, 5); - e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); - - e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); - e->support_ai = GRAB_BITS(buf, 5, 1, 1); - e->conn_type = GRAB_BITS(buf, 5, 2, 2); - e->sad_count = GRAB_BITS(buf, 5, 4, 4); - - e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; - e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); - - e->port_id = get_unaligned_le64(buf + 8); - - /* not specified, but the spec's tendency is little endian */ - e->manufacture_id = get_unaligned_le16(buf + 16); - e->product_id = get_unaligned_le16(buf + 18); - - if (mnl > ELD_MAX_MNL) { - codec_info(codec, "HDMI: MNL is reserved value %d\n", mnl); - goto out_fail; - } else if (ELD_FIXED_BYTES + mnl > size) { - codec_info(codec, "HDMI: out of range MNL %d\n", mnl); - goto out_fail; - } else - strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); - - for (i = 0; i < e->sad_count; i++) { - if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - codec_info(codec, "HDMI: out of range SAD %d\n", i); - goto out_fail; - } - hdmi_update_short_audio_desc(codec, e->sad + i, - buf + ELD_FIXED_BYTES + mnl + 3 * i); - } - - /* - * HDMI sink's ELD info cannot always be retrieved for now, e.g. - * in console or for audio devices. Assume the highest speakers - * configuration, to _not_ prohibit multi-channel audio playback. - */ - if (!e->spk_alloc) - e->spk_alloc = 0xffff; - - return 0; - -out_fail: - return -EINVAL; -} - int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, @@ -346,155 +105,27 @@ error: return ret; } -/* - * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with - * hdmi-specific routine. - */ -static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) -{ - static const unsigned int alsa_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, - 88200, 96000, 176400, 192000, 384000 - }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++) - if (pcm & (1 << i)) - j += scnprintf(buf + j, buflen - j, " %d", - alsa_rates[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} - -#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 - -static void hdmi_show_short_audio_desc(struct hda_codec *codec, - struct cea_sad *a) -{ - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; - char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; - - if (!a->format) - return; - - hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); - - if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); - else if (a->max_bitrate) - snprintf(buf2, sizeof(buf2), - ", max bitrate = %d", a->max_bitrate); - else - buf2[0] = '\0'; - - codec_dbg(codec, - "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", - cea_audio_coding_type_names[a->format], - a->channels, buf, buf2); -} - -void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) -{ - int i; - - codec_dbg(codec, "HDMI: detected monitor %s at connection type %s\n", - e->monitor_name, - eld_connection_type_names[e->conn_type]); - - if (e->spk_alloc) { - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - codec_dbg(codec, "HDMI: available speakers:%s\n", buf); - } - - for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(codec, e->sad + i); -} - #ifdef CONFIG_SND_PROC_FS - -static void hdmi_print_sad_info(int i, struct cea_sad *a, - struct snd_info_buffer *buffer) -{ - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; - - snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", - i, a->format, cea_audio_coding_type_names[a->format]); - snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); - - hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); - - if (a->format == AUDIO_CODING_TYPE_LPCM) { - snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", - i, a->sample_bits, buf); - } - - if (a->max_bitrate) - snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", - i, a->max_bitrate); - - if (a->profile) - snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); -} - void snd_hdmi_print_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer, hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid) { - struct parsed_hdmi_eld *e = &eld->info; - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - int i; - static const char * const eld_version_names[32] = { - "reserved", - "reserved", - "CEA-861D or below", - [3 ... 30] = "reserved", - [31] = "partial" - }; - static const char * const cea_edid_version_names[8] = { - "no CEA EDID Timing Extension block present", - "CEA-861", - "CEA-861-A", - "CEA-861-B, C or D", - [4 ... 7] = "reserved" - }; - snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present); snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid); snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid); snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id); snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid); + if (!eld->eld_valid) return; - snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); - snd_iprintf(buffer, "connection_type\t\t%s\n", - eld_connection_type_names[e->conn_type]); - snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, - eld_version_names[e->eld_ver]); - snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, - cea_edid_version_names[e->cea_edid_ver]); - snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); - snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); - snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); - snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); - snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); - snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); - - snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); - - snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); - - for (i = 0; i < e->sad_count; i++) - hdmi_print_sad_info(i, e->sad + i, buffer); + + snd_print_eld_info(&eld->info, buffer); } void snd_hdmi_write_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer) { - struct parsed_hdmi_eld *e = &eld->info; + struct snd_parsed_hdmi_eld *e = &eld->info; char line[64]; char name[64]; char *sname; @@ -556,7 +187,7 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld, #endif /* CONFIG_SND_PROC_FS */ /* update PCM info based on ELD */ -void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, +void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo) { u32 rates; @@ -574,17 +205,17 @@ void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, maxbps = 16; channels_max = 2; for (i = 0; i < e->sad_count; i++) { - struct cea_sad *a = &e->sad[i]; + struct snd_cea_sad *a = &e->sad[i]; rates |= a->rates; if (a->channels > channels_max) channels_max = a->channels; if (a->format == AUDIO_CODING_TYPE_LPCM) { - if (a->sample_bits & AC_SUPPCM_BITS_20) { + if (a->sample_bits & ELD_PCM_BITS_20) { formats |= SNDRV_PCM_FMTBIT_S32_LE; if (maxbps < 20) maxbps = 20; } - if (a->sample_bits & AC_SUPPCM_BITS_24) { + if (a->sample_bits & ELD_PCM_BITS_24) { formats |= SNDRV_PCM_FMTBIT_S32_LE; if (maxbps < 24) maxbps = 24; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index de2a3d08c73c..b34d84fedcc8 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1383,7 +1383,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs, struct nid_path *path; hda_nid_t pin = pins[i]; - if (!spec->obey_preferred_dacs) { + if (!spec->preferred_dacs) { path = snd_hda_get_path_from_idx(codec, path_idx[i]); if (path) { badness += assign_out_path_ctls(codec, path); @@ -1395,7 +1395,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs, if (dacs[i]) { if (is_dac_already_used(codec, dacs[i])) badness += bad->shared_primary; - } else if (spec->obey_preferred_dacs) { + } else if (spec->preferred_dacs) { badness += BAD_NO_PRIMARY_DAC; } @@ -4955,6 +4955,69 @@ void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on) } EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm); +/* forcibly mute the speaker output without caching; return true if updated */ +static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid) +{ + if (!nid) + return false; + if (!nid_has_mute(codec, nid, HDA_OUTPUT)) + return false; /* no mute, skip */ + if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & + snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) & + HDA_AMP_MUTE) + return false; /* both channels already muted, skip */ + + /* direct amp update without caching */ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT | + AC_AMP_SET_RIGHT | HDA_AMP_MUTE); + return true; +} + +/** + * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs + * @codec: the HDA codec + * + * Forcibly mute the speaker outputs, to be called at suspend or shutdown. + * + * The mute state done by this function isn't cached, hence the original state + * will be restored at resume. + * + * Return true if the mute state has been changed. + */ +bool snd_hda_gen_shutup_speakers(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + const int *paths; + const struct nid_path *path; + int i, p, num_paths; + bool updated = false; + + /* if already powered off, do nothing */ + if (!snd_hdac_is_power_on(&codec->core)) + return false; + + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) { + paths = spec->out_paths; + num_paths = spec->autocfg.line_outs; + } else { + paths = spec->speaker_paths; + num_paths = spec->autocfg.speaker_outs; + } + + for (i = 0; i < num_paths; i++) { + path = snd_hda_get_path_from_idx(codec, paths[i]); + if (!path) + continue; + for (p = 0; p < path->depth; p++) + if (force_mute_output_path(codec, path->path[p])) + updated = true; + } + + return updated; +} +EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers); + /** * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and * set up the hda_gen_spec @@ -6021,7 +6084,6 @@ void snd_hda_gen_free(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_gen_free); -#ifdef CONFIG_PM /** * snd_hda_gen_check_power_status - check the loopback power save state * @codec: the HDA codec @@ -6035,7 +6097,6 @@ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); } EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status); -#endif /* @@ -6048,9 +6109,7 @@ static const struct hda_codec_ops generic_patch_ops = { .init = snd_hda_gen_init, .free = snd_hda_gen_free, .unsol_event = snd_hda_jack_unsol_event, -#ifdef CONFIG_PM .check_power_status = snd_hda_gen_check_power_status, -#endif }; /* diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index a8eea8367629..9612afaa61c2 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -232,7 +232,6 @@ struct hda_gen_spec { unsigned int power_down_unused:1; /* power down unused widgets */ unsigned int dac_min_mute:1; /* minimal = mute for DACs */ unsigned int suppress_vmaster:1; /* don't create vmaster kctls */ - unsigned int obey_preferred_dacs:1; /* obey preferred_dacs assignment */ /* other internal flags */ unsigned int no_analog:1; /* digital I/O only */ @@ -340,9 +339,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_callback *jack); void snd_hda_gen_update_outputs(struct hda_codec *codec); -#ifdef CONFIG_PM int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid); -#endif unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, hda_nid_t nid, unsigned int power_state); @@ -355,5 +352,6 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec, int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, int (*callback)(struct led_classdev *, enum led_brightness)); +bool snd_hda_gen_shutup_speakers(struct hda_codec *codec); #endif /* __SOUND_HDA_GENERIC_H */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 727f39acedfc..9325e5c3cbe6 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -84,10 +84,8 @@ static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) { -#ifndef CONFIG_SND_DEBUG_VERBOSE if (!capable(CAP_SYS_RAWIO)) return -EACCES; -#endif return 0; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1b550c42db09..439cf1bda6e6 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -4,7 +4,7 @@ * hda_intel.c - Implementation of primary alsa driver code base * for Intel HD Audio. * - * Copyright(c) 2004 Intel Corporation. All rights reserved. + * Copyright(c) 2004 Intel Corporation * * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> * PeiSen Hou <pshou@realtek.com.tw> @@ -37,6 +37,7 @@ #include <linux/completion.h> #include <linux/acpi.h> #include <linux/pgtable.h> +#include <linux/dmi.h> #ifdef CONFIG_X86 /* for snoop control */ @@ -175,8 +176,8 @@ module_param(power_save, xint, 0644); MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " "(in second, 0 = disable)."); -static bool pm_blacklist = true; -module_param(pm_blacklist, bool, 0644); +static int pm_blacklist = -1; +module_param(pm_blacklist, bint, 0644); MODULE_PARM_DESC(pm_blacklist, "Enable power-management denylist"); /* reset the HD-audio controller in power save mode. @@ -186,8 +187,10 @@ MODULE_PARM_DESC(pm_blacklist, "Enable power-management denylist"); static bool power_save_controller = 1; module_param(power_save_controller, bool, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); -#else +#else /* CONFIG_PM */ #define power_save 0 +#define pm_blacklist 0 +#define power_save_controller false #endif /* CONFIG_PM */ static int align_buffer_size = -1; @@ -237,6 +240,7 @@ enum { AZX_DRIVER_CTHDA, AZX_DRIVER_CMEDIA, AZX_DRIVER_ZHAOXIN, + AZX_DRIVER_ZHAOXINHDMI, AZX_DRIVER_LOONGSON, AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ @@ -289,6 +293,9 @@ enum { #define AZX_DCAPS_INTEL_BROXTON AZX_DCAPS_INTEL_SKYLAKE +#define AZX_DCAPS_INTEL_LNL \ + (AZX_DCAPS_INTEL_SKYLAKE | AZX_DCAPS_PIO_COMMANDS) + /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB |\ @@ -349,6 +356,7 @@ static const char * const driver_short_names[] = { [AZX_DRIVER_CTHDA] = "HDA Creative", [AZX_DRIVER_CMEDIA] = "HDA C-Media", [AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin", + [AZX_DRIVER_ZHAOXINHDMI] = "HDA Zhaoxin HDMI", [AZX_DRIVER_LOONGSON] = "HDA Loongson", [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; @@ -768,6 +776,14 @@ static void azx_clear_irq_pending(struct azx *chip) static int azx_acquire_irq(struct azx *chip, int do_disconnect) { struct hdac_bus *bus = azx_bus(chip); + int ret; + + if (!chip->msi || pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_MSI) < 0) { + ret = pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_INTX); + if (ret < 0) + return ret; + chip->msi = 0; + } if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, @@ -781,7 +797,6 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) } bus->irq = chip->pci->irq; chip->card->sync_irq = bus->irq; - pci_intx(chip->pci, !chip->msi); return 0; } @@ -890,7 +905,6 @@ static void __azx_shutdown_chip(struct azx *chip, bool skip_link_reset) display_power(chip, false); } -#ifdef CONFIG_PM static DEFINE_MUTEX(card_list_lock); static LIST_HEAD(card_list); @@ -916,7 +930,7 @@ static void azx_del_card_list(struct azx *chip) } /* trigger power-save check at writing parameter */ -static int param_set_xint(const char *val, const struct kernel_param *kp) +static int __maybe_unused param_set_xint(const char *val, const struct kernel_param *kp) { struct hda_intel *hda; struct azx *chip; @@ -926,10 +940,14 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) if (ret || prev == power_save) return ret; + if (pm_blacklist > 0) + return 0; + mutex_lock(&card_list_lock); list_for_each_entry(hda, &card_list, list) { chip = &hda->chip; - if (!hda->probe_continued || chip->disabled) + if (!hda->probe_continued || chip->disabled || + hda->runtime_pm_disabled) continue; snd_hda_set_power_save(&chip->bus, power_save * 1000); } @@ -987,7 +1005,6 @@ static void __azx_runtime_resume(struct azx *chip) display_power(chip, false); } -#ifdef CONFIG_PM_SLEEP static int azx_prepare(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -1025,22 +1042,12 @@ static int azx_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hdac_bus *bus; if (!azx_is_pm_ready(card)) return 0; chip = card->private_data; - bus = azx_bus(chip); azx_shutdown_chip(chip); - if (bus->irq >= 0) { - free_irq(bus->irq, chip); - bus->irq = -1; - chip->card->sync_irq = -1; - } - - if (chip->msi) - pci_disable_msi(chip->pci); trace_azx_suspend(chip); return 0; @@ -1055,11 +1062,6 @@ static int azx_resume(struct device *dev) return 0; chip = card->private_data; - if (chip->msi) - if (pci_enable_msi(chip->pci) < 0) - chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) - return -EIO; __azx_runtime_resume(chip); @@ -1097,7 +1099,6 @@ static int azx_thaw_noirq(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ static int azx_runtime_suspend(struct device *dev) { @@ -1159,23 +1160,14 @@ static int azx_runtime_idle(struct device *dev) } static const struct dev_pm_ops azx_pm = { - SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume) -#ifdef CONFIG_PM_SLEEP - .prepare = azx_prepare, - .complete = azx_complete, - .freeze_noirq = azx_freeze_noirq, - .thaw_noirq = azx_thaw_noirq, -#endif - SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) + SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume) + .prepare = pm_sleep_ptr(azx_prepare), + .complete = pm_sleep_ptr(azx_complete), + .freeze_noirq = pm_sleep_ptr(azx_freeze_noirq), + .thaw_noirq = pm_sleep_ptr(azx_thaw_noirq), + RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) }; -#define AZX_PM_OPS &azx_pm -#else -#define azx_add_card_list(chip) /* NOP */ -#define azx_del_card_list(chip) /* NOP */ -#define AZX_PM_OPS NULL -#endif /* CONFIG_PM */ - static int azx_probe_continue(struct azx *chip); @@ -1363,8 +1355,21 @@ static void azx_free(struct azx *chip) if (use_vga_switcheroo(hda)) { if (chip->disabled && hda->probe_continued) snd_hda_unlock_devices(&chip->bus); - if (hda->vga_switcheroo_registered) + if (hda->vga_switcheroo_registered) { vga_switcheroo_unregister_client(chip->pci); + + /* Some GPUs don't have sound, and azx_first_init fails, + * leaving the device probed but non-functional. As long + * as it's probed, the PCI subsystem keeps its runtime + * PM status as active. Force it to suspended (as we + * actually stop the chip) to allow GPU to suspend via + * vga_switcheroo, and print a warning. + */ + dev_warn(&pci->dev, "GPU sound probed, but not operational: please add a quirk to driver_denylist\n"); + pm_runtime_disable(&pci->dev); + pm_runtime_set_suspended(&pci->dev); + pm_runtime_enable(&pci->dev); + } } if (bus->chip_init) { @@ -1747,6 +1752,8 @@ static int default_bdl_pos_adj(struct azx *chip) case AZX_DRIVER_ICH: case AZX_DRIVER_PCH: return 1; + case AZX_DRIVER_ZHAOXINHDMI: + return 128; default: return 32; } @@ -1816,7 +1823,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, /* use the non-cached pages in non-snoop mode */ if (!azx_snoop(chip)) - azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_WC_SG; + azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_WC; if (chip->driver_type == AZX_DRIVER_NVIDIA) { dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); @@ -1870,14 +1877,18 @@ static int azx_first_init(struct azx *chip) bus->polling_mode = 1; bus->not_use_interrupts = 1; bus->access_sdnctl_in_dword = 1; + if (!chip->jackpoll_interval) + chip->jackpoll_interval = msecs_to_jiffies(1500); } - err = pcim_iomap_regions(pci, 1 << 0, "ICH HD audio"); - if (err < 0) - return err; + if (chip->driver_type == AZX_DRIVER_ZHAOXINHDMI) + bus->polling_mode = 1; + + bus->remap_addr = pcim_iomap_region(pci, 0, "ICH HD audio"); + if (IS_ERR(bus->remap_addr)) + return PTR_ERR(bus->remap_addr); bus->addr = pci_resource_start(pci, 0); - bus->remap_addr = pcim_iomap_table(pci)[0]; if (chip->driver_type == AZX_DRIVER_SKL) snd_hdac_bus_parse_capabilities(bus); @@ -1895,13 +1906,9 @@ static int azx_first_init(struct azx *chip) chip->gts_present = true; #endif - if (chip->msi) { - if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { - dev_dbg(card->dev, "Disabling 64bit MSI\n"); - pci->no_64bit_msi = true; - } - if (pci_enable_msi(pci) < 0) - chip->msi = 0; + if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) { + dev_dbg(card->dev, "Disabling 64bit MSI\n"); + pci->no_64bit_msi = true; } pci_set_master(pci); @@ -1973,6 +1980,7 @@ static int azx_first_init(struct azx *chip) chip->capture_streams = ATIHDMI_NUM_CAPTURE; break; case AZX_DRIVER_GFHDMI: + case AZX_DRIVER_ZHAOXINHDMI: case AZX_DRIVER_GENERIC: default: chip->playback_streams = ICH6_NUM_PLAYBACK; @@ -2053,7 +2061,7 @@ static int disable_msi_reset_irq(struct azx *chip) free_irq(bus->irq, chip); bus->irq = -1; chip->card->sync_irq = -1; - pci_disable_msi(chip->pci); + pci_free_irq_vectors(chip->pci); chip->msi = 0; err = azx_acquire_irq(chip, 1); if (err < 0) @@ -2074,6 +2082,27 @@ static const struct pci_device_id driver_denylist[] = { {} }; +static struct pci_device_id driver_denylist_ideapad_z570[] = { + { PCI_DEVICE_SUB(0x10de, 0x0bea, 0x0000, 0x0000) }, /* NVIDIA GF108 HDA */ + {} +}; + +/* DMI-based denylist, to be used when: + * - PCI subsystem IDs are zero, impossible to distinguish from valid sound cards. + * - Different modifications of the same laptop use different GPU models. + */ +static const struct dmi_system_id driver_denylist_dmi[] = { + { + /* No HDA in NVIDIA DGPU. BIOS disables it, but quirk_nvidia_hda() reenables. */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"), + }, + .driver_data = &driver_denylist_ideapad_z570, + }, + {} +}; + static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, .position_check = azx_position_check, @@ -2084,6 +2113,7 @@ static DECLARE_BITMAP(probed_devs, SNDRV_CARDS); static int azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { + const struct dmi_system_id *dmi; struct snd_card *card; struct hda_intel *hda; struct azx *chip; @@ -2096,6 +2126,12 @@ static int azx_probe(struct pci_dev *pci, return -ENODEV; } + dmi = dmi_first_match(driver_denylist_dmi); + if (dmi && pci_match_id(dmi->driver_data, pci)) { + dev_info(&pci->dev, "Skipping the device on the DMI denylist\n"); + return -ENODEV; + } + dev = find_first_zero_bit(probed_devs, SNDRV_CARDS); if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2206,7 +2242,6 @@ out_free: return err; } -#ifdef CONFIG_PM /* On some boards setting power_save to a non 0 value leads to clicking / * popping sounds when ever we enter/leave powersaving mode. Ideally we would * figure out how to avoid these sounds, but that is not always feasible. @@ -2246,16 +2281,19 @@ static const struct snd_pci_quirk power_save_denylist[] = { SND_PCI_QUIRK(0x1631, 0xe017, "Packard Bell NEC IMEDIA 5204", 0), /* KONTRON SinglePC may cause a stall at runtime resume */ SND_PCI_QUIRK(0x1734, 0x1232, "KONTRON SinglePC", 0), + /* Dell ALC3271 */ + SND_PCI_QUIRK(0x1028, 0x0962, "Dell ALC3271", 0), + /* https://bugzilla.kernel.org/show_bug.cgi?id=220210 */ + SND_PCI_QUIRK(0x17aa, 0x5079, "Lenovo Thinkpad E15", 0), {} }; -#endif /* CONFIG_PM */ static void set_default_power_save(struct azx *chip) { + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); int val = power_save; -#ifdef CONFIG_PM - if (pm_blacklist) { + if (pm_blacklist < 0) { const struct snd_pci_quirk *q; q = snd_pci_quirk_lookup(chip->pci, power_save_denylist); @@ -2263,9 +2301,12 @@ static void set_default_power_save(struct azx *chip) dev_info(chip->card->dev, "device %04x:%04x is on the power_save denylist, forcing power_save to 0\n", q->subvendor, q->subdevice); val = 0; + hda->runtime_pm_disabled = 1; } + } else if (pm_blacklist > 0) { + dev_info(chip->card->dev, "Forcing power_save to 0 via option\n"); + val = 0; } -#endif /* CONFIG_PM */ snd_hda_set_power_save(&chip->bus, val * 1000); } @@ -2321,10 +2362,6 @@ static int azx_probe_continue(struct azx *chip) chip->fw->data); if (err < 0) goto out_free; -#ifndef CONFIG_PM - release_firmware(chip->fw); /* no longer needed */ - chip->fw = NULL; -#endif } #endif @@ -2502,12 +2539,20 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, { PCI_DEVICE_DATA(INTEL, HDA_MTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Battlemage */ + { PCI_DEVICE_DATA(INTEL, HDA_BMG, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Lunarlake-P */ - { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) }, /* Arrow Lake-S */ { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, /* Arrow Lake */ { PCI_DEVICE_DATA(INTEL, HDA_ARL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + /* Panther Lake */ + { PCI_DEVICE_DATA(INTEL, HDA_PTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) }, + /* Panther Lake-H */ + { PCI_DEVICE_DATA(INTEL, HDA_PTL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) }, + /* Wildcat Lake */ + { PCI_DEVICE_DATA(INTEL, HDA_WCL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) }, /* Apollolake (Broxton-P) */ { PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) }, /* Gemini-Lake */ @@ -2681,8 +2726,11 @@ static const struct pci_device_id azx_ids[] = { { PCI_VDEVICE(ATI, 0xab38), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, + { PCI_VDEVICE(ATI, 0xab40), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, /* GLENFLY */ - { PCI_DEVICE(0x6766, PCI_ANY_ID), + { PCI_DEVICE(PCI_VENDOR_ID_GLENFLY, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_GFHDMI | AZX_DCAPS_POSFIX_LPIB | @@ -2748,11 +2796,26 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI }, /* Zhaoxin */ { PCI_VDEVICE(ZHAOXIN, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN }, + { PCI_VDEVICE(ZHAOXIN, 0x9141), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(ZHAOXIN, 0x9142), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(ZHAOXIN, 0x9144), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(ZHAOXIN, 0x9145), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(ZHAOXIN, 0x9146), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, /* Loongson HDAudio*/ { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA), - .driver_data = AZX_DRIVER_LOONGSON }, + .driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL }, { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI), - .driver_data = AZX_DRIVER_LOONGSON }, + .driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); @@ -2765,7 +2828,7 @@ static struct pci_driver azx_driver = { .remove = azx_remove, .shutdown = azx_shutdown, .driver = { - .pm = AZX_PM_OPS, + .pm = pm_ptr(&azx_pm), }, }; diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 0f39418f9328..2d1725f86ef1 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -22,6 +22,7 @@ struct hda_intel { /* extra flags */ unsigned int irq_pending_warned:1; unsigned int probe_continued:1; + unsigned int runtime_pm_disabled:1; /* vga_switcheroo setup */ unsigned int use_vga_switcheroo:1; diff --git a/sound/pci/hda/hda_intel_trace.h b/sound/pci/hda/hda_intel_trace.h index 73a7adfa192d..2775fa81a500 100644 --- a/sound/pci/hda/hda_intel_trace.h +++ b/sound/pci/hda/hda_intel_trace.h @@ -34,7 +34,6 @@ DEFINE_EVENT(hda_pm, azx_resume, TP_ARGS(chip) ); -#ifdef CONFIG_PM DEFINE_EVENT(hda_pm, azx_runtime_suspend, TP_PROTO(struct azx *chip), TP_ARGS(chip) @@ -44,7 +43,6 @@ DEFINE_EVENT(hda_pm, azx_runtime_resume, TP_PROTO(struct azx *chip), TP_ARGS(chip) ); -#endif #endif /* _TRACE_HDA_INTEL_H */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 53a5a62b78fa..68c31f5354b7 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -10,6 +10,8 @@ #ifndef __SOUND_HDA_LOCAL_H #define __SOUND_HDA_LOCAL_H +#include <sound/pcm_drm_eld.h> + /* We abuse kcontrol_new.subdev field to pass the NID corresponding to * the given new control. If id.subdev has a bit flag HDA_SUBDEV_NID_FLAG, * snd_hda_ctl_add() takes the lower-bit subdev value as a valid NID. @@ -292,6 +294,32 @@ struct hda_fixup { } v; }; +/* + * extended form of snd_pci_quirk: + * for PCI SSID matching, use SND_PCI_QUIRK() like before; + * for codec SSID matching, use the new HDA_CODEC_QUIRK() instead + */ +struct hda_quirk { + unsigned short subvendor; /* PCI subvendor ID */ + unsigned short subdevice; /* PCI subdevice ID */ + unsigned short subdevice_mask; /* bitmask to match */ + bool match_codec_ssid; /* match only with codec SSID */ + int value; /* value */ +#ifdef CONFIG_SND_DEBUG_VERBOSE + const char *name; /* name of the device (optional) */ +#endif +}; + +#ifdef CONFIG_SND_DEBUG_VERBOSE +#define HDA_CODEC_QUIRK(vend, dev, xname, val) \ + { _SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname),\ + .match_codec_ssid = true } +#else +#define HDA_CODEC_QUIRK(vend, dev, xname, val) \ + { _SND_PCI_QUIRK_ID(vend, dev), .value = (val), \ + .match_codec_ssid = true } +#endif + struct snd_hda_pin_quirk { unsigned int codec; /* Codec vendor/device ID */ unsigned short subvendor; /* PCI subvendor ID */ @@ -351,7 +379,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action); void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth); void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, + const struct hda_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, @@ -543,8 +571,6 @@ struct hda_nid_item { int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, struct snd_kcontrol *kctl); -int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, - unsigned int index, hda_nid_t nid); void snd_hda_ctls_clear(struct hda_codec *codec); /* @@ -649,61 +675,18 @@ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, #define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \ snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL) -/* - * CEA Short Audio Descriptor data - */ -struct cea_sad { - int channels; - int format; /* (format == 0) indicates invalid SAD */ - int rates; - int sample_bits; /* for LPCM */ - int max_bitrate; /* for AC3...ATRAC */ - int profile; /* for WMAPRO */ -}; - -#define ELD_FIXED_BYTES 20 -#define ELD_MAX_SIZE 256 -#define ELD_MAX_MNL 16 -#define ELD_MAX_SAD 16 - -/* - * ELD: EDID Like Data - */ -struct parsed_hdmi_eld { - /* - * all fields will be cleared before updating ELD - */ - int baseline_len; - int eld_ver; - int cea_edid_ver; - char monitor_name[ELD_MAX_MNL + 1]; - int manufacture_id; - int product_id; - u64 port_id; - int support_hdcp; - int support_ai; - int conn_type; - int aud_synch_delay; - int spk_alloc; - int sad_count; - struct cea_sad sad[ELD_MAX_SAD]; -}; - struct hdmi_eld { bool monitor_present; bool eld_valid; int eld_size; char eld_buffer[ELD_MAX_SIZE]; - struct parsed_hdmi_eld info; + struct snd_parsed_hdmi_eld info; }; int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size); -int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, - const unsigned char *buf, int size); -void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e); -void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, +void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 69ebc37a4d6f..140e24bf4d7f 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -26,7 +26,6 @@ struct hda_hint { const char *val; /* contained in the same alloc as key */ }; -#ifdef CONFIG_PM static ssize_t power_on_acct_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -47,7 +46,6 @@ static ssize_t power_off_acct_show(struct device *dev, static DEVICE_ATTR_RO(power_on_acct); static DEVICE_ATTR_RO(power_off_acct); -#endif /* CONFIG_PM */ #define CODEC_INFO_SHOW(type, field) \ static ssize_t type##_show(struct device *dev, \ @@ -650,7 +648,7 @@ static const struct hda_patch_item patch_items[NUM_LINE_MODES] = { }, }; -/* check the line starting with '[' -- change the parser mode accodingly */ +/* check the line starting with '[' -- change the parser mode accordingly */ static int parse_line_mode(char *buf, struct hda_bus *bus) { int i; @@ -745,10 +743,8 @@ static struct attribute *hda_dev_attrs[] = { &dev_attr_modelname.attr, &dev_attr_init_pin_configs.attr, &dev_attr_driver_pin_configs.attr, -#ifdef CONFIG_PM &dev_attr_power_on_acct.attr, &dev_attr_power_off_acct.attr, -#endif #ifdef CONFIG_SND_HDA_RECONFIG &dev_attr_init_verbs.attr, &dev_attr_hints.attr, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index d967e70a7058..6ab338f37db5 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -72,6 +72,10 @@ struct hda_tegra_soc { bool has_hda2codec_2x_reset; bool has_hda2hdmi; + bool has_hda2codec_2x; + bool input_stream; + bool always_on; + bool requires_init; }; struct hda_tegra { @@ -125,7 +129,7 @@ static void hda_tegra_init(struct hda_tegra *hda) /* * power management */ -static int __maybe_unused hda_tegra_suspend(struct device *dev) +static int hda_tegra_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); int rc; @@ -138,7 +142,7 @@ static int __maybe_unused hda_tegra_suspend(struct device *dev) return 0; } -static int __maybe_unused hda_tegra_resume(struct device *dev) +static int hda_tegra_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); int rc; @@ -151,7 +155,7 @@ static int __maybe_unused hda_tegra_resume(struct device *dev) return 0; } -static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev) +static int hda_tegra_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; @@ -170,7 +174,7 @@ static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused hda_tegra_runtime_resume(struct device *dev) +static int hda_tegra_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; @@ -187,7 +191,9 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev) if (rc != 0) return rc; if (chip->running) { - hda_tegra_init(hda); + if (hda->soc->requires_init) + hda_tegra_init(hda); + azx_init_chip(chip, 1); /* disable controller wake up event*/ azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & @@ -204,10 +210,8 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev) } static const struct dev_pm_ops hda_tegra_pm = { - SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) - SET_RUNTIME_PM_OPS(hda_tegra_runtime_suspend, - hda_tegra_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) + RUNTIME_PM_OPS(hda_tegra_runtime_suspend, hda_tegra_runtime_resume, NULL) }; static int hda_tegra_dev_disconnect(struct snd_device *device) @@ -252,7 +256,8 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) bus->remap_addr = hda->regs + HDA_BAR0; bus->addr = res->start + HDA_BAR0; - hda_tegra_init(hda); + if (hda->soc->requires_init) + hda_tegra_init(hda); return 0; } @@ -325,7 +330,7 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) * starts with offset 0 which is wrong as HW register for output stream * offset starts with 4. */ - if (of_device_is_compatible(np, "nvidia,tegra234-hda")) + if (!hda->soc->input_stream) chip->capture_streams = 4; chip->playback_streams = (gcap >> 12) & 0x0f; @@ -379,14 +384,14 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) } /* driver name */ - strscpy(card->driver, drv_name, sizeof(card->driver)); + strscpy(card->driver, drv_name); /* shortname for card */ sname = of_get_property(np, "nvidia,model", NULL); if (!sname) sname = drv_name; if (strlen(sname) > sizeof(card->shortname)) dev_info(card->dev, "truncating shortname for card\n"); - strscpy(card->shortname, sname, sizeof(card->shortname)); + strscpy(card->shortname, sname); /* longname for card */ snprintf(card->longname, sizeof(card->longname), @@ -421,7 +426,6 @@ static int hda_tegra_create(struct snd_card *card, chip->driver_caps = driver_caps; chip->driver_type = driver_caps & 0xff; chip->dev_index = 0; - chip->jackpoll_interval = msecs_to_jiffies(5000); INIT_LIST_HEAD(&chip->pcm_list); chip->codec_probe_mask = -1; @@ -438,7 +442,16 @@ static int hda_tegra_create(struct snd_card *card, chip->bus.core.sync_write = 0; chip->bus.core.needs_damn_long_delay = 1; chip->bus.core.aligned_mmio = 1; - chip->bus.jackpoll_in_suspend = 1; + + /* + * HDA power domain and clocks are always on for Tegra264 and + * the jack detection logic would work always, so no need of + * jack polling mechanism running. + */ + if (!hda->soc->always_on) { + chip->jackpoll_interval = msecs_to_jiffies(5000); + chip->bus.jackpoll_in_suspend = 1; + } err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { @@ -452,22 +465,44 @@ static int hda_tegra_create(struct snd_card *card, static const struct hda_tegra_soc tegra30_data = { .has_hda2codec_2x_reset = true, .has_hda2hdmi = true, + .has_hda2codec_2x = true, + .input_stream = true, + .always_on = false, + .requires_init = true, }; static const struct hda_tegra_soc tegra194_data = { .has_hda2codec_2x_reset = false, .has_hda2hdmi = true, + .has_hda2codec_2x = true, + .input_stream = true, + .always_on = false, + .requires_init = true, }; static const struct hda_tegra_soc tegra234_data = { .has_hda2codec_2x_reset = true, .has_hda2hdmi = false, + .has_hda2codec_2x = true, + .input_stream = false, + .always_on = false, + .requires_init = true, +}; + +static const struct hda_tegra_soc tegra264_data = { + .has_hda2codec_2x_reset = true, + .has_hda2hdmi = false, + .has_hda2codec_2x = false, + .input_stream = false, + .always_on = true, + .requires_init = false, }; static const struct of_device_id hda_tegra_match[] = { { .compatible = "nvidia,tegra30-hda", .data = &tegra30_data }, { .compatible = "nvidia,tegra194-hda", .data = &tegra194_data }, { .compatible = "nvidia,tegra234-hda", .data = &tegra234_data }, + { .compatible = "nvidia,tegra264-hda", .data = &tegra264_data }, {}, }; MODULE_DEVICE_TABLE(of, hda_tegra_match); @@ -522,7 +557,9 @@ static int hda_tegra_probe(struct platform_device *pdev) hda->clocks[hda->nclocks++].id = "hda"; if (hda->soc->has_hda2hdmi) hda->clocks[hda->nclocks++].id = "hda2hdmi"; - hda->clocks[hda->nclocks++].id = "hda2codec_2x"; + + if (hda->soc->has_hda2codec_2x) + hda->clocks[hda->nclocks++].id = "hda2codec_2x"; err = devm_clk_bulk_get(&pdev->dev, hda->nclocks, hda->clocks); if (err < 0) @@ -602,11 +639,11 @@ static void hda_tegra_shutdown(struct platform_device *pdev) static struct platform_driver tegra_platform_hda = { .driver = { .name = "tegra-hda", - .pm = &hda_tegra_pm, + .pm = pm_ptr(&hda_tegra_pm), .of_match_table = hda_tegra_match, }, .probe = hda_tegra_probe, - .remove_new = hda_tegra_remove, + .remove = hda_tegra_remove, .shutdown = hda_tegra_shutdown, }; module_platform_driver(tegra_platform_hda); diff --git a/sound/pci/hda/ideapad_hotkey_led_helper.c b/sound/pci/hda/ideapad_hotkey_led_helper.c new file mode 100644 index 000000000000..c10d97964d49 --- /dev/null +++ b/sound/pci/hda/ideapad_hotkey_led_helper.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Ideapad helper functions for Lenovo Ideapad LED control, + * It should be included from codec driver. + */ + +#if IS_ENABLED(CONFIG_IDEAPAD_LAPTOP) + +#include <linux/acpi.h> +#include <linux/leds.h> + +static bool is_ideapad(struct hda_codec *codec) +{ + return (codec->core.subsystem_id >> 16 == 0x17aa) && + (acpi_dev_found("LHK2019") || acpi_dev_found("VPC2004")); +} + +static void hda_fixup_ideapad_acpi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + if (!is_ideapad(codec)) + return; + snd_hda_gen_add_mute_led_cdev(codec, NULL); + snd_hda_gen_add_micmute_led_cdev(codec, NULL); + } +} + +#else /* CONFIG_IDEAPAD_LAPTOP */ + +static void hda_fixup_ideapad_acpi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ +} + +#endif /* CONFIG_IDEAPAD_LAPTOP */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 8afe6000f7da..56354fe060a1 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -72,7 +72,6 @@ static int create_beep_ctls(struct hda_codec *codec) #define create_beep_ctls(codec) 0 #endif -#ifdef CONFIG_PM static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, hda_nid_t hp) { @@ -118,7 +117,6 @@ static int ad198x_suspend(struct hda_codec *codec) ad198x_power_eapd(codec); return 0; } -#endif /* follow EAPD via vmaster hook */ static void ad_vmaster_eapd_hook(void *private_data, int enabled) @@ -158,10 +156,8 @@ static const struct hda_codec_ops ad198x_auto_patch_ops = { .init = snd_hda_gen_init, .free = snd_hda_gen_free, .unsol_event = snd_hda_jack_unsol_event, -#ifdef CONFIG_PM .check_power_status = snd_hda_gen_check_power_status, .suspend = ad198x_suspend, -#endif }; @@ -349,7 +345,7 @@ static const struct hda_fixup ad1986a_fixups[] = { }, }; -static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { +static const struct hda_quirk ad1986a_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC), SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD), @@ -592,7 +588,7 @@ static const struct hda_fixup ad1981_fixups[] = { }, }; -static const struct snd_pci_quirk ad1981_fixup_tbl[] = { +static const struct hda_quirk ad1981_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), @@ -1065,7 +1061,7 @@ static const struct hda_fixup ad1884_fixups[] = { }, }; -static const struct snd_pci_quirk ad1884_fixup_tbl[] = { +static const struct hda_quirk ad1884_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART), SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD), diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index aa312441604f..d40197fb5fbd 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1134,7 +1134,6 @@ struct ca0132_spec { struct hda_codec *codec; struct delayed_work unsol_hp_work; - int quirk; #ifdef ENABLE_TUNING_CONTROLS long cur_ctl_vals[TUNING_CTLS_COUNT]; @@ -1166,7 +1165,6 @@ struct ca0132_spec { * CA0132 quirks table */ enum { - QUIRK_NONE, QUIRK_ALIENWARE, QUIRK_ALIENWARE_M17XR4, QUIRK_SBZ, @@ -1176,10 +1174,11 @@ enum { QUIRK_R3D, QUIRK_AE5, QUIRK_AE7, + QUIRK_NONE = HDA_FIXUP_ID_NOT_SET, }; #ifdef CONFIG_PCI -#define ca0132_quirk(spec) ((spec)->quirk) +#define ca0132_quirk(spec) ((spec)->codec->fixup_id) #define ca0132_use_pci_mmio(spec) ((spec)->use_pci_mmio) #define ca0132_use_alt_functions(spec) ((spec)->use_alt_functions) #define ca0132_use_alt_controls(spec) ((spec)->use_alt_controls) @@ -1293,7 +1292,7 @@ static const struct hda_pintbl ae7_pincfgs[] = { {} }; -static const struct snd_pci_quirk ca0132_quirks[] = { +static const struct hda_quirk ca0132_quirks[] = { SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4), SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE), @@ -1316,6 +1315,19 @@ static const struct snd_pci_quirk ca0132_quirks[] = { {} }; +static const struct hda_model_fixup ca0132_quirk_models[] = { + { .id = QUIRK_ALIENWARE, .name = "alienware" }, + { .id = QUIRK_ALIENWARE_M17XR4, .name = "alienware-m17xr4" }, + { .id = QUIRK_SBZ, .name = "sbz" }, + { .id = QUIRK_ZXR, .name = "zxr" }, + { .id = QUIRK_ZXR_DBPRO, .name = "zxr-dbpro" }, + { .id = QUIRK_R3DI, .name = "r3di" }, + { .id = QUIRK_R3D, .name = "r3d" }, + { .id = QUIRK_AE5, .name = "ae5" }, + { .id = QUIRK_AE7, .name = "ae7" }, + {} +}; + /* Output selection quirk info structures. */ #define MAX_QUIRK_MMIO_GPIO_SET_VALS 3 #define MAX_QUIRK_SCP_SET_VALS 2 @@ -9682,7 +9694,6 @@ static void dbpro_free(struct hda_codec *codec) kfree(codec->spec); } -#ifdef CONFIG_PM static int ca0132_suspend(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -9690,7 +9701,6 @@ static int ca0132_suspend(struct hda_codec *codec) cancel_delayed_work_sync(&spec->unsol_hp_work); return 0; } -#endif static const struct hda_codec_ops ca0132_patch_ops = { .build_controls = ca0132_build_controls, @@ -9698,9 +9708,7 @@ static const struct hda_codec_ops ca0132_patch_ops = { .init = ca0132_init, .free = ca0132_free, .unsol_event = snd_hda_jack_unsol_event, -#ifdef CONFIG_PM .suspend = ca0132_suspend, -#endif }; static const struct hda_codec_ops dbpro_patch_ops = { @@ -9961,17 +9969,15 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) */ static void sbz_detect_quirk(struct hda_codec *codec) { - struct ca0132_spec *spec = codec->spec; - switch (codec->core.subsystem_id) { case 0x11020033: - spec->quirk = QUIRK_ZXR; + codec->fixup_id = QUIRK_ZXR; break; case 0x1102003f: - spec->quirk = QUIRK_ZXR_DBPRO; + codec->fixup_id = QUIRK_ZXR_DBPRO; break; default: - spec->quirk = QUIRK_SBZ; + codec->fixup_id = QUIRK_SBZ; break; } } @@ -9980,7 +9986,6 @@ static int patch_ca0132(struct hda_codec *codec) { struct ca0132_spec *spec; int err; - const struct snd_pci_quirk *quirk; codec_dbg(codec, "patch_ca0132\n"); @@ -9991,11 +9996,7 @@ static int patch_ca0132(struct hda_codec *codec) spec->codec = codec; /* Detect codec quirk */ - quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks); - if (quirk) - spec->quirk = quirk->value; - else - spec->quirk = QUIRK_NONE; + snd_hda_pick_fixup(codec, ca0132_quirk_models, ca0132_quirks, NULL); if (ca0132_quirk(spec) == QUIRK_SBZ) sbz_detect_quirk(codec); @@ -10072,7 +10073,7 @@ static int patch_ca0132(struct hda_codec *codec) spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20); if (spec->mem_base == NULL) { codec_warn(codec, "pci_iomap failed! Setting quirk to QUIRK_NONE."); - spec->quirk = QUIRK_NONE; + codec->fixup_id = QUIRK_NONE; } } #endif diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 6807b4708a17..06e046214a41 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -385,7 +385,7 @@ static const struct hda_model_fixup cs420x_models[] = { {} }; -static const struct snd_pci_quirk cs420x_fixup_tbl[] = { +static const struct hda_quirk cs420x_fixup_tbl[] = { SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), @@ -634,13 +634,13 @@ static const struct hda_model_fixup cs4208_models[] = { {} }; -static const struct snd_pci_quirk cs4208_fixup_tbl[] = { +static const struct hda_quirk cs4208_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO), {} /* terminator */ }; /* codec SSID matching */ -static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = { +static const struct hda_quirk cs4208_mac_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI), SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), @@ -818,7 +818,7 @@ static const struct hda_model_fixup cs421x_models[] = { {} }; -static const struct snd_pci_quirk cs421x_fixup_tbl[] = { +static const struct hda_quirk cs421x_fixup_tbl[] = { /* Test Intel board + CDB2410 */ SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), {} /* terminator */ @@ -1128,7 +1128,6 @@ static int cs421x_parse_auto_config(struct hda_codec *codec) return 0; } -#ifdef CONFIG_PM /* * Manage PDREF, when transitioning to D3hot * (DAC,ADC) -> D3, PDREF=1, AFG->D3 @@ -1153,7 +1152,6 @@ static int cs421x_suspend(struct hda_codec *codec) return 0; } -#endif static const struct hda_codec_ops cs421x_patch_ops = { .build_controls = snd_hda_gen_build_controls, @@ -1161,9 +1159,7 @@ static const struct hda_codec_ops cs421x_patch_ops = { .init = cs421x_init, .free = cs_free, .unsol_event = snd_hda_jack_unsol_event, -#ifdef CONFIG_PM .suspend = cs421x_suspend, -#endif }; static int patch_cs4210(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 2ddd33f8dd6c..fe946d407830 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -17,10 +17,231 @@ #include "hda_jack.h" #include "hda_generic.h" +/* CM9825 Offset Definitions */ + +#define CM9825_VERB_SET_HPF_1 0x781 +#define CM9825_VERB_SET_HPF_2 0x785 +#define CM9825_VERB_SET_PLL 0x7a0 +#define CM9825_VERB_SET_NEG 0x7a1 +#define CM9825_VERB_SET_ADCL 0x7a2 +#define CM9825_VERB_SET_DACL 0x7a3 +#define CM9825_VERB_SET_MBIAS 0x7a4 +#define CM9825_VERB_SET_VNEG 0x7a8 +#define CM9825_VERB_SET_D2S 0x7a9 +#define CM9825_VERB_SET_DACTRL 0x7aa +#define CM9825_VERB_SET_PDNEG 0x7ac +#define CM9825_VERB_SET_VDO 0x7ad +#define CM9825_VERB_SET_CDALR 0x7b0 +#define CM9825_VERB_SET_MTCBA 0x7b1 +#define CM9825_VERB_SET_OTP 0x7b2 +#define CM9825_VERB_SET_OCP 0x7b3 +#define CM9825_VERB_SET_GAD 0x7b4 +#define CM9825_VERB_SET_TMOD 0x7b5 +#define CM9825_VERB_SET_SNR 0x7b6 + struct cmi_spec { struct hda_gen_spec gen; + const struct hda_verb *chip_d0_verbs; + const struct hda_verb *chip_d3_verbs; + const struct hda_verb *chip_hp_present_verbs; + const struct hda_verb *chip_hp_remove_verbs; + struct hda_codec *codec; + struct delayed_work unsol_hp_work; + int quirk; +}; + +static const struct hda_verb cm9825_std_d3_verbs[] = { + /* chip sleep verbs */ + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ + {0x43, CM9825_VERB_SET_PLL, 0x01}, /* PLL set */ + {0x43, CM9825_VERB_SET_NEG, 0xc2}, /* NEG set */ + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ + {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ + {0x43, CM9825_VERB_SET_VNEG, 0x50}, /* VOL NEG */ + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ + {0x43, CM9825_VERB_SET_PDNEG, 0x04}, /* SEL OSC */ + {0x43, CM9825_VERB_SET_CDALR, 0xf6}, /* Class D */ + {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ + {} +}; + +static const struct hda_verb cm9825_std_d0_verbs[] = { + /* chip init verbs */ + {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, /* EAPD set */ + {0x43, CM9825_VERB_SET_SNR, 0x30}, /* SNR set */ + {0x43, CM9825_VERB_SET_PLL, 0x00}, /* PLL set */ + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ + {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */ + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ + {0x43, CM9825_VERB_SET_VNEG, 0x56}, /* VOL NEG */ + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ + {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ + {0x43, CM9825_VERB_SET_PDNEG, 0x0c}, /* SEL OSC */ + {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ + {0x43, CM9825_VERB_SET_CDALR, 0xf4}, /* Class D */ + {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */ + {0x43, CM9825_VERB_SET_MTCBA, 0x61}, /* SR set */ + {0x43, CM9825_VERB_SET_OCP, 0x33}, /* OTP set */ + {0x43, CM9825_VERB_SET_GAD, 0x07}, /* ADC -3db */ + {0x43, CM9825_VERB_SET_TMOD, 0x26}, /* Class D clk */ + {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | + AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d}, /* Gain set */ + {0x3C, AC_VERB_SET_AMP_GAIN_MUTE | + AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d}, /* Gain set */ + {0x43, CM9825_VERB_SET_HPF_1, 0x40}, /* HPF set */ + {0x43, CM9825_VERB_SET_HPF_2, 0x40}, /* HPF set */ + {} }; +static const struct hda_verb cm9825_hp_present_verbs[] = { + {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, /* PIN off */ + {0x43, CM9825_VERB_SET_ADCL, 0x88}, /* ADC */ + {0x43, CM9825_VERB_SET_DACL, 0xaa}, /* DACL */ + {0x43, CM9825_VERB_SET_MBIAS, 0x10}, /* MBIAS */ + {0x43, CM9825_VERB_SET_D2S, 0xf2}, /* depop */ + {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */ + {0x43, CM9825_VERB_SET_VDO, 0xc4}, /* VDO set */ + {} +}; + +static const struct hda_verb cm9825_hp_remove_verbs[] = { + {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */ + {0x43, CM9825_VERB_SET_DACL, 0x56}, /* DACL */ + {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */ + {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */ + {0x43, CM9825_VERB_SET_DACTRL, 0xe0}, /* DACTRL set */ + {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */ + {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* PIN on */ + {} +}; + +static void cm9825_unsol_hp_delayed(struct work_struct *work) +{ + struct cmi_spec *spec = + container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work); + struct hda_jack_tbl *jack; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_jack_plugin = false; + int err = 0; + + hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); + + codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", + (int)hp_jack_plugin, hp_pin); + + if (!hp_jack_plugin) { + err = + snd_hda_codec_write(spec->codec, 0x42, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); + if (err) + codec_dbg(spec->codec, "codec_write err %d\n", err); + + snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs); + } else { + snd_hda_sequence_write(spec->codec, + spec->chip_hp_present_verbs); + } + + jack = snd_hda_jack_tbl_get(spec->codec, hp_pin); + if (jack) { + jack->block_report = 0; + snd_hda_jack_report_sync(spec->codec); + } +} + +static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) +{ + struct cmi_spec *spec = codec->spec; + struct hda_jack_tbl *tbl; + + /* Delay enabling the HP amp, to let the mic-detection + * state machine run. + */ + + codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid); + + tbl = snd_hda_jack_tbl_get(codec, cb->nid); + if (tbl) + tbl->block_report = 1; + schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200)); +} + +static void cm9825_setup_unsol(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + + snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback); +} + +static int cm9825_init(struct hda_codec *codec) +{ + snd_hda_gen_init(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + + return 0; +} + +static void cm9825_free(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + + cancel_delayed_work_sync(&spec->unsol_hp_work); + snd_hda_gen_free(codec); +} + +static int cm9825_suspend(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + + cancel_delayed_work_sync(&spec->unsol_hp_work); + + snd_hda_sequence_write(codec, spec->chip_d3_verbs); + + return 0; +} + +static int cm9825_resume(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + hda_nid_t hp_pin = 0; + bool hp_jack_plugin = false; + int err; + + err = + snd_hda_codec_write(spec->codec, 0x42, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00); + if (err) + codec_dbg(codec, "codec_write err %d\n", err); + + msleep(150); /* for depop noise */ + + codec->patch_ops.init(codec); + + hp_pin = spec->gen.autocfg.hp_pins[0]; + hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin); + + codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n", + (int)hp_jack_plugin, hp_pin); + + if (!hp_jack_plugin) { + err = + snd_hda_codec_write(spec->codec, 0x42, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); + + if (err) + codec_dbg(codec, "codec_write err %d\n", err); + + snd_hda_sequence_write(codec, cm9825_hp_remove_verbs); + } + + snd_hda_regmap_sync(codec); + hda_call_check_power_status(codec, 0x01); + + return 0; +} + /* * stuff for auto-parser */ @@ -32,6 +253,53 @@ static const struct hda_codec_ops cmi_auto_patch_ops = { .unsol_event = snd_hda_jack_unsol_event, }; +static int patch_cm9825(struct hda_codec *codec) +{ + struct cmi_spec *spec; + struct auto_pin_cfg *cfg; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed); + codec->spec = spec; + spec->codec = codec; + codec->patch_ops = cmi_auto_patch_ops; + codec->patch_ops.init = cm9825_init; + codec->patch_ops.suspend = cm9825_suspend; + codec->patch_ops.resume = cm9825_resume; + codec->patch_ops.free = cm9825_free; + codec->patch_ops.check_power_status = snd_hda_gen_check_power_status; + cfg = &spec->gen.autocfg; + snd_hda_gen_spec_init(&spec->gen); + spec->chip_d0_verbs = cm9825_std_d0_verbs; + spec->chip_d3_verbs = cm9825_std_d3_verbs; + spec->chip_hp_present_verbs = cm9825_hp_present_verbs; + spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs; + + snd_hda_sequence_write(codec, spec->chip_d0_verbs); + + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + goto error; + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + goto error; + + cm9825_setup_unsol(codec); + + return 0; + + error: + cm9825_free(codec); + + codec_info(codec, "Enter err %d\n", err); + + return err; +} + static int patch_cmi9880(struct hda_codec *codec) { struct cmi_spec *spec; @@ -113,6 +381,7 @@ static const struct hda_device_id snd_hda_id_cmedia[] = { HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888), HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880), HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880), + HDA_CODEC_ENTRY(0x13f69825, "CM9825", patch_cm9825), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e8209178d87b..34874039ad45 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -21,12 +21,6 @@ #include "hda_jack.h" #include "hda_generic.h" -enum { - CX_HEADSET_NOPRESENT = 0, - CX_HEADSET_PARTPRESENT, - CX_HEADSET_ALLPRESENT, -}; - struct conexant_spec { struct hda_gen_spec gen; @@ -48,7 +42,6 @@ struct conexant_spec { unsigned int gpio_led; unsigned int gpio_mute_led_mask; unsigned int gpio_mic_led_mask; - unsigned int headset_present_flag; bool is_cx8070_sn6140; }; @@ -173,18 +166,18 @@ static void cxt_init_gpio_led(struct hda_codec *codec) static void cx_fixup_headset_recog(struct hda_codec *codec) { - unsigned int mic_persent; + unsigned int mic_present; /* fix some headset type recognize fail issue, such as EDIFIER headset */ - /* set micbiasd output current comparator threshold from 66% to 55%. */ + /* set micbias output current comparator threshold from 66% to 55%. */ snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010); - /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias registor + /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register * value adjustment trim from 2.2K ohms to 2.0K ohms. */ snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10); /* fix reboot headset type recognize fail issue */ - mic_persent = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); - if (mic_persent & AC_PINSENSE_PRESENCE) + mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); + if (mic_present & AC_PINSENSE_PRESENCE) /* enable headset mic VREF */ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); else @@ -250,68 +243,35 @@ static void cx_process_headset_plugin(struct hda_codec *codec) } } -static void cx_update_headset_mic_vref(struct hda_codec *codec, unsigned int res) +static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_callback *event) { - unsigned int phone_present, mic_persent, phone_tag, mic_tag; - struct conexant_spec *spec = codec->spec; + unsigned int mic_present; - /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled, - * the node 19 can only be config to microphone or disabled. - * Check hp&mic tag to process headset pulgin&plugout. + /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, + * the node 19 can only be configured to microphone or disabled. + * Check hp&mic tag to process headset plugin & plugout. */ - phone_tag = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0); - mic_tag = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0); - if ((phone_tag & (res >> AC_UNSOL_RES_TAG_SHIFT)) || - (mic_tag & (res >> AC_UNSOL_RES_TAG_SHIFT))) { - phone_present = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_PIN_SENSE, 0x0); - if (!(phone_present & AC_PINSENSE_PRESENCE)) {/* headphone plugout */ - spec->headset_present_flag = CX_HEADSET_NOPRESENT; - snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); - return; - } - if (spec->headset_present_flag == CX_HEADSET_NOPRESENT) { - spec->headset_present_flag = CX_HEADSET_PARTPRESENT; - } else if (spec->headset_present_flag == CX_HEADSET_PARTPRESENT) { - mic_persent = snd_hda_codec_read(codec, 0x19, 0, - AC_VERB_GET_PIN_SENSE, 0x0); - /* headset is present */ - if ((phone_present & AC_PINSENSE_PRESENCE) && - (mic_persent & AC_PINSENSE_PRESENCE)) { - cx_process_headset_plugin(codec); - spec->headset_present_flag = CX_HEADSET_ALLPRESENT; - } - } - } -} - -static void cx_jack_unsol_event(struct hda_codec *codec, unsigned int res) -{ - struct conexant_spec *spec = codec->spec; - - if (spec->is_cx8070_sn6140) - cx_update_headset_mic_vref(codec, res); - - snd_hda_jack_unsol_event(codec, res); + mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); + if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); + else + cx_process_headset_plugin(codec); } -#ifdef CONFIG_PM static int cx_auto_suspend(struct hda_codec *codec) { cx_auto_shutdown(codec); return 0; } -#endif static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = snd_hda_gen_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = cx_auto_init, .free = cx_auto_free, - .unsol_event = cx_jack_unsol_event, -#ifdef CONFIG_PM + .unsol_event = snd_hda_jack_unsol_event, .suspend = cx_auto_suspend, .check_power_status = snd_hda_gen_check_power_status, -#endif }; /* @@ -331,6 +291,7 @@ enum { CXT_FIXUP_GPIO1, CXT_FIXUP_ASPIRE_DMIC, CXT_FIXUP_THINKPAD_ACPI, + CXT_FIXUP_LENOVO_XPAD_ACPI, CXT_FIXUP_OLPC_XO, CXT_FIXUP_CAP_MIX_AMP, CXT_FIXUP_TOSHIBA_P105, @@ -341,15 +302,21 @@ enum { CXT_FIXUP_HP_SPECTRE, CXT_FIXUP_HP_GATE_MIC, CXT_FIXUP_MUTE_LED_GPIO, + CXT_FIXUP_HP_ELITEONE_OUT_DIS, CXT_FIXUP_HP_ZBOOK_MUTE_LED, CXT_FIXUP_HEADSET_MIC, CXT_FIXUP_HP_MIC_NO_PRESENCE, CXT_PINCFG_SWS_JS201D, + CXT_PINCFG_TOP_SPEAKER, + CXT_FIXUP_HP_A_U, }; /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" +/* for hda_fixup_ideapad_acpi() */ +#include "ideapad_hotkey_led_helper.c" + static void cxt_fixup_stereo_dmic(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -357,6 +324,19 @@ static void cxt_fixup_stereo_dmic(struct hda_codec *codec, spec->gen.inv_dmic_split = 1; } +/* fix widget control pin settings */ +static void cxt_fixup_update_pinctl(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PROBE) { + /* Unset OUT_EN for this Node pin, leaving only HP_EN. + * This is the value stored in the codec register after + * the correct initialization of the previous windows boot. + */ + snd_hda_set_pin_ctl_cache(codec, 0x1d, AC_PINCTL_HP_EN); + } +} + static void cxt5066_increase_mic_boost(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -799,6 +779,18 @@ static void cxt_setup_mute_led(struct hda_codec *codec, } } +static void cxt_setup_gpio_unmute(struct hda_codec *codec, + unsigned int gpio_mute_mask) +{ + if (gpio_mute_mask) { + // set gpio data to 0. + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, gpio_mute_mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, gpio_mute_mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_STICKY_MASK, 0); + } +} + static void cxt_fixup_mute_led_gpio(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -813,6 +805,15 @@ static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec, cxt_setup_mute_led(codec, 0x10, 0x20); } +static void cxt_fixup_hp_a_u(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + // Init vers in BIOS mute the spk/hp by set gpio high to avoid pop noise, + // so need to unmute once by clearing the gpio data when runs into the system. + if (action == HDA_FIXUP_ACT_INIT) + cxt_setup_gpio_unmute(codec, 0x2); +} + /* ThinkPad X200 & co with cxt5051 */ static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ @@ -931,6 +932,12 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = hda_fixup_thinkpad_acpi, }, + [CXT_FIXUP_LENOVO_XPAD_ACPI] = { + .type = HDA_FIXUP_FUNC, + .v.func = hda_fixup_ideapad_acpi, + .chained = true, + .chain_id = CXT_FIXUP_THINKPAD_ACPI, + }, [CXT_FIXUP_OLPC_XO] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_olpc_xo, @@ -991,6 +998,10 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_mute_led_gpio, }, + [CXT_FIXUP_HP_ELITEONE_OUT_DIS] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_update_pinctl, + }, [CXT_FIXUP_HP_ZBOOK_MUTE_LED] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_hp_zbook_mute_led, @@ -1012,9 +1023,20 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = cxt_pincfg_sws_js201d, }, + [CXT_PINCFG_TOP_SPEAKER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1d, 0x82170111 }, + { } + }, + }, + [CXT_FIXUP_HP_A_U] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_hp_a_u, + }, }; -static const struct snd_pci_quirk cxt5045_fixups[] = { +static const struct hda_quirk cxt5045_fixups[] = { SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105), /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have @@ -1034,7 +1056,7 @@ static const struct hda_model_fixup cxt5045_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5047_fixups[] = { +static const struct hda_quirk cxt5047_fixups[] = { /* HP laptops have really bad sound over 0 dB on NID 0x10. */ SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047), @@ -1046,7 +1068,7 @@ static const struct hda_model_fixup cxt5047_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5051_fixups[] = { +static const struct hda_quirk cxt5051_fixups[] = { SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200), {} @@ -1057,7 +1079,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5066_fixups[] = { +static const struct hda_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), @@ -1068,6 +1090,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x8231, "HP ProBook 450 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), @@ -1077,6 +1100,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83e5, "HP EliteOne 1000 G2", CXT_FIXUP_HP_ELITEONE_OUT_DIS), SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED), @@ -1085,6 +1109,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), + SND_PCI_QUIRK(0x14f1, 0x0252, "MBX-Z60MR100", CXT_FIXUP_HP_A_U), SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), @@ -1105,9 +1130,11 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI), + SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad/Ideapad", CXT_FIXUP_LENOVO_XPAD_ACPI), SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), + HDA_CODEC_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER), + HDA_CODEC_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER), {} }; @@ -1117,6 +1144,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { { .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" }, { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" }, { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" }, + { .id = CXT_FIXUP_LENOVO_XPAD_ACPI, .name = "thinkpad-ideapad" }, { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, { .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" }, { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, @@ -1127,6 +1155,8 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" }, { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" }, { .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" }, + { .id = CXT_PINCFG_TOP_SPEAKER, .name = "sirius-top-speaker" }, + { .id = CXT_FIXUP_HP_A_U, .name = "HP-U-support" }, {} }; @@ -1167,7 +1197,7 @@ static int patch_conexant_auto(struct hda_codec *codec) case 0x14f11f86: case 0x14f11f87: spec->is_cx8070_sn6140 = true; - spec->headset_present_flag = CX_HEADSET_NOPRESENT; + snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); break; } diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c index 36b411d1a960..09240138e087 100644 --- a/sound/pci/hda/patch_cs8409-tables.c +++ b/sound/pci/hda/patch_cs8409-tables.c @@ -121,7 +121,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = { { CS42L42_MIXER_CHA_VOL, 0x3F }, { CS42L42_MIXER_CHB_VOL, 0x3F }, { CS42L42_MIXER_ADC_VOL, 0x3f }, - { CS42L42_HP_CTL, 0x03 }, + { CS42L42_HP_CTL, 0x0D }, { CS42L42_MIC_DET_CTL1, 0xB6 }, { CS42L42_TIPSENSE_CTL, 0xC2 }, { CS42L42_HS_CLAMP_DISABLE, 0x01 }, @@ -131,7 +131,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = { { CS42L42_RSENSE_CTL3, 0x00 }, { CS42L42_TSENSE_CTL, 0x80 }, { CS42L42_HS_BIAS_CTL, 0xC0 }, - { CS42L42_PWR_CTL1, 0x02 }, + { CS42L42_PWR_CTL1, 0x02, 10000 }, { CS42L42_ADC_OVFL_INT_MASK, 0xff }, { CS42L42_MIXER_INT_MASK, 0xff }, { CS42L42_SRC_INT_MASK, 0xff }, @@ -315,7 +315,7 @@ static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = { { CS42L42_ASP_TX_SZ_EN, 0x01 }, { CS42L42_PWR_CTL1, 0x0A }, { CS42L42_PWR_CTL2, 0x84 }, - { CS42L42_HP_CTL, 0x03 }, + { CS42L42_HP_CTL, 0x0D }, { CS42L42_MIXER_CHA_VOL, 0x3F }, { CS42L42_MIXER_CHB_VOL, 0x3F }, { CS42L42_MIXER_ADC_VOL, 0x3f }, @@ -328,7 +328,7 @@ static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = { { CS42L42_RSENSE_CTL3, 0x00 }, { CS42L42_TSENSE_CTL, 0x80 }, { CS42L42_HS_BIAS_CTL, 0xC0 }, - { CS42L42_PWR_CTL1, 0x02 }, + { CS42L42_PWR_CTL1, 0x02, 10000 }, { CS42L42_ADC_OVFL_INT_MASK, 0xff }, { CS42L42_MIXER_INT_MASK, 0xff }, { CS42L42_SRC_INT_MASK, 0xff }, @@ -371,7 +371,7 @@ static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = { { CS42L42_ASP_TX_SZ_EN, 0x00 }, { CS42L42_PWR_CTL1, 0x0E }, { CS42L42_PWR_CTL2, 0x84 }, - { CS42L42_HP_CTL, 0x01 }, + { CS42L42_HP_CTL, 0x0D }, { CS42L42_MIXER_CHA_VOL, 0x3F }, { CS42L42_MIXER_CHB_VOL, 0x3F }, { CS42L42_MIXER_ADC_VOL, 0x3f }, @@ -384,7 +384,7 @@ static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = { { CS42L42_RSENSE_CTL3, 0x00 }, { CS42L42_TSENSE_CTL, 0x80 }, { CS42L42_HS_BIAS_CTL, 0xC0 }, - { CS42L42_PWR_CTL1, 0x06 }, + { CS42L42_PWR_CTL1, 0x06, 10000 }, { CS42L42_ADC_OVFL_INT_MASK, 0xff }, { CS42L42_MIXER_INT_MASK, 0xff }, { CS42L42_SRC_INT_MASK, 0xff }, @@ -473,7 +473,7 @@ struct sub_codec dolphin_cs42l42_1 = { * Arrays Used for all projects using CS8409 ******************************************************************************/ -const struct snd_pci_quirk cs8409_fixup_tbl[] = { +const struct hda_quirk cs8409_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE), SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE), SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE), diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c index e41316e2e983..e50006757a2c 100644 --- a/sound/pci/hda/patch_cs8409.c +++ b/sound/pci/hda/patch_cs8409.c @@ -346,6 +346,11 @@ static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i if (cs8409_i2c_wait_complete(codec) < 0) goto error; + /* Certain use cases may require a delay + * after a write operation before proceeding. + */ + if (seq[i].delay) + fsleep(seq[i].delay); } mutex_unlock(&spec->i2c_mux); @@ -876,7 +881,7 @@ static void cs42l42_resume(struct sub_codec *cs42l42) { CS42L42_DET_INT_STATUS2, 0x00 }, { CS42L42_TSRS_PLUG_STATUS, 0x00 }, }; - int fsv_old, fsv_new; + unsigned int fsv; /* Bring CS42L42 out of Reset */ spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0); @@ -888,18 +893,19 @@ static void cs42l42_resume(struct sub_codec *cs42l42) /* Initialize CS42L42 companion codec */ cs8409_i2c_bulk_write(cs42l42, cs42l42->init_seq, cs42l42->init_seq_num); - msleep(CS42L42_INIT_TIMEOUT_MS); /* Clear interrupts, by reading interrupt status registers */ cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs)); - fsv_old = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL); - if (cs42l42->full_scale_vol == CS42L42_FULL_SCALE_VOL_0DB) - fsv_new = fsv_old & ~CS42L42_FULL_SCALE_VOL_MASK; - else - fsv_new = fsv_old & CS42L42_FULL_SCALE_VOL_MASK; - if (fsv_new != fsv_old) - cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv_new); + fsv = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL); + if (cs42l42->full_scale_vol) { + // Set the full scale volume bit + fsv |= CS42L42_FULL_SCALE_VOL_MASK; + cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv); + } + // Unmute analog channels A and B + fsv = (fsv & ~CS42L42_ANA_MUTE_AB); + cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv); /* we have to explicitly allow unsol event handling even during the * resume phase so that the jack event is processed properly @@ -909,7 +915,6 @@ static void cs42l42_resume(struct sub_codec *cs42l42) cs42l42_enable_jack_detect(cs42l42); } -#ifdef CONFIG_PM static void cs42l42_suspend(struct sub_codec *cs42l42) { struct hda_codec *codec = cs42l42->codec; @@ -921,7 +926,7 @@ static void cs42l42_suspend(struct sub_codec *cs42l42) { CS42L42_MIXER_CHA_VOL, 0x3F }, { CS42L42_MIXER_ADC_VOL, 0x3F }, { CS42L42_MIXER_CHB_VOL, 0x3F }, - { CS42L42_HP_CTL, 0x0F }, + { CS42L42_HP_CTL, 0x0D }, { CS42L42_ASP_RX_DAI0_EN, 0x00 }, { CS42L42_ASP_CLK_CFG, 0x00 }, { CS42L42_PWR_CTL1, 0xFE }, @@ -948,7 +953,6 @@ static void cs42l42_suspend(struct sub_codec *cs42l42) spec->gpio_data &= ~cs42l42->reset_gpio; snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data); } -#endif static void cs8409_free(struct hda_codec *codec) { @@ -1003,7 +1007,6 @@ static void cs8409_cs42l42_jack_unsol_event(struct hda_codec *codec, unsigned in } } -#ifdef CONFIG_PM /* Manage PDREF, when transition to D3hot */ static int cs8409_cs42l42_suspend(struct hda_codec *codec) { @@ -1025,7 +1028,6 @@ static int cs8409_cs42l42_suspend(struct hda_codec *codec) return 0; } -#endif /* Vendor specific HW configuration * PLL, ASP, I2C, SPI, GPIOs, DMIC etc... @@ -1080,9 +1082,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { .init = cs8409_init, .free = cs8409_free, .unsol_event = cs8409_cs42l42_jack_unsol_event, -#ifdef CONFIG_PM .suspend = cs8409_cs42l42_suspend, -#endif }; static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags, @@ -1310,9 +1310,7 @@ static const struct hda_codec_ops cs8409_dolphin_patch_ops = { .init = cs8409_init, .free = cs8409_free, .unsol_event = dolphin_jack_unsol_event, -#ifdef CONFIG_PM .suspend = cs8409_cs42l42_suspend, -#endif }; static int dolphin_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags, @@ -1411,8 +1409,9 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac kctrl = snd_hda_gen_add_kctl(&spec->gen, "Line Out Playback Volume", &cs42l42_dac_volume_mixer); /* Update Line Out kcontrol template */ - kctrl->private_value = HDA_COMPOSE_AMP_VAL_OFS(DOLPHIN_HP_PIN_NID, 3, CS8409_CODEC1, - HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE; + if (kctrl) + kctrl->private_value = HDA_COMPOSE_AMP_VAL_OFS(DOLPHIN_HP_PIN_NID, 3, CS8409_CODEC1, + HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE; cs8409_enable_ur(codec, 0); snd_hda_codec_set_name(codec, "CS8409/CS42L42"); break; diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h index 937e9387abdc..e4bd2e12110b 100644 --- a/sound/pci/hda/patch_cs8409.h +++ b/sound/pci/hda/patch_cs8409.h @@ -229,10 +229,10 @@ enum cs8409_coefficient_index_registers { #define CS42L42_I2C_SLEEP_US (2000) #define CS42L42_PDN_TIMEOUT_US (250000) #define CS42L42_PDN_SLEEP_US (2000) -#define CS42L42_INIT_TIMEOUT_MS (45) +#define CS42L42_ANA_MUTE_AB (0x0C) #define CS42L42_FULL_SCALE_VOL_MASK (2) -#define CS42L42_FULL_SCALE_VOL_0DB (1) -#define CS42L42_FULL_SCALE_VOL_MINUS6DB (0) +#define CS42L42_FULL_SCALE_VOL_0DB (0) +#define CS42L42_FULL_SCALE_VOL_MINUS6DB (1) /* Dell BULLSEYE / WARLOCK / CYBORG Specific Definitions */ @@ -290,6 +290,7 @@ enum { struct cs8409_i2c_param { unsigned int addr; unsigned int value; + unsigned int delay; }; struct cs8409_cir_param { @@ -355,7 +356,7 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback; extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture; -extern const struct snd_pci_quirk cs8409_fixup_tbl[]; +extern const struct hda_quirk cs8409_fixup_tbl[]; extern const struct hda_model_fixup cs8409_models[]; extern const struct hda_fixup cs8409_fixups[]; extern const struct hda_verb cs8409_cs42l42_init_verbs[]; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 495d63101186..9a7793eb16e9 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -3,7 +3,7 @@ * * patch_hdmi.c - routines for HDMI/DisplayPort codecs * - * Copyright(c) 2008-2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008-2010 Intel Corporation * Copyright (c) 2006 ATI Technologies Inc. * Copyright (c) 2008 NVIDIA Corp. All rights reserved. * Copyright (c) 2008 Wei Ni <wni@nvidia.com> @@ -1511,8 +1511,8 @@ static void update_eld(struct hda_codec *codec, if (eld->eld_valid) { if (eld->eld_size <= 0 || - snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, - eld->eld_size) < 0) { + snd_parse_eld(hda_codec_dev(codec), &eld->info, + eld->eld_buffer, eld->eld_size) < 0) { eld->eld_valid = false; if (repoll) { schedule_delayed_work(&per_pin->work, @@ -1555,7 +1555,7 @@ static void update_eld(struct hda_codec *codec, pcm_jack = pin_idx_to_pcm_jack(codec, per_pin); if (eld->eld_valid) - snd_hdmi_show_eld(codec, &eld->info); + snd_show_eld(hda_codec_dev(codec), &eld->info); eld_changed = (pin_eld->eld_valid != eld->eld_valid); eld_changed |= (pin_eld->monitor_present != eld->monitor_present); @@ -1989,6 +1989,8 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) } static const struct snd_pci_quirk force_connect_list[] = { + SND_PCI_QUIRK(0x103c, 0x83e2, "HP EliteDesk 800 G4", 1), + SND_PCI_QUIRK(0x103c, 0x83ef, "HP MP9 G4 Retail System AMS", 1), SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1), SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1), SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1), @@ -2513,7 +2515,6 @@ static void generic_hdmi_free(struct hda_codec *codec) generic_spec_free(codec); } -#ifdef CONFIG_PM static int generic_hdmi_suspend(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -2540,7 +2541,6 @@ static int generic_hdmi_resume(struct hda_codec *codec) } return 0; } -#endif static const struct hda_codec_ops generic_hdmi_patch_ops = { .init = generic_hdmi_init, @@ -2548,10 +2548,8 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { .build_pcms = generic_hdmi_build_pcms, .build_controls = generic_hdmi_build_controls, .unsol_event = hdmi_unsol_event, -#ifdef CONFIG_PM .suspend = generic_hdmi_suspend, .resume = generic_hdmi_resume, -#endif }; static const struct hdmi_ops generic_standard_hdmi_ops = { @@ -2952,7 +2950,6 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec, } } -#ifdef CONFIG_PM static int i915_adlp_hdmi_suspend(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -3032,7 +3029,6 @@ static int i915_adlp_hdmi_resume(struct hda_codec *codec) return res; } -#endif /* precondition and allocation for Intel codecs */ static int alloc_intel_hdmi(struct hda_codec *codec) @@ -3167,10 +3163,8 @@ static int patch_i915_adlp_hdmi(struct hda_codec *codec) if (spec->silent_stream_type) { spec->silent_stream_type = SILENT_STREAM_KAE; -#ifdef CONFIG_PM codec->patch_ops.resume = i915_adlp_hdmi_resume; codec->patch_ops.suspend = i915_adlp_hdmi_suspend; -#endif } } @@ -4557,6 +4551,9 @@ HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi), HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi), +HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP", patch_tegra234_hdmi), +HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP", patch_tegra234_hdmi), +HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP", patch_tegra234_hdmi), HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi), @@ -4595,15 +4592,32 @@ HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP", patch_nvhdmi), +HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP", patch_nvhdmi), HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch), HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch), HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP", patch_gf_hdmi), @@ -4616,6 +4630,17 @@ HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi), HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f87, "ZX-100S HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f88, "KX-5000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f89, "KX-5000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f8a, "KX-6000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f8b, "KX-6000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f8c, "KX-6000G HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f8d, "KX-6000G HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f8e, "KX-7000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f8f, "KX-7000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x1d179f90, "KX-7000 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_i915_cpt_hdmi), HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI", patch_generic_hdmi), @@ -4642,8 +4667,11 @@ HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi), HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a17c36a36aa5..d91aac06adde 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11,20 +11,24 @@ */ #include <linux/acpi.h> +#include <linux/cleanup.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/dmi.h> #include <linux/module.h> +#include <linux/i2c.h> #include <linux/input.h> #include <linux/leds.h> #include <linux/ctype.h> +#include <linux/spi/spi.h> #include <sound/core.h> #include <sound/jack.h> #include <sound/hda_codec.h> #include "hda_local.h" #include "hda_auto_parser.h" +#include "hda_beep.h" #include "hda_jack.h" #include "hda_generic.h" #include "hda_component.h" @@ -109,9 +113,7 @@ struct alc_spec { /* hooks */ void (*init_hook)(struct hda_codec *codec); -#ifdef CONFIG_PM void (*power_hook)(struct hda_codec *codec); -#endif void (*shutup)(struct hda_codec *codec); int init_amp; @@ -124,6 +126,7 @@ struct alc_spec { unsigned int has_hs_key:1; unsigned int no_internal_mic_pin:1; unsigned int en_3kpull_low:1; + int num_speaker_amps; /* for PLL fix */ hda_nid_t pll_nid; @@ -133,7 +136,7 @@ struct alc_spec { u8 alc_mute_keycode_map[1]; /* component binding */ - struct hda_component comps[HDA_MAX_COMPONENTS]; + struct hda_component_parent comps; }; /* @@ -438,6 +441,10 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); fallthrough; case 0x10ec0215: + case 0x10ec0236: + case 0x10ec0245: + case 0x10ec0256: + case 0x10ec0257: case 0x10ec0285: case 0x10ec0289: alc_update_coef_idx(codec, 0x36, 1<<13, 0); @@ -445,12 +452,8 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0230: case 0x10ec0233: case 0x10ec0235: - case 0x10ec0236: - case 0x10ec0245: case 0x10ec0255: - case 0x10ec0256: case 0x19e58326: - case 0x10ec0257: case 0x10ec0282: case 0x10ec0283: case 0x10ec0286: @@ -471,6 +474,8 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) break; case 0x10ec0234: case 0x10ec0274: + alc_write_coef_idx(codec, 0x6e, 0x0c25); + fallthrough; case 0x10ec0294: case 0x10ec0700: case 0x10ec0701: @@ -582,19 +587,25 @@ static void alc_shutup_pins(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + if (spec->no_shutup_pins) + return; + switch (codec->core.vendor_id) { case 0x10ec0236: case 0x10ec0256: + case 0x10ec0257: case 0x19e58326: case 0x10ec0283: + case 0x10ec0285: case 0x10ec0286: + case 0x10ec0287: case 0x10ec0288: + case 0x10ec0295: case 0x10ec0298: alc_headset_mic_no_shutup(codec); break; default: - if (!spec->no_shutup_pins) - snd_hda_shutup_pins(codec); + snd_hda_shutup_pins(codec); break; } } @@ -882,9 +893,7 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) } } -/* - */ - +/* inverted digital-mic */ static void alc_fixup_inv_dmic(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -920,6 +929,8 @@ static void alc_pre_init(struct hda_codec *codec) ((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME) #define is_s4_resume(codec) \ ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE) +#define is_s4_suspend(codec) \ + ((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE) static int alc_init(struct hda_codec *codec) { @@ -943,9 +954,19 @@ static int alc_init(struct hda_codec *codec) return 0; } -#define alc_free snd_hda_gen_free +/* forward declaration */ +static const struct component_master_ops comp_master_ops; + +static void alc_free(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec) + hda_component_manager_free(&spec->comps, &comp_master_ops); + + snd_hda_gen_free(codec); +} -#ifdef CONFIG_PM static inline void alc_shutup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -984,7 +1005,6 @@ static int alc_resume(struct hda_codec *codec) hda_call_check_power_status(codec, 0x01); return 0; } -#endif /* */ @@ -994,11 +1014,9 @@ static const struct hda_codec_ops alc_patch_ops = { .init = alc_init, .free = alc_free, .unsol_event = snd_hda_jack_unsol_event, -#ifdef CONFIG_PM .resume = alc_resume, .suspend = alc_suspend, .check_power_status = snd_hda_gen_check_power_status, -#endif }; @@ -1550,7 +1568,7 @@ static const struct hda_fixup alc880_fixups[] = { }, }; -static const struct snd_pci_quirk alc880_fixup_tbl[] = { +static const struct hda_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A), SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), @@ -1859,7 +1877,7 @@ static const struct hda_fixup alc260_fixups[] = { }, }; -static const struct snd_pci_quirk alc260_fixup_tbl[] = { +static const struct hda_quirk alc260_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1), SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1), @@ -2551,7 +2569,7 @@ static const struct hda_fixup alc882_fixups[] = { }, }; -static const struct snd_pci_quirk alc882_fixup_tbl[] = { +static const struct hda_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), @@ -2638,6 +2656,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), @@ -2895,7 +2914,7 @@ static const struct hda_fixup alc262_fixups[] = { }, }; -static const struct snd_pci_quirk alc262_fixup_tbl[] = { +static const struct hda_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200), SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), @@ -3056,7 +3075,7 @@ static const struct hda_model_fixup alc268_fixup_models[] = { {} }; -static const struct snd_pci_quirk alc268_fixup_tbl[] = { +static const struct hda_quirk alc268_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF), SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC), /* below is codec SSID since multiple Toshiba laptops have the @@ -3598,25 +3617,22 @@ static void alc256_init(struct hda_codec *codec) hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); - if (hp_pin_sense) + if (hp_pin_sense) { msleep(2); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ - alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ - - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - if (hp_pin_sense || spec->ultra_low_power) - msleep(85); - - snd_hda_codec_write(codec, hp_pin, 0, + snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - if (hp_pin_sense || spec->ultra_low_power) - msleep(100); + msleep(75); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + msleep(75); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ + } alc_update_coef_idx(codec, 0x46, 3 << 12, 0); - alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */ alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15); /* @@ -3640,29 +3656,28 @@ static void alc256_shutup(struct hda_codec *codec) alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); - if (hp_pin_sense) + if (hp_pin_sense) { msleep(2); - snd_hda_codec_write(codec, hp_pin, 0, + snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp_pin_sense || spec->ultra_low_power) - msleep(85); + msleep(75); /* 3k pull low control for Headset jack. */ /* NOTE: call this before clearing the pin, otherwise codec stalls */ /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly * when booting with headset plugged. So skip setting it for the codec alc257 */ - if (spec->en_3kpull_low) - alc_update_coef_idx(codec, 0x46, 0, 3 << 12); + if (spec->en_3kpull_low) + alc_update_coef_idx(codec, 0x46, 0, 3 << 12); - if (!spec->no_shutup_pins) - snd_hda_codec_write(codec, hp_pin, 0, + if (!spec->no_shutup_pins) + snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - if (hp_pin_sense || spec->ultra_low_power) - msleep(100); + msleep(75); + } alc_auto_setup_eapd(codec, false); alc_shutup_pins(codec); @@ -3757,33 +3772,29 @@ static void alc225_init(struct hda_codec *codec) hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); hp2_pin_sense = snd_hda_jack_detect(codec, 0x16); - if (hp1_pin_sense || hp2_pin_sense) + if (hp1_pin_sense || hp2_pin_sense) { msleep(2); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + msleep(75); - alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ - - if (hp1_pin_sense || spec->ultra_low_power) - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp2_pin_sense) - snd_hda_codec_write(codec, 0x16, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power) - msleep(85); - - if (hp1_pin_sense || spec->ultra_low_power) - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - if (hp2_pin_sense) - snd_hda_codec_write(codec, 0x16, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - - if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power) - msleep(100); + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); - alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ + msleep(75); + alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ + } } static void alc225_shutup(struct hda_codec *codec) @@ -3795,36 +3806,35 @@ static void alc225_shutup(struct hda_codec *codec) if (!hp_pin) hp_pin = 0x21; - alc_disable_headset_jack_key(codec); - /* 3k pull low control for Headset jack. */ - alc_update_coef_idx(codec, 0x4a, 0, 3 << 10); - hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); hp2_pin_sense = snd_hda_jack_detect(codec, 0x16); - if (hp1_pin_sense || hp2_pin_sense) + if (hp1_pin_sense || hp2_pin_sense) { + alc_disable_headset_jack_key(codec); + /* 3k pull low control for Headset jack. */ + alc_update_coef_idx(codec, 0x4a, 0, 3 << 10); msleep(2); - if (hp1_pin_sense || spec->ultra_low_power) - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp2_pin_sense) - snd_hda_codec_write(codec, 0x16, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power) - msleep(85); + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp1_pin_sense || spec->ultra_low_power) - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - if (hp2_pin_sense) - snd_hda_codec_write(codec, 0x16, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + msleep(75); - if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power) - msleep(100); + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + msleep(75); + alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); + alc_enable_headset_jack_key(codec); + } alc_auto_setup_eapd(codec, false); alc_shutup_pins(codec); if (spec->ultra_low_power) { @@ -3835,9 +3845,79 @@ static void alc225_shutup(struct hda_codec *codec) alc_update_coef_idx(codec, 0x4a, 3<<4, 2<<4); msleep(30); } +} - alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); - alc_enable_headset_jack_key(codec); +static void alc222_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = alc_get_hp_pin(spec); + bool hp1_pin_sense, hp2_pin_sense; + + if (!hp_pin) + return; + + msleep(30); + + hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); + hp2_pin_sense = snd_hda_jack_detect(codec, 0x14); + + if (hp1_pin_sense || hp2_pin_sense) { + msleep(2); + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + msleep(75); + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + + msleep(75); + } +} + +static void alc222_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = alc_get_hp_pin(spec); + bool hp1_pin_sense, hp2_pin_sense; + + if (!hp_pin) + hp_pin = 0x21; + + hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); + hp2_pin_sense = snd_hda_jack_detect(codec, 0x14); + + if (hp1_pin_sense || hp2_pin_sense) { + msleep(2); + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + msleep(75); + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + + msleep(75); + } + alc_auto_setup_eapd(codec, false); + alc_shutup_pins(codec); } static void alc_default_init(struct hda_codec *codec) @@ -3853,20 +3933,18 @@ static void alc_default_init(struct hda_codec *codec) hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); - if (hp_pin_sense) + if (hp_pin_sense) { msleep(2); - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - if (hp_pin_sense) - msleep(85); + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + msleep(75); - if (hp_pin_sense) - msleep(100); + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + msleep(75); + } } static void alc_default_shutup(struct hda_codec *codec) @@ -3882,22 +3960,20 @@ static void alc_default_shutup(struct hda_codec *codec) hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); - if (hp_pin_sense) + if (hp_pin_sense) { msleep(2); - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - if (hp_pin_sense) - msleep(85); - - if (!spec->no_shutup_pins) snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp_pin_sense) - msleep(100); + msleep(75); + if (!spec->no_shutup_pins) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + + msleep(75); + } alc_auto_setup_eapd(codec, false); alc_shutup_pins(codec); } @@ -4039,7 +4115,6 @@ static void alc5505_dsp_init(struct hda_codec *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; @@ -4085,7 +4160,6 @@ static int alc269_resume(struct hda_codec *codec) return 0; } -#endif /* CONFIG_PM */ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -4670,6 +4744,22 @@ static void alc245_fixup_hp_mute_led_coefbit(struct hda_codec *codec, } } +static void alc245_fixup_hp_mute_led_v1_coefbit(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->mute_led_polarity = 0; + spec->mute_led_coef.idx = 0x0b; + spec->mute_led_coef.mask = 1 << 3; + spec->mute_led_coef.on = 1 << 3; + spec->mute_led_coef.off = 0; + snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set); + } +} + /* turn on/off mic-mute LED per capture hook by coef bit */ static int coef_micmute_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) @@ -4720,6 +4810,21 @@ static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec, } } +static void alc295_fixup_hp_mute_led_coefbit11(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->mute_led_polarity = 0; + spec->mute_led_coef.idx = 0xb; + spec->mute_led_coef.mask = 3 << 3; + spec->mute_led_coef.on = 1 << 3; + spec->mute_led_coef.off = 1 << 4; + snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set); + } +} + static void alc285_fixup_hp_mute_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -4802,7 +4907,134 @@ static void alc298_fixup_samsung_amp(struct hda_codec *codec, } } -#if IS_REACHABLE(CONFIG_INPUT) +struct alc298_samsung_v2_amp_desc { + unsigned short nid; + int init_seq_size; + unsigned short init_seq[18][2]; +}; + +static const struct alc298_samsung_v2_amp_desc +alc298_samsung_v2_amp_desc_tbl[] = { + { 0x38, 18, { + { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 }, + { 0x201b, 0x0001 }, { 0x201d, 0x0001 }, { 0x201f, 0x00fe }, + { 0x2021, 0x0000 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 }, + { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e }, + { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x2399, 0x0003 }, + { 0x23a4, 0x00b5 }, { 0x23a5, 0x0001 }, { 0x23ba, 0x0094 } + }}, + { 0x39, 18, { + { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 }, + { 0x201b, 0x0002 }, { 0x201d, 0x0002 }, { 0x201f, 0x00fd }, + { 0x2021, 0x0001 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 }, + { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e }, + { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x2399, 0x0003 }, + { 0x23a4, 0x00b5 }, { 0x23a5, 0x0001 }, { 0x23ba, 0x0094 } + }}, + { 0x3c, 15, { + { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 }, + { 0x201b, 0x0001 }, { 0x201d, 0x0001 }, { 0x201f, 0x00fe }, + { 0x2021, 0x0000 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 }, + { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e }, + { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x23ba, 0x008d } + }}, + { 0x3d, 15, { + { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 }, + { 0x201b, 0x0002 }, { 0x201d, 0x0002 }, { 0x201f, 0x00fd }, + { 0x2021, 0x0001 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 }, + { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e }, + { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x23ba, 0x008d } + }} +}; + +static void alc298_samsung_v2_enable_amps(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + static const unsigned short enable_seq[][2] = { + { 0x203a, 0x0081 }, { 0x23ff, 0x0001 }, + }; + int i, j; + + for (i = 0; i < spec->num_speaker_amps; i++) { + alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid); + for (j = 0; j < ARRAY_SIZE(enable_seq); j++) + alc298_samsung_write_coef_pack(codec, enable_seq[j]); + codec_dbg(codec, "alc298_samsung_v2: Enabled speaker amp 0x%02x\n", + alc298_samsung_v2_amp_desc_tbl[i].nid); + } +} + +static void alc298_samsung_v2_disable_amps(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + static const unsigned short disable_seq[][2] = { + { 0x23ff, 0x0000 }, { 0x203a, 0x0080 }, + }; + int i, j; + + for (i = 0; i < spec->num_speaker_amps; i++) { + alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid); + for (j = 0; j < ARRAY_SIZE(disable_seq); j++) + alc298_samsung_write_coef_pack(codec, disable_seq[j]); + codec_dbg(codec, "alc298_samsung_v2: Disabled speaker amp 0x%02x\n", + alc298_samsung_v2_amp_desc_tbl[i].nid); + } +} + +static void alc298_samsung_v2_playback_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + /* Dynamically enable/disable speaker amps before and after playback */ + if (action == HDA_GEN_PCM_ACT_OPEN) + alc298_samsung_v2_enable_amps(codec); + if (action == HDA_GEN_PCM_ACT_CLOSE) + alc298_samsung_v2_disable_amps(codec); +} + +static void alc298_samsung_v2_init_amps(struct hda_codec *codec, + int num_speaker_amps) +{ + struct alc_spec *spec = codec->spec; + int i, j; + + /* Set spec's num_speaker_amps before doing anything else */ + spec->num_speaker_amps = num_speaker_amps; + + /* Disable speaker amps before init to prevent any physical damage */ + alc298_samsung_v2_disable_amps(codec); + + /* Initialize the speaker amps */ + for (i = 0; i < spec->num_speaker_amps; i++) { + alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid); + for (j = 0; j < alc298_samsung_v2_amp_desc_tbl[i].init_seq_size; j++) { + alc298_samsung_write_coef_pack(codec, + alc298_samsung_v2_amp_desc_tbl[i].init_seq[j]); + } + alc_write_coef_idx(codec, 0x89, 0x0); + codec_dbg(codec, "alc298_samsung_v2: Initialized speaker amp 0x%02x\n", + alc298_samsung_v2_amp_desc_tbl[i].nid); + } + + /* register hook to enable speaker amps only when they are needed */ + spec->gen.pcm_playback_hook = alc298_samsung_v2_playback_hook; +} + +static void alc298_fixup_samsung_amp_v2_2_amps(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PROBE) + alc298_samsung_v2_init_amps(codec, 2); +} + +static void alc298_fixup_samsung_amp_v2_4_amps(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PROBE) + alc298_samsung_v2_init_amps(codec, 4); +} + static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) { @@ -4911,10 +5143,6 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, spec->kb_dev = NULL; } } -#else /* INPUT */ -#define alc280_fixup_hp_gpio2_mic_hotkey NULL -#define alc233_fixup_lenovo_line2_mic_hotkey NULL -#endif /* INPUT */ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -4928,6 +5156,40 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, } } +static void alc233_fixup_lenovo_low_en_micmute_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->micmute_led_polarity = 1; + alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action); +} + +static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay) +{ + if (delay <= 0) + delay = 75; + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + msleep(delay); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + msleep(delay); +} + +static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay) +{ + if (delay <= 0) + delay = 75; + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + msleep(delay); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + msleep(delay); +} + static const struct coef_fw alc225_pre_hsmode[] = { UPDATE_COEF(0x4a, 1<<8, 0), UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), @@ -5029,6 +5291,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0236: case 0x10ec0256: case 0x19e58326: + alc_hp_mute_disable(codec, 75); alc_process_coef_fw(codec, coef0256); break; case 0x10ec0234: @@ -5063,6 +5326,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0295: case 0x10ec0289: case 0x10ec0299: + alc_hp_mute_disable(codec, 75); alc_process_coef_fw(codec, alc225_pre_hsmode); alc_process_coef_fw(codec, coef0225); break; @@ -5288,6 +5552,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) case 0x10ec0299: alc_process_coef_fw(codec, alc225_pre_hsmode); alc_process_coef_fw(codec, coef0225); + alc_hp_enable_unmute(codec, 75); break; case 0x10ec0255: alc_process_coef_fw(codec, coef0255); @@ -5300,6 +5565,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) alc_write_coef_idx(codec, 0x45, 0xc089); msleep(50); alc_process_coef_fw(codec, coef0256); + alc_hp_enable_unmute(codec, 75); break; case 0x10ec0234: case 0x10ec0274: @@ -5397,6 +5663,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) case 0x10ec0256: case 0x19e58326: alc_process_coef_fw(codec, coef0256); + alc_hp_enable_unmute(codec, 75); break; case 0x10ec0234: case 0x10ec0274: @@ -5445,6 +5712,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) alc_process_coef_fw(codec, coef0225_2); else alc_process_coef_fw(codec, coef0225_1); + alc_hp_enable_unmute(codec, 75); break; case 0x10ec0867: alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); @@ -5512,6 +5780,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0256: case 0x19e58326: alc_process_coef_fw(codec, coef0256); + alc_hp_enable_unmute(codec, 75); break; case 0x10ec0234: case 0x10ec0274: @@ -5549,6 +5818,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0289: case 0x10ec0299: alc_process_coef_fw(codec, coef0225); + alc_hp_enable_unmute(codec, 75); break; } codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); @@ -5617,25 +5887,21 @@ static void alc_determine_headset_type(struct hda_codec *codec) alc_write_coef_idx(codec, 0x06, 0x6104); alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - msleep(80); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - alc_process_coef_fw(codec, coef0255); msleep(300); val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; - + if (!is_ctia) { + alc_write_coef_idx(codec, 0x45, 0xe089); + msleep(100); + val = alc_read_coef_idx(codec, 0x46); + if ((val & 0x0070) == 0x0070) + is_ctia = false; + else + is_ctia = true; + } alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3); alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); - - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - msleep(80); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); break; case 0x10ec0234: case 0x10ec0274: @@ -5712,12 +5978,6 @@ static void alc_determine_headset_type(struct hda_codec *codec) case 0x10ec0295: case 0x10ec0289: case 0x10ec0299: - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - msleep(80); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - alc_process_coef_fw(codec, alc225_pre_hsmode); alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000); val = alc_read_coef_idx(codec, 0x45); @@ -5734,15 +5994,19 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x00f0) == 0x00f0; } + if (!is_ctia) { + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10); + alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8); + msleep(100); + val = alc_read_coef_idx(codec, 0x46); + if ((val & 0x00f0) == 0x00f0) + is_ctia = false; + else + is_ctia = true; + } alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6); alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4); alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); - - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - msleep(80); - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); break; case 0x10ec0867: is_ctia = true; @@ -5750,7 +6014,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) } codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", - is_ctia ? "yes" : "no"); + str_yes_no(is_ctia)); spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP; } @@ -6339,6 +6603,17 @@ static void alc285_fixup_speaker2_to_dac1(struct hda_codec *codec, } } +/* disable DAC3 (0x06) selection on NID 0x15 - share Speaker/Bass Speaker DAC 0x03 */ +static void alc294_fixup_bass_speaker_15(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + static const hda_nid_t conn[] = { 0x02, 0x03 }; + snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn); + snd_hda_gen_add_micmute_led_cdev(codec, NULL); + } +} + /* Hook to update amp GPIO4 for automute */ static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec, struct hda_jack_callback *jack) @@ -6469,6 +6744,25 @@ static void alc274_fixup_bind_dacs(struct hda_codec *codec, codec->power_save_node = 0; } +/* avoid DAC 0x06 for speaker switch 0x17; it has no volume control */ +static void alc274_fixup_hp_aio_bind_dacs(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */ + /* The speaker is routed to the Node 0x06 by a mistake, thus the + * speaker's volume can't be adjusted since the node doesn't have + * Amp-out capability. Assure the speaker and lineout pin to be + * coupled with DAC NID 0x02. + */ + static const hda_nid_t preferred_pairs[] = { + 0x16, 0x02, 0x17, 0x02, 0x21, 0x03, 0 + }; + struct alc_spec *spec = codec->spec; + + snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); + spec->gen.preferred_dacs = preferred_pairs; +} + /* avoid DAC 0x06 for bass speaker 0x17; it has no volume control */ static void alc289_fixup_asus_ga401(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -6478,10 +6772,8 @@ static void alc289_fixup_asus_ga401(struct hda_codec *codec, }; struct alc_spec *spec = codec->spec; - if (action == HDA_FIXUP_ACT_PRE_PROBE) { + if (action == HDA_FIXUP_ACT_PRE_PROBE) spec->gen.preferred_dacs = preferred_pairs; - spec->gen.obey_preferred_dacs = 1; - } } /* The DAC of NID 0x3 will introduce click/pop noise on headphones, so invalidate it */ @@ -6533,6 +6825,23 @@ static void alc295_fixup_chromebook(struct hda_codec *codec, } } +static void alc256_fixup_chromebook(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + if (codec->core.subsystem_id == 0x10280d76) + spec->gen.suppress_auto_mute = 0; + else + spec->gen.suppress_auto_mute = 1; + spec->gen.suppress_auto_mic = 1; + spec->en_3kpull_low = false; + break; + } +} + static void alc_fixup_disable_mic_vref(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -6678,6 +6987,41 @@ static void alc285_fixup_hp_spectre_x360_eb1(struct hda_codec *codec, } } +/* GPIO1 = amplifier on/off */ +static void alc285_fixup_hp_spectre_x360_df1(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + static const hda_nid_t conn[] = { 0x02 }; + static const struct hda_pintbl pincfgs[] = { + { 0x14, 0x90170110 }, /* front/high speakers */ + { 0x17, 0x90170130 }, /* back/bass speakers */ + { } + }; + + // enable mute led + alc285_fixup_hp_mute_led_coefbit(codec, fix, action); + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + /* needed for amp of back speakers */ + spec->gpio_mask |= 0x01; + spec->gpio_dir |= 0x01; + snd_hda_apply_pincfgs(codec, pincfgs); + /* share DAC to have unified volume control */ + snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn); + snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); + break; + case HDA_FIXUP_ACT_INIT: + /* need to toggle GPIO to enable the amp of back speakers */ + alc_update_gpio_data(codec, 0x01, true); + msleep(100); + alc_update_gpio_data(codec, 0x01, false); + break; + } +} + static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -6750,6 +7094,30 @@ static void alc285_fixup_hp_envy_x360(struct hda_codec *codec, } } +static void alc285_fixup_hp_beep(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + codec->beep_just_power_on = true; + } else if (action == HDA_FIXUP_ACT_INIT) { +#ifdef CONFIG_SND_HDA_INPUT_BEEP + /* + * Just enable loopback to internal speaker and headphone jack. + * Disable amplification to get about the same beep volume as + * was on pure BIOS setup before loading the driver. + */ + alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13)); + + snd_hda_enable_beep_device(codec, 1); + +#if !IS_ENABLED(CONFIG_INPUT_PCSPKR) + dev_warn_once(hda_codec_dev(codec), + "enable CONFIG_INPUT_PCSPKR to get PC beeps\n"); +#endif +#endif + } +} + /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" @@ -6760,6 +7128,15 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, hda_fixup_thinkpad_acpi(codec, fix, action); } +/* for hda_fixup_ideapad_acpi() */ +#include "ideapad_hotkey_led_helper.c" + +static void alc_fixup_ideapad_acpi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + hda_fixup_ideapad_acpi(codec, fix, action); +} + /* Fixup for Lenovo Legion 15IMHg05 speaker output on headset removal. */ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec, const struct hda_fixup *fix, @@ -6781,8 +7158,7 @@ static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data) codec_info(cdc, "ACPI Notification %d\n", event); - hda_component_acpi_device_notify(spec->comps, ARRAY_SIZE(spec->comps), - handle, event, data); + hda_component_acpi_device_notify(&spec->comps, handle, event, data); } static int comp_bind(struct device *dev) @@ -6791,12 +7167,12 @@ static int comp_bind(struct device *dev) struct alc_spec *spec = cdc->spec; int ret; - ret = hda_component_manager_bind(cdc, spec->comps); + ret = hda_component_manager_bind(cdc, &spec->comps); if (ret) return ret; return hda_component_manager_bind_acpi_notifications(cdc, - spec->comps, ARRAY_SIZE(spec->comps), + &spec->comps, comp_acpi_device_notify, cdc); } @@ -6805,8 +7181,8 @@ static void comp_unbind(struct device *dev) struct hda_codec *cdc = dev_to_hda_codec(dev); struct alc_spec *spec = cdc->spec; - hda_component_manager_unbind_acpi_notifications(cdc, spec->comps, comp_acpi_device_notify); - hda_component_manager_unbind(cdc, spec->comps); + hda_component_manager_unbind_acpi_notifications(cdc, &spec->comps, comp_acpi_device_notify); + hda_component_manager_unbind(cdc, &spec->comps); } static const struct component_master_ops comp_master_ops = { @@ -6819,7 +7195,7 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_ { struct alc_spec *spec = cdc->spec; - hda_component_manager_playback_hook(spec->comps, ARRAY_SIZE(spec->comps), action); + hda_component_manager_playback_hook(&spec->comps, action); } static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus, @@ -6830,7 +7206,7 @@ static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bu switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: - ret = hda_component_manager_init(cdc, spec->comps, count, bus, hid, + ret = hda_component_manager_init(cdc, &spec->comps, count, bus, hid, match_str, &comp_master_ops); if (ret) return; @@ -6838,11 +7214,75 @@ static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bu spec->gen.pcm_playback_hook = comp_generic_playback_hook; break; case HDA_FIXUP_ACT_FREE: - hda_component_manager_free(cdc, &comp_master_ops); + hda_component_manager_free(&spec->comps, &comp_master_ops); break; } } +static void find_cirrus_companion_amps(struct hda_codec *cdc) +{ + struct device *dev = hda_codec_dev(cdc); + struct acpi_device *adev; + struct fwnode_handle *fwnode __free(fwnode_handle) = NULL; + const char *bus = NULL; + static const struct { + const char *hid; + const char *name; + } acpi_ids[] = {{ "CSC3554", "cs35l54-hda" }, + { "CSC3556", "cs35l56-hda" }, + { "CSC3557", "cs35l57-hda" }}; + char *match; + int i, count = 0, count_devindex = 0; + + for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) { + adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid, NULL, -1); + if (adev) + break; + } + if (!adev) { + codec_dbg(cdc, "Did not find ACPI entry for a Cirrus Amp\n"); + return; + } + + count = i2c_acpi_client_count(adev); + if (count > 0) { + bus = "i2c"; + } else { + count = acpi_spi_count_resources(adev); + if (count > 0) + bus = "spi"; + } + + fwnode = fwnode_handle_get(acpi_fwnode_handle(adev)); + acpi_dev_put(adev); + + if (!bus) { + codec_err(cdc, "Did not find any buses for %s\n", acpi_ids[i].hid); + return; + } + + if (!fwnode) { + codec_err(cdc, "Could not get fwnode for %s\n", acpi_ids[i].hid); + return; + } + + /* + * When available the cirrus,dev-index property is an accurate + * count of the amps in a system and is used in preference to + * the count of bus devices that can contain additional address + * alias entries. + */ + count_devindex = fwnode_property_count_u32(fwnode, "cirrus,dev-index"); + if (count_devindex > 0) + count = count_devindex; + + match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-%s.%%d", acpi_ids[i].name); + if (!match) + return; + codec_info(cdc, "Found %d %s on %s (%s)\n", count, acpi_ids[i].hid, bus, match); + comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count); +} + static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2); @@ -6875,9 +7315,14 @@ static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const st comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2); } -static void cs35l56_fixup_spi_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action) +static void alc285_fixup_asus_ga403u(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { - comp_generic_fixup(cdc, action, "spi", "CSC3556", "-%s:00-cs35l56-hda.%d", 4); + /* + * The same SSID has been re-used in different hardware, they have + * different codecs and the newer GA403U has a ALC285. + */ + if (cdc->core.vendor_id != 0x10ec0285) + alc_fixup_inv_dmic(cdc, fix, action); } static void tas2781_fixup_i2c(struct hda_codec *cdc, @@ -6886,6 +7331,11 @@ static void tas2781_fixup_i2c(struct hda_codec *cdc, comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1); } +static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix, int action) +{ + comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2); +} + static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { @@ -7047,6 +7497,9 @@ static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec, }; struct alc_spec *spec = codec->spec; + /* Support Audio mute LED and Mic mute LED on keyboard */ + hda_fixup_ideapad_acpi(codec, fix, action); + switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: snd_hda_apply_pincfgs(codec, pincfgs); @@ -7156,6 +7609,121 @@ static void alc245_fixup_hp_spectre_x360_eu0xxx(struct hda_codec *codec, alc245_fixup_hp_gpio_led(codec, fix, action); } +/* some changes for Spectre x360 16, 2024 model */ +static void alc245_fixup_hp_spectre_x360_16_aa0xxx(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* + * The Pin Complex 0x14 for the treble speakers is wrongly reported as + * unconnected. + * The Pin Complex 0x17 for the bass speakers has the lowest association + * and sequence values so shift it up a bit to squeeze 0x14 in. + */ + struct alc_spec *spec = codec->spec; + static const struct hda_pintbl pincfgs[] = { + { 0x14, 0x90170110 }, // top/treble + { 0x17, 0x90170111 }, // bottom/bass + { } + }; + + /* + * Force DAC 0x02 for the bass speakers 0x17. + */ + static const hda_nid_t conn[] = { 0x02 }; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + /* needed for amp of back speakers */ + spec->gpio_mask |= 0x01; + spec->gpio_dir |= 0x01; + snd_hda_apply_pincfgs(codec, pincfgs); + snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); + break; + case HDA_FIXUP_ACT_INIT: + /* need to toggle GPIO to enable the amp of back speakers */ + alc_update_gpio_data(codec, 0x01, true); + msleep(100); + alc_update_gpio_data(codec, 0x01, false); + break; + } + + cs35l41_fixup_i2c_two(codec, fix, action); + alc245_fixup_hp_mute_led_coefbit(codec, fix, action); + alc245_fixup_hp_gpio_led(codec, fix, action); +} + +static void alc245_fixup_hp_zbook_firefly_g12a(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const hda_nid_t conn[] = { 0x02 }; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->gen.auto_mute_via_amp = 1; + snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); + break; + } + + cs35l41_fixup_i2c_two(codec, fix, action); + alc245_fixup_hp_mute_led_coefbit(codec, fix, action); + alc285_fixup_hp_coef_micmute_led(codec, fix, action); +} + +/* + * ALC287 PCM hooks + */ +static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */ + break; + case HDA_GEN_PCM_ACT_CLOSE: + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */ + break; + } +} + +static void alc287_s4_power_gpio3_default(struct hda_codec *codec) +{ + if (is_s4_suspend(codec)) { + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */ + } +} + +static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const struct coef_fw coefs[] = { + WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC300), + WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023), + WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301), + WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023), + }; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11); + alc_process_coef_fw(codec, coefs); + spec->power_hook = alc287_s4_power_gpio3_default; + spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook; +} + +/* + * Clear COEF 0x0d (PCBEEP passthrough) bit 0x40 where BIOS sets it wrongly + * at PM resume + */ +static void alc283_fixup_dell_hp_resume(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_INIT) + alc_write_coef_idx(codec, 0xd, 0x2800); +} enum { ALC269_FIXUP_GPIO2, @@ -7197,6 +7765,7 @@ enum { ALC286_FIXUP_SONY_MIC_NO_PRESENCE, ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT, ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST, ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, @@ -7225,12 +7794,17 @@ enum { ALC290_FIXUP_MONO_SPEAKERS_HSJACK, ALC290_FIXUP_SUBWOOFER, ALC290_FIXUP_SUBWOOFER_HSJACK, + ALC295_FIXUP_HP_MUTE_LED_COEFBIT11, ALC269_FIXUP_THINKPAD_ACPI, + ALC269_FIXUP_LENOVO_XPAD_ACPI, ALC269_FIXUP_DMIC_THINKPAD_ACPI, + ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13, + ALC269VC_FIXUP_INFINIX_Y4_MAX, ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO, ALC255_FIXUP_ACER_MIC_NO_PRESENCE, ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST, ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, ALC255_FIXUP_HEADSET_MODE, ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, @@ -7249,6 +7823,7 @@ enum { ALC280_FIXUP_HP_9480M, ALC245_FIXUP_HP_X360_AMP, ALC285_FIXUP_HP_SPECTRE_X360_EB1, + ALC285_FIXUP_HP_SPECTRE_X360_DF1, ALC285_FIXUP_HP_ENVY_X360, ALC288_FIXUP_DELL_HEADSET_MODE, ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, @@ -7264,6 +7839,7 @@ enum { ALC275_FIXUP_DELL_XPS, ALC293_FIXUP_LENOVO_SPK_NOISE, ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, + ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED, ALC255_FIXUP_DELL_SPK_NOISE, ALC225_FIXUP_DISABLE_MIC_VREF, ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, @@ -7321,6 +7897,7 @@ enum { ALC286_FIXUP_ACER_AIO_HEADSET_MIC, ALC256_FIXUP_ASUS_HEADSET_MIC, ALC256_FIXUP_ASUS_MIC_NO_PRESENCE, + ALC255_FIXUP_PREDATOR_SUBWOOFER, ALC299_FIXUP_PREDATOR_SPK, ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, ALC289_FIXUP_DELL_SPK1, @@ -7348,11 +7925,15 @@ enum { ALC285_FIXUP_HP_GPIO_LED, ALC285_FIXUP_HP_MUTE_LED, ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED, + ALC285_FIXUP_HP_BEEP_MICMUTE_LED, ALC236_FIXUP_HP_MUTE_LED_COEFBIT2, ALC236_FIXUP_HP_GPIO_LED, ALC236_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, + ALC236_FIXUP_LENOVO_INV_DMIC, ALC298_FIXUP_SAMSUNG_AMP, + ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS, + ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, @@ -7376,6 +7957,7 @@ enum { ALC274_FIXUP_HP_MIC, ALC274_FIXUP_HP_HEADSET_MIC, ALC274_FIXUP_HP_ENVY_GPIO, + ALC274_FIXUP_ASUS_ZEN_AIO_27, ALC256_FIXUP_ASUS_HPE, ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, ALC287_FIXUP_HP_GPIO_LED, @@ -7398,7 +7980,6 @@ enum { ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE, ALC287_FIXUP_YOGA7_14ITL_SPEAKERS, ALC298_FIXUP_LENOVO_C940_DUET7, - ALC287_FIXUP_LENOVO_14IRP8_DUETITL, ALC287_FIXUP_13S_GEN2_SPEAKERS, ALC256_FIXUP_SET_COEF_DEFAULTS, ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, @@ -7424,18 +8005,39 @@ enum { ALC236_FIXUP_DELL_DUAL_CODECS, ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI, ALC287_FIXUP_TAS2781_I2C, + ALC245_FIXUP_TAS2781_SPI_2, ALC287_FIXUP_YOGA7_14ARB7_I2C, ALC245_FIXUP_HP_MUTE_LED_COEFBIT, + ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT, ALC245_FIXUP_HP_X360_MUTE_LEDS, ALC287_FIXUP_THINKPAD_I2S_SPK, ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD, ALC2XX_FIXUP_HEADSET_MIC, ALC289_FIXUP_DELL_CS35L41_SPI_2, ALC294_FIXUP_CS35L41_I2C_2, - ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED, ALC256_FIXUP_ACER_SFG16_MICMUTE_LED, ALC256_FIXUP_HEADPHONE_AMP_VOL, ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX, + ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX, + ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A, + ALC285_FIXUP_ASUS_GA403U, + ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC, + ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1, + ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC, + ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1, + ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318, + ALC256_FIXUP_CHROME_BOOK, + ALC245_FIXUP_CLEVO_NOISY_MIC, + ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE, + ALC233_FIXUP_MEDION_MTL_SPK, + ALC294_FIXUP_BASS_SPEAKER_15, + ALC283_FIXUP_DELL_HP_RESUME, + ALC294_FIXUP_ASUS_CS35L41_SPI_2, + ALC274_FIXUP_HP_AIO_BIND_DACS, + ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2, + ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC, + ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1, + ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC, }; /* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -7455,26 +8057,6 @@ static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec, __snd_hda_apply_fixup(codec, id, action, 0); } -/* A special fixup for Lenovo Slim/Yoga Pro 9 14IRP8 and Yoga DuetITL 2021; - * 14IRP8 PCI SSID will mistakenly be matched with the DuetITL codec SSID, - * so we need to apply a different fixup in this case. The only DuetITL codec - * SSID reported so far is the 17aa:3802 while the 14IRP8 has the 17aa:38be - * and 17aa:38bf. If it weren't for the PCI SSID, the 14IRP8 models would - * have matched correctly by their codecs. - */ -static void alc287_fixup_lenovo_14irp8_duetitl(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa3802) - id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* DuetITL */ - else - id = ALC287_FIXUP_TAS2781_I2C; /* 14IRP8 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - static const struct hda_fixup alc269_fixups[] = { [ALC269_FIXUP_GPIO2] = { .type = HDA_FIXUP_FUNC, @@ -7609,6 +8191,25 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_pincfg_U7x7_headset_mic, }, + [ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x90170151 }, /* use as internal speaker (LFE) */ + { 0x1b, 0x90170152 }, /* use as internal speaker (back) */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + }, + [ALC269VC_FIXUP_INFINIX_Y4_MAX] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170150 }, /* use as internal speaker */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + }, [ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -7727,6 +8328,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MODE }, + [ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE + }, [ALC269_FIXUP_DELL2_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -7973,6 +8580,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_SKU_IGNORE, }, + [ALC269_FIXUP_LENOVO_XPAD_ACPI] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_ideapad_acpi, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, [ALC269_FIXUP_DMIC_THINKPAD_ACPI] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic, @@ -8007,6 +8620,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC255_FIXUP_HEADSET_MODE }, + [ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, [ALC255_FIXUP_DELL2_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -8224,6 +8843,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_fixup_lenovo_line2_mic_hotkey, }, + [ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc233_fixup_lenovo_low_en_micmute_led, + }, [ALC233_FIXUP_INTEL_NUC8_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic, @@ -8673,6 +9296,13 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE }, + [ALC255_FIXUP_PREDATOR_SUBWOOFER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x17, 0x90170151 }, /* use as internal speaker (LFE) */ + { 0x1b, 0x90170152 } /* use as internal speaker (back) */ + } + }, [ALC299_FIXUP_PREDATOR_SPK] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -8680,6 +9310,12 @@ static const struct hda_fixup alc269_fixups[] = { { } } }, + [ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_i2c_two, + .chained = true, + .chain_id = ALC255_FIXUP_PREDATOR_SUBWOOFER + }, [ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -8898,6 +9534,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc285_fixup_hp_spectre_x360_mute_led, }, + [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_beep, + .chained = true, + .chain_id = ALC285_FIXUP_HP_MUTE_LED, + }, [ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = { .type = HDA_FIXUP_FUNC, .v.func = alc236_fixup_hp_mute_led_coefbit2, @@ -8914,12 +9556,30 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc236_fixup_hp_mute_led_micmute_vref, }, + [ALC236_FIXUP_LENOVO_INV_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + .chained = true, + .chain_id = ALC283_FIXUP_INT_MIC, + }, + [ALC295_FIXUP_HP_MUTE_LED_COEFBIT11] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc295_fixup_hp_mute_led_coefbit11, + }, [ALC298_FIXUP_SAMSUNG_AMP] = { .type = HDA_FIXUP_FUNC, .v.func = alc298_fixup_samsung_amp, .chained = true, .chain_id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET }, + [ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc298_fixup_samsung_amp_v2_2_amps + }, + [ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc298_fixup_samsung_amp_v2_4_amps + }, [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -9130,6 +9790,26 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc274_fixup_hp_envy_gpio, }, + [ALC274_FIXUP_ASUS_ZEN_AIO_27] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x10 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xc420 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x40 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x8800 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0249 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x202b }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x62 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xa007 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x5060 }, + {} + }, + .chained = true, + .chain_id = ALC2XX_FIXUP_HEADSET_MIC, + }, [ALC256_FIXUP_ASUS_HPE] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -9231,6 +9911,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc285_fixup_hp_spectre_x360_eb1 }, + [ALC285_FIXUP_HP_SPECTRE_X360_DF1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_spectre_x360_df1 + }, [ALC285_FIXUP_HP_ENVY_X360] = { .type = HDA_FIXUP_FUNC, .v.func = alc285_fixup_hp_envy_x360, @@ -9365,10 +10049,6 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc298_fixup_lenovo_c940_duet7, }, - [ALC287_FIXUP_LENOVO_14IRP8_DUETITL] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_14irp8_duetitl, - }, [ALC287_FIXUP_13S_GEN2_SPEAKERS] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -9583,6 +10263,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK, }, + [ALC245_FIXUP_TAS2781_SPI_2] = { + .type = HDA_FIXUP_FUNC, + .v.func = tas2781_fixup_spi, + .chained = true, + .chain_id = ALC285_FIXUP_HP_GPIO_LED, + }, [ALC287_FIXUP_YOGA7_14ARB7_I2C] = { .type = HDA_FIXUP_FUNC, .v.func = yoga7_14arb7_fixup_i2c, @@ -9593,6 +10279,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc245_fixup_hp_mute_led_coefbit, }, + [ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc245_fixup_hp_mute_led_v1_coefbit, + }, [ALC245_FIXUP_HP_X360_MUTE_LEDS] = { .type = HDA_FIXUP_FUNC, .v.func = alc245_fixup_hp_mute_led_coefbit, @@ -9625,12 +10315,6 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = cs35l41_fixup_i2c_two, }, - [ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED] = { - .type = HDA_FIXUP_FUNC, - .v.func = cs35l56_fixup_spi_four, - .chained = true, - .chain_id = ALC285_FIXUP_HP_GPIO_LED, - }, [ALC256_FIXUP_ACER_SFG16_MICMUTE_LED] = { .type = HDA_FIXUP_FUNC, .v.func = alc256_fixup_acer_sfg16_micmute_led, @@ -9643,9 +10327,124 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc245_fixup_hp_spectre_x360_eu0xxx, }, + [ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc245_fixup_hp_spectre_x360_16_aa0xxx, + }, + [ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc245_fixup_hp_zbook_firefly_g12a, + }, + [ALC285_FIXUP_ASUS_GA403U] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_asus_ga403u, + }, + [ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a11050 }, + { 0x1b, 0x03a11c30 }, + { } + }, + .chained = true, + .chain_id = ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1 + }, + [ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_speaker2_to_dac1, + .chained = true, + .chain_id = ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC, + }, + [ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a11050 }, + { 0x1b, 0x03a11c30 }, + { } + }, + }, + [ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_speaker2_to_dac1, + .chained = true, + .chain_id = ALC285_FIXUP_ASUS_GA403U, + }, + [ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc287_fixup_lenovo_thinkpad_with_alc1318, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI + }, + [ALC256_FIXUP_CHROME_BOOK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc256_fixup_chromebook, + .chained = true, + .chain_id = ALC225_FIXUP_HEADSET_JACK + }, + [ALC245_FIXUP_CLEVO_NOISY_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, + }, + [ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */ + { 0x1b, 0x20a11040 }, /* dock mic */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + }, + [ALC233_FIXUP_MEDION_MTL_SPK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170110 }, + { } + }, + }, + [ALC294_FIXUP_BASS_SPEAKER_15] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc294_fixup_bass_speaker_15, + }, + [ALC283_FIXUP_DELL_HP_RESUME] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc283_fixup_dell_hp_resume, + }, + [ALC294_FIXUP_ASUS_CS35L41_SPI_2] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l41_fixup_spi_two, + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC, + }, + [ALC274_FIXUP_HP_AIO_BIND_DACS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc274_fixup_hp_aio_bind_dacs, + }, + [ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a11050 }, + { 0x1b, 0x03a11c30 }, + { } + }, + .chained = true, + .chain_id = ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1 + }, + [ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_speaker2_to_dac1, + }, + [ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE, + }, }; -static const struct snd_pci_quirk alc269_fixup_tbl[] = { +static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), @@ -9658,6 +10457,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF), + SND_PCI_QUIRK(0x1025, 0x100c, "Acer Aspire E5-574G", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC), @@ -9667,6 +10467,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x110e, "Acer Aspire ES1-432", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1166, "Acer Veriton N4640G", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x1025, 0x1167, "Acer Veriton N6640G", ALC269_FIXUP_LIFEBOOK), + SND_PCI_QUIRK(0x1025, 0x1177, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER), + SND_PCI_QUIRK(0x1025, 0x1178, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER), SND_PCI_QUIRK(0x1025, 0x1246, "Acer Predator Helios 500", ALC299_FIXUP_PREDATOR_SPK), SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS), SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE), @@ -9681,12 +10483,17 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1330, "Acer TravelMate X514-51T", ALC255_FIXUP_ACER_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x1360, "Acer Aspire A115", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x141f, "Acer Spin SP513-54N", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x142b, "Acer Swift SF314-42", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), + SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), @@ -9698,6 +10505,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), 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, 0x0604, "Dell Venue 11 Pro 7130", ALC283_FIXUP_DELL_HP_RESUME), 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, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X), @@ -9729,6 +10537,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC), SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC), SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB), + SND_PCI_QUIRK(0x1028, 0x0879, "Dell Latitude 5420 Rugged", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), @@ -9763,6 +10572,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0c1e, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c28, "Dell Inspiron 16 Plus 7630", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS), SND_PCI_QUIRK(0x1028, 0x0c4d, "Dell", ALC287_FIXUP_CS35L41_I2C_4), + SND_PCI_QUIRK(0x1028, 0x0c94, "Dell Polaris 3 metal", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1028, 0x0c96, "Dell Polaris 2in1", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x1028, 0x0cbd, "Dell Oasis 13 CS MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2), SND_PCI_QUIRK(0x1028, 0x0cbe, "Dell Oasis 13 2-IN-1 MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2), SND_PCI_QUIRK(0x1028, 0x0cbf, "Dell Oasis 13 Low Weight MTU-L", ALC289_FIXUP_DELL_CS35L41_SPI_2), @@ -9845,17 +10656,21 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x841c, "HP Pavilion 15-CK0xx", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3), + SND_PCI_QUIRK(0x103c, 0x84a6, "HP 250 G7 Notebook PC", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x84ae, "HP 15-db0403ng", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN), SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360), SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11), SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360), SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), + SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1), SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), @@ -9866,7 +10681,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT), - SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED), SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED), @@ -9879,6 +10694,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x87d3, "HP Laptop 15-gw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x87df, "HP ProBook 430 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f1, "HP ProBook 630 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), @@ -9887,12 +10704,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f6, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), + SND_PCI_QUIRK(0x103c, 0x87fd, "HP Laptop 14-dq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x87fe, "HP Laptop 15s-fq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8805, "HP ProBook 650 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x880d, "HP EliteBook 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8811, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), SND_PCI_QUIRK(0x103c, 0x8812, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), SND_PCI_QUIRK(0x103c, 0x881d, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x881e, "HP Laptop 15s-du3xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), @@ -9903,12 +10722,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8870, "HP ZBook Fury 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8873, "HP ZBook Studio 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x887a, "HP Laptop 15s-eq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x887c, "HP Laptop 14s-fq1xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x888a, "HP ENVY x360 Convertible 15-eu0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), SND_PCI_QUIRK(0x103c, 0x888d, "HP ZBook Power 15.6 inch G8 Mobile Workstation PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8895, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED), SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x88dd, "HP Pavilion 15z-ec200", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8902, "HP OMEN 16", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x890e, "HP 255 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8919, "HP Pavilion Aero Laptop 13-be0xxx", ALC287_FIXUP_HP_GPIO_LED), @@ -9921,6 +10742,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8975, "HP EliteBook x360 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x897d, "HP mt440 Mobile Thin Client U74", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8981, "HP Elite Dragonfly G3", ALC245_FIXUP_CS35L41_SPI_4), + SND_PCI_QUIRK(0x103c, 0x898a, "HP Pavilion 15-eg100", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x898e, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x898f, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8991, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), @@ -9948,7 +10770,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8a2c, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4), @@ -9976,6 +10797,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8b59, "HP Elite mt645 G7 Mobile Thin Client U89", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8b5f, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b63, "HP Elite Dragonfly 13.5 inch G4", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b65, "HP ProBook 455 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b66, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), @@ -9993,6 +10815,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8bbe, "HP Victus 16-r0xxx (MB 8BBE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), + SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), + SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), @@ -10007,17 +10834,21 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX), - SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX), SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c21, "HP Pavilion Plus Laptop 14-ey0XXX", ALC245_FIXUP_HP_X360_MUTE_LEDS), + SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c4d, "HP Omen", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c4e, "HP Omen", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8c4f, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8c50, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8c51, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c66, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8c67, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8c68, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), @@ -10025,46 +10856,132 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c7b, "HP ProBook 445 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c7c, "HP ProBook 445 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c7d, "HP ProBook 465 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c7e, "HP ProBook 465 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c7f, "HP EliteBook 645 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c80, "HP EliteBook 645 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c81, "HP EliteBook 665 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c89, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c8a, "HP EliteBook 630", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c8c, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c8d, "HP ProBook 440 G11", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c8e, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c90, "HP EliteBook 640", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8c9c, "HP Victus 16-s1xxx (MB 8C9C)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8caf, "HP Elite mt645 G8 Mobile Thin Client", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8cbd, "HP Pavilion Aero Laptop 13-bg0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), + SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX), + SND_PCI_QUIRK(0x103c, 0x8cde, "HP OmniBook Ultra Flip Laptop 14t", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX), + SND_PCI_QUIRK(0x103c, 0x8cdf, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ce0, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d07, "HP Victus 15-fb2xxx (MB 8D07)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), + SND_PCI_QUIRK(0x103c, 0x8d18, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS), + SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d85, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d86, "HP Elite X360 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d8c, "HP EliteBook 13 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d8d, "HP Elite X360 13 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d8e, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d8f, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8d9e, "HP 17 Turbine OmniBook X DIS", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8d9f, "HP 14 Cadet (x360)", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8da0, "HP 16 Clipper OmniBook 7(X360)", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8da1, "HP 16 Clipper OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8da7, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8da8, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8dd4, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS), + SND_PCI_QUIRK(0x103c, 0x8de8, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8de9, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8dec, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ded, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8dee, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8def, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8df0, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8df1, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8dfb, "HP EliteBook 6 G1a 14", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8dfd, "HP EliteBook 6 G1a 16", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8dfe, "HP EliteBook 665 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e11, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e12, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e13, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e14, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e15, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e16, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e17, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e1b, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e1c, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e1d, "HP ZBook X Gli 16 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e2c, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e36, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e37, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e3a, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e3b, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), + SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1043, 0x106f, "ASUS VivoBook X515UA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1074, "ASUS G614PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK), + SND_PCI_QUIRK(0x1043, 0x10a4, "ASUS TP3407SA", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x10d3, "ASUS K6500ZC", ALC294_FIXUP_ASUS_SPK), + SND_PCI_QUIRK(0x1043, 0x1154, "ASUS TP3607SH", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1043, 0x1194, "ASUS UM3406KA", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1294, "ASUS B3405CVA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x12a3, "Asus N7691ZM", ALC269_FIXUP_ASUS_N7601ZM), SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC), - SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x12b4, "ASUS B3405CCA / P3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x1314, "ASUS GA605K", ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1460, "Asus VivoBook 15", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X/GA402N", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604VI/VC/VE/VG/VJ/VQ/VU/VV/VY/VZ", ALC285_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603VQ/VU/VV/VJ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601VV/VU/VJ/VQ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G614JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS G513PI/PU/PV", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x14f2, "ASUS VivoBook X515JA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1503, "ASUS G733PY/PZ/PZV/PYV", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2), @@ -10091,12 +11008,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x19ce, "ASUS B9450FA", ALC294_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x19e1, "ASUS UX581LV", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), - SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1a63, "ASUS UX3405MA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1a8e, "ASUS G712LWS", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B), - SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1043, 0x1b13, "ASUS U41SV/GA403U", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1b93, "ASUS G614JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1c03, "ASUS UM3406HA", ALC287_FIXUP_CS35L41_I2C_2), @@ -10104,10 +11021,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1c33, "ASUS UX5304MA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), + SND_PCI_QUIRK(0x1043, 0x1c63, "ASUS GU605M", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1), + SND_PCI_QUIRK(0x1043, 0x1c80, "ASUS VivoBook TP401", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS), SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JU/JV/JI", ALC285_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JY/JZ/JI/JG", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), - SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1ccf, "ASUS G814JU/JV/JI", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1cdf, "ASUS G814JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1cef, "ASUS G834JY/JZ/JI/JG", ALC285_FIXUP_ASUS_HEADSET_MIC), @@ -10115,25 +11034,58 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606WA", ALC294_FIXUP_BASS_SPEAKER_15), + SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15), SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1e1f, "ASUS Vivobook 15 X1504VAP", ALC2XX_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS), SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS), + SND_PCI_QUIRK(0x1043, 0x1e63, "ASUS H7606W", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1), + SND_PCI_QUIRK(0x1043, 0x1e83, "ASUS GA605W", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), + SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE), + SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RCLA72", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x1f1f, "ASUS H7604JI/JV/J3D", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1f63, "ASUS P5405CSA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401), + SND_PCI_QUIRK(0x1043, 0x1fb3, "ASUS ROG Flow Z13 GZ302EA", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x3011, "ASUS B5605CVA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), - SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3061, "ASUS B3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3071, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x30c1, "ASUS B3605CCA / P3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x30d1, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x30e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x31d0, "ASUS Zen AIO 27 Z272SD_A272SD", ALC274_FIXUP_ASUS_ZEN_AIO_27), + SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), + SND_PCI_QUIRK(0x1043, 0x3d78, "ASUS GA603KH", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x3d88, "ASUS GA603KM", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x3e00, "ASUS G814FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x3e20, "ASUS G814PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x1043, 0x3e30, "ASUS TP3607SA", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x3ee0, "ASUS Strix G815_JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x3ef0, "ASUS Strix G635LR_LW_LX", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x3f00, "ASUS Strix G815LH_LM_LP", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x3f10, "ASUS Strix G835LR_LW_LX", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x3f30, "ASUS Strix G815LR_LW", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x1043, 0x3fd0, "ASUS B3605CVA", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3ff0, "ASUS B5405CVA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), @@ -10153,30 +11105,40 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), + SND_PCI_QUIRK(0x10ec, 0x119e, "Positivo SU C1400", ALC269_FIXUP_ASPIRE_HEADSET_MIC), + SND_PCI_QUIRK(0x10ec, 0x11bc, "VAIO VJFE-IL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), - SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE), + SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc1a3, "Samsung Galaxy Book Pro (NP935XDB-KC1SE)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc1a4, "Samsung Galaxy Book Pro 360 (NT935QBD)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc1a6, "Samsung Galaxy Book Pro 360 (NP930QBD)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xca06, "Samsung Galaxy Book3 360 (NP730QFG)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc868, "Samsung Galaxy Book2 Pro (NP930XED)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xc870, "Samsung Galaxy Book2 Pro (NP950XED)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS), + SND_PCI_QUIRK(0x144d, 0xc872, "Samsung Galaxy Book2 Pro (NP950XEE)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS), + SND_PCI_QUIRK(0x144d, 0xc886, "Samsung Galaxy Book3 Pro (NP964XFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), + SND_PCI_QUIRK(0x144d, 0xc1ca, "Samsung Galaxy Book3 Pro 360 (NP960QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), + SND_PCI_QUIRK(0x144d, 0xc1cc, "Samsung Galaxy Book3 Ultra (NT960XFH)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x152d, 0x1082, "Quanta NL3", ALC269_FIXUP_LIFEBOOK), + SND_PCI_QUIRK(0x152d, 0x1262, "Huawei NBLB-WAX9N", ALC2XX_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1558, 0x0353, "Clevo V35[05]SN[CDE]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x1323, "Clevo N130ZU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x1325, "Clevo N15[01][CW]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -10185,6 +11147,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x2624, "Clevo L240TU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x28c1, "Clevo V370VND", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1558, 0x35a1, "Clevo V3[56]0EN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x35b1, "Clevo V3[57]0WN[MNP]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -10212,6 +11177,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x51b1, "Clevo NS50AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x51b3, "Clevo NS70AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x5700, "Clevo X560WN[RST]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -10246,9 +11212,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x961d, "Clevo N960S[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x971d, "Clevo N970T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL5[03]RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xa554, "VAIO VJFH52", ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xa600, "Clevo NL50NU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xa650, "Clevo NP[567]0SN[CD]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xa671, "Clevo NP70SN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xa741, "Clevo V54x_6x_TNE", ALC245_FIXUP_CLEVO_NOISY_MIC), + SND_PCI_QUIRK(0x1558, 0xa743, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC), + SND_PCI_QUIRK(0x1558, 0xa763, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC), SND_PCI_QUIRK(0x1558, 0xb018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xb019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xb022, "Clevo NH77D[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -10282,6 +11252,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x222e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x2231, "Thinkpad T560", ALC292_FIXUP_TPT460), SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460), + SND_PCI_QUIRK(0x17aa, 0x2234, "Thinkpad ICE-1", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), @@ -10302,6 +11273,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2318, "Thinkpad Z13 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x2319, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x231e, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318), + SND_PCI_QUIRK(0x17aa, 0x231f, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318), + SND_PCI_QUIRK(0x17aa, 0x2326, "Hera2", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), @@ -10314,11 +11288,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340), SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x17aa, 0x3384, "ThinkCentre M90a PRO", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED), + SND_PCI_QUIRK(0x17aa, 0x3386, "ThinkCentre M90a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED), + SND_PCI_QUIRK(0x17aa, 0x3387, "ThinkCentre M70a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED), SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8 / DuetITL 2021", ALC287_FIXUP_LENOVO_14IRP8_DUETITL), + HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), + SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7), SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS), + HDA_CODEC_QUIRK(0x17aa, 0x3820, "IdeaPad 330-17IKB 81DM", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF), @@ -10330,33 +11309,63 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6), + SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x386f, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), + HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1), + HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */ + SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C), + SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x387f, "Yoga S780-16 pro dual LX", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x3880, "Yoga S780-16 pro dual YC", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual power mode2 YC", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3882, "Lenovo Yoga Pro 7 14APH8", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), SND_PCI_QUIRK(0x17aa, 0x3884, "Y780 YG DUAL", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x3891, "Lenovo Yoga Pro 7 14AHP9", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x38a5, "Y580P AMD dual", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x38b5, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x38b6, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x38b7, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x38b8, "Yoga S780-14.5 proX AMD YC Dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38b9, "Yoga S780-14.5 proX AMD LX Dual", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38c3, "Y980 DUAL", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38c7, "Thinkbook 13x Gen 4", ALC287_FIXUP_CS35L41_I2C_4), + SND_PCI_QUIRK(0x17aa, 0x38c8, "Thinkbook 13x Gen 4", ALC287_FIXUP_CS35L41_I2C_4), SND_PCI_QUIRK(0x17aa, 0x38cb, "Y790 YG DUAL", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38cd, "Y790 VECO DUAL", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38d2, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x38d3, "Yoga S990-16 Pro IMH YC Dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38d4, "Yoga S990-16 Pro IMH VECO Dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38d5, "Yoga S990-16 Pro IMH YC Quad", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38d6, "Yoga S990-16 Pro IMH VECO Quad", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x38d7, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x38df, "Yoga Y990 Intel YC Dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), + SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), + SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC), + SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), @@ -10381,18 +11390,23 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), SND_PCI_QUIRK(0x17aa, 0x9e56, "Lenovo ZhaoYang CF4620Z", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1849, 0x0269, "Positivo Master C6400", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK), SND_PCI_QUIRK(0x1849, 0xa233, "Positivo Master C6300", ALC269_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1854, 0x0440, "LG CQ6", ALC256_FIXUP_HEADPHONE_AMP_VOL), SND_PCI_QUIRK(0x1854, 0x0441, "LG CQ6 AIO", ALC256_FIXUP_HEADPHONE_AMP_VOL), + SND_PCI_QUIRK(0x1854, 0x0488, "LG gram 16 (16Z90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), + SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS), SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC), SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20), SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI), SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101), SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), + SND_PCI_QUIRK(0x1c6c, 0x122a, "Positivo N14AP7", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1c6c, 0x1251, "Positivo N14KP6-TG", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS), SND_PCI_QUIRK(0x1d05, 0x1096, "TongFang GMxMRxx", ALC269_FIXUP_NO_SHUTUP), @@ -10403,20 +11417,33 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1d05, 0x1147, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x1d05, 0x115c, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x1d05, 0x121b, "TongFang GMxAGxx", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x1d05, 0x1387, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1d05, 0x1409, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS), SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), + SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13), SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO), + SND_PCI_QUIRK(0x2782, 0x1407, "Positivo P15X", ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC), + SND_PCI_QUIRK(0x2782, 0x1409, "Positivo K116J", ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC), + SND_PCI_QUIRK(0x2782, 0x1701, "Infinix Y4 Max", ALC269VC_FIXUP_INFINIX_Y4_MAX), + SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX), SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME), + SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK), SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), SND_PCI_QUIRK(0x8086, 0x3038, "Intel NUC 13", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0xf111, 0x0001, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0xf111, 0x0005, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0xf111, 0x0006, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0xf111, 0x0009, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0xf111, 0x000c, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE), #if 0 /* Below is a quirk table taken from the old code. @@ -10469,11 +11496,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { {} }; -static const struct snd_pci_quirk alc269_fixup_vendor_tbl[] = { +static const struct hda_quirk alc269_fixup_vendor_tbl[] = { SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), - SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo XPAD", ALC269_FIXUP_LENOVO_XPAD_ACPI), SND_PCI_QUIRK_VENDOR(0x19e5, "Huawei Matebook", ALC255_FIXUP_MIC_MUTE_LED), {} }; @@ -10495,6 +11522,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"}, {.id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, .name = "dell-headset3"}, {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, .name = "dell-headset4"}, + {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET, .name = "dell-headset4-quiet"}, {.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"}, @@ -10537,6 +11565,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK, .name = "mono-speakers"}, {.id = ALC290_FIXUP_SUBWOOFER_HSJACK, .name = "alc290-subwoofer"}, {.id = ALC269_FIXUP_THINKPAD_ACPI, .name = "thinkpad"}, + {.id = ALC269_FIXUP_LENOVO_XPAD_ACPI, .name = "lenovo-xpad-led"}, {.id = ALC269_FIXUP_DMIC_THINKPAD_ACPI, .name = "dmic-thinkpad"}, {.id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE, .name = "alc255-acer"}, {.id = ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc255-asus"}, @@ -10586,10 +11615,13 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"}, {.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-headset-jack"}, {.id = ALC295_FIXUP_CHROME_BOOK, .name = "alc-chrome-book"}, + {.id = ALC256_FIXUP_CHROME_BOOK, .name = "alc-2024y-chromebook"}, {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"}, {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"}, {.id = ALC298_FIXUP_SAMSUNG_AMP, .name = "alc298-samsung-amp"}, + {.id = ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS, .name = "alc298-samsung-amp-v2-2-amps"}, + {.id = ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS, .name = "alc298-samsung-amp-v2-4-amps"}, {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"}, {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"}, {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, @@ -10597,12 +11629,15 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"}, {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"}, {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"}, + {.id = ALC285_FIXUP_HP_SPECTRE_X360_DF1, .name = "alc285-hp-spectre-x360-df1"}, {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"}, {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"}, {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"}, {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"}, {.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"}, {.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"}, + {.id = ALC236_FIXUP_LENOVO_INV_DMIC, .name = "alc236-fixup-lenovo-inv-mic"}, + {.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"}, {} }; #define ALC225_STANDARD_PINS \ @@ -11045,20 +12080,22 @@ static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, {0x19, 0x40000000}, {0x1b, 0x40000000}), - SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, + SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET, {0x19, 0x40000000}, {0x1b, 0x40000000}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x19, 0x40000000}, {0x1a, 0x40000000}), - SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST, {0x19, 0x40000000}, {0x1a, 0x40000000}), - SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, + SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST, {0x19, 0x40000000}, {0x1a, 0x40000000}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC2XX_FIXUP_HEADSET_MIC, {0x19, 0x40000000}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1558, "Clevo", ALC2XX_FIXUP_HEADSET_MIC, + {0x19, 0x40000000}), {} }; @@ -11118,10 +12155,8 @@ static int patch_alc269(struct hda_codec *codec) codec->power_save_node = 0; spec->en_3kpull_low = true; -#ifdef CONFIG_PM codec->patch_ops.suspend = alc269_suspend; codec->patch_ops.resume = alc269_resume; -#endif spec->shutup = alc_default_shutup; spec->init_hook = alc_default_init; @@ -11248,8 +12283,11 @@ static int patch_alc269(struct hda_codec *codec) spec->codec_variant = ALC269_TYPE_ALC300; spec->gen.mixer_nid = 0; /* no loopback on ALC300 */ break; + case 0x10ec0222: case 0x10ec0623: spec->codec_variant = ALC269_TYPE_ALC623; + spec->shutup = alc222_shutup; + spec->init_hook = alc222_init; break; case 0x10ec0700: case 0x10ec0701: @@ -11286,6 +12324,13 @@ static int patch_alc269(struct hda_codec *codec) snd_hda_pick_pin_fixup(codec, alc269_fallback_pin_fixup_tbl, alc269_fixups, false); snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl, alc269_fixups); + + /* + * Check whether ACPI describes companion amplifiers that require + * component binding + */ + find_cirrus_companion_amps(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); @@ -11393,7 +12438,7 @@ static const struct hda_fixup alc861_fixups[] = { } }; -static const struct snd_pci_quirk alc861_fixup_tbl[] = { +static const struct hda_quirk alc861_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J), SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J), SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), @@ -11419,9 +12464,7 @@ static int patch_alc861(struct hda_codec *codec) if (has_cdefine_beep(codec)) spec->gen.beep_nid = 0x23; -#ifdef CONFIG_PM spec->power_hook = alc_power_eapd; -#endif alc_pre_init(codec); @@ -11499,7 +12542,7 @@ static const struct hda_fixup alc861vd_fixups[] = { }, }; -static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { +static const struct hda_quirk alc861vd_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS), SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS), @@ -11844,6 +12887,7 @@ enum { ALC897_FIXUP_LENOVO_HEADSET_MODE, ALC897_FIXUP_HEADSET_MIC_PIN2, ALC897_FIXUP_UNIS_H3C_X500S, + ALC897_FIXUP_HEADSET_MIC_PIN3, }; static const struct hda_fixup alc662_fixups[] = { @@ -12290,10 +13334,18 @@ static const struct hda_fixup alc662_fixups[] = { {} }, }, + [ALC897_FIXUP_HEADSET_MIC_PIN3] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a11050 }, /* use as headset mic */ + { } + }, + }, }; -static const struct snd_pci_quirk alc662_fixup_tbl[] = { +static const struct hda_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3), SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), @@ -12713,7 +13765,7 @@ MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek HD-audio codec"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_COMPONENT); +MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT"); static struct hda_codec_driver realtek_driver = { .id = snd_hda_id_realtek, diff --git a/sound/pci/hda/patch_senarytech.c b/sound/pci/hda/patch_senarytech.c new file mode 100644 index 000000000000..0691996fa971 --- /dev/null +++ b/sound/pci/hda/patch_senarytech.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HD audio interface patch for Senary HDA audio codec + * + * Initially based on sound/pci/hda/patch_conexant.c + */ + +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <sound/core.h> +#include <sound/jack.h> + +#include <sound/hda_codec.h> +#include "hda_local.h" +#include "hda_auto_parser.h" +#include "hda_beep.h" +#include "hda_jack.h" +#include "hda_generic.h" + +struct senary_spec { + struct hda_gen_spec gen; + + /* extra EAPD pins */ + unsigned int num_eapds; + hda_nid_t eapds[4]; + hda_nid_t mute_led_eapd; + + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + + int mute_led_polarity; + unsigned int gpio_led; + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; +}; + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +/* additional beep mixers; private_value will be overwritten */ +static const struct snd_kcontrol_new senary_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), +}; + +static int set_beep_amp(struct senary_spec *spec, hda_nid_t nid, + int idx, int dir) +{ + struct snd_kcontrol_new *knew; + unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); + int i; + + spec->gen.beep_nid = nid; + for (i = 0; i < ARRAY_SIZE(senary_beep_mixer); i++) { + knew = snd_hda_gen_add_kctl(&spec->gen, NULL, + &senary_beep_mixer[i]); + if (!knew) + return -ENOMEM; + knew->private_value = beep_amp; + } + return 0; +} + +static int senary_auto_parse_beep(struct hda_codec *codec) +{ + struct senary_spec *spec = codec->spec; + hda_nid_t nid; + + for_each_hda_codec_node(nid, codec) + if ((get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) && + (get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_AMP_OVRD))) + return set_beep_amp(spec, nid, 0, HDA_OUTPUT); + return 0; +} +#else +#define senary_auto_parse_beep(codec) 0 +#endif + +/* parse EAPDs */ +static void senary_auto_parse_eapd(struct hda_codec *codec) +{ + struct senary_spec *spec = codec->spec; + hda_nid_t nid; + + for_each_hda_codec_node(nid, codec) { + if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) + continue; + if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) + continue; + spec->eapds[spec->num_eapds++] = nid; + if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) + break; + } +} + +static void senary_auto_turn_eapd(struct hda_codec *codec, int num_pins, + const hda_nid_t *pins, bool on) +{ + int i; + + for (i = 0; i < num_pins; i++) { + if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_EAPD_BTLENABLE, + on ? 0x02 : 0); + } +} + +/* turn on/off EAPD according to Master switch */ +static void senary_auto_vmaster_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + struct senary_spec *spec = codec->spec; + + senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); +} + +static void senary_init_gpio_led(struct hda_codec *codec) +{ + struct senary_spec *spec = codec->spec; + unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask; + + if (mask) { + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, + mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, + mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_led); + } +} + +static int senary_auto_init(struct hda_codec *codec) +{ + snd_hda_gen_init(codec); + senary_init_gpio_led(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + + return 0; +} + +static void senary_auto_shutdown(struct hda_codec *codec) +{ + struct senary_spec *spec = codec->spec; + + /* Turn the problematic codec into D3 to avoid spurious noises + * from the internal speaker during (and after) reboot + */ + senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false); +} + +static void senary_auto_free(struct hda_codec *codec) +{ + senary_auto_shutdown(codec); + snd_hda_gen_free(codec); +} + +static int senary_auto_suspend(struct hda_codec *codec) +{ + senary_auto_shutdown(codec); + return 0; +} + +static const struct hda_codec_ops senary_auto_patch_ops = { + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = senary_auto_init, + .free = senary_auto_free, + .unsol_event = snd_hda_jack_unsol_event, + .suspend = senary_auto_suspend, + .check_power_status = snd_hda_gen_check_power_status, +}; + +static int patch_senary_auto(struct hda_codec *codec) +{ + struct senary_spec *spec; + int err; + + codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + snd_hda_gen_spec_init(&spec->gen); + codec->spec = spec; + codec->patch_ops = senary_auto_patch_ops; + + senary_auto_parse_eapd(codec); + spec->gen.own_eapd_ctl = 1; + + if (!spec->gen.vmaster_mute.hook) + spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, + spec->parse_flags); + if (err < 0) + goto error; + + err = senary_auto_parse_beep(codec); + if (err < 0) + goto error; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + goto error; + + /* Some laptops with Senary chips show stalls in S3 resume, + * which falls into the single-cmd mode. + * Better to make reset, then. + */ + if (!codec->bus->core.sync_write) { + codec_info(codec, + "Enable sync_write for stable communication\n"); + codec->bus->core.sync_write = 1; + codec->bus->allow_bus_reset = 1; + } + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return 0; + + error: + senary_auto_free(codec); + return err; +} + +/* + */ + +static const struct hda_device_id snd_hda_id_senary[] = { + HDA_CODEC_ENTRY(0x1fa86186, "SN6186", patch_senary_auto), + {} /* terminator */ +}; +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_senary); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Senarytech HD-audio codec"); + +static struct hda_codec_driver senary_driver = { + .id = snd_hda_id_senary, +}; + +module_hda_codec_driver(senary_driver); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 61258b0aac8d..bde6b7373858 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1462,7 +1462,7 @@ static const struct hda_model_fixup stac9200_models[] = { {} }; -static const struct snd_pci_quirk stac9200_fixup_tbl[] = { +static const struct hda_quirk stac9200_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), @@ -1683,7 +1683,7 @@ static const struct hda_model_fixup stac925x_models[] = { {} }; -static const struct snd_pci_quirk stac925x_fixup_tbl[] = { +static const struct hda_quirk stac925x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), @@ -1957,7 +1957,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { +static const struct hda_quirk stac92hd73xx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), @@ -2154,10 +2154,8 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec, if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ -#ifdef CONFIG_PM /* resetting controller clears GPIO, so we need to keep on */ codec->core.power_caps &= ~AC_PWRST_CLKSTOP; -#endif } } @@ -2755,7 +2753,7 @@ static const struct hda_model_fixup stac92hd83xxx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { +static const struct hda_quirk stac92hd83xxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD83XXX_REF), @@ -3238,7 +3236,7 @@ static const struct hda_model_fixup stac92hd71bxx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd71bxx_fixup_tbl[] = { +static const struct hda_quirk stac92hd71bxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD71BXX_REF), @@ -3498,7 +3496,7 @@ static const struct hda_pintbl ecs202_pin_configs[] = { }; /* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */ -static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = { +static const struct hda_quirk stac922x_intel_mac_fixup_tbl[] = { SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3), SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1), SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2), @@ -3642,7 +3640,7 @@ static const struct hda_model_fixup stac922x_models[] = { {} }; -static const struct snd_pci_quirk stac922x_fixup_tbl[] = { +static const struct hda_quirk stac922x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D945_REF), @@ -3970,7 +3968,7 @@ static const struct hda_model_fixup stac927x_models[] = { {} }; -static const struct snd_pci_quirk stac927x_fixup_tbl[] = { +static const struct hda_quirk stac927x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D965_REF), @@ -4180,7 +4178,7 @@ static const struct hda_model_fixup stac9205_models[] = { {} }; -static const struct snd_pci_quirk stac9205_fixup_tbl[] = { +static const struct hda_quirk stac9205_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), @@ -4257,7 +4255,7 @@ static const struct hda_fixup stac92hd95_fixups[] = { }, }; -static const struct snd_pci_quirk stac92hd95_fixup_tbl[] = { +static const struct hda_quirk stac92hd95_fixup_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1911, "HP Spectre 13", STAC_92HD95_HP_BASS), {} /* terminator */ }; @@ -4442,7 +4440,6 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer, #define stac927x_proc_hook NULL #endif -#ifdef CONFIG_PM static int stac_suspend(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -4456,9 +4453,6 @@ static int stac_suspend(struct hda_codec *codec) return 0; } -#else -#define stac_suspend NULL -#endif /* CONFIG_PM */ static const struct hda_codec_ops stac_patch_ops = { .build_controls = snd_hda_gen_build_controls, @@ -4466,9 +4460,7 @@ static const struct hda_codec_ops stac_patch_ops = { .init = stac_init, .free = stac_free, .unsol_event = snd_hda_jack_unsol_event, -#ifdef CONFIG_PM .suspend = stac_suspend, -#endif }; static int alloc_stac_spec(struct hda_codec *codec) @@ -5010,7 +5002,7 @@ static const struct hda_fixup stac9872_fixups[] = { }, }; -static const struct snd_pci_quirk stac9872_fixup_tbl[] = { +static const struct hda_quirk stac9872_fixup_tbl[] = { SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0, "Sony VAIO F/S", STAC_9872_VAIO), {} /* terminator */ diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 2994f85bc1b9..d0893059b1b9 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -379,7 +379,6 @@ static void via_free(struct hda_codec *codec) snd_hda_gen_free(codec); } -#ifdef CONFIG_PM static int via_suspend(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -400,9 +399,7 @@ static int via_resume(struct hda_codec *codec) snd_hda_regmap_sync(codec); return 0; } -#endif -#ifdef CONFIG_PM static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct via_spec *spec = codec->spec; @@ -410,7 +407,6 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) vt1708_update_hp_work(codec); return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid); } -#endif /* */ @@ -423,11 +419,9 @@ static const struct hda_codec_ops via_patch_ops = { .init = via_init, .free = via_free, .unsol_event = snd_hda_jack_unsol_event, -#ifdef CONFIG_PM .suspend = via_suspend, .resume = via_resume, .check_power_status = via_check_power_status, -#endif }; @@ -1041,7 +1035,7 @@ static const struct hda_fixup via_fixups[] = { }, }; -static const struct snd_pci_quirk vt2002p_fixups[] = { +static const struct hda_quirk vt2002p_fixups[] = { SND_PCI_QUIRK(0x1043, 0x13f7, "Asus B23E", VIA_FIXUP_POWER_SAVE), SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75), SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST), diff --git a/sound/pci/hda/tas2781_hda.c b/sound/pci/hda/tas2781_hda.c new file mode 100644 index 000000000000..34217ce9f28e --- /dev/null +++ b/sound/pci/hda/tas2781_hda.c @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// TAS2781 HDA Shared Lib for I2C&SPI driver +// +// Copyright 2025 Texas Instruments, Inc. +// +// Author: Shenghao Ding <shenghao-ding@ti.com> + +#include <linux/component.h> +#include <linux/crc8.h> +#include <linux/crc32.h> +#include <linux/efi.h> +#include <linux/firmware.h> +#include <linux/i2c.h> +#include <linux/pm_runtime.h> +#include <sound/soc.h> +#include <sound/tas2781.h> + +#include "tas2781_hda.h" + +const efi_guid_t tasdev_fct_efi_guid[] = { + /* DELL */ + EFI_GUID(0xcc92382d, 0x6337, 0x41cb, 0xa8, 0x8b, 0x8e, 0xce, 0x74, + 0x91, 0xea, 0x9f), + /* HP */ + EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, + 0xa3, 0x5d, 0xb3), + /* LENOVO & OTHERS */ + EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, 0x43, 0xa3, 0xf4, + 0x31, 0x0a, 0x92), +}; +EXPORT_SYMBOL_NS_GPL(tasdev_fct_efi_guid, "SND_HDA_SCODEC_TAS2781"); + +static void tas2781_apply_calib(struct tasdevice_priv *p) +{ + struct calidata *cali_data = &p->cali_data; + struct cali_reg *r = &cali_data->cali_reg_array; + unsigned char *data = cali_data->data; + unsigned int *tmp_val = (unsigned int *)data; + unsigned int cali_reg[TASDEV_CALIB_N] = { + TASDEVICE_REG(0, 0x17, 0x74), + TASDEVICE_REG(0, 0x18, 0x0c), + TASDEVICE_REG(0, 0x18, 0x14), + TASDEVICE_REG(0, 0x13, 0x70), + TASDEVICE_REG(0, 0x18, 0x7c), + }; + unsigned int crc, oft, node_num; + unsigned char *buf; + int i, j, k, l; + + if (tmp_val[0] == 2781) { + /* + * New features were added in calibrated Data V3: + * 1. Added calibration registers address define in + * a node, marked as Device id == 0x80. + * New features were added in calibrated Data V2: + * 1. Added some the fields to store the link_id and + * uniqie_id for multi-link solutions + * 2. Support flexible number of devices instead of + * fixed one in V1. + * Layout of calibrated data V2 in UEFI(total 256 bytes): + * ChipID (2781, 4 bytes) + * Data-Group-Sum (4 bytes) + * TimeStamp of Calibration (4 bytes) + * for (i = 0; i < Data-Group-Sum; i++) { + * if (Data type != 0x80) (4 bytes) + * Calibrated Data of Device #i (20 bytes) + * else + * Calibration registers address (5*4 = 20 bytes) + * # V2: No reg addr in data grp section. + * # V3: Normally the last grp is the reg addr. + * } + * CRC (4 bytes) + * Reserved (the rest) + */ + crc = crc32(~0, data, (3 + tmp_val[1] * 6) * 4) ^ ~0; + + if (crc != tmp_val[3 + tmp_val[1] * 6]) { + cali_data->total_sz = 0; + dev_err(p->dev, "%s: CRC error\n", __func__); + return; + } + node_num = tmp_val[1]; + + for (j = 0, k = 0; j < node_num; j++) { + oft = j * 6 + 3; + if (tmp_val[oft] == TASDEV_UEFI_CALI_REG_ADDR_FLG) { + for (i = 0; i < TASDEV_CALIB_N; i++) { + buf = &data[(oft + i + 1) * 4]; + cali_reg[i] = TASDEVICE_REG(buf[1], + buf[2], buf[3]); + } + } else { + l = j * (cali_data->cali_dat_sz_per_dev + 1); + if (k >= p->ndev || l > oft * 4) { + dev_err(p->dev, "%s: dev sum error\n", + __func__); + cali_data->total_sz = 0; + return; + } + + data[l] = k; + oft++; + for (i = 0; i < TASDEV_CALIB_N * 4; i++) + data[l + i + 1] = data[4 * oft + i]; + k++; + } + } + } else { + /* + * Calibration data is in V1 format. + * struct cali_data { + * char cali_data[20]; + * } + * + * struct { + * struct cali_data cali_data[4]; + * int TimeStamp of Calibration (4 bytes) + * int CRC (4 bytes) + * } ueft; + */ + crc = crc32(~0, data, 84) ^ ~0; + if (crc != tmp_val[21]) { + cali_data->total_sz = 0; + dev_err(p->dev, "%s: V1 CRC error\n", __func__); + return; + } + + for (j = p->ndev - 1; j >= 0; j--) { + l = j * (cali_data->cali_dat_sz_per_dev + 1); + for (i = TASDEV_CALIB_N * 4; i > 0 ; i--) + data[l + i] = data[p->index * 5 + i]; + data[l+i] = j; + } + } + + if (p->dspbin_typ == TASDEV_BASIC) { + r->r0_reg = cali_reg[0]; + r->invr0_reg = cali_reg[1]; + r->r0_low_reg = cali_reg[2]; + r->pow_reg = cali_reg[3]; + r->tlimit_reg = cali_reg[4]; + } + + p->is_user_space_calidata = true; + cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1); +} + +/* + * Update the calibration data, including speaker impedance, f0, etc, + * into algo. Calibrate data is done by manufacturer in the factory. + * The data is used by Algo for calculating the speaker temperature, + * speaker membrane excursion and f0 in real time during playback. + * Calibration data format in EFI is V2, since 2024. + */ +int tas2781_save_calibration(struct tas2781_hda *hda) +{ + /* + * GUID was used for data access in BIOS, it was provided by board + * manufactory. + */ + efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO]; + static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME; + struct tasdevice_priv *p = hda->priv; + struct calidata *cali_data = &p->cali_data; + unsigned long total_sz = 0; + unsigned int attr, size; + unsigned char *data; + efi_status_t status; + + if (hda->catlog_id < LENOVO) + efi_guid = tasdev_fct_efi_guid[hda->catlog_id]; + + cali_data->cali_dat_sz_per_dev = 20; + size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1); + /* Get real size of UEFI variable */ + status = efi.get_variable(efi_name, &efi_guid, &attr, &total_sz, NULL); + cali_data->total_sz = total_sz > size ? total_sz : size; + if (status == EFI_BUFFER_TOO_SMALL) { + /* Allocate data buffer of data_size bytes */ + data = p->cali_data.data = devm_kzalloc(p->dev, + p->cali_data.total_sz, GFP_KERNEL); + if (!data) { + p->cali_data.total_sz = 0; + return -ENOMEM; + } + /* Get variable contents into buffer */ + status = efi.get_variable(efi_name, &efi_guid, &attr, + &p->cali_data.total_sz, data); + } + if (status != EFI_SUCCESS) { + p->cali_data.total_sz = 0; + return status; + } + + tas2781_apply_calib(p); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781"); + +void tas2781_hda_remove(struct device *dev, + const struct component_ops *ops) +{ + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + + component_del(tas_hda->dev, ops); + + pm_runtime_get_sync(tas_hda->dev); + pm_runtime_disable(tas_hda->dev); + + pm_runtime_put_noidle(tas_hda->dev); + + tasdevice_remove(tas_hda->priv); +} +EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_info_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_info_programs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_info_config(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct tasdevice_fw *tas_fw = tas_priv->fmw; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = tas_fw->nr_configurations - 1; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id; + + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__, + kcontrol->id.name, tas_priv->rcabin.profile_cfg_id); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + int profile_id = ucontrol->value.integer.value[0]; + int max = tas_priv->rcabin.ncfgs - 1; + int val, ret = 0; + + val = clamp(profile_id, 0, max); + + guard(mutex)(&tas_priv->codec_lock); + + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__, + kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val); + + if (tas_priv->rcabin.profile_cfg_id != val) { + tas_priv->rcabin.profile_cfg_id = val; + ret = 1; + } + + return ret; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_program_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas_priv->cur_prog; + + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__, + kcontrol->id.name, tas_priv->cur_prog); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_program_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct tasdevice_fw *tas_fw = tas_priv->fmw; + int nr_program = ucontrol->value.integer.value[0]; + int max = tas_fw->nr_programs - 1; + int val, ret = 0; + + val = clamp(nr_program, 0, max); + + guard(mutex)(&tas_priv->codec_lock); + + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__, + kcontrol->id.name, tas_priv->cur_prog, val); + + if (tas_priv->cur_prog != val) { + tas_priv->cur_prog = val; + ret = 1; + } + + return ret; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_config_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas_priv->cur_conf; + + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__, + kcontrol->id.name, tas_priv->cur_conf); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781"); + +int tasdevice_config_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct tasdevice_fw *tas_fw = tas_priv->fmw; + int nr_config = ucontrol->value.integer.value[0]; + int max = tas_fw->nr_configurations - 1; + int val, ret = 0; + + val = clamp(nr_config, 0, max); + + guard(mutex)(&tas_priv->codec_lock); + + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__, + kcontrol->id.name, tas_priv->cur_conf, val); + + if (tas_priv->cur_conf != val) { + tas_priv->cur_conf = val; + ret = 1; + } + + return ret; +} +EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781"); + +MODULE_DESCRIPTION("TAS2781 HDA Driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>"); diff --git a/sound/pci/hda/tas2781_hda.h b/sound/pci/hda/tas2781_hda.h new file mode 100644 index 000000000000..575a701c8dfb --- /dev/null +++ b/sound/pci/hda/tas2781_hda.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * HDA audio driver for Texas Instruments TAS2781 smart amp + * + * Copyright (C) 2025 Texas Instruments, Inc. + */ +#ifndef __TAS2781_HDA_H__ +#define __TAS2781_HDA_H__ + +#include <sound/asound.h> + +/* Flag of calibration registers address. */ +#define TASDEV_UEFI_CALI_REG_ADDR_FLG BIT(7) +#define TASDEVICE_CALIBRATION_DATA_NAME L"CALI_DATA" +#define TASDEV_CALIB_N 5 + +/* + * No standard control callbacks for SNDRV_CTL_ELEM_IFACE_CARD + * Define two controls, one is Volume control callbacks, the other is + * flag setting control callbacks. + */ + +/* Volume control callbacks for tas2781 */ +#define ACARD_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \ + xhandler_get, xhandler_put, tlv_array) { \ + .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&(struct soc_mixer_control) { \ + .reg = xreg, .rreg = xreg, \ + .shift = xshift, .rshift = xshift,\ + .min = xmin, .max = xmax, .invert = xinvert, \ + } \ +} + +/* Flag control callbacks for tas2781 */ +#define ACARD_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) { \ + .iface = SNDRV_CTL_ELEM_IFACE_CARD, \ + .name = xname, \ + .info = snd_ctl_boolean_mono_info, \ + .get = xhandler_get, \ + .put = xhandler_put, \ + .private_value = xdata, \ +} + +enum device_catlog_id { + DELL = 0, + HP, + LENOVO, + OTHERS +}; + +struct tas2781_hda { + struct device *dev; + struct tasdevice_priv *priv; + struct snd_kcontrol *dsp_prog_ctl; + struct snd_kcontrol *dsp_conf_ctl; + struct snd_kcontrol *prof_ctl; + enum device_catlog_id catlog_id; + void *hda_priv; +}; + +extern const efi_guid_t tasdev_fct_efi_guid[]; + +int tas2781_save_calibration(struct tas2781_hda *p); +void tas2781_hda_remove(struct device *dev, + const struct component_ops *ops); +int tasdevice_info_profile(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uctl); +int tasdevice_info_programs(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uctl); +int tasdevice_info_config(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uctl); +int tasdevice_set_profile_id(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl); +int tasdevice_get_profile_id(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl); +int tasdevice_program_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl); +int tasdevice_program_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl); +int tasdevice_config_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl); +int tasdevice_config_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *uctl); + +#endif diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 4475cea8e9f7..d91eed9f7804 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -2,10 +2,12 @@ // // TAS2781 HDA I2C driver // -// Copyright 2023 Texas Instruments, Inc. +// Copyright 2023 - 2025 Texas Instruments, Inc. // // Author: Shenghao Ding <shenghao-ding@ti.com> +// Current maintainer: Baojun Xu <baojun.xu@ti.com> +#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/crc8.h> #include <linux/crc32.h> @@ -14,11 +16,13 @@ #include <linux/i2c.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/pci_ids.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <sound/hda_codec.h> #include <sound/soc.h> #include <sound/tas2781.h> +#include <sound/tas2781-comlib-i2c.h> #include <sound/tlv.h> #include <sound/tas2781-tlv.h> @@ -27,69 +31,23 @@ #include "hda_component.h" #include "hda_jack.h" #include "hda_generic.h" - -#define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20 - -/* No standard control callbacks for SNDRV_CTL_ELEM_IFACE_CARD - * Define two controls, one is Volume control callbacks, the other is - * flag setting control callbacks. - */ - -/* Volume control callbacks for tas2781 */ -#define ACARD_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \ - xhandler_get, xhandler_put, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = (xname),\ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw_range, \ - .get = xhandler_get, .put = xhandler_put, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = xreg, .rreg = xreg, .shift = xshift, \ - .rshift = xshift, .min = xmin, .max = xmax, \ - .invert = xinvert} } - -/* Flag control callbacks for tas2781 */ -#define ACARD_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, \ - .info = snd_ctl_boolean_mono_info, \ - .get = xhandler_get, .put = xhandler_put, \ - .private_value = xdata } - -enum calib_data { - R0_VAL = 0, - INV_R0, - R0LOW, - POWER, - TLIM, - CALIB_MAX -}; - -#define TAS2563_MAX_CHANNELS 4 - -#define TAS2563_CAL_POWER TASDEVICE_REG(0, 0x0d, 0x3c) -#define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34) -#define TAS2563_CAL_INVR0 TASDEVICE_REG(0, 0x0f, 0x40) -#define TAS2563_CAL_R0_LOW TASDEVICE_REG(0, 0x0f, 0x48) -#define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14) -#define TAS2563_CAL_N 5 -#define TAS2563_CAL_DATA_SIZE 4 -#define TAS2563_CAL_CH_SIZE 20 -#define TAS2563_CAL_ARRAY_SIZE 80 - -static unsigned int cal_regs[TAS2563_CAL_N] = { - TAS2563_CAL_POWER, TAS2563_CAL_R0, TAS2563_CAL_INVR0, - TAS2563_CAL_R0_LOW, TAS2563_CAL_TLIM, -}; - - -struct tas2781_hda { - struct device *dev; - struct tasdevice_priv *priv; - struct snd_kcontrol *dsp_prog_ctl; - struct snd_kcontrol *dsp_conf_ctl; - struct snd_kcontrol *prof_ctl; - struct snd_kcontrol *snd_ctls[3]; +#include "tas2781_hda.h" + +#define TAS2563_CAL_VAR_NAME_MAX 16 +#define TAS2563_CAL_ARRAY_SIZE 80 +#define TAS2563_CAL_DATA_SIZE 4 +#define TAS2563_MAX_CHANNELS 4 +#define TAS2563_CAL_CH_SIZE 20 + +#define TAS2563_CAL_R0_LOW TASDEVICE_REG(0, 0x0f, 0x48) +#define TAS2563_CAL_POWER TASDEVICE_REG(0, 0x0d, 0x3c) +#define TAS2563_CAL_INVR0 TASDEVICE_REG(0, 0x0f, 0x40) +#define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14) +#define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34) + +struct tas2781_hda_i2c_priv { + struct snd_kcontrol *snd_ctls[2]; + int (*save_calibration)(struct tas2781_hda *h); }; static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) @@ -108,10 +66,20 @@ static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) return 1; } +static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false }; + +static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = { + { "speakerid-gpios", &speakerid_gpios, 1 }, + { } +}; + static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) { struct acpi_device *adev; + struct device *physdev; LIST_HEAD(resources); + const char *sub; + uint32_t subid; int ret; adev = acpi_dev_get_first_match_dev(hid, NULL, -1); @@ -121,18 +89,50 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) return -ENODEV; } + physdev = get_device(acpi_get_first_physical_node(adev)); ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); - if (ret < 0) + if (ret < 0) { + dev_err(p->dev, "Failed to get ACPI resource.\n"); + goto err; + } + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) { + /* No subsys id in older tas2563 projects. */ + if (!strncmp(hid, "INT8866", sizeof("INT8866"))) + goto end_2563; + dev_err(p->dev, "Failed to get SUBSYS ID.\n"); + ret = PTR_ERR(sub); goto err; + } + /* Speaker id was needed for ASUS projects. */ + ret = kstrtou32(sub, 16, &subid); + if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) { + ret = devm_acpi_dev_add_driver_gpios(p->dev, + tas2781_speaker_id_gpios); + if (ret < 0) + dev_err(p->dev, "Failed to add driver gpio %d.\n", + ret); + p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN); + if (IS_ERR(p->speaker_id)) { + dev_err(p->dev, "Failed to get Speaker id.\n"); + ret = PTR_ERR(p->speaker_id); + goto err; + } + } else { + p->speaker_id = NULL; + } +end_2563: acpi_dev_free_resource_list(&resources); strscpy(p->dev_name, hid, sizeof(p->dev_name)); + put_device(physdev); acpi_dev_put(adev); return 0; err: dev_err(p->dev, "read acpi error, ret: %d\n", ret); + put_device(physdev); acpi_dev_put(adev); return ret; @@ -161,190 +161,49 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) pm_runtime_put_autosuspend(dev); break; default: - dev_dbg(tas_hda->dev, "Playback action not supported: %d\n", - action); break; } } -static int tasdevice_info_profile(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1; - - return 0; -} - -static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id; - - return 0; -} - -static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - int nr_profile = ucontrol->value.integer.value[0]; - int max = tas_priv->rcabin.ncfgs - 1; - int val, ret = 0; - - val = clamp(nr_profile, 0, max); - - if (tas_priv->rcabin.profile_cfg_id != val) { - tas_priv->rcabin.profile_cfg_id = val; - ret = 1; - } - - return ret; -} - -static int tasdevice_info_programs(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - struct tasdevice_fw *tas_fw = tas_priv->fmw; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = tas_fw->nr_programs - 1; - - return 0; -} - -static int tasdevice_info_config(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - struct tasdevice_fw *tas_fw = tas_priv->fmw; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = tas_fw->nr_configurations - 1; - - return 0; -} - -static int tasdevice_program_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = tas_priv->cur_prog; - - return 0; -} - -static int tasdevice_program_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - struct tasdevice_fw *tas_fw = tas_priv->fmw; - int nr_program = ucontrol->value.integer.value[0]; - int max = tas_fw->nr_programs - 1; - int val, ret = 0; - - val = clamp(nr_program, 0, max); - - if (tas_priv->cur_prog != val) { - tas_priv->cur_prog = val; - ret = 1; - } - - return ret; -} - -static int tasdevice_config_get(struct snd_kcontrol *kcontrol, +static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int ret; - ucontrol->value.integer.value[0] = tas_priv->cur_conf; + mutex_lock(&tas_priv->codec_lock); - return 0; -} + ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc); -static int tasdevice_config_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - struct tasdevice_fw *tas_fw = tas_priv->fmw; - int nr_config = ucontrol->value.integer.value[0]; - int max = tas_fw->nr_configurations - 1; - int val, ret = 0; + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n", + __func__, kcontrol->id.name, ucontrol->value.integer.value[0]); - val = clamp(nr_config, 0, max); - - if (tas_priv->cur_conf != val) { - tas_priv->cur_conf = val; - ret = 1; - } + mutex_unlock(&tas_priv->codec_lock); return ret; } -/* - * tas2781_digital_getvol - get the volum control - * @kcontrol: control pointer - * @ucontrol: User data - * Customer Kcontrol for tas2781 is primarily for regmap booking, paging - * depends on internal regmap mechanism. - * tas2781 contains book and page two-level register map, especially - * book switching will set the register BXXP00R7F, after switching to the - * correct book, then leverage the mechanism for paging to access the - * register. - */ -static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - - return tasdevice_digital_getvol(tas_priv, ucontrol, mc); -} - -static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, +static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + int ret; - return tasdevice_amp_getvol(tas_priv, ucontrol, mc); -} + mutex_lock(&tas_priv->codec_lock); -static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n", + __func__, kcontrol->id.name, ucontrol->value.integer.value[0]); - /* The check of the given value is in tasdevice_digital_putvol. */ - return tasdevice_digital_putvol(tas_priv, ucontrol, mc); -} + /* The check of the given value is in tasdevice_amp_putvol. */ + ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc); -static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + mutex_unlock(&tas_priv->codec_lock); - /* The check of the given value is in tasdevice_amp_putvol. */ - return tasdevice_amp_putvol(tas_priv, ucontrol, mc); + return ret; } static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, @@ -352,9 +211,13 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, { struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + mutex_lock(&tas_priv->codec_lock); + ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status; - dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__, - tas_priv->force_fwload_status ? "ON" : "OFF"); + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", + __func__, kcontrol->id.name, tas_priv->force_fwload_status); + + mutex_unlock(&tas_priv->codec_lock); return 0; } @@ -365,14 +228,20 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); bool change, val = (bool)ucontrol->value.integer.value[0]; + mutex_lock(&tas_priv->codec_lock); + + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", + __func__, kcontrol->id.name, + tas_priv->force_fwload_status, val); + if (tas_priv->force_fwload_status == val) change = false; else { change = true; tas_priv->force_fwload_status = val; } - dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__, - tas_priv->force_fwload_status ? "ON" : "OFF"); + + mutex_unlock(&tas_priv->codec_lock); return change; } @@ -381,9 +250,6 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, tas2781_amp_putvol, amp_vol_tlv), - ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL, - 0, 0, 200, 1, tas2781_digital_getvol, - tas2781_digital_putvol, dvc_tlv), ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, tas2781_force_fwload_get, tas2781_force_fwload_put), }; @@ -412,175 +278,114 @@ static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = { .put = tasdevice_config_put, }; -static void tas2563_apply_calib(struct tasdevice_priv *tas_priv) -{ - int offset = 0; - __be32 data; - int ret; - - for (int i = 0; i < tas_priv->ndev; i++) { - for (int j = 0; j < TAS2563_CAL_N; ++j) { - data = cpu_to_be32( - *(uint32_t *)&tas_priv->cali_data.data[offset]); - ret = tasdevice_dev_bulk_write(tas_priv, i, cal_regs[j], - (unsigned char *)&data, TAS2563_CAL_DATA_SIZE); - if (ret) - dev_err(tas_priv->dev, - "Error writing calib regs\n"); - offset += TAS2563_CAL_DATA_SIZE; - } - } -} - -static int tas2563_save_calibration(struct tasdevice_priv *tas_priv) +static int tas2563_save_calibration(struct tas2781_hda *h) { - static efi_guid_t efi_guid = EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, - 0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92); - - static efi_char16_t *efi_vars[TAS2563_MAX_CHANNELS][TAS2563_CAL_N] = { - { L"Power_1", L"R0_1", L"InvR0_1", L"R0_Low_1", L"TLim_1" }, - { L"Power_2", L"R0_2", L"InvR0_2", L"R0_Low_2", L"TLim_2" }, - { L"Power_3", L"R0_3", L"InvR0_3", L"R0_Low_3", L"TLim_3" }, - { L"Power_4", L"R0_4", L"InvR0_4", L"R0_Low_4", L"TLim_4" }, + efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO]; + char *vars[TASDEV_CALIB_N] = { + "R0_%d", "InvR0_%d", "R0_Low_%d", "Power_%d", "TLim_%d" }; - + efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX]; unsigned long max_size = TAS2563_CAL_DATA_SIZE; + unsigned char var8[TAS2563_CAL_VAR_NAME_MAX]; + struct tasdevice_priv *p = h->hda_priv; + struct calidata *cd = &p->cali_data; + struct cali_reg *r = &cd->cali_reg_array; unsigned int offset = 0; + unsigned char *data; efi_status_t status; unsigned int attr; + int ret, i, j, k; - tas_priv->cali_data.data = devm_kzalloc(tas_priv->dev, - TAS2563_CAL_ARRAY_SIZE, GFP_KERNEL); - if (!tas_priv->cali_data.data) + cd->cali_dat_sz_per_dev = TAS2563_CAL_DATA_SIZE * TASDEV_CALIB_N; + + /* extra byte for each device is the device number */ + cd->total_sz = (cd->cali_dat_sz_per_dev + 1) * p->ndev; + data = cd->data = devm_kzalloc(p->dev, cd->total_sz, + GFP_KERNEL); + if (!data) return -ENOMEM; - for (int i = 0; i < tas_priv->ndev; ++i) { - for (int j = 0; j < TAS2563_CAL_N; ++j) { - status = efi.get_variable(efi_vars[i][j], + for (i = 0; i < p->ndev; ++i) { + data[offset] = i; + offset++; + for (j = 0; j < TASDEV_CALIB_N; ++j) { + ret = snprintf(var8, sizeof(var8), vars[j], i); + + if (ret < 0 || ret >= sizeof(var8) - 1) { + dev_err(p->dev, "%s: Read %s failed\n", + __func__, var8); + return -EINVAL; + } + /* + * Our variable names are ASCII by construction, but + * EFI names are wide chars. Convert and zero-pad. + */ + memset(efi_name, 0, sizeof(efi_name)); + for (k = 0; k < sizeof(var8) && var8[k]; k++) + efi_name[k] = var8[k]; + status = efi.get_variable(efi_name, &efi_guid, &attr, &max_size, - &tas_priv->cali_data.data[offset]); + &data[offset]); if (status != EFI_SUCCESS || max_size != TAS2563_CAL_DATA_SIZE) { - dev_warn(tas_priv->dev, - "Calibration data read failed %ld\n", status); + dev_warn(p->dev, + "Dev %d: Caldat[%d] read failed %ld\n", + i, j, status); return -EINVAL; } offset += TAS2563_CAL_DATA_SIZE; } } - tas_priv->cali_data.total_sz = offset; - tasdevice_apply_calibration(tas_priv); - - return 0; -} - -static void tas2781_apply_calib(struct tasdevice_priv *tas_priv) -{ - static const unsigned char page_array[CALIB_MAX] = { - 0x17, 0x18, 0x18, 0x0d, 0x18 - }; - static const unsigned char rgno_array[CALIB_MAX] = { - 0x74, 0x0c, 0x14, 0x3c, 0x7c - }; - unsigned char *data; - int i, j, rc; - - for (i = 0; i < tas_priv->ndev; i++) { - data = tas_priv->cali_data.data + - i * TASDEVICE_SPEAKER_CALIBRATION_SIZE; - for (j = 0; j < CALIB_MAX; j++) { - rc = tasdevice_dev_bulk_write(tas_priv, i, - TASDEVICE_REG(0, page_array[j], rgno_array[j]), - &(data[4 * j]), 4); - if (rc < 0) - dev_err(tas_priv->dev, - "chn %d calib %d bulk_wr err = %d\n", - i, j, rc); - } - } -} - -/* Update the calibration data, including speaker impedance, f0, etc, into algo. - * Calibrate data is done by manufacturer in the factory. These data are used - * by Algo for calculating the speaker temperature, speaker membrane excursion - * and f0 in real time during playback. - */ -static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) -{ - efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, - 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3); - static efi_char16_t efi_name[] = L"CALI_DATA"; - struct tm *tm = &tas_priv->tm; - unsigned int attr, crc; - unsigned int *tmp_val; - efi_status_t status; - - /* Lenovo devices */ - if (tas_priv->catlog_id == LENOVO) - efi_guid = EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, - 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92); - - tas_priv->cali_data.total_sz = 0; - /* Get real size of UEFI variable */ - status = efi.get_variable(efi_name, &efi_guid, &attr, - &tas_priv->cali_data.total_sz, tas_priv->cali_data.data); - if (status == EFI_BUFFER_TOO_SMALL) { - /* Allocate data buffer of data_size bytes */ - tas_priv->cali_data.data = devm_kzalloc(tas_priv->dev, - tas_priv->cali_data.total_sz, GFP_KERNEL); - if (!tas_priv->cali_data.data) - return -ENOMEM; - /* Get variable contents into buffer */ - status = efi.get_variable(efi_name, &efi_guid, &attr, - &tas_priv->cali_data.total_sz, - tas_priv->cali_data.data); - } - if (status != EFI_SUCCESS) + if (cd->total_sz != offset) { + dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) dismatch\n", + __func__, cd->total_sz, offset); return -EINVAL; + } - tmp_val = (unsigned int *)tas_priv->cali_data.data; - - crc = crc32(~0, tas_priv->cali_data.data, 84) ^ ~0; - dev_dbg(tas_priv->dev, "cali crc 0x%08x PK tmp_val 0x%08x\n", - crc, tmp_val[21]); + r->r0_reg = TAS2563_CAL_R0; + r->invr0_reg = TAS2563_CAL_INVR0; + r->r0_low_reg = TAS2563_CAL_R0_LOW; + r->pow_reg = TAS2563_CAL_POWER; + r->tlimit_reg = TAS2563_CAL_TLIM; - if (crc == tmp_val[21]) { - time64_to_tm(tmp_val[20], 0, tm); - dev_dbg(tas_priv->dev, "%4ld-%2d-%2d, %2d:%2d:%2d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - tasdevice_apply_calibration(tas_priv); - } else - tas_priv->cali_data.total_sz = 0; + /* + * TAS2781_FMWLIB supports two solutions of calibrated data. One is + * from the driver itself: driver reads the calibrated files directly + * during probe; The other from user space: during init of audio hal, + * the audio hal will pass the calibrated data via kcontrol interface. + * Driver will store this data in "struct calidata" for use. For hda + * device, calibrated data are usunally saved into UEFI. So Hda side + * codec driver use the mixture of these two solutions, driver reads + * the data from UEFI, then store this data in "struct calidata" for + * use. + */ + p->is_user_space_calidata = true; return 0; } static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) { + struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; struct hda_codec *codec = tas_hda->priv->codec; - if (tas_hda->dsp_prog_ctl) - snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); + snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); + snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); - if (tas_hda->dsp_conf_ctl) - snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); + for (int i = ARRAY_SIZE(hda_priv->snd_ctls) - 1; i >= 0; i--) + snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]); - for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--) - if (tas_hda->snd_ctls[i]) - snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]); - - if (tas_hda->prof_ctl) - snd_ctl_remove(codec->card, tas_hda->prof_ctl); + snd_ctl_remove(codec->card, tas_hda->prof_ctl); } static void tasdev_fw_ready(const struct firmware *fmw, void *context) { struct tasdevice_priv *tas_priv = context; struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); + struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; struct hda_codec *codec = tas_priv->codec; - int i, ret; + int i, ret, spk_id; pm_runtime_get_sync(tas_priv->dev); mutex_lock(&tas_priv->codec_lock); @@ -599,9 +404,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) } for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) { - tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i], + hda_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i], tas_priv); - ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]); + ret = snd_ctl_add(codec->card, hda_priv->snd_ctls[i]); if (ret) { dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n", @@ -613,8 +418,25 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) tasdevice_dsp_remove(tas_priv); tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; - scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X.bin", - codec->core.subsystem_id & 0xffff); + if (tas_priv->speaker_id != NULL) { + // Speaker id need to be checked for ASUS only. + spk_id = gpiod_get_value(tas_priv->speaker_id); + if (spk_id < 0) { + // Speaker id is not valid, use default. + dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id); + spk_id = 0; + } + snprintf(tas_priv->coef_binaryname, + sizeof(tas_priv->coef_binaryname), + "TAS2XXX%04X%d.bin", + lower_16_bits(codec->core.subsystem_id), + spk_id); + } else { + snprintf(tas_priv->coef_binaryname, + sizeof(tas_priv->coef_binaryname), + "TAS2XXX%04X.bin", + lower_16_bits(codec->core.subsystem_id)); + } ret = tasdevice_dsp_parser(tas_priv); if (ret) { dev_err(tas_priv->dev, "dspfw load %s error\n", @@ -653,15 +475,14 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) /* If calibrated data occurs error, dsp will still works with default * calibrated data inside algo. */ - tasdevice_save_calibration(tas_priv); + hda_priv->save_calibration(tas_hda); tasdevice_tuning_switch(tas_hda->priv, 0); tas_hda->priv->playback_started = true; out: mutex_unlock(&tas_hda->priv->codec_lock); - if (fmw) - release_firmware(fmw); + release_firmware(fmw); pm_runtime_mark_last_busy(tas_hda->dev); pm_runtime_put_autosuspend(tas_hda->dev); } @@ -670,40 +491,40 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, void *master_data) { struct tas2781_hda *tas_hda = dev_get_drvdata(dev); - struct hda_component *comps = master_data; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; struct hda_codec *codec; unsigned int subid; int ret; - if (!comps || tas_hda->priv->index < 0 || - tas_hda->priv->index >= HDA_MAX_COMPONENTS) + comp = hda_component_from_index(parent, tas_hda->priv->index); + if (!comp) return -EINVAL; - comps = &comps[tas_hda->priv->index]; - if (comps->dev) + if (comp->dev) return -EBUSY; - codec = comps->codec; + codec = parent->codec; subid = codec->core.subsystem_id >> 16; switch (subid) { - case 0x17aa: - tas_hda->priv->catlog_id = LENOVO; + case 0x1028: + tas_hda->catlog_id = DELL; break; default: - tas_hda->priv->catlog_id = OTHERS; + tas_hda->catlog_id = LENOVO; break; } pm_runtime_get_sync(dev); - comps->dev = dev; + comp->dev = dev; - strscpy(comps->name, dev_name(dev), sizeof(comps->name)); + strscpy(comp->name, dev_name(dev), sizeof(comp->name)); ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready); if (!ret) - comps->playback_hook = tas2781_hda_playback_hook; + comp->playback_hook = tas2781_hda_playback_hook; pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -715,13 +536,14 @@ static void tas2781_hda_unbind(struct device *dev, struct device *master, void *master_data) { struct tas2781_hda *tas_hda = dev_get_drvdata(dev); - struct hda_component *comps = master_data; - comps = &comps[tas_hda->priv->index]; - - if (comps->dev == dev) { - comps->dev = NULL; - memset(comps->name, 0, sizeof(comps->name)); - comps->playback_hook = NULL; + struct hda_component_parent *parent = master_data; + struct hda_component *comp; + + comp = hda_component_from_index(parent, tas_hda->priv->index); + if (comp && (comp->dev == dev)) { + comp->dev = NULL; + memset(comp->name, 0, sizeof(comp->name)); + comp->playback_hook = NULL; } tas2781_hda_remove_controls(tas_hda); @@ -737,31 +559,23 @@ static const struct component_ops tas2781_hda_comp_ops = { .unbind = tas2781_hda_unbind, }; -static void tas2781_hda_remove(struct device *dev) -{ - struct tas2781_hda *tas_hda = dev_get_drvdata(dev); - - pm_runtime_get_sync(tas_hda->dev); - pm_runtime_disable(tas_hda->dev); - - component_del(tas_hda->dev, &tas2781_hda_comp_ops); - - pm_runtime_put_noidle(tas_hda->dev); - - tasdevice_remove(tas_hda->priv); -} - static int tas2781_hda_i2c_probe(struct i2c_client *clt) { + struct tas2781_hda_i2c_priv *hda_priv; struct tas2781_hda *tas_hda; const char *device_name; int ret; - tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL); if (!tas_hda) return -ENOMEM; + hda_priv = devm_kzalloc(&clt->dev, sizeof(*hda_priv), GFP_KERNEL); + if (!hda_priv) + return -ENOMEM; + + tas_hda->hda_priv = hda_priv; + dev_set_drvdata(&clt->dev, tas_hda); tas_hda->dev = &clt->dev; @@ -771,18 +585,16 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) if (strstr(dev_name(&clt->dev), "TIAS2781")) { device_name = "TIAS2781"; - tas_hda->priv->save_calibration = tas2781_save_calibration; - tas_hda->priv->apply_calibration = tas2781_apply_calib; + hda_priv->save_calibration = tas2781_save_calibration; tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; } else if (strstr(dev_name(&clt->dev), "INT8866")) { device_name = "INT8866"; - tas_hda->priv->save_calibration = tas2563_save_calibration; - tas_hda->priv->apply_calibration = tas2563_apply_calib; + hda_priv->save_calibration = tas2563_save_calibration; tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR; } else return -ENODEV; - tas_hda->priv->irq_info.irq = clt->irq; + tas_hda->priv->irq = clt->irq; ret = tas2781_read_acpi(tas_hda->priv, device_name); if (ret) return dev_err_probe(tas_hda->dev, ret, @@ -798,7 +610,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) pm_runtime_set_active(tas_hda->dev); pm_runtime_enable(tas_hda->dev); - tas2781_reset(tas_hda->priv); + tasdevice_reset(tas_hda->priv); ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops); if (ret) { @@ -808,13 +620,13 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) err: if (ret) - tas2781_hda_remove(&clt->dev); + tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops); return ret; } static void tas2781_hda_i2c_remove(struct i2c_client *clt) { - tas2781_hda_remove(&clt->dev); + tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops); } static int tas2781_runtime_suspend(struct device *dev) @@ -848,11 +660,6 @@ static int tas2781_runtime_resume(struct device *dev) tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); - /* If calibrated data occurs error, dsp will still works with default - * calibrated data inside algo. - */ - tasdevice_apply_calibration(tas_hda->priv); - mutex_unlock(&tas_hda->priv->codec_lock); return 0; @@ -893,14 +700,9 @@ static int tas2781_system_resume(struct device *dev) tas_hda->priv->tasdevice[i].cur_prog = -1; tas_hda->priv->tasdevice[i].cur_conf = -1; } - tas2781_reset(tas_hda->priv); + tasdevice_reset(tas_hda->priv); tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); - /* If calibrated data occurs error, dsp will still work with default - * calibrated data inside algo. - */ - tasdevice_apply_calibration(tas_hda->priv); - if (tas_hda->priv->playback_started) tasdevice_tuning_switch(tas_hda->priv, 0); @@ -915,7 +717,7 @@ static const struct dev_pm_ops tas2781_hda_pm_ops = { }; static const struct i2c_device_id tas2781_hda_i2c_id[] = { - { "tas2781-hda", 0 }, + { "tas2781-hda" }, {} }; @@ -941,4 +743,5 @@ module_i2c_driver(tas2781_hda_i2c_driver); MODULE_DESCRIPTION("TAS2781 HDA Driver"); MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_TAS2781_FMWLIB); +MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB"); +MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781"); diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/pci/hda/tas2781_hda_spi.c new file mode 100644 index 000000000000..5c03e9d2283a --- /dev/null +++ b/sound/pci/hda/tas2781_hda_spi.c @@ -0,0 +1,958 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// TAS2781 HDA SPI driver +// +// Copyright 2024 - 2025 Texas Instruments, Inc. +// +// Author: Baojun Xu <baojun.xu@ti.com> + +#include <linux/acpi.h> +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/crc8.h> +#include <linux/crc32.h> +#include <linux/efi.h> +#include <linux/firmware.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <linux/time.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <sound/hda_codec.h> +#include <sound/soc.h> +#include <sound/tas2781.h> +#include <sound/tlv.h> +#include <sound/tas2781-tlv.h> + +#include "hda_local.h" +#include "hda_auto_parser.h" +#include "hda_component.h" +#include "hda_jack.h" +#include "hda_generic.h" +#include "tas2781_hda.h" + +#define TASDEVICE_RANGE_MAX_SIZE (256 * 128) +#define TASDEVICE_WIN_LEN 128 +#define TAS2781_SPI_MAX_FREQ (4 * HZ_PER_MHZ) +/* Flag of calibration registers address. */ +#define TASDEVICE_CALIBRATION_REG_ADDRESS BIT(7) +#define TASDEV_UEFI_CALI_REG_ADDR_FLG BIT(7) + +/* System Reset Check Register */ +#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c) +#define TAS2781_REG_CLK_CONFIG_RESET 0x19 + +struct tas2781_hda_spi_priv { + struct snd_kcontrol *snd_ctls[3]; +}; + +static const struct regmap_range_cfg tasdevice_ranges[] = { + { + .range_min = 0, + .range_max = TASDEVICE_RANGE_MAX_SIZE, + .selector_reg = TASDEVICE_PAGE_SELECT, + .selector_mask = GENMASK(7, 0), + .selector_shift = 0, + .window_start = 0, + .window_len = TASDEVICE_WIN_LEN, + }, +}; + +static const struct regmap_config tasdevice_regmap = { + .reg_bits = 8, + .val_bits = 8, + .zero_flag_mask = true, + .read_flag_mask = 0x01, + .reg_shift = -1, + .cache_type = REGCACHE_NONE, + .ranges = tasdevice_ranges, + .num_ranges = ARRAY_SIZE(tasdevice_ranges), + .max_register = TASDEVICE_RANGE_MAX_SIZE, +}; + +static int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv, + unsigned short chn, unsigned int reg, unsigned int *val) +{ + int ret; + + /* + * In our TAS2781 SPI mode, if read from other book (not book 0), + * or read from page number larger than 1 in book 0, one more byte + * read is needed, and first byte is a dummy byte, need to be ignored. + */ + if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) { + unsigned char data[2]; + + ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, + data, sizeof(data)); + *val = data[1]; + } else { + ret = tasdevice_dev_read(tas_priv, chn, reg, val); + } + if (ret < 0) + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + + return ret; +} + +static int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv, + unsigned short chn, unsigned int reg, unsigned char *data, + unsigned int len) +{ + int ret; + + /* + * In our TAS2781 SPI mode, if read from other book (not book 0), + * or read from page number larger than 1 in book 0, one more byte + * read is needed, and first byte is a dummy byte, need to be ignored. + */ + if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) { + unsigned char buf[TASDEVICE_WIN_LEN + 1]; + + ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, + buf, len + 1); + memcpy(data, buf + 1, len); + } else { + ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, data, len); + } + if (ret < 0) + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + + return ret; +} + +static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv, + unsigned short chn, unsigned int reg, unsigned int mask, + unsigned int value) +{ + int ret, val; + + /* + * In our TAS2781 SPI mode, read/write was masked in last bit of + * address, it cause regmap_update_bits() not work as expected. + */ + ret = tasdevice_dev_read(tas_priv, chn, reg, &val); + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + return ret; + } + + ret = tasdevice_dev_write(tas_priv, chn, TASDEVICE_PAGE_REG(reg), + (val & ~mask) | (mask & value)); + if (ret < 0) + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + + return ret; +} + +static int tasdevice_spi_change_chn_book(struct tasdevice_priv *p, + unsigned short chn, int book) +{ + int ret = 0; + + if (chn == p->index) { + struct tasdevice *tasdev = &p->tasdevice[chn]; + struct regmap *map = p->regmap; + + if (tasdev->cur_book != book) { + ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book); + if (ret < 0) + dev_err(p->dev, "%s, E=%d\n", __func__, ret); + else + tasdev->cur_book = book; + } + } else { + ret = -EXDEV; + dev_dbg(p->dev, "Not error, %s ignore channel(%d)\n", + __func__, chn); + } + + return ret; +} + +static void tas2781_spi_reset(struct tasdevice_priv *tas_dev) +{ + int ret; + + if (tas_dev->reset) { + gpiod_set_value_cansleep(tas_dev->reset, 0); + fsleep(800); + gpiod_set_value_cansleep(tas_dev->reset, 1); + } else { + ret = tasdevice_dev_write(tas_dev, tas_dev->index, + TASDEVICE_REG_SWRESET, TASDEVICE_REG_SWRESET_RESET); + if (ret < 0) { + dev_err(tas_dev->dev, "dev sw-reset fail, %d\n", ret); + return; + } + fsleep(1000); + } +} + +static int tascodec_spi_init(struct tasdevice_priv *tas_priv, + void *codec, struct module *module, + void (*cont)(const struct firmware *fw, void *context)) +{ + int ret; + + /* + * Codec Lock Hold to ensure that codec_probe and firmware parsing and + * loading do not simultaneously execute. + */ + guard(mutex)(&tas_priv->codec_lock); + + scnprintf(tas_priv->rca_binaryname, + sizeof(tas_priv->rca_binaryname), "%sRCA%d.bin", + tas_priv->dev_name, tas_priv->ndev); + crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL); + tas_priv->codec = codec; + ret = request_firmware_nowait(module, FW_ACTION_UEVENT, + tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv, + cont); + if (ret) + dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n", + ret); + + return ret; +} + +static void tasdevice_spi_init(struct tasdevice_priv *tas_priv) +{ + tas_priv->tasdevice[tas_priv->index].cur_book = -1; + tas_priv->tasdevice[tas_priv->index].cur_conf = -1; + tas_priv->tasdevice[tas_priv->index].cur_prog = -1; + + tas_priv->isspi = true; + + tas_priv->update_bits = tasdevice_spi_dev_update_bits; + tas_priv->change_chn_book = tasdevice_spi_change_chn_book; + tas_priv->dev_read = tasdevice_spi_dev_read; + tas_priv->dev_bulk_read = tasdevice_spi_dev_bulk_read; + + mutex_init(&tas_priv->codec_lock); +} + +static int tasdevice_spi_amp_putvol(struct tasdevice_priv *tas_priv, + struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) +{ + unsigned int invert = mc->invert; + unsigned char mask; + int max = mc->max; + int val, ret; + + mask = rounddown_pow_of_two(max); + mask <<= mc->shift; + val = clamp(invert ? max - ucontrol->value.integer.value[0] : + ucontrol->value.integer.value[0], 0, max); + + ret = tasdevice_spi_dev_update_bits(tas_priv, tas_priv->index, + mc->reg, mask, (unsigned int)(val << mc->shift)); + if (ret) + dev_err(tas_priv->dev, "set AMP vol error in dev %d\n", + tas_priv->index); + + return ret; +} + +static int tasdevice_spi_amp_getvol(struct tasdevice_priv *tas_priv, + struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) +{ + unsigned int invert = mc->invert; + unsigned char mask = 0; + int max = mc->max; + int ret, val; + + ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index, mc->reg, &val); + if (ret) { + dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__); + return ret; + } + + mask = rounddown_pow_of_two(max); + mask <<= mc->shift; + val = (val & mask) >> mc->shift; + val = clamp(invert ? max - val : val, 0, max); + ucontrol->value.integer.value[0] = val; + + return ret; +} + +static int tasdevice_spi_digital_putvol(struct tasdevice_priv *p, + struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) +{ + unsigned int invert = mc->invert; + int max = mc->max; + int val, ret; + + val = clamp(invert ? max - ucontrol->value.integer.value[0] : + ucontrol->value.integer.value[0], 0, max); + ret = tasdevice_dev_write(p, p->index, mc->reg, (unsigned int)val); + if (ret) + dev_err(p->dev, "set digital vol err in dev %d\n", p->index); + + return ret; +} + +static int tasdevice_spi_digital_getvol(struct tasdevice_priv *p, + struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) +{ + unsigned int invert = mc->invert; + int max = mc->max; + int ret, val; + + ret = tasdevice_spi_dev_read(p, p->index, mc->reg, &val); + if (ret) { + dev_err(p->dev, "%s, get digital vol err\n", __func__); + return ret; + } + + val = clamp(invert ? max - val : val, 0, max); + ucontrol->value.integer.value[0] = val; + + return ret; +} + +static int tas2781_read_acpi(struct tas2781_hda *tas_hda, + const char *hid, int id) +{ + struct tasdevice_priv *p = tas_hda->priv; + struct acpi_device *adev; + struct device *physdev; + u32 values[HDA_MAX_COMPONENTS]; + const char *property; + size_t nval; + int ret, i; + + adev = acpi_dev_get_first_match_dev(hid, NULL, -1); + if (!adev) { + dev_err(p->dev, "Failed to find ACPI device: %s\n", hid); + return -ENODEV; + } + + strscpy(p->dev_name, hid, sizeof(p->dev_name)); + physdev = get_device(acpi_get_first_physical_node(adev)); + acpi_dev_put(adev); + + property = "ti,dev-index"; + ret = device_property_count_u32(physdev, property); + if (ret <= 0 || ret > ARRAY_SIZE(values)) { + ret = -EINVAL; + goto err; + } + p->ndev = nval = ret; + + ret = device_property_read_u32_array(physdev, property, values, nval); + if (ret) + goto err; + + p->index = U8_MAX; + for (i = 0; i < nval; i++) { + if (values[i] == id) { + p->index = i; + break; + } + } + if (p->index == U8_MAX) { + dev_dbg(p->dev, "No index found in %s\n", property); + ret = -ENODEV; + goto err; + } + + if (p->index == 0) { + /* All of amps share same RESET pin. */ + p->reset = devm_gpiod_get_index_optional(physdev, "reset", + p->index, GPIOD_OUT_LOW); + if (IS_ERR(p->reset)) { + ret = PTR_ERR(p->reset); + dev_err_probe(p->dev, ret, "Failed on reset GPIO\n"); + goto err; + } + } + put_device(physdev); + + return 0; +err: + dev_err(p->dev, "read acpi error, ret: %d\n", ret); + put_device(physdev); + acpi_dev_put(adev); + + return ret; +} + +static void tas2781_hda_playback_hook(struct device *dev, int action) +{ + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct tasdevice_priv *tas_priv = tas_hda->priv; + + if (action == HDA_GEN_PCM_ACT_OPEN) { + pm_runtime_get_sync(dev); + guard(mutex)(&tas_priv->codec_lock); + if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK) + tasdevice_tuning_switch(tas_hda->priv, 0); + } else if (action == HDA_GEN_PCM_ACT_CLOSE) { + guard(mutex)(&tas_priv->codec_lock); + if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK) + tasdevice_tuning_switch(tas_priv, 1); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } +} + +/* + * tas2781_digital_getvol - get the volum control + * @kcontrol: control pointer + * @ucontrol: User data + * + * Customer Kcontrol for tas2781 is primarily for regmap booking, paging + * depends on internal regmap mechanism. + * tas2781 contains book and page two-level register map, especially + * book switching will set the register BXXP00R7F, after switching to the + * correct book, then leverage the mechanism for paging to access the + * register. + * + * Return 0 if succeeded. + */ +static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + guard(mutex)(&tas_priv->codec_lock); + return tasdevice_spi_digital_getvol(tas_priv, ucontrol, mc); +} + +static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + guard(mutex)(&tas_priv->codec_lock); + return tasdevice_spi_amp_getvol(tas_priv, ucontrol, mc); +} + +static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + guard(mutex)(&tas_priv->codec_lock); + return tasdevice_spi_digital_putvol(tas_priv, ucontrol, mc); +} + +static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + guard(mutex)(&tas_priv->codec_lock); + return tasdevice_spi_amp_putvol(tas_priv, ucontrol, mc); +} + +static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status; + dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__, + str_on_off(tas_priv->force_fwload_status)); + + return 0; +} + +static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + bool change, val = (bool)ucontrol->value.integer.value[0]; + + if (tas_priv->force_fwload_status == val) { + change = false; + } else { + change = true; + tas_priv->force_fwload_status = val; + } + dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__, + str_on_off(tas_priv->force_fwload_status)); + + return change; +} + +static struct snd_kcontrol_new tas2781_snd_ctls[] = { + ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_AMP_LEVEL, 1, 0, 20, 0, + tas2781_amp_getvol, tas2781_amp_putvol, amp_vol_tlv), + ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_DVC_LVL, 0, 0, 200, 1, + tas2781_digital_getvol, tas2781_digital_putvol, dvc_tlv), + ACARD_SINGLE_BOOL_EXT(NULL, 0, tas2781_force_fwload_get, + tas2781_force_fwload_put), +}; + +static struct snd_kcontrol_new tas2781_prof_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .info = tasdevice_info_profile, + .get = tasdevice_get_profile_id, + .put = tasdevice_set_profile_id, +}; + +static struct snd_kcontrol_new tas2781_dsp_ctls[] = { + /* Speaker Program */ + { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .info = tasdevice_info_programs, + .get = tasdevice_program_get, + .put = tasdevice_program_put, + }, + /* Speaker Config */ + { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .info = tasdevice_info_config, + .get = tasdevice_config_get, + .put = tasdevice_config_put, + }, +}; + +static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) +{ + struct hda_codec *codec = tas_hda->priv->codec; + struct tas2781_hda_spi_priv *h_priv = tas_hda->hda_priv; + + snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); + + snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); + + for (int i = ARRAY_SIZE(h_priv->snd_ctls) - 1; i >= 0; i--) + snd_ctl_remove(codec->card, h_priv->snd_ctls[i]); + + snd_ctl_remove(codec->card, tas_hda->prof_ctl); +} + +static int tas2781_hda_spi_prf_ctl(struct tas2781_hda *h) +{ + struct tasdevice_priv *p = h->priv; + struct hda_codec *c = p->codec; + char name[64]; + int rc; + + snprintf(name, sizeof(name), "Speaker-%d Profile Id", p->index); + tas2781_prof_ctl.name = name; + h->prof_ctl = snd_ctl_new1(&tas2781_prof_ctl, p); + rc = snd_ctl_add(c->card, h->prof_ctl); + if (rc) + dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n", + tas2781_prof_ctl.name, rc); + return rc; +} + +static int tas2781_hda_spi_snd_ctls(struct tas2781_hda *h) +{ + struct tas2781_hda_spi_priv *h_priv = h->hda_priv; + struct tasdevice_priv *p = h->priv; + struct hda_codec *c = p->codec; + char name[64]; + int i = 0; + int rc; + + snprintf(name, sizeof(name), "Speaker-%d Analog Volume", p->index); + tas2781_snd_ctls[i].name = name; + h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p); + rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]); + if (rc) { + dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n", + tas2781_snd_ctls[i].name, rc); + return rc; + } + i++; + snprintf(name, sizeof(name), "Speaker-%d Digital Volume", p->index); + tas2781_snd_ctls[i].name = name; + h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p); + rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]); + if (rc) { + dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n", + tas2781_snd_ctls[i].name, rc); + return rc; + } + i++; + snprintf(name, sizeof(name), "Froce Speaker-%d FW Load", p->index); + tas2781_snd_ctls[i].name = name; + h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p); + rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]); + if (rc) { + dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n", + tas2781_snd_ctls[i].name, rc); + } + return rc; +} + +static int tas2781_hda_spi_dsp_ctls(struct tas2781_hda *h) +{ + struct tasdevice_priv *p = h->priv; + struct hda_codec *c = p->codec; + char name[64]; + int i = 0; + int rc; + + snprintf(name, sizeof(name), "Speaker-%d Program Id", p->index); + tas2781_dsp_ctls[i].name = name; + h->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p); + rc = snd_ctl_add(c->card, h->dsp_prog_ctl); + if (rc) { + dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n", + tas2781_dsp_ctls[i].name, rc); + return rc; + } + i++; + snprintf(name, sizeof(name), "Speaker-%d Config Id", p->index); + tas2781_dsp_ctls[i].name = name; + h->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p); + rc = snd_ctl_add(c->card, h->dsp_conf_ctl); + if (rc) { + dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n", + tas2781_dsp_ctls[i].name, rc); + } + + return rc; +} + +static void tasdev_fw_ready(const struct firmware *fmw, void *context) +{ + struct tasdevice_priv *tas_priv = context; + struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); + struct hda_codec *codec = tas_priv->codec; + int ret, val; + + pm_runtime_get_sync(tas_priv->dev); + guard(mutex)(&tas_priv->codec_lock); + + ret = tasdevice_rca_parser(tas_priv, fmw); + if (ret) + goto out; + + /* Add control one time only. */ + ret = tas2781_hda_spi_prf_ctl(tas_hda); + if (ret) + goto out; + + ret = tas2781_hda_spi_snd_ctls(tas_hda); + if (ret) + goto out; + + tasdevice_dsp_remove(tas_priv); + + tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; + scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X-%01d.bin", + lower_16_bits(codec->core.subsystem_id), tas_priv->index); + ret = tasdevice_dsp_parser(tas_priv); + if (ret) { + dev_err(tas_priv->dev, "dspfw load %s error\n", + tas_priv->coef_binaryname); + tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; + goto out; + } + + ret = tas2781_hda_spi_dsp_ctls(tas_hda); + if (ret) + goto out; + /* Perform AMP reset before firmware download. */ + tas2781_spi_reset(tas_priv); + tas_priv->rcabin.profile_cfg_id = 0; + + tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; + ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index, + TAS2781_REG_CLK_CONFIG, &val); + if (ret < 0) + goto out; + + if (val == TAS2781_REG_CLK_CONFIG_RESET) { + ret = tasdevice_prmg_load(tas_priv, 0); + if (ret < 0) { + dev_err(tas_priv->dev, "FW download failed = %d\n", + ret); + goto out; + } + tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; + } + if (tas_priv->fmw->nr_programs > 0) + tas_priv->tasdevice[tas_priv->index].cur_prog = 0; + if (tas_priv->fmw->nr_configurations > 0) + tas_priv->tasdevice[tas_priv->index].cur_conf = 0; + + /* + * If calibrated data occurs error, dsp will still works with default + * calibrated data inside algo. + */ + tas2781_save_calibration(tas_hda); +out: + release_firmware(fmw); + pm_runtime_mark_last_busy(tas_hda->priv->dev); + pm_runtime_put_autosuspend(tas_hda->priv->dev); +} + +static int tas2781_hda_bind(struct device *dev, struct device *master, + void *master_data) +{ + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct hda_component_parent *parent = master_data; + struct hda_component *comp; + struct hda_codec *codec; + int ret; + + comp = hda_component_from_index(parent, tas_hda->priv->index); + if (!comp) + return -EINVAL; + + if (comp->dev) + return -EBUSY; + + codec = parent->codec; + + pm_runtime_get_sync(dev); + + comp->dev = dev; + + strscpy(comp->name, dev_name(dev), sizeof(comp->name)); + + ret = tascodec_spi_init(tas_hda->priv, codec, THIS_MODULE, + tasdev_fw_ready); + if (!ret) + comp->playback_hook = tas2781_hda_playback_hook; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return ret; +} + +static void tas2781_hda_unbind(struct device *dev, struct device *master, + void *master_data) +{ + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct hda_component_parent *parent = master_data; + struct tasdevice_priv *tas_priv = tas_hda->priv; + struct hda_component *comp; + + comp = hda_component_from_index(parent, tas_priv->index); + if (comp && (comp->dev == dev)) { + comp->dev = NULL; + memset(comp->name, 0, sizeof(comp->name)); + comp->playback_hook = NULL; + } + + tas2781_hda_remove_controls(tas_hda); + + tasdevice_config_info_remove(tas_priv); + tasdevice_dsp_remove(tas_priv); + + tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING; +} + +static const struct component_ops tas2781_hda_comp_ops = { + .bind = tas2781_hda_bind, + .unbind = tas2781_hda_unbind, +}; + +static int tas2781_hda_spi_probe(struct spi_device *spi) +{ + struct tas2781_hda_spi_priv *hda_priv; + struct tasdevice_priv *tas_priv; + struct tas2781_hda *tas_hda; + const char *device_name; + int ret = 0; + + tas_hda = devm_kzalloc(&spi->dev, sizeof(*tas_hda), GFP_KERNEL); + if (!tas_hda) + return -ENOMEM; + + hda_priv = devm_kzalloc(&spi->dev, sizeof(*hda_priv), GFP_KERNEL); + if (!hda_priv) + return -ENOMEM; + + tas_hda->hda_priv = hda_priv; + spi->max_speed_hz = TAS2781_SPI_MAX_FREQ; + + tas_priv = devm_kzalloc(&spi->dev, sizeof(*tas_priv), GFP_KERNEL); + if (!tas_priv) + return -ENOMEM; + tas_priv->dev = &spi->dev; + tas_hda->priv = tas_priv; + tas_priv->regmap = devm_regmap_init_spi(spi, &tasdevice_regmap); + if (IS_ERR(tas_priv->regmap)) { + ret = PTR_ERR(tas_priv->regmap); + dev_err(tas_priv->dev, "Failed to allocate regmap: %d\n", + ret); + return ret; + } + if (strstr(dev_name(&spi->dev), "TXNW2781")) { + device_name = "TXNW2781"; + } else { + dev_err(tas_priv->dev, "Unmatched spi dev %s\n", + dev_name(&spi->dev)); + return -ENODEV; + } + + tas_priv->irq = spi->irq; + dev_set_drvdata(&spi->dev, tas_hda); + ret = tas2781_read_acpi(tas_hda, device_name, + spi_get_chipselect(spi, 0)); + if (ret) + return dev_err_probe(tas_priv->dev, ret, + "Platform not supported\n"); + + tasdevice_spi_init(tas_priv); + + pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000); + pm_runtime_use_autosuspend(tas_priv->dev); + pm_runtime_mark_last_busy(tas_priv->dev); + pm_runtime_set_active(tas_priv->dev); + pm_runtime_get_noresume(tas_priv->dev); + pm_runtime_enable(tas_priv->dev); + + pm_runtime_put_autosuspend(tas_priv->dev); + + ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops); + if (ret) { + dev_err(tas_priv->dev, "Register component fail: %d\n", ret); + pm_runtime_disable(tas_priv->dev); + tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops); + } + + return ret; +} + +static void tas2781_hda_spi_remove(struct spi_device *spi) +{ + tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops); +} + +static int tas2781_runtime_suspend(struct device *dev) +{ + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct tasdevice_priv *tas_priv = tas_hda->priv; + + guard(mutex)(&tas_priv->codec_lock); + + if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK + && tas_priv->playback_started) + tasdevice_tuning_switch(tas_priv, 1); + + tas_priv->tasdevice[tas_priv->index].cur_book = -1; + tas_priv->tasdevice[tas_priv->index].cur_conf = -1; + + return 0; +} + +static int tas2781_runtime_resume(struct device *dev) +{ + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct tasdevice_priv *tas_priv = tas_hda->priv; + + guard(mutex)(&tas_priv->codec_lock); + + if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK + && tas_priv->playback_started) + tasdevice_tuning_switch(tas_priv, 0); + + return 0; +} + +static int tas2781_system_suspend(struct device *dev) +{ + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct tasdevice_priv *tas_priv = tas_hda->priv; + int ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + + /* Shutdown chip before system suspend */ + if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK + && tas_priv->playback_started) + tasdevice_tuning_switch(tas_priv, 1); + + return 0; +} + +static int tas2781_system_resume(struct device *dev) +{ + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct tasdevice_priv *tas_priv = tas_hda->priv; + int ret, val; + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + guard(mutex)(&tas_priv->codec_lock); + ret = tas_priv->dev_read(tas_priv, tas_priv->index, + TAS2781_REG_CLK_CONFIG, &val); + if (ret < 0) + return ret; + + if (val == TAS2781_REG_CLK_CONFIG_RESET) { + tas_priv->tasdevice[tas_priv->index].cur_book = -1; + tas_priv->tasdevice[tas_priv->index].cur_conf = -1; + tas_priv->tasdevice[tas_priv->index].cur_prog = -1; + + ret = tasdevice_prmg_load(tas_priv, 0); + if (ret < 0) { + dev_err(tas_priv->dev, + "FW download failed = %d\n", ret); + return ret; + } + tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; + + if (tas_priv->playback_started) + tasdevice_tuning_switch(tas_priv, 0); + } + + return ret; +} + +static const struct dev_pm_ops tas2781_hda_pm_ops = { + RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume) +}; + +static const struct spi_device_id tas2781_hda_spi_id[] = { + { "tas2781-hda", }, + {} +}; + +static const struct acpi_device_id tas2781_acpi_hda_match[] = { + {"TXNW2781", }, + {} +}; +MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match); + +static struct spi_driver tas2781_hda_spi_driver = { + .driver = { + .name = "tas2781-hda", + .acpi_match_table = tas2781_acpi_hda_match, + .pm = &tas2781_hda_pm_ops, + }, + .id_table = tas2781_hda_spi_id, + .probe = tas2781_hda_spi_probe, + .remove = tas2781_hda_spi_remove, +}; +module_spi_driver(tas2781_hda_spi_driver); + +MODULE_DESCRIPTION("TAS2781 HDA SPI Driver"); +MODULE_AUTHOR("Baojun, Xu, <baojun.xug@ti.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB"); +MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781"); diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 1196f22a9b45..f406a048374c 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile @@ -4,9 +4,9 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-ice17xx-ak4xxx-objs := ak4xxx.o -snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o psc724.o wm8766.o wm8776.o +snd-ice17xx-ak4xxx-y := ak4xxx.o +snd-ice1712-y := ice1712.o delta.o hoontech.o ews.o +snd-ice1724-y := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o psc724.o wm8766.o wm8776.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 3b0c3e70987b..a8ac14887676 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2502,7 +2502,7 @@ static int snd_ice1712_create(struct snd_card *card, pci_write_config_word(ice->pci, 0x42, 0x0006); snd_ice1712_proc_init(ice); - err = pci_request_regions(pci, "ICE1712"); + err = pcim_request_all_regions(pci, "ICE1712"); if (err < 0) return err; ice->port = pci_resource_start(pci, 0); diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 1dc776acd637..be22b159e65a 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2491,7 +2491,7 @@ static int snd_vt1724_create(struct snd_card *card, pci_set_master(pci); snd_vt1724_proc_init(ice); - err = pci_request_regions(pci, "ICE1724"); + err = pcim_request_all_regions(pci, "ICE1724"); if (err < 0) return err; ice->port = pci_resource_start(pci, 0); diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 096ec76f5304..a12dafbf53ab 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -170,14 +170,9 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el tmp = stac9460_get(ice, idx); ovol = 0x7f - (tmp & 0x7f); change = (ovol != nvol); - if (change) { - ovol = (0x7f - nvol) | (tmp & 0x80); - /* - dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n", - idx, ovol); - */ + if (change) stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); - } + return change; } diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index dae3e15ba534..51e7f1f1a48e 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -703,7 +703,6 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich if (!(status & ICH_BCIS)) { step = 0; } else if (civ == ichdev->civ) { - // snd_printd("civ same %d\n", civ); step = 1; ichdev->civ++; ichdev->civ &= ICH_REG_LVI_MASK; @@ -711,8 +710,6 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich step = civ - ichdev->civ; if (step < 0) step += ICH_REG_LVI_MASK + 1; - // if (step != 1) - // snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ); ichdev->civ = civ; } @@ -2929,7 +2926,7 @@ static int snd_intel8x0_init(struct snd_card *card, pci->device == PCI_DEVICE_ID_INTEL_440MX) chip->fix_nocache = 1; /* enable workaround */ - err = pci_request_regions(pci, card->shortname); + err = pcim_request_all_regions(pci, card->shortname); if (err < 0) return err; diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 3d6f5b3cc73e..1ce775fe8a70 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -423,7 +423,6 @@ static inline void snd_intel8x0m_update(struct intel8x0m *chip, struct ichdev *i civ = igetbyte(chip, port + ICH_REG_OFF_CIV); if (civ == ichdev->civ) { - // snd_printd("civ same %d\n", civ); step = 1; ichdev->civ++; ichdev->civ &= ICH_REG_LVI_MASK; @@ -431,8 +430,6 @@ static inline void snd_intel8x0m_update(struct intel8x0m *chip, struct ichdev *i step = civ - ichdev->civ; if (step < 0) step += ICH_REG_LVI_MASK + 1; - // if (step != 1) - // snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ); ichdev->civ = civ; } @@ -1063,7 +1060,7 @@ static int snd_intel8x0m_init(struct snd_card *card, chip->pci = pci; chip->irq = -1; - err = pci_request_regions(pci, card->shortname); + err = pcim_request_all_regions(pci, card->shortname); if (err < 0) return err; diff --git a/sound/pci/korg1212/Makefile b/sound/pci/korg1212/Makefile index 42eb287c77af..ab0186ffbd58 100644 --- a/sound/pci/korg1212/Makefile +++ b/sound/pci/korg1212/Makefile @@ -4,7 +4,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-korg1212-objs := korg1212.o +snd-korg1212-y := korg1212.o # Toplevel Module Dependency obj-$(CONFIG_SND_KORG1212) += snd-korg1212.o diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 5c2cac201a28..56dea5b10828 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -28,14 +28,14 @@ // ---------------------------------------------------------------------------- #define K1212_DEBUG_LEVEL 0 #if K1212_DEBUG_LEVEL > 0 -#define K1212_DEBUG_PRINTK(fmt,args...) printk(KERN_DEBUG fmt,##args) +#define K1212_DEBUG_PRINTK(fmt, args...) pr_debug(fmt, ##args) #else -#define K1212_DEBUG_PRINTK(fmt,...) do { } while (0) +#define K1212_DEBUG_PRINTK(fmt, ...) do { } while (0) #endif #if K1212_DEBUG_LEVEL > 1 -#define K1212_DEBUG_PRINTK_VERBOSE(fmt,args...) printk(KERN_DEBUG fmt,##args) +#define K1212_DEBUG_PRINTK_VERBOSE(fmt, args...) pr_debug(fmt, ##args) #else -#define K1212_DEBUG_PRINTK_VERBOSE(fmt,...) +#define K1212_DEBUG_PRINTK_VERBOSE(fmt, ...) #endif // ---------------------------------------------------------------------------- @@ -308,9 +308,6 @@ struct snd_korg1212 { spinlock_t lock; struct mutex open_mutex; - struct timer_list timer; /* timer callback for checking ack of stop request */ - int stop_pending_cnt; /* counter for stop pending check */ - wait_queue_head_t wait; unsigned long iomem; @@ -382,7 +379,7 @@ struct snd_korg1212 { unsigned long totalerrorcnt; // Total Error Count int dsp_is_loaded; - int dsp_stop_is_processed; + int dsp_stop_processing; }; @@ -565,52 +562,17 @@ static int snd_korg1212_Send1212Command(struct snd_korg1212 *korg1212, /* spinlock already held */ static void snd_korg1212_SendStop(struct snd_korg1212 *korg1212) { - if (! korg1212->stop_pending_cnt) { - korg1212->sharedBufferPtr->cardCommand = 0xffffffff; - /* program the timer */ - korg1212->stop_pending_cnt = HZ; - mod_timer(&korg1212->timer, jiffies + 1); - } + korg1212->dsp_stop_processing = 1; + korg1212->sharedBufferPtr->cardCommand = 0xffffffff; } static void snd_korg1212_SendStopAndWait(struct snd_korg1212 *korg1212) { unsigned long flags; spin_lock_irqsave(&korg1212->lock, flags); - korg1212->dsp_stop_is_processed = 0; snd_korg1212_SendStop(korg1212); spin_unlock_irqrestore(&korg1212->lock, flags); - wait_event_timeout(korg1212->wait, korg1212->dsp_stop_is_processed, (HZ * 3) / 2); -} - -/* timer callback for checking the ack of stop request */ -static void snd_korg1212_timer_func(struct timer_list *t) -{ - struct snd_korg1212 *korg1212 = from_timer(korg1212, t, timer); - unsigned long flags; - - spin_lock_irqsave(&korg1212->lock, flags); - if (korg1212->sharedBufferPtr->cardCommand == 0) { - /* ack'ed */ - korg1212->stop_pending_cnt = 0; - korg1212->dsp_stop_is_processed = 1; - wake_up(&korg1212->wait); - K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: Stop ack'ed [%s]\n", - stateName[korg1212->cardState]); - } else { - if (--korg1212->stop_pending_cnt > 0) { - /* reprogram timer */ - mod_timer(&korg1212->timer, jiffies + 1); - } else { - snd_printd("korg1212_timer_func timeout\n"); - korg1212->sharedBufferPtr->cardCommand = 0; - korg1212->dsp_stop_is_processed = 1; - wake_up(&korg1212->wait); - K1212_DEBUG_PRINTK("K1212_DEBUG: Stop timeout [%s]\n", - stateName[korg1212->cardState]); - } - } - spin_unlock_irqrestore(&korg1212->lock, flags); + wait_event_timeout(korg1212->wait, !korg1212->dsp_stop_processing, HZ); } static int snd_korg1212_TurnOnIdleMonitor(struct snd_korg1212 *korg1212) @@ -1131,11 +1093,13 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id) K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: IRQ DMAE count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]); - snd_printk(KERN_ERR "korg1212: DMA Error\n"); + dev_err(korg1212->card->dev, "korg1212: DMA Error\n"); korg1212->errorcnt++; korg1212->totalerrorcnt++; korg1212->sharedBufferPtr->cardCommand = 0; + korg1212->dsp_stop_processing = 0; snd_korg1212_setCardState(korg1212, K1212_STATE_ERRORSTOP); + wake_up(&korg1212->wait); break; // ------------------------------------------------------------------------ @@ -1147,6 +1111,8 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id) korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]); korg1212->sharedBufferPtr->cardCommand = 0; + korg1212->dsp_stop_processing = 0; + wake_up(&korg1212->wait); break; default: @@ -1272,8 +1238,8 @@ static int snd_korg1212_silence(struct snd_korg1212 *korg1212, int pos, int coun #if K1212_DEBUG_LEVEL > 0 if ( (void *) dst < (void *) korg1212->playDataBufsPtr || (void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) { - printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_silence KERNEL EFAULT dst=%p iter=%d\n", - dst, i); + pr_debug("K1212_DEBUG: %s KERNEL EFAULT dst=%p iter=%d\n", + __func__, dst, i); return -EFAULT; } #endif @@ -1305,7 +1271,8 @@ static int snd_korg1212_copy_to(struct snd_pcm_substream *substream, #if K1212_DEBUG_LEVEL > 0 if ( (void *) src < (void *) korg1212->recordDataBufsPtr || (void *) src > (void *) korg1212->recordDataBufsPtr[8].bufferData ) { - printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_copy_to KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst->kvec.iov_base, i); + pr_debug("K1212_DEBUG: %s KERNEL EFAULT, src=%p dst=%p iter=%d\n", + __func__, src, dst->kvec.iov_base, i); return -EFAULT; } #endif @@ -1330,8 +1297,8 @@ static int snd_korg1212_copy_from(struct snd_pcm_substream *substream, size = korg1212->channels * 2; dst = korg1212->playDataBufsPtr[0].bufferData + pos; - K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_from pos=%d size=%d count=%d\n", - pos, size, count); + K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: %s pos=%d size=%d count=%d\n", + __func__, pos, size, count); if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES)) return -EINVAL; @@ -1340,7 +1307,8 @@ static int snd_korg1212_copy_from(struct snd_pcm_substream *substream, #if K1212_DEBUG_LEVEL > 0 if ( (void *) dst < (void *) korg1212->playDataBufsPtr || (void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) { - printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_copy_from KERNEL EFAULT, src=%p dst=%p iter=%d\n", src->kvec.iov_base, dst, i); + pr_debug("K1212_DEBUG: %s KERNEL EFAULT, src=%p dst=%p iter=%d\n", + __func__, src->kvec.iov_base, dst, i); return -EFAULT; } #endif @@ -1533,6 +1501,14 @@ static int snd_korg1212_hw_params(struct snd_pcm_substream *substream, return 0; } +static int snd_korg1212_sync_stop(struct snd_pcm_substream *substream) +{ + struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); + + wait_event_timeout(korg1212->wait, !korg1212->dsp_stop_processing, HZ); + return 0; +} + static int snd_korg1212_prepare(struct snd_pcm_substream *substream) { struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream); @@ -1542,19 +1518,7 @@ static int snd_korg1212_prepare(struct snd_pcm_substream *substream) stateName[korg1212->cardState]); spin_lock_irq(&korg1212->lock); - - /* FIXME: we should wait for ack! */ - if (korg1212->stop_pending_cnt > 0) { - K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_prepare - Stop is pending... [%s]\n", - stateName[korg1212->cardState]); - spin_unlock_irq(&korg1212->lock); - return -EAGAIN; - /* - korg1212->sharedBufferPtr->cardCommand = 0; - del_timer(&korg1212->timer); - korg1212->stop_pending_cnt = 0; - */ - } + korg1212->dsp_stop_processing = 0; rc = snd_korg1212_SetupForPlay(korg1212); @@ -1666,6 +1630,7 @@ static const struct snd_pcm_ops snd_korg1212_playback_ops = { .hw_params = snd_korg1212_hw_params, .prepare = snd_korg1212_prepare, .trigger = snd_korg1212_trigger, + .sync_stop = snd_korg1212_sync_stop, .pointer = snd_korg1212_playback_pointer, .copy = snd_korg1212_playback_copy, .fill_silence = snd_korg1212_playback_silence, @@ -1678,6 +1643,7 @@ static const struct snd_pcm_ops snd_korg1212_capture_ops = { .hw_params = snd_korg1212_hw_params, .prepare = snd_korg1212_prepare, .trigger = snd_korg1212_trigger, + .sync_stop = snd_korg1212_sync_stop, .pointer = snd_korg1212_capture_pointer, .copy = snd_korg1212_capture_copy, }; @@ -2084,7 +2050,6 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) init_waitqueue_head(&korg1212->wait); spin_lock_init(&korg1212->lock); mutex_init(&korg1212->open_mutex); - timer_setup(&korg1212->timer, snd_korg1212_timer_func, 0); korg1212->irq = -1; korg1212->clkSource = K1212_CLKIDX_Local; @@ -2106,7 +2071,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) for (i=0; i<kAudioChannels; i++) korg1212->volumePhase[i] = 0; - err = pcim_iomap_regions_request_all(pci, 1 << 0, "korg1212"); + err = pcim_request_all_regions(pci, "korg1212"); if (err < 0) return err; @@ -2128,14 +2093,16 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) korg1212->iomem2, iomem2_size, stateName[korg1212->cardState]); - korg1212->iobase = pcim_iomap_table(pci)[0]; + korg1212->iobase = pcim_iomap(pci, 0, 0); + if (!korg1212->iobase) + return -ENOMEM; err = devm_request_irq(&pci->dev, pci->irq, snd_korg1212_interrupt, IRQF_SHARED, KBUILD_MODNAME, korg1212); if (err) { - snd_printk(KERN_ERR "korg1212: unable to grab IRQ %d\n", pci->irq); + dev_err(&pci->dev, "korg1212: unable to grab IRQ %d\n", pci->irq); return -EBUSY; } @@ -2232,7 +2199,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) err = request_firmware(&dsp_code, "korg/k1212.dsp", &pci->dev); if (err < 0) { - snd_printk(KERN_ERR "firmware not available\n"); + dev_err(&pci->dev, "firmware not available\n"); return err; } diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index 1aa30e90b86a..fb8bd54e4c2d 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -541,6 +541,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci, int dev) struct lola *chip = card->private_data; int err; unsigned int dever; + void __iomem *iomem; err = pcim_enable_device(pci); if (err < 0) @@ -580,14 +581,19 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci, int dev) chip->sample_rate_min = 16000; } - err = pcim_iomap_regions(pci, (1 << 0) | (1 << 2), DRVNAME); - if (err < 0) - return err; + iomem = pcim_iomap_region(pci, 0, DRVNAME); + if (IS_ERR(iomem)) + return PTR_ERR(iomem); + chip->bar[0].remap_addr = iomem; chip->bar[0].addr = pci_resource_start(pci, 0); - chip->bar[0].remap_addr = pcim_iomap_table(pci)[0]; + + iomem = pcim_iomap_region(pci, 2, DRVNAME); + if (IS_ERR(iomem)) + return PTR_ERR(iomem); + + chip->bar[1].remap_addr = iomem; chip->bar[1].addr = pci_resource_start(pci, 2); - chip->bar[1].remap_addr = pcim_iomap_table(pci)[2]; pci_set_master(pci); diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h index 0ff772cf66e6..25f72f9e3f9b 100644 --- a/sound/pci/lola/lola.h +++ b/sound/pci/lola/lola.h @@ -499,8 +499,6 @@ int lola_init_mixer_widget(struct lola *chip, int nid); void lola_free_mixer(struct lola *chip); int lola_create_mixer(struct lola *chip); int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute); -void lola_save_mixer(struct lola *chip); -void lola_restore_mixer(struct lola *chip); int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update); /* proc */ diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c index cafd30e30913..2e73fbf335ed 100644 --- a/sound/pci/lola/lola_clock.c +++ b/sound/pci/lola/lola_clock.c @@ -35,7 +35,7 @@ unsigned int lola_sample_rate_convert(unsigned int coded) default: return 0; /* error */ } - /* ajustement */ + /* adjustement */ switch (coded & 0x60) { case (0 << 5): break; case (1 << 5): freq = (freq * 999) / 1000; break; diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c index 6b162489cb5f..9cb26a8a4e1a 100644 --- a/sound/pci/lola/lola_mixer.c +++ b/sound/pci/lola/lola_mixer.c @@ -336,49 +336,6 @@ int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute) return lola_codec_flush(chip); } -void lola_save_mixer(struct lola *chip) -{ - /* mute analog output */ - if (chip->mixer.array_saved) { - /* store contents of mixer array */ - memcpy_fromio(chip->mixer.array_saved, chip->mixer.array, - sizeof(*chip->mixer.array)); - } - lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */ -} - -void lola_restore_mixer(struct lola *chip) -{ - int i; - - /*lola_reset_setups(chip);*/ - if (chip->mixer.array_saved) { - /* restore contents of mixer array */ - memcpy_toio(chip->mixer.array, chip->mixer.array_saved, - sizeof(*chip->mixer.array)); - /* inform micro-controller about all restored values - * and ignore return values - */ - for (i = 0; i < chip->mixer.src_phys_ins; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_SOURCE_GAIN, - i, 0); - for (i = 0; i < chip->mixer.src_stream_outs; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_SOURCE_GAIN, - chip->mixer.src_stream_out_ofs + i, 0); - for (i = 0; i < chip->mixer.dest_stream_ins; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - i, 0); - for (i = 0; i < chip->mixer.dest_phys_outs; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - chip->mixer.dest_phys_out_ofs + i, 0); - lola_codec_flush(chip); - } -} - /* */ diff --git a/sound/pci/lx6464es/Makefile b/sound/pci/lx6464es/Makefile index c295f68bac68..2b3047c7a388 100644 --- a/sound/pci/lx6464es/Makefile +++ b/sound/pci/lx6464es/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-lx6464es-objs := lx6464es.o lx_core.o +snd-lx6464es-y := lx6464es.o lx_core.o obj-$(CONFIG_SND_LX6464ES) += snd-lx6464es.o diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index bd9b6148dd6f..63ebf9803ea8 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -944,7 +944,7 @@ static int snd_lx6464es_create(struct snd_card *card, mutex_init(&chip->setup_mutex); /* request resources */ - err = pci_request_regions(pci, card_name); + err = pcim_request_all_regions(pci, card_name); if (err < 0) return err; diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index b5b0d43bb8dc..9d95ecb299ae 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -231,14 +231,14 @@ static void lx_message_dump(struct lx_rmh *rmh) u8 idx = rmh->cmd_idx; int i; - snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName); + pr_debug(LXRMH "command %s\n", dsp_commands[idx].dcOpName); for (i = 0; i != rmh->cmd_len; ++i) - snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]); + pr_debug(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]); for (i = 0; i != rmh->stat_len; ++i) - snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]); - snd_printk("\n"); + pr_debug(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]); + pr_debug("\n"); } #else static inline void lx_message_dump(struct lx_rmh *rmh) diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h index 296013c910b7..c1113439f7c9 100644 --- a/sound/pci/lx6464es/lx_core.h +++ b/sound/pci/lx6464es/lx_core.h @@ -129,21 +129,18 @@ int lx_stream_set_state(struct lx6464es *chip, u32 pipe, static inline int lx_stream_start(struct lx6464es *chip, u32 pipe, int is_capture) { - snd_printdd("->lx_stream_start\n"); return lx_stream_set_state(chip, pipe, is_capture, SSTATE_RUN); } static inline int lx_stream_pause(struct lx6464es *chip, u32 pipe, int is_capture) { - snd_printdd("->lx_stream_pause\n"); return lx_stream_set_state(chip, pipe, is_capture, SSTATE_PAUSE); } static inline int lx_stream_stop(struct lx6464es *chip, u32 pipe, int is_capture) { - snd_printdd("->lx_stream_stop\n"); return lx_stream_set_state(chip, pipe, is_capture, SSTATE_STOP); } diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index f4d211970d7e..e61e15774706 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2552,7 +2552,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, if (err < 0) return err; - err = pci_request_regions(pci, card->driver); + err = pcim_request_all_regions(pci, card->driver); if (err < 0) return err; diff --git a/sound/pci/mixart/Makefile b/sound/pci/mixart/Makefile index 16cfeb78a0b6..b803e5e72791 100644 --- a/sound/pci/mixart/Makefile +++ b/sound/pci/mixart/Makefile @@ -4,6 +4,6 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o +snd-mixart-y := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o obj-$(CONFIG_SND_MIXART) += snd-mixart.o diff --git a/sound/pci/nm256/Makefile b/sound/pci/nm256/Makefile index 3063766ac56b..7d55fe774d20 100644 --- a/sound/pci/nm256/Makefile +++ b/sound/pci/nm256/Makefile @@ -4,7 +4,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-nm256-objs := nm256.o +snd-nm256-y := nm256.o # Toplevel Module Dependency obj-$(CONFIG_SND_NM256) += snd-nm256.o diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 11ba7d4eac2a..cd4dc43dbff1 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -696,7 +696,9 @@ snd_nm256_playback_copy(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; - return copy_from_iter_toio(s->bufptr + pos, src, count); + if (copy_from_iter_toio(s->bufptr + pos, count, src) != count) + return -EFAULT; + return 0; } /* @@ -710,7 +712,9 @@ snd_nm256_capture_copy(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct nm256_stream *s = runtime->private_data; - return copy_to_iter_fromio(dst, s->bufptr + pos, count); + if (copy_to_iter_fromio(s->bufptr + pos, count, dst) != count) + return -EFAULT; + return 0; } #endif /* !__i386__ */ @@ -1443,7 +1447,7 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci) chip->buffer_addr = pci_resource_start(pci, 0); chip->cport_addr = pci_resource_start(pci, 1); - err = pci_request_regions(pci, card->driver); + err = pcim_request_all_regions(pci, card->driver); if (err < 0) return err; diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index 0dfc4f840992..cc0c24694750 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 -snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o -snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o -snd-se6x-objs := se6x.o -snd-virtuoso-objs := virtuoso.o xonar_lib.o \ +snd-oxygen-lib-y := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o +snd-oxygen-y := oxygen.o xonar_dg_mixer.o xonar_dg.o +snd-se6x-y := se6x.o +snd-virtuoso-y := virtuoso.o xonar_lib.o \ xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index c346f42befc2..ff7439634d76 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -854,11 +854,9 @@ static struct pci_driver oxygen_driver = { .name = KBUILD_MODNAME, .id_table = oxygen_ids, .probe = generic_oxygen_probe, -#ifdef CONFIG_PM_SLEEP .driver = { - .pm = &oxygen_pci_pm, + .pm = pm_sleep_ptr(&oxygen_pci_pm), }, -#endif }; module_pci_driver(oxygen_driver); diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 0cae640708f3..820026daf838 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -161,9 +161,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, const struct pci_device_id *id ) ); -#ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops oxygen_pci_pm; -#endif void oxygen_pci_shutdown(struct pci_dev *pci); /* oxygen_mixer.c */ diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 92ffe9dc20c5..39b8ccf37cdd 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -609,7 +609,7 @@ static int __oxygen_pci_probe(struct pci_dev *pci, int index, char *id, if (err < 0) return err; - err = pci_request_regions(pci, DRIVER); + err = pcim_request_all_regions(pci, DRIVER); if (err < 0) { dev_err(card->dev, "cannot reserve PCI resources\n"); return err; @@ -713,7 +713,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, } EXPORT_SYMBOL(oxygen_pci_probe); -#ifdef CONFIG_PM_SLEEP static int oxygen_pci_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -789,9 +788,7 @@ static int oxygen_pci_resume(struct device *dev) return 0; } -SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume); -EXPORT_SYMBOL(oxygen_pci_pm); -#endif /* CONFIG_PM_SLEEP */ +EXPORT_SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume); void oxygen_pci_shutdown(struct pci_dev *pci) { diff --git a/sound/pci/oxygen/se6x.c b/sound/pci/oxygen/se6x.c index 17650a5b1bfa..9d009015d97e 100644 --- a/sound/pci/oxygen/se6x.c +++ b/sound/pci/oxygen/se6x.c @@ -137,11 +137,9 @@ static struct pci_driver se6x_driver = { .name = KBUILD_MODNAME, .id_table = se6x_ids, .probe = se6x_probe, -#ifdef CONFIG_PM_SLEEP .driver = { - .pm = &oxygen_pci_pm, + .pm = pm_sleep_ptr(&oxygen_pci_pm), }, -#endif .shutdown = oxygen_pci_shutdown, }; diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 2e405133371f..ded62199da7f 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -82,11 +82,9 @@ static struct pci_driver xonar_driver = { .name = KBUILD_MODNAME, .id_table = xonar_ids, .probe = xonar_probe, -#ifdef CONFIG_PM_SLEEP .driver = { - .pm = &oxygen_pci_pm, + .pm = pm_sleep_ptr(&oxygen_pci_pm), }, -#endif .shutdown = oxygen_pci_shutdown, }; diff --git a/sound/pci/pcxhr/Makefile b/sound/pci/pcxhr/Makefile index 5993d86cfb5d..0ea1e5ccb56f 100644 --- a/sound/pci/pcxhr/Makefile +++ b/sound/pci/pcxhr/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o +snd-pcxhr-y := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c index f340458fd2e1..e1435afc4907 100644 --- a/sound/pci/pcxhr/pcxhr_mix22.c +++ b/sound/pci/pcxhr/pcxhr_mix22.c @@ -535,7 +535,7 @@ int hr222_update_analog_audio_level(struct snd_pcxhr *chip, { dev_dbg(chip->card->dev, "hr222_update_analog_audio_level(%s chan=%d)\n", - is_capture ? "capture" : "playback", channel); + snd_pcm_direction_name(is_capture), channel); if (is_capture) { int level_l, level_r, level_mic; /* we have to update all levels */ diff --git a/sound/pci/riptide/Makefile b/sound/pci/riptide/Makefile index 9a505bae243e..9b4e9595859a 100644 --- a/sound/pci/riptide/Makefile +++ b/sound/pci/riptide/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-riptide-objs := riptide.o +snd-riptide-y := riptide.o obj-$(CONFIG_SND_RIPTIDE) += snd-riptide.o diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 7e80686fb41a..578be0755b8a 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -380,6 +380,7 @@ struct riptideport { }; struct cmdif { + struct device *dev; struct riptideport *hwport; spinlock_t lock; unsigned int cmdcnt; /* cmd statistics */ @@ -727,7 +728,7 @@ static int loadfirmware(struct cmdif *cif, const unsigned char *img, } } } - snd_printdd("load firmware return %d\n", err); + dev_dbg(cif->dev, "load firmware return %d\n", err); return err; } @@ -740,7 +741,7 @@ alloclbuspath(struct cmdif *cif, unsigned char source, sink = *path & (~SPLIT_PATH); if (sink != E2SINK_MAX) { - snd_printdd("alloc path 0x%x->0x%x\n", source, sink); + dev_dbg(cif->dev, "alloc path 0x%x->0x%x\n", source, sink); SEND_PSEL(cif, source, sink); source = lbusin2out[sink][0]; type = lbusin2out[sink][1]; @@ -778,7 +779,7 @@ freelbuspath(struct cmdif *cif, unsigned char source, const unsigned char *path) sink = *path & (~SPLIT_PATH); if (sink != E2SINK_MAX) { - snd_printdd("free path 0x%x->0x%x\n", source, sink); + dev_dbg(cif->dev, "free path 0x%x->0x%x\n", source, sink); SEND_PCLR(cif, source, sink); source = lbusin2out[sink][0]; } @@ -811,8 +812,8 @@ static int writearm(struct cmdif *cif, u32 addr, u32 data, u32 mask) } else rptr.retlongs[0] &= ~mask; } - snd_printdd("send arm 0x%x 0x%x 0x%x return %d\n", addr, data, mask, - flag); + dev_dbg(cif->dev, "send arm 0x%x 0x%x 0x%x return %d\n", addr, data, mask, + flag); return flag; } @@ -832,14 +833,14 @@ static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm, hwport = cif->hwport; if (cif->errcnt > MAX_ERROR_COUNT) { if (cif->is_reset) { - snd_printk(KERN_ERR - "Riptide: Too many failed cmds, reinitializing\n"); + dev_err(cif->dev, + "Riptide: Too many failed cmds, reinitializing\n"); if (riptide_reset(cif, NULL) == 0) { cif->errcnt = 0; return -EIO; } } - snd_printk(KERN_ERR "Riptide: Initialization failed.\n"); + dev_err(cif->dev, "Riptide: Initialization failed.\n"); return -EINVAL; } if (ret) { @@ -899,21 +900,21 @@ static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm, if (time < cif->cmdtimemin) cif->cmdtimemin = time; if ((cif->cmdcnt) % 1000 == 0) - snd_printdd - ("send cmd %d time: %d mintime: %d maxtime %d err: %d\n", - cif->cmdcnt, cif->cmdtime, cif->cmdtimemin, - cif->cmdtimemax, cif->errcnt); + dev_dbg(cif->dev, + "send cmd %d time: %d mintime: %d maxtime %d err: %d\n", + cif->cmdcnt, cif->cmdtime, cif->cmdtimemin, + cif->cmdtimemax, cif->errcnt); return 0; errout: cif->errcnt++; spin_unlock_irqrestore(&cif->lock, irqflags); - snd_printdd - ("send cmd %d hw: 0x%x flag: 0x%x cmd: 0x%x parm: 0x%x ret: 0x%x 0x%x CMDE: %d DATF: %d failed %d\n", - cif->cmdcnt, (int)((void *)&(cmdport->stat) - (void *)hwport), - flags, cmd, parm, ret ? ret->retlongs[0] : 0, - ret ? ret->retlongs[1] : 0, IS_CMDE(cmdport), IS_DATF(cmdport), - err); + dev_dbg(cif->dev, + "send cmd %d hw: 0x%x flag: 0x%x cmd: 0x%x parm: 0x%x ret: 0x%x 0x%x CMDE: %d DATF: %d failed %d\n", + cif->cmdcnt, (int)((void *)&(cmdport->stat) - (void *)hwport), + flags, cmd, parm, ret ? ret->retlongs[0] : 0, + ret ? ret->retlongs[1] : 0, IS_CMDE(cmdport), IS_DATF(cmdport), + err); return err; } @@ -923,14 +924,14 @@ setmixer(struct cmdif *cif, short num, unsigned short rval, unsigned short lval) union cmdret rptr = CMDRET_ZERO; int i = 0; - snd_printdd("sent mixer %d: 0x%x 0x%x\n", num, rval, lval); + dev_dbg(cif->dev, "sent mixer %d: 0x%x 0x%x\n", num, rval, lval); do { SEND_SDGV(cif, num, num, rval, lval); SEND_RDGV(cif, num, num, &rptr); if (rptr.retwords[0] == lval && rptr.retwords[1] == rval) return 0; } while (i++ < MAX_WRITE_RETRY); - snd_printdd("sent mixer failed\n"); + dev_dbg(cif->dev, "sent mixer failed\n"); return -EIO; } @@ -961,7 +962,7 @@ getsourcesink(struct cmdif *cif, unsigned char source, unsigned char sink, return -EIO; *a = rptr.retbytes[0]; *b = rptr.retbytes[1]; - snd_printdd("getsourcesink 0x%x 0x%x\n", *a, *b); + dev_dbg(cif->dev, "%s 0x%x 0x%x\n", __func__, *a, *b); return 0; } @@ -988,11 +989,11 @@ getsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int *rate) } if (p[0]) { if (p[1] != p[0]) - snd_printdd("rates differ %d %d\n", p[0], p[1]); + dev_dbg(cif->dev, "rates differ %d %d\n", p[0], p[1]); *rate = (unsigned int)p[0]; } else *rate = (unsigned int)p[1]; - snd_printdd("getsampleformat %d %d %d\n", intdec[0], intdec[1], *rate); + dev_dbg(cif->dev, "getsampleformat %d %d %d\n", intdec[0], intdec[1], *rate); return 0; } @@ -1003,9 +1004,9 @@ setsampleformat(struct cmdif *cif, { unsigned char w, ch, sig, order; - snd_printdd - ("setsampleformat mixer: %d id: %d channels: %d format: %d\n", - mixer, id, channels, format); + dev_dbg(cif->dev, + "%s mixer: %d id: %d channels: %d format: %d\n", + __func__, mixer, id, channels, format); ch = channels == 1; w = snd_pcm_format_width(format) == 8; sig = snd_pcm_format_unsigned(format) != 0; @@ -1013,7 +1014,7 @@ setsampleformat(struct cmdif *cif, if (SEND_SETF(cif, mixer, w, ch, order, sig, id) && SEND_SETF(cif, mixer, w, ch, order, sig, id)) { - snd_printdd("setsampleformat failed\n"); + dev_dbg(cif->dev, "%s failed\n", __func__); return -EIO; } return 0; @@ -1026,8 +1027,8 @@ setsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int rate) union cmdret rptr = CMDRET_ZERO; int i; - snd_printdd("setsamplerate intdec: %d,%d rate: %d\n", intdec[0], - intdec[1], rate); + dev_dbg(cif->dev, "%s intdec: %d,%d rate: %d\n", __func__, + intdec[0], intdec[1], rate); D = 48000; M = ((rate == 48000) ? 47999 : rate) * 65536; N = M % D; @@ -1042,8 +1043,8 @@ setsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int rate) rptr.retwords[3] != N && i++ < MAX_WRITE_RETRY); if (i > MAX_WRITE_RETRY) { - snd_printdd("sent samplerate %d: %d failed\n", - *intdec, rate); + dev_dbg(cif->dev, "sent samplerate %d: %d failed\n", + *intdec, rate); return -EIO; } } @@ -1062,7 +1063,7 @@ getmixer(struct cmdif *cif, short num, unsigned short *rval, return -EIO; *rval = rptr.retwords[0]; *lval = rptr.retwords[1]; - snd_printdd("got mixer %d: 0x%x 0x%x\n", num, *rval, *lval); + dev_dbg(cif->dev, "got mixer %d: 0x%x 0x%x\n", num, *rval, *lval); return 0; } @@ -1105,8 +1106,8 @@ static irqreturn_t riptide_handleirq(int irq, void *dev_id) if ((flag & EOS_STATUS) && (data->state == ST_PLAY)) { data->state = ST_STOP; - snd_printk(KERN_ERR - "Riptide: DMA stopped unexpectedly\n"); + dev_err(cif->dev, + "Riptide: DMA stopped unexpectedly\n"); } c->dwStat_Ctl = cpu_to_le32(flag & @@ -1119,11 +1120,11 @@ static irqreturn_t riptide_handleirq(int irq, void *dev_id) period_bytes = frames_to_bytes(runtime, runtime->period_size); - snd_printdd - ("interrupt 0x%x after 0x%lx of 0x%lx frames in period\n", - READ_AUDIO_STATUS(cif->hwport), - bytes_to_frames(runtime, pos), - runtime->period_size); + dev_dbg(cif->dev, + "interrupt 0x%x after 0x%lx of 0x%lx frames in period\n", + READ_AUDIO_STATUS(cif->hwport), + bytes_to_frames(runtime, pos), + runtime->period_size); j = 0; if (pos >= period_bytes) { j++; @@ -1184,23 +1185,23 @@ static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) break; } if (!timeout) { - snd_printk(KERN_ERR - "Riptide: device not ready, audio status: 0x%x " - "ready: %d gerr: %d\n", - READ_AUDIO_STATUS(cif->hwport), - IS_READY(cif->hwport), IS_GERR(cif->hwport)); + dev_err(cif->dev, + "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n", + READ_AUDIO_STATUS(cif->hwport), + IS_READY(cif->hwport), IS_GERR(cif->hwport)); return -EIO; } else { - snd_printdd - ("Riptide: audio status: 0x%x ready: %d gerr: %d\n", - READ_AUDIO_STATUS(cif->hwport), - IS_READY(cif->hwport), IS_GERR(cif->hwport)); + dev_dbg(cif->dev, + "Riptide: audio status: 0x%x ready: %d gerr: %d\n", + READ_AUDIO_STATUS(cif->hwport), + IS_READY(cif->hwport), IS_GERR(cif->hwport)); } SEND_GETV(cif, &firmware.ret); - snd_printdd("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", - firmware.firmware.ASIC, firmware.firmware.CODEC, - firmware.firmware.AUXDSP, firmware.firmware.PROG); + dev_dbg(cif->dev, + "Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", + firmware.firmware.ASIC, firmware.firmware.CODEC, + firmware.firmware.AUXDSP, firmware.firmware.PROG); if (!chip) return 1; @@ -1211,20 +1212,20 @@ static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) } - snd_printdd("Writing Firmware\n"); + dev_dbg(cif->dev, "Writing Firmware\n"); if (!chip->fw_entry) { err = request_firmware(&chip->fw_entry, "riptide.hex", &chip->pci->dev); if (err) { - snd_printk(KERN_ERR - "Riptide: Firmware not available %d\n", err); + dev_err(cif->dev, + "Riptide: Firmware not available %d\n", err); return -EIO; } } err = loadfirmware(cif, chip->fw_entry->data, chip->fw_entry->size); if (err) { - snd_printk(KERN_ERR - "Riptide: Could not load firmware %d\n", err); + dev_err(cif->dev, + "Riptide: Could not load firmware %d\n", err); return err; } @@ -1257,7 +1258,7 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) SEND_SACR(cif, 0, AC97_RESET); SEND_RACR(cif, AC97_RESET, &rptr); - snd_printdd("AC97: 0x%x 0x%x\n", rptr.retlongs[0], rptr.retlongs[1]); + dev_dbg(cif->dev, "AC97: 0x%x 0x%x\n", rptr.retlongs[0], rptr.retlongs[1]); SEND_PLST(cif, 0); SEND_SLST(cif, 0); @@ -1350,11 +1351,11 @@ static snd_pcm_uframes_t snd_riptide_pointer(struct snd_pcm_substream SEND_GPOS(cif, 0, data->id, &rptr); if (data->size && runtime->period_size) { - snd_printdd - ("pointer stream %d position 0x%x(0x%x in buffer) bytes 0x%lx(0x%lx in period) frames\n", - data->id, rptr.retlongs[1], rptr.retlongs[1] % data->size, - bytes_to_frames(runtime, rptr.retlongs[1]), - bytes_to_frames(runtime, + dev_dbg(cif->dev, + "pointer stream %d position 0x%x(0x%x in buffer) bytes 0x%lx(0x%lx in period) frames\n", + data->id, rptr.retlongs[1], rptr.retlongs[1] % data->size, + bytes_to_frames(runtime, rptr.retlongs[1]), + bytes_to_frames(runtime, rptr.retlongs[1]) % runtime->period_size); if (rptr.retlongs[1] > data->pointer) ret = @@ -1365,8 +1366,9 @@ static snd_pcm_uframes_t snd_riptide_pointer(struct snd_pcm_substream bytes_to_frames(runtime, data->pointer % data->size); } else { - snd_printdd("stream not started or strange parms (%d %ld)\n", - data->size, runtime->period_size); + dev_dbg(cif->dev, + "stream not started or strange parms (%d %ld)\n", + data->size, runtime->period_size); ret = bytes_to_frames(runtime, 0); } return ret; @@ -1410,7 +1412,7 @@ static int snd_riptide_trigger(struct snd_pcm_substream *substream, int cmd) udelay(1); } while (i != rptr.retlongs[1] && j++ < MAX_WRITE_RETRY); if (j > MAX_WRITE_RETRY) - snd_printk(KERN_ERR "Riptide: Could not stop stream!"); + dev_err(cif->dev, "Riptide: Could not stop stream!"); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (!(data->state & ST_PAUSE)) { @@ -1448,8 +1450,8 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream) if (snd_BUG_ON(!cif || !data)) return -EINVAL; - snd_printdd("prepare id %d ch: %d f:0x%x r:%d\n", data->id, - runtime->channels, runtime->format, runtime->rate); + dev_dbg(cif->dev, "prepare id %d ch: %d f:0x%x r:%d\n", data->id, + runtime->channels, runtime->format, runtime->rate); spin_lock_irq(&chip->lock); channels = runtime->channels; @@ -1469,8 +1471,7 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream) lbuspath = data->paths.stereo; break; } - snd_printdd("use sgdlist at 0x%p\n", - data->sgdlist.area); + dev_dbg(cif->dev, "use sgdlist at 0x%p\n", data->sgdlist.area); if (data->sgdlist.area) { unsigned int i, j, size, pages, f, pt, period; struct sgd *c, *p = NULL; @@ -1483,9 +1484,9 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream) pages = DIV_ROUND_UP(size, f); data->size = size; data->pages = pages; - snd_printdd - ("create sgd size: 0x%x pages %d of size 0x%x for period 0x%x\n", - size, pages, f, period); + dev_dbg(cif->dev, + "create sgd size: 0x%x pages %d of size 0x%x for period 0x%x\n", + size, pages, f, period); pt = 0; j = 0; for (i = 0; i < pages; i++) { @@ -1543,17 +1544,18 @@ snd_riptide_hw_params(struct snd_pcm_substream *substream, struct snd_dma_buffer *sgdlist = &data->sgdlist; int err; - snd_printdd("hw params id %d (sgdlist: 0x%p 0x%lx %d)\n", data->id, - sgdlist->area, (unsigned long)sgdlist->addr, - (int)sgdlist->bytes); + dev_dbg(chip->card->dev, "hw params id %d (sgdlist: 0x%p 0x%lx %d)\n", + data->id, sgdlist->area, (unsigned long)sgdlist->addr, + (int)sgdlist->bytes); if (sgdlist->area) snd_dma_free_pages(sgdlist); err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, sizeof(struct sgd) * (DESC_MAX_MASK + 1), sgdlist); if (err < 0) { - snd_printk(KERN_ERR "Riptide: failed to alloc %d dma bytes\n", - (int)sizeof(struct sgd) * (DESC_MAX_MASK + 1)); + dev_err(chip->card->dev, + "Riptide: failed to alloc %d dma bytes\n", + (int)sizeof(struct sgd) * (DESC_MAX_MASK + 1)); return err; } data->sgdbuf = (struct sgd *)sgdlist->area; @@ -1729,13 +1731,13 @@ snd_riptide_codec_write(struct snd_ac97 *ac97, unsigned short reg, if (snd_BUG_ON(!cif)) return; - snd_printdd("Write AC97 reg 0x%x 0x%x\n", reg, val); + dev_dbg(cif->dev, "Write AC97 reg 0x%x 0x%x\n", reg, val); do { SEND_SACR(cif, val, reg); SEND_RACR(cif, reg, &rptr); } while (rptr.retwords[1] != val && i++ < MAX_WRITE_RETRY); if (i > MAX_WRITE_RETRY) - snd_printdd("Write AC97 reg failed\n"); + dev_dbg(cif->dev, "Write AC97 reg failed\n"); } static unsigned short snd_riptide_codec_read(struct snd_ac97 *ac97, @@ -1750,7 +1752,7 @@ static unsigned short snd_riptide_codec_read(struct snd_ac97 *ac97, if (SEND_RACR(cif, reg, &rptr) != 0) SEND_RACR(cif, reg, &rptr); - snd_printdd("Read AC97 reg 0x%x got 0x%x\n", reg, rptr.retwords[1]); + dev_dbg(cif->dev, "Read AC97 reg 0x%x got 0x%x\n", reg, rptr.retwords[1]); return rptr.retwords[1]; } @@ -1768,6 +1770,7 @@ static int snd_riptide_initialize(struct snd_riptide *chip) cif = kzalloc(sizeof(struct cmdif), GFP_KERNEL); if (!cif) return -ENOMEM; + cif->dev = chip->card->dev; cif->hwport = (struct riptideport *)chip->port; spin_lock_init(&cif->lock); chip->cif = cif; @@ -1781,11 +1784,11 @@ static int snd_riptide_initialize(struct snd_riptide *chip) case 0x4310: case 0x4320: case 0x4330: - snd_printdd("Modem enable?\n"); + dev_dbg(cif->dev, "Modem enable?\n"); SEND_SETDPLL(cif); break; } - snd_printdd("Enabling MPU IRQs\n"); + dev_dbg(cif->dev, "Enabling MPU IRQs\n"); if (chip->rmidi) SET_EMPUIRQ(cif->hwport); return err; @@ -1828,7 +1831,7 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci) chip->cif = NULL; card->private_free = snd_riptide_free; - err = pci_request_regions(pci, "RIPTIDE"); + err = pcim_request_all_regions(pci, "RIPTIDE"); if (err < 0) return err; hwport = (struct riptideport *)chip->port; @@ -1838,8 +1841,8 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci) snd_riptide_interrupt, riptide_handleirq, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n", - pci->irq); + dev_err(&pci->dev, "Riptide: unable to grab IRQ %d\n", + pci->irq); return -EBUSY; } chip->irq = pci->irq; @@ -1987,9 +1990,9 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) goto inc_dev; } if (!request_region(joystick_port[dev], 8, "Riptide gameport")) { - snd_printk(KERN_WARNING - "Riptide: cannot grab gameport 0x%x\n", - joystick_port[dev]); + dev_err(&pci->dev, + "Riptide: cannot grab gameport 0x%x\n", + joystick_port[dev]); gameport_free_port(gameport); ret = -EBUSY; goto inc_dev; @@ -2064,9 +2067,9 @@ __snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id val, MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi); if (err < 0) - snd_printk(KERN_WARNING - "Riptide: Can't Allocate MPU at 0x%x\n", - val); + dev_warn(&pci->dev, + "Riptide: Can't Allocate MPU at 0x%x\n", + val); else chip->mpuaddr = val; } @@ -2076,15 +2079,15 @@ __snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id err = snd_opl3_create(card, val, val + 2, OPL3_HW_RIPTIDE, 0, &chip->opl3); if (err < 0) - snd_printk(KERN_WARNING - "Riptide: Can't Allocate OPL3 at 0x%x\n", - val); + dev_warn(&pci->dev, + "Riptide: Can't Allocate OPL3 at 0x%x\n", + val); else { chip->opladdr = val; err = snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL); if (err < 0) - snd_printk(KERN_WARNING - "Riptide: Can't Allocate OPL3-HWDEP\n"); + dev_warn(&pci->dev, + "Riptide: Can't Allocate OPL3-HWDEP\n"); } } #ifdef SUPPORT_JOYSTICK diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 02144bbee6d5..4bf122abea48 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -256,8 +256,10 @@ static int snd_rme32_playback_copy(struct snd_pcm_substream *substream, { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - return copy_from_iter_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, - src, count); + if (copy_from_iter_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, + count, src) != count) + return -EFAULT; + return 0; } /* copy callback for halfduplex mode */ @@ -267,9 +269,10 @@ static int snd_rme32_capture_copy(struct snd_pcm_substream *substream, { struct rme32 *rme32 = snd_pcm_substream_chip(substream); - return copy_to_iter_fromio(dst, - rme32->iobase + RME32_IO_DATA_BUFFER + pos, - count); + if (copy_to_iter_fromio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, + count, dst) != count) + return -EFAULT; + return 0; } /* @@ -1281,7 +1284,7 @@ static int snd_rme32_create(struct rme32 *rme32) if (err < 0) return err; - err = pci_request_regions(pci, "RME32"); + err = pcim_request_all_regions(pci, "RME32"); if (err < 0) return err; rme32->port = pci_resource_start(rme32->pci, 0); diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index d50ad25574ad..01029843d7f3 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -322,8 +322,10 @@ snd_rme96_playback_copy(struct snd_pcm_substream *substream, { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - return copy_from_iter_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, - src, count); + if (copy_from_iter_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, + count, src) != count) + return -EFAULT; + return 0; } static int @@ -333,9 +335,10 @@ snd_rme96_capture_copy(struct snd_pcm_substream *substream, { struct rme96 *rme96 = snd_pcm_substream_chip(substream); - return copy_to_iter_fromio(dst, - rme96->iobase + RME96_IO_REC_BUFFER + pos, - count); + if (copy_to_iter_fromio(rme96->iobase + RME96_IO_REC_BUFFER + pos, + count, dst) != count) + return -EFAULT; + return 0; } /* @@ -1572,7 +1575,7 @@ snd_rme96_create(struct rme96 *rme96) if (err < 0) return err; - err = pci_request_regions(pci, "RME96"); + err = pcim_request_all_regions(pci, "RME96"); if (err < 0) return err; rme96->port = pci_resource_start(rme96->pci, 0); diff --git a/sound/pci/rme9652/Makefile b/sound/pci/rme9652/Makefile index a3351447ddc0..cc99ae892211 100644 --- a/sound/pci/rme9652/Makefile +++ b/sound/pci/rme9652/Makefile @@ -4,9 +4,9 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-rme9652-objs := rme9652.o -snd-hdsp-objs := hdsp.o -snd-hdspm-objs := hdspm.o +snd-rme9652-y := rme9652.o +snd-hdsp-y := hdsp.o +snd-hdspm-y := hdspm.o # Toplevel Module Dependency obj-$(CONFIG_SND_RME9652) += snd-rme9652.o diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index e7d1b43471a2..8df0f5bba0f6 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1298,8 +1298,10 @@ static int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id) static void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id) { - while (snd_hdsp_midi_input_available (hdsp, id)) - snd_hdsp_midi_read_byte (hdsp, id); + int count = 256; + + while (snd_hdsp_midi_input_available(hdsp, id) && --count) + snd_hdsp_midi_read_byte(hdsp, id); } static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi) @@ -1391,7 +1393,7 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, static void snd_hdsp_midi_output_timer(struct timer_list *t) { - struct hdsp_midi *hmidi = from_timer(hmidi, t, timer); + struct hdsp_midi *hmidi = timer_container_of(hmidi, t, timer); unsigned long flags; snd_hdsp_midi_output_write(hmidi); @@ -1425,7 +1427,7 @@ static void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream } } else { if (hmidi->istimer && --hmidi->istimer <= 0) - del_timer (&hmidi->timer); + timer_delete(&hmidi->timer); } spin_unlock_irqrestore (&hmidi->lock, flags); if (up) @@ -3442,7 +3444,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0)); snd_iprintf(buffer, "MIDI2 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut1)); snd_iprintf(buffer, "MIDI2 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn1)); - snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_work ? "on" : "off"); + snd_iprintf(buffer, "Use Midi Tasklet: %s\n", str_on_off(hdsp->use_midi_work)); snd_iprintf(buffer, "\n"); @@ -3450,8 +3452,8 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) snd_iprintf(buffer, "Buffer Size (Latency): %d samples (2 periods of %lu bytes)\n", x, (unsigned long) hdsp->period_bytes); snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", hdsp_hw_pointer(hdsp)); - snd_iprintf(buffer, "Precise pointer: %s\n", hdsp->precise_ptr ? "on" : "off"); - snd_iprintf(buffer, "Line out: %s\n", (hdsp->control_register & HDSP_LineOut) ? "on" : "off"); + snd_iprintf(buffer, "Precise pointer: %s\n", str_on_off(hdsp->precise_ptr)); + snd_iprintf(buffer, "Line out: %s\n", str_on_off(hdsp->control_register & HDSP_LineOut)); snd_iprintf(buffer, "Firmware version: %d\n", (status2&HDSP_version0)|(status2&HDSP_version1)<<1|(status2&HDSP_version2)<<2); @@ -3748,8 +3750,8 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) snd_iprintf(buffer, "Phones Gain : %s\n", tmp); snd_iprintf(buffer, "XLR Breakout Cable : %s\n", - hdsp_toggle_setting(hdsp, HDSP_XLRBreakoutCable) ? - "yes" : "no"); + str_yes_no(hdsp_toggle_setting(hdsp, + HDSP_XLRBreakoutCable))); if (hdsp->control_register & HDSP_AnalogExtensionBoard) snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n"); @@ -4299,14 +4301,6 @@ static const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_period_sizes .mask = 0 }; -static const unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; - -static const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_9632_sample_rates = { - .count = ARRAY_SIZE(hdsp_9632_sample_rates), - .list = hdsp_9632_sample_rates, - .mask = 0 -}; - static int snd_hdsp_hw_rule_in_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -4497,8 +4491,9 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream) runtime->hw.rate_min = runtime->hw.rate_max = hdsp->system_sample_rate; } else if (hdsp->io_type == H9632) { runtime->hw.rate_max = 192000; - runtime->hw.rates = SNDRV_PCM_RATE_KNOT; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates); + runtime->hw.rates |= (SNDRV_PCM_RATE_128000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000); } if (hdsp->io_type == H9632) { runtime->hw.channels_min = hdsp->qs_out_channels; @@ -4573,8 +4568,9 @@ static int snd_hdsp_capture_open(struct snd_pcm_substream *substream) runtime->hw.channels_min = hdsp->qs_in_channels; runtime->hw.channels_max = hdsp->ss_in_channels; runtime->hw.rate_max = 192000; - runtime->hw.rates = SNDRV_PCM_RATE_KNOT; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates); + runtime->hw.rates |= (SNDRV_PCM_RATE_128000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000); } snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, snd_hdsp_hw_rule_in_channels, hdsp, @@ -5281,7 +5277,7 @@ static int snd_hdsp_create(struct snd_card *card, pci_set_master(hdsp->pci); - err = pci_request_regions(pci, "hdsp"); + err = pcim_request_all_regions(pci, "hdsp"); if (err < 0) return err; hdsp->port = pci_resource_start(pci, 0); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 267c7848974a..2041cf00cca0 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1838,8 +1838,10 @@ static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id) static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id) { - while (snd_hdspm_midi_input_available (hdspm, id)) - snd_hdspm_midi_read_byte (hdspm, id); + int count = 256; + + while (snd_hdspm_midi_input_available(hdspm, id) && --count) + snd_hdspm_midi_read_byte(hdspm, id); } static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) @@ -1941,7 +1943,7 @@ snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) static void snd_hdspm_midi_output_timer(struct timer_list *t) { - struct hdspm_midi *hmidi = from_timer(hmidi, t, timer); + struct hdspm_midi *hmidi = timer_container_of(hmidi, t, timer); unsigned long flags; snd_hdspm_midi_output_write(hmidi); @@ -1976,7 +1978,7 @@ snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) } } else { if (hmidi->istimer && --hmidi->istimer <= 0) - del_timer (&hmidi->timer); + timer_delete(&hmidi->timer); } spin_unlock_irqrestore (&hmidi->lock, flags); if (up) @@ -3081,7 +3083,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, -#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \ +#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .access = SNDRV_CTL_ELEM_ACCESS_READ |\ @@ -3127,7 +3129,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, -#define HDSPM_TCO_LTC_FRAMES(xname, xindex) \ +#define HDSPM_TCO_LTC_FRAMES(xname) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .access = SNDRV_CTL_ELEM_ACCESS_READ |\ @@ -4628,8 +4630,8 @@ static const struct snd_kcontrol_new snd_hdspm_controls_tco[] = { HDSPM_TCO_WORD_TERM("TCO Word Term", 0), HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11), HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12), - HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0), - HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0) + HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate"), + HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format") }; @@ -4925,14 +4927,14 @@ snd_hdspm_proc_read_madi(struct snd_info_entry *entry, x, (unsigned long) hdspm->period_bytes); snd_iprintf(buffer, "Line out: %s\n", - (hdspm->control_register & HDSPM_LineOut) ? "on " : "off"); + str_on_off(hdspm->control_register & HDSPM_LineOut)); snd_iprintf(buffer, "ClearTrackMarker = %s, Transmit in %s Channel Mode, " "Auto Input %s\n", - (hdspm->control_register & HDSPM_clr_tms) ? "on" : "off", + str_on_off(hdspm->control_register & HDSPM_clr_tms), (hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56", - (hdspm->control_register & HDSPM_AutoInp) ? "on" : "off"); + str_on_off(hdspm->control_register & HDSPM_AutoInp)); if (!(hdspm->control_register & HDSPM_ClockModeMaster)) @@ -5086,12 +5088,9 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, snd_iprintf(buffer, "ClearTrackMarker %s, Emphasis %s, Dolby %s\n", - (hdspm-> - control_register & HDSPM_clr_tms) ? "on" : "off", - (hdspm-> - control_register & HDSPM_Emphasis) ? "on" : "off", - (hdspm-> - control_register & HDSPM_Dolby) ? "on" : "off"); + str_on_off(hdspm->control_register & HDSPM_clr_tms), + str_on_off(hdspm->control_register & HDSPM_Emphasis), + str_on_off(hdspm->control_register & HDSPM_Dolby)); pref_syncref = hdspm_pref_sync_ref(hdspm); @@ -5610,15 +5609,13 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, /* dev_dbg(hdspm->card->dev, "Allocated sample buffer for %s at 0x%08X\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "playback" : "capture", + snd_pcm_direction_name(substream->stream), snd_pcm_sgbuf_get_addr(substream, 0)); */ /* dev_dbg(hdspm->card->dev, "set_hwparams: %s %d Hz, %d channels, bs = %d\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "playback" : "capture", + snd_pcm_direction_name(substream->stream), params_rate(params), params_channels(params), params_buffer_size(params)); */ @@ -6032,18 +6029,6 @@ static int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params, return snd_interval_list(c, 3, list, 0); } - -static const unsigned int hdspm_aes32_sample_rates[] = { - 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 -}; - -static const struct snd_pcm_hw_constraint_list -hdspm_hw_constraints_aes32_sample_rates = { - .count = ARRAY_SIZE(hdspm_aes32_sample_rates), - .list = hdspm_aes32_sample_rates, - .mask = 0 -}; - static int snd_hdspm_open(struct snd_pcm_substream *substream) { struct hdspm *hdspm = snd_pcm_substream_chip(substream); @@ -6096,9 +6081,7 @@ static int snd_hdspm_open(struct snd_pcm_substream *substream) } if (AES32 == hdspm->io_type) { - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &hdspm_hw_constraints_aes32_sample_rates); + runtime->hw.rates |= SNDRV_PCM_RATE_128000; } else { snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, (playback ? @@ -6575,13 +6558,12 @@ static int snd_hdspm_create(struct snd_card *card, pci_set_master(hdspm->pci); - err = pcim_iomap_regions(pci, 1 << 0, "hdspm"); - if (err < 0) - return err; + hdspm->iobase = pcim_iomap_region(pci, 0, "hdspm"); + if (IS_ERR(hdspm->iobase)) + return PTR_ERR(hdspm->iobase); hdspm->port = pci_resource_start(pci, 0); io_extent = pci_resource_len(pci, 0); - hdspm->iobase = pcim_iomap_table(pci)[0]; dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n", (unsigned long)hdspm->iobase, hdspm->port, hdspm->port + io_extent - 1); diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index d066c70ae160..34d9c7995ddd 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1561,8 +1561,7 @@ snd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buff x, (unsigned long) rme9652->period_bytes); snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", rme9652_hw_pointer(rme9652)); - snd_iprintf(buffer, "Passthru: %s\n", - rme9652->passthru ? "yes" : "no"); + snd_iprintf(buffer, "Passthru: %s\n", str_yes_no(rme9652->passthru)); if ((rme9652->control_register & (RME9652_Master | RME9652_wsel)) == 0) { snd_iprintf(buffer, "Clock mode: autosync\n"); @@ -1685,7 +1684,7 @@ snd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buff snd_iprintf(buffer, "\n"); snd_iprintf(buffer, "Timecode signal: %s\n", - (status & RME9652_tc_valid) ? "yes" : "no"); + str_yes_no(status & RME9652_tc_valid)); /* thru modes */ @@ -2407,7 +2406,7 @@ static int snd_rme9652_create(struct snd_card *card, spin_lock_init(&rme9652->lock); - err = pci_request_regions(pci, "rme9652"); + err = pcim_request_all_regions(pci, "rme9652"); if (err < 0) return err; rme9652->port = pci_resource_start(pci, 0); diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 53206beb2cb5..42b22f123fa7 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -1273,7 +1273,7 @@ static int sis_chip_create(struct snd_card *card, sis->irq = -1; sis->ioport = pci_resource_start(pci, 0); - rc = pci_request_regions(pci, "SiS7019"); + rc = pcim_request_all_regions(pci, "SiS7019"); if (rc) { dev_err(&pci->dev, "unable request regions\n"); return rc; diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index f91cbf6eeca0..808a793ff4da 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1118,7 +1118,7 @@ static void snd_sonicvibes_proc_read(struct snd_info_entry *entry, tmp = sonic->srs_space & 0x0f; snd_iprintf(buffer, "SRS 3D : %s\n", - sonic->srs_space & 0x80 ? "off" : "on"); + str_off_on(sonic->srs_space & 0x80)); snd_iprintf(buffer, "SRS Space : %s\n", tmp == 0x00 ? "100%" : tmp == 0x01 ? "75%" : @@ -1135,9 +1135,9 @@ static void snd_sonicvibes_proc_read(struct snd_info_entry *entry, tmp == 0x00 ? "on-board ROM" : tmp == 0x01 ? "PCI bus" : "on-board ROM + PCI bus"); tmp = sonic->mpu_switch; - snd_iprintf(buffer, "Onboard synth : %s\n", tmp & 0x01 ? "on" : "off"); - snd_iprintf(buffer, "Ext. Rx to synth : %s\n", tmp & 0x02 ? "on" : "off"); - snd_iprintf(buffer, "MIDI to ext. Tx : %s\n", tmp & 0x04 ? "on" : "off"); + snd_iprintf(buffer, "Onboard synth : %s\n", str_on_off(tmp & 0x01)); + snd_iprintf(buffer, "Ext. Rx to synth : %s\n", str_on_off(tmp & 0x02)); + snd_iprintf(buffer, "MIDI to ext. Tx : %s\n", str_on_off(tmp & 0x04)); } static void snd_sonicvibes_proc_init(struct sonicvibes *sonic) @@ -1227,7 +1227,7 @@ static int snd_sonicvibes_create(struct snd_card *card, sonic->pci = pci; sonic->irq = -1; - err = pci_request_regions(pci, "S3 SonicVibes"); + err = pcim_request_all_regions(pci, "S3 SonicVibes"); if (err < 0) return err; diff --git a/sound/pci/trident/Makefile b/sound/pci/trident/Makefile index e8975bc37fcb..476d16abcfc9 100644 --- a/sound/pci/trident/Makefile +++ b/sound/pci/trident/Makefile @@ -4,7 +4,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-trident-objs := trident.o trident_main.o trident_memory.o +snd-trident-y := trident.o trident_main.o trident_memory.o # Toplevel Module Dependency obj-$(CONFIG_SND_TRIDENT) += snd-trident.o diff --git a/sound/pci/trident/trident.h b/sound/pci/trident/trident.h index 9768a7fc2349..ed2d4eecc704 100644 --- a/sound/pci/trident/trident.h +++ b/sound/pci/trident/trident.h @@ -406,7 +406,6 @@ int snd_trident_create_gameport(struct snd_trident *trident); int snd_trident_pcm(struct snd_trident *trident, int device); int snd_trident_foldback_pcm(struct snd_trident *trident, int device); int snd_trident_spdif_pcm(struct snd_trident *trident, int device); -int snd_trident_attach_synthesizer(struct snd_trident * trident); struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port); void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice); @@ -419,9 +418,5 @@ extern const struct dev_pm_ops snd_trident_pm; struct snd_util_memblk *snd_trident_alloc_pages(struct snd_trident *trident, struct snd_pcm_substream *substream); int snd_trident_free_pages(struct snd_trident *trident, struct snd_util_memblk *blk); -struct snd_util_memblk *snd_trident_synth_alloc(struct snd_trident *trident, unsigned int size); -int snd_trident_synth_free(struct snd_trident *trident, struct snd_util_memblk *blk); -int snd_trident_synth_copy_from_user(struct snd_trident *trident, struct snd_util_memblk *blk, - int offset, const char __user *data, int size); #endif /* __SOUND_TRIDENT_H */ diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index e98eea1e6d81..4e16b79d6584 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3278,9 +3278,9 @@ static void snd_trident_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "Spurious IRQs : %d\n", trident->spurious_irq_count); snd_iprintf(buffer, "Spurious IRQ dlta: %d\n", trident->spurious_irq_max_delta); if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) - snd_iprintf(buffer, "IEC958 Mixer Out : %s\n", trident->spdif_ctrl == 0x28 ? "on" : "off"); + snd_iprintf(buffer, "IEC958 Mixer Out : %s\n", str_on_off(trident->spdif_ctrl == 0x28)); if (trident->device == TRIDENT_DEVICE_ID_NX) { - snd_iprintf(buffer, "Rear Speakers : %s\n", trident->ac97_ctrl & 0x00000010 ? "on" : "off"); + snd_iprintf(buffer, "Rear Speakers : %s\n", str_on_off(trident->ac97_ctrl & 0x00000010)); if (trident->tlb.entries) { snd_iprintf(buffer,"\nVirtual Memory\n"); snd_iprintf(buffer, "Memory Maximum : %d\n", trident->tlb.memhdr->size); @@ -3533,7 +3533,7 @@ int snd_trident_create(struct snd_card *card, trident->midi_port = TRID_REG(trident, T4D_MPU401_BASE); pci_set_master(pci); - err = pci_request_regions(pci, "Trident Audio"); + err = pcim_request_all_regions(pci, "Trident Audio"); if (err < 0) return err; trident->port = pci_resource_start(pci, 0); diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 05de2b9f4ed7..4a36f194c7f8 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -137,14 +137,14 @@ __found_pages: /* * check if the given pointer is valid for pages */ -static int is_valid_page(unsigned long ptr) +static int is_valid_page(struct snd_trident *trident, unsigned long ptr) { if (ptr & ~0x3fffffffUL) { - snd_printk(KERN_ERR "max memory size is 1GB!!\n"); + dev_err(trident->card->dev, "max memory size is 1GB!!\n"); return 0; } if (ptr & (SNDRV_TRIDENT_PAGE_SIZE-1)) { - snd_printk(KERN_ERR "page is not aligned\n"); + dev_err(trident->card->dev, "page is not aligned\n"); return 0; } return 1; @@ -184,7 +184,7 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident, for (page = firstpg(blk); page <= lastpg(blk); page++, idx++) { unsigned long ofs = idx << PAGE_SHIFT; dma_addr_t addr = snd_pcm_sgbuf_get_addr(substream, ofs); - if (! is_valid_page(addr)) { + if (!is_valid_page(trident, addr)) { __snd_util_mem_free(hdr, blk); mutex_unlock(&hdr->block_mutex); return NULL; @@ -227,7 +227,7 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident, addr = runtime->dma_addr; for (page = firstpg(blk); page <= lastpg(blk); page++, addr += SNDRV_TRIDENT_PAGE_SIZE) { - if (! is_valid_page(addr)) { + if (!is_valid_page(trident, addr)) { __snd_util_mem_free(hdr, blk); mutex_unlock(&hdr->block_mutex); return NULL; diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 89838b4fb118..a04dbc0a420f 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2326,7 +2326,7 @@ static int snd_via82xx_create(struct snd_card *card, pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->old_legacy & ~(VIA_FUNC_ENABLE_SB|VIA_FUNC_ENABLE_FM)); - err = pci_request_regions(pci, card->driver); + err = pcim_request_all_regions(pci, card->driver); if (err < 0) return err; chip->port = pci_resource_start(pci, 0); diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index a0a49b8d1511..eef0f9ddaae0 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1071,7 +1071,7 @@ static int snd_via82xx_create(struct snd_card *card, chip->pci = pci; chip->irq = -1; - err = pci_request_regions(pci, card->driver); + err = pcim_request_all_regions(pci, card->driver); if (err < 0) return err; chip->port = pci_resource_start(pci, 0); diff --git a/sound/pci/vx222/Makefile b/sound/pci/vx222/Makefile index dda900e45385..6889137eb438 100644 --- a/sound/pci/vx222/Makefile +++ b/sound/pci/vx222/Makefile @@ -4,6 +4,6 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-vx222-objs := vx222.o vx222_ops.o +snd-vx222-y := vx222.o vx222_ops.o obj-$(CONFIG_SND_VX222) += snd-vx222.o diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 468a6a20dc1e..693a4e471cf7 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -123,7 +123,7 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci, vx = to_vx222(chip); vx->pci = pci; - err = pci_request_regions(pci, CARD_NAME); + err = pcim_request_all_regions(pci, KBUILD_MODNAME); if (err < 0) return err; for (i = 0; i < 2; i++) @@ -204,7 +204,6 @@ static int snd_vx222_probe(struct pci_dev *pci, return 0; } -#ifdef CONFIG_PM_SLEEP static int snd_vx222_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -221,18 +220,14 @@ static int snd_vx222_resume(struct device *dev) return snd_vx_resume(&vx->core); } -static SIMPLE_DEV_PM_OPS(snd_vx222_pm, snd_vx222_suspend, snd_vx222_resume); -#define SND_VX222_PM_OPS &snd_vx222_pm -#else -#define SND_VX222_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(snd_vx222_pm, snd_vx222_suspend, snd_vx222_resume); static struct pci_driver vx222_driver = { .name = KBUILD_MODNAME, .id_table = snd_vx222_ids, .probe = snd_vx222_probe, .driver = { - .pm = SND_VX222_PM_OPS, + .pm = pm_ptr(&snd_vx222_pm), }, }; diff --git a/sound/pci/ymfpci/Makefile b/sound/pci/ymfpci/Makefile index 40a1d83e1a9e..2d7856403371 100644 --- a/sound/pci/ymfpci/Makefile +++ b/sound/pci/ymfpci/Makefile @@ -4,7 +4,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-ymfpci-objs := ymfpci.o ymfpci_main.o +snd-ymfpci-y := ymfpci.o ymfpci_main.o # Toplevel Module Dependency obj-$(CONFIG_SND_YMFPCI) += snd-ymfpci.o diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 6b8d8690b6b2..d495f53a8324 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2307,7 +2307,7 @@ int snd_ymfpci_create(struct snd_card *card, chip->device_id = pci->device; chip->rev = pci->revision; - err = pci_request_regions(pci, "YMFPCI"); + err = pcim_request_all_regions(pci, "YMFPCI"); if (err < 0) return err; |