diff options
Diffstat (limited to 'sound/pci')
90 files changed, 2037 insertions, 4366 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 6e710dce5c60..88ac37739b76 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -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/ad1889.c b/sound/pci/ad1889.c index 9ed778b6b03c..ac27a93ce4ff 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -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/ali5451.c b/sound/pci/ali5451/ali5451.c index 793d2f13267e..69c02bdd38ce 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -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/asihpi.c b/sound/pci/asihpi/asihpi.c index 5a84591b13fc..7e5ce96954b9 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -518,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) @@ -2300,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; @@ -2319,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; @@ -2347,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/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/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/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 8a895d838005..053a18f434bf 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -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/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 cb8593c376ee..b00df0a60d3f 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2980,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); 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/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 9993b02d2968..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; diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index 0bb447ccd77c..aa179644b5c9 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -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/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..2ef59184249c 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -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/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 5b8a5ba825bd..bbe252b8916c 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1563,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/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/memory.c b/sound/pci/emu10k1/memory.c index d29711777161..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; } diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 71c89e4e3090..1e6adf1ae304 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -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 e393578cbe68..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,6 @@ 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 @@ -144,7 +149,6 @@ 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 @@ -159,7 +163,7 @@ 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 @@ -167,7 +171,6 @@ config SND_HDA_SCODEC_CS35L56_I2C 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 @@ -176,7 +179,7 @@ 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 @@ -184,19 +187,23 @@ config SND_HDA_SCODEC_CS35L56_SPI 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 help @@ -212,6 +219,10 @@ config SND_HDA_SCODEC_TAS2781_SPI 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 @@ -222,6 +233,7 @@ comment "Set to Y if you want auto-loading the side codec driver" 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 @@ -266,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, diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 210c406dfbc5..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-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 @@ -37,10 +38,10 @@ 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-cs-dsp-ctls-y := hda_cs_dsp_ctl.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 tas2781_spi_fwlib.o +snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o # common driver obj-$(CONFIG_SND_HDA) := snd-hda-codec.o @@ -70,8 +71,8 @@ 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 @@ -80,3 +81,4 @@ obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o # 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_test.c b/sound/pci/hda/cirrus_scodec_test.c index f5d6241daee4..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,10 +320,7 @@ 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, }; diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 5dc021976c79..d9c8872b1866 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -20,7 +20,6 @@ #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_PART "cs35l41" @@ -74,6 +73,21 @@ static const struct cirrus_amp_cal_controls cs35l41_calibration_controls = { .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); MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot" @@ -169,23 +183,23 @@ static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41, if (spkid > -1 && ssid && amp_name) *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], ssid, spkid, amp_name, filetype); else if (spkid > -1 && ssid) *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d.%s", CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], ssid, spkid, filetype); else if (ssid && amp_name) *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-%s.%s", CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], ssid, amp_name, filetype); else if (ssid) *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s.%s", CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], ssid, filetype); else *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s.%s", CS35L41_PART, - dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], + dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], filetype); if (*filename == NULL) @@ -588,7 +602,7 @@ static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41) } 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; @@ -1108,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; @@ -1137,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, @@ -1174,7 +1200,7 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) } dev_info(cs35l41->dev, "Firmware Loaded - Type: %s, Gain: %d\n", - hda_cs_dsp_fw_ids[cs35l41->firmware_type], cs35l41->tuning_gain); + cs35l41_hda_fw_ids[cs35l41->firmware_type], cs35l41->tuning_gain); return 0; @@ -1276,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; @@ -1290,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) @@ -1430,7 +1456,7 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas 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"); @@ -2055,7 +2081,6 @@ const struct dev_pm_ops cs35l41_hda_pm_ops = { 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"); diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 61d2314834e7..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 }, @@ -452,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 }, diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 4ef7878e8fd4..3f2fd32f4ad9 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" /* @@ -68,7 +67,7 @@ static void cs35l56_hda_play(struct cs35l56_hda *cs35l56) 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); @@ -180,7 +179,7 @@ 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; @@ -202,7 +201,7 @@ 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; @@ -231,13 +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; cs35l56_hda_wait_dsp_ready(cs35l56); - ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, &pos); + ret = regmap_read(cs35l56->base.regmap, + cs35l56->base.fw_reg->posture_number, &pos); if (ret) return ret; @@ -249,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; @@ -260,10 +260,8 @@ static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol, cs35l56_hda_wait_dsp_ready(cs35l56); - ret = regmap_update_bits_check(cs35l56->base.regmap, - CS35L56_MAIN_POSTURE_NUMBER, - CS35L56_MAIN_POSTURE_MASK, - pos, &changed); + ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->posture_number, + CS35L56_MAIN_POSTURE_MASK, pos, &changed); if (ret) return ret; @@ -298,14 +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; cs35l56_hda_wait_dsp_ready(cs35l56); - ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, &raw_vol); + ret = regmap_read(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume, &raw_vol); if (ret) return ret; @@ -324,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; @@ -339,10 +337,8 @@ static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol, cs35l56_hda_wait_dsp_ready(cs35l56); - ret = regmap_update_bits_check(cs35l56->base.regmap, - CS35L56_MAIN_RENDER_USER_VOLUME, - CS35L56_MAIN_RENDER_USER_VOLUME_MASK, - raw_vol, &changed); + 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; @@ -546,12 +542,10 @@ 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); } @@ -667,7 +661,8 @@ static void 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; @@ -680,6 +675,8 @@ static void 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); @@ -1120,7 +1117,6 @@ 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_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c index c7b836613149..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); diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c index d4ee5bb7c486..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); 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_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..1fef350d821e 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 */ @@ -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 14763c0f31ad..c018beeecd3d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1732,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 - * @kctl: the control element to assign - * @index: index to kctl - * @nid: corresponding NID (optional) - * - * 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 */ @@ -2470,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; } @@ -3037,8 +3008,7 @@ const struct dev_pm_ops hda_codec_driver_pm = { .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_suspend = pm_ptr(hda_codec_runtime_suspend), - .runtime_resume = pm_ptr(hda_codec_runtime_resume), + RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, NULL) }; /* suspend the codec at shutdown; called from driver's shutdown callback */ 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 18fa6e7edb49..000000000000 --- a/sound/pci/hda/hda_cs_dsp_ctl.c +++ /dev/null @@ -1,249 +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/cleanup.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; - - return cs_dsp_coeff_lock_and_write_ctrl(cs_ctl, 0, p, cs_ctl->len); -} - -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; - - return cs_dsp_coeff_lock_and_read_ctrl(cs_ctl, 0, p, cs_ctl->len); -} - -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_free_kcontrol(struct snd_kcontrol *kctl) -{ - 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; - - /* NULL priv to prevent a double-free in hda_cs_dsp_control_remove() */ - cs_ctl->priv = NULL; - kfree(ctl); -} - -static void hda_cs_dsp_add_kcontrol(struct cs_dsp_coeff_ctl *cs_ctl, - const struct hda_cs_dsp_ctl_info *info, - const char *name) -{ - struct snd_kcontrol_new kcontrol = {0}; - struct snd_kcontrol *kctl; - struct hda_cs_dsp_coeff_ctl *ctl __free(kfree) = NULL; - 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; - } - - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); - if (!ctl) - return; - - ctl->cs_ctl = cs_ctl; - ctl->card = info->card; - - 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; - - kctl = snd_ctl_new1(&kcontrol, (void *)ctl); - if (!kctl) - return; - - kctl->private_free = hda_cs_dsp_free_kcontrol; - ctl->kctl = kctl; - - /* snd_ctl_add() calls our private_free on error, which will kfree(ctl) */ - cs_ctl->priv = no_free_ptr(ctl); - ret = snd_ctl_add(info->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); -} - -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]; - 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); - } - - hda_cs_dsp_add_kcontrol(cs_ctl, info, 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; - - /* ctl and kctl may already have been removed by ALSA private_free */ - if (ctl) - snd_ctl_remove(ctl->card, ctl->kctl); -} -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; - 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; - - 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 301730432375..d3e87b9c1a4f 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -17,11 +17,6 @@ #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_intel.c b/sound/pci/hda/hda_intel.c index 7d7f9aac50a9..e6df706f740d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -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 */ @@ -239,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 */ @@ -354,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", }; @@ -1050,7 +1053,7 @@ static int azx_suspend(struct device *dev) return 0; } -static int __maybe_unused azx_resume(struct device *dev) +static int azx_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1097,7 +1100,7 @@ static int azx_thaw_noirq(struct device *dev) return 0; } -static int __maybe_unused azx_runtime_suspend(struct device *dev) +static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1114,7 +1117,7 @@ static int __maybe_unused azx_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused azx_runtime_resume(struct device *dev) +static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1131,7 +1134,7 @@ static int __maybe_unused azx_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused azx_runtime_idle(struct device *dev) +static int azx_runtime_idle(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1162,7 +1165,7 @@ static const struct dev_pm_ops azx_pm = { .complete = pm_sleep_ptr(azx_complete), .freeze_noirq = pm_sleep_ptr(azx_freeze_noirq), .thaw_noirq = pm_sleep_ptr(azx_thaw_noirq), - SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) + RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) }; @@ -1352,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) { @@ -1736,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; } @@ -1863,12 +1881,14 @@ static int azx_first_init(struct azx *chip) 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); @@ -1960,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; @@ -2061,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, @@ -2071,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; @@ -2083,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; @@ -2232,6 +2281,8 @@ 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), {} }; @@ -2496,6 +2547,10 @@ static const struct pci_device_id azx_ids[] = { { 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 */ @@ -2736,6 +2791,21 @@ 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 | AZX_DCAPS_NO_TCSEL }, @@ -2753,7 +2823,7 @@ static struct pci_driver azx_driver = { .remove = azx_remove, .shutdown = azx_shutdown, .driver = { - .pm = &azx_pm, + .pm = pm_ptr(&azx_pm), }, }; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 763f79f6f32e..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. @@ -569,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); /* @@ -675,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_tegra.c b/sound/pci/hda/hda_tegra.c index b1e30a83dfb0..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,7 +639,7 @@ 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, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4985e72b9094..34874039ad45 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1090,6 +1090,7 @@ static const struct hda_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), diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c index 759f48038273..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 }, diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c index 614327218634..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 @@ -920,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 }, diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h index 5e48115caf09..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 { diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 643e0496b093..08308231b4ed 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -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); @@ -4551,6 +4551,7 @@ 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(0x10de0034, "Tegra264 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), @@ -4610,6 +4611,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), @@ -4640,6 +4652,7 @@ 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 8192be394d0d..cd0d7ba7320e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -28,6 +28,7 @@ #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" @@ -440,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); @@ -447,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: @@ -586,6 +587,9 @@ 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: @@ -601,8 +605,7 @@ static void alc_shutup_pins(struct hda_codec *codec) alc_headset_mic_no_shutup(codec); break; default: - if (!spec->no_shutup_pins) - snd_hda_shutup_pins(codec); + snd_hda_shutup_pins(codec); break; } } @@ -3788,6 +3791,7 @@ static void alc225_init(struct hda_codec *codec) AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); msleep(75); + alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ } } @@ -3842,6 +3846,79 @@ static void alc225_shutup(struct hda_codec *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) { struct alc_spec *spec = codec->spec; @@ -4666,6 +4743,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) @@ -4716,6 +4809,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) { @@ -4926,7 +5034,6 @@ static void alc298_fixup_samsung_amp_v2_4_amps(struct hda_codec *codec, alc298_samsung_v2_init_amps(codec, 4); } -#if IS_REACHABLE(CONFIG_INPUT) static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) { @@ -5035,10 +5142,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) @@ -5052,6 +5155,16 @@ 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) @@ -6629,6 +6742,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) @@ -6698,7 +6830,10 @@ static void alc256_fixup_chromebook(struct hda_codec *codec, switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: - spec->gen.suppress_auto_mute = 1; + 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; @@ -6850,6 +6985,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) { @@ -6922,6 +7092,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" @@ -7453,6 +7647,24 @@ static void alc245_fixup_hp_spectre_x360_16_aa0xxx(struct hda_codec *codec, 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 */ @@ -7577,6 +7789,7 @@ 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, @@ -7605,6 +7818,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, @@ -7620,6 +7834,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, @@ -7689,7 +7904,6 @@ enum { ALC285_FIXUP_THINKPAD_X1_GEN7, ALC285_FIXUP_THINKPAD_HEADSET_JACK, ALC294_FIXUP_ASUS_ALLY, - ALC294_FIXUP_ASUS_ALLY_X, ALC294_FIXUP_ASUS_ALLY_PINS, ALC294_FIXUP_ASUS_ALLY_VERBS, ALC294_FIXUP_ASUS_ALLY_SPEAKER, @@ -7706,6 +7920,7 @@ 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, @@ -7788,6 +8003,7 @@ enum { 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, @@ -7798,6 +8014,7 @@ enum { 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, @@ -7810,6 +8027,9 @@ enum { 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, }; /* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -8615,6 +8835,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, @@ -9078,6 +9302,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[]) { @@ -9137,12 +9367,6 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS }, - [ALC294_FIXUP_ASUS_ALLY_X] = { - .type = HDA_FIXUP_FUNC, - .v.func = tas2781_fixup_i2c, - .chained = true, - .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS - }, [ALC294_FIXUP_ASUS_ALLY_PINS] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -9302,6 +9526,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, @@ -9324,6 +9554,10 @@ static const struct hda_fixup alc269_fixups[] = { .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, @@ -9669,6 +9903,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, @@ -10033,6 +10271,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, @@ -10081,6 +10323,10 @@ static const struct hda_fixup alc269_fixups[] = { .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, @@ -10158,6 +10404,16 @@ static const struct hda_fixup alc269_fixups[] = { .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, + }, }; static const struct hda_quirk alc269_fixup_tbl[] = { @@ -10207,6 +10463,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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), @@ -10374,6 +10633,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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), @@ -10381,6 +10641,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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), @@ -10391,7 +10652,7 @@ static const struct hda_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), @@ -10421,6 +10682,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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), @@ -10525,6 +10787,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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, 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), @@ -10583,23 +10846,70 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), 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", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), + 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, 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, 0x8e18, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), + 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, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED), + 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, 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), @@ -10607,27 +10917,32 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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, 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), @@ -10643,7 +10958,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS), SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY), - SND_PCI_QUIRK(0x1043, 0x1eb3, "ROG Ally X RC72LA", ALC294_FIXUP_ASUS_ALLY_X), SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), @@ -10655,7 +10969,6 @@ static const struct hda_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, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2), @@ -10669,10 +10982,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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), @@ -10681,6 +10995,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), @@ -10698,14 +11013,28 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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, 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), @@ -10713,6 +11042,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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), @@ -10911,6 +11242,9 @@ static const struct hda_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), 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), @@ -10982,6 +11316,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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), @@ -11045,6 +11380,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { 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), @@ -11245,6 +11581,7 @@ 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"}, @@ -11898,8 +12235,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: diff --git a/sound/pci/hda/tas2781-spi.h b/sound/pci/hda/tas2781-spi.h deleted file mode 100644 index ecfc3c8bb821..000000000000 --- a/sound/pci/hda/tas2781-spi.h +++ /dev/null @@ -1,158 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -// -// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier -// -// Copyright (C) 2024 Texas Instruments Incorporated -// https://www.ti.com -// -// The TAS2781 driver implements a flexible and configurable -// algo coefficient setting for TAS2781 chips. -// -// Author: Baojun Xu <baojun.xu@ti.com> -// - -#ifndef __TAS2781_SPI_H__ -#define __TAS2781_SPI_H__ - -#define TASDEVICE_RATES \ - (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200) - -#define TASDEVICE_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - -#define TASDEVICE_MAX_BOOK_NUM 256 -#define TASDEVICE_MAX_PAGE 256 - -#define TASDEVICE_MAX_SIZE (TASDEVICE_MAX_BOOK_NUM * TASDEVICE_MAX_PAGE) - -/* PAGE Control Register (available in page0 of each book) */ -#define TASDEVICE_PAGE_SELECT 0x00 -#define TASDEVICE_BOOKCTL_PAGE 0x00 -#define TASDEVICE_BOOKCTL_REG GENMASK(7, 1) -#define TASDEVICE_BOOK_ID(reg) (((reg) & GENMASK(24, 16)) >> 16) -#define TASDEVICE_PAGE_ID(reg) (((reg) & GENMASK(15, 8)) >> 8) -#define TASDEVICE_REG_ID(reg) (((reg) & GENMASK(7, 1)) >> 1) -#define TASDEVICE_PAGE_REG(reg) ((reg) & GENMASK(15, 1)) -#define TASDEVICE_REG(book, page, reg) \ - (((book) << 16) | ((page) << 8) | ((reg) << 1)) - -/* Software Reset */ -#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01) -#define TAS2781_REG_SWRESET_RESET BIT(0) - -/* System Reset Check Register */ -#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c) -#define TAS2781_REG_CLK_CONFIG_RESET (0x19) -#define TAS2781_PRE_POST_RESET_CFG 3 - -/* Block Checksum */ -#define TASDEVICE_CHECKSUM TASDEVICE_REG(0x0, 0x0, 0x7e) - -/* Volume control */ -#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1a) -#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03) -#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1) - -#define TASDEVICE_CMD_SING_W 0x1 -#define TASDEVICE_CMD_BURST 0x2 -#define TASDEVICE_CMD_DELAY 0x3 -#define TASDEVICE_CMD_FIELD_W 0x4 - -#define TAS2781_SPI_MAX_FREQ (4 * HZ_PER_MHZ) - -#define TASDEVICE_CRC8_POLYNOMIAL 0x4d -#define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20 - -/* Flag of calibration registers address. */ -#define TASDEVICE_CALIBRATION_REG_ADDRESS BIT(7) - -#define TASDEVICE_CALIBRATION_DATA_NAME L"CALI_DATA" -#define TASDEVICE_CALIBRATION_DATA_SIZE 256 - -enum calib_data { - R0_VAL = 0, - INV_R0, - R0LOW, - POWER, - TLIM, - CALIB_MAX -}; - -struct tasdevice_priv { - struct tasdevice_fw *cali_data_fmw; - struct tasdevice_rca rcabin; - struct tasdevice_fw *fmw; - struct gpio_desc *reset; - struct mutex codec_lock; - struct regmap *regmap; - struct device *dev; - struct tm tm; - - unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE]; - unsigned char coef_binaryname[64]; - unsigned char rca_binaryname[64]; - unsigned char dev_name[32]; - - bool force_fwload_status; - bool playback_started; - bool is_loading; - bool is_loaderr; - unsigned int cali_reg_array[CALIB_MAX]; - unsigned int cali_data[CALIB_MAX]; - unsigned int err_code; - void *codec; - int cur_book; - int cur_prog; - int cur_conf; - int fw_state; - int index; - int irq; - - int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv, - const struct firmware *fmw, - int offset); - int (*fw_parse_program_data)(struct tasdevice_priv *tas_priv, - struct tasdevice_fw *tas_fmw, - const struct firmware *fmw, int offset); - int (*fw_parse_configuration_data)(struct tasdevice_priv *tas_priv, - struct tasdevice_fw *tas_fmw, - const struct firmware *fmw, - int offset); - int (*tasdevice_load_block)(struct tasdevice_priv *tas_priv, - struct tasdev_blk *block); - - int (*save_calibration)(struct tasdevice_priv *tas_priv); - void (*apply_calibration)(struct tasdevice_priv *tas_priv); -}; - -int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv, - unsigned int reg, unsigned int *value); -int tasdevice_spi_dev_write(struct tasdevice_priv *tas_priv, - unsigned int reg, unsigned int value); -int tasdevice_spi_dev_bulk_write(struct tasdevice_priv *tas_priv, - unsigned int reg, unsigned char *p_data, - unsigned int n_length); -int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv, - unsigned int reg, unsigned char *p_data, - unsigned int n_length); -int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tasdevice, - unsigned int reg, unsigned int mask, - unsigned int value); - -void tasdevice_spi_select_cfg_blk(void *context, int conf_no, - unsigned char block_type); -void tasdevice_spi_config_info_remove(void *context); -int tasdevice_spi_dsp_parser(void *context); -int tasdevice_spi_rca_parser(void *context, const struct firmware *fmw); -void tasdevice_spi_dsp_remove(void *context); -void tasdevice_spi_calbin_remove(void *context); -int tasdevice_spi_select_tuningprm_cfg(void *context, int prm, int cfg_no, - int rca_conf_no); -int tasdevice_spi_prmg_load(void *context, int prm_no); -int tasdevice_spi_prmg_calibdata_load(void *context, int prm_no); -void tasdevice_spi_tuning_switch(void *context, int state); -int tas2781_spi_load_calibration(void *context, char *file_name, - unsigned short i); -#endif /* __TAS2781_SPI_H__ */ diff --git a/sound/pci/hda/tas2781_hda.c b/sound/pci/hda/tas2781_hda.c new file mode 100644 index 000000000000..5f1d4b3e9688 --- /dev/null +++ b/sound/pci/hda/tas2781_hda.c @@ -0,0 +1,377 @@ +// 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; + 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; + } + + for (j = 0, k = 0; j < tmp_val[1]; 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; + for (i = 0; i < TASDEV_CALIB_N * 4; i++) + data[l + i] = 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 0e42b87dadb8..d91eed9f7804 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -2,7 +2,7 @@ // // TAS2781 HDA I2C driver // -// Copyright 2023 - 2024 Texas Instruments, Inc. +// Copyright 2023 - 2025 Texas Instruments, Inc. // // Author: Shenghao Ding <shenghao-ding@ti.com> // Current maintainer: Baojun Xu <baojun.xu@ti.com> @@ -22,6 +22,7 @@ #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> @@ -30,69 +31,23 @@ #include "hda_component.h" #include "hda_jack.h" #include "hda_generic.h" +#include "tas2781_hda.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, -}; +#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 { - 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 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) @@ -210,176 +165,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) } } -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); - - mutex_lock(&tas_priv->codec_lock); - - 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); - - mutex_unlock(&tas_priv->codec_lock); - - 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); - - mutex_lock(&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; - } - - mutex_unlock(&tas_priv->codec_lock); - - 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); - - mutex_lock(&tas_priv->codec_lock); - - 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); - - mutex_unlock(&tas_priv->codec_lock); - - 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); - - mutex_lock(&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; - } - - mutex_unlock(&tas_priv->codec_lock); - - return ret; -} - -static int tasdevice_config_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - - mutex_lock(&tas_priv->codec_lock); - - 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); - - mutex_unlock(&tas_priv->codec_lock); - - return 0; -} - -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; - - val = clamp(nr_config, 0, max); - - mutex_lock(&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; - } - - mutex_unlock(&tas_priv->codec_lock); - - return ret; -} - static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -493,162 +278,103 @@ 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, 0x13, 0x18, - }; - static const unsigned char rgno_array[CALIB_MAX] = { - 0x74, 0x0c, 0x14, 0x70, 0x7c, - }; - int offset = 0; - int i, j, rc; - __be32 data; - - for (i = 0; i < tas_priv->ndev; i++) { - for (j = 0; j < CALIB_MAX; j++) { - data = cpu_to_be32( - *(uint32_t *)&tas_priv->cali_data.data[offset]); - rc = tasdevice_dev_bulk_write(tas_priv, i, - TASDEVICE_REG(0, page_array[j], rgno_array[j]), - (unsigned char *)&data, 4); - if (rc < 0) - dev_err(tas_priv->dev, - "chn %d calib %d bulk_wr err = %d\n", - i, j, rc); - offset += 4; - } - } -} - -/* 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; 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(tas_hda->snd_ctls) - 1; i >= 0; i--) - snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]); + for (int i = ARRAY_SIZE(hda_priv->snd_ctls) - 1; i >= 0; i--) + snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]); snd_ctl_remove(codec->card, tas_hda->prof_ctl); } @@ -657,6 +383,7 @@ 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, spk_id; @@ -677,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", @@ -748,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); } @@ -782,11 +508,11 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, 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; } @@ -833,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); - - component_del(tas_hda->dev, &tas2781_hda_comp_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); -} - 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; @@ -867,13 +585,11 @@ 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; @@ -904,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) @@ -944,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; @@ -992,11 +703,6 @@ static int tas2781_system_resume(struct device *dev) 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); @@ -1038,3 +744,4 @@ 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_HDA_SCODEC_TAS2781"); diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/pci/hda/tas2781_hda_spi.c index a42fa990e7b9..5c03e9d2283a 100644 --- a/sound/pci/hda/tas2781_hda_spi.c +++ b/sound/pci/hda/tas2781_hda_spi.c @@ -2,7 +2,7 @@ // // TAS2781 HDA SPI driver // -// Copyright 2024 Texas Instruments, Inc. +// Copyright 2024 - 2025 Texas Instruments, Inc. // // Author: Baojun Xu <baojun.xu@ti.com> @@ -27,68 +27,41 @@ #include <sound/hda_codec.h> #include <sound/soc.h> -#include <sound/tas2781-dsp.h> +#include <sound/tas2781.h> #include <sound/tlv.h> #include <sound/tas2781-tlv.h> -#include "tas2781-spi.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" -/* - * 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, \ - } \ -} +#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) -/* 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, \ -} +/* System Reset Check Register */ +#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c) +#define TAS2781_REG_CLK_CONFIG_RESET 0x19 -struct tas2781_hda { - struct tasdevice_priv *priv; - struct acpi_device *dacpi; - struct snd_kcontrol *dsp_prog_ctl; - struct snd_kcontrol *dsp_conf_ctl; +struct tas2781_hda_spi_priv { struct snd_kcontrol *snd_ctls[3]; - struct snd_kcontrol *prof_ctl; }; static const struct regmap_range_cfg tasdevice_ranges[] = { { .range_min = 0, - .range_max = TASDEVICE_MAX_SIZE, + .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_MAX_PAGE, + .window_len = TASDEVICE_WIN_LEN, }, }; @@ -96,39 +69,19 @@ 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_MAX_SIZE, + .max_register = TASDEVICE_RANGE_MAX_SIZE, }; -static int tasdevice_spi_switch_book(struct tasdevice_priv *tas_priv, int reg) -{ - struct regmap *map = tas_priv->regmap; - - if (tas_priv->cur_book != TASDEVICE_BOOK_ID(reg)) { - int ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, - TASDEVICE_BOOK_ID(reg)); - if (ret < 0) { - dev_err(tas_priv->dev, "Switch Book E=%d\n", ret); - return ret; - } - tas_priv->cur_book = TASDEVICE_BOOK_ID(reg); - } - return 0; -} - -int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv, - unsigned int reg, - unsigned int *val) +static int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv, + unsigned short chn, unsigned int reg, unsigned int *val) { - struct regmap *map = tas_priv->regmap; int ret; - ret = tasdevice_spi_switch_book(tas_priv, reg); - if (ret < 0) - return 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 @@ -137,11 +90,11 @@ int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv, if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) { unsigned char data[2]; - ret = regmap_bulk_read(map, TASDEVICE_PAGE_REG(reg) | 1, + ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, data, sizeof(data)); *val = data[1]; } else { - ret = regmap_read(map, TASDEVICE_PAGE_REG(reg) | 1, val); + ret = tasdevice_dev_read(tas_priv, chn, reg, val); } if (ret < 0) dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); @@ -149,71 +102,25 @@ int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv, return ret; } -int tasdevice_spi_dev_write(struct tasdevice_priv *tas_priv, - unsigned int reg, - unsigned int value) -{ - struct regmap *map = tas_priv->regmap; - int ret; - - ret = tasdevice_spi_switch_book(tas_priv, reg); - if (ret < 0) - return ret; - - ret = regmap_write(map, TASDEVICE_PAGE_REG(reg), value); - if (ret < 0) - dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); - - return ret; -} - -int tasdevice_spi_dev_bulk_write(struct tasdevice_priv *tas_priv, - unsigned int reg, - unsigned char *data, - unsigned int len) +static int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv, + unsigned short chn, unsigned int reg, unsigned char *data, + unsigned int len) { - struct regmap *map = tas_priv->regmap; int ret; - ret = tasdevice_spi_switch_book(tas_priv, reg); - if (ret < 0) - return ret; - - ret = regmap_bulk_write(map, TASDEVICE_PAGE_REG(reg), data, len); - if (ret < 0) - dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); - - return ret; -} - -int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv, - unsigned int reg, - unsigned char *data, - unsigned int len) -{ - struct regmap *map = tas_priv->regmap; - int ret; - - ret = tasdevice_spi_switch_book(tas_priv, reg); - if (ret < 0) - return ret; - - if (len > TASDEVICE_MAX_PAGE) - len = TASDEVICE_MAX_PAGE; /* * 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_MAX_PAGE+1]; + unsigned char buf[TASDEVICE_WIN_LEN + 1]; - ret = regmap_bulk_read(map, TASDEVICE_PAGE_REG(reg) | 1, buf, - len + 1); + ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, + buf, len + 1); memcpy(data, buf + 1, len); } else { - ret = regmap_bulk_read(map, TASDEVICE_PAGE_REG(reg) | 1, data, - len); + 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); @@ -221,31 +128,55 @@ int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv, return ret; } -int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv, - unsigned int reg, - unsigned int mask, - unsigned int value) +static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv, + unsigned short chn, unsigned int reg, unsigned int mask, + unsigned int value) { - struct regmap *map = tas_priv->regmap; 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_spi_dev_read(tas_priv, reg, &val); + 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 = regmap_write(map, TASDEVICE_PAGE_REG(reg), - (val & ~mask) | (mask & value)); + + 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; @@ -254,12 +185,15 @@ static void tas2781_spi_reset(struct tasdevice_priv *tas_dev) 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); } - ret = tasdevice_spi_dev_write(tas_dev, TAS2781_REG_SWRESET, - TAS2781_REG_SWRESET_RESET); - if (ret < 0) - dev_err(tas_dev->dev, "dev sw-reset fail, %d\n", ret); - fsleep(1000); } static int tascodec_spi_init(struct tasdevice_priv *tas_priv, @@ -276,7 +210,7 @@ static int tascodec_spi_init(struct tasdevice_priv *tas_priv, scnprintf(tas_priv->rca_binaryname, sizeof(tas_priv->rca_binaryname), "%sRCA%d.bin", - tas_priv->dev_name, tas_priv->index); + 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, @@ -291,26 +225,22 @@ static int tascodec_spi_init(struct tasdevice_priv *tas_priv, static void tasdevice_spi_init(struct tasdevice_priv *tas_priv) { - tas_priv->cur_prog = -1; - tas_priv->cur_conf = -1; + 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->cur_book = -1; - tas_priv->cur_prog = -1; - tas_priv->cur_conf = -1; + tas_priv->isspi = true; - /* Store default registers address for calibration data. */ - tas_priv->cali_reg_array[0] = TASDEVICE_REG(0, 0x17, 0x74); - tas_priv->cali_reg_array[1] = TASDEVICE_REG(0, 0x18, 0x0c); - tas_priv->cali_reg_array[2] = TASDEVICE_REG(0, 0x18, 0x14); - tas_priv->cali_reg_array[3] = TASDEVICE_REG(0, 0x13, 0x70); - tas_priv->cali_reg_array[4] = TASDEVICE_REG(0, 0x18, 0x7c); + 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) + struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) { unsigned int invert = mc->invert; unsigned char mask; @@ -321,7 +251,8 @@ static int tasdevice_spi_amp_putvol(struct tasdevice_priv *tas_priv, 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, + + 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", @@ -331,16 +262,14 @@ static int tasdevice_spi_amp_putvol(struct tasdevice_priv *tas_priv, } static int tasdevice_spi_amp_getvol(struct tasdevice_priv *tas_priv, - struct snd_ctl_elem_value *ucontrol, - struct soc_mixer_control *mc) + 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; - /* Read the primary device */ - ret = tasdevice_spi_dev_read(tas_priv, mc->reg, &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; @@ -355,9 +284,8 @@ static int tasdevice_spi_amp_getvol(struct tasdevice_priv *tas_priv, return ret; } -static int tasdevice_spi_digital_putvol(struct tasdevice_priv *tas_priv, - struct snd_ctl_elem_value *ucontrol, - struct soc_mixer_control *mc) +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; @@ -365,26 +293,23 @@ static int tasdevice_spi_digital_putvol(struct tasdevice_priv *tas_priv, val = clamp(invert ? max - ucontrol->value.integer.value[0] : ucontrol->value.integer.value[0], 0, max); - ret = tasdevice_spi_dev_write(tas_priv, mc->reg, (unsigned int)val); + ret = tasdevice_dev_write(p, p->index, mc->reg, (unsigned int)val); if (ret) - dev_err(tas_priv->dev, "set digital vol err in dev %d\n", - tas_priv->index); + 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 *tas_priv, - struct snd_ctl_elem_value *ucontrol, - struct soc_mixer_control *mc) +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; - /* Read the primary device as the whole */ - ret = tasdevice_spi_dev_read(tas_priv, mc->reg, &val); + ret = tasdevice_spi_dev_read(p, p->index, mc->reg, &val); if (ret) { - dev_err(tas_priv->dev, "%s, get digital vol err\n", __func__); + dev_err(p->dev, "%s, get digital vol err\n", __func__); return ret; } @@ -395,8 +320,7 @@ static int tasdevice_spi_digital_getvol(struct tasdevice_priv *tas_priv, } static int tas2781_read_acpi(struct tas2781_hda *tas_hda, - const char *hid, - int id) + const char *hid, int id) { struct tasdevice_priv *p = tas_hda->priv; struct acpi_device *adev; @@ -413,7 +337,6 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda, } strscpy(p->dev_name, hid, sizeof(p->dev_name)); - tas_hda->dacpi = adev; physdev = get_device(acpi_get_first_physical_node(adev)); acpi_dev_put(adev); @@ -423,7 +346,7 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda, ret = -EINVAL; goto err; } - nval = ret; + p->ndev = nval = ret; ret = device_property_read_u32_array(physdev, property, values, nval); if (ret) @@ -466,139 +389,22 @@ err: 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_hda->priv->codec_lock); - tasdevice_spi_tuning_switch(tas_hda->priv, 0); + 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_hda->priv->codec_lock); - tasdevice_spi_tuning_switch(tas_hda->priv, 1); + 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); } } -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 max = tas_priv->rcabin.ncfgs - 1; - int val; - - val = clamp(ucontrol->value.integer.value[0], 0, max); - if (tas_priv->rcabin.profile_cfg_id != val) { - tas_priv->rcabin.profile_cfg_id = val; - return 1; - } - - return 0; -} - -static 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; -} - -static int tasdevice_info_config(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_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); - int nr_program = ucontrol->value.integer.value[0]; - int max = tas_priv->fmw->nr_programs - 1; - int val; - - val = clamp(nr_program, 0, max); - - if (tas_priv->cur_prog != val) { - tas_priv->cur_prog = val; - return 1; - } - - return 0; -} - -static 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; - - return 0; -} - -static int tasdevice_config_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); - int max = tas_priv->fmw->nr_configurations - 1; - int val; - - val = clamp(ucontrol->value.integer.value[0], 0, max); - - if (tas_priv->cur_conf != val) { - tas_priv->cur_conf = val; - return 1; - } - - return 0; -} - /* * tas2781_digital_getvol - get the volum control * @kcontrol: control pointer @@ -620,6 +426,7 @@ static int tas2781_digital_getvol(struct snd_kcontrol *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); } @@ -630,6 +437,7 @@ static int tas2781_amp_getvol(struct snd_kcontrol *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); } @@ -640,7 +448,7 @@ static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - /* The check of the given value is in tasdevice_digital_putvol. */ + guard(mutex)(&tas_priv->codec_lock); return tasdevice_spi_digital_putvol(tas_priv, ucontrol, mc); } @@ -651,7 +459,7 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - /* The check of the given value is in tasdevice_amp_putvol. */ + guard(mutex)(&tas_priv->codec_lock); return tasdevice_spi_amp_putvol(tas_priv, ucontrol, mc); } @@ -685,226 +493,139 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, return change; } -static const struct snd_kcontrol_new tas2781_snd_controls[] = { - ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain 0", TAS2781_AMP_LEVEL, - 1, 0, 20, 0, tas2781_amp_getvol, - tas2781_amp_putvol, amp_vol_tlv), - ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain 0", TAS2781_DVC_LVL, - 0, 0, 200, 1, tas2781_digital_getvol, - tas2781_digital_putvol, dvc_tlv), - ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load 0", 0, - tas2781_force_fwload_get, tas2781_force_fwload_put), - ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain 1", TAS2781_AMP_LEVEL, - 1, 0, 20, 0, tas2781_amp_getvol, - tas2781_amp_putvol, amp_vol_tlv), - ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain 1", TAS2781_DVC_LVL, - 0, 0, 200, 1, tas2781_digital_getvol, - tas2781_digital_putvol, dvc_tlv), - ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load 1", 0, - tas2781_force_fwload_get, tas2781_force_fwload_put), +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 const struct snd_kcontrol_new tas2781_prof_ctrl[] = { -{ - .name = "Speaker Profile Id - 0", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = tasdevice_info_profile, - .get = tasdevice_get_profile_id, - .put = tasdevice_set_profile_id, -}, -{ - .name = "Speaker Profile Id - 1", +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 const struct snd_kcontrol_new tas2781_dsp_prog_ctrl[] = { -{ - .name = "Speaker Program Id 0", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = tasdevice_info_programs, - .get = tasdevice_program_get, - .put = tasdevice_program_put, -}, -{ - .name = "Speaker Program Id 1", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = tasdevice_info_programs, - .get = tasdevice_program_get, - .put = tasdevice_program_put, -}, }; -static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl[] = { -{ - .name = "Speaker Config Id 0", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = tasdevice_info_config, - .get = tasdevice_config_get, - .put = tasdevice_config_put, -}, -{ - .name = "Speaker Config Id 1", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = tasdevice_info_config, - .get = tasdevice_config_get, - .put = tasdevice_config_put, -}, +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_apply_calib(struct tasdevice_priv *tas_priv) +static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) { - int i, rc; + struct hda_codec *codec = tas_hda->priv->codec; + struct tas2781_hda_spi_priv *h_priv = tas_hda->hda_priv; - /* - * If no calibration data exist in tasdevice_priv *tas_priv, - * calibration apply will be ignored, and use default values - * in firmware binary, which was loaded during firmware download. - */ - if (tas_priv->cali_data[0] == 0) - return; - /* - * Calibration data was saved in tasdevice_priv *tas_priv as: - * unsigned int cali_data[CALIB_MAX]; - * and every data (in 4 bytes) will be saved in register which in - * book 0, and page number in page_array[], offset was saved in - * rgno_array[]. - */ - for (i = 0; i < CALIB_MAX; i++) { - rc = tasdevice_spi_dev_bulk_write(tas_priv, - tas_priv->cali_reg_array[i], - (unsigned char *)&tas_priv->cali_data[i], 4); - if (rc < 0) - dev_err(tas_priv->dev, - "chn %d calib %d bulk_wr err = %d\n", - tas_priv->index, i, rc); - } + 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); } -/* - * 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. - * Calibration data format in EFI is V2, since 2024. - */ -static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) -{ - /* - * GUID was used for data access in BIOS, it was provided by board - * manufactory, like HP: "{02f9af02-7734-4233-b43d-93fe5aa35db3}" - */ - efi_guid_t efi_guid = - EFI_GUID(0x02f9af02, 0x7734, 0x4233, - 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3); - static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME; - unsigned char data[TASDEVICE_CALIBRATION_DATA_SIZE], *buf; - unsigned int attr, crc, offset, *tmp_val; - struct tm *tm = &tas_priv->tm; - unsigned long total_sz = 0; - efi_status_t status; - - tas_priv->cali_data[0] = 0; - status = efi.get_variable(efi_name, &efi_guid, &attr, &total_sz, data); - if (status == EFI_BUFFER_TOO_SMALL) { - if (total_sz > TASDEVICE_CALIBRATION_DATA_SIZE) - return -ENOMEM; - /* Get variable contents into buffer */ - status = efi.get_variable(efi_name, &efi_guid, &attr, - &total_sz, data); +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; } - if (status != EFI_SUCCESS) - return status; - - tmp_val = (unsigned int *)data; - 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) - * Device-Sum (4 bytes) - * TimeStamp of Calibration (4 bytes) - * for (i = 0; i < Device-Sum; i++) { - * Device #i index_info () { - * SDW link id (2bytes) - * SDW unique_id (2bytes) - * } // if Device number is 0x80, mean it's - * calibration registers address. - * Calibrated Data of Device #i (20 bytes) - * } - * 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]) - return 0; - - time64_to_tm(tmp_val[2], 0, tm); - for (int j = 0; j < tmp_val[1]; j++) { - offset = j * 6 + 3; - if (tmp_val[offset] == tas_priv->index) { - for (int i = 0; i < CALIB_MAX; i++) - tas_priv->cali_data[i] = - tmp_val[offset + i + 1]; - } else if (tmp_val[offset] == - TASDEVICE_CALIBRATION_REG_ADDRESS) { - for (int i = 0; i < CALIB_MAX; i++) { - buf = &data[(offset + i + 1) * 4]; - tas_priv->cali_reg_array[i] = - TASDEVICE_REG(buf[1], buf[2], - buf[3]); - } - } - tas_priv->apply_calibration(tas_priv); - } - } 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]) { - time64_to_tm(tmp_val[20], 0, tm); - for (int i = 0; i < CALIB_MAX; i++) - tas_priv->cali_data[i] = - tmp_val[tas_priv->index * 5 + i]; - tas_priv->apply_calibration(tas_priv); - } + 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; } - - return 0; + 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 void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) +static int tas2781_hda_spi_dsp_ctls(struct tas2781_hda *h) { - struct hda_codec *codec = tas_hda->priv->codec; - - snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); + struct tasdevice_priv *p = h->priv; + struct hda_codec *c = p->codec; + char name[64]; + int i = 0; + int rc; - snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); - - for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--) - snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]); + 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); + } - snd_ctl_remove(codec->card, tas_hda->prof_ctl); + return rc; } static void tasdev_fw_ready(const struct firmware *fmw, void *context) @@ -912,44 +633,30 @@ 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 i, j, ret; + int ret, val; pm_runtime_get_sync(tas_priv->dev); guard(mutex)(&tas_priv->codec_lock); - ret = tasdevice_spi_rca_parser(tas_priv, fmw); + ret = tasdevice_rca_parser(tas_priv, fmw); if (ret) goto out; /* Add control one time only. */ - tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl[tas_priv->index], - tas_priv); - ret = snd_ctl_add(codec->card, tas_hda->prof_ctl); - if (ret) { - dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n", - tas2781_prof_ctrl[tas_priv->index].name, ret); + ret = tas2781_hda_spi_prf_ctl(tas_hda); + if (ret) + goto out; + + ret = tas2781_hda_spi_snd_ctls(tas_hda); + if (ret) goto out; - } - j = tas_priv->index * ARRAY_SIZE(tas2781_snd_controls) / 2; - for (i = 0; i < 3; i++) { - tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i+j], - tas_priv); - ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]); - if (ret) { - dev_err(tas_priv->dev, - "Failed to add KControl %s = %d\n", - tas2781_snd_controls[i+tas_priv->index*3].name, - ret); - goto out; - } - } - tasdevice_spi_dsp_remove(tas_priv); + tasdevice_dsp_remove(tas_priv); tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; - scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%08X-%01d.bin", - codec->core.subsystem_id, tas_priv->index); - ret = tasdevice_spi_dsp_parser(tas_priv); + 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); @@ -957,55 +664,40 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) goto out; } - /* Add control one time only. */ - tas_hda->dsp_prog_ctl = - snd_ctl_new1(&tas2781_dsp_prog_ctrl[tas_priv->index], - tas_priv); - ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl); - if (ret) { - dev_err(tas_priv->dev, - "Failed to add KControl %s = %d\n", - tas2781_dsp_prog_ctrl[tas_priv->index].name, ret); - goto out; - } - - tas_hda->dsp_conf_ctl = - snd_ctl_new1(&tas2781_dsp_conf_ctrl[tas_priv->index], - tas_priv); - ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl); - if (ret) { - dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n", - tas2781_dsp_conf_ctrl[tas_priv->index].name, ret); + ret = tas2781_hda_spi_dsp_ctls(tas_hda); + if (ret) goto out; - } - /* Perform AMP reset before firmware download. */ - tas_priv->rcabin.profile_cfg_id = TAS2781_PRE_POST_RESET_CFG; - tasdevice_spi_tuning_switch(tas_priv, 0); tas2781_spi_reset(tas_priv); tas_priv->rcabin.profile_cfg_id = 0; - tasdevice_spi_tuning_switch(tas_priv, 1); tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; - ret = tasdevice_spi_prmg_load(tas_priv, 0); - if (ret < 0) { - dev_err(tas_priv->dev, "FW download failed = %d\n", ret); + 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->cur_prog = 0; + tas_priv->tasdevice[tas_priv->index].cur_prog = 0; if (tas_priv->fmw->nr_configurations > 0) - tas_priv->cur_conf = 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. */ - tas_priv->save_calibration(tas_priv); - + tas2781_save_calibration(tas_hda); out: - if (fmw) - release_firmware(fmw); + release_firmware(fmw); pm_runtime_mark_last_busy(tas_hda->priv->dev); pm_runtime_put_autosuspend(tas_hda->priv->dev); } @@ -1050,9 +742,10 @@ static void tas2781_hda_unbind(struct device *dev, struct device *master, { 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_hda->priv->index); + comp = hda_component_from_index(parent, tas_priv->index); if (comp && (comp->dev == dev)) { comp->dev = NULL; memset(comp->name, 0, sizeof(comp->name)); @@ -1061,8 +754,8 @@ static void tas2781_hda_unbind(struct device *dev, struct device *master, tas2781_hda_remove_controls(tas_hda); - tasdevice_spi_config_info_remove(tas_hda->priv); - tasdevice_spi_dsp_remove(tas_hda->priv); + tasdevice_config_info_remove(tas_priv); + tasdevice_dsp_remove(tas_priv); tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING; } @@ -1072,22 +765,9 @@ 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); - - component_del(tas_hda->priv->dev, &tas2781_hda_comp_ops); - - pm_runtime_get_sync(tas_hda->priv->dev); - pm_runtime_disable(tas_hda->priv->dev); - - pm_runtime_put_noidle(tas_hda->priv->dev); - - mutex_destroy(&tas_hda->priv->codec_lock); -} - 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; @@ -1097,6 +777,11 @@ static int tas2781_hda_spi_probe(struct spi_device *spi) 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); @@ -1113,8 +798,6 @@ static int tas2781_hda_spi_probe(struct spi_device *spi) } if (strstr(dev_name(&spi->dev), "TXNW2781")) { device_name = "TXNW2781"; - tas_priv->save_calibration = tas2781_save_calibration; - tas_priv->apply_calibration = tas2781_apply_calib; } else { dev_err(tas_priv->dev, "Unmatched spi dev %s\n", dev_name(&spi->dev)); @@ -1127,16 +810,10 @@ static int tas2781_hda_spi_probe(struct spi_device *spi) spi_get_chipselect(spi, 0)); if (ret) return dev_err_probe(tas_priv->dev, ret, - "Platform not supported\n"); + "Platform not supported\n"); tasdevice_spi_init(tas_priv); - ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops); - if (ret) { - dev_err(tas_priv->dev, "Register component fail: %d\n", ret); - return ret; - } - pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000); pm_runtime_use_autosuspend(tas_priv->dev); pm_runtime_mark_last_busy(tas_priv->dev); @@ -1146,24 +823,34 @@ static int tas2781_hda_spi_probe(struct spi_device *spi) pm_runtime_put_autosuspend(tas_priv->dev); - return 0; + 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_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_hda->priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); - tasdevice_spi_tuning_switch(tas_hda->priv, 1); + if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK + && tas_priv->playback_started) + tasdevice_tuning_switch(tas_priv, 1); - tas_hda->priv->cur_book = -1; - tas_hda->priv->cur_conf = -1; + tas_priv->tasdevice[tas_priv->index].cur_book = -1; + tas_priv->tasdevice[tas_priv->index].cur_conf = -1; return 0; } @@ -1171,10 +858,13 @@ static int tas2781_runtime_suspend(struct device *dev) 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_hda->priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); - tasdevice_spi_tuning_switch(tas_hda->priv, 0); + if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK + && tas_priv->playback_started) + tasdevice_tuning_switch(tas_priv, 0); return 0; } @@ -1182,6 +872,7 @@ static int tas2781_runtime_resume(struct device *dev) 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); @@ -1189,44 +880,44 @@ static int tas2781_system_suspend(struct device *dev) return ret; /* Shutdown chip before system suspend */ - tasdevice_spi_tuning_switch(tas_hda->priv, 1); - tas2781_spi_reset(tas_hda->priv); - /* - * Reset GPIO may be shared, so cannot reset here. - * However beyond this point, amps may be powered down. - */ + 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_hda->priv->codec_lock); - ret = tasdevice_spi_dev_read(tas_hda->priv, TAS2781_REG_CLK_CONFIG, - &val); + 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_hda->priv->cur_book = -1; - tas_hda->priv->cur_conf = -1; - tas_hda->priv->cur_prog = -1; + 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_spi_prmg_load(tas_hda->priv, 0); + ret = tasdevice_prmg_load(tas_priv, 0); if (ret < 0) { - dev_err(tas_hda->priv->dev, + dev_err(tas_priv->dev, "FW download failed = %d\n", ret); return ret; } + tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; - if (tas_hda->priv->playback_started) - tasdevice_spi_tuning_switch(tas_hda->priv, 0); + if (tas_priv->playback_started) + tasdevice_tuning_switch(tas_priv, 0); } return ret; @@ -1263,3 +954,5 @@ 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/hda/tas2781_spi_fwlib.c b/sound/pci/hda/tas2781_spi_fwlib.c deleted file mode 100644 index 0e2acbc3c900..000000000000 --- a/sound/pci/hda/tas2781_spi_fwlib.c +++ /dev/null @@ -1,2006 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// TAS2781 HDA SPI driver -// -// Copyright 2024 Texas Instruments, Inc. -// -// Author: Baojun Xu <baojun.xu@ti.com> - -#include <linux/crc8.h> -#include <linux/firmware.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/unaligned.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/tas2781-dsp.h> -#include <sound/tlv.h> - -#include "tas2781-spi.h" - -#define OFFSET_ERROR_BIT BIT(31) - -#define ERROR_PRAM_CRCCHK 0x0000000 -#define ERROR_YRAM_CRCCHK 0x0000001 -#define PPC_DRIVER_CRCCHK 0x00000200 - -#define TAS2781_SA_COEFF_SWAP_REG TASDEVICE_REG(0, 0x35, 0x2c) -#define TAS2781_YRAM_BOOK1 140 -#define TAS2781_YRAM1_PAGE 42 -#define TAS2781_YRAM1_START_REG 88 - -#define TAS2781_YRAM2_START_PAGE 43 -#define TAS2781_YRAM2_END_PAGE 49 -#define TAS2781_YRAM2_START_REG 8 -#define TAS2781_YRAM2_END_REG 127 - -#define TAS2781_YRAM3_PAGE 50 -#define TAS2781_YRAM3_START_REG 8 -#define TAS2781_YRAM3_END_REG 27 - -/* should not include B0_P53_R44-R47 */ -#define TAS2781_YRAM_BOOK2 0 -#define TAS2781_YRAM4_START_PAGE 50 -#define TAS2781_YRAM4_END_PAGE 60 - -#define TAS2781_YRAM5_PAGE 61 -#define TAS2781_YRAM5_START_REG TAS2781_YRAM3_START_REG -#define TAS2781_YRAM5_END_REG TAS2781_YRAM3_END_REG - -#define TASDEVICE_MAXPROGRAM_NUM_KERNEL 5 -#define TASDEVICE_MAXCONFIG_NUM_KERNEL_MULTIPLE_AMPS 64 -#define TASDEVICE_MAXCONFIG_NUM_KERNEL 10 -#define MAIN_ALL_DEVICES_1X 0x01 -#define MAIN_DEVICE_A_1X 0x02 -#define MAIN_DEVICE_B_1X 0x03 -#define MAIN_DEVICE_C_1X 0x04 -#define MAIN_DEVICE_D_1X 0x05 -#define COEFF_DEVICE_A_1X 0x12 -#define COEFF_DEVICE_B_1X 0x13 -#define COEFF_DEVICE_C_1X 0x14 -#define COEFF_DEVICE_D_1X 0x15 -#define PRE_DEVICE_A_1X 0x22 -#define PRE_DEVICE_B_1X 0x23 -#define PRE_DEVICE_C_1X 0x24 -#define PRE_DEVICE_D_1X 0x25 -#define PRE_SOFTWARE_RESET_DEVICE_A 0x41 -#define PRE_SOFTWARE_RESET_DEVICE_B 0x42 -#define PRE_SOFTWARE_RESET_DEVICE_C 0x43 -#define PRE_SOFTWARE_RESET_DEVICE_D 0x44 -#define POST_SOFTWARE_RESET_DEVICE_A 0x45 -#define POST_SOFTWARE_RESET_DEVICE_B 0x46 -#define POST_SOFTWARE_RESET_DEVICE_C 0x47 -#define POST_SOFTWARE_RESET_DEVICE_D 0x48 - -struct tas_crc { - unsigned char offset; - unsigned char len; -}; - -struct blktyp_devidx_map { - unsigned char blktyp; - unsigned char dev_idx; -}; - -/* fixed m68k compiling issue: mapping table can save code field */ -static const struct blktyp_devidx_map ppc3_tas2781_mapping_table[] = { - { MAIN_ALL_DEVICES_1X, 0x80 }, - { MAIN_DEVICE_A_1X, 0x81 }, - { COEFF_DEVICE_A_1X, 0x81 }, - { PRE_DEVICE_A_1X, 0x81 }, - { PRE_SOFTWARE_RESET_DEVICE_A, 0xC1 }, - { POST_SOFTWARE_RESET_DEVICE_A, 0xC1 }, - { MAIN_DEVICE_B_1X, 0x82 }, - { COEFF_DEVICE_B_1X, 0x82 }, - { PRE_DEVICE_B_1X, 0x82 }, - { PRE_SOFTWARE_RESET_DEVICE_B, 0xC2 }, - { POST_SOFTWARE_RESET_DEVICE_B, 0xC2 }, - { MAIN_DEVICE_C_1X, 0x83 }, - { COEFF_DEVICE_C_1X, 0x83 }, - { PRE_DEVICE_C_1X, 0x83 }, - { PRE_SOFTWARE_RESET_DEVICE_C, 0xC3 }, - { POST_SOFTWARE_RESET_DEVICE_C, 0xC3 }, - { MAIN_DEVICE_D_1X, 0x84 }, - { COEFF_DEVICE_D_1X, 0x84 }, - { PRE_DEVICE_D_1X, 0x84 }, - { PRE_SOFTWARE_RESET_DEVICE_D, 0xC4 }, - { POST_SOFTWARE_RESET_DEVICE_D, 0xC4 }, -}; - -static const struct blktyp_devidx_map ppc3_mapping_table[] = { - { MAIN_ALL_DEVICES_1X, 0x80 }, - { MAIN_DEVICE_A_1X, 0x81 }, - { COEFF_DEVICE_A_1X, 0xC1 }, - { PRE_DEVICE_A_1X, 0xC1 }, - { MAIN_DEVICE_B_1X, 0x82 }, - { COEFF_DEVICE_B_1X, 0xC2 }, - { PRE_DEVICE_B_1X, 0xC2 }, - { MAIN_DEVICE_C_1X, 0x83 }, - { COEFF_DEVICE_C_1X, 0xC3 }, - { PRE_DEVICE_C_1X, 0xC3 }, - { MAIN_DEVICE_D_1X, 0x84 }, - { COEFF_DEVICE_D_1X, 0xC4 }, - { PRE_DEVICE_D_1X, 0xC4 }, -}; - -static const struct blktyp_devidx_map non_ppc3_mapping_table[] = { - { MAIN_ALL_DEVICES, 0x80 }, - { MAIN_DEVICE_A, 0x81 }, - { COEFF_DEVICE_A, 0xC1 }, - { PRE_DEVICE_A, 0xC1 }, - { MAIN_DEVICE_B, 0x82 }, - { COEFF_DEVICE_B, 0xC2 }, - { PRE_DEVICE_B, 0xC2 }, - { MAIN_DEVICE_C, 0x83 }, - { COEFF_DEVICE_C, 0xC3 }, - { PRE_DEVICE_C, 0xC3 }, - { MAIN_DEVICE_D, 0x84 }, - { COEFF_DEVICE_D, 0xC4 }, - { PRE_DEVICE_D, 0xC4 }, -}; - -/* - * Device support different configurations for different scene, - * like voice, music, calibration, was write in regbin file. - * Will be stored into tas_priv after regbin was loaded. - */ -static struct tasdevice_config_info *tasdevice_add_config( - struct tasdevice_priv *tas_priv, unsigned char *config_data, - unsigned int config_size, int *status) -{ - struct tasdevice_config_info *cfg_info; - struct tasdev_blk_data **bk_da; - unsigned int config_offset = 0; - unsigned int i; - - /* - * In most projects are many audio cases, such as music, handfree, - * receiver, games, audio-to-haptics, PMIC record, bypass mode, - * portrait, landscape, etc. Even in multiple audios, one or - * two of the chips will work for the special case, such as - * ultrasonic application. In order to support these variable-numbers - * of audio cases, flexible configs have been introduced in the - * DSP firmware. - */ - cfg_info = kzalloc(sizeof(*cfg_info), GFP_KERNEL); - if (!cfg_info) { - *status = -ENOMEM; - return NULL; - } - - if (tas_priv->rcabin.fw_hdr.binary_version_num >= 0x105) { - if ((config_offset + 64) > config_size) { - *status = -EINVAL; - dev_err(tas_priv->dev, "add conf: Out of boundary\n"); - goto config_err; - } - config_offset += 64; - } - - if ((config_offset + 4) > config_size) { - *status = -EINVAL; - dev_err(tas_priv->dev, "add config: Out of boundary\n"); - goto config_err; - } - - /* - * convert data[offset], data[offset + 1], data[offset + 2] and - * data[offset + 3] into host - */ - cfg_info->nblocks = get_unaligned_be32(&config_data[config_offset]); - config_offset += 4; - - /* - * Several kinds of dsp/algorithm firmwares can run on tas2781, - * the number and size of blk are not fixed and different among - * these firmwares. - */ - bk_da = cfg_info->blk_data = kcalloc(cfg_info->nblocks, - sizeof(*bk_da), GFP_KERNEL); - if (!bk_da) { - *status = -ENOMEM; - goto config_err; - } - cfg_info->real_nblocks = 0; - for (i = 0; i < cfg_info->nblocks; i++) { - if (config_offset + 12 > config_size) { - *status = -EINVAL; - dev_err(tas_priv->dev, - "%s: Out of boundary: i = %d nblocks = %u!\n", - __func__, i, cfg_info->nblocks); - goto block_err; - } - bk_da[i] = kzalloc(sizeof(*bk_da[i]), GFP_KERNEL); - if (!bk_da[i]) { - *status = -ENOMEM; - goto block_err; - } - - bk_da[i]->dev_idx = config_data[config_offset]; - config_offset++; - - bk_da[i]->block_type = config_data[config_offset]; - config_offset++; - - bk_da[i]->yram_checksum = - get_unaligned_be16(&config_data[config_offset]); - config_offset += 2; - bk_da[i]->block_size = - get_unaligned_be32(&config_data[config_offset]); - config_offset += 4; - - bk_da[i]->n_subblks = - get_unaligned_be32(&config_data[config_offset]); - - config_offset += 4; - - if (config_offset + bk_da[i]->block_size > config_size) { - *status = -EINVAL; - dev_err(tas_priv->dev, - "%s: Out of boundary: i = %d blks = %u!\n", - __func__, i, cfg_info->nblocks); - goto block_err; - } - /* instead of kzalloc+memcpy */ - bk_da[i]->regdata = kmemdup(&config_data[config_offset], - bk_da[i]->block_size, GFP_KERNEL); - if (!bk_da[i]->regdata) { - *status = -ENOMEM; - i++; - goto block_err; - } - - config_offset += bk_da[i]->block_size; - cfg_info->real_nblocks += 1; - } - - return cfg_info; -block_err: - for (int j = 0; j < i; j++) - kfree(bk_da[j]); - kfree(bk_da); -config_err: - kfree(cfg_info); - return NULL; -} - -/* Regbin file parser function. */ -int tasdevice_spi_rca_parser(void *context, const struct firmware *fmw) -{ - struct tasdevice_priv *tas_priv = context; - struct tasdevice_config_info **cfg_info; - struct tasdevice_rca_hdr *fw_hdr; - struct tasdevice_rca *rca; - unsigned int total_config_sz = 0; - int offset = 0, ret = 0, i; - unsigned char *buf; - - rca = &tas_priv->rcabin; - fw_hdr = &rca->fw_hdr; - if (!fmw || !fmw->data) { - dev_err(tas_priv->dev, "Failed to read %s\n", - tas_priv->rca_binaryname); - tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - return -EINVAL; - } - buf = (unsigned char *)fmw->data; - fw_hdr->img_sz = get_unaligned_be32(&buf[offset]); - offset += 4; - if (fw_hdr->img_sz != fmw->size) { - dev_err(tas_priv->dev, - "File size not match, %d %u", (int)fmw->size, - fw_hdr->img_sz); - tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - return -EINVAL; - } - - fw_hdr->checksum = get_unaligned_be32(&buf[offset]); - offset += 4; - fw_hdr->binary_version_num = get_unaligned_be32(&buf[offset]); - if (fw_hdr->binary_version_num < 0x103) { - dev_err(tas_priv->dev, "File version 0x%04x is too low", - fw_hdr->binary_version_num); - tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - return -EINVAL; - } - offset += 4; - fw_hdr->drv_fw_version = get_unaligned_be32(&buf[offset]); - offset += 8; - fw_hdr->plat_type = buf[offset++]; - fw_hdr->dev_family = buf[offset++]; - fw_hdr->reserve = buf[offset++]; - fw_hdr->ndev = buf[offset++]; - if (offset + TASDEVICE_DEVICE_SUM > fw_hdr->img_sz) { - dev_err(tas_priv->dev, "rca_ready: Out of boundary!\n"); - tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - return -EINVAL; - } - - for (i = 0; i < TASDEVICE_DEVICE_SUM; i++, offset++) - fw_hdr->devs[i] = buf[offset]; - - fw_hdr->nconfig = get_unaligned_be32(&buf[offset]); - offset += 4; - - for (i = 0; i < TASDEVICE_CONFIG_SUM; i++) { - fw_hdr->config_size[i] = get_unaligned_be32(&buf[offset]); - offset += 4; - total_config_sz += fw_hdr->config_size[i]; - } - - if (fw_hdr->img_sz - total_config_sz != (unsigned int)offset) { - dev_err(tas_priv->dev, "Bin file err %d - %d != %d!\n", - fw_hdr->img_sz, total_config_sz, (int)offset); - tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - return -EINVAL; - } - - cfg_info = kcalloc(fw_hdr->nconfig, sizeof(*cfg_info), GFP_KERNEL); - if (!cfg_info) { - tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - return -ENOMEM; - } - rca->cfg_info = cfg_info; - rca->ncfgs = 0; - for (i = 0; i < (int)fw_hdr->nconfig; i++) { - rca->ncfgs += 1; - cfg_info[i] = tasdevice_add_config(tas_priv, &buf[offset], - fw_hdr->config_size[i], &ret); - if (ret) { - tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - return ret; - } - offset += (int)fw_hdr->config_size[i]; - } - - return ret; -} - -/* fixed m68k compiling issue: mapping table can save code field */ -static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw, - struct tasdev_blk *block) -{ - struct blktyp_devidx_map *p = - (struct blktyp_devidx_map *)non_ppc3_mapping_table; - struct tasdevice_dspfw_hdr *fw_hdr = &tas_fmw->fw_hdr; - struct tasdevice_fw_fixed_hdr *fw_fixed_hdr = &fw_hdr->fixed_hdr; - int i, n = ARRAY_SIZE(non_ppc3_mapping_table); - unsigned char dev_idx = 0; - - if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781) { - p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table; - n = ARRAY_SIZE(ppc3_tas2781_mapping_table); - } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION) { - p = (struct blktyp_devidx_map *)ppc3_mapping_table; - n = ARRAY_SIZE(ppc3_mapping_table); - } - - for (i = 0; i < n; i++) { - if (block->type == p[i].blktyp) { - dev_idx = p[i].dev_idx; - break; - } - } - - return dev_idx; -} - -/* Block parser function. */ -static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw, - struct tasdev_blk *block, const struct firmware *fmw, int offset) -{ - const unsigned char *data = fmw->data; - - if (offset + 16 > fmw->size) { - dev_err(tas_fmw->dev, "%s: File Size error\n", __func__); - return -EINVAL; - } - - /* - * Convert data[offset], data[offset + 1], data[offset + 2] and - * data[offset + 3] into host. - */ - block->type = get_unaligned_be32(&data[offset]); - offset += 4; - - block->is_pchksum_present = data[offset++]; - block->pchksum = data[offset++]; - block->is_ychksum_present = data[offset++]; - block->ychksum = data[offset++]; - block->blk_size = get_unaligned_be32(&data[offset]); - offset += 4; - block->nr_subblocks = get_unaligned_be32(&data[offset]); - offset += 4; - - /* - * Fixed m68k compiling issue: - * 1. mapping table can save code field. - * 2. storing the dev_idx as a member of block can reduce unnecessary - * time and system resource comsumption of dev_idx mapping every - * time the block data writing to the dsp. - */ - block->dev_idx = map_dev_idx(tas_fmw, block); - - if (offset + block->blk_size > fmw->size) { - dev_err(tas_fmw->dev, "%s: nSublocks error\n", __func__); - return -EINVAL; - } - /* instead of kzalloc+memcpy */ - block->data = kmemdup(&data[offset], block->blk_size, GFP_KERNEL); - if (!block->data) - return -ENOMEM; - - offset += block->blk_size; - - return offset; -} - -/* Data of block parser function. */ -static int fw_parse_data_kernel(struct tasdevice_fw *tas_fmw, - struct tasdevice_data *img_data, const struct firmware *fmw, - int offset) -{ - const unsigned char *data = fmw->data; - struct tasdev_blk *blk; - unsigned int i; - - if (offset + 4 > fmw->size) { - dev_err(tas_fmw->dev, "%s: File Size error\n", __func__); - return -EINVAL; - } - img_data->nr_blk = get_unaligned_be32(&data[offset]); - offset += 4; - - img_data->dev_blks = kcalloc(img_data->nr_blk, - sizeof(struct tasdev_blk), GFP_KERNEL); - if (!img_data->dev_blks) - return -ENOMEM; - - for (i = 0; i < img_data->nr_blk; i++) { - blk = &img_data->dev_blks[i]; - offset = fw_parse_block_data_kernel( - tas_fmw, blk, fmw, offset); - if (offset < 0) { - kfree(img_data->dev_blks); - return -EINVAL; - } - } - - return offset; -} - -/* Data of DSP program parser function. */ -static int fw_parse_program_data_kernel( - struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw, - const struct firmware *fmw, int offset) -{ - struct tasdevice_prog *program; - unsigned int i; - - for (i = 0; i < tas_fmw->nr_programs; i++) { - program = &tas_fmw->programs[i]; - if (offset + 72 > fmw->size) { - dev_err(tas_priv->dev, "%s: mpName error\n", __func__); - return -EINVAL; - } - /* skip 72 unused byts */ - offset += 72; - - offset = fw_parse_data_kernel(tas_fmw, &program->dev_data, - fmw, offset); - if (offset < 0) - break; - } - - return offset; -} - -/* Data of DSP configurations parser function. */ -static int fw_parse_configuration_data_kernel(struct tasdevice_priv *tas_priv, - struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) -{ - const unsigned char *data = fmw->data; - struct tasdevice_config *config; - unsigned int i; - - for (i = 0; i < tas_fmw->nr_configurations; i++) { - config = &tas_fmw->configs[i]; - if (offset + 80 > fmw->size) { - dev_err(tas_priv->dev, "%s: mpName error\n", __func__); - return -EINVAL; - } - memcpy(config->name, &data[offset], 64); - /* skip extra 16 bytes */ - offset += 80; - - offset = fw_parse_data_kernel(tas_fmw, &config->dev_data, - fmw, offset); - if (offset < 0) - break; - } - - return offset; -} - -/* DSP firmware file header parser function for early PPC3 firmware binary. */ -static int fw_parse_variable_header_kernel(struct tasdevice_priv *tas_priv, - const struct firmware *fmw, int offset) -{ - struct tasdevice_fw *tas_fmw = tas_priv->fmw; - struct tasdevice_dspfw_hdr *fw_hdr = &tas_fmw->fw_hdr; - struct tasdevice_config *config; - struct tasdevice_prog *program; - const unsigned char *buf = fmw->data; - unsigned short max_confs; - unsigned int i; - - if (offset + 12 + 4 * TASDEVICE_MAXPROGRAM_NUM_KERNEL > fmw->size) { - dev_err(tas_priv->dev, "%s: File Size error\n", __func__); - return -EINVAL; - } - fw_hdr->device_family = get_unaligned_be16(&buf[offset]); - if (fw_hdr->device_family != 0) { - dev_err(tas_priv->dev, "%s:not TAS device\n", __func__); - return -EINVAL; - } - offset += 2; - fw_hdr->device = get_unaligned_be16(&buf[offset]); - if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE || - fw_hdr->device == 6) { - dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device); - return -EINVAL; - } - offset += 2; - - tas_fmw->nr_programs = get_unaligned_be32(&buf[offset]); - offset += 4; - - if (tas_fmw->nr_programs == 0 || - tas_fmw->nr_programs > TASDEVICE_MAXPROGRAM_NUM_KERNEL) { - dev_err(tas_priv->dev, "mnPrograms is invalid\n"); - return -EINVAL; - } - - tas_fmw->programs = kcalloc(tas_fmw->nr_programs, - sizeof(*tas_fmw->programs), GFP_KERNEL); - if (!tas_fmw->programs) - return -ENOMEM; - - for (i = 0; i < tas_fmw->nr_programs; i++) { - program = &tas_fmw->programs[i]; - program->prog_size = get_unaligned_be32(&buf[offset]); - offset += 4; - } - - /* Skip the unused prog_size */ - offset += 4 * (TASDEVICE_MAXPROGRAM_NUM_KERNEL - tas_fmw->nr_programs); - - tas_fmw->nr_configurations = get_unaligned_be32(&buf[offset]); - offset += 4; - - /* - * The max number of config in firmware greater than 4 pieces of - * tas2781s is different from the one lower than 4 pieces of - * tas2781s. - */ - max_confs = TASDEVICE_MAXCONFIG_NUM_KERNEL; - if (tas_fmw->nr_configurations == 0 || - tas_fmw->nr_configurations > max_confs) { - dev_err(tas_priv->dev, "%s: Conf is invalid\n", __func__); - kfree(tas_fmw->programs); - return -EINVAL; - } - - if (offset + 4 * max_confs > fmw->size) { - dev_err(tas_priv->dev, "%s: mpConfigurations err\n", __func__); - kfree(tas_fmw->programs); - return -EINVAL; - } - - tas_fmw->configs = kcalloc(tas_fmw->nr_configurations, - sizeof(*tas_fmw->configs), GFP_KERNEL); - if (!tas_fmw->configs) { - kfree(tas_fmw->programs); - return -ENOMEM; - } - - for (i = 0; i < tas_fmw->nr_programs; i++) { - config = &tas_fmw->configs[i]; - config->cfg_size = get_unaligned_be32(&buf[offset]); - offset += 4; - } - - /* Skip the unused configs */ - offset += 4 * (max_confs - tas_fmw->nr_programs); - - return offset; -} - -/* - * In sub-block data, have three type sub-block: - * 1. Single byte write. - * 2. Multi-byte write. - * 3. Delay. - * 4. Bits update. - * This function perform single byte write to device. - */ -static int tasdevice_single_byte_wr(void *context, int dev_idx, - unsigned char *data, int sublocksize) -{ - struct tasdevice_priv *tas_priv = context; - unsigned short len = get_unaligned_be16(&data[2]); - int i, subblk_offset, rc; - - subblk_offset = 4; - if (subblk_offset + 4 * len > sublocksize) { - dev_err(tas_priv->dev, "process_block: Out of boundary\n"); - return 0; - } - - for (i = 0; i < len; i++) { - if (dev_idx == (tas_priv->index + 1) || dev_idx == 0) { - rc = tasdevice_spi_dev_write(tas_priv, - TASDEVICE_REG(data[subblk_offset], - data[subblk_offset + 1], - data[subblk_offset + 2]), - data[subblk_offset + 3]); - if (rc < 0) { - dev_err(tas_priv->dev, - "process_block: single write error\n"); - subblk_offset |= OFFSET_ERROR_BIT; - } - } - subblk_offset += 4; - } - - return subblk_offset; -} - -/* - * In sub-block data, have three type sub-block: - * 1. Single byte write. - * 2. Multi-byte write. - * 3. Delay. - * 4. Bits update. - * This function perform multi-write to device. - */ -static int tasdevice_burst_wr(void *context, int dev_idx, unsigned char *data, - int sublocksize) -{ - struct tasdevice_priv *tas_priv = context; - unsigned short len = get_unaligned_be16(&data[2]); - int subblk_offset, rc; - - subblk_offset = 4; - if (subblk_offset + 4 + len > sublocksize) { - dev_err(tas_priv->dev, "%s: BST Out of boundary\n", __func__); - subblk_offset |= OFFSET_ERROR_BIT; - } - if (len % 4) { - dev_err(tas_priv->dev, "%s:Bst-len(%u)not div by 4\n", - __func__, len); - subblk_offset |= OFFSET_ERROR_BIT; - } - - if (dev_idx == (tas_priv->index + 1) || dev_idx == 0) { - rc = tasdevice_spi_dev_bulk_write(tas_priv, - TASDEVICE_REG(data[subblk_offset], - data[subblk_offset + 1], - data[subblk_offset + 2]), - &data[subblk_offset + 4], len); - if (rc < 0) { - dev_err(tas_priv->dev, "%s: bulk_write error = %d\n", - __func__, rc); - subblk_offset |= OFFSET_ERROR_BIT; - } - } - subblk_offset += (len + 4); - - return subblk_offset; -} - -/* Just delay for ms.*/ -static int tasdevice_delay(void *context, int dev_idx, unsigned char *data, - int sublocksize) -{ - struct tasdevice_priv *tas_priv = context; - unsigned int sleep_time, subblk_offset = 2; - - if (subblk_offset + 2 > sublocksize) { - dev_err(tas_priv->dev, "%s: delay Out of boundary\n", - __func__); - subblk_offset |= OFFSET_ERROR_BIT; - } - if (dev_idx == (tas_priv->index + 1) || dev_idx == 0) { - sleep_time = get_unaligned_be16(&data[2]) * 1000; - fsleep(sleep_time); - } - subblk_offset += 2; - - return subblk_offset; -} - -/* - * In sub-block data, have three type sub-block: - * 1. Single byte write. - * 2. Multi-byte write. - * 3. Delay. - * 4. Bits update. - * This function perform bits update. - */ -static int tasdevice_field_wr(void *context, int dev_idx, unsigned char *data, - int sublocksize) -{ - struct tasdevice_priv *tas_priv = context; - int rc, subblk_offset = 2; - - if (subblk_offset + 6 > sublocksize) { - dev_err(tas_priv->dev, "%s: bit write Out of boundary\n", - __func__); - subblk_offset |= OFFSET_ERROR_BIT; - } - if (dev_idx == (tas_priv->index + 1) || dev_idx == 0) { - rc = tasdevice_spi_dev_update_bits(tas_priv, - TASDEVICE_REG(data[subblk_offset + 2], - data[subblk_offset + 3], - data[subblk_offset + 4]), - data[subblk_offset + 1], - data[subblk_offset + 5]); - if (rc < 0) { - dev_err(tas_priv->dev, "%s: update_bits error = %d\n", - __func__, rc); - subblk_offset |= OFFSET_ERROR_BIT; - } - } - subblk_offset += 6; - - return subblk_offset; -} - -/* Data block process function. */ -static int tasdevice_process_block(void *context, unsigned char *data, - unsigned char dev_idx, int sublocksize) -{ - struct tasdevice_priv *tas_priv = context; - int blktyp = dev_idx & 0xC0, subblk_offset; - unsigned char subblk_typ = data[1]; - - switch (subblk_typ) { - case TASDEVICE_CMD_SING_W: - subblk_offset = tasdevice_single_byte_wr(tas_priv, - dev_idx & 0x4f, data, sublocksize); - break; - case TASDEVICE_CMD_BURST: - subblk_offset = tasdevice_burst_wr(tas_priv, - dev_idx & 0x4f, data, sublocksize); - break; - case TASDEVICE_CMD_DELAY: - subblk_offset = tasdevice_delay(tas_priv, - dev_idx & 0x4f, data, sublocksize); - break; - case TASDEVICE_CMD_FIELD_W: - subblk_offset = tasdevice_field_wr(tas_priv, - dev_idx & 0x4f, data, sublocksize); - break; - default: - subblk_offset = 2; - break; - } - if (((subblk_offset & OFFSET_ERROR_BIT) != 0) && blktyp != 0) { - if (blktyp == 0x80) { - tas_priv->cur_prog = -1; - tas_priv->cur_conf = -1; - } else - tas_priv->cur_conf = -1; - } - subblk_offset &= ~OFFSET_ERROR_BIT; - - return subblk_offset; -} - -/* - * Device support different configurations for different scene, - * this function was used for choose different config. - */ -void tasdevice_spi_select_cfg_blk(void *pContext, int conf_no, - unsigned char block_type) -{ - struct tasdevice_priv *tas_priv = pContext; - struct tasdevice_rca *rca = &tas_priv->rcabin; - struct tasdevice_config_info **cfg_info = rca->cfg_info; - struct tasdev_blk_data **blk_data; - unsigned int j, k; - - if (conf_no >= rca->ncfgs || conf_no < 0 || !cfg_info) { - dev_err(tas_priv->dev, "conf_no should be not more than %u\n", - rca->ncfgs); - return; - } - blk_data = cfg_info[conf_no]->blk_data; - - for (j = 0; j < cfg_info[conf_no]->real_nblocks; j++) { - unsigned int length = 0, rc = 0; - - if (block_type > 5 || block_type < 2) { - dev_err(tas_priv->dev, - "block_type should be in range from 2 to 5\n"); - break; - } - if (block_type != blk_data[j]->block_type) - continue; - - for (k = 0; k < blk_data[j]->n_subblks; k++) { - tas_priv->is_loading = true; - - rc = tasdevice_process_block(tas_priv, - blk_data[j]->regdata + length, - blk_data[j]->dev_idx, - blk_data[j]->block_size - length); - length += rc; - if (blk_data[j]->block_size < length) { - dev_err(tas_priv->dev, - "%s: %u %u out of boundary\n", - __func__, length, - blk_data[j]->block_size); - break; - } - } - if (length != blk_data[j]->block_size) - dev_err(tas_priv->dev, "%s: %u %u size is not same\n", - __func__, length, blk_data[j]->block_size); - } -} - -/* Block process function. */ -static int tasdevice_load_block_kernel( - struct tasdevice_priv *tasdevice, struct tasdev_blk *block) -{ - const unsigned int blk_size = block->blk_size; - unsigned char *data = block->data; - unsigned int i, length; - - for (i = 0, length = 0; i < block->nr_subblocks; i++) { - int rc = tasdevice_process_block(tasdevice, data + length, - block->dev_idx, blk_size - length); - if (rc < 0) { - dev_err(tasdevice->dev, - "%s: %u %u sublock write error\n", - __func__, length, blk_size); - return rc; - } - length += rc; - if (blk_size < length) { - dev_err(tasdevice->dev, "%s: %u %u out of boundary\n", - __func__, length, blk_size); - rc = -ENOMEM; - return rc; - } - } - - return 0; -} - -/* DSP firmware file header parser function. */ -static int fw_parse_variable_hdr(struct tasdevice_priv *tas_priv, - struct tasdevice_dspfw_hdr *fw_hdr, - const struct firmware *fmw, int offset) -{ - const unsigned char *buf = fmw->data; - int len = strlen((char *)&buf[offset]); - - len++; - - if (offset + len + 8 > fmw->size) { - dev_err(tas_priv->dev, "%s: File Size error\n", __func__); - return -EINVAL; - } - - offset += len; - - fw_hdr->device_family = get_unaligned_be32(&buf[offset]); - if (fw_hdr->device_family != 0) { - dev_err(tas_priv->dev, "%s: not TAS device\n", __func__); - return -EINVAL; - } - offset += 4; - - fw_hdr->device = get_unaligned_be32(&buf[offset]); - if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE || - fw_hdr->device == 6) { - dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device); - return -EINVAL; - } - offset += 4; - fw_hdr->ndev = 1; - - return offset; -} - -/* DSP firmware file header parser function for size variabled header. */ -static int fw_parse_variable_header_git(struct tasdevice_priv - *tas_priv, const struct firmware *fmw, int offset) -{ - struct tasdevice_fw *tas_fmw = tas_priv->fmw; - struct tasdevice_dspfw_hdr *fw_hdr = &tas_fmw->fw_hdr; - - offset = fw_parse_variable_hdr(tas_priv, fw_hdr, fmw, offset); - - return offset; -} - -/* DSP firmware file block parser function. */ -static int fw_parse_block_data(struct tasdevice_fw *tas_fmw, - struct tasdev_blk *block, const struct firmware *fmw, int offset) -{ - unsigned char *data = (unsigned char *)fmw->data; - int n; - - if (offset + 8 > fmw->size) { - dev_err(tas_fmw->dev, "%s: Type error\n", __func__); - return -EINVAL; - } - block->type = get_unaligned_be32(&data[offset]); - offset += 4; - - if (tas_fmw->fw_hdr.fixed_hdr.drv_ver >= PPC_DRIVER_CRCCHK) { - if (offset + 8 > fmw->size) { - dev_err(tas_fmw->dev, "PChkSumPresent error\n"); - return -EINVAL; - } - block->is_pchksum_present = data[offset]; - offset++; - - block->pchksum = data[offset]; - offset++; - - block->is_ychksum_present = data[offset]; - offset++; - - block->ychksum = data[offset]; - offset++; - } else { - block->is_pchksum_present = 0; - block->is_ychksum_present = 0; - } - - block->nr_cmds = get_unaligned_be32(&data[offset]); - offset += 4; - - n = block->nr_cmds * 4; - if (offset + n > fmw->size) { - dev_err(tas_fmw->dev, - "%s: File Size(%lu) error offset = %d n = %d\n", - __func__, (unsigned long)fmw->size, offset, n); - return -EINVAL; - } - /* instead of kzalloc+memcpy */ - block->data = kmemdup(&data[offset], n, GFP_KERNEL); - if (!block->data) - return -ENOMEM; - - offset += n; - - return offset; -} - -/* - * When parsing error occurs, all the memory resource will be released - * in the end of tasdevice_rca_ready. - */ -static int fw_parse_data(struct tasdevice_fw *tas_fmw, - struct tasdevice_data *img_data, const struct firmware *fmw, - int offset) -{ - const unsigned char *data = (unsigned char *)fmw->data; - struct tasdev_blk *blk; - unsigned int i, n; - - if (offset + 64 > fmw->size) { - dev_err(tas_fmw->dev, "%s: Name error\n", __func__); - return -EINVAL; - } - memcpy(img_data->name, &data[offset], 64); - offset += 64; - - n = strlen((char *)&data[offset]); - n++; - if (offset + n + 2 > fmw->size) { - dev_err(tas_fmw->dev, "%s: Description error\n", __func__); - return -EINVAL; - } - offset += n; - img_data->nr_blk = get_unaligned_be16(&data[offset]); - offset += 2; - - img_data->dev_blks = kcalloc(img_data->nr_blk, - sizeof(*img_data->dev_blks), GFP_KERNEL); - if (!img_data->dev_blks) - return -ENOMEM; - - for (i = 0; i < img_data->nr_blk; i++) { - blk = &img_data->dev_blks[i]; - offset = fw_parse_block_data(tas_fmw, blk, fmw, offset); - if (offset < 0) - return -EINVAL; - } - - return offset; -} - -/* - * When parsing error occurs, all the memory resource will be released - * in the end of tasdevice_rca_ready. - */ -static int fw_parse_program_data(struct tasdevice_priv *tas_priv, - struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) -{ - unsigned char *buf = (unsigned char *)fmw->data; - struct tasdevice_prog *program; - int i; - - if (offset + 2 > fmw->size) { - dev_err(tas_priv->dev, "%s: File Size error\n", __func__); - return -EINVAL; - } - tas_fmw->nr_programs = get_unaligned_be16(&buf[offset]); - offset += 2; - - if (tas_fmw->nr_programs == 0) { - /* Not error in calibration Data file, return directly */ - dev_dbg(tas_priv->dev, "%s: No Programs data, maybe calbin\n", - __func__); - return offset; - } - - tas_fmw->programs = - kcalloc(tas_fmw->nr_programs, sizeof(*tas_fmw->programs), - GFP_KERNEL); - if (!tas_fmw->programs) - return -ENOMEM; - - for (i = 0; i < tas_fmw->nr_programs; i++) { - int n = 0; - - program = &tas_fmw->programs[i]; - if (offset + 64 > fmw->size) { - dev_err(tas_priv->dev, "%s: mpName error\n", __func__); - return -EINVAL; - } - offset += 64; - - n = strlen((char *)&buf[offset]); - /* skip '\0' and 5 unused bytes */ - n += 6; - if (offset + n > fmw->size) { - dev_err(tas_priv->dev, "Description err\n"); - return -EINVAL; - } - - offset += n; - - offset = fw_parse_data(tas_fmw, &program->dev_data, fmw, - offset); - if (offset < 0) - return offset; - } - - return offset; -} - -/* - * When parsing error occurs, all the memory resource will be released - * in the end of tasdevice_rca_ready. - */ -static int fw_parse_configuration_data(struct tasdevice_priv *tas_priv, - struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) -{ - unsigned char *data = (unsigned char *)fmw->data; - struct tasdevice_config *config; - unsigned int i, n; - - if (offset + 2 > fmw->size) { - dev_err(tas_priv->dev, "%s: File Size error\n", __func__); - return -EINVAL; - } - tas_fmw->nr_configurations = get_unaligned_be16(&data[offset]); - offset += 2; - - if (tas_fmw->nr_configurations == 0) { - dev_err(tas_priv->dev, "%s: Conf is zero\n", __func__); - /* Not error for calibration Data file, return directly */ - return offset; - } - tas_fmw->configs = kcalloc(tas_fmw->nr_configurations, - sizeof(*tas_fmw->configs), GFP_KERNEL); - if (!tas_fmw->configs) - return -ENOMEM; - for (i = 0; i < tas_fmw->nr_configurations; i++) { - config = &tas_fmw->configs[i]; - if (offset + 64 > fmw->size) { - dev_err(tas_priv->dev, "File Size err\n"); - return -EINVAL; - } - memcpy(config->name, &data[offset], 64); - offset += 64; - - n = strlen((char *)&data[offset]); - n += 15; - if (offset + n > fmw->size) { - dev_err(tas_priv->dev, "Description err\n"); - return -EINVAL; - } - offset += n; - offset = fw_parse_data(tas_fmw, &config->dev_data, - fmw, offset); - if (offset < 0) - break; - } - - return offset; -} - -/* yram5 page check. */ -static bool check_inpage_yram_rg(struct tas_crc *cd, - unsigned char reg, unsigned char len) -{ - bool in = false; - - if (reg <= TAS2781_YRAM5_END_REG && - reg >= TAS2781_YRAM5_START_REG) { - if (reg + len > TAS2781_YRAM5_END_REG) - cd->len = TAS2781_YRAM5_END_REG - reg + 1; - else - cd->len = len; - cd->offset = reg; - in = true; - } else if (reg < TAS2781_YRAM5_START_REG) { - if (reg + len > TAS2781_YRAM5_START_REG) { - cd->offset = TAS2781_YRAM5_START_REG; - cd->len = len - TAS2781_YRAM5_START_REG + reg; - in = true; - } - } - - return in; -} - -/* DSP firmware yram block check. */ -static bool check_inpage_yram_bk1(struct tas_crc *cd, - unsigned char page, unsigned char reg, unsigned char len) -{ - bool in = false; - - if (page == TAS2781_YRAM1_PAGE) { - if (reg >= TAS2781_YRAM1_START_REG) { - cd->offset = reg; - cd->len = len; - in = true; - } else if (reg + len > TAS2781_YRAM1_START_REG) { - cd->offset = TAS2781_YRAM1_START_REG; - cd->len = len - TAS2781_YRAM1_START_REG + reg; - in = true; - } - } else if (page == TAS2781_YRAM3_PAGE) { - in = check_inpage_yram_rg(cd, reg, len); - } - - return in; -} - -/* - * Return Code: - * true -- the registers are in the inpage yram - * false -- the registers are NOT in the inpage yram - */ -static bool check_inpage_yram(struct tas_crc *cd, unsigned char book, - unsigned char page, unsigned char reg, unsigned char len) -{ - bool in = false; - - if (book == TAS2781_YRAM_BOOK1) - in = check_inpage_yram_bk1(cd, page, reg, len); - else if (book == TAS2781_YRAM_BOOK2 && page == TAS2781_YRAM5_PAGE) - in = check_inpage_yram_rg(cd, reg, len); - - return in; -} - -/* yram4 page check. */ -static bool check_inblock_yram_bk(struct tas_crc *cd, - unsigned char page, unsigned char reg, unsigned char len) -{ - bool in = false; - - if ((page >= TAS2781_YRAM4_START_PAGE && - page <= TAS2781_YRAM4_END_PAGE) || - (page >= TAS2781_YRAM2_START_PAGE && - page <= TAS2781_YRAM2_END_PAGE)) { - if (reg <= TAS2781_YRAM2_END_REG && - reg >= TAS2781_YRAM2_START_REG) { - cd->offset = reg; - cd->len = len; - in = true; - } else if (reg < TAS2781_YRAM2_START_REG) { - if (reg + len - 1 >= TAS2781_YRAM2_START_REG) { - cd->offset = TAS2781_YRAM2_START_REG; - cd->len = reg + len - TAS2781_YRAM2_START_REG; - in = true; - } - } - } - - return in; -} - -/* - * Return Code: - * true -- the registers are in the inblock yram - * false -- the registers are NOT in the inblock yram - */ -static bool check_inblock_yram(struct tas_crc *cd, unsigned char book, - unsigned char page, unsigned char reg, unsigned char len) -{ - bool in = false; - - if (book == TAS2781_YRAM_BOOK1 || book == TAS2781_YRAM_BOOK2) - in = check_inblock_yram_bk(cd, page, reg, len); - - return in; -} - -/* yram page check. */ -static bool check_yram(struct tas_crc *cd, unsigned char book, - unsigned char page, unsigned char reg, unsigned char len) -{ - bool in; - - in = check_inpage_yram(cd, book, page, reg, len); - if (!in) - in = check_inblock_yram(cd, book, page, reg, len); - - return in; -} - -/* Checksum for data block. */ -static int tasdev_multibytes_chksum(struct tasdevice_priv *tasdevice, - unsigned char book, unsigned char page, - unsigned char reg, unsigned int len) -{ - struct tas_crc crc_data; - unsigned char crc_chksum = 0; - unsigned char nBuf1[128]; - int ret = 0, i; - bool in; - - if ((reg + len - 1) > 127) { - ret = -EINVAL; - dev_err(tasdevice->dev, "firmware error\n"); - goto end; - } - - if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) && - (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG)) && - (reg == TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG)) && - (len == 4)) { - /* DSP swap command, pass */ - ret = 0; - goto end; - } - - in = check_yram(&crc_data, book, page, reg, len); - if (!in) - goto end; - - if (len == 1) { - dev_err(tasdevice->dev, "firmware error\n"); - ret = -EINVAL; - goto end; - } - - ret = tasdevice_spi_dev_bulk_read(tasdevice, - TASDEVICE_REG(book, page, crc_data.offset), - nBuf1, crc_data.len); - if (ret < 0) - goto end; - - for (i = 0; i < crc_data.len; i++) { - if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) && - (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG)) && - ((i + crc_data.offset) >= - TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG)) && - ((i + crc_data.offset) <= - (TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG) + 4))) - /* DSP swap command, bypass */ - continue; - else - crc_chksum += crc8(tasdevice->crc8_lkp_tbl, &nBuf1[i], - 1, 0); - } - - ret = crc_chksum; - -end: - return ret; -} - -/* Checksum for single register. */ -static int do_singlereg_checksum(struct tasdevice_priv *tasdevice, - unsigned char book, unsigned char page, - unsigned char reg, unsigned char val) -{ - struct tas_crc crc_data; - unsigned int nData1; - int ret = 0; - bool in; - - /* DSP swap command, pass */ - if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) && - (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG)) && - (reg >= TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG)) && - (reg <= (TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG) + 4))) - return 0; - - in = check_yram(&crc_data, book, page, reg, 1); - if (!in) - return 0; - ret = tasdevice_spi_dev_read(tasdevice, - TASDEVICE_REG(book, page, reg), &nData1); - if (ret < 0) - return ret; - - if (nData1 != val) { - dev_err(tasdevice->dev, - "B[0x%x]P[0x%x]R[0x%x] W[0x%x], R[0x%x]\n", - book, page, reg, val, nData1); - tasdevice->err_code |= ERROR_YRAM_CRCCHK; - return -EAGAIN; - } - - ret = crc8(tasdevice->crc8_lkp_tbl, &val, 1, 0); - - return ret; -} - -/* Block type check. */ -static void set_err_prg_cfg(unsigned int type, struct tasdevice_priv *p) -{ - if ((type == MAIN_ALL_DEVICES) || (type == MAIN_DEVICE_A) || - (type == MAIN_DEVICE_B) || (type == MAIN_DEVICE_C) || - (type == MAIN_DEVICE_D)) - p->cur_prog = -1; - else - p->cur_conf = -1; -} - -/* Checksum for data bytes. */ -static int tasdev_bytes_chksum(struct tasdevice_priv *tas_priv, - struct tasdev_blk *block, unsigned char book, - unsigned char page, unsigned char reg, unsigned int len, - unsigned char val, unsigned char *crc_chksum) -{ - int ret; - - if (len > 1) - ret = tasdev_multibytes_chksum(tas_priv, book, page, reg, - len); - else - ret = do_singlereg_checksum(tas_priv, book, page, reg, val); - - if (ret > 0) { - *crc_chksum += ret; - goto end; - } - - if (ret != -EAGAIN) - goto end; - - block->nr_retry--; - if (block->nr_retry > 0) - goto end; - - set_err_prg_cfg(block->type, tas_priv); - -end: - return ret; -} - -/* Multi-data byte write. */ -static int tasdev_multibytes_wr(struct tasdevice_priv *tas_priv, - struct tasdev_blk *block, unsigned char book, - unsigned char page, unsigned char reg, unsigned char *data, - unsigned int len, unsigned int *nr_cmds, - unsigned char *crc_chksum) -{ - int ret; - - if (len > 1) { - ret = tasdevice_spi_dev_bulk_write(tas_priv, - TASDEVICE_REG(book, page, reg), data + 3, len); - if (ret < 0) - return ret; - if (block->is_ychksum_present) - ret = tasdev_bytes_chksum(tas_priv, block, - book, page, reg, len, 0, crc_chksum); - } else { - ret = tasdevice_spi_dev_write(tas_priv, - TASDEVICE_REG(book, page, reg), data[3]); - if (ret < 0) - return ret; - if (block->is_ychksum_present) - ret = tasdev_bytes_chksum(tas_priv, block, book, - page, reg, 1, data[3], crc_chksum); - } - - if (!block->is_ychksum_present || ret >= 0) { - *nr_cmds += 1; - if (len >= 2) - *nr_cmds += ((len - 2) / 4) + 1; - } - - return ret; -} - -/* Checksum for block. */ -static int tasdev_block_chksum(struct tasdevice_priv *tas_priv, - struct tasdev_blk *block) -{ - unsigned int nr_value; - int ret; - - ret = tasdevice_spi_dev_read(tas_priv, TASDEVICE_CHECKSUM, &nr_value); - if (ret < 0) { - dev_err(tas_priv->dev, "%s: read error %d.\n", __func__, ret); - set_err_prg_cfg(block->type, tas_priv); - return ret; - } - - if ((nr_value & 0xff) != block->pchksum) { - dev_err(tas_priv->dev, "%s: PChkSum err %d ", __func__, ret); - dev_err(tas_priv->dev, "PChkSum = 0x%x, Reg = 0x%x\n", - block->pchksum, (nr_value & 0xff)); - tas_priv->err_code |= ERROR_PRAM_CRCCHK; - ret = -EAGAIN; - block->nr_retry--; - - if (block->nr_retry <= 0) - set_err_prg_cfg(block->type, tas_priv); - } else { - tas_priv->err_code &= ~ERROR_PRAM_CRCCHK; - } - - return ret; -} - -/* Firmware block load function. */ -static int tasdev_load_blk(struct tasdevice_priv *tas_priv, - struct tasdev_blk *block) -{ - unsigned int sleep_time, len, nr_cmds; - unsigned char offset, book, page, val; - unsigned char *data = block->data; - unsigned char crc_chksum = 0; - int ret = 0; - - while (block->nr_retry > 0) { - if (block->is_pchksum_present) { - ret = tasdevice_spi_dev_write(tas_priv, - TASDEVICE_CHECKSUM, 0); - if (ret < 0) - break; - } - - if (block->is_ychksum_present) - crc_chksum = 0; - - nr_cmds = 0; - - while (nr_cmds < block->nr_cmds) { - data = block->data + nr_cmds * 4; - - book = data[0]; - page = data[1]; - offset = data[2]; - val = data[3]; - - nr_cmds++; - /* Single byte write */ - if (offset <= 0x7F) { - ret = tasdevice_spi_dev_write(tas_priv, - TASDEVICE_REG(book, page, offset), - val); - if (ret < 0) - break; - if (block->is_ychksum_present) { - ret = tasdev_bytes_chksum(tas_priv, - block, book, page, offset, - 1, val, &crc_chksum); - if (ret < 0) - break; - } - continue; - } - /* sleep command */ - if (offset == 0x81) { - /* book -- data[0] page -- data[1] */ - sleep_time = ((book << 8) + page)*1000; - fsleep(sleep_time); - continue; - } - /* Multiple bytes write */ - if (offset == 0x85) { - data += 4; - len = (book << 8) + page; - book = data[0]; - page = data[1]; - offset = data[2]; - ret = tasdev_multibytes_wr(tas_priv, - block, book, page, offset, data, - len, &nr_cmds, &crc_chksum); - if (ret < 0) - break; - } - } - if (ret == -EAGAIN) { - if (block->nr_retry > 0) - continue; - } else if (ret < 0) { - /* err in current device, skip it */ - break; - } - - if (block->is_pchksum_present) { - ret = tasdev_block_chksum(tas_priv, block); - if (ret == -EAGAIN) { - if (block->nr_retry > 0) - continue; - } else if (ret < 0) { - /* err in current device, skip it */ - break; - } - } - - if (block->is_ychksum_present) { - /* TBD, open it when FW ready */ - dev_err(tas_priv->dev, - "Blk YChkSum: FW = 0x%x, YCRC = 0x%x\n", - block->ychksum, crc_chksum); - - tas_priv->err_code &= - ~ERROR_YRAM_CRCCHK; - ret = 0; - } - /* skip current blk */ - break; - } - - return ret; -} - -/* Firmware block load function. */ -static int tasdevice_load_block(struct tasdevice_priv *tas_priv, - struct tasdev_blk *block) -{ - int ret = 0; - - block->nr_retry = 6; - if (tas_priv->is_loading == false) - return 0; - ret = tasdev_load_blk(tas_priv, block); - if (ret < 0) - dev_err(tas_priv->dev, "Blk (%d) load error\n", block->type); - - return ret; -} - -/* - * Select firmware binary parser & load callback functions by ppc3 version - * and firmware binary version. - */ -static int dspfw_default_callback(struct tasdevice_priv *tas_priv, - unsigned int drv_ver, unsigned int ppcver) -{ - int rc = 0; - - if (drv_ver == 0x100) { - if (ppcver >= PPC3_VERSION) { - tas_priv->fw_parse_variable_header = - fw_parse_variable_header_kernel; - tas_priv->fw_parse_program_data = - fw_parse_program_data_kernel; - tas_priv->fw_parse_configuration_data = - fw_parse_configuration_data_kernel; - tas_priv->tasdevice_load_block = - tasdevice_load_block_kernel; - } else if (ppcver == 0x00) { - tas_priv->fw_parse_variable_header = - fw_parse_variable_header_git; - tas_priv->fw_parse_program_data = - fw_parse_program_data; - tas_priv->fw_parse_configuration_data = - fw_parse_configuration_data; - tas_priv->tasdevice_load_block = - tasdevice_load_block; - } else { - dev_err(tas_priv->dev, - "Wrong PPCVer :0x%08x\n", ppcver); - rc = -EINVAL; - } - } else { - dev_err(tas_priv->dev, "Wrong DrvVer : 0x%02x\n", drv_ver); - rc = -EINVAL; - } - - return rc; -} - -/* DSP firmware binary file header parser function. */ -static int fw_parse_header(struct tasdevice_priv *tas_priv, - struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) -{ - struct tasdevice_dspfw_hdr *fw_hdr = &tas_fmw->fw_hdr; - struct tasdevice_fw_fixed_hdr *fw_fixed_hdr = &fw_hdr->fixed_hdr; - static const unsigned char magic_number[] = {0x35, 0x35, 0x35, 0x32, }; - const unsigned char *buf = (unsigned char *)fmw->data; - - if (offset + 92 > fmw->size) { - dev_err(tas_priv->dev, "%s: File Size error\n", __func__); - offset = -EINVAL; - goto out; - } - if (memcmp(&buf[offset], magic_number, 4)) { - dev_err(tas_priv->dev, "%s: Magic num NOT match\n", __func__); - offset = -EINVAL; - goto out; - } - offset += 4; - - /* - * Convert data[offset], data[offset + 1], data[offset + 2] and - * data[offset + 3] into host - */ - fw_fixed_hdr->fwsize = get_unaligned_be32(&buf[offset]); - offset += 4; - if (fw_fixed_hdr->fwsize != fmw->size) { - dev_err(tas_priv->dev, "File size not match, %lu %u", - (unsigned long)fmw->size, fw_fixed_hdr->fwsize); - offset = -EINVAL; - goto out; - } - offset += 4; - fw_fixed_hdr->ppcver = get_unaligned_be32(&buf[offset]); - offset += 8; - fw_fixed_hdr->drv_ver = get_unaligned_be32(&buf[offset]); - offset += 72; - -out: - return offset; -} - -/* DSP firmware binary file parser function. */ -static int tasdevice_dspfw_ready(const struct firmware *fmw, void *context) -{ - struct tasdevice_priv *tas_priv = context; - struct tasdevice_fw_fixed_hdr *fw_fixed_hdr; - struct tasdevice_fw *tas_fmw; - int offset = 0, ret = 0; - - if (!fmw || !fmw->data) { - dev_err(tas_priv->dev, "%s: Failed to read firmware %s\n", - __func__, tas_priv->coef_binaryname); - return -EINVAL; - } - - tas_priv->fmw = kzalloc(sizeof(*tas_priv->fmw), GFP_KERNEL); - if (!tas_priv->fmw) - return -ENOMEM; - tas_fmw = tas_priv->fmw; - tas_fmw->dev = tas_priv->dev; - offset = fw_parse_header(tas_priv, tas_fmw, fmw, offset); - - if (offset == -EINVAL) - return -EINVAL; - - fw_fixed_hdr = &tas_fmw->fw_hdr.fixed_hdr; - /* Support different versions of firmware */ - switch (fw_fixed_hdr->drv_ver) { - case 0x301: - case 0x302: - case 0x502: - case 0x503: - tas_priv->fw_parse_variable_header = - fw_parse_variable_header_kernel; - tas_priv->fw_parse_program_data = - fw_parse_program_data_kernel; - tas_priv->fw_parse_configuration_data = - fw_parse_configuration_data_kernel; - tas_priv->tasdevice_load_block = - tasdevice_load_block_kernel; - break; - case 0x202: - case 0x400: - tas_priv->fw_parse_variable_header = - fw_parse_variable_header_git; - tas_priv->fw_parse_program_data = - fw_parse_program_data; - tas_priv->fw_parse_configuration_data = - fw_parse_configuration_data; - tas_priv->tasdevice_load_block = - tasdevice_load_block; - break; - default: - ret = dspfw_default_callback(tas_priv, - fw_fixed_hdr->drv_ver, fw_fixed_hdr->ppcver); - if (ret) - return ret; - break; - } - - offset = tas_priv->fw_parse_variable_header(tas_priv, fmw, offset); - if (offset < 0) - return offset; - - offset = tas_priv->fw_parse_program_data(tas_priv, tas_fmw, fmw, - offset); - if (offset < 0) - return offset; - - offset = tas_priv->fw_parse_configuration_data(tas_priv, - tas_fmw, fmw, offset); - if (offset < 0) - ret = offset; - - return ret; -} - -/* DSP firmware binary file parser function. */ -int tasdevice_spi_dsp_parser(void *context) -{ - struct tasdevice_priv *tas_priv = context; - const struct firmware *fw_entry; - int ret; - - ret = request_firmware(&fw_entry, tas_priv->coef_binaryname, - tas_priv->dev); - if (ret) { - dev_err(tas_priv->dev, "%s: load %s error\n", __func__, - tas_priv->coef_binaryname); - return ret; - } - - ret = tasdevice_dspfw_ready(fw_entry, tas_priv); - release_firmware(fw_entry); - fw_entry = NULL; - - return ret; -} - -/* DSP firmware program block data remove function. */ -static void tasdev_dsp_prog_blk_remove(struct tasdevice_prog *prog) -{ - struct tasdevice_data *tas_dt; - struct tasdev_blk *blk; - unsigned int i; - - if (!prog) - return; - - tas_dt = &prog->dev_data; - - if (!tas_dt->dev_blks) - return; - - for (i = 0; i < tas_dt->nr_blk; i++) { - blk = &tas_dt->dev_blks[i]; - kfree(blk->data); - } - kfree(tas_dt->dev_blks); -} - -/* DSP firmware program block data remove function. */ -static void tasdev_dsp_prog_remove(struct tasdevice_prog *prog, - unsigned short nr) -{ - int i; - - for (i = 0; i < nr; i++) - tasdev_dsp_prog_blk_remove(&prog[i]); - kfree(prog); -} - -/* DSP firmware config block data remove function. */ -static void tasdev_dsp_cfg_blk_remove(struct tasdevice_config *cfg) -{ - struct tasdevice_data *tas_dt; - struct tasdev_blk *blk; - unsigned int i; - - if (cfg) { - tas_dt = &cfg->dev_data; - - if (!tas_dt->dev_blks) - return; - - for (i = 0; i < tas_dt->nr_blk; i++) { - blk = &tas_dt->dev_blks[i]; - kfree(blk->data); - } - kfree(tas_dt->dev_blks); - } -} - -/* DSP firmware config remove function. */ -static void tasdev_dsp_cfg_remove(struct tasdevice_config *config, - unsigned short nr) -{ - int i; - - for (i = 0; i < nr; i++) - tasdev_dsp_cfg_blk_remove(&config[i]); - kfree(config); -} - -/* DSP firmware remove function. */ -void tasdevice_spi_dsp_remove(void *context) -{ - struct tasdevice_priv *tas_dev = context; - - if (!tas_dev->fmw) - return; - - if (tas_dev->fmw->programs) - tasdev_dsp_prog_remove(tas_dev->fmw->programs, - tas_dev->fmw->nr_programs); - if (tas_dev->fmw->configs) - tasdev_dsp_cfg_remove(tas_dev->fmw->configs, - tas_dev->fmw->nr_configurations); - kfree(tas_dev->fmw); - tas_dev->fmw = NULL; -} - -/* DSP firmware calibration data remove function. */ -static void tas2781_clear_calfirmware(struct tasdevice_fw *tas_fmw) -{ - struct tasdevice_calibration *calibration; - struct tasdev_blk *block; - unsigned int blks; - int i; - - if (!tas_fmw->calibrations) - goto out; - - for (i = 0; i < tas_fmw->nr_calibrations; i++) { - calibration = &tas_fmw->calibrations[i]; - if (!calibration) - continue; - - if (!calibration->dev_data.dev_blks) - continue; - - for (blks = 0; blks < calibration->dev_data.nr_blk; blks++) { - block = &calibration->dev_data.dev_blks[blks]; - if (!block) - continue; - kfree(block->data); - } - kfree(calibration->dev_data.dev_blks); - } - kfree(tas_fmw->calibrations); -out: - kfree(tas_fmw); -} - -/* Calibration data from firmware remove function. */ -void tasdevice_spi_calbin_remove(void *context) -{ - struct tasdevice_priv *tas_priv = context; - - if (tas_priv->cali_data_fmw) { - tas2781_clear_calfirmware(tas_priv->cali_data_fmw); - tas_priv->cali_data_fmw = NULL; - } -} - -/* Configuration remove function. */ -void tasdevice_spi_config_info_remove(void *context) -{ - struct tasdevice_priv *tas_priv = context; - struct tasdevice_rca *rca = &tas_priv->rcabin; - struct tasdevice_config_info **ci = rca->cfg_info; - unsigned int i, j; - - if (!ci) - return; - for (i = 0; i < rca->ncfgs; i++) { - if (!ci[i]) - continue; - if (ci[i]->blk_data) { - for (j = 0; j < ci[i]->real_nblocks; j++) { - if (!ci[i]->blk_data[j]) - continue; - kfree(ci[i]->blk_data[j]->regdata); - kfree(ci[i]->blk_data[j]); - } - kfree(ci[i]->blk_data); - } - kfree(ci[i]); - } - kfree(ci); -} - -/* DSP firmware program block data load function. */ -static int tasdevice_load_data(struct tasdevice_priv *tas_priv, - struct tasdevice_data *dev_data) -{ - struct tasdev_blk *block; - unsigned int i; - int ret = 0; - - for (i = 0; i < dev_data->nr_blk; i++) { - block = &dev_data->dev_blks[i]; - ret = tas_priv->tasdevice_load_block(tas_priv, block); - if (ret < 0) - break; - } - - return ret; -} - -/* DSP firmware program load interface function. */ -int tasdevice_spi_prmg_load(void *context, int prm_no) -{ - struct tasdevice_priv *tas_priv = context; - struct tasdevice_fw *tas_fmw = tas_priv->fmw; - struct tasdevice_prog *program; - struct tasdevice_config *conf; - int ret = 0; - - if (!tas_fmw) { - dev_err(tas_priv->dev, "%s: Firmware is NULL\n", __func__); - return -EINVAL; - } - if (prm_no >= 0 && prm_no <= tas_fmw->nr_programs) { - tas_priv->cur_conf = 0; - tas_priv->is_loading = true; - program = &tas_fmw->programs[prm_no]; - ret = tasdevice_load_data(tas_priv, &program->dev_data); - if (ret < 0) { - dev_err(tas_priv->dev, "Program failed %d.\n", ret); - return ret; - } - tas_priv->cur_prog = prm_no; - - conf = &tas_fmw->configs[tas_priv->cur_conf]; - ret = tasdevice_load_data(tas_priv, &conf->dev_data); - if (ret < 0) - dev_err(tas_priv->dev, "Config failed %d.\n", ret); - } else { - dev_err(tas_priv->dev, - "%s: prm(%d) is not in range of Programs %u\n", - __func__, prm_no, tas_fmw->nr_programs); - return -EINVAL; - } - - return ret; -} - -/* RCABIN configuration switch interface function. */ -void tasdevice_spi_tuning_switch(void *context, int state) -{ - struct tasdevice_priv *tas_priv = context; - int profile_cfg_id = tas_priv->rcabin.profile_cfg_id; - - if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) { - dev_err(tas_priv->dev, "DSP bin file not loaded\n"); - return; - } - - if (state == 0) - tasdevice_spi_select_cfg_blk(tas_priv, profile_cfg_id, - TASDEVICE_BIN_BLK_PRE_POWER_UP); - else - tasdevice_spi_select_cfg_blk(tas_priv, profile_cfg_id, - TASDEVICE_BIN_BLK_PRE_SHUTDOWN); -} 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/intel8x0.c b/sound/pci/intel8x0.c index e4bb99f71c2c..51e7f1f1a48e 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2926,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 38f8de51d641..1ce775fe8a70 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1060,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/korg1212.c b/sound/pci/korg1212/korg1212.c index 49b71082c485..56dea5b10828 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -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 { - dev_dbg(korg1212->card->dev, "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) @@ -1135,7 +1097,9 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id) 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: @@ -1535,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); @@ -1544,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); @@ -1668,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, @@ -1680,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, }; @@ -2086,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; 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_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/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/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/nm256/nm256.c b/sound/pci/nm256/nm256.c index 44085237fb44..cd4dc43dbff1 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1447,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/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/riptide/riptide.c b/sound/pci/riptide/riptide.c index 329816f37b76..578be0755b8a 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1831,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; diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index a8c2ceaadef5..4bf122abea48 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1284,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 1265a7efac60..01029843d7f3 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1575,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/hdsp.c b/sound/pci/rme9652/hdsp.c index fd3dfbad397a..873b7eadfc50 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1427,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) @@ -5277,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 f89718b19d23..64de54089955 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1978,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) @@ -6558,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 5b8dd7b0a02c..34d9c7995ddd 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -2406,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 c30eaf1038e7..808a793ff4da 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -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/trident_main.c b/sound/pci/trident/trident_main.c index 8039f445bee2..4e16b79d6584 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -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/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/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/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; |