diff options
Diffstat (limited to 'sound')
133 files changed, 2345 insertions, 4850 deletions
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 84e264f335ca..693d48f08b88 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/mutex.h> +#include <linux/string.h> #include <linux/types.h> #include <linux/io.h> @@ -589,7 +590,7 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip) pcm->private_data = chip; pcm->info_flags = 0; - strcpy(pcm->name, chip->card->shortname); + strscpy(pcm->name, chip->card->shortname); chip->pcm = pcm; return 0; @@ -748,9 +749,9 @@ static int atmel_ac97c_probe(struct platform_device *pdev) spin_lock_init(&chip->lock); - strcpy(card->driver, "Atmel AC97C"); - strcpy(card->shortname, "Atmel AC97C"); - sprintf(card->longname, "Atmel AC97 controller"); + strscpy(card->driver, "Atmel AC97C"); + strscpy(card->shortname, "Atmel AC97C"); + strscpy(card->longname, "Atmel AC97 controller"); chip->card = card; chip->pclk = pclk; diff --git a/sound/core/control.c b/sound/core/control.c index 0ddade871b52..11f660fc6f2b 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1405,7 +1405,7 @@ static bool check_user_elem_overflow(struct snd_card *card, ssize_t add) static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct user_element *ue = kcontrol->private_data; + struct user_element *ue = snd_kcontrol_chip(kcontrol); unsigned int offset; offset = snd_ctl_get_ioff(kcontrol, &uinfo->id); @@ -1418,7 +1418,7 @@ static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct user_element *ue = kcontrol->private_data; + struct user_element *ue = snd_kcontrol_chip(kcontrol); const char *names; unsigned int item; unsigned int offset; @@ -1443,7 +1443,7 @@ static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol, static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct user_element *ue = kcontrol->private_data; + struct user_element *ue = snd_kcontrol_chip(kcontrol); unsigned int size = ue->elem_data_size; char *src = ue->elem_data + snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size; @@ -1456,7 +1456,7 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int err, change; - struct user_element *ue = kcontrol->private_data; + struct user_element *ue = snd_kcontrol_chip(kcontrol); unsigned int size = ue->elem_data_size; char *dst = ue->elem_data + snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size; @@ -1475,7 +1475,7 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, unsigned int size) { - struct user_element *ue = kctl->private_data; + struct user_element *ue = snd_kcontrol_chip(kctl); unsigned int *container; unsigned int mask = 0; int i; @@ -1528,7 +1528,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, static int read_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, unsigned int size) { - struct user_element *ue = kctl->private_data; + struct user_element *ue = snd_kcontrol_chip(kctl); if (ue->tlv_data_size == 0 || ue->tlv_data == NULL) return -ENXIO; @@ -1598,7 +1598,7 @@ static size_t compute_user_elem_size(size_t size, unsigned int count) static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) { - struct user_element *ue = kcontrol->private_data; + struct user_element *ue = snd_kcontrol_chip(kcontrol); // decrement the allocation size. ue->card->user_ctl_alloc_size -= compute_user_elem_size(ue->elem_data_size, kcontrol->count); diff --git a/sound/core/device.c b/sound/core/device.c index b57d80a17052..cdc5af526739 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -237,26 +237,3 @@ void snd_device_free_all(struct snd_card *card) list_for_each_entry_safe_reverse(dev, next, &card->devices, list) __snd_device_free(dev); } - -/** - * snd_device_get_state - Get the current state of the given device - * @card: the card instance - * @device_data: the data pointer to release - * - * Returns the current state of the given device object. For the valid - * device, either @SNDRV_DEV_BUILD, @SNDRV_DEV_REGISTERED or - * @SNDRV_DEV_DISCONNECTED is returned. - * Or for a non-existing device, -1 is returned as an error. - * - * Return: the current state, or -1 if not found - */ -int snd_device_get_state(struct snd_card *card, void *device_data) -{ - struct snd_device *dev; - - dev = look_for_dev(card, device_data); - if (dev) - return dev->state; - return -1; -} -EXPORT_SYMBOL_GPL(snd_device_get_state); diff --git a/sound/core/jack.c b/sound/core/jack.c index e4bcecdf89b7..850f82340278 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -575,25 +575,6 @@ EXPORT_SYMBOL(snd_jack_new); #ifdef CONFIG_SND_JACK_INPUT_DEV /** - * snd_jack_set_parent - Set the parent device for a jack - * - * @jack: The jack to configure - * @parent: The device to set as parent for the jack. - * - * Set the parent for the jack devices in the device tree. This - * function is only valid prior to registration of the jack. If no - * parent is configured then the parent device will be the sound card. - */ -void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) -{ - WARN_ON(jack->registered); - guard(mutex)(&jack->input_dev_lock); - if (jack->input_dev) - jack->input_dev->dev.parent = parent; -} -EXPORT_SYMBOL(snd_jack_set_parent); - -/** * snd_jack_set_key - Set a key mapping on a jack * * @jack: The jack to configure diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 4683b9139c56..4ecb17bd5436 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1074,8 +1074,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) runtime->oss.params = 0; runtime->oss.prepare = 1; runtime->oss.buffer_used = 0; - if (runtime->dma_area) - snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); + snd_pcm_runtime_buffer_set_silence(runtime); runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index b134a51b3fd5..72040964b6fd 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -328,27 +328,6 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); -/** - * snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel - * @substream: PCM substream - * @filter_fn: Filter function used to request the DMA channel - * @filter_data: Data passed to the DMA filter function - * - * This function will request a DMA channel using the passed filter function and - * data. The function should usually be called from the pcm open callback. Note - * that this function will use private_data field of the substream's runtime. So - * it is not available to your pcm driver implementation. - * - * Return: 0 on success, a negative error code otherwise - */ -int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, - dma_filter_fn filter_fn, void *filter_data) -{ - return snd_dmaengine_pcm_open(substream, - snd_dmaengine_pcm_request_channel(filter_fn, filter_data)); -} -EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); - int snd_dmaengine_pcm_sync_stop(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index ea3941f8666b..56725d36825b 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -458,7 +458,7 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) substream->stream, size, dmab) < 0) { kfree(dmab); - pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", + pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot allocate for size %zu\n", substream->pcm->card->number, substream->pcm->device, substream->stream ? 'c' : 'p', substream->number, substream->pcm->name, size); diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index d3a08e292072..71eec32a7a0a 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -586,33 +586,3 @@ unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a, return rates_a & rates_b; } EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect); - -/** - * snd_pcm_rate_range_to_bits - converts rate range to SNDRV_PCM_RATE_xxx bit - * @rate_min: the minimum sample rate - * @rate_max: the maximum sample rate - * - * This function has an implicit assumption: the rates in the given range have - * only the pre-defined rates like 44100 or 16000. - * - * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate range, - * or SNDRV_PCM_RATE_KNOT for an unknown range. - */ -unsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min, - unsigned int rate_max) -{ - unsigned int rates = 0; - int i; - - for (i = 0; i < snd_pcm_known_rates.count; i++) { - if (snd_pcm_known_rates.list[i] >= rate_min - && snd_pcm_known_rates.list[i] <= rate_max) - rates |= 1 << i; - } - - if (!rates) - rates = SNDRV_PCM_RATE_KNOT; - - return rates; -} -EXPORT_SYMBOL_GPL(snd_pcm_rate_range_to_bits); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 6c2b6a62d9d2..853ac5bb33ff 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -723,6 +723,17 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) atomic_inc(&runtime->buffer_accessing); } +/* fill the PCM buffer with the current silence format; called from pcm_oss.c */ +void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime) +{ + snd_pcm_buffer_access_lock(runtime); + if (runtime->dma_area) + snd_pcm_format_set_silence(runtime->format, runtime->dma_area, + bytes_to_samples(runtime, runtime->dma_bytes)); + snd_pcm_buffer_access_unlock(runtime); +} +EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence); + #if IS_ENABLED(CONFIG_SND_PCM_OSS) #define is_oss_stream(substream) ((substream)->oss.oss) #else diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 5df26788dda4..10add922323d 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -564,22 +564,6 @@ void snd_seq_queue_client_leave(int client) /*----------------------------------------------------------------*/ -/* remove cells from all queues */ -void snd_seq_queue_client_leave_cells(int client) -{ - int i; - struct snd_seq_queue *q; - - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - q = queueptr(i); - if (!q) - continue; - snd_seq_prioq_leave(q->tickq, client, 0); - snd_seq_prioq_leave(q->timeq, client, 0); - queuefree(q); - } -} - /* remove cells based on flush criteria */ void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info) { diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h index 74cc31aacdac..b81379c9af43 100644 --- a/sound/core/seq/seq_queue.h +++ b/sound/core/seq/seq_queue.h @@ -66,7 +66,6 @@ void snd_seq_queue_client_leave(int client); int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop); /* Remove events */ -void snd_seq_queue_client_leave_cells(int client); void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info); /* return pointer to queue structure for specified id */ diff --git a/sound/core/seq_device.c b/sound/core/seq_device.c index 4492be5d2317..bac9f8603734 100644 --- a/sound/core/seq_device.c +++ b/sound/core/seq_device.c @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL"); static int snd_seq_bus_match(struct device *dev, const struct device_driver *drv) { struct snd_seq_device *sdev = to_seq_dev(dev); - struct snd_seq_driver *sdrv = to_seq_drv(drv); + const struct snd_seq_driver *sdrv = to_seq_drv(drv); return strcmp(sdrv->id, sdev->id) == 0 && sdrv->argsize == sdev->argsize; diff --git a/sound/hda/hda_bus_type.c b/sound/hda/hda_bus_type.c index 7545ace7b0ee..eb72a7af2e56 100644 --- a/sound/hda/hda_bus_type.c +++ b/sound/hda/hda_bus_type.c @@ -21,7 +21,7 @@ MODULE_LICENSE("GPL"); * driver id_table and returns the matching device id entry. */ const struct hda_device_id * -hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv) +hdac_get_device_id(struct hdac_device *hdev, const struct hdac_driver *drv) { if (drv->id_table) { const struct hda_device_id *id = drv->id_table; @@ -38,7 +38,7 @@ hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv) } EXPORT_SYMBOL_GPL(hdac_get_device_id); -static int hdac_codec_match(struct hdac_device *dev, struct hdac_driver *drv) +static int hdac_codec_match(struct hdac_device *dev, const struct hdac_driver *drv) { if (hdac_get_device_id(dev, drv)) return 1; @@ -49,7 +49,7 @@ static int hdac_codec_match(struct hdac_device *dev, struct hdac_driver *drv) static int hda_bus_match(struct device *dev, const struct device_driver *drv) { struct hdac_device *hdev = dev_to_hdac_dev(dev); - struct hdac_driver *hdrv = drv_to_hdac_driver(drv); + const struct hdac_driver *hdrv = drv_to_hdac_driver(drv); if (hdev->type != hdrv->type) return 0; diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 4e85a838ad7e..e7f6208af5b0 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -826,25 +826,6 @@ int snd_hdac_stream_set_spib(struct hdac_bus *bus, EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib); /** - * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream - * @bus: HD-audio core bus - * @azx_dev: hdac_stream - * - * Return maxfifo for the stream - */ -int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus, - struct hdac_stream *azx_dev) -{ - if (!bus->spbcap) { - dev_err(bus->dev, "Address of SPB capability is NULL\n"); - return -EINVAL; - } - - return readl(azx_dev->fifo_addr); -} -EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo); - -/** * snd_hdac_stream_drsm_enable - enable DMA resume for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable DRSM diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 01594f858129..3cb1e7fc3b3b 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -541,7 +541,7 @@ static const struct config_entry config_table[] = { }, #endif - /* Panther Lake */ + /* Panther Lake, Wildcat Lake */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_PANTHERLAKE) { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, @@ -551,6 +551,10 @@ static const struct config_entry config_table[] = { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = PCI_DEVICE_ID_INTEL_HDA_PTL_H, }, + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_WCL, + }, #endif diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 088cff799e0b..6d72a871bda0 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -350,8 +350,11 @@ int intel_nhlt_ssp_device_type(struct device *dev, struct nhlt_acpi_table *nhlt, struct nhlt_endpoint *epnt; int i; - if (!nhlt) + if (!nhlt) { + dev_err(dev, "%s: NHLT table is missing (query for SSP%d)\n", + __func__, virtual_bus_id); return -EINVAL; + } epnt = (struct nhlt_endpoint *)nhlt->desc; for (i = 0; i < nhlt->endpoint_count; i++) { @@ -366,6 +369,20 @@ int intel_nhlt_ssp_device_type(struct device *dev, struct nhlt_acpi_table *nhlt, epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); } + dev_err(dev, "%s: No match for SSP%d in NHLT table\n", __func__, + virtual_bus_id); + + dev_dbg(dev, "Available endpoints:\n"); + epnt = (struct nhlt_endpoint *)nhlt->desc; + for (i = 0; i < nhlt->endpoint_count; i++) { + dev_dbg(dev, + "%d: link_type: %d, vbus_id: %d, dir: %d, dev_type: %d\n", + i, epnt->linktype, epnt->virtual_bus_id, + epnt->direction, epnt->device_type); + + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + return -EINVAL; } EXPORT_SYMBOL(intel_nhlt_ssp_device_type); diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c index ba38c285241c..0fbac827124b 100644 --- a/sound/i2c/other/pt2258.c +++ b/sound/i2c/other/pt2258.c @@ -80,7 +80,7 @@ static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol, static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_pt2258 *pt = kcontrol->private_data; + struct snd_pt2258 *pt = snd_kcontrol_chip(kcontrol); int base = kcontrol->private_value; /* chip does not support register reads */ @@ -92,7 +92,7 @@ static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol, static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_pt2258 *pt = kcontrol->private_data; + struct snd_pt2258 *pt = snd_kcontrol_chip(kcontrol); int base = kcontrol->private_value; unsigned char bytes[2]; int val0, val1; @@ -133,7 +133,7 @@ static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol, static int pt2258_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_pt2258 *pt = kcontrol->private_data; + struct snd_pt2258 *pt = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = !pt->mute; return 0; @@ -142,7 +142,7 @@ static int pt2258_switch_get(struct snd_kcontrol *kcontrol, static int pt2258_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_pt2258 *pt = kcontrol->private_data; + struct snd_pt2258 *pt = snd_kcontrol_chip(kcontrol); unsigned char bytes[2]; int val; diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c index 1dc9e0edb3d9..f167eb8d516b 100644 --- a/sound/isa/gus/gus_io.c +++ b/sound/isa/gus/gus_io.c @@ -228,49 +228,6 @@ unsigned short snd_gf1_i_look16(struct snd_gus_card * gus, unsigned char reg) return res; } -#if 0 - -void snd_gf1_i_adlib_write(struct snd_gus_card * gus, - unsigned char reg, - unsigned char data) -{ - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); - __snd_gf1_adlib_write(gus, reg, data); - spin_unlock_irqrestore(&gus->reg_lock, flags); -} - -void snd_gf1_i_write_addr(struct snd_gus_card * gus, unsigned char reg, - unsigned int addr, short w_16bit) -{ - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); - __snd_gf1_write_addr(gus, reg, addr, w_16bit); - spin_unlock_irqrestore(&gus->reg_lock, flags); -} - -#endif /* 0 */ - -#ifdef CONFIG_SND_DEBUG -static unsigned int snd_gf1_i_read_addr(struct snd_gus_card * gus, - unsigned char reg, short w_16bit) -{ - unsigned int res; - unsigned long flags; - - spin_lock_irqsave(&gus->reg_lock, flags); - res = __snd_gf1_read_addr(gus, reg, w_16bit); - spin_unlock_irqrestore(&gus->reg_lock, flags); - return res; -} -#endif - -/* - - */ - void snd_gf1_dram_addr(struct snd_gus_card * gus, unsigned int addr) { outb(0x43, gus->gf1.reg_regsel); @@ -418,189 +375,3 @@ void snd_gf1_select_active_voices(struct snd_gus_card * gus) udelay(100); } } - -#ifdef CONFIG_SND_DEBUG - -void snd_gf1_print_voice_registers(struct snd_gus_card * gus) -{ - unsigned char mode; - int voice, ctrl; - - voice = gus->gf1.active_voice; - dev_info(gus->card->dev, - " -%i- GF1 voice ctrl, ramp ctrl = 0x%x, 0x%x\n", - voice, ctrl = snd_gf1_i_read8(gus, 0), snd_gf1_i_read8(gus, 0x0d)); - dev_info(gus->card->dev, - " -%i- GF1 frequency = 0x%x\n", - voice, snd_gf1_i_read16(gus, 1)); - dev_info(gus->card->dev, - " -%i- GF1 loop start, end = 0x%x (0x%x), 0x%x (0x%x)\n", - voice, snd_gf1_i_read_addr(gus, 2, ctrl & 4), - snd_gf1_i_read_addr(gus, 2, (ctrl & 4) ^ 4), - snd_gf1_i_read_addr(gus, 4, ctrl & 4), - snd_gf1_i_read_addr(gus, 4, (ctrl & 4) ^ 4)); - dev_info(gus->card->dev, - " -%i- GF1 ramp start, end, rate = 0x%x, 0x%x, 0x%x\n", - voice, snd_gf1_i_read8(gus, 7), snd_gf1_i_read8(gus, 8), - snd_gf1_i_read8(gus, 6)); - dev_info(gus->card->dev, - " -%i- GF1 volume = 0x%x\n", - voice, snd_gf1_i_read16(gus, 9)); - dev_info(gus->card->dev, - " -%i- GF1 position = 0x%x (0x%x)\n", - voice, snd_gf1_i_read_addr(gus, 0x0a, ctrl & 4), - snd_gf1_i_read_addr(gus, 0x0a, (ctrl & 4) ^ 4)); - if (gus->interwave && snd_gf1_i_read8(gus, 0x19) & 0x01) { /* enhanced mode */ - mode = snd_gf1_i_read8(gus, 0x15); - dev_info(gus->card->dev, - " -%i- GFA1 mode = 0x%x\n", - voice, mode); - if (mode & 0x01) { /* Effect processor */ - dev_info(gus->card->dev, - " -%i- GFA1 effect address = 0x%x\n", - voice, snd_gf1_i_read_addr(gus, 0x11, ctrl & 4)); - dev_info(gus->card->dev, - " -%i- GFA1 effect volume = 0x%x\n", - voice, snd_gf1_i_read16(gus, 0x16)); - dev_info(gus->card->dev, - " -%i- GFA1 effect volume final = 0x%x\n", - voice, snd_gf1_i_read16(gus, 0x1d)); - dev_info(gus->card->dev, - " -%i- GFA1 effect accumulator = 0x%x\n", - voice, snd_gf1_i_read8(gus, 0x14)); - } - if (mode & 0x20) { - dev_info(gus->card->dev, - " -%i- GFA1 left offset = 0x%x (%i)\n", - voice, snd_gf1_i_read16(gus, 0x13), - snd_gf1_i_read16(gus, 0x13) >> 4); - dev_info(gus->card->dev, - " -%i- GFA1 left offset final = 0x%x (%i)\n", - voice, snd_gf1_i_read16(gus, 0x1c), - snd_gf1_i_read16(gus, 0x1c) >> 4); - dev_info(gus->card->dev, - " -%i- GFA1 right offset = 0x%x (%i)\n", - voice, snd_gf1_i_read16(gus, 0x0c), - snd_gf1_i_read16(gus, 0x0c) >> 4); - dev_info(gus->card->dev, - " -%i- GFA1 right offset final = 0x%x (%i)\n", - voice, snd_gf1_i_read16(gus, 0x1b), - snd_gf1_i_read16(gus, 0x1b) >> 4); - } else - dev_info(gus->card->dev, - " -%i- GF1 pan = 0x%x\n", - voice, snd_gf1_i_read8(gus, 0x0c)); - } else - dev_info(gus->card->dev, - " -%i- GF1 pan = 0x%x\n", - voice, snd_gf1_i_read8(gus, 0x0c)); -} - -#if 0 - -void snd_gf1_print_global_registers(struct snd_gus_card * gus) -{ - unsigned char global_mode = 0x00; - - dev_info(gus->card->dev, - " -G- GF1 active voices = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_ACTIVE_VOICES)); - if (gus->interwave) { - global_mode = snd_gf1_i_read8(gus, SNDRV_GF1_GB_GLOBAL_MODE); - dev_info(gus->card->dev, - " -G- GF1 global mode = 0x%x\n", - global_mode); - } - if (global_mode & 0x02) /* LFO enabled? */ - dev_info(gus->card->dev, - " -G- GF1 LFO base = 0x%x\n", - snd_gf1_i_look16(gus, SNDRV_GF1_GW_LFO_BASE)); - dev_info(gus->card->dev, - " -G- GF1 voices IRQ read = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_VOICES_IRQ_READ)); - dev_info(gus->card->dev, - " -G- GF1 DRAM DMA control = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL)); - dev_info(gus->card->dev, - " -G- GF1 DRAM DMA high/low = 0x%x/0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH), - snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW)); - dev_info(gus->card->dev, - " -G- GF1 DRAM IO high/low = 0x%x/0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_IO_HIGH), - snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_IO_LOW)); - if (!gus->interwave) - dev_info(gus->card->dev, - " -G- GF1 record DMA control = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL)); - dev_info(gus->card->dev, - " -G- GF1 DRAM IO 16 = 0x%x\n", - snd_gf1_i_look16(gus, SNDRV_GF1_GW_DRAM_IO16)); - if (gus->gf1.enh_mode) { - dev_info(gus->card->dev, - " -G- GFA1 memory config = 0x%x\n", - snd_gf1_i_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG)); - dev_info(gus->card->dev, - " -G- GFA1 memory control = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_MEMORY_CONTROL)); - dev_info(gus->card->dev, - " -G- GFA1 FIFO record base = 0x%x\n", - snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_RECORD_BASE_ADDR)); - dev_info(gus->card->dev, - " -G- GFA1 FIFO playback base = 0x%x\n", - snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_PLAY_BASE_ADDR)); - dev_info(gus->card->dev, - " -G- GFA1 interleave control = 0x%x\n", - snd_gf1_i_look16(gus, SNDRV_GF1_GW_INTERLEAVE)); - } -} - -void snd_gf1_print_setup_registers(struct snd_gus_card * gus) -{ - dev_info(gus->card->dev, - " -S- mix control = 0x%x\n", - inb(GUSP(gus, MIXCNTRLREG))); - dev_info(gus->card->dev, - " -S- IRQ status = 0x%x\n", - inb(GUSP(gus, IRQSTAT))); - dev_info(gus->card->dev, - " -S- timer control = 0x%x\n", - inb(GUSP(gus, TIMERCNTRL))); - dev_info(gus->card->dev, - " -S- timer data = 0x%x\n", - inb(GUSP(gus, TIMERDATA))); - dev_info(gus->card->dev, - " -S- status read = 0x%x\n", - inb(GUSP(gus, REGCNTRLS))); - dev_info(gus->card->dev, - " -S- Sound Blaster control = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL)); - dev_info(gus->card->dev, - " -S- AdLib timer 1/2 = 0x%x/0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1), - snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2)); - dev_info(gus->card->dev, - " -S- reset = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)); - if (gus->interwave) { - dev_info(gus->card->dev, - " -S- compatibility = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_COMPATIBILITY)); - dev_info(gus->card->dev, - " -S- decode control = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_DECODE_CONTROL)); - dev_info(gus->card->dev, - " -S- version number = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER)); - dev_info(gus->card->dev, - " -S- MPU-401 emul. control A/B = 0x%x/0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A), - snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B)); - dev_info(gus->card->dev, - " -S- emulation IRQ = 0x%x\n", - snd_gf1_i_look8(gus, SNDRV_GF1_GB_EMULATION_IRQ)); - } -} -#endif /* 0 */ - -#endif diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 51ce405eba7a..7166869e423d 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -22,18 +22,6 @@ MODULE_LICENSE("GPL"); static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches); -int snd_gus_use_inc(struct snd_gus_card * gus) -{ - if (!try_module_get(gus->card->module)) - return 0; - return 1; -} - -void snd_gus_use_dec(struct snd_gus_card * gus) -{ - module_put(gus->card->module); -} - static int snd_gus_joystick_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -443,8 +431,6 @@ EXPORT_SYMBOL(snd_gf1_new_mixer); /* gus_pcm.c */ EXPORT_SYMBOL(snd_gf1_pcm_new); /* gus.c */ -EXPORT_SYMBOL(snd_gus_use_inc); -EXPORT_SYMBOL(snd_gus_use_dec); EXPORT_SYMBOL(snd_gus_create); EXPORT_SYMBOL(snd_gus_initialize); /* gus_irq.c */ diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c index ac5da1281042..326bc6028885 100644 --- a/sound/isa/gus/gus_reset.c +++ b/sound/isa/gus/gus_reset.c @@ -141,10 +141,6 @@ void snd_gf1_stop_voice(struct snd_gus_card * gus, unsigned short voice) if (gus->gf1.enh_mode) snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, 0); spin_unlock_irqrestore(&gus->reg_lock, flags); -#if 0 - snd_gf1_lfo_shutdown(gus, voice, ULTRA_LFO_VIBRATO); - snd_gf1_lfo_shutdown(gus, voice, ULTRA_LFO_TREMOLO); -#endif } static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min, @@ -182,10 +178,6 @@ static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, 0); } spin_unlock_irqrestore(&gus->reg_lock, flags); -#if 0 - snd_gf1_lfo_shutdown(gus, i, ULTRA_LFO_VIBRATO); - snd_gf1_lfo_shutdown(gus, i, ULTRA_LFO_TREMOLO); -#endif } } @@ -335,9 +327,7 @@ int snd_gf1_start(struct snd_gus_card * gus) } else { gus->gf1.sw_lfo = 1; } -#if 0 - snd_gf1_lfo_init(gus); -#endif + if (gus->gf1.memory > 0) for (i = 0; i < 4; i++) snd_gf1_poke(gus, gus->gf1.default_voice_address + i, 0); @@ -391,8 +381,6 @@ int snd_gf1_stop(struct snd_gus_card * gus) snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* disable IRQ & DAC */ snd_gf1_timers_done(gus); snd_gf1_mem_done(gus); -#if 0 - snd_gf1_lfo_done(gus); -#endif + return 0; } diff --git a/sound/isa/msnd/Makefile b/sound/isa/msnd/Makefile index 5f8d6b472722..d56412aae857 100644 --- a/sound/isa/msnd/Makefile +++ b/sound/isa/msnd/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -snd-msnd-lib-y := msnd.o msnd_midi.o msnd_pinnacle_mixer.o +snd-msnd-lib-y := msnd.o msnd_pinnacle_mixer.o snd-msnd-pinnacle-y := msnd_pinnacle.o snd-msnd-classic-y := msnd_classic.o diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h index 533d71cee9ba..3d7810ed9186 100644 --- a/sound/isa/msnd/msnd.h +++ b/sound/isa/msnd/msnd.h @@ -216,7 +216,6 @@ struct snd_msnd { int captureLimit; int capturePeriods; struct snd_card *card; - void *msndmidi_mpu; struct snd_rawmidi *rmidi; /* Hardware resources */ @@ -286,9 +285,6 @@ int snd_msnd_DAPQ(struct snd_msnd *chip, int start); int snd_msnd_DARQ(struct snd_msnd *chip, int start); int snd_msnd_pcm(struct snd_card *card, int device); -int snd_msndmidi_new(struct snd_card *card, int device); -void snd_msndmidi_input_read(void *mpu); - void snd_msndmix_setup(struct snd_msnd *chip); int snd_msndmix_new(struct snd_card *card); int snd_msndmix_force_recsrc(struct snd_msnd *chip, int recsrc); diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c deleted file mode 100644 index 3ffc8758bec2..000000000000 --- a/sound/isa/msnd/msnd_midi.c +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * Copyright (c) 2009 by Krzysztof Helt - * Routines for control of MPU-401 in UART mode - * - * MPU-401 supports UART mode which is not capable generate transmit - * interrupts thus output is done via polling. Also, if irq < 0, then - * input is done also via polling. Do not expect good performance. - */ - -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/errno.h> -#include <linux/export.h> -#include <sound/core.h> -#include <sound/rawmidi.h> - -#include "msnd.h" - -#define MSNDMIDI_MODE_BIT_INPUT 0 -#define MSNDMIDI_MODE_BIT_OUTPUT 1 -#define MSNDMIDI_MODE_BIT_INPUT_TRIGGER 2 -#define MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER 3 - -struct snd_msndmidi { - struct snd_msnd *dev; - - unsigned long mode; /* MSNDMIDI_MODE_XXXX */ - - struct snd_rawmidi_substream *substream_input; - - spinlock_t input_lock; -}; - -/* - * input/output open/close - protected by open_mutex in rawmidi.c - */ -static int snd_msndmidi_input_open(struct snd_rawmidi_substream *substream) -{ - struct snd_msndmidi *mpu; - - mpu = substream->rmidi->private_data; - - mpu->substream_input = substream; - - snd_msnd_enable_irq(mpu->dev); - - snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_START); - set_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode); - return 0; -} - -static int snd_msndmidi_input_close(struct snd_rawmidi_substream *substream) -{ - struct snd_msndmidi *mpu; - - mpu = substream->rmidi->private_data; - snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_STOP); - clear_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode); - mpu->substream_input = NULL; - snd_msnd_disable_irq(mpu->dev); - return 0; -} - -static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu) -{ - u16 tail; - - tail = readw(mpu->dev->MIDQ + JQS_wTail); - writew(tail, mpu->dev->MIDQ + JQS_wHead); -} - -/* - * trigger input - */ -static void snd_msndmidi_input_trigger(struct snd_rawmidi_substream *substream, - int up) -{ - unsigned long flags; - struct snd_msndmidi *mpu; - - mpu = substream->rmidi->private_data; - spin_lock_irqsave(&mpu->input_lock, flags); - if (up) { - if (!test_and_set_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, - &mpu->mode)) - snd_msndmidi_input_drop(mpu); - } else { - clear_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode); - } - spin_unlock_irqrestore(&mpu->input_lock, flags); - if (up) - snd_msndmidi_input_read(mpu); -} - -void snd_msndmidi_input_read(void *mpuv) -{ - unsigned long flags; - struct snd_msndmidi *mpu = mpuv; - void __iomem *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF; - u16 head, tail, size; - - spin_lock_irqsave(&mpu->input_lock, flags); - head = readw(mpu->dev->MIDQ + JQS_wHead); - tail = readw(mpu->dev->MIDQ + JQS_wTail); - size = readw(mpu->dev->MIDQ + JQS_wSize); - if (head > size || tail > size) - goto out; - while (head != tail) { - unsigned char val = readw(pwMIDQData + 2 * head); - - if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) - snd_rawmidi_receive(mpu->substream_input, &val, 1); - if (++head > size) - head = 0; - writew(head, mpu->dev->MIDQ + JQS_wHead); - } - out: - spin_unlock_irqrestore(&mpu->input_lock, flags); -} -EXPORT_SYMBOL(snd_msndmidi_input_read); - -static const struct snd_rawmidi_ops snd_msndmidi_input = { - .open = snd_msndmidi_input_open, - .close = snd_msndmidi_input_close, - .trigger = snd_msndmidi_input_trigger, -}; - -static void snd_msndmidi_free(struct snd_rawmidi *rmidi) -{ - struct snd_msndmidi *mpu = rmidi->private_data; - kfree(mpu); -} - -int snd_msndmidi_new(struct snd_card *card, int device) -{ - struct snd_msnd *chip = card->private_data; - struct snd_msndmidi *mpu; - struct snd_rawmidi *rmidi; - int err; - - err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi); - if (err < 0) - return err; - mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); - if (mpu == NULL) { - snd_device_free(card, rmidi); - return -ENOMEM; - } - mpu->dev = chip; - chip->msndmidi_mpu = mpu; - rmidi->private_data = mpu; - rmidi->private_free = snd_msndmidi_free; - spin_lock_init(&mpu->input_lock); - strcpy(rmidi->name, "MSND MIDI"); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, - &snd_msndmidi_input); - rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; - return 0; -} diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 635403301a15..8caf431677e5 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -142,11 +142,6 @@ static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage) } break; - case HIMT_MIDI_IN_UCHAR: - if (chip->msndmidi_mpu) - snd_msndmidi_input_read(chip->msndmidi_mpu); - break; - default: dev_dbg(chip->card->dev, LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage)); diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 52884e6b9193..312b217491d4 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -14,6 +14,7 @@ #include <linux/export.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/string.h> #include <sound/core.h> #include <sound/emu8000.h> #include <sound/emu8000_reg.h> @@ -1096,7 +1097,7 @@ snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, #if IS_ENABLED(CONFIG_SND_SEQUENCER) if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000, sizeof(struct snd_emu8000*), &awe) >= 0) { - strcpy(awe->name, "EMU-8000"); + strscpy(awe->name, "EMU-8000"); *(struct snd_emu8000 **)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw; } #else diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index b28490973892..69d9bfb6c14c 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/io.h> #include <linux/delay.h> +#include <linux/string.h> #include <asm/dma.h> #include <linux/isa.h> #include <sound/core.h> @@ -286,8 +287,8 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev) jazz16->chip = chip; - strcpy(card->driver, "jazz16"); - strcpy(card->shortname, "Media Vision Jazz16"); + strscpy(card->driver, "jazz16"); + strscpy(card->shortname, "Media Vision Jazz16"); sprintf(card->longname, "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d", port[dev], xirq, xdma8, xdma16); diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 2f7505ad855c..752762117338 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -10,6 +10,7 @@ #include <linux/err.h> #include <linux/isa.h> #include <linux/module.h> +#include <linux/string.h> #include <sound/core.h> #include <sound/sb.h> #include <sound/sb16_csp.h> @@ -337,12 +338,12 @@ static int snd_sb16_probe(struct snd_card *card, int dev) if (err < 0) return err; - strcpy(card->driver, + strscpy(card->driver, #ifdef SNDRV_SBAWE_EMU8000 awe_port[dev] > 0 ? "SB AWE" : #endif "SB16"); - strcpy(card->shortname, chip->name); + strscpy(card->shortname, chip->name); sprintf(card->longname, "%s at 0x%lx, irq %i, dma ", chip->name, chip->port, diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 8726778c815e..6d5131265913 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -9,6 +9,7 @@ #include <linux/isa.h> #include <linux/ioport.h> #include <linux/module.h> +#include <linux/string.h> #include <sound/core.h> #include <sound/sb.h> #include <sound/opl3.h> @@ -162,8 +163,8 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) if (err < 0) return err; - strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8"); - strcpy(card->shortname, chip->name); + strscpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8"); + strscpy(card->shortname, chip->name); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", chip->name, chip->port, diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index d2908fc280f8..57867e51d367 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -14,6 +14,7 @@ */ #include <linux/io.h> +#include <linux/string.h> #include <linux/time.h> #include <sound/core.h> #include <sound/sb.h> @@ -254,7 +255,7 @@ int snd_sb8dsp_midi(struct snd_sb *chip, int device) err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, "SB8 MIDI"); + strscpy(rmidi->name, "SB8 MIDI"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_sb8dsp_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_sb8dsp_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT; diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 9d23b7a4570b..b2709ed134b4 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -6,6 +6,7 @@ #include <linux/io.h> #include <linux/delay.h> +#include <linux/string.h> #include <linux/time.h> #include <sound/core.h> #include <sound/sb.h> @@ -718,7 +719,7 @@ static int snd_sbmixer_init(struct snd_sb *chip, return err; } snd_component_add(card, name); - strcpy(card->mixername, name); + strscpy(card->mixername, name); return 0; } @@ -799,7 +800,7 @@ int snd_sbmixer_new(struct snd_sb *chip) return err; break; default: - strcpy(card->mixername, "???"); + strscpy(card->mixername, "???"); } return 0; } diff --git a/sound/mips/snd-n64.c b/sound/mips/snd-n64.c index bff6d85b8fe2..e1b2ff65d850 100644 --- a/sound/mips/snd-n64.c +++ b/sound/mips/snd-n64.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/spinlock.h> +#include <linux/string.h> #include <sound/control.h> #include <sound/core.h> @@ -327,14 +328,14 @@ static int __init n64audio_probe(struct platform_device *pdev) goto fail_dma_alloc; pcm->private_data = priv; - strcpy(pcm->name, "N64 Audio"); + strscpy(pcm->name, "N64 Audio"); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &n64audio_pcm_ops); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, card->dev, 0, 0); - strcpy(card->driver, "N64 Audio"); - strcpy(card->shortname, "N64 Audio"); - strcpy(card->longname, "N64 Audio"); + strscpy(card->driver, "N64 Audio"); + strscpy(card->shortname, "N64 Audio"); + strscpy(card->longname, "N64 Audio"); irq = platform_get_irq(pdev, 0); if (irq < 0) { 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/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 08b0bde1a461..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; }; @@ -104,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, }; @@ -112,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, @@ -192,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; @@ -235,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) @@ -258,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"); + 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_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; - } - - 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 }, @@ -357,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..d5bc81099d0d 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"); @@ -1577,7 +1603,7 @@ static const struct regmap_irq cs35l41_reg_irqs[] = { CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR), }; -static struct regmap_irq_chip cs35l41_regmap_irq_chip = { +static const struct regmap_irq_chip cs35l41_regmap_irq_chip = { .name = "cs35l41 IRQ1 Controller", .status_base = CS35L41_IRQ1_STATUS1, .mask_base = CS35L41_IRQ1_MASK1, @@ -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 aed7d7284231..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" /* @@ -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,7 +230,7 @@ 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; @@ -250,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; @@ -297,7 +296,7 @@ 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; @@ -323,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; @@ -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/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..df8f88beddd0 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -18,10 +18,10 @@ /* * find a matching codec id */ -static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv) +static int hda_codec_match(struct hdac_device *dev, const struct hdac_driver *drv) { struct hda_codec *codec = container_of(dev, struct hda_codec, core); - struct hda_codec_driver *driver = + const struct hda_codec_driver *driver = container_of(drv, struct hda_codec_driver, core); const struct hda_device_id *list; /* check probe_id instead of vendor_id if set */ @@ -44,7 +44,7 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) struct hda_codec *codec = container_of(dev, struct hda_codec, core); /* ignore unsol events during shutdown */ - if (codec->bus->shutdown) + if (codec->card->shutdown || codec->bus->shutdown) return; /* ignore unsol events during system suspend/resume */ 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..e5210ed48ddf 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 */ @@ -2715,6 +2724,9 @@ static const struct pci_device_id azx_ids[] = { { PCI_VDEVICE(ATI, 0xab38), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | AZX_DCAPS_PM_RUNTIME }, + { PCI_VDEVICE(ATI, 0xab40), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, /* GLENFLY */ { PCI_DEVICE(PCI_VENDOR_ID_GLENFLY, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, @@ -2782,6 +2794,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 8a2b09e4a7d5..cd0d7ba7320e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6830,7 +6830,10 @@ static void alc256_fixup_chromebook(struct hda_codec *codec, switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: - spec->gen.suppress_auto_mute = 1; + if (codec->core.subsystem_id == 0x10280d76) + spec->gen.suppress_auto_mute = 0; + else + spec->gen.suppress_auto_mute = 1; spec->gen.suppress_auto_mic = 1; spec->en_3kpull_low = false; break; @@ -8026,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; @@ -9298,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[]) { @@ -10453,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), @@ -10882,9 +10895,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), SND_PCI_QUIRK(0x103c, 0x8e1b, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), SND_PCI_QUIRK(0x103c, 0x8e1c, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A), + SND_PCI_QUIRK(0x103c, 0x8e1d, "HP ZBook X Gli 16 G12", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8e2c, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8e36, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8e37, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e3a, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e3b, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), @@ -11300,6 +11316,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), + SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC), SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TAS2781_I2C), 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; diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 5a93f4587356..f88331a48638 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -469,8 +469,8 @@ static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol, static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_card_aica *dreamcastcard; - dreamcastcard = kcontrol->private_data; + struct snd_card_aica *dreamcastcard = snd_kcontrol_chip(kcontrol); + if (unlikely(!dreamcastcard->channel)) return -ETXTBSY; /* we've not yet been set up */ ucontrol->value.integer.value[0] = dreamcastcard->channel->vol; @@ -480,9 +480,9 @@ static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol, static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_card_aica *dreamcastcard; + struct snd_card_aica *dreamcastcard = snd_kcontrol_chip(kcontrol); unsigned int vol; - dreamcastcard = kcontrol->private_data; + if (unlikely(!dreamcastcard->channel)) return -ETXTBSY; vol = ucontrol->value.integer.value[0]; diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index b4f4696809dd..5dd24ab90d0f 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -464,6 +464,28 @@ err: return -EINVAL; } +static int mca_fe_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + unsigned int mask, nchannels; + + if (cl->tdm_slots) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + mask = cl->tdm_tx_mask; + else + mask = cl->tdm_rx_mask; + + nchannels = hweight32(mask); + } else { + nchannels = 2; + } + + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + 1, nchannels); +} + static int mca_fe_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { @@ -680,6 +702,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops mca_fe_ops = { + .startup = mca_fe_startup, .set_fmt = mca_fe_set_fmt, .set_bclk_ratio = mca_set_bclk_ratio, .set_tdm_slot = mca_fe_set_tdm_slot, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 477d33234fdd..126f897312d4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -264,6 +264,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TAS2770 imply SND_SOC_TAS2780 imply SND_SOC_TAS2781_COMLIB + imply SND_SOC_TAS2781_COMLIB_I2C imply SND_SOC_TAS2781_FMWLIB imply SND_SOC_TAS2781_I2C imply SND_SOC_TAS5086 @@ -2025,20 +2026,24 @@ config SND_SOC_TAS2780 digital input mono Class-D audio power amplifiers. config SND_SOC_TAS2781_COMLIB + tristate + +config SND_SOC_TAS2781_COMLIB_I2C depends on I2C select CRC8 select REGMAP_I2C tristate config SND_SOC_TAS2781_FMWLIB - depends on SND_SOC_TAS2781_COMLIB + select SND_SOC_TAS2781_COMLIB + select CRC8 tristate default n config SND_SOC_TAS2781_I2C tristate "Texas Instruments TAS2781 speaker amplifier based on I2C" depends on I2C - select SND_SOC_TAS2781_COMLIB + select SND_SOC_TAS2781_COMLIB_I2C select SND_SOC_TAS2781_FMWLIB help Enable support for Texas Instruments TAS2781 Smart Amplifier diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 66e2f2381d40..6d7aa109ede7 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -310,6 +310,7 @@ snd-soc-tas6424-y := tas6424.o snd-soc-tda7419-y := tda7419.o snd-soc-tas2770-y := tas2770.o snd-soc-tas2781-comlib-y := tas2781-comlib.o +snd-soc-tas2781-comlib-i2c-y := tas2781-comlib-i2c.o snd-soc-tas2781-fmwlib-y := tas2781-fmwlib.o snd-soc-tas2781-i2c-y := tas2781-i2c.o snd-soc-tfa9879-y := tfa9879.o @@ -723,6 +724,7 @@ obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.o obj-$(CONFIG_SND_SOC_TAS2780) += snd-soc-tas2780.o obj-$(CONFIG_SND_SOC_TAS2781_COMLIB) += snd-soc-tas2781-comlib.o +obj-$(CONFIG_SND_SOC_TAS2781_COMLIB_I2C) += snd-soc-tas2781-comlib-i2c.o obj-$(CONFIG_SND_SOC_TAS2781_FMWLIB) += snd-soc-tas2781-fmwlib.o obj-$(CONFIG_SND_SOC_TAS2781_I2C) += snd-soc-tas2781-i2c.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c new file mode 100644 index 000000000000..c078bb0a8437 --- /dev/null +++ b/sound/soc/codecs/tas2781-comlib-i2c.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers based on I2C +// +// Copyright 2025 Texas Instruments, Inc. +// +// Author: Shenghao Ding <shenghao-ding@ti.com> + +#include <linux/crc8.h> +#include <linux/firmware.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tas2781.h> +#include <sound/tas2781-comlib-i2c.h> + +static const struct regmap_range_cfg tasdevice_ranges[] = { + { + .range_min = 0, + .range_max = 256 * 128, + .selector_reg = TASDEVICE_PAGE_SELECT, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 128, + }, +}; + +static const struct regmap_config tasdevice_regmap = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_NONE, + .ranges = tasdevice_ranges, + .num_ranges = ARRAY_SIZE(tasdevice_ranges), + .max_register = 256 * 128, +}; + +static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv, + unsigned short chn, int book) +{ + struct i2c_client *client = (struct i2c_client *)tas_priv->client; + int ret = 0; + + if (chn < tas_priv->ndev) { + struct tasdevice *tasdev = &tas_priv->tasdevice[chn]; + struct regmap *map = tas_priv->regmap; + + if (client->addr != tasdev->dev_addr) { + client->addr = tasdev->dev_addr; + /* All tas2781s share the same regmap, clear the page + * inside regmap once switching to another tas2781. + * Register 0 at any pages and any books inside tas2781 + * is the same one for page-switching. + */ + ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d channel:%d\n", + __func__, ret, chn); + goto out; + } + } + + if (tasdev->cur_book != book) { + ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book); + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", + __func__, ret); + goto out; + } + tasdev->cur_book = book; + } + } else { + ret = -EINVAL; + dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__, + chn); + } + +out: + return ret; +} + +int tasdev_chn_switch(struct tasdevice_priv *tas_priv, + unsigned short chn) +{ + struct i2c_client *client = (struct i2c_client *)tas_priv->client; + struct tasdevice *tasdev = &tas_priv->tasdevice[chn]; + struct regmap *map = tas_priv->regmap; + int ret; + + if (client->addr != tasdev->dev_addr) { + client->addr = tasdev->dev_addr; + /* All devices share the same regmap, clear the page + * inside regmap once switching to another device. + * Register 0 at any pages and any books inside tas2781 + * is the same one for page-switching. + */ + ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + return ret; + } + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(tasdev_chn_switch); + +int tasdevice_dev_update_bits( + struct tasdevice_priv *tas_priv, unsigned short chn, + unsigned int reg, unsigned int mask, unsigned int value) +{ + int ret = 0; + + if (chn < tas_priv->ndev) { + struct regmap *map = tas_priv->regmap; + + ret = tas_priv->change_chn_book(tas_priv, chn, + TASDEVICE_BOOK_ID(reg)); + if (ret < 0) + goto out; + + ret = regmap_update_bits(map, TASDEVICE_PGRG(reg), + mask, value); + if (ret < 0) + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + } else { + dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__, + chn); + ret = -EINVAL; + } + +out: + return ret; +} +EXPORT_SYMBOL_GPL(tasdevice_dev_update_bits); + +struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c) +{ + struct tasdevice_priv *tas_priv; + + tas_priv = devm_kzalloc(&i2c->dev, sizeof(*tas_priv), GFP_KERNEL); + if (!tas_priv) + return NULL; + tas_priv->dev = &i2c->dev; + tas_priv->client = (void *)i2c; + + return tas_priv; +} +EXPORT_SYMBOL_GPL(tasdevice_kzalloc); + +int tasdevice_init(struct tasdevice_priv *tas_priv) +{ + int ret = 0; + int i; + + tas_priv->regmap = devm_regmap_init_i2c(tas_priv->client, + &tasdevice_regmap); + if (IS_ERR(tas_priv->regmap)) { + ret = PTR_ERR(tas_priv->regmap); + dev_err(tas_priv->dev, "Failed to allocate register map: %d\n", + ret); + goto out; + } + + tas_priv->cur_prog = -1; + tas_priv->cur_conf = -1; + tas_priv->isspi = false; + + for (i = 0; i < tas_priv->ndev; i++) { + tas_priv->tasdevice[i].cur_book = -1; + tas_priv->tasdevice[i].cur_prog = -1; + tas_priv->tasdevice[i].cur_conf = -1; + } + + tas_priv->update_bits = tasdevice_dev_update_bits; + tas_priv->change_chn_book = tasdevice_change_chn_book; + tas_priv->dev_read = tasdevice_dev_read; + tas_priv->dev_bulk_read = tasdevice_dev_bulk_read; + + mutex_init(&tas_priv->codec_lock); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(tasdevice_init); + +static int tasdevice_clamp(int val, int max, unsigned int invert) +{ + if (val > max) + val = max; + if (invert) + val = max - val; + if (val < 0) + val = 0; + return val; +} + +int tasdevice_amp_putvol(struct tasdevice_priv *tas_priv, + struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) +{ + unsigned int invert = mc->invert; + unsigned char mask; + int max = mc->max; + int err_cnt = 0; + int val, i, ret; + + mask = (1 << fls(max)) - 1; + mask <<= mc->shift; + val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert); + for (i = 0; i < tas_priv->ndev; i++) { + ret = tasdevice_dev_update_bits(tas_priv, i, + mc->reg, mask, (unsigned int)(val << mc->shift)); + if (!ret) + continue; + err_cnt++; + dev_err(tas_priv->dev, "set AMP vol error in dev %d\n", i); + } + + /* All the devices set error, return 0 */ + return (err_cnt == tas_priv->ndev) ? 0 : 1; +} +EXPORT_SYMBOL_GPL(tasdevice_amp_putvol); + +int tasdevice_amp_getvol(struct tasdevice_priv *tas_priv, + struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) +{ + unsigned int invert = mc->invert; + unsigned char mask = 0; + int max = mc->max; + int ret = 0; + int val; + + /* Read the primary device */ + ret = tasdevice_dev_read(tas_priv, 0, mc->reg, &val); + if (ret) { + dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__); + goto out; + } + + mask = (1 << fls(max)) - 1; + mask <<= mc->shift; + val = (val & mask) >> mc->shift; + val = tasdevice_clamp(val, max, invert); + ucontrol->value.integer.value[0] = val; + +out: + return ret; + +} +EXPORT_SYMBOL_GPL(tasdevice_amp_getvol); + +int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv, + 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_dev_read(tas_priv, 0, mc->reg, &val); + if (ret) { + dev_err(tas_priv->dev, "%s, get digital vol error\n", + __func__); + goto out; + } + + val = tasdevice_clamp(val, max, invert); + ucontrol->value.integer.value[0] = val; + +out: + return ret; + +} +EXPORT_SYMBOL_GPL(tasdevice_digital_getvol); + +int tasdevice_digital_putvol(struct tasdevice_priv *tas_priv, + struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) +{ + unsigned int invert = mc->invert; + int max = mc->max; + int err_cnt = 0; + int ret; + int val, i; + + val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert); + + for (i = 0; i < tas_priv->ndev; i++) { + ret = tasdevice_dev_write(tas_priv, i, mc->reg, + (unsigned int)val); + if (!ret) + continue; + err_cnt++; + dev_err(tas_priv->dev, + "set digital vol err in dev %d\n", i); + } + + /* All the devices set error, return 0 */ + return (err_cnt == tas_priv->ndev) ? 0 : 1; + +} +EXPORT_SYMBOL_GPL(tasdevice_digital_putvol); + +void tasdevice_reset(struct tasdevice_priv *tas_dev) +{ + int ret, i; + + if (tas_dev->reset) { + gpiod_set_value_cansleep(tas_dev->reset, 0); + usleep_range(500, 1000); + gpiod_set_value_cansleep(tas_dev->reset, 1); + } else { + for (i = 0; i < tas_dev->ndev; i++) { + ret = tasdevice_dev_write(tas_dev, i, + TASDEVICE_REG_SWRESET, + TASDEVICE_REG_SWRESET_RESET); + if (ret < 0) + dev_err(tas_dev->dev, + "dev %d swreset fail, %d\n", + i, ret); + } + } + usleep_range(1000, 1050); +} +EXPORT_SYMBOL_GPL(tasdevice_reset); + +int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, + struct module *module, + void (*cont)(const struct firmware *fw, void *context)) +{ + int ret = 0; + + /* Codec Lock Hold to ensure that codec_probe and firmware parsing and + * loading do not simultaneously execute. + */ + mutex_lock(&tas_priv->codec_lock); + + if (tas_priv->name_prefix) + scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin", + tas_priv->name_prefix, tas_priv->dev_name, + tas_priv->ndev); + else + scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin", + tas_priv->dev_name, tas_priv->ndev); + crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL); + tas_priv->codec = codec; + ret = request_firmware_nowait(module, FW_ACTION_UEVENT, + tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv, + cont); + if (ret) + dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n", + ret); + + /* Codec Lock Release*/ + mutex_unlock(&tas_priv->codec_lock); + return ret; +} +EXPORT_SYMBOL_GPL(tascodec_init); + +MODULE_DESCRIPTION("TAS2781 common library for I2C"); +MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c index 1e0b3aa95749..4cec9f8a00af 100644 --- a/sound/soc/codecs/tas2781-comlib.c +++ b/sound/soc/codecs/tas2781-comlib.c @@ -2,14 +2,14 @@ // // TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers // -// Copyright 2023 - 2024 Texas Instruments, Inc. +// Copyright 2023 - 2025 Texas Instruments, Inc. // // Author: Shenghao Ding <shenghao-ding@ti.com> #include <linux/crc8.h> +#include <linux/dev_printk.h> #include <linux/firmware.h> #include <linux/gpio/consumer.h> -#include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> @@ -17,67 +17,24 @@ #include <linux/of_irq.h> #include <linux/regmap.h> #include <linux/slab.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> #include <sound/tas2781.h> -#define TASDEVICE_CRC8_POLYNOMIAL 0x4d - -static const struct regmap_range_cfg tasdevice_ranges[] = { - { - .range_min = 0, - .range_max = 256 * 128, - .selector_reg = TASDEVICE_PAGE_SELECT, - .selector_mask = 0xff, - .selector_shift = 0, - .window_start = 0, - .window_len = 128, - }, -}; - -static const struct regmap_config tasdevice_regmap = { - .reg_bits = 8, - .val_bits = 8, - .cache_type = REGCACHE_NONE, - .ranges = tasdevice_ranges, - .num_ranges = ARRAY_SIZE(tasdevice_ranges), - .max_register = 256 * 128, -}; - -static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv, - unsigned short chn, int book) +int tasdevice_dev_read(struct tasdevice_priv *tas_priv, + unsigned short chn, unsigned int reg, unsigned int *val) { - struct i2c_client *client = (struct i2c_client *)tas_priv->client; int ret = 0; if (chn < tas_priv->ndev) { - struct tasdevice *tasdev = &tas_priv->tasdevice[chn]; struct regmap *map = tas_priv->regmap; - if (client->addr != tasdev->dev_addr) { - client->addr = tasdev->dev_addr; - /* All tas2781s share the same regmap, clear the page - * inside regmap once switching to another tas2781. - * Register 0 at any pages and any books inside tas2781 - * is the same one for page-switching. - */ - ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); - if (ret < 0) { - dev_err(tas_priv->dev, "%s, E=%d channel:%d\n", - __func__, ret, chn); - goto out; - } - } + ret = tas_priv->change_chn_book(tas_priv, chn, + TASDEVICE_BOOK_ID(reg)); + if (ret < 0) + goto out; - if (tasdev->cur_book != book) { - ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book); - if (ret < 0) { - dev_err(tas_priv->dev, "%s, E=%d\n", - __func__, ret); - goto out; - } - tasdev->cur_book = book; - } + ret = regmap_read(map, TASDEVICE_PGRG(reg), val); + if (ret < 0) + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); } else { ret = -EINVAL; dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__, @@ -87,59 +44,33 @@ static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv, out: return ret; } +EXPORT_SYMBOL_GPL(tasdevice_dev_read); -int tasdev_chn_switch(struct tasdevice_priv *tas_priv, - unsigned short chn) -{ - struct i2c_client *client = (struct i2c_client *)tas_priv->client; - struct tasdevice *tasdev = &tas_priv->tasdevice[chn]; - struct regmap *map = tas_priv->regmap; - int ret; - - if (client->addr != tasdev->dev_addr) { - client->addr = tasdev->dev_addr; - /* All devices share the same regmap, clear the page - * inside regmap once switching to another device. - * Register 0 at any pages and any books inside tas2781 - * is the same one for page-switching. - */ - ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); - if (ret < 0) { - dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); - return ret; - } - return 1; - } - return 0; -} -EXPORT_SYMBOL_GPL(tasdev_chn_switch); - -int tasdevice_dev_read(struct tasdevice_priv *tas_priv, - unsigned short chn, unsigned int reg, unsigned int *val) +int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv, + unsigned short chn, unsigned int reg, unsigned char *data, + unsigned int len) { int ret = 0; if (chn < tas_priv->ndev) { struct regmap *map = tas_priv->regmap; - ret = tasdevice_change_chn_book(tas_priv, chn, + ret = tas_priv->change_chn_book(tas_priv, chn, TASDEVICE_BOOK_ID(reg)); if (ret < 0) goto out; - ret = regmap_read(map, TASDEVICE_PGRG(reg), val); + ret = regmap_bulk_read(map, TASDEVICE_PGRG(reg), data, len); if (ret < 0) dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); - } else { - ret = -EINVAL; + } else dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__, chn); - } out: return ret; } -EXPORT_SYMBOL_GPL(tasdevice_dev_read); +EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_read); int tasdevice_dev_write(struct tasdevice_priv *tas_priv, unsigned short chn, unsigned int reg, unsigned int value) @@ -149,7 +80,7 @@ int tasdevice_dev_write(struct tasdevice_priv *tas_priv, if (chn < tas_priv->ndev) { struct regmap *map = tas_priv->regmap; - ret = tasdevice_change_chn_book(tas_priv, chn, + ret = tas_priv->change_chn_book(tas_priv, chn, TASDEVICE_BOOK_ID(reg)); if (ret < 0) goto out; @@ -179,7 +110,7 @@ int tasdevice_dev_bulk_write( if (chn < tas_priv->ndev) { struct regmap *map = tas_priv->regmap; - ret = tasdevice_change_chn_book(tas_priv, chn, + ret = tas_priv->change_chn_book(tas_priv, chn, TASDEVICE_BOOK_ID(reg)); if (ret < 0) goto out; @@ -199,161 +130,6 @@ out: } EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_write); -int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv, - unsigned short chn, unsigned int reg, unsigned char *data, - unsigned int len) -{ - int ret = 0; - - if (chn < tas_priv->ndev) { - struct regmap *map = tas_priv->regmap; - - ret = tasdevice_change_chn_book(tas_priv, chn, - TASDEVICE_BOOK_ID(reg)); - if (ret < 0) - goto out; - - ret = regmap_bulk_read(map, TASDEVICE_PGRG(reg), data, len); - if (ret < 0) - dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); - } else - dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__, - chn); - -out: - return ret; -} -EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_read); - -int tasdevice_dev_update_bits( - struct tasdevice_priv *tas_priv, unsigned short chn, - unsigned int reg, unsigned int mask, unsigned int value) -{ - int ret = 0; - - if (chn < tas_priv->ndev) { - struct regmap *map = tas_priv->regmap; - - ret = tasdevice_change_chn_book(tas_priv, chn, - TASDEVICE_BOOK_ID(reg)); - if (ret < 0) - goto out; - - ret = regmap_update_bits(map, TASDEVICE_PGRG(reg), - mask, value); - if (ret < 0) - dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); - } else { - dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__, - chn); - ret = -EINVAL; - } - -out: - return ret; -} -EXPORT_SYMBOL_GPL(tasdevice_dev_update_bits); - -struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c) -{ - struct tasdevice_priv *tas_priv; - - tas_priv = devm_kzalloc(&i2c->dev, sizeof(*tas_priv), GFP_KERNEL); - if (!tas_priv) - return NULL; - tas_priv->dev = &i2c->dev; - tas_priv->client = (void *)i2c; - - return tas_priv; -} -EXPORT_SYMBOL_GPL(tasdevice_kzalloc); - -void tasdevice_reset(struct tasdevice_priv *tas_dev) -{ - int ret, i; - - if (tas_dev->reset) { - gpiod_set_value_cansleep(tas_dev->reset, 0); - usleep_range(500, 1000); - gpiod_set_value_cansleep(tas_dev->reset, 1); - } else { - for (i = 0; i < tas_dev->ndev; i++) { - ret = tasdevice_dev_write(tas_dev, i, - TASDEVICE_REG_SWRESET, - TASDEVICE_REG_SWRESET_RESET); - if (ret < 0) - dev_err(tas_dev->dev, - "dev %d swreset fail, %d\n", - i, ret); - } - } - usleep_range(1000, 1050); -} -EXPORT_SYMBOL_GPL(tasdevice_reset); - -int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, - struct module *module, - void (*cont)(const struct firmware *fw, void *context)) -{ - int ret = 0; - - /* Codec Lock Hold to ensure that codec_probe and firmware parsing and - * loading do not simultaneously execute. - */ - mutex_lock(&tas_priv->codec_lock); - - if (tas_priv->name_prefix) - scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin", - tas_priv->name_prefix, tas_priv->dev_name, - tas_priv->ndev); - else - scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin", - tas_priv->dev_name, tas_priv->ndev); - crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL); - tas_priv->codec = codec; - ret = request_firmware_nowait(module, FW_ACTION_UEVENT, - tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv, - cont); - if (ret) - dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n", - ret); - - /* Codec Lock Release*/ - mutex_unlock(&tas_priv->codec_lock); - return ret; -} -EXPORT_SYMBOL_GPL(tascodec_init); - -int tasdevice_init(struct tasdevice_priv *tas_priv) -{ - int ret = 0; - int i; - - tas_priv->regmap = devm_regmap_init_i2c(tas_priv->client, - &tasdevice_regmap); - if (IS_ERR(tas_priv->regmap)) { - ret = PTR_ERR(tas_priv->regmap); - dev_err(tas_priv->dev, "Failed to allocate register map: %d\n", - ret); - goto out; - } - - tas_priv->cur_prog = -1; - tas_priv->cur_conf = -1; - - for (i = 0; i < tas_priv->ndev; i++) { - tas_priv->tasdevice[i].cur_book = -1; - tas_priv->tasdevice[i].cur_prog = -1; - tas_priv->tasdevice[i].cur_conf = -1; - } - - mutex_init(&tas_priv->codec_lock); - -out: - return ret; -} -EXPORT_SYMBOL_GPL(tasdevice_init); - static void tasdev_dsp_prog_blk_remove(struct tasdevice_prog *prog) { struct tasdevice_data *tas_dt; @@ -440,137 +216,6 @@ void tasdevice_remove(struct tasdevice_priv *tas_priv) } EXPORT_SYMBOL_GPL(tasdevice_remove); -int tasdevice_save_calibration(struct tasdevice_priv *tas_priv) -{ - if (tas_priv->save_calibration) - return tas_priv->save_calibration(tas_priv); - return -EINVAL; -} -EXPORT_SYMBOL_GPL(tasdevice_save_calibration); - -void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv) -{ - if (tas_priv->apply_calibration && tas_priv->cali_data.total_sz) - tas_priv->apply_calibration(tas_priv); -} -EXPORT_SYMBOL_GPL(tasdevice_apply_calibration); - -static int tasdevice_clamp(int val, int max, unsigned int invert) -{ - if (val > max) - val = max; - if (invert) - val = max - val; - if (val < 0) - val = 0; - return val; -} - -int tasdevice_amp_putvol(struct tasdevice_priv *tas_priv, - struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) -{ - unsigned int invert = mc->invert; - unsigned char mask; - int max = mc->max; - int err_cnt = 0; - int val, i, ret; - - mask = (1 << fls(max)) - 1; - mask <<= mc->shift; - val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert); - for (i = 0; i < tas_priv->ndev; i++) { - ret = tasdevice_dev_update_bits(tas_priv, i, - mc->reg, mask, (unsigned int)(val << mc->shift)); - if (!ret) - continue; - err_cnt++; - dev_err(tas_priv->dev, "set AMP vol error in dev %d\n", i); - } - - /* All the devices set error, return 0 */ - return (err_cnt == tas_priv->ndev) ? 0 : 1; -} -EXPORT_SYMBOL_GPL(tasdevice_amp_putvol); - -int tasdevice_amp_getvol(struct tasdevice_priv *tas_priv, - struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) -{ - unsigned int invert = mc->invert; - unsigned char mask = 0; - int max = mc->max; - int ret = 0; - int val; - - /* Read the primary device */ - ret = tasdevice_dev_read(tas_priv, 0, mc->reg, &val); - if (ret) { - dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__); - goto out; - } - - mask = (1 << fls(max)) - 1; - mask <<= mc->shift; - val = (val & mask) >> mc->shift; - val = tasdevice_clamp(val, max, invert); - ucontrol->value.integer.value[0] = val; - -out: - return ret; - -} -EXPORT_SYMBOL_GPL(tasdevice_amp_getvol); - -int tasdevice_digital_putvol(struct tasdevice_priv *tas_priv, - struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc) -{ - unsigned int invert = mc->invert; - int max = mc->max; - int err_cnt = 0; - int ret; - int val, i; - - val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert); - - for (i = 0; i < tas_priv->ndev; i++) { - ret = tasdevice_dev_write(tas_priv, i, mc->reg, - (unsigned int)val); - if (!ret) - continue; - err_cnt++; - dev_err(tas_priv->dev, - "set digital vol err in dev %d\n", i); - } - - /* All the devices set error, return 0 */ - return (err_cnt == tas_priv->ndev) ? 0 : 1; - -} -EXPORT_SYMBOL_GPL(tasdevice_digital_putvol); - -int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv, - 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_dev_read(tas_priv, 0, mc->reg, &val); - if (ret) { - dev_err(tas_priv->dev, "%s, get digital vol error\n", - __func__); - goto out; - } - - val = tasdevice_clamp(val, max, invert); - ucontrol->value.integer.value[0] = val; - -out: - return ret; - -} -EXPORT_SYMBOL_GPL(tasdevice_digital_getvol); - MODULE_DESCRIPTION("TAS2781 common library"); MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index e0c095bc6b8a..c9c1e608ddb7 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -808,8 +808,13 @@ static int tasdevice_process_block(void *context, unsigned char *data, chn = idx - 1; chnend = idx; } else { - chn = 0; - chnend = tas_priv->ndev; + if (tas_priv->isspi) { + chn = tas_priv->index; + chnend = chn + 1; + } else { + chn = 0; + chnend = tas_priv->ndev; + } } for (; chn < chnend; chn++) { @@ -901,7 +906,7 @@ static int tasdevice_process_block(void *context, unsigned char *data, is_err = true; break; } - rc = tasdevice_dev_update_bits(tas_priv, chn, + rc = tas_priv->update_bits(tas_priv, chn, TASDEVICE_REG(data[subblk_offset + 2], data[subblk_offset + 3], data[subblk_offset + 4]), @@ -1466,7 +1471,7 @@ static int tasdev_multibytes_chksum(struct tasdevice_priv *tasdevice, goto end; } - ret = tasdevice_dev_bulk_read(tasdevice, chn, + ret = tasdevice->dev_bulk_read(tasdevice, chn, TASDEVICE_REG(book, page, crc_data.offset), nBuf1, crc_data.len); if (ret < 0) @@ -1516,7 +1521,7 @@ static int do_singlereg_checksum(struct tasdevice_priv *tasdevice, in = check_yram(&crc_data, book, page, reg, 1); if (!in) goto end; - ret = tasdevice_dev_read(tasdevice, chl, + ret = tasdevice->dev_read(tasdevice, chl, TASDEVICE_REG(book, page, reg), &nData1); if (ret < 0) goto end; @@ -1620,7 +1625,7 @@ static int tasdev_block_chksum(struct tasdevice_priv *tas_priv, unsigned int nr_value; int ret; - ret = tasdevice_dev_read(tas_priv, chn, TASDEVICE_CHECKSUM_REG, + ret = tas_priv->dev_read(tas_priv, chn, TASDEVICE_CHECKSUM_REG, &nr_value); if (ret < 0) { dev_err(tas_priv->dev, "%s: Chn %d\n", __func__, chn); diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 68d9fe83212a..c40d8f754d89 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -31,6 +31,7 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/tas2781.h> +#include <sound/tas2781-comlib-i2c.h> #include <sound/tlv.h> #include <sound/tas2563-tlv.h> #include <sound/tas2781-tlv.h> diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 3033e2d3fe16..90e367586493 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -228,6 +228,7 @@ config SND_SOC_MT8188 config SND_SOC_MT8188_MT6359 tristate "ASoC Audio driver for MT8188 with MT6359 and I2S codecs" depends on SND_SOC_MT8188 && MTK_PMIC_WRAP + depends on SND_SOC_MT6359_ACCDET || !SND_SOC_MT6359_ACCDET depends on I2C select SND_SOC_MT6359 select SND_SOC_HDMI_CODEC diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index fcc7df75346f..a233b80049ee 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -91,6 +91,10 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, else ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, tx_ch, 0, NULL); + if (ret != 0 && ret != -ENOTSUPP) { + dev_err(rtd->dev, "failed to set cpu chan map, err:%d\n", ret); + return ret; + } } return 0; diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index b1be03011d7e..6492e1cefbfb 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -76,7 +76,7 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev) snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops); - if (chip && chip->hw_ip_version == SOF_INTEL_ACE_2_0) + if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0) bus->use_pio_for_commands = true; #else snd_hdac_ext_bus_init(bus, dev, NULL, NULL); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b34e5fdf10f1..6a3932d90b43 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1049,7 +1049,21 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, if (!*mach && codec_num <= 2) { bool tplg_fixup = false; - hda_mach = snd_soc_acpi_intel_hda_machines; + /* + * make a local copy of the match array since we might + * be modifying it + */ + hda_mach = devm_kmemdup_array(sdev->dev, + snd_soc_acpi_intel_hda_machines, + 2, /* we have one entry + sentinel in the array */ + sizeof(snd_soc_acpi_intel_hda_machines[0]), + GFP_KERNEL); + if (!hda_mach) { + dev_err(bus->dev, + "%s: failed to duplicate the HDA match table\n", + __func__); + return; + } dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 108cad04879e..e14f82c0831f 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -935,6 +935,7 @@ extern const struct sof_intel_dsp_desc mtl_chip_info; extern const struct sof_intel_dsp_desc arl_s_chip_info; extern const struct sof_intel_dsp_desc lnl_chip_info; extern const struct sof_intel_dsp_desc ptl_chip_info; +extern const struct sof_intel_dsp_desc wcl_chip_info; /* Probes support */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c index 7d4c46f56931..68f6a9841633 100644 --- a/sound/soc/sof/intel/pci-ptl.c +++ b/sound/soc/sof/intel/pci-ptl.c @@ -55,10 +55,40 @@ static const struct sof_dev_desc ptl_desc = { .ops_init = sof_ptl_ops_init, }; +static const struct sof_dev_desc wcl_desc = { + .use_acpi_target_states = true, + .machines = snd_soc_acpi_intel_ptl_machines, + .alt_machines = snd_soc_acpi_intel_ptl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &wcl_chip_info, + .ipc_supported_mask = BIT(SOF_IPC_TYPE_4), + .ipc_default = SOF_IPC_TYPE_4, + .dspless_mode_supported = true, + .default_fw_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ipc4/wcl", + }, + .default_lib_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/wcl", + }, + .default_tplg_path = { + [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg", + }, + .default_fw_filename = { + [SOF_IPC_TYPE_4] = "sof-wcl.ri", + }, + .nocodec_tplg_filename = "sof-ptl-nocodec.tplg", + .ops = &sof_ptl_ops, + .ops_init = sof_ptl_ops_init, +}; + /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_PTL, &ptl_desc) }, /* PTL */ { PCI_DEVICE_DATA(INTEL, HDA_PTL_H, &ptl_desc) }, /* PTL-H */ + { PCI_DEVICE_DATA(INTEL, HDA_WCL, &wcl_desc) }, /* WCL */ { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/ptl.c b/sound/soc/sof/intel/ptl.c index aa0b772178bc..875d18193b05 100644 --- a/sound/soc/sof/intel/ptl.c +++ b/sound/soc/sof/intel/ptl.c @@ -126,6 +126,29 @@ const struct sof_intel_dsp_desc ptl_chip_info = { .hw_ip_version = SOF_INTEL_ACE_3_0, }; +const struct sof_intel_dsp_desc wcl_chip_info = { + .cores_num = 3, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = LNL_DSP_REG_HFDSC, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .d0i3_offset = MTL_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_ext, + .check_sdw_irq = lnl_dsp_check_sdw_irq, + .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .cl_init = mtl_dsp_cl_init, + .power_down_dsp = mtl_power_down_dsp, + .disable_interrupts = lnl_dsp_disable_interrupts, + .hw_ip_version = SOF_INTEL_ACE_3_0, +}; + MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL"); MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 576f407cd456..976a4794d610 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -531,6 +531,14 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol, return -EINVAL; } + /* Check header id */ + if (header.numid != SOF_CTRL_CMD_BINARY) { + dev_err_ratelimited(scomp->dev, + "Incorrect numid for bytes put %d\n", + header.numid); + return -EINVAL; + } + /* Verify the ABI header first */ if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr))) return -EFAULT; @@ -613,7 +621,8 @@ static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol, if (data_size > size) return -ENOSPC; - header.numid = scontrol->comp_id; + /* Set header id and length */ + header.numid = SOF_CTRL_CMD_BINARY; header.length = data_size; if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 52903503cf3b..8eee3e1aadf9 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -799,7 +799,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm spcm->stream[stream].private = stream_priv; - if (!support_info) + /* Delay reporting is only supported on playback */ + if (!support_info || stream == SNDRV_PCM_STREAM_CAPTURE) continue; time_info = kzalloc(sizeof(*time_info), GFP_KERNEL); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2d4e660b19d5..d612d693efc3 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1071,7 +1071,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, struct snd_sof_dai *dai) { struct snd_soc_card *card = scomp->card; - struct snd_soc_pcm_runtime *rtd; + struct snd_soc_pcm_runtime *rtd, *full, *partial; struct snd_soc_dai *cpu_dai; int stream; int i; @@ -1088,12 +1088,22 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, else goto end; + full = NULL; + partial = NULL; list_for_each_entry(rtd, &card->rtd_list, list) { /* does stream match DAI link ? */ - if (!rtd->dai_link->stream_name || - !strstr(rtd->dai_link->stream_name, w->sname)) - continue; + if (rtd->dai_link->stream_name) { + if (!strcmp(rtd->dai_link->stream_name, w->sname)) { + full = rtd; + break; + } else if (strstr(rtd->dai_link->stream_name, w->sname)) { + partial = rtd; + } + } + } + rtd = full ? full : partial; + if (rtd) { for_each_rtd_cpu_dais(rtd, i, cpu_dai) { /* * Please create DAI widget in the right order diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 9bdf3db51d62..e73d3b262f57 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -39,6 +39,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/string.h> #include <sound/core.h> #include <sound/pcm.h> @@ -754,7 +755,7 @@ static int snd_amd7930_pcm(struct snd_amd7930 *amd) pcm->private_data = amd; pcm->info_flags = 0; - strcpy(pcm->name, amd->card->shortname); + strscpy(pcm->name, amd->card->shortname); amd->pcm = pcm; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, @@ -874,7 +875,7 @@ static int snd_amd7930_mixer(struct snd_amd7930 *amd) return -EINVAL; card = amd->card; - strcpy(card->mixername, card->shortname); + strscpy(card->mixername, card->shortname); for (idx = 0; idx < ARRAY_SIZE(amd7930_controls); idx++) { if ((err = snd_ctl_add(card, @@ -1007,8 +1008,8 @@ static int amd7930_sbus_probe(struct platform_device *op) if (err < 0) return err; - strcpy(card->driver, "AMD7930"); - strcpy(card->shortname, "Sun AMD7930"); + strscpy(card->driver, "AMD7930"); + strscpy(card->shortname, "Sun AMD7930"); sprintf(card->longname, "%s at 0x%02lx:0x%08Lx, irq %d", card->shortname, rp->flags & 0xffL, diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 69f1c9e37f4b..93cbe158009f 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -60,6 +60,7 @@ #include <linux/io.h> #include <linux/dma-mapping.h> #include <linux/gfp.h> +#include <linux/string.h> #include <sound/core.h> #include <sound/pcm.h> @@ -2239,7 +2240,7 @@ static int snd_dbri_pcm(struct snd_card *card) pcm->private_data = card->private_data; pcm->info_flags = 0; - strcpy(pcm->name, card->shortname); + strscpy(pcm->name, card->shortname); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, NULL, 64 * 1024, 64 * 1024); @@ -2446,7 +2447,7 @@ static int snd_dbri_mixer(struct snd_card *card) return -EINVAL; dbri = card->private_data; - strcpy(card->mixername, card->shortname); + strscpy(card->mixername, card->shortname); for (idx = 0; idx < ARRAY_SIZE(dbri_controls); idx++) { err = snd_ctl_add(card, @@ -2613,8 +2614,8 @@ static int dbri_probe(struct platform_device *op) if (err < 0) return err; - strcpy(card->driver, "DBRI"); - strcpy(card->shortname, "Sun DBRI"); + strscpy(card->driver, "DBRI"); + strscpy(card->shortname, "Sun DBRI"); rp = &op->resource[0]; sprintf(card->longname, "%s at 0x%02lx:0x%016llx, irq %d", card->shortname, diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c index 7df65041ace5..98f9964311a7 100644 --- a/sound/usb/fcp.c +++ b/sound/usb/fcp.c @@ -1092,8 +1092,7 @@ static int fcp_find_fc_interface(struct usb_mixer_interface *mixer) epd = get_endpoint(intf->altsetting, 0); private->bInterfaceNumber = desc->bInterfaceNumber; - private->bEndpointAddress = epd->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; + private->bEndpointAddress = usb_endpoint_num(epd); private->wMaxPacketSize = le16_to_cpu(epd->wMaxPacketSize); private->bInterval = epd->bInterval; return 0; diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 4727043fd745..77f06da93151 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -57,6 +57,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */ IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */ IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */ + IMPLICIT_FB_FIXED_DEV(0x19f7, 0x000a, 0x84, 3), /* RODE AI-1 */ IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */ IMPLICIT_FB_FIXED_DEV(0x1686, 0xf029, 0x82, 2), /* Zoom UAC-2 */ IMPLICIT_FB_FIXED_DEV(0x2466, 0x8003, 0x86, 2), /* Fractal Audio Axe-Fx II */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index cfed000f243a..3a8a977ed359 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1530,6 +1530,7 @@ static void snd_usbmidi_free(struct snd_usb_midi *umidi) snd_usbmidi_in_endpoint_delete(ep->in); } mutex_destroy(&umidi->mutex); + timer_shutdown_sync(&umidi->error_timer); kfree(umidi); } @@ -1553,7 +1554,7 @@ void snd_usbmidi_disconnect(struct list_head *p) spin_unlock_irq(&umidi->disc_lock); up_write(&umidi->disc_rwsem); - timer_delete_sync(&umidi->error_timer); + timer_shutdown_sync(&umidi->error_timer); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint *ep = &umidi->endpoints[i]; @@ -2088,7 +2089,7 @@ static int roland_load_get(struct snd_kcontrol *kcontrol, static int roland_load_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { - struct snd_usb_midi *umidi = kcontrol->private_data; + struct snd_usb_midi *umidi = snd_kcontrol_chip(kcontrol); int changed; if (value->value.enumerated.item[0] > 1) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 66976be06bc0..11be79af26db 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -547,7 +547,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); DECLARE_TLV_DB_MINMAX(scale, 0, 0); if (size < sizeof(scale)) @@ -1367,7 +1367,7 @@ static int get_max_exposed(struct usb_mixer_elem_info *cval) static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); if (cval->val_type == USB_MIXER_BOOLEAN || cval->val_type == USB_MIXER_INV_BOOLEAN) @@ -1399,7 +1399,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); int c, cnt, val, err; ucontrol->value.integer.value[0] = cval->min; @@ -1431,7 +1431,7 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); int max_val = get_max_exposed(cval); int c, cnt, val, oval, err; int changed = 0; @@ -1475,7 +1475,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, static int mixer_ctl_master_bool_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); int val, err; err = snd_usb_get_cur_mix_value(cval, 0, 0, &val); @@ -1543,7 +1543,7 @@ error: static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); int ret, val; ret = get_connector_value(cval, kcontrol->id.name, &val); @@ -2302,7 +2302,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); int err, val; err = get_cur_ctl_value(cval, cval->control << 8, &val); @@ -2319,7 +2319,7 @@ static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol, static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); int val, oval, err; err = get_cur_ctl_value(cval, cval->control << 8, &oval); @@ -2654,7 +2654,7 @@ static int parse_audio_extension_unit(struct mixer_build *state, int unitid, static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); const char **itemlist = (const char **)kcontrol->private_value; if (snd_BUG_ON(!itemlist)) @@ -2666,7 +2666,7 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); int val, err; err = get_cur_ctl_value(cval, cval->control << 8, &val); @@ -2683,7 +2683,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); int val, oval, err; err = get_cur_ctl_value(cval, cval->control << 8, &oval); diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index a90673d43822..aad205df93b2 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2000,7 +2000,7 @@ static int realtek_hda_get(struct snd_usb_audio *chip, u32 cmd, u32 *value) static int realtek_ctl_connector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = cval->head.mixer->chip; u32 pv = kcontrol->private_value; u32 node_id = pv & 0xff; @@ -3525,10 +3525,13 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_CAP_RECOUT 0x0a #define SND_DJM_CAP_RECOUT_NOMIC 0x0e #define SND_DJM_CAP_NONE 0x0f +#define SND_DJM_CAP_FXSEND 0x10 #define SND_DJM_CAP_CH1PFADER 0x11 #define SND_DJM_CAP_CH2PFADER 0x12 #define SND_DJM_CAP_CH3PFADER 0x13 #define SND_DJM_CAP_CH4PFADER 0x14 +#define SND_DJM_CAP_EXT1SEND 0x21 +#define SND_DJM_CAP_EXT2SEND 0x22 #define SND_DJM_CAP_CH1PREFADER 0x31 #define SND_DJM_CAP_CH2PREFADER 0x32 #define SND_DJM_CAP_CH3PREFADER 0x33 @@ -3559,6 +3562,7 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_750MK2_IDX 0x4 #define SND_DJM_450_IDX 0x5 #define SND_DJM_A9_IDX 0x6 +#define SND_DJM_V10_IDX 0x7 #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ @@ -3598,8 +3602,8 @@ static const char *snd_djm_get_label_caplevel_common(u16 wvalue) } }; -// The DJM-A9 has different capture levels than other, older models -static const char *snd_djm_get_label_caplevel_a9(u16 wvalue) +// Models like DJM-A9 or DJM-V10 have different capture levels than others +static const char *snd_djm_get_label_caplevel_high(u16 wvalue) { switch (wvalue) { case 0x0000: return "+15dB"; @@ -3627,6 +3631,7 @@ static const char *snd_djm_get_label_cap_common(u16 wvalue) case SND_DJM_CAP_RECOUT_NOMIC: return "Rec Out without Mic"; case SND_DJM_CAP_AUX: return "Aux"; case SND_DJM_CAP_NONE: return "None"; + case SND_DJM_CAP_FXSEND: return "FX SEND"; case SND_DJM_CAP_CH1PREFADER: return "Pre Fader Ch1"; case SND_DJM_CAP_CH2PREFADER: return "Pre Fader Ch2"; case SND_DJM_CAP_CH3PREFADER: return "Pre Fader Ch3"; @@ -3635,6 +3640,8 @@ static const char *snd_djm_get_label_cap_common(u16 wvalue) case SND_DJM_CAP_CH2PFADER: return "Post Fader Ch2"; case SND_DJM_CAP_CH3PFADER: return "Post Fader Ch3"; case SND_DJM_CAP_CH4PFADER: return "Post Fader Ch4"; + case SND_DJM_CAP_EXT1SEND: return "EXT1 SEND"; + case SND_DJM_CAP_EXT2SEND: return "EXT2 SEND"; default: return NULL; } }; @@ -3653,7 +3660,8 @@ static const char *snd_djm_get_label_cap_850(u16 wvalue) static const char *snd_djm_get_label_caplevel(u8 device_idx, u16 wvalue) { switch (device_idx) { - case SND_DJM_A9_IDX: return snd_djm_get_label_caplevel_a9(wvalue); + case SND_DJM_A9_IDX: return snd_djm_get_label_caplevel_high(wvalue); + case SND_DJM_V10_IDX: return snd_djm_get_label_caplevel_high(wvalue); default: return snd_djm_get_label_caplevel_common(wvalue); } }; @@ -3705,13 +3713,13 @@ static const u16 snd_djm_opts_250mk2_pb2[] = { 0x0200, 0x0201, 0x0204 }; static const u16 snd_djm_opts_250mk2_pb3[] = { 0x0300, 0x0301, 0x0304 }; static const struct snd_djm_ctl snd_djm_ctls_250mk2[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 250mk2_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 250mk2_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 250mk2_cap3, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch1 Output", 250mk2_pb1, 0, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch2 Output", 250mk2_pb2, 1, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch3 Output", 250mk2_pb3, 2, SND_DJM_WINDEX_PB) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 250mk2_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 250mk2_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 250mk2_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Output 1 Playback Switch", 250mk2_pb1, 0, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 2 Playback Switch", 250mk2_pb2, 1, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 3 Playback Switch", 250mk2_pb3, 2, SND_DJM_WINDEX_PB) }; @@ -3730,13 +3738,13 @@ static const u16 snd_djm_opts_450_pb2[] = { 0x0200, 0x0201, 0x0204 }; static const u16 snd_djm_opts_450_pb3[] = { 0x0300, 0x0301, 0x0304 }; static const struct snd_djm_ctl snd_djm_ctls_450[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 450_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 450_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 450_cap3, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch1 Output", 450_pb1, 0, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch2 Output", 450_pb2, 1, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch3 Output", 450_pb3, 2, SND_DJM_WINDEX_PB) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 450_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 450_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 450_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Output 1 Playback Switch", 450_pb1, 0, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 2 Playback Switch", 450_pb2, 1, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 3 Playback Switch", 450_pb3, 2, SND_DJM_WINDEX_PB) }; @@ -3751,11 +3759,11 @@ static const u16 snd_djm_opts_750_cap4[] = { 0x0401, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; static const struct snd_djm_ctl snd_djm_ctls_750[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 750_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 750_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 750_cap3, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", 750_cap4, 0, SND_DJM_WINDEX_CAP) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 750_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 750_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 750_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", 750_cap4, 0, SND_DJM_WINDEX_CAP) }; @@ -3770,11 +3778,11 @@ static const u16 snd_djm_opts_850_cap4[] = { 0x0400, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; static const struct snd_djm_ctl snd_djm_ctls_850[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 850_cap1, 1, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 850_cap2, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 850_cap3, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", 850_cap4, 1, SND_DJM_WINDEX_CAP) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 850_cap1, 1, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 850_cap2, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 850_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", 850_cap4, 1, SND_DJM_WINDEX_CAP) }; @@ -3791,12 +3799,12 @@ static const u16 snd_djm_opts_900nxs2_cap5[] = { 0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 }; static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 900nxs2_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 900nxs2_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 900nxs2_cap3, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", 900nxs2_cap4, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch5 Input", 900nxs2_cap5, 3, SND_DJM_WINDEX_CAP) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 900nxs2_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 900nxs2_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 900nxs2_cap3, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", 900nxs2_cap4, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 5 Capture Switch", 900nxs2_cap5, 3, SND_DJM_WINDEX_CAP) }; // DJM-750MK2 @@ -3817,15 +3825,15 @@ static const u16 snd_djm_opts_750mk2_pb3[] = { 0x0300, 0x0301, 0x0304 }; static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 750mk2_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 750mk2_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 750mk2_cap3, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", 750mk2_cap4, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch5 Input", 750mk2_cap5, 3, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch1 Output", 750mk2_pb1, 0, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch2 Output", 750mk2_pb2, 1, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch3 Output", 750mk2_pb3, 2, SND_DJM_WINDEX_PB) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 750mk2_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 750mk2_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 750mk2_cap3, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", 750mk2_cap4, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 5 Capture Switch", 750mk2_cap5, 3, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Output 1 Playback Switch", 750mk2_pb1, 0, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 2 Playback Switch", 750mk2_pb2, 1, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 3 Playback Switch", 750mk2_pb3, 2, SND_DJM_WINDEX_PB) }; @@ -3845,12 +3853,56 @@ static const u16 snd_djm_opts_a9_cap5[] = { 0x0501, 0x0502, 0x0503, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050a, 0x050e }; static const struct snd_djm_ctl snd_djm_ctls_a9[] = { - SND_DJM_CTL("Capture Level", a9_cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Master Input", a9_cap1, 3, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch1 Input", a9_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", a9_cap3, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", a9_cap4, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", a9_cap5, 2, SND_DJM_WINDEX_CAP) + SND_DJM_CTL("Master Input Level Capture Switch", a9_cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Master Input Capture Switch", a9_cap1, 3, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 1 Capture Switch", a9_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", a9_cap3, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", a9_cap4, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", a9_cap5, 2, SND_DJM_WINDEX_CAP) +}; + +// DJM-V10 +static const u16 snd_djm_opts_v10_cap_level[] = { + 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500 +}; +static const u16 snd_djm_opts_v10_cap1[] = { + 0x0103, + 0x0100, 0x0102, 0x0106, 0x0110, 0x0107, + 0x0108, 0x0109, 0x010a, 0x0121, 0x0122 +}; +static const u16 snd_djm_opts_v10_cap2[] = { + 0x0200, 0x0202, 0x0206, 0x0210, 0x0207, + 0x0208, 0x0209, 0x020a, 0x0221, 0x0222 +}; +static const u16 snd_djm_opts_v10_cap3[] = { + 0x0303, + 0x0300, 0x0302, 0x0306, 0x0310, 0x0307, + 0x0308, 0x0309, 0x030a, 0x0321, 0x0322 +}; +static const u16 snd_djm_opts_v10_cap4[] = { + 0x0403, + 0x0400, 0x0402, 0x0406, 0x0410, 0x0407, + 0x0408, 0x0409, 0x040a, 0x0421, 0x0422 +}; +static const u16 snd_djm_opts_v10_cap5[] = { + 0x0500, 0x0502, 0x0506, 0x0510, 0x0507, + 0x0508, 0x0509, 0x050a, 0x0521, 0x0522 +}; +static const u16 snd_djm_opts_v10_cap6[] = { + 0x0603, + 0x0600, 0x0602, 0x0606, 0x0610, 0x0607, + 0x0608, 0x0609, 0x060a, 0x0621, 0x0622 +}; + +static const struct snd_djm_ctl snd_djm_ctls_v10[] = { + SND_DJM_CTL("Master Input Level Capture Switch", v10_cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", v10_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", v10_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", v10_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", v10_cap4, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 5 Capture Switch", v10_cap5, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 6 Capture Switch", v10_cap6, 0, SND_DJM_WINDEX_CAP) + // playback channels are fixed and controlled by hardware knobs on the mixer }; static const struct snd_djm_device snd_djm_devices[] = { @@ -3861,6 +3913,7 @@ static const struct snd_djm_device snd_djm_devices[] = { [SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2), [SND_DJM_450_IDX] = SND_DJM_DEVICE(450), [SND_DJM_A9_IDX] = SND_DJM_DEVICE(a9), + [SND_DJM_V10_IDX] = SND_DJM_DEVICE(v10), }; @@ -4151,6 +4204,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x2b73, 0x003c): /* Pioneer DJ / AlphaTheta DJM-A9 */ err = snd_djm_controls_create(mixer, SND_DJM_A9_IDX); break; + case USB_ID(0x2b73, 0x0034): /* Pioneer DJ DJM-V10 */ + err = snd_djm_controls_create(mixer, SND_DJM_V10_IDX); + break; } return err; diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 288d22e6a0b2..93589e86828a 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -8574,8 +8574,7 @@ static int scarlett2_find_fc_interface(struct usb_device *dev, epd = get_endpoint(intf->altsetting, 0); private->bInterfaceNumber = desc->bInterfaceNumber; - private->bEndpointAddress = epd->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; + private->bEndpointAddress = usb_endpoint_num(epd); private->wMaxPacketSize = le16_to_cpu(epd->wMaxPacketSize); private->bInterval = epd->bInterval; return 0; diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c index 20ac32635f1f..236b69054867 100644 --- a/sound/usb/mixer_us16x08.c +++ b/sound/usb/mixer_us16x08.c @@ -180,7 +180,7 @@ static int snd_us16x08_route_info(struct snd_kcontrol *kcontrol, static int snd_us16x08_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); int index = ucontrol->id.index; /* route has no bias */ @@ -192,7 +192,7 @@ static int snd_us16x08_route_get(struct snd_kcontrol *kcontrol, static int snd_us16x08_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = elem->head.mixer->chip; int index = ucontrol->id.index; char buf[sizeof(route_msg)]; @@ -249,7 +249,7 @@ static int snd_us16x08_master_info(struct snd_kcontrol *kcontrol, static int snd_us16x08_master_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); int index = ucontrol->id.index; ucontrol->value.integer.value[0] = elem->cache_val[index]; @@ -260,7 +260,7 @@ static int snd_us16x08_master_get(struct snd_kcontrol *kcontrol, static int snd_us16x08_master_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = elem->head.mixer->chip; char buf[sizeof(mix_msg_out)]; int val, err; @@ -297,7 +297,7 @@ static int snd_us16x08_master_put(struct snd_kcontrol *kcontrol, static int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = elem->head.mixer->chip; char buf[sizeof(mix_msg_out)]; int val, err = 0; @@ -338,7 +338,7 @@ static int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol, static int snd_us16x08_bus_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); switch (elem->head.id) { case SND_US16X08_ID_BUSS_OUT: @@ -359,7 +359,7 @@ static int snd_us16x08_bus_get(struct snd_kcontrol *kcontrol, static int snd_us16x08_channel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); int index = ucontrol->id.index; ucontrol->value.integer.value[0] = elem->cache_val[index]; @@ -370,7 +370,7 @@ static int snd_us16x08_channel_get(struct snd_kcontrol *kcontrol, static int snd_us16x08_channel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = elem->head.mixer->chip; char buf[sizeof(mix_msg_in)]; int val, err; @@ -417,7 +417,7 @@ static int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol, static int snd_us16x08_comp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_us16x08_comp_store *store = elem->private_data; int index = ucontrol->id.index; int val_idx = COMP_STORE_IDX(elem->head.id); @@ -430,7 +430,7 @@ static int snd_us16x08_comp_get(struct snd_kcontrol *kcontrol, static int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = elem->head.mixer->chip; struct snd_us16x08_comp_store *store = elem->private_data; int index = ucontrol->id.index; @@ -485,7 +485,7 @@ static int snd_us16x08_eqswitch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int val; - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_us16x08_eq_store *store = elem->private_data; int index = ucontrol->id.index; @@ -500,7 +500,7 @@ static int snd_us16x08_eqswitch_get(struct snd_kcontrol *kcontrol, static int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = elem->head.mixer->chip; struct snd_us16x08_eq_store *store = elem->private_data; int index = ucontrol->id.index; @@ -544,7 +544,7 @@ static int snd_us16x08_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int val; - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_us16x08_eq_store *store = elem->private_data; int index = ucontrol->id.index; int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1; @@ -560,7 +560,7 @@ static int snd_us16x08_eq_get(struct snd_kcontrol *kcontrol, static int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = elem->head.mixer->chip; struct snd_us16x08_eq_store *store = elem->private_data; int index = ucontrol->id.index; @@ -684,7 +684,7 @@ static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int i, set; - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = elem->head.mixer->chip; struct snd_us16x08_meter_store *store = elem->private_data; u8 meter_urb[64] = {0}; @@ -744,7 +744,7 @@ static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol, static int snd_us16x08_meter_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *elem = kcontrol->private_data; + struct usb_mixer_elem_info *elem = snd_kcontrol_chip(kcontrol); struct snd_us16x08_meter_store *store = elem->private_data; int val; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 8954be23325c..eafc0d73cca1 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3187,6 +3187,57 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + /* + * Pioneer DJ DJM-V10 + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0034), + QUIRK_DRIVER_INFO { + QUIRK_DATA_COMPOSITE { + { + QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 12, // outputs + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, + { + QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 12, // inputs + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x82, + .ep_idx = 1, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_IMPLICIT_FB, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, + QUIRK_COMPOSITE_END + } + } +}, /* * MacroSilicon MS2100/MS2106 based AV capture cards diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index dbbc9eb935a4..bd24f3a78ea9 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1872,6 +1872,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, break; case USB_ID(0x2b73, 0x000a): /* Pioneer DJM-900NXS2 */ case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */ + case USB_ID(0x2b73, 0x0034): /* Pioneer DJM-V10 */ pioneer_djm_set_format_quirk(subs, 0x0082); break; case USB_ID(0x08e4, 0x017f): /* Pioneer DJM-750 */ @@ -2284,6 +2285,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_DISABLE_AUTOSUSPEND), DEVICE_FLG(0x17aa, 0x104d, /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */ QUIRK_FLAG_DISABLE_AUTOSUSPEND), + DEVICE_FLG(0x17ef, 0x3083, /* Lenovo TBT3 dock */ + QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1852, 0x5062, /* Luxman D-08u */ QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), DEVICE_FLG(0x1852, 0x5065, /* Luxman DA-06 */ diff --git a/sound/virtio/virtio_kctl.c b/sound/virtio/virtio_kctl.c index 7aa79c05b464..ffb903d56297 100644 --- a/sound/virtio/virtio_kctl.c +++ b/sound/virtio/virtio_kctl.c @@ -47,7 +47,7 @@ static const unsigned int g_v2a_mask_map[] = { static int virtsnd_kctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct virtio_snd *snd = kcontrol->private_data; + struct virtio_snd *snd = snd_kcontrol_chip(kcontrol); struct virtio_kctl *kctl = &snd->kctls[kcontrol->private_value]; struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[kcontrol->private_value]; @@ -102,7 +102,7 @@ static int virtsnd_kctl_info(struct snd_kcontrol *kcontrol, static int virtsnd_kctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue) { - struct virtio_snd *snd = kcontrol->private_data; + struct virtio_snd *snd = snd_kcontrol_chip(kcontrol); struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[kcontrol->private_value]; unsigned int type = le32_to_cpu(kinfo->type); @@ -175,7 +175,7 @@ on_failure: static int virtsnd_kctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue) { - struct virtio_snd *snd = kcontrol->private_data; + struct virtio_snd *snd = snd_kcontrol_chip(kcontrol); struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[kcontrol->private_value]; unsigned int type = le32_to_cpu(kinfo->type); @@ -239,7 +239,7 @@ static int virtsnd_kctl_put(struct snd_kcontrol *kcontrol, static int virtsnd_kctl_tlv_op(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *utlv) { - struct virtio_snd *snd = kcontrol->private_data; + struct virtio_snd *snd = snd_kcontrol_chip(kcontrol); struct virtio_snd_msg *msg; struct virtio_snd_ctl_hdr *hdr; unsigned int *tlv; diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 7fcc528a0204..fe5cb4139088 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -22,6 +22,7 @@ #include <linux/pm_runtime.h> #include <linux/dma-mapping.h> #include <linux/delay.h> +#include <linux/string.h> #include <sound/core.h> #include <sound/asoundef.h> #include <sound/pcm.h> @@ -1698,9 +1699,9 @@ static int __hdmi_lpe_audio_probe(struct platform_device *pdev) card_ctx = card->private_data; card_ctx->dev = &pdev->dev; card_ctx->card = card; - strcpy(card->driver, INTEL_HAD); - strcpy(card->shortname, "Intel HDMI/DP LPE Audio"); - strcpy(card->longname, "Intel HDMI/DP LPE Audio"); + strscpy(card->driver, INTEL_HAD); + strscpy(card->shortname, "Intel HDMI/DP LPE Audio"); + strscpy(card->longname, "Intel HDMI/DP LPE Audio"); card_ctx->irq = -1; |