diff options
Diffstat (limited to 'sound/pci')
74 files changed, 1526 insertions, 3773 deletions
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 65100f925b72..7e5ce96954b9 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -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/cttimer.c b/sound/pci/ctxfi/cttimer.c index 89e47fa14f70..aa179644b5c9 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -119,7 +119,7 @@ static void ct_systimer_stop(struct ct_timer_instance *ti) 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 4effcc0090ac..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; 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/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 4e0693f0ab0f..37bac890613e 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2649,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 9c427270ff4f..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 @@ -109,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 @@ -125,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 @@ -142,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 @@ -157,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 @@ -165,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 @@ -174,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 @@ -182,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 @@ -210,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 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 235d22049aa9..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; @@ -665,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; @@ -678,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); @@ -1118,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 903578466905..f57533d3d728 100644 --- a/sound/pci/hda/cs35l56_hda_spi.c +++ b/sound/pci/hda/cs35l56_hda_spi.c @@ -29,6 +29,9 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi) #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_bind.c b/sound/pci/hda/hda_bind.c index 9521e5e0e6e6..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 */ diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b436d436831b..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 */ 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_intel.c b/sound/pci/hda/hda_intel.c index 512fb22f5e5e..e6df706f740d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -240,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 */ @@ -355,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", }; @@ -1750,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; } @@ -1877,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); @@ -1974,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; @@ -2542,6 +2549,8 @@ static const struct pci_device_id azx_ids[] = { { 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 */ @@ -2782,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 }, diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 4714057dba85..68c31f5354b7 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -571,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); /* diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index a590d431c5ff..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 { @@ -187,7 +191,9 @@ static int 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) & @@ -250,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; } @@ -323,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; @@ -377,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), @@ -419,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; @@ -436,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) { @@ -450,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); @@ -520,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) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 7167989a8d86..08308231b4ed 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -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 20ab1fb2195f..cd0d7ba7320e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8029,6 +8029,7 @@ enum { 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; @@ -9301,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[]) { @@ -10456,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), diff --git a/sound/pci/hda/tas2781-spi.h b/sound/pci/hda/tas2781-spi.h deleted file mode 100644 index 7a0faceeb675..000000000000 --- a/sound/pci/hda/tas2781-spi.h +++ /dev/null @@ -1,157 +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; - - 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 29dc4f500580..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, \ - .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,170 +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) +static int tas2563_save_calibration(struct tas2781_hda *h) { - 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 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; + + cd->cali_dat_sz_per_dev = TAS2563_CAL_DATA_SIZE * TASDEV_CALIB_N; - tas_priv->cali_data.data = devm_kzalloc(tas_priv->dev, - TAS2563_CAL_ARRAY_SIZE, GFP_KERNEL); - if (!tas_priv->cali_data.data) + /* 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) -{ - struct calidata *cali_data = &tas_priv->cali_data; - struct cali_reg *r = &cali_data->cali_reg_array; - unsigned int cali_reg[CALIB_MAX] = { - 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), - }; - int i, j, rc; - int oft = 0; - __be32 data; - - if (tas_priv->dspbin_typ != TASDEV_BASIC) { - cali_reg[0] = r->r0_reg; - cali_reg[1] = r->invr0_reg; - cali_reg[2] = r->r0_low_reg; - cali_reg[3] = r->pow_reg; - cali_reg[4] = r->tlimit_reg; - } - - 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[oft]); - rc = tasdevice_dev_bulk_write(tas_priv, i, - cali_reg[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); - oft += 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"; - 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]); - - if (crc == tmp_val[21]) { - time64_t seconds = tmp_val[20]; + 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; - dev_dbg(tas_priv->dev, "%ptTsr\n", &seconds); - 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); } @@ -665,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; @@ -685,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", @@ -756,7 +475,7 @@ 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; @@ -789,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; } @@ -840,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; @@ -874,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; @@ -911,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) @@ -951,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; @@ -999,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); @@ -1045,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 25175ff4b3aa..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, \ - .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) -{ - 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) +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; - - 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,223 +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", +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, -}, -{ - .name = "Speaker Profile Id - 1", - .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; - 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; - - 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]) { - 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; + 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_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]); + 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) @@ -909,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, val; + 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); @@ -954,54 +664,38 @@ 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; tas2781_spi_reset(tas_priv); tas_priv->rcabin.profile_cfg_id = 0; tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; - ret = tasdevice_spi_dev_read(tas_priv, TAS2781_REG_CLK_CONFIG, &val); + 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_spi_prmg_load(tas_priv, 0); - if (ret < 0) { - dev_err(tas_priv->dev, "FW download failed = %d\n", ret); - 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. */ - + tas2781_save_calibration(tas_hda); out: release_firmware(fmw); pm_runtime_mark_last_busy(tas_hda->priv->dev); @@ -1048,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)); @@ -1059,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; } @@ -1070,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; @@ -1095,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); @@ -1111,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)); @@ -1125,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); @@ -1144,25 +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); - if (tas_hda->priv->playback_started) - 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; } @@ -1170,11 +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); - if (tas_hda->priv->playback_started) - 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,8 +880,9 @@ static int tas2781_system_suspend(struct device *dev) return ret; /* Shutdown chip before system suspend */ - if (tas_hda->priv->playback_started) - 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); return 0; } @@ -1198,32 +890,34 @@ static int tas2781_system_suspend(struct device *dev) 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; @@ -1260,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 d90d022d8449..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 - 2025 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_BASIC_MIN) { - p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table; - n = ARRAY_SIZE(ppc3_tas2781_mapping_table); - } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION_BASE) { - 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 & 0x3f, data, sublocksize); - break; - case TASDEVICE_CMD_BURST: - subblk_offset = tasdevice_burst_wr(tas_priv, - dev_idx & 0x3f, data, sublocksize); - break; - case TASDEVICE_CMD_DELAY: - subblk_offset = tasdevice_delay(tas_priv, - dev_idx & 0x3f, data, sublocksize); - break; - case TASDEVICE_CMD_FIELD_W: - subblk_offset = tasdevice_field_wr(tas_priv, - dev_idx & 0x3f, 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_BASE) { - 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/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_lib.c b/sound/pci/oxygen/oxygen_lib.c index 9340d3c9ffd6..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; 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 dc326face54a..873b7eadfc50 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -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 1935de046f00..64de54089955 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -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 fdb039896205..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++) 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; |