diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-07-02 15:25:23 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-07-02 15:25:23 -0700 |
commit | d6b63b5b7d7f363c6a54421533791e9849adf2e0 (patch) | |
tree | 4ce13ab8c97a3eafe0669b217fc24c9273dc42c6 /sound | |
parent | bd31b9efbf549d9630bf2f269a3a56dcb29fcac1 (diff) | |
parent | 9a7b7ec3c6f2aedb99c9f39dd9cb63c2deff3437 (diff) | |
download | linux-d6b63b5b7d7f363c6a54421533791e9849adf2e0.tar.bz2 |
Merge tag 'sound-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"As the diffstat scatters over the tree, we've got many tree-wide small
changes, but also got quite a few intrusive changes in the core side.
The only ABI-visible core change is the new rawmidi framing mode
support while others are kernel-internal, mostly code refactoring
and/or nice improvements.
Here are some highlights:
Core:
- A new framing access mode for rawmidi to get timestamps
- Cleanup / refactoring of buffer memory management helper code
- Support for automatic negotiation of ASoC DAI formats
- Revival of software suspend for PCM and control core, as a
preliminary work for PCI BAR rescan support
ASoC:
- Accessory detection support for several Qualcomm parts
- Support for IEC958 control with hdmi-codec
- Merging of Tegra machine drivers into a single driver
- Support for AmLogic SM1 TOACODEC, Intel AlderLake-M, several NXP
i.MX8 variants, NXP TFA1 and TDF9897, Rockchip RK817, Qualcomm
Quinary MI2S, Texas Instruments TAS2505
USB-audio:
- Reduction of latency at playback start
- Code cleanup / fixes of usx2y driver
- Scarlett2 mixer code fixes and enhancements
- Quirks for Ozone and Denon devices
HD-audio:
- A few quirks for HP and ASUS machines
- Display power management fixes
Others:
- FireWire code refactoring and enhancements
- Tree-wide trivial coding-style fixes"
* tag 'sound-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (594 commits)
ALSA: usb-audio: scarlett2: Fix for loop increment in scarlett2_usb_get_config
ALSA: hda/realtek: fix mute/micmute LEDs for HP ProBook 630 G8
ALSA: hda/realtek: fix mute/micmute LEDs for HP ProBook 445 G8
ALSA: hda/realtek: fix mute/micmute LEDs for HP ProBook 450 G8
ALSA: hda/realtek - Add ALC285 HP init procedure
ALSA: hda/realtek - Add type for ALC287
ALSA: scarlett2: Fix scarlett2_*_ctl_put() return values again
ALSA: scarlett2: Fix pad count for 18i8 Gen 3
ALSA: hda/realtek: fix mute/micmute LEDs for HP EliteBook 830 G8 Notebook PC
ALSA: firewire-lib: Fix 'amdtp_domain_start()' when no AMDTP_OUT_STREAM stream is found
ASoC: qcom: lpass-cpu: mark IRQ_CLEAR register as volatile and readable
ALSA: hda: Release codec display power during shutdown/reboot
ALSA: hda: Release controller display power during shutdown/reboot
ALSA: hda/realtek: Apply LED fixup for HP Dragonfly G1, too
ASoC: fsl: remove unnecessary oom message
ASoC: tlv320aic32x4: dt-bindings: add TAS2505 to compatible
ASoC: tlv320aic32x4: add support for TAS2505
ASoC: tlv320aic32x4: add type to device private data struct
ASoC: tegra30: ahub: Use devm_platform_get_and_ioremap_resource()
ASoC: tegra: tegra210_admaif: Use devm_platform_get_and_ioremap_resource()
...
Diffstat (limited to 'sound')
522 files changed, 25686 insertions, 10491 deletions
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index d9077e91382b..6ddf646cda65 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -520,7 +520,7 @@ static int ac97_bus_remove(struct device *dev) struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver); int ret; - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index 1c8e8131a716..a9e502a6cdeb 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -918,10 +918,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, } cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL); - if (!cii) { - printk(KERN_DEBUG "i2sbus: failed to allocate cii\n"); + if (!cii) return -ENOMEM; - } /* use the private data to point to the codec info */ cii->sdev = soundbus_dev_get(dev); diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 6322e6392594..a67e6685b00c 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -47,9 +47,7 @@ static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97, static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { - int __always_unused ret; - - ret = pxa2xx_ac97_write(ac97->num, reg, val); + pxa2xx_ac97_write(ac97->num, reg, val); } static const struct snd_ac97_bus_ops pxa2xx_ac97_ops = { diff --git a/sound/core/control.c b/sound/core/control.c index 498e3701514a..a25c0d64d104 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -995,7 +995,10 @@ static int __snd_ctl_elem_info(struct snd_card *card, #ifdef CONFIG_SND_DEBUG info->access = 0; #endif - result = kctl->info(kctl, info); + result = snd_power_ref_and_wait(card); + if (!result) + result = kctl->info(kctl, info); + snd_power_unref(card); if (result >= 0) { snd_BUG_ON(info->access); index_offset = snd_ctl_get_ioff(kctl, &info->id); @@ -1042,9 +1045,6 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; - result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); - if (result < 0) - return result; result = snd_ctl_elem_info(ctl, &info); if (result < 0) return result; @@ -1088,7 +1088,10 @@ static int snd_ctl_elem_read(struct snd_card *card, if (!snd_ctl_skip_validation(&info)) fill_remaining_elem_value(control, &info, pattern); - ret = kctl->get(kctl, control); + ret = snd_power_ref_and_wait(card); + if (!ret) + ret = kctl->get(kctl, control); + snd_power_unref(card); if (ret < 0) return ret; if (!snd_ctl_skip_validation(&info) && @@ -1113,10 +1116,6 @@ static int snd_ctl_elem_read_user(struct snd_card *card, if (IS_ERR(control)) return PTR_ERR(control); - result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) - goto error; - down_read(&card->controls_rwsem); result = snd_ctl_elem_read(card, control); up_read(&card->controls_rwsem); @@ -1154,7 +1153,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, } snd_ctl_build_ioff(&control->id, kctl, index_offset); - result = kctl->put(kctl, control); + result = snd_power_ref_and_wait(card); + if (!result) + result = kctl->put(kctl, control); + snd_power_unref(card); if (result < 0) { up_write(&card->controls_rwsem); return result; @@ -1183,10 +1185,6 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file, return PTR_ERR(control); card = file->card; - result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) - goto error; - result = snd_ctl_elem_write(card, file, control); if (result < 0) goto error; @@ -1669,7 +1667,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND}, }; struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)]; - int i; + int i, ret; /* Check support of the request for this element. */ for (i = 0; i < ARRAY_SIZE(pairs); ++i) { @@ -1687,7 +1685,11 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, vd->owner != NULL && vd->owner != file) return -EPERM; - return kctl->tlv.c(kctl, op_flag, size, buf); + ret = snd_power_ref_and_wait(file->card); + if (!ret) + ret = kctl->tlv.c(kctl, op_flag, size, buf); + snd_power_unref(file->card); + return ret; } static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id, @@ -1815,11 +1817,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; case SNDRV_CTL_IOCTL_POWER_STATE: -#ifdef CONFIG_PM - return put_user(card->power_state, ip) ? -EFAULT : 0; -#else return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0; -#endif } down_read(&snd_ioctl_rwsem); list_for_each_entry(p, &snd_control_ioctls, list) { diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 1d708aab9c98..470dabc60aa0 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -96,9 +96,6 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) goto error; - err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; err = snd_ctl_elem_info(ctl, data); if (err < 0) goto error; @@ -187,7 +184,10 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, return -ENOMEM; } info->id = *id; - err = kctl->info(kctl, info); + err = snd_power_ref_and_wait(card); + if (!err) + err = kctl->info(kctl, info); + snd_power_unref(card); up_read(&card->controls_rwsem); if (err >= 0) { err = info->type; @@ -298,9 +298,6 @@ static int ctl_elem_read_user(struct snd_card *card, if (err < 0) goto error; - err = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; err = snd_ctl_elem_read(card, data); if (err < 0) goto error; @@ -326,9 +323,6 @@ static int ctl_elem_write_user(struct snd_ctl_file *file, if (err < 0) goto error; - err = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; err = snd_ctl_elem_write(card, file, data); if (err < 0) goto error; diff --git a/sound/core/control_led.c b/sound/core/control_led.c index a90e31dbde61..764058cc345d 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -393,11 +393,11 @@ static void snd_ctl_led_dev_release(struct device *dev) * sysfs */ -static ssize_t show_mode(struct device *dev, +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); - const char *str; + const char *str = NULL; switch (led->mode) { case MODE_FOLLOW_MUTE: str = "follow-mute"; break; @@ -408,7 +408,8 @@ static ssize_t show_mode(struct device *dev, return sprintf(buf, "%s\n", str); } -static ssize_t store_mode(struct device *dev, struct device_attribute *attr, +static ssize_t mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); @@ -437,7 +438,7 @@ static ssize_t store_mode(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_brightness(struct device *dev, +static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); @@ -445,8 +446,8 @@ static ssize_t show_brightness(struct device *dev, return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type)); } -static DEVICE_ATTR(mode, 0644, show_mode, store_mode); -static DEVICE_ATTR(brightness, 0444, show_brightness, NULL); +static DEVICE_ATTR_RW(mode); +static DEVICE_ATTR_RO(brightness); static struct attribute *snd_ctl_led_dev_attrs[] = { &dev_attr_mode.attr, @@ -580,22 +581,25 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si return count; } -static ssize_t parse_attach(struct device *dev, struct device_attribute *attr, +static ssize_t attach_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); return set_led_id(led_card, buf, count, true); } -static ssize_t parse_detach(struct device *dev, struct device_attribute *attr, +static ssize_t detach_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); return set_led_id(led_card, buf, count, false); } -static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); int err; @@ -608,8 +612,8 @@ static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t ctl_list(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t list_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); struct snd_card *card; @@ -642,10 +646,10 @@ static ssize_t ctl_list(struct device *dev, return buf2 - buf; } -static DEVICE_ATTR(attach, 0200, NULL, parse_attach); -static DEVICE_ATTR(detach, 0200, NULL, parse_detach); -static DEVICE_ATTR(reset, 0200, NULL, ctl_reset); -static DEVICE_ATTR(list, 0444, ctl_list, NULL); +static DEVICE_ATTR_WO(attach); +static DEVICE_ATTR_WO(detach); +static DEVICE_ATTR_WO(reset); +static DEVICE_ATTR_RO(list); static struct attribute *snd_ctl_led_card_attrs[] = { &dev_attr_attach.attr, diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 264b8ea64bc2..e95fa275c289 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -195,7 +195,8 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw, return -ENXIO; memset(&info, 0, sizeof(info)); info.dsp_loaded = hw->dsp_loaded; - if ((err = hw->ops.dsp_status(hw, &info)) < 0) + err = hw->ops.dsp_status(hw, &info); + if (err < 0) return err; if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -500,7 +501,8 @@ static void __init snd_hwdep_proc_init(void) { struct snd_info_entry *entry; - if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { + entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL); + if (entry) { entry->c.text.read = snd_hwdep_proc_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index 83900485dd8c..1ba887c7954e 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -31,7 +31,8 @@ int snd_oss_info_register(int dev, int num, char *string) return -ENXIO; mutex_lock(&strings); if (string == NULL) { - if ((x = snd_sndstat_strings[num][dev]) != NULL) { + x = snd_sndstat_strings[num][dev]; + if (x) { kfree(x); x = NULL; } diff --git a/sound/core/init.c b/sound/core/init.c index ef41f5b3a240..1490568efdb0 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -220,6 +220,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid, mutex_init(&card->memory_mutex); #ifdef CONFIG_PM init_waitqueue_head(&card->power_sleep); + init_waitqueue_head(&card->power_ref_sleep); + atomic_set(&card->power_ref, 0); #endif init_waitqueue_head(&card->remove_sleep); card->sync_irq = -1; @@ -442,6 +444,7 @@ int snd_card_disconnect(struct snd_card *card) #ifdef CONFIG_PM wake_up(&card->power_sleep); + snd_power_sync_ref(card); #endif return 0; } @@ -662,17 +665,15 @@ void snd_card_set_id(struct snd_card *card, const char *nid) } EXPORT_SYMBOL(snd_card_set_id); -static ssize_t -card_id_show_attr(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t id_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); return scnprintf(buf, PAGE_SIZE, "%s\n", card->id); } -static ssize_t -card_id_store_attr(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t id_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); char buf1[sizeof(card->id)]; @@ -700,17 +701,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(id, 0644, card_id_show_attr, card_id_store_attr); +static DEVICE_ATTR_RW(id); -static ssize_t -card_number_show_attr(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t number_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); return scnprintf(buf, PAGE_SIZE, "%i\n", card->number); } -static DEVICE_ATTR(number, 0444, card_number_show_attr, NULL); +static DEVICE_ATTR_RO(number); static struct attribute *card_dev_attrs[] = { &dev_attr_id.attr, @@ -770,7 +770,8 @@ int snd_card_register(struct snd_card *card) card->registered = true; } - if ((err = snd_device_register_all(card)) < 0) + err = snd_device_register_all(card); + if (err < 0) return err; mutex_lock(&snd_card_mutex); if (snd_cards[card->number]) { @@ -813,7 +814,8 @@ static void snd_card_info_read(struct snd_info_entry *entry, for (idx = count = 0; idx < SNDRV_CARDS; idx++) { mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) { + card = snd_cards[idx]; + if (card) { count++; snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n", idx, @@ -837,7 +839,8 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer) for (idx = count = 0; idx < SNDRV_CARDS; idx++) { mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) { + card = snd_cards[idx]; + if (card) { count++; snd_iprintf(buffer, "%s\n", card->longname); } @@ -859,7 +862,8 @@ static void snd_card_module_info_read(struct snd_info_entry *entry, for (idx = 0; idx < SNDRV_CARDS; idx++) { mutex_lock(&snd_card_mutex); - if ((card = snd_cards[idx]) != NULL) + card = snd_cards[idx]; + if (card) snd_iprintf(buffer, "%2i %s\n", idx, card->module->name); mutex_unlock(&snd_card_mutex); @@ -1002,21 +1006,28 @@ EXPORT_SYMBOL(snd_card_file_remove); #ifdef CONFIG_PM /** - * snd_power_wait - wait until the power-state is changed. - * @card: soundcard structure - * @power_state: expected power state + * snd_power_ref_and_wait - wait until the card gets powered up + * @card: soundcard structure + * + * Take the power_ref reference count of the given card, and + * wait until the card gets powered up to SNDRV_CTL_POWER_D0 state. + * The refcount is down again while sleeping until power-up, hence this + * function can be used for syncing the floating control ops accesses, + * typically around calling control ops. * - * Waits until the power-state is changed. + * The caller needs to pull down the refcount via snd_power_unref() later + * no matter whether the error is returned from this function or not. * - * Return: Zero if successful, or a negative error code. + * Return: Zero if successful, or a negative error code. */ -int snd_power_wait(struct snd_card *card, unsigned int power_state) +int snd_power_ref_and_wait(struct snd_card *card) { wait_queue_entry_t wait; int result = 0; + snd_power_ref(card); /* fastpath */ - if (snd_power_get_state(card) == power_state) + if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) return 0; init_waitqueue_entry(&wait, current); add_wait_queue(&card->power_sleep, &wait); @@ -1025,13 +1036,33 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state) result = -ENODEV; break; } - if (snd_power_get_state(card) == power_state) + if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0) break; + snd_power_unref(card); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(30 * HZ); + snd_power_ref(card); } remove_wait_queue(&card->power_sleep, &wait); return result; } +EXPORT_SYMBOL_GPL(snd_power_ref_and_wait); + +/** + * snd_power_wait - wait until the card gets powered up (old form) + * @card: soundcard structure + * + * Wait until the card gets powered up to SNDRV_CTL_POWER_D0 state. + * + * Return: Zero if successful, or a negative error code. + */ +int snd_power_wait(struct snd_card *card) +{ + int ret; + + ret = snd_power_ref_and_wait(card); + snd_power_unref(card); + return ret; +} EXPORT_SYMBOL(snd_power_wait); #endif /* CONFIG_PM */ diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 966bef5acc75..83b79edfa52d 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -15,99 +15,27 @@ #include <asm/set_memory.h> #endif #include <sound/memalloc.h> +#include "memalloc_local.h" -/* - * - * Bus-specific memory allocators - * - */ - -#ifdef CONFIG_HAS_DMA -/* allocate the coherent DMA pages */ -static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) -{ - gfp_t gfp_flags; +static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab); - gfp_flags = GFP_KERNEL - | __GFP_COMP /* compound page lets parts be mapped */ - | __GFP_NORETRY /* don't trigger OOM-killer */ - | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, - gfp_flags); -#ifdef CONFIG_X86 - if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) - set_memory_wc((unsigned long)dmab->area, - PAGE_ALIGN(size) >> PAGE_SHIFT); -#endif -} - -/* free the coherent DMA pages */ -static void snd_free_dev_pages(struct snd_dma_buffer *dmab) -{ -#ifdef CONFIG_X86 - if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) - set_memory_wb((unsigned long)dmab->area, - PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); -#endif - dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); -} - -#ifdef CONFIG_GENERIC_ALLOCATOR -/** - * snd_malloc_dev_iram - allocate memory from on-chip internal ram - * @dmab: buffer allocation record to store the allocated data - * @size: number of bytes to allocate from the iram - * - * This function requires iram phandle provided via of_node - */ -static void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size) +/* a cast to gfp flag from the dev pointer; for CONTINUOUS and VMALLOC types */ +static inline gfp_t snd_mem_get_gfp_flags(const struct snd_dma_buffer *dmab, + gfp_t default_gfp) { - struct device *dev = dmab->dev.dev; - struct gen_pool *pool = NULL; - - dmab->area = NULL; - dmab->addr = 0; - - if (dev->of_node) - pool = of_gen_pool_get(dev->of_node, "iram", 0); - - if (!pool) - return; - - /* Assign the pool into private_data field */ - dmab->private_data = pool; - - dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr, - PAGE_SIZE); + if (!dmab->dev.dev) + return default_gfp; + else + return (__force gfp_t)(unsigned long)dmab->dev.dev; } -/** - * snd_free_dev_iram - free allocated specific memory from on-chip internal ram - * @dmab: buffer allocation record to store the allocated data - */ -static void snd_free_dev_iram(struct snd_dma_buffer *dmab) +static int __snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size) { - struct gen_pool *pool = dmab->private_data; - - if (pool && dmab->area) - gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes); -} -#endif /* CONFIG_GENERIC_ALLOCATOR */ -#endif /* CONFIG_HAS_DMA */ - -/* - * - * ALSA generic memory management - * - */ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); -static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev, - gfp_t default_gfp) -{ - if (!dev) - return default_gfp; - else - return (__force gfp_t)(unsigned long)dev; + if (WARN_ON_ONCE(!ops || !ops->alloc)) + return -EINVAL; + return ops->alloc(dmab, size); } /** @@ -126,7 +54,7 @@ static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev, int snd_dma_alloc_pages(int type, struct device *device, size_t size, struct snd_dma_buffer *dmab) { - gfp_t gfp; + int err; if (WARN_ON(!size)) return -ENXIO; @@ -140,43 +68,10 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->area = NULL; dmab->addr = 0; dmab->private_data = NULL; - switch (type) { - case SNDRV_DMA_TYPE_CONTINUOUS: - gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL); - dmab->area = alloc_pages_exact(size, gfp); - break; - case SNDRV_DMA_TYPE_VMALLOC: - gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM); - dmab->area = __vmalloc(size, gfp); - break; -#ifdef CONFIG_HAS_DMA -#ifdef CONFIG_GENERIC_ALLOCATOR - case SNDRV_DMA_TYPE_DEV_IRAM: - snd_malloc_dev_iram(dmab, size); - if (dmab->area) - break; - /* Internal memory might have limited size and no enough space, - * so if we fail to malloc, try to fetch memory traditionally. - */ - dmab->dev.type = SNDRV_DMA_TYPE_DEV; - fallthrough; -#endif /* CONFIG_GENERIC_ALLOCATOR */ - case SNDRV_DMA_TYPE_DEV: - case SNDRV_DMA_TYPE_DEV_UC: - snd_malloc_dev_pages(dmab, size); - break; -#endif -#ifdef CONFIG_SND_DMA_SGBUF - case SNDRV_DMA_TYPE_DEV_SG: - case SNDRV_DMA_TYPE_DEV_UC_SG: - snd_malloc_sgbuf_pages(device, size, dmab, NULL); - break; -#endif - default: - pr_err("snd-malloc: invalid device type %d\n", type); - return -ENXIO; - } - if (! dmab->area) + err = __snd_dma_alloc_pages(dmab, size); + if (err < 0) + return err; + if (!dmab->area) return -ENOMEM; dmab->bytes = size; return 0; @@ -217,7 +112,6 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, } EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); - /** * snd_dma_free_pages - release the allocated buffer * @dmab: the buffer allocation record to release @@ -226,32 +120,288 @@ EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); */ void snd_dma_free_pages(struct snd_dma_buffer *dmab) { - switch (dmab->dev.type) { - case SNDRV_DMA_TYPE_CONTINUOUS: - free_pages_exact(dmab->area, dmab->bytes); - break; - case SNDRV_DMA_TYPE_VMALLOC: - vfree(dmab->area); - break; + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->free) + ops->free(dmab); +} +EXPORT_SYMBOL(snd_dma_free_pages); + +/** + * snd_dma_buffer_mmap - perform mmap of the given DMA buffer + * @dmab: buffer allocation information + * @area: VM area information + */ +int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->mmap) + return ops->mmap(dmab, area); + else + return -ENOENT; +} +EXPORT_SYMBOL(snd_dma_buffer_mmap); + +/** + * snd_sgbuf_get_addr - return the physical address at the corresponding offset + * @dmab: buffer allocation information + * @offset: offset in the ring buffer + */ +dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset) +{ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->get_addr) + return ops->get_addr(dmab, offset); + else + return dmab->addr + offset; +} +EXPORT_SYMBOL(snd_sgbuf_get_addr); + +/** + * snd_sgbuf_get_page - return the physical page at the corresponding offset + * @dmab: buffer allocation information + * @offset: offset in the ring buffer + */ +struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset) +{ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->get_page) + return ops->get_page(dmab, offset); + else + return virt_to_page(dmab->area + offset); +} +EXPORT_SYMBOL(snd_sgbuf_get_page); + +/** + * snd_sgbuf_get_chunk_size - compute the max chunk size with continuous pages + * on sg-buffer + * @dmab: buffer allocation information + * @ofs: offset in the ring buffer + * @size: the requested size + */ +unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, + unsigned int ofs, unsigned int size) +{ + const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); + + if (ops && ops->get_chunk_size) + return ops->get_chunk_size(dmab, ofs, size); + else + return size; +} +EXPORT_SYMBOL(snd_sgbuf_get_chunk_size); + +/* + * Continuous pages allocator + */ +static int snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL); + + dmab->area = alloc_pages_exact(size, gfp); + return 0; +} + +static void snd_dma_continuous_free(struct snd_dma_buffer *dmab) +{ + free_pages_exact(dmab->area, dmab->bytes); +} + +static int snd_dma_continuous_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + return remap_pfn_range(area, area->vm_start, + dmab->addr >> PAGE_SHIFT, + area->vm_end - area->vm_start, + area->vm_page_prot); +} + +static const struct snd_malloc_ops snd_dma_continuous_ops = { + .alloc = snd_dma_continuous_alloc, + .free = snd_dma_continuous_free, + .mmap = snd_dma_continuous_mmap, +}; + +/* + * VMALLOC allocator + */ +static int snd_dma_vmalloc_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL | __GFP_HIGHMEM); + + dmab->area = __vmalloc(size, gfp); + return 0; +} + +static void snd_dma_vmalloc_free(struct snd_dma_buffer *dmab) +{ + vfree(dmab->area); +} + +static int snd_dma_vmalloc_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + return remap_vmalloc_range(area, dmab->area, 0); +} + +static dma_addr_t snd_dma_vmalloc_get_addr(struct snd_dma_buffer *dmab, + size_t offset) +{ + return page_to_phys(vmalloc_to_page(dmab->area + offset)) + + offset % PAGE_SIZE; +} + +static struct page *snd_dma_vmalloc_get_page(struct snd_dma_buffer *dmab, + size_t offset) +{ + return vmalloc_to_page(dmab->area + offset); +} + +static unsigned int +snd_dma_vmalloc_get_chunk_size(struct snd_dma_buffer *dmab, + unsigned int ofs, unsigned int size) +{ + ofs %= PAGE_SIZE; + size += ofs; + if (size > PAGE_SIZE) + size = PAGE_SIZE; + return size - ofs; +} + +static const struct snd_malloc_ops snd_dma_vmalloc_ops = { + .alloc = snd_dma_vmalloc_alloc, + .free = snd_dma_vmalloc_free, + .mmap = snd_dma_vmalloc_mmap, + .get_addr = snd_dma_vmalloc_get_addr, + .get_page = snd_dma_vmalloc_get_page, + .get_chunk_size = snd_dma_vmalloc_get_chunk_size, +}; + #ifdef CONFIG_HAS_DMA +/* + * IRAM allocator + */ #ifdef CONFIG_GENERIC_ALLOCATOR - case SNDRV_DMA_TYPE_DEV_IRAM: - snd_free_dev_iram(dmab); - break; +static int snd_dma_iram_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + struct device *dev = dmab->dev.dev; + struct gen_pool *pool; + + if (dev->of_node) { + pool = of_gen_pool_get(dev->of_node, "iram", 0); + /* Assign the pool into private_data field */ + dmab->private_data = pool; + + dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr, + PAGE_SIZE); + if (dmab->area) + return 0; + } + + /* Internal memory might have limited size and no enough space, + * so if we fail to malloc, try to fetch memory traditionally. + */ + dmab->dev.type = SNDRV_DMA_TYPE_DEV; + return __snd_dma_alloc_pages(dmab, size); +} + +static void snd_dma_iram_free(struct snd_dma_buffer *dmab) +{ + struct gen_pool *pool = dmab->private_data; + + if (pool && dmab->area) + gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes); +} + +static int snd_dma_iram_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); + return remap_pfn_range(area, area->vm_start, + dmab->addr >> PAGE_SHIFT, + area->vm_end - area->vm_start, + area->vm_page_prot); +} + +static const struct snd_malloc_ops snd_dma_iram_ops = { + .alloc = snd_dma_iram_alloc, + .free = snd_dma_iram_free, + .mmap = snd_dma_iram_mmap, +}; #endif /* CONFIG_GENERIC_ALLOCATOR */ - case SNDRV_DMA_TYPE_DEV: - case SNDRV_DMA_TYPE_DEV_UC: - snd_free_dev_pages(dmab); - break; + +/* + * Coherent device pages allocator + */ +static int snd_dma_dev_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + gfp_t gfp_flags; + + gfp_flags = GFP_KERNEL + | __GFP_COMP /* compound page lets parts be mapped */ + | __GFP_NORETRY /* don't trigger OOM-killer */ + | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ + dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, + gfp_flags); +#ifdef CONFIG_X86 + if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wc((unsigned long)dmab->area, + PAGE_ALIGN(size) >> PAGE_SHIFT); #endif + return 0; +} + +static void snd_dma_dev_free(struct snd_dma_buffer *dmab) +{ +#ifdef CONFIG_X86 + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wb((unsigned long)dmab->area, + PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); +#endif + dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); +} + +static int snd_dma_dev_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + return dma_mmap_coherent(dmab->dev.dev, area, + dmab->area, dmab->addr, dmab->bytes); +} + +static const struct snd_malloc_ops snd_dma_dev_ops = { + .alloc = snd_dma_dev_alloc, + .free = snd_dma_dev_free, + .mmap = snd_dma_dev_mmap, +}; +#endif /* CONFIG_HAS_DMA */ + +/* + * Entry points + */ +static const struct snd_malloc_ops *dma_ops[] = { + [SNDRV_DMA_TYPE_CONTINUOUS] = &snd_dma_continuous_ops, + [SNDRV_DMA_TYPE_VMALLOC] = &snd_dma_vmalloc_ops, +#ifdef CONFIG_HAS_DMA + [SNDRV_DMA_TYPE_DEV] = &snd_dma_dev_ops, + [SNDRV_DMA_TYPE_DEV_UC] = &snd_dma_dev_ops, +#ifdef CONFIG_GENERIC_ALLOCATOR + [SNDRV_DMA_TYPE_DEV_IRAM] = &snd_dma_iram_ops, +#endif /* CONFIG_GENERIC_ALLOCATOR */ +#endif /* CONFIG_HAS_DMA */ #ifdef CONFIG_SND_DMA_SGBUF - case SNDRV_DMA_TYPE_DEV_SG: - case SNDRV_DMA_TYPE_DEV_UC_SG: - snd_free_sgbuf_pages(dmab); - break; + [SNDRV_DMA_TYPE_DEV_SG] = &snd_dma_sg_ops, + [SNDRV_DMA_TYPE_DEV_UC_SG] = &snd_dma_sg_ops, #endif - default: - pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); - } +}; + +static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab) +{ + if (WARN_ON_ONCE(dmab->dev.type <= SNDRV_DMA_TYPE_UNKNOWN || + dmab->dev.type >= ARRAY_SIZE(dma_ops))) + return NULL; + return dma_ops[dmab->dev.type]; } -EXPORT_SYMBOL(snd_dma_free_pages); diff --git a/sound/core/memalloc_local.h b/sound/core/memalloc_local.h new file mode 100644 index 000000000000..dbea7f2aed07 --- /dev/null +++ b/sound/core/memalloc_local.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-only +#ifndef __MEMALLOC_LOCAL_H +#define __MEMALLOC_LOCAL_H + +struct snd_malloc_ops { + int (*alloc)(struct snd_dma_buffer *dmab, size_t size); + void (*free)(struct snd_dma_buffer *dmab); + dma_addr_t (*get_addr)(struct snd_dma_buffer *dmab, size_t offset); + struct page *(*get_page)(struct snd_dma_buffer *dmab, size_t offset); + unsigned int (*get_chunk_size)(struct snd_dma_buffer *dmab, + unsigned int ofs, unsigned int size); + int (*mmap)(struct snd_dma_buffer *dmab, struct vm_area_struct *area); +}; + +#ifdef CONFIG_SND_DMA_SGBUF +extern const struct snd_malloc_ops snd_dma_sg_ops; +#endif + +#endif /* __MEMALLOC_LOCAL_H */ diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index bec928327478..6a5abdd4271b 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -185,7 +185,8 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer) if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */ int err; unsigned int index; - if ((err = mixer->get_recsrc(fmixer, &index)) < 0) + err = mixer->get_recsrc(fmixer, &index); + if (err < 0) return err; result = 1 << index; } else { @@ -517,7 +518,8 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) { up_read(&card->controls_rwsem); return; } @@ -555,7 +557,8 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) { up_read(&card->controls_rwsem); return; } @@ -620,7 +623,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) { up_read(&card->controls_rwsem); return; } @@ -636,7 +640,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max); if (uinfo->count > 1) uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); - if ((res = kctl->put(kctl, uctl)) < 0) + res = kctl->put(kctl, uctl); + if (res < 0) goto __unalloc; if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); @@ -661,7 +666,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + kctl = snd_ctl_find_numid(card, numid); + if (!kctl) { up_read(&card->controls_rwsem); return; } @@ -681,7 +687,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, } else { uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0; } - if ((res = kctl->put(kctl, uctl)) < 0) + res = kctl->put(kctl, uctl); + if (res < 0) goto __unalloc; if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); @@ -809,9 +816,11 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = -ENOENT; goto __unlock; } - if ((err = kctl->info(kctl, uinfo)) < 0) + err = kctl->info(kctl, uinfo); + if (err < 0) goto __unlock; - if ((err = kctl->get(kctl, uctl)) < 0) + err = kctl->get(kctl, uctl); + if (err < 0) goto __unlock; for (idx = 0; idx < 32; idx++) { if (!(mixer->mask_recsrc & (1 << idx))) @@ -860,7 +869,8 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = -ENOENT; goto __unlock; } - if ((err = kctl->info(kctl, uinfo)) < 0) + err = kctl->info(kctl, uinfo); + if (err < 0) goto __unlock; for (idx = 0; idx < 32; idx++) { if (!(mixer->mask_recsrc & (1 << idx))) @@ -915,7 +925,8 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl up_read(&card->controls_rwsem); return -ENOMEM; } - if ((err = kcontrol->info(kcontrol, info)) < 0) { + err = kcontrol->info(kcontrol, info); + if (err < 0) { up_read(&card->controls_rwsem); kfree(info); return err; @@ -1036,7 +1047,10 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, if (snd_mixer_oss_build_test_all(mixer, ptr, &slot)) return 0; down_read(&mixer->card->controls_rwsem); - if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { + kctl = NULL; + if (!ptr->index) + kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); + if (kctl) { struct snd_ctl_elem_info *uinfo; uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); @@ -1343,9 +1357,10 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd) if (mixer == NULL) return -ENOMEM; mutex_init(&mixer->reg_mutex); - if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, - card, 0, - &snd_mixer_oss_f_ops, card)) < 0) { + err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, + card, 0, + &snd_mixer_oss_f_ops, card); + if (err < 0) { dev_err(card->dev, "unable to register OSS mixer device %i:%i\n", card->number, 0); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 86c39ee01aaa..82a818734a5f 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -955,9 +955,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) if (!direct) { /* add necessary plugins */ snd_pcm_oss_plugin_clear(substream); - if ((err = snd_pcm_plug_format_plugins(substream, - params, - sparams)) < 0) { + err = snd_pcm_plug_format_plugins(substream, params, sparams); + if (err < 0) { pcm_dbg(substream->pcm, "snd_pcm_plug_format_plugins failed: %i\n", err); snd_pcm_oss_plugin_clear(substream); @@ -965,7 +964,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) } if (runtime->oss.plugin_first) { struct snd_pcm_plugin *plugin; - if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) { + err = snd_pcm_plugin_build_io(substream, sparams, &plugin); + if (err < 0) { pcm_dbg(substream->pcm, "snd_pcm_plugin_build_io failed: %i\n", err); snd_pcm_oss_plugin_clear(substream); @@ -1011,7 +1011,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) sw_params->silence_size = frames; } - if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) { + err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params); + if (err < 0) { pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err); goto failure; } @@ -1573,7 +1574,8 @@ static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file) substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL); } @@ -1645,7 +1647,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) goto __direct; - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; atomic_inc(&runtime->oss.rw_ref); if (mutex_lock_interruptible(&runtime->oss.params_lock)) { @@ -1711,7 +1714,8 @@ unlock: substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream != NULL) { - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; runtime = substream->runtime; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); @@ -1758,7 +1762,8 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; return substream->runtime->oss.rate; } @@ -1795,7 +1800,8 @@ static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; return substream->runtime->oss.channels; } @@ -1805,7 +1811,8 @@ static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; return substream->runtime->oss.period_bytes; } @@ -1820,7 +1827,8 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) const struct snd_mask *format_mask; int fmt; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; if (atomic_read(&substream->mmap_count)) direct = 1; @@ -1890,7 +1898,8 @@ static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) + err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream); + if (err < 0) return err; return substream->runtime->oss.format; } @@ -2050,11 +2059,13 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (psubstream) { - if ((err = snd_pcm_oss_make_ready(psubstream)) < 0) + err = snd_pcm_oss_make_ready(psubstream); + if (err < 0) return err; } if (csubstream) { - if ((err = snd_pcm_oss_make_ready(csubstream)) < 0) + err = snd_pcm_oss_make_ready(csubstream); + if (err < 0) return err; } if (psubstream) { @@ -2141,7 +2152,8 @@ static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file) substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream == NULL) return -EINVAL; - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; runtime = substream->runtime; if (runtime->oss.params || runtime->oss.prepare) @@ -2168,7 +2180,8 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream substream = pcm_oss_file->streams[stream]; if (substream == NULL) return -EINVAL; - if ((err = snd_pcm_oss_make_ready(substream)) < 0) + err = snd_pcm_oss_make_ready(substream); + if (err < 0) return err; runtime = substream->runtime; if (runtime->oss.params || runtime->oss.prepare) { @@ -2239,9 +2252,11 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre return -EINVAL; runtime = substream->runtime; - if (runtime->oss.params && - (err = snd_pcm_oss_change_params(substream, false)) < 0) - return err; + if (runtime->oss.params) { + err = snd_pcm_oss_change_params(substream, false); + if (err < 0) + return err; + } info.fragsize = runtime->oss.period_bytes; info.fragstotal = runtime->periods; @@ -2601,7 +2616,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long case SNDCTL_DSP_SPEED: if (get_user(res, p)) return -EFAULT; - if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0) + res = snd_pcm_oss_set_rate(pcm_oss_file, res); + if (res < 0) return res; return put_user(res, p); case SOUND_PCM_READ_RATE: @@ -2613,7 +2629,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long if (get_user(res, p)) return -EFAULT; res = res > 0 ? 2 : 1; - if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0) + res = snd_pcm_oss_set_channels(pcm_oss_file, res); + if (res < 0) return res; return put_user(--res, p); case SNDCTL_DSP_GETBLKSIZE: @@ -2829,7 +2846,8 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) snd_pcm_state_t ostate; poll_wait(file, &runtime->sleep, wait); snd_pcm_stream_lock_irq(csubstream); - if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING || + ostate = runtime->status->state; + if (ostate != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_capture_ready(csubstream)) mask |= EPOLLIN | EPOLLRDNORM; snd_pcm_stream_unlock_irq(csubstream); @@ -3043,7 +3061,8 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm) struct snd_pcm_str *pstr = &pcm->streams[stream]; if (pstr->substream_count == 0) continue; - if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) { + entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root); + if (entry) { entry->content = SNDRV_INFO_CONTENT_TEXT; entry->mode = S_IFREG | 0644; entry->c.text.read = snd_pcm_oss_proc_read; @@ -3191,7 +3210,8 @@ static int __init alsa_pcm_oss_init(void) adsp_map[i] = 1; } } - if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0) + err = snd_pcm_notify(&snd_pcm_oss_notify, 0); + if (err < 0) return err; return 0; } diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index d5ca161d588c..061ba06bc926 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -59,7 +59,8 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t } else { format = &plugin->dst_format; } - if ((width = snd_pcm_format_physical_width(format->format)) < 0) + width = snd_pcm_format_physical_width(format->format); + if (width < 0) return width; size = frames * format->channels * width; if (snd_BUG_ON(size % 8)) @@ -572,7 +573,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plu } v = plugin->buf_channels; *channels = v; - if ((width = snd_pcm_format_physical_width(format->format)) < 0) + width = snd_pcm_format_physical_width(format->format); + if (width < 0) return width; nchannels = format->channels; if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && @@ -600,16 +602,17 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st while (plugin) { if (frames <= 0) return frames; - if ((next = plugin->next) != NULL) { + next = plugin->next; + if (next) { snd_pcm_sframes_t frames1 = frames; if (plugin->dst_frames) { frames1 = plugin->dst_frames(plugin, frames); if (frames1 <= 0) return frames1; } - if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) { + err = next->client_channels(next, frames1, &dst_channels); + if (err < 0) return err; - } if (err != frames1) { frames = err; if (plugin->src_frames) { @@ -621,7 +624,8 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st } else dst_channels = NULL; pdprintf("write plugin: %s, %li\n", plugin->name, frames); - if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) + frames = plugin->transfer(plugin, src_channels, dst_channels, frames); + if (frames < 0) return frames; src_channels = dst_channels; plugin = next; @@ -643,16 +647,18 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str src_channels = NULL; plugin = snd_pcm_plug_first(plug); while (plugin && frames > 0) { - if ((next = plugin->next) != NULL) { - if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) { + next = plugin->next; + if (next) { + err = plugin->client_channels(plugin, frames, &dst_channels); + if (err < 0) return err; - } frames = err; } else { dst_channels = dst_channels_final; } pdprintf("read plugin: %s, %li\n", plugin->name, frames); - if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) + frames = plugin->transfer(plugin, src_channels, dst_channels, frames); + if (frames < 0) return frames; plugin = next; src_channels = dst_channels; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index b163164a83ec..6fd3677685d7 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1004,7 +1004,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) substream->pstr->substream_opened--; } -static ssize_t show_pcm_class(struct device *dev, +static ssize_t pcm_class_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev); @@ -1024,7 +1024,7 @@ static ssize_t show_pcm_class(struct device *dev, return sprintf(buf, "%s\n", str); } -static DEVICE_ATTR(pcm_class, 0444, show_pcm_class, NULL); +static DEVICE_ATTR_RO(pcm_class); static struct attribute *pcm_dev_attrs[] = { &dev_attr_pcm_class.attr, NULL diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 590a46a9e78d..a59de24695ec 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -239,7 +239,8 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime; int err; - if (! (runtime = substream->runtime)) + runtime = substream->runtime; + if (!runtime) return -ENOTTY; data = kmalloc(sizeof(*data), GFP_KERNEL); @@ -343,7 +344,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - if ((ch = substream->runtime->channels) > 128) + ch = substream->runtime->channels; + if (ch > 128) return -EINVAL; if (get_user(buf, &data32->bufs) || get_user(frames, &data32->frames)) diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index f9a211cc1f2c..7a1b816f67cc 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c @@ -9,41 +9,85 @@ #include <sound/pcm_params.h> #include <sound/pcm_iec958.h> -static int create_iec958_consumer(uint rate, uint sample_width, - u8 *cs, size_t len) +/** + * snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Create the consumer format channel status data in @cs of maximum size + * @len. When relevant, the configuration-dependant bits will be set as + * unspecified. + * + * Drivers should then call einter snd_pcm_fill_iec958_consumer() or + * snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified + * bits by their actual values. + * + * Drivers may wish to tweak the contents of the buffer after creation. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len) { - unsigned int fs, ws; - if (len < 4) return -EINVAL; - switch (rate) { - case 32000: - fs = IEC958_AES3_CON_FS_32000; - break; - case 44100: - fs = IEC958_AES3_CON_FS_44100; - break; - case 48000: - fs = IEC958_AES3_CON_FS_48000; - break; - case 88200: - fs = IEC958_AES3_CON_FS_88200; - break; - case 96000: - fs = IEC958_AES3_CON_FS_96000; - break; - case 176400: - fs = IEC958_AES3_CON_FS_176400; - break; - case 192000: - fs = IEC958_AES3_CON_FS_192000; - break; - default: + memset(cs, 0, len); + + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; + cs[1] = IEC958_AES1_CON_GENERAL; + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID; + + if (len > 4) + cs[4] = IEC958_AES4_CON_WORDLEN_NOTID; + + return len; +} +EXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default); + +static int fill_iec958_consumer(uint rate, uint sample_width, + u8 *cs, size_t len) +{ + if (len < 4) return -EINVAL; + + if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) { + unsigned int fs; + + switch (rate) { + case 32000: + fs = IEC958_AES3_CON_FS_32000; + break; + case 44100: + fs = IEC958_AES3_CON_FS_44100; + break; + case 48000: + fs = IEC958_AES3_CON_FS_48000; + break; + case 88200: + fs = IEC958_AES3_CON_FS_88200; + break; + case 96000: + fs = IEC958_AES3_CON_FS_96000; + break; + case 176400: + fs = IEC958_AES3_CON_FS_176400; + break; + case 192000: + fs = IEC958_AES3_CON_FS_192000; + break; + default: + return -EINVAL; + } + + cs[3] &= ~IEC958_AES3_CON_FS; + cs[3] |= fs; } - if (len > 4) { + if (len > 4 && + (cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) { + unsigned int ws; + switch (sample_width) { case 16: ws = IEC958_AES4_CON_WORDLEN_20_16; @@ -64,20 +108,57 @@ static int create_iec958_consumer(uint rate, uint sample_width, default: return -EINVAL; } - } - memset(cs, 0, len); + cs[4] &= ~IEC958_AES4_CON_WORDLEN; + cs[4] |= ws; + } - cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; - cs[1] = IEC958_AES1_CON_GENERAL; - cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; - cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs; + return len; +} - if (len > 4) - cs[4] = ws; +/** + * snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status + * @runtime: pcm runtime structure with ->rate filled in + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Fill the unspecified bits in an IEC958 status bits array using the + * parameters of the PCM runtime @runtime. + * + * Drivers may wish to tweak the contents of the buffer after its been + * filled. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, + u8 *cs, size_t len) +{ + return fill_iec958_consumer(runtime->rate, + snd_pcm_format_width(runtime->format), + cs, len); +} +EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer); - return len; +/** + * snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status + * @params: the hw_params instance for extracting rate and sample format + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Fill the unspecified bits in an IEC958 status bits array using the + * parameters of the PCM hardware parameters @params. + * + * Drivers may wish to tweak the contents of the buffer after its been + * filled.. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, + u8 *cs, size_t len) +{ + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); } +EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params); /** * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status @@ -95,9 +176,13 @@ static int create_iec958_consumer(uint rate, uint sample_width, int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, size_t len) { - return create_iec958_consumer(runtime->rate, - snd_pcm_format_width(runtime->format), - cs, len); + int ret; + + ret = snd_pcm_create_iec958_consumer_default(cs, len); + if (ret < 0) + return ret; + + return snd_pcm_fill_iec958_consumer(runtime, cs, len); } EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); @@ -117,7 +202,12 @@ EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, u8 *cs, size_t len) { - return create_iec958_consumer(params_rate(params), params_width(params), - cs, len); + int ret; + + ret = snd_pcm_create_iec958_consumer_default(cs, len); + if (ret < 0) + return ret; + + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); } EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b7e3d8f44511..7d5883432085 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1778,27 +1778,38 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, EXPORT_SYMBOL(snd_pcm_lib_ioctl); /** - * snd_pcm_period_elapsed - update the pcm status for the next period - * @substream: the pcm substream instance + * snd_pcm_period_elapsed_under_stream_lock() - update the status of runtime for the next period + * under acquired lock of PCM substream. + * @substream: the instance of pcm substream. + * + * This function is called when the batch of audio data frames as the same size as the period of + * buffer is already processed in audio data transmission. + * + * The call of function updates the status of runtime with the latest position of audio data + * transmission, checks overrun and underrun over buffer, awaken user processes from waiting for + * available audio data frames, sampling audio timestamp, and performs stop or drain the PCM + * substream according to configured threshold. + * + * The function is intended to use for the case that PCM driver operates audio data frames under + * acquired lock of PCM substream; e.g. in callback of any operation of &snd_pcm_ops in process + * context. In any interrupt context, it's preferrable to use ``snd_pcm_period_elapsed()`` instead + * since lock of PCM substream should be acquired in advance. * - * This function is called from the interrupt handler when the - * PCM has processed the period size. It will update the current - * pointer, wake up sleepers, etc. + * Developer should pay enough attention that some callbacks in &snd_pcm_ops are done by the call of + * function: * - * Even if more than one periods have elapsed since the last call, you - * have to call this only once. + * - .pointer - to retrieve current position of audio data transmission by frame count or XRUN state. + * - .trigger - with SNDRV_PCM_TRIGGER_STOP at XRUN or DRAINING state. + * - .get_time_info - to retrieve audio time stamp if needed. + * + * Even if more than one periods have elapsed since the last call, you have to call this only once. */ -void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) +void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; - unsigned long flags; - if (snd_BUG_ON(!substream)) - return; - - snd_pcm_stream_lock_irqsave(substream, flags); if (PCM_RUNTIME_CHECK(substream)) - goto _unlock; + return; runtime = substream->runtime; if (!snd_pcm_running(substream) || @@ -1811,7 +1822,30 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) #endif _end: kill_fasync(&runtime->fasync, SIGIO, POLL_IN); - _unlock: +} +EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock); + +/** + * snd_pcm_period_elapsed() - update the status of runtime for the next period by acquiring lock of + * PCM substream. + * @substream: the instance of PCM substream. + * + * This function is mostly similar to ``snd_pcm_period_elapsed_under_stream_lock()`` except for + * acquiring lock of PCM substream voluntarily. + * + * It's typically called by any type of IRQ handler when hardware IRQ occurs to notify event that + * the batch of audio data frames as the same size as the period of buffer is already processed in + * audio data transmission. + */ +void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) +{ + unsigned long flags; + + if (snd_BUG_ON(!substream)) + return; + + snd_pcm_stream_lock_irqsave(substream, flags); + snd_pcm_period_elapsed_under_stream_lock(substream); snd_pcm_stream_unlock_irqrestore(substream, flags); } EXPORT_SYMBOL(snd_pcm_period_elapsed); diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index e3b3558aeab6..fe9689b8a6a6 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -65,11 +65,6 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream); void snd_pcm_group_init(struct snd_pcm_group *group); void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq); -#ifdef CONFIG_SND_DMA_SGBUF -struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, - unsigned long offset); -#endif - #define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime) /* loop over all PCM substreams */ diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 542a75babdee..d7621ed105bd 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -337,27 +337,6 @@ void snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type, } EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all); -#ifdef CONFIG_SND_DMA_SGBUF -/* - * snd_pcm_sgbuf_ops_page - get the page struct at the given offset - * @substream: the pcm substream instance - * @offset: the buffer offset - * - * Used as the page callback of PCM ops. - * - * Return: The page struct at the given buffer offset. %NULL on failure. - */ -struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset) -{ - struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - - unsigned int idx = offset >> PAGE_SHIFT; - if (idx >= (unsigned int)sgbuf->pages) - return NULL; - return sgbuf->page_table[idx]; -} -#endif /* CONFIG_SND_DMA_SGBUF */ - /** * snd_pcm_lib_malloc_pages - allocate the DMA buffer * @substream: the substream to allocate the DMA buffer to diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 257d412eac5d..4866aed97aac 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -266,7 +266,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format) int val; if (!valid_format(format)) return -EINVAL; - if ((val = pcm_formats[(INT)format].signd) < 0) + val = pcm_formats[(INT)format].signd; + if (val < 0) return -EINVAL; return val; } @@ -314,7 +315,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) int val; if (!valid_format(format)) return -EINVAL; - if ((val = pcm_formats[(INT)format].le) < 0) + val = pcm_formats[(INT)format].le; + if (val < 0) return -EINVAL; return val; } @@ -350,7 +352,8 @@ int snd_pcm_format_width(snd_pcm_format_t format) int val; if (!valid_format(format)) return -EINVAL; - if ((val = pcm_formats[(INT)format].width) == 0) + val = pcm_formats[(INT)format].width; + if (!val) return -EINVAL; return val; } @@ -368,7 +371,8 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) int val; if (!valid_format(format)) return -EINVAL; - if ((val = pcm_formats[(INT)format].phys) == 0) + val = pcm_formats[(INT)format].phys; + if (!val) return -EINVAL; return val; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8dbe86cf2e4f..14e32825c339 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -768,7 +768,8 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req)) cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); - if ((usecs = period_to_usecs(runtime)) >= 0) + usecs = period_to_usecs(runtime); + if (usecs >= 0) cpu_latency_qos_add_request(&substream->latency_pm_qos_req, usecs); return 0; @@ -2658,7 +2659,8 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, goto error; } - if ((err = substream->ops->open(substream)) < 0) + err = substream->ops->open(substream); + if (err < 0) goto error; substream->hw_opened = 1; @@ -2799,6 +2801,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file) if (snd_BUG_ON(!substream)) return -ENXIO; pcm = substream->pcm; + + /* block until the device gets woken up as it may touch the hardware */ + snd_power_wait(pcm->card); + mutex_lock(&pcm->open_mutex); snd_pcm_release_substream(substream); kfree(pcm_file); @@ -3193,7 +3199,7 @@ static int snd_pcm_common_ioctl(struct file *file, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; - res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0); + res = snd_power_wait(substream->pcm->card); if (res < 0) return res; @@ -3638,24 +3644,6 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file } #endif /* coherent mmap */ -static inline struct page * -snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) -{ - void *vaddr = substream->runtime->dma_area + ofs; - - switch (substream->dma_buffer.dev.type) { -#ifdef CONFIG_SND_DMA_SGBUF - case SNDRV_DMA_TYPE_DEV_SG: - case SNDRV_DMA_TYPE_DEV_UC_SG: - return snd_pcm_sgbuf_ops_page(substream, ofs); -#endif /* CONFIG_SND_DMA_SGBUF */ - case SNDRV_DMA_TYPE_VMALLOC: - return vmalloc_to_page(vaddr); - default: - return virt_to_page(vaddr); - } -} - /* * fault callback for mmapping a RAM page */ @@ -3677,7 +3665,7 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf) if (substream->ops->page) page = substream->ops->page(substream, offset); else - page = snd_pcm_default_page_ops(substream, offset); + page = snd_sgbuf_get_page(snd_pcm_get_dma_buf(substream), offset); if (!page) return VM_FAULT_SIGBUS; get_page(page); @@ -3712,22 +3700,9 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) { area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; -#ifdef CONFIG_GENERIC_ALLOCATOR - if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) { - area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); - return remap_pfn_range(area, area->vm_start, - substream->dma_buffer.addr >> PAGE_SHIFT, - area->vm_end - area->vm_start, area->vm_page_prot); - } -#endif /* CONFIG_GENERIC_ALLOCATOR */ - if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page && - (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV || - substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_UC)) - return dma_mmap_coherent(substream->dma_buffer.dev.dev, - area, - substream->runtime->dma_area, - substream->runtime->dma_addr, - substream->runtime->dma_bytes); + if (!substream->ops->page && + !snd_dma_buffer_mmap(snd_pcm_get_dma_buf(substream), area)) + return 0; /* mmap with fault handler */ area->vm_ops = &snd_pcm_vm_ops_data_fault; return 0; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index aca00af93afe..6c0a4a67ad2e 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -680,9 +680,12 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, bool is_input) { char *newbuf, *oldbuf; + unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) return -EINVAL; + if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP && (params->buffer_size & 0x1f) != 0) + return -EINVAL; if (params->avail_min < 1 || params->avail_min > params->buffer_size) return -EINVAL; if (params->buffer_size != runtime->buffer_size) { @@ -720,8 +723,24 @@ EXPORT_SYMBOL(snd_rawmidi_output_params); int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params *params) { + unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; + unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK; + int err; + + if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE) + return -EINVAL; + else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW) + return -EINVAL; + if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) + return -EINVAL; snd_rawmidi_drain_input(substream); - return resize_runtime_buffer(substream->runtime, params, true); + err = resize_runtime_buffer(substream->runtime, params, true); + if (err < 0) + return err; + + substream->framing = framing; + substream->clock_type = clock_type; + return 0; } EXPORT_SYMBOL(snd_rawmidi_input_params); @@ -963,6 +982,62 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, return -ENOIOCTLCMD; } +static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream, + const unsigned char *buffer, int src_count, const struct timespec64 *tstamp) +{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_framing_tstamp *dest_ptr; + struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec }; + int dest_frames = 0; + int orig_count = src_count; + int frame_size = sizeof(struct snd_rawmidi_framing_tstamp); + + BUILD_BUG_ON(frame_size != 0x20); + if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0)) + return -EINVAL; + + while (src_count > 0) { + if ((int)(runtime->buffer_size - runtime->avail) < frame_size) { + runtime->xruns += src_count; + break; + } + if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH) + frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH; + else { + frame.length = src_count; + memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH); + } + memcpy(frame.data, buffer, frame.length); + buffer += frame.length; + src_count -= frame.length; + dest_ptr = (struct snd_rawmidi_framing_tstamp *) (runtime->buffer + runtime->hw_ptr); + *dest_ptr = frame; + runtime->avail += frame_size; + runtime->hw_ptr += frame_size; + runtime->hw_ptr %= runtime->buffer_size; + dest_frames++; + } + return orig_count - src_count; +} + +static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substream) +{ + struct timespec64 ts64 = {0, 0}; + + switch (substream->clock_type) { + case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW: + ktime_get_raw_ts64(&ts64); + break; + case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC: + ktime_get_ts64(&ts64); + break; + case SNDRV_RAWMIDI_MODE_CLOCK_REALTIME: + ktime_get_real_ts64(&ts64); + break; + } + return ts64; +} + /** * snd_rawmidi_receive - receive the input data from the device * @substream: the rawmidi substream @@ -977,6 +1052,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, const unsigned char *buffer, int count) { unsigned long flags; + struct timespec64 ts64 = get_framing_tstamp(substream); int result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -987,8 +1063,11 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, "snd_rawmidi_receive: input is not active!!!\n"); return -EINVAL; } + spin_lock_irqsave(&runtime->lock, flags); - if (count == 1) { /* special case, faster code */ + if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { + result = receive_with_tstamp_framing(substream, buffer, count, &ts64); + } else if (count == 1) { /* special case, faster code */ substream->bytes++; if (runtime->avail < runtime->buffer_size) { runtime->buffer[runtime->hw_ptr++] = buffer[0]; @@ -1541,6 +1620,8 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; unsigned long buffer_size, avail, xruns; + unsigned int clock_type; + static const char *clock_names[4] = { "none", "realtime", "monotonic", "monotonic raw" }; rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); @@ -1596,6 +1677,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Avail : %lu\n" " Overruns : %lu\n", buffer_size, avail, xruns); + if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { + clock_type = substream->clock_type >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT; + if (!snd_BUG_ON(clock_type >= ARRAY_SIZE(clock_names))) + snd_iprintf(buffer, + " Framing : tstamp\n" + " Clock type : %s\n", + clock_names[clock_type]); + } } } } diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c index 7397130976d0..68a93443583c 100644 --- a/sound/core/rawmidi_compat.c +++ b/sound/core/rawmidi_compat.c @@ -13,7 +13,8 @@ struct snd_rawmidi_params32 { u32 buffer_size; u32 avail_min; unsigned int no_active_sensing; /* avoid bit-field */ - unsigned char reserved[16]; + unsigned int mode; + unsigned char reserved[12]; } __attribute__((packed)); static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, @@ -25,6 +26,7 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, if (get_user(params.stream, &src->stream) || get_user(params.buffer_size, &src->buffer_size) || get_user(params.avail_min, &src->avail_min) || + get_user(params.mode, &src->mode) || get_user(val, &src->no_active_sensing)) return -EFAULT; params.no_active_sensing = val; diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 250a92b18726..77c1214acd90 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -67,13 +67,16 @@ static int __init alsa_seq_oss_init(void) { int rc; - if ((rc = register_device()) < 0) + rc = register_device(); + if (rc < 0) goto error; - if ((rc = register_proc()) < 0) { + rc = register_proc(); + if (rc < 0) { unregister_device(); goto error; } - if ((rc = snd_seq_oss_create_client()) < 0) { + rc = snd_seq_oss_create_client(); + if (rc < 0) { unregister_proc(); unregister_device(); goto error; @@ -133,7 +136,8 @@ odev_release(struct inode *inode, struct file *file) { struct seq_oss_devinfo *dp; - if ((dp = file->private_data) == NULL) + dp = file->private_data; + if (!dp) return 0; mutex_lock(®ister_mutex); @@ -226,16 +230,18 @@ register_device(void) int rc; mutex_lock(®ister_mutex); - if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, - NULL, 0, - &seq_oss_f_ops, NULL)) < 0) { + rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, + NULL, 0, + &seq_oss_f_ops, NULL); + if (rc < 0) { pr_err("ALSA: seq_oss: can't register device seq\n"); mutex_unlock(®ister_mutex); return rc; } - if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, - NULL, 0, - &seq_oss_f_ops, NULL)) < 0) { + rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, + NULL, 0, + &seq_oss_f_ops, NULL); + if (rc < 0) { pr_err("ALSA: seq_oss: can't register device music\n"); snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0); mutex_unlock(®ister_mutex); diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 4534a154b8c8..0ee4a5081fd6 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -94,10 +94,10 @@ snd_seq_oss_create_client(void) port_callback.event_input = receive_announce; port->kernel = &port_callback; - call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port); - if ((system_port = port->addr.port) >= 0) { + if (call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port) >= 0) { struct snd_seq_port_subscribe subs; + system_port = port->addr.port; memset(&subs, 0, sizeof(subs)); subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; @@ -354,7 +354,8 @@ alloc_seq_queue(struct seq_oss_devinfo *dp) qinfo.owner = system_client; qinfo.locked = 1; strcpy(qinfo.name, "OSS Sequencer Emulation"); - if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0) + rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo); + if (rc < 0) return rc; dp->queue = qinfo.queue; return 0; @@ -485,7 +486,8 @@ snd_seq_oss_system_info_read(struct snd_info_buffer *buf) snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients); for (i = 0; i < num_clients; i++) { snd_iprintf(buf, "\nApplication %d: ", i); - if ((dp = client_table[i]) == NULL) { + dp = client_table[i]; + if (!dp) { snd_iprintf(buf, "*empty*\n"); continue; } diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 3f82c196de46..1e3bf086f867 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -152,7 +152,8 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) /* * look for the identical slot */ - if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) { + mdev = find_slot(pinfo->addr.client, pinfo->addr.port); + if (mdev) { /* already exists */ snd_use_lock_free(&mdev->use_lock); return 0; @@ -218,7 +219,8 @@ snd_seq_oss_midi_check_exit_port(int client, int port) unsigned long flags; int index; - if ((mdev = find_slot(client, port)) != NULL) { + mdev = find_slot(client, port); + if (mdev) { spin_lock_irqsave(®ister_lock, flags); midi_devs[mdev->seq_device] = NULL; spin_unlock_irqrestore(®ister_lock, flags); @@ -250,7 +252,8 @@ snd_seq_oss_midi_clear_all(void) spin_lock_irqsave(®ister_lock, flags); for (i = 0; i < max_midi_devs; i++) { - if ((mdev = midi_devs[i]) != NULL) { + mdev = midi_devs[i]; + if (mdev) { snd_midi_event_free(mdev->coder); kfree(mdev); midi_devs[i] = NULL; @@ -318,7 +321,8 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) struct seq_oss_midi *mdev; struct snd_seq_port_subscribe subs; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return -ENODEV; /* already used? */ @@ -384,7 +388,8 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) struct seq_oss_midi *mdev; struct snd_seq_port_subscribe subs; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return -ENODEV; if (! mdev->opened || mdev->devinfo != dp) { snd_use_lock_free(&mdev->use_lock); @@ -421,7 +426,8 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) struct seq_oss_midi *mdev; int mode; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return 0; mode = 0; @@ -443,7 +449,8 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_midi *mdev; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return; if (! mdev->opened) { snd_use_lock_free(&mdev->use_lock); @@ -491,7 +498,8 @@ snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_ad { struct seq_oss_midi *mdev; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return; addr->client = mdev->client; addr->port = mdev->port; @@ -511,7 +519,8 @@ snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data) if (dp->readq == NULL) return 0; - if ((mdev = find_slot(ev->source.client, ev->source.port)) == NULL) + mdev = find_slot(ev->source.client, ev->source.port); + if (!mdev) return 0; if (! (mdev->opened & PERM_READ)) { snd_use_lock_free(&mdev->use_lock); @@ -623,7 +632,8 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru { struct seq_oss_midi *mdev; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return -ENODEV; if (snd_midi_event_encode_byte(mdev->coder, c, ev)) { snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port); @@ -642,7 +652,8 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info { struct seq_oss_midi *mdev; - if ((mdev = get_mididev(dp, dev)) == NULL) + mdev = get_mididev(dp, dev); + if (!mdev) return -ENXIO; inf->device = dev; inf->dev_type = 0; /* FIXME: ?? */ diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c index 537d5f423e20..8a142fd54a19 100644 --- a/sound/core/seq/oss/seq_oss_rw.c +++ b/sound/core/seq/oss/seq_oss_rw.c @@ -132,7 +132,8 @@ snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count, } /* insert queue */ - if ((err = insert_queue(dp, &rec, opt)) < 0) + err = insert_queue(dp, &rec, opt); + if (err < 0) break; result += ev_size; diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 722f5059b300..e3394919daa0 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -451,7 +451,8 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, if (info->is_midi) return 0; - if ((rec = get_synthdev(dp, dev)) == NULL) + rec = get_synthdev(dp, dev); + if (!rec) return -ENXIO; if (rec->oper.load_patch == NULL) @@ -569,7 +570,8 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u info = get_synthinfo_nospec(dp, dev); if (!info || info->is_midi) return -ENXIO; - if ((rec = get_synthdev(dp, dev)) == NULL) + rec = get_synthdev(dp, dev); + if (!rec) return -ENXIO; if (rec->oper.ioctl == NULL) rc = -ENXIO; @@ -619,7 +621,8 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in inf->device = dev; strscpy(inf->name, minf.name, sizeof(inf->name)); } else { - if ((rec = get_synthdev(dp, dev)) == NULL) + rec = get_synthdev(dp, dev); + if (!rec) return -ENXIO; inf->synth_type = rec->synth_type; inf->synth_subtype = rec->synth_subtype; diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 0a02a59103b4..3e3209ce53b1 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -27,7 +27,8 @@ snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen) struct seq_oss_writeq *q; struct snd_seq_client_pool pool; - if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) + q = kzalloc(sizeof(*q), GFP_KERNEL); + if (!q) return NULL; q->dp = dp; q->maxlen = maxlen; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index b6a24fb5e76b..2e9d695d336c 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -416,7 +416,10 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, if (snd_BUG_ON(!client)) return -ENXIO; - if (!client->accept_input || (fifo = client->data.user.fifo) == NULL) + if (!client->accept_input) + return -ENXIO; + fifo = client->data.user.fifo; + if (!fifo) return -ENXIO; if (atomic_read(&fifo->overflow) > 0) { @@ -435,9 +438,9 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, int nonblock; nonblock = (file->f_flags & O_NONBLOCK) || result > 0; - if ((err = snd_seq_fifo_cell_out(fifo, &cell, nonblock)) < 0) { + err = snd_seq_fifo_cell_out(fifo, &cell, nonblock); + if (err < 0) break; - } if (snd_seq_ev_is_variable(&cell->event)) { struct snd_seq_event tmpev; tmpev = cell->event; @@ -970,7 +973,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, return err; /* we got a cell. enqueue it. */ - if ((err = snd_seq_enqueue_event(cell, atomic, hop)) < 0) { + err = snd_seq_enqueue_event(cell, atomic, hop); + if (err < 0) { snd_seq_cell_free(cell); return err; } @@ -1312,7 +1316,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) return -EINVAL; } if (client->type == KERNEL_CLIENT) { - if ((callback = info->kernel) != NULL) { + callback = info->kernel; + if (callback) { if (callback->owner) port->owner = callback->owner; port->private_data = callback->private_data; @@ -1466,13 +1471,17 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client, struct snd_seq_client *receiver = NULL, *sender = NULL; struct snd_seq_client_port *sport = NULL, *dport = NULL; - if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL) + receiver = snd_seq_client_use_ptr(subs->dest.client); + if (!receiver) goto __end; - if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) + sender = snd_seq_client_use_ptr(subs->sender.client); + if (!sender) goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) + sport = snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) goto __end; - if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL) + dport = snd_seq_port_use_ptr(receiver, subs->dest.port); + if (!dport) goto __end; result = check_subscription_permission(client, sport, dport, subs); @@ -1508,13 +1517,17 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client, struct snd_seq_client *receiver = NULL, *sender = NULL; struct snd_seq_client_port *sport = NULL, *dport = NULL; - if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL) + receiver = snd_seq_client_use_ptr(subs->dest.client); + if (!receiver) goto __end; - if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) + sender = snd_seq_client_use_ptr(subs->sender.client); + if (!sender) goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) + sport = snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) goto __end; - if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL) + dport = snd_seq_port_use_ptr(receiver, subs->dest.port); + if (!dport) goto __end; result = check_subscription_permission(client, sport, dport, subs); @@ -1926,9 +1939,11 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client, struct snd_seq_client_port *sport = NULL; result = -EINVAL; - if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) + sender = snd_seq_client_use_ptr(subs->sender.client); + if (!sender) goto __end; - if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) + sport = snd_seq_port_use_ptr(sender, subs->sender.port); + if (!sport) goto __end; result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest, subs); @@ -1955,9 +1970,11 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) struct list_head *p; int i; - if ((cptr = snd_seq_client_use_ptr(subs->root.client)) == NULL) + cptr = snd_seq_client_use_ptr(subs->root.client); + if (!cptr) goto __end; - if ((port = snd_seq_port_use_ptr(cptr, subs->root.port)) == NULL) + port = snd_seq_port_use_ptr(cptr, subs->root.port); + if (!port) goto __end; switch (subs->type) { diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index cd5a4cad8881..ac760b1e3d12 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -109,7 +109,8 @@ create_port(int idx, int type) struct snd_seq_port_callback pcb; struct snd_seq_dummy_port *rec; - if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) + rec = kzalloc(sizeof(*rec), GFP_KERNEL); + if (!rec) return NULL; rec->client = my_client; diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index eaaa8b5830bb..f8e02e98709a 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -143,7 +143,8 @@ static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f) { struct snd_seq_event_cell *cell; - if ((cell = f->head) != NULL) { + cell = f->head; + if (cell) { f->head = cell->next; /* reset tail if this was the last element */ diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index e245bb6ba533..b7aee23fc387 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -69,7 +69,8 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, int len, err; struct snd_seq_event_cell *cell; - if ((len = get_var_len(event)) <= 0) + len = get_var_len(event); + if (len <= 0) return len; if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { @@ -133,7 +134,8 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char int len, newlen; int err; - if ((len = get_var_len(event)) < 0) + len = get_var_len(event); + if (len < 0) return len; newlen = len; if (size_aligned > 0) diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 6825940ea2cf..4589aac09154 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -101,7 +101,8 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i if (snd_BUG_ON(!substream || !buf)) return -EINVAL; runtime = substream->runtime; - if ((tmp = runtime->avail) < count) { + tmp = runtime->avail; + if (tmp < count) { if (printk_ratelimit()) pr_err("ALSA: seq_midi: MIDI output buffer overrun\n"); return -ENOMEM; @@ -167,10 +168,11 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe struct snd_rawmidi_params params; /* open midi port */ - if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device, - msynth->subdevice, - SNDRV_RAWMIDI_LFLG_INPUT, - &msynth->input_rfile)) < 0) { + err = snd_rawmidi_kernel_open(msynth->card, msynth->device, + msynth->subdevice, + SNDRV_RAWMIDI_LFLG_INPUT, + &msynth->input_rfile); + if (err < 0) { pr_debug("ALSA: seq_midi: midi input open failed!!!\n"); return err; } @@ -178,7 +180,8 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe memset(¶ms, 0, sizeof(params)); params.avail_min = 1; params.buffer_size = input_buffer_size; - if ((err = snd_rawmidi_input_params(msynth->input_rfile.input, ¶ms)) < 0) { + err = snd_rawmidi_input_params(msynth->input_rfile.input, ¶ms); + if (err < 0) { snd_rawmidi_kernel_release(&msynth->input_rfile); return err; } @@ -209,10 +212,11 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info struct snd_rawmidi_params params; /* open midi port */ - if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device, - msynth->subdevice, - SNDRV_RAWMIDI_LFLG_OUTPUT, - &msynth->output_rfile)) < 0) { + err = snd_rawmidi_kernel_open(msynth->card, msynth->device, + msynth->subdevice, + SNDRV_RAWMIDI_LFLG_OUTPUT, + &msynth->output_rfile); + if (err < 0) { pr_debug("ALSA: seq_midi: midi output open failed!!!\n"); return err; } @@ -220,7 +224,8 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info params.avail_min = 1; params.buffer_size = output_buffer_size; params.no_active_sensing = 1; - if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, ¶ms)) < 0) { + err = snd_rawmidi_output_params(msynth->output_rfile.output, ¶ms); + if (err < 0) { snd_rawmidi_kernel_release(&msynth->output_rfile); return err; } diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 13cfc2d47fa7..d6c02dea976c 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -222,7 +222,8 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name) struct snd_seq_queue *q; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) != NULL) { + q = queueptr(i); + if (q) { if (strncmp(q->name, name, sizeof(q->name)) == 0) return q; queuefree(q); @@ -432,7 +433,8 @@ int snd_seq_queue_timer_open(int queueid) if (queue == NULL) return -EINVAL; tmr = queue->timer; - if ((result = snd_seq_timer_open(queue)) < 0) { + result = snd_seq_timer_open(queue); + if (result < 0) { snd_seq_timer_defaults(tmr); result = snd_seq_timer_open(queue); } @@ -548,7 +550,8 @@ void snd_seq_queue_client_leave(int client) /* delete own queues from queue list */ for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queue_list_remove(i, client)) != NULL) + q = queue_list_remove(i, client); + if (q) queue_delete(q); } @@ -556,7 +559,8 @@ void snd_seq_queue_client_leave(int client) * they are not owned by this client */ for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) + q = queueptr(i); + if (!q) continue; if (test_bit(client, q->clients_bitmap)) { snd_seq_prioq_leave(q->tickq, client, 0); @@ -578,7 +582,8 @@ void snd_seq_queue_client_leave_cells(int client) struct snd_seq_queue *q; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) + q = queueptr(i); + if (!q) continue; snd_seq_prioq_leave(q->tickq, client, 0); snd_seq_prioq_leave(q->timeq, client, 0); @@ -593,7 +598,8 @@ void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info) struct snd_seq_queue *q; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) + q = queueptr(i); + if (!q) continue; if (test_bit(client, q->clients_bitmap) && (! (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) || @@ -724,7 +730,8 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, int owner; for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) + q = queueptr(i); + if (!q) continue; tmr = q->timer; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 77d7037d1476..4abc38c70cae 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -482,10 +482,11 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi int err; *rrmidi = NULL; - if ((err = snd_rawmidi_new(card, "VirMidi", device, - 16, /* may be configurable */ - 16, /* may be configurable */ - &rmidi)) < 0) + err = snd_rawmidi_new(card, "VirMidi", device, + 16, /* may be configurable */ + 16, /* may be configurable */ + &rmidi); + if (err < 0) return err; strcpy(rmidi->name, rmidi->id); rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index 29ddb76187e5..232cf3f1bcb3 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -10,20 +10,34 @@ #include <linux/vmalloc.h> #include <linux/export.h> #include <sound/memalloc.h> - +#include "memalloc_local.h" + +struct snd_sg_page { + void *buf; + dma_addr_t addr; +}; + +struct snd_sg_buf { + int size; /* allocated byte size */ + int pages; /* allocated pages */ + int tblsize; /* allocated table size */ + struct snd_sg_page *table; /* address table */ + struct page **page_table; /* page table (for vmap/vunmap) */ + struct device *dev; +}; /* table entries are align to 32 */ #define SGBUF_TBL_ALIGN 32 #define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN) -int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) +static void snd_dma_sg_free(struct snd_dma_buffer *dmab) { struct snd_sg_buf *sgbuf = dmab->private_data; struct snd_dma_buffer tmpb; int i; - if (! sgbuf) - return -EINVAL; + if (!sgbuf) + return; vunmap(dmab->area); dmab->area = NULL; @@ -45,15 +59,11 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) kfree(sgbuf->page_table); kfree(sgbuf); dmab->private_data = NULL; - - return 0; } #define MAX_ALLOC_PAGES 32 -void *snd_malloc_sgbuf_pages(struct device *device, - size_t size, struct snd_dma_buffer *dmab, - size_t *res_size) +static int snd_dma_sg_alloc(struct snd_dma_buffer *dmab, size_t size) { struct snd_sg_buf *sgbuf; unsigned int i, pages, chunk, maxpages; @@ -63,18 +73,16 @@ void *snd_malloc_sgbuf_pages(struct device *device, int type = SNDRV_DMA_TYPE_DEV; pgprot_t prot = PAGE_KERNEL; - dmab->area = NULL; - dmab->addr = 0; dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); - if (! sgbuf) - return NULL; + if (!sgbuf) + return -ENOMEM; if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) { type = SNDRV_DMA_TYPE_DEV_UC; #ifdef pgprot_noncached prot = pgprot_noncached(PAGE_KERNEL); #endif } - sgbuf->dev = device; + sgbuf->dev = dmab->dev.dev; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL); @@ -94,12 +102,10 @@ void *snd_malloc_sgbuf_pages(struct device *device, if (chunk > maxpages) chunk = maxpages; chunk <<= PAGE_SHIFT; - if (snd_dma_alloc_pages_fallback(type, device, + if (snd_dma_alloc_pages_fallback(type, dmab->dev.dev, chunk, &tmpb) < 0) { if (!sgbuf->pages) goto _failed; - if (!res_size) - goto _failed; size = sgbuf->pages * PAGE_SIZE; break; } @@ -124,27 +130,42 @@ void *snd_malloc_sgbuf_pages(struct device *device, dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot); if (! dmab->area) goto _failed; - if (res_size) - *res_size = sgbuf->size; - return dmab->area; + return 0; _failed: - snd_free_sgbuf_pages(dmab); /* free the table */ - return NULL; + snd_dma_sg_free(dmab); /* free the table */ + return -ENOMEM; } -/* - * compute the max chunk size with continuous pages on sg-buffer - */ -unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, - unsigned int ofs, unsigned int size) +static dma_addr_t snd_dma_sg_get_addr(struct snd_dma_buffer *dmab, + size_t offset) +{ + struct snd_sg_buf *sgbuf = dmab->private_data; + dma_addr_t addr; + + addr = sgbuf->table[offset >> PAGE_SHIFT].addr; + addr &= ~((dma_addr_t)PAGE_SIZE - 1); + return addr + offset % PAGE_SIZE; +} + +static struct page *snd_dma_sg_get_page(struct snd_dma_buffer *dmab, + size_t offset) +{ + struct snd_sg_buf *sgbuf = dmab->private_data; + unsigned int idx = offset >> PAGE_SHIFT; + + if (idx >= (unsigned int)sgbuf->pages) + return NULL; + return sgbuf->page_table[idx]; +} + +static unsigned int snd_dma_sg_get_chunk_size(struct snd_dma_buffer *dmab, + unsigned int ofs, + unsigned int size) { struct snd_sg_buf *sg = dmab->private_data; unsigned int start, end, pg; - if (!sg) - return size; - start = ofs >> PAGE_SHIFT; end = (ofs + size - 1) >> PAGE_SHIFT; /* check page continuity */ @@ -160,4 +181,11 @@ unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, /* ok, all on continuous pages */ return size; } -EXPORT_SYMBOL(snd_sgbuf_get_chunk_size); + +const struct snd_malloc_ops snd_dma_sg_ops = { + .alloc = snd_dma_sg_alloc, + .free = snd_dma_sg_free, + .get_addr = snd_dma_sg_get_addr, + .get_page = snd_dma_sg_get_page, + .get_chunk_size = snd_dma_sg_get_chunk_size, +}; diff --git a/sound/core/sound.c b/sound/core/sound.c index af89e51dd44a..df5571d98629 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -357,7 +357,8 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu mutex_lock(&sound_mutex); for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { - if (!(mptr = snd_minors[minor])) + mptr = snd_minors[minor]; + if (!mptr) continue; if (mptr->card >= 0) { if (mptr->device >= 0) diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 610f317bea9d..7ed0a2a91035 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -217,7 +217,8 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry, mutex_lock(&sound_oss_mutex); for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) { - if (!(mptr = snd_oss_minors[minor])) + mptr = snd_oss_minors[minor]; + if (!mptr) continue; if (mptr->card >= 0) snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", minor, diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 8c552e25805a..d0b55dbb411a 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c @@ -104,7 +104,8 @@ static int snd_mpu401_probe(struct platform_device *devptr) err = snd_mpu401_create(&devptr->dev, dev, &card); if (err < 0) return err; - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } @@ -182,7 +183,8 @@ static int snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev, err = snd_mpu401_create(&pnp_dev->dev, dev, &card); if (err < 0) return err; - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } @@ -227,7 +229,8 @@ static int __init alsa_card_mpu401_init(void) { int i, err; - if ((err = platform_driver_register(&snd_mpu401_driver)) < 0) + err = platform_driver_register(&snd_mpu401_driver); + if (err < 0) return err; for (i = 0; i < SNDRV_CARDS; i++) { diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 65982d6babfc..f435b9b4ae24 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -271,8 +271,11 @@ static int snd_mpu401_uart_input_open(struct snd_rawmidi_substream *substream) int err; mpu = substream->rmidi->private_data; - if (mpu->open_input && (err = mpu->open_input(mpu)) < 0) - return err; + if (mpu->open_input) { + err = mpu->open_input(mpu); + if (err < 0) + return err; + } if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) { if (snd_mpu401_do_reset(mpu) < 0) goto error_out; @@ -293,8 +296,11 @@ static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream) int err; mpu = substream->rmidi->private_data; - if (mpu->open_output && (err = mpu->open_output(mpu)) < 0) - return err; + if (mpu->open_output) { + err = mpu->open_output(mpu); + if (err < 0) + return err; + } if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { if (snd_mpu401_do_reset(mpu) < 0) goto error_out; @@ -524,8 +530,9 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT; in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0; out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0; - if ((err = snd_rawmidi_new(card, "MPU-401U", device, - out_enable, in_enable, &rmidi)) < 0) + err = snd_rawmidi_new(card, "MPU-401U", device, + out_enable, in_enable, &rmidi); + if (err < 0) return err; mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); if (!mpu) { diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index df4b7f9cd50f..0e95b08d34d6 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -566,7 +566,8 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id) */ static int snd_mtpav_get_ISA(struct mtpav *mcard) { - if ((mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI")) == NULL) { + mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI"); + if (!mcard->res_port) { snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port); return -EBUSY; } @@ -628,10 +629,11 @@ static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard) hwports = 8; mcard->num_ports = hwports; - if ((rval = snd_rawmidi_new(mcard->card, "MotuMIDI", 0, - mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1, - mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1, - &mcard->rmidi)) < 0) + rval = snd_rawmidi_new(mcard->card, "MotuMIDI", 0, + mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1, + mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1, + &mcard->rmidi); + if (rval < 0) return rval; rawmidi = mcard->rmidi; rawmidi->private_data = mcard; @@ -744,7 +746,8 @@ static int __init alsa_card_mtpav_init(void) { int err; - if ((err = platform_driver_register(&snd_mtpav_driver)) < 0) + err = platform_driver_register(&snd_mtpav_driver); + if (err < 0) return err; device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0); diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 322d530ab07b..d3bc9e8c407d 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -950,7 +950,8 @@ static int snd_mts64_probe(struct platform_device *pdev) goto free_pardev; } - if ((err = snd_mts64_create(card, pardev, &mts)) < 0) { + err = snd_mts64_create(card, pardev, &mts); + if (err < 0) { snd_printd("Cannot create main component\n"); goto release_pardev; } @@ -963,19 +964,22 @@ static int snd_mts64_probe(struct platform_device *pdev) goto __err; } - if ((err = snd_mts64_rawmidi_create(card)) < 0) { + err = snd_mts64_rawmidi_create(card); + if (err < 0) { snd_printd("Creating Rawmidi component failed\n"); goto __err; } /* init device */ - if ((err = mts64_device_init(p)) < 0) + err = mts64_device_init(p); + if (err < 0) goto __err; platform_set_drvdata(pdev, card); /* At this point card will be usable */ - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_printd("Cannot register card\n"); goto __err; } @@ -1031,7 +1035,8 @@ static int __init snd_mts64_module_init(void) { int err; - if ((err = platform_driver_register(&snd_mts64_driver)) < 0) + err = platform_driver_register(&snd_mts64_driver); + if (err < 0) return err; if (parport_register_driver(&mts64_parport_driver) != 0) { diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index 9259522483c8..6c1f1cc092d8 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -243,7 +243,8 @@ static int snd_opl3_timer1_init(struct snd_opl3 * opl3, int timer_no) tid.card = opl3->card->number; tid.device = timer_no; tid.subdevice = 0; - if ((err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer)) >= 0) { + err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer); + if (err >= 0) { strcpy(timer->name, "AdLib timer #1"); timer->private_data = opl3; timer->hw = snd_opl3_timer1; @@ -263,7 +264,8 @@ static int snd_opl3_timer2_init(struct snd_opl3 * opl3, int timer_no) tid.card = opl3->card->number; tid.device = timer_no; tid.subdevice = 0; - if ((err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer)) >= 0) { + err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer); + if (err >= 0) { strcpy(timer->name, "AdLib timer #2"); timer->private_data = opl3; timer->hw = snd_opl3_timer2; @@ -348,7 +350,8 @@ int snd_opl3_new(struct snd_card *card, spin_lock_init(&opl3->reg_lock); spin_lock_init(&opl3->timer_lock); - if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops); + if (err < 0) { snd_opl3_free(opl3); return err; } @@ -396,19 +399,23 @@ int snd_opl3_create(struct snd_card *card, int err; *ropl3 = NULL; - if ((err = snd_opl3_new(card, hardware, &opl3)) < 0) + err = snd_opl3_new(card, hardware, &opl3); + if (err < 0) return err; if (! integrated) { - if ((opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)")) == NULL) { + opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)"); + if (!opl3->res_l_port) { snd_printk(KERN_ERR "opl3: can't grab left port 0x%lx\n", l_port); snd_device_free(card, opl3); return -EBUSY; } - if (r_port != 0 && - (opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)")) == NULL) { - snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port); - snd_device_free(card, opl3); - return -EBUSY; + if (r_port != 0) { + opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)"); + if (!opl3->res_r_port) { + snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port); + snd_device_free(card, opl3); + return -EBUSY; + } } } opl3->l_port = l_port; @@ -423,7 +430,8 @@ int snd_opl3_create(struct snd_card *card, break; default: opl3->command = &snd_opl2_command; - if ((err = snd_opl3_detect(opl3)) < 0) { + err = snd_opl3_detect(opl3); + if (err < 0) { snd_printd("OPL2/3 chip not detected at 0x%lx/0x%lx\n", opl3->l_port, opl3->r_port); snd_device_free(card, opl3); @@ -449,11 +457,14 @@ int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev) { int err; - if (timer1_dev >= 0) - if ((err = snd_opl3_timer1_init(opl3, timer1_dev)) < 0) + if (timer1_dev >= 0) { + err = snd_opl3_timer1_init(opl3, timer1_dev); + if (err < 0) return err; + } if (timer2_dev >= 0) { - if ((err = snd_opl3_timer2_init(opl3, timer2_dev)) < 0) { + err = snd_opl3_timer2_init(opl3, timer2_dev); + if (err < 0) { snd_device_free(opl3->card, opl3->timer1); opl3->timer1 = NULL; return err; @@ -477,7 +488,8 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, /* create hardware dependent device (direct FM) */ - if ((err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw)) < 0) { + err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw); + if (err < 0) { snd_device_free(card, opl3); return err; } diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index eb23c55323ae..e1b69c65c3c8 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c @@ -180,8 +180,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op, if (vp2->state == SNDRV_OPL3_ST_ON_2OP) { /* kill two voices, EXPENSIVE */ bp++; - voice_time = (voice_time > vp->time) ? - voice_time : vp->time; + voice_time = max(voice_time, vp2->time); } } else { /* allocate 2op voice */ diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index c82c7c1c0714..7645365eec89 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c @@ -136,7 +136,8 @@ static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) if (snd_BUG_ON(!arg)) return -ENXIO; - if ((err = snd_opl3_synth_setup(opl3)) < 0) + err = snd_opl3_synth_setup(opl3); + if (err < 0) return err; /* fill the argument data */ @@ -144,7 +145,8 @@ static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) arg->addr.client = opl3->oss_chset->client; arg->addr.port = opl3->oss_chset->port; - if ((err = snd_opl3_synth_use_inc(opl3)) < 0) + err = snd_opl3_synth_use_inc(opl3); + if (err < 0) return err; opl3->synth_mode = SNDRV_OPL3_MODE_SYNTH; diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index cd2a01b5e2e1..75de1299c3dc 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -92,7 +92,8 @@ static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe struct snd_opl3 *opl3 = private_data; int err; - if ((err = snd_opl3_synth_setup(opl3)) < 0) + err = snd_opl3_synth_setup(opl3); + if (err < 0) return err; if (use_internal_drums) { @@ -107,7 +108,8 @@ static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe } if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) { - if ((err = snd_opl3_synth_use_inc(opl3)) < 0) + err = snd_opl3_synth_use_inc(opl3); + if (err < 0) return err; } opl3->synth_mode = SNDRV_OPL3_MODE_SEQ; @@ -227,7 +229,8 @@ static int snd_opl3_seq_probe(struct device *_dev) if (client < 0) return client; - if ((err = snd_opl3_synth_create_port(opl3)) < 0) { + err = snd_opl3_synth_create_port(opl3); + if (err < 0) { snd_seq_delete_kernel_client(client); opl3->seq_client = -1; return err; diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 2f4514ed47c5..52a656735365 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -749,7 +749,8 @@ static int snd_portman_probe(struct platform_device *pdev) goto free_pardev; } - if ((err = portman_create(card, pardev, &pm)) < 0) { + err = portman_create(card, pardev, &pm); + if (err < 0) { snd_printd("Cannot create main component\n"); goto release_pardev; } @@ -762,19 +763,22 @@ static int snd_portman_probe(struct platform_device *pdev) goto __err; } - if ((err = snd_portman_rawmidi_create(card)) < 0) { + err = snd_portman_rawmidi_create(card); + if (err < 0) { snd_printd("Creating Rawmidi component failed\n"); goto __err; } /* init device */ - if ((err = portman_device_init(pm)) < 0) + err = portman_device_init(pm); + if (err < 0) goto __err; platform_set_drvdata(pdev, card); /* At this point card will be usable */ - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_printd("Cannot register card\n"); goto __err; } @@ -831,7 +835,8 @@ static int __init snd_portman_module_init(void) { int err; - if ((err = platform_driver_register(&snd_portman_driver)) < 0) + err = platform_driver_register(&snd_portman_driver); + if (err < 0) return err; if (parport_register_driver(&portman_parport_driver) != 0) { diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 6d5d1ca59ecf..da9983cba01c 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -783,7 +783,8 @@ static int snd_uart16550_create(struct snd_card *card, int err; - if ((uart = kzalloc(sizeof(*uart), GFP_KERNEL)) == NULL) + uart = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) return -ENOMEM; uart->adaptor = adaptor; uart->card = card; @@ -792,7 +793,8 @@ static int snd_uart16550_create(struct snd_card *card, uart->base = iobase; uart->drop_on_full = droponfull; - if ((err = snd_uart16550_detect(uart)) <= 0) { + err = snd_uart16550_detect(uart); + if (err <= 0) { printk(KERN_ERR "no UART detected at 0x%lx\n", iobase); snd_uart16550_free(uart); return -ENODEV; @@ -818,7 +820,8 @@ static int snd_uart16550_create(struct snd_card *card, uart->timer_running = 0; /* Register device */ - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, uart, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, uart, &ops); + if (err < 0) { snd_uart16550_free(uart); return err; } @@ -932,14 +935,10 @@ static int snd_serial_probe(struct platform_device *devptr) strcpy(card->driver, "Serial"); strcpy(card->shortname, "Serial MIDI (UART16550A)"); - if ((err = snd_uart16550_create(card, - port[dev], - irq[dev], - speed[dev], - base[dev], - adaptor[dev], - droponfull[dev], - &uart)) < 0) + err = snd_uart16550_create(card, port[dev], irq[dev], speed[dev], + base[dev], adaptor[dev], droponfull[dev], + &uart); + if (err < 0) goto _err; err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi); @@ -952,7 +951,8 @@ static int snd_serial_probe(struct platform_device *devptr) uart->base, uart->irq); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto _err; platform_set_drvdata(devptr, card); @@ -992,7 +992,8 @@ static int __init alsa_card_serial_init(void) { int i, cards, err; - if ((err = platform_driver_register(&snd_serial_driver)) < 0) + err = platform_driver_register(&snd_serial_driver); + if (err < 0) return err; cards = 0; diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index a22e5b1a5458..a10449af5a76 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -110,20 +110,25 @@ static int vx_transfer_end(struct vx_core *chip, int cmd) { int err; - if ((err = vx_reset_chk(chip)) < 0) + err = vx_reset_chk(chip); + if (err < 0) return err; /* irq MESS_READ/WRITE_END */ - if ((err = vx_send_irq_dsp(chip, cmd)) < 0) + err = vx_send_irq_dsp(chip, cmd); + if (err < 0) return err; /* Wait CHK = 1 */ - if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) + err = vx_wait_isr_bit(chip, ISR_CHK); + if (err < 0) return err; /* If error, Read RX */ - if ((err = vx_inb(chip, ISR)) & ISR_ERR) { - if ((err = vx_wait_for_rx_full(chip)) < 0) { + err = vx_inb(chip, ISR); + if (err & ISR_ERR) { + err = vx_wait_for_rx_full(chip); + if (err < 0) { snd_printd(KERN_DEBUG "transfer_end: error in rx_full\n"); return err; } @@ -232,7 +237,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) if (chip->chip_status & VX_STAT_IS_STALE) return -EBUSY; - if ((err = vx_reset_chk(chip)) < 0) { + err = vx_reset_chk(chip); + if (err < 0) { snd_printd(KERN_DEBUG "vx_send_msg: vx_reset_chk error\n"); return err; } @@ -254,7 +260,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) rmh->Cmd[0] &= MASK_1_WORD_COMMAND; /* Wait for TX empty */ - if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) { + err = vx_wait_isr_bit(chip, ISR_TX_EMPTY); + if (err < 0) { snd_printd(KERN_DEBUG "vx_send_msg: wait tx empty error\n"); return err; } @@ -265,18 +272,21 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) vx_outb(chip, TXL, rmh->Cmd[0] & 0xff); /* Trigger irq MESSAGE */ - if ((err = vx_send_irq_dsp(chip, IRQ_MESSAGE)) < 0) { + err = vx_send_irq_dsp(chip, IRQ_MESSAGE); + if (err < 0) { snd_printd(KERN_DEBUG "vx_send_msg: send IRQ_MESSAGE error\n"); return err; } /* Wait for CHK = 1 */ - if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) + err = vx_wait_isr_bit(chip, ISR_CHK); + if (err < 0) return err; /* If error, get error value from RX */ if (vx_inb(chip, ISR) & ISR_ERR) { - if ((err = vx_wait_for_rx_full(chip)) < 0) { + err = vx_wait_for_rx_full(chip); + if (err < 0) { snd_printd(KERN_DEBUG "vx_send_msg: rx_full read error\n"); return err; } @@ -292,7 +302,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) if (rmh->LgCmd > 1) { for (i = 1; i < rmh->LgCmd; i++) { /* Wait for TX ready */ - if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) { + err = vx_wait_isr_bit(chip, ISR_TX_READY); + if (err < 0) { snd_printd(KERN_DEBUG "vx_send_msg: tx_ready error\n"); return err; } @@ -303,13 +314,15 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) vx_outb(chip, TXL, rmh->Cmd[i] & 0xff); /* Trigger irq MESS_READ_NEXT */ - if ((err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT)) < 0) { + err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT); + if (err < 0) { snd_printd(KERN_DEBUG "vx_send_msg: IRQ_READ_NEXT error\n"); return err; } } /* Wait for TX empty */ - if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) { + err = vx_wait_isr_bit(chip, ISR_TX_READY); + if (err < 0) { snd_printd(KERN_DEBUG "vx_send_msg: TX_READY error\n"); return err; } @@ -362,17 +375,21 @@ int vx_send_rih_nolock(struct vx_core *chip, int cmd) #if 0 printk(KERN_DEBUG "send_rih: cmd = 0x%x\n", cmd); #endif - if ((err = vx_reset_chk(chip)) < 0) + err = vx_reset_chk(chip); + if (err < 0) return err; /* send the IRQ */ - if ((err = vx_send_irq_dsp(chip, cmd)) < 0) + err = vx_send_irq_dsp(chip, cmd); + if (err < 0) return err; /* Wait CHK = 1 */ - if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) + err = vx_wait_isr_bit(chip, ISR_CHK); + if (err < 0) return err; /* If error, read RX */ if (vx_inb(chip, ISR) & ISR_ERR) { - if ((err = vx_wait_for_rx_full(chip)) < 0) + err = vx_wait_for_rx_full(chip); + if (err < 0) return err; err = vx_inb(chip, RXH) << 16; err |= vx_inb(chip, RXM) << 8; @@ -648,7 +665,8 @@ int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot) vx_reset_board(chip, cold_reset); vx_validate_irq(chip, 0); - if ((err = snd_vx_load_boot_image(chip, boot)) < 0) + err = snd_vx_load_boot_image(chip, boot); + if (err < 0) return err; msleep(10); @@ -678,7 +696,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp) for (i = 0; i < dsp->size; i += 3) { image = dsp->data + i; /* Wait DSP ready for a new read */ - if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) { + err = vx_wait_isr_bit(chip, ISR_TX_EMPTY); + if (err < 0) { printk(KERN_ERR "dsp loading error at position %d\n", i); return err; @@ -698,7 +717,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp) msleep(200); - if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) + err = vx_wait_isr_bit(chip, ISR_CHK); + if (err < 0) return err; vx_toggle_dac_mute(chip, 0); diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c index 01baa6d872e9..efbb644edba1 100644 --- a/sound/drivers/vx/vx_hwdep.c +++ b/sound/drivers/vx/vx_hwdep.c @@ -78,15 +78,19 @@ int snd_vx_setup_firmware(struct vx_core *chip) /* ok, we reached to the last one */ /* create the devices if not built yet */ - if ((err = snd_vx_pcm_new(chip)) < 0) + err = snd_vx_pcm_new(chip); + if (err < 0) return err; - if ((err = snd_vx_mixer_new(chip)) < 0) + err = snd_vx_mixer_new(chip); + if (err < 0) return err; - if (chip->ops->add_controls) - if ((err = chip->ops->add_controls(chip)) < 0) + if (chip->ops->add_controls) { + err = chip->ops->add_controls(chip); + if (err < 0) return err; + } chip->chip_status |= VX_STAT_DEVICE_INIT; chip->chip_status |= VX_STAT_CHIP_INIT; diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index 13099f8c84d6..53d78eb13c53 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -910,7 +910,8 @@ int snd_vx_mixer_new(struct vx_core *chip) temp = vx_control_output_level; temp.index = i; temp.tlv.p = chip->hw->output_level_db_scale; - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; } @@ -921,22 +922,26 @@ int snd_vx_mixer_new(struct vx_core *chip) temp.index = i; temp.name = "PCM Playback Volume"; temp.private_value = val; - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; temp = vx_control_output_switch; temp.index = i; temp.private_value = val; - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; temp = vx_control_monitor_gain; temp.index = i; temp.private_value = val; - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; temp = vx_control_monitor_switch; temp.index = i; temp.private_value = val; - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; } for (i = 0; i < chip->hw->num_outs; i++) { @@ -944,20 +949,25 @@ int snd_vx_mixer_new(struct vx_core *chip) temp.index = i; temp.name = "PCM Capture Volume"; temp.private_value = (i * 2) | (1 << 8); - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; } /* Audio source */ - if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip)); + if (err < 0) return err; /* clock mode */ - if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip)); + if (err < 0) return err; /* IEC958 controls */ - if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip)); + if (err < 0) return err; /* VU, peak, saturation meters */ for (c = 0; c < 2; c++) { @@ -968,7 +978,8 @@ int snd_vx_mixer_new(struct vx_core *chip) temp = vx_control_saturation; temp.index = i; temp.private_value = val; - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; } sprintf(name, "%s VU Meter", dir[c]); @@ -976,14 +987,16 @@ int snd_vx_mixer_new(struct vx_core *chip) temp.index = i; temp.name = name; temp.private_value = val; - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; sprintf(name, "%s Peak Meter", dir[c]); temp = vx_control_peak_meter; temp.index = i; temp.name = name; temp.private_value = val; - if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; } } diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index daffda99b4f7..3924f5283745 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -341,10 +341,12 @@ static int vx_toggle_pipe(struct vx_core *chip, struct vx_pipe *pipe, int state) } } - if ((err = vx_conf_pipe(chip, pipe)) < 0) + err = vx_conf_pipe(chip, pipe); + if (err < 0) return err; - if ((err = vx_send_irqa(chip)) < 0) + err = vx_send_irqa(chip); + if (err < 0) return err; /* If it completes successfully, wait for the pipes @@ -680,8 +682,9 @@ static void vx_pcm_playback_transfer(struct vx_core *chip, if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE)) return; for (i = 0; i < nchunks; i++) { - if ((err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe, - chip->ibl.size)) < 0) + err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe, + chip->ibl.size); + if (err < 0) return; } } @@ -698,7 +701,8 @@ static void vx_pcm_playback_update(struct vx_core *chip, struct snd_pcm_runtime *runtime = subs->runtime; if (pipe->running && ! (chip->chip_status & VX_STAT_IS_STALE)) { - if ((err = vx_update_pipe_position(chip, runtime, pipe)) < 0) + err = vx_update_pipe_position(chip, runtime, pipe); + if (err < 0) return; if (pipe->transferred >= (int)runtime->period_size) { pipe->transferred %= runtime->period_size; @@ -747,11 +751,13 @@ static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd) pipe->running = 0; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if ((err = vx_toggle_pipe(chip, pipe, 0)) < 0) + err = vx_toggle_pipe(chip, pipe, 0); + if (err < 0) return err; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0) + err = vx_toggle_pipe(chip, pipe, 1); + if (err < 0) return err; break; default: @@ -792,13 +798,15 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs) snd_printdd(KERN_DEBUG "reopen the pipe with data_mode = %d\n", data_mode); vx_init_rmh(&rmh, CMD_FREE_PIPE); vx_set_pipe_cmd_params(&rmh, 0, pipe->number, 0); - if ((err = vx_send_msg(chip, &rmh)) < 0) + err = vx_send_msg(chip, &rmh); + if (err < 0) return err; vx_init_rmh(&rmh, CMD_RES_PIPE); vx_set_pipe_cmd_params(&rmh, 0, pipe->number, pipe->channels); if (data_mode) rmh.Cmd[0] |= BIT_DATA_MODE; - if ((err = vx_send_msg(chip, &rmh)) < 0) + err = vx_send_msg(chip, &rmh); + if (err < 0) return err; pipe->data_mode = data_mode; } @@ -810,7 +818,8 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs) } vx_set_clock(chip, runtime->rate); - if ((err = vx_set_format(chip, pipe, runtime)) < 0) + err = vx_set_format(chip, pipe, runtime); + if (err < 0) return err; if (vx_is_pcmcia(chip)) { @@ -1187,7 +1196,8 @@ int snd_vx_pcm_new(struct vx_core *chip) unsigned int i; int err; - if ((err = vx_init_audio_io(chip)) < 0) + err = vx_init_audio_io(chip); + if (err < 0) return err; for (i = 0; i < chip->hw->num_codecs; i++) { diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 9897bd26a438..fd109bea4c53 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -18,8 +18,25 @@ config SND_DICE select SND_HWDEP select SND_FIREWIRE_LIB help - Say Y here to include support for many DACs based on the DICE - chip family (DICE-II/Jr/Mini) which TC Applied Technologies produces. + Say Y here to include support for devices based on the DICE chip family + (DICE-II/TCD2210(Mini)/TCD2220(Jr.)) which TC Applied Technologies (TCAT) produced. + * Allen and Heath Zed R16 + * Alesis iO 14/26 FireWire, MasterControl, MultiMix 8/12/16 FireWire + * Avid Mbox 3 Pro + * FlexRadio Systems FLEX-3000, FLEX-5000 + * Focusrite Liquid Saffire 56 + * Focusrite Saffire Pro 14, Pro 24, Pro 24 DSP, Pro 26, Pro 40(TCD2220) + * Harman Music Group Lexicon I-ONIX FW810S + * Loud Technologies Mackie Onyx Blackbird, Onyx 820i/1220i/1620i/1640i (latter models) + * M-Audio ProFire 610/2626 + * Mytek Stereo192-DSD DAC + * Midas Klark Teknik VeniceF series + * PreSonus FireStudio, FireStudio Mobile, FireStudio Project, FireStudio Tube + * PreSonus StudioLive 16.4.2, 16.0.2, 24.4.2, 32.4.2 + * Solid State Logic Duende Classic, Duende Mini + * TC Electronic Studio Konnekt 48, Konnekt 24D, Konnekt Live, Impact Twin + * TC Electronic Digital Konnekt x32, Desktop Konnekt 6 + * Weiss Engineering ADC2, Vesta, Minerva, AFI1, DAC1, INT202, DAC202 To compile this driver as a module, choose M here: the module will be called snd-dice. @@ -38,7 +55,7 @@ config SND_OXFW * Mackie(Loud) Onyx 1640i (former model) * Mackie(Loud) Onyx Satellite * Mackie(Loud) Tapco Link.Firewire - * Mackie(Loud) d.4 pro + * Mackie(Loud) d.2 pro/d.4 pro (built-in FireWire card with OXFW971 ASIC) * Mackie(Loud) U.420/U.420d * TASCAM FireOne * Stanton Controllers & Systems 1 Deck/Mixer @@ -84,7 +101,7 @@ config SND_BEBOB * PreSonus FIREBOX/FIREPOD/FP10/Inspire1394 * BridgeCo RDAudio1/Audio5 * Mackie Onyx 1220/1620/1640 (FireWire I/O Card) - * Mackie d.2 (FireWire Option) and d.2 Pro + * Mackie d.2 (optional FireWire card with DM1000 ASIC) * Stanton FinalScratch 2 (ScratchAmp) * Tascam IF-FW/DM * Behringer XENIX UFX 1204/1604 @@ -110,6 +127,7 @@ config SND_BEBOB * M-Audio Ozonic/NRV10/ProfireLightBridge * M-Audio FireWire 1814/ProjectMix IO * Digidesign Mbox 2 Pro + * ToneWeal FW66 To compile this driver as a module, choose M here: the module will be called snd-bebob. @@ -148,12 +166,16 @@ config SND_FIREWIRE_MOTU select SND_HWDEP help Say Y here to enable support for FireWire devices which MOTU produced: + * 828 + * 896 * 828mk2 * Traveler * Ultralite * 8pre * 828mk3 (FireWire only) * 828mk3 (Hybrid) + * Ultralite mk3 (FireWire only) + * Ultralite mk3 (Hybrid) * Audio Express * 4pre diff --git a/sound/firewire/amdtp-am824.c b/sound/firewire/amdtp-am824.c index fea92e148790..d9c700f652bb 100644 --- a/sound/firewire/amdtp-am824.c +++ b/sound/firewire/amdtp-am824.c @@ -410,10 +410,10 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, * @s: the AMDTP stream to initialize * @unit: the target of the stream * @dir: the direction of stream - * @flags: the packet transmission method to use + * @flags: the details of the streaming protocol consist of cip_flags enumeration-constants. */ int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, - enum amdtp_stream_direction dir, enum cip_flags flags) + enum amdtp_stream_direction dir, unsigned int flags) { amdtp_stream_process_ctx_payloads_t process_ctx_payloads; diff --git a/sound/firewire/amdtp-am824.h b/sound/firewire/amdtp-am824.h index 06d280783581..2b092b1061ba 100644 --- a/sound/firewire/amdtp-am824.h +++ b/sound/firewire/amdtp-am824.h @@ -45,5 +45,5 @@ void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, struct snd_rawmidi_substream *midi); int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, - enum amdtp_stream_direction dir, enum cip_flags flags); + enum amdtp_stream_direction dir, unsigned int flags); #endif diff --git a/sound/firewire/amdtp-stream-trace.h b/sound/firewire/amdtp-stream-trace.h index aa53c13b89d3..5fd2aeccdfc2 100644 --- a/sound/firewire/amdtp-stream-trace.h +++ b/sound/firewire/amdtp-stream-trace.h @@ -49,7 +49,7 @@ TRACE_EVENT(amdtp_packet, __entry->data_blocks = data_blocks; __entry->data_block_counter = data_block_counter, __entry->packet_index = packet_index; - __entry->irq = !!in_interrupt(); + __entry->irq = !!in_softirq(); __entry->index = index; ), TP_printk( diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 5805c5de39fb..9be2260e4ca2 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -20,7 +20,7 @@ #define CYCLES_PER_SECOND 8000 #define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND) -#define OHCI_MAX_SECOND 8 +#define OHCI_SECOND_MODULUS 8 /* Always support Linux tracing subsystem. */ #define CREATE_TRACE_POINTS @@ -33,7 +33,8 @@ #define TAG_NO_CIP_HEADER 0 #define TAG_CIP 1 -/* common isochronous packet header parameters */ +// Common Isochronous Packet (CIP) header parameters. Use two quadlets CIP header when supported. +#define CIP_HEADER_QUADLETS 2 #define CIP_EOH_SHIFT 31 #define CIP_EOH (1u << CIP_EOH_SHIFT) #define CIP_EOH_MASK 0x80000000 @@ -48,36 +49,46 @@ #define CIP_FMT_MASK 0x3f000000 #define CIP_FDF_MASK 0x00ff0000 #define CIP_FDF_SHIFT 16 +#define CIP_FDF_NO_DATA 0xff #define CIP_SYT_MASK 0x0000ffff #define CIP_SYT_NO_INFO 0xffff +#define CIP_SYT_CYCLE_MODULUS 16 +#define CIP_NO_DATA ((CIP_FDF_NO_DATA << CIP_FDF_SHIFT) | CIP_SYT_NO_INFO) + +#define CIP_HEADER_SIZE (sizeof(__be32) * CIP_HEADER_QUADLETS) /* Audio and Music transfer protocol specific parameters */ #define CIP_FMT_AM 0x10 #define AMDTP_FDF_NO_DATA 0xff -// For iso header, tstamp and 2 CIP header. -#define IR_CTX_HEADER_SIZE_CIP 16 // For iso header and tstamp. -#define IR_CTX_HEADER_SIZE_NO_CIP 8 +#define IR_CTX_HEADER_DEFAULT_QUADLETS 2 +// Add nothing. +#define IR_CTX_HEADER_SIZE_NO_CIP (sizeof(__be32) * IR_CTX_HEADER_DEFAULT_QUADLETS) +// Add two quadlets CIP header. +#define IR_CTX_HEADER_SIZE_CIP (IR_CTX_HEADER_SIZE_NO_CIP + CIP_HEADER_SIZE) #define HEADER_TSTAMP_MASK 0x0000ffff -#define IT_PKT_HEADER_SIZE_CIP 8 // For 2 CIP header. +#define IT_PKT_HEADER_SIZE_CIP CIP_HEADER_SIZE #define IT_PKT_HEADER_SIZE_NO_CIP 0 // Nothing. -static void pcm_period_work(struct work_struct *work); +// The initial firmware of OXFW970 can postpone transmission of packet during finishing +// asynchronous transaction. This module accepts 5 cycles to skip as maximum to avoid buffer +// overrun. Actual device can skip more, then this module stops the packet streaming. +#define IR_JUMBO_PAYLOAD_MAX_SKIP_CYCLES 5 /** * amdtp_stream_init - initialize an AMDTP stream structure * @s: the AMDTP stream to initialize * @unit: the target of the stream * @dir: the direction of stream - * @flags: the packet transmission method to use + * @flags: the details of the streaming protocol consist of cip_flags enumeration-constants. * @fmt: the value of fmt field in CIP header * @process_ctx_payloads: callback handler to process payloads of isoc context * @protocol_size: the size to allocate newly for protocol */ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, - enum amdtp_stream_direction dir, enum cip_flags flags, + enum amdtp_stream_direction dir, unsigned int flags, unsigned int fmt, amdtp_stream_process_ctx_payloads_t process_ctx_payloads, unsigned int protocol_size) @@ -94,18 +105,13 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->flags = flags; s->context = ERR_PTR(-1); mutex_init(&s->mutex); - INIT_WORK(&s->period_work, pcm_period_work); s->packet_index = 0; - init_waitqueue_head(&s->callback_wait); - s->callbacked = false; + init_waitqueue_head(&s->ready_wait); s->fmt = fmt; s->process_ctx_payloads = process_ctx_payloads; - if (dir == AMDTP_OUT_STREAM) - s->ctx_data.rx.syt_override = -1; - return 0; } EXPORT_SYMBOL(amdtp_stream_init); @@ -183,14 +189,13 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, unsigned int maximum_usec_per_period; int err; - hw->info = SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_BLOCK_TRANSFER | + hw->info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID; + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; - /* SNDRV_PCM_INFO_BATCH */ hw->periods_min = 2; hw->periods_max = UINT_MAX; @@ -287,22 +292,29 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, s->syt_interval = amdtp_syt_intervals[sfc]; // default buffering in the device. - if (s->direction == AMDTP_OUT_STREAM) { - s->ctx_data.rx.transfer_delay = - TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; - - if (s->flags & CIP_BLOCKING) { - // additional buffering needed to adjust for no-data - // packets. - s->ctx_data.rx.transfer_delay += - TICKS_PER_SECOND * s->syt_interval / rate; - } - } + s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE; + + // additional buffering needed to adjust for no-data packets. + if (s->flags & CIP_BLOCKING) + s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate; return 0; } EXPORT_SYMBOL(amdtp_stream_set_parameters); +// The CIP header is processed in context header apart from context payload. +static int amdtp_stream_get_max_ctx_payload_size(struct amdtp_stream *s) +{ + unsigned int multiplier; + + if (s->flags & CIP_JUMBO_PAYLOAD) + multiplier = IR_JUMBO_PAYLOAD_MAX_SKIP_CYCLES; + else + multiplier = 1; + + return s->syt_interval * s->data_block_quadlets * sizeof(__be32) * multiplier; +} + /** * amdtp_stream_get_max_payload - get the stream's packet size * @s: the AMDTP stream @@ -312,16 +324,14 @@ EXPORT_SYMBOL(amdtp_stream_set_parameters); */ unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s) { - unsigned int multiplier = 1; - unsigned int cip_header_size = 0; + unsigned int cip_header_size; - if (s->flags & CIP_JUMBO_PAYLOAD) - multiplier = 5; if (!(s->flags & CIP_NO_HEADER)) - cip_header_size = sizeof(__be32) * 2; + cip_header_size = CIP_HEADER_SIZE; + else + cip_header_size = 0; - return cip_header_size + - s->syt_interval * s->data_block_quadlets * sizeof(__be32) * multiplier; + return cip_header_size + amdtp_stream_get_max_ctx_payload_size(s); } EXPORT_SYMBOL(amdtp_stream_get_max_payload); @@ -333,32 +343,46 @@ EXPORT_SYMBOL(amdtp_stream_get_max_payload); */ void amdtp_stream_pcm_prepare(struct amdtp_stream *s) { - cancel_work_sync(&s->period_work); s->pcm_buffer_pointer = 0; s->pcm_period_pointer = 0; } EXPORT_SYMBOL(amdtp_stream_pcm_prepare); -static unsigned int calculate_data_blocks(unsigned int *data_block_state, - bool is_blocking, bool is_no_info, - unsigned int syt_interval, enum cip_sfc sfc) +static void pool_blocking_data_blocks(struct amdtp_stream *s, struct seq_desc *descs, + const unsigned int seq_size, unsigned int seq_tail, + unsigned int count) { - unsigned int data_blocks; + const unsigned int syt_interval = s->syt_interval; + int i; + + for (i = 0; i < count; ++i) { + struct seq_desc *desc = descs + seq_tail; - /* Blocking mode. */ - if (is_blocking) { - /* This module generate empty packet for 'no data'. */ - if (is_no_info) - data_blocks = 0; + if (desc->syt_offset != CIP_SYT_NO_INFO) + desc->data_blocks = syt_interval; else - data_blocks = syt_interval; - /* Non-blocking mode. */ - } else { + desc->data_blocks = 0; + + seq_tail = (seq_tail + 1) % seq_size; + } +} + +static void pool_ideal_nonblocking_data_blocks(struct amdtp_stream *s, struct seq_desc *descs, + const unsigned int seq_size, unsigned int seq_tail, + unsigned int count) +{ + const enum cip_sfc sfc = s->sfc; + unsigned int state = s->ctx_data.rx.data_block_state; + int i; + + for (i = 0; i < count; ++i) { + struct seq_desc *desc = descs + seq_tail; + if (!cip_sfc_is_base_44100(sfc)) { // Sample_rate / 8000 is an integer, and precomputed. - data_blocks = *data_block_state; + desc->data_blocks = state; } else { - unsigned int phase = *data_block_state; + unsigned int phase = state; /* * This calculates the number of data blocks per packet so that @@ -370,18 +394,19 @@ static unsigned int calculate_data_blocks(unsigned int *data_block_state, */ if (sfc == CIP_SFC_44100) /* 6 6 5 6 5 6 5 ... */ - data_blocks = 5 + ((phase & 1) ^ - (phase == 0 || phase >= 40)); + desc->data_blocks = 5 + ((phase & 1) ^ (phase == 0 || phase >= 40)); else /* 12 11 11 11 11 ... or 23 22 22 22 22 ... */ - data_blocks = 11 * (sfc >> 1) + (phase == 0); + desc->data_blocks = 11 * (sfc >> 1) + (phase == 0); if (++phase >= (80 >> (sfc >> 1))) phase = 0; - *data_block_state = phase; + state = phase; } + + seq_tail = (seq_tail + 1) % seq_size; } - return data_blocks; + s->ctx_data.rx.data_block_state = state; } static unsigned int calculate_syt_offset(unsigned int *last_syt_offset, @@ -423,6 +448,149 @@ static unsigned int calculate_syt_offset(unsigned int *last_syt_offset, return syt_offset; } +static void pool_ideal_syt_offsets(struct amdtp_stream *s, struct seq_desc *descs, + const unsigned int seq_size, unsigned int seq_tail, + unsigned int count) +{ + const enum cip_sfc sfc = s->sfc; + unsigned int last = s->ctx_data.rx.last_syt_offset; + unsigned int state = s->ctx_data.rx.syt_offset_state; + int i; + + for (i = 0; i < count; ++i) { + struct seq_desc *desc = descs + seq_tail; + + desc->syt_offset = calculate_syt_offset(&last, &state, sfc); + + seq_tail = (seq_tail + 1) % seq_size; + } + + s->ctx_data.rx.last_syt_offset = last; + s->ctx_data.rx.syt_offset_state = state; +} + +static unsigned int compute_syt_offset(unsigned int syt, unsigned int cycle, + unsigned int transfer_delay) +{ + unsigned int cycle_lo = (cycle % CYCLES_PER_SECOND) & 0x0f; + unsigned int syt_cycle_lo = (syt & 0xf000) >> 12; + unsigned int syt_offset; + + // Round up. + if (syt_cycle_lo < cycle_lo) + syt_cycle_lo += CIP_SYT_CYCLE_MODULUS; + syt_cycle_lo -= cycle_lo; + + // Subtract transfer delay so that the synchronization offset is not so large + // at transmission. + syt_offset = syt_cycle_lo * TICKS_PER_CYCLE + (syt & 0x0fff); + if (syt_offset < transfer_delay) + syt_offset += CIP_SYT_CYCLE_MODULUS * TICKS_PER_CYCLE; + + return syt_offset - transfer_delay; +} + +// Both of the producer and consumer of the queue runs in the same clock of IEEE 1394 bus. +// Additionally, the sequence of tx packets is severely checked against any discontinuity +// before filling entries in the queue. The calculation is safe even if it looks fragile by +// overrun. +static unsigned int calculate_cached_cycle_count(struct amdtp_stream *s, unsigned int head) +{ + const unsigned int cache_size = s->ctx_data.tx.cache.size; + unsigned int cycles = s->ctx_data.tx.cache.tail; + + if (cycles < head) + cycles += cache_size; + cycles -= head; + + return cycles; +} + +static void cache_seq(struct amdtp_stream *s, const struct pkt_desc *descs, unsigned int desc_count) +{ + const unsigned int transfer_delay = s->transfer_delay; + const unsigned int cache_size = s->ctx_data.tx.cache.size; + struct seq_desc *cache = s->ctx_data.tx.cache.descs; + unsigned int cache_tail = s->ctx_data.tx.cache.tail; + bool aware_syt = !(s->flags & CIP_UNAWARE_SYT); + int i; + + for (i = 0; i < desc_count; ++i) { + struct seq_desc *dst = cache + cache_tail; + const struct pkt_desc *src = descs + i; + + if (aware_syt && src->syt != CIP_SYT_NO_INFO) + dst->syt_offset = compute_syt_offset(src->syt, src->cycle, transfer_delay); + else + dst->syt_offset = CIP_SYT_NO_INFO; + dst->data_blocks = src->data_blocks; + + cache_tail = (cache_tail + 1) % cache_size; + } + + s->ctx_data.tx.cache.tail = cache_tail; +} + +static void pool_ideal_seq_descs(struct amdtp_stream *s, unsigned int count) +{ + struct seq_desc *descs = s->ctx_data.rx.seq.descs; + unsigned int seq_tail = s->ctx_data.rx.seq.tail; + const unsigned int seq_size = s->ctx_data.rx.seq.size; + + pool_ideal_syt_offsets(s, descs, seq_size, seq_tail, count); + + if (s->flags & CIP_BLOCKING) + pool_blocking_data_blocks(s, descs, seq_size, seq_tail, count); + else + pool_ideal_nonblocking_data_blocks(s, descs, seq_size, seq_tail, count); + + s->ctx_data.rx.seq.tail = (seq_tail + count) % seq_size; +} + +static void pool_replayed_seq(struct amdtp_stream *s, unsigned int count) +{ + struct amdtp_stream *target = s->ctx_data.rx.replay_target; + const struct seq_desc *cache = target->ctx_data.tx.cache.descs; + const unsigned int cache_size = target->ctx_data.tx.cache.size; + unsigned int cache_head = s->ctx_data.rx.cache_head; + struct seq_desc *descs = s->ctx_data.rx.seq.descs; + const unsigned int seq_size = s->ctx_data.rx.seq.size; + unsigned int seq_tail = s->ctx_data.rx.seq.tail; + int i; + + for (i = 0; i < count; ++i) { + descs[seq_tail] = cache[cache_head]; + seq_tail = (seq_tail + 1) % seq_size; + cache_head = (cache_head + 1) % cache_size; + } + + s->ctx_data.rx.seq.tail = seq_tail; + s->ctx_data.rx.cache_head = cache_head; +} + +static void pool_seq_descs(struct amdtp_stream *s, unsigned int count) +{ + struct amdtp_domain *d = s->domain; + + if (!d->replay.enable || !s->ctx_data.rx.replay_target) { + pool_ideal_seq_descs(s, count); + } else { + if (!d->replay.on_the_fly) { + pool_replayed_seq(s, count); + } else { + struct amdtp_stream *tx = s->ctx_data.rx.replay_target; + const unsigned int cache_size = tx->ctx_data.tx.cache.size; + const unsigned int cache_head = s->ctx_data.rx.cache_head; + unsigned int cached_cycles = calculate_cached_cycle_count(tx, cache_head); + + if (cached_cycles > count && cached_cycles > cache_size / 2) + pool_replayed_seq(s, count); + else + pool_ideal_seq_descs(s, count); + } + } +} + static void update_pcm_pointers(struct amdtp_stream *s, struct snd_pcm_substream *pcm, unsigned int frames) @@ -437,18 +605,21 @@ static void update_pcm_pointers(struct amdtp_stream *s, s->pcm_period_pointer += frames; if (s->pcm_period_pointer >= pcm->runtime->period_size) { s->pcm_period_pointer -= pcm->runtime->period_size; - queue_work(system_highpri_wq, &s->period_work); - } -} -static void pcm_period_work(struct work_struct *work) -{ - struct amdtp_stream *s = container_of(work, struct amdtp_stream, - period_work); - struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); - - if (pcm) - snd_pcm_period_elapsed(pcm); + // The program in user process should periodically check the status of intermediate + // buffer associated to PCM substream to process PCM frames in the buffer, instead + // of receiving notification of period elapsed by poll wait. + if (!pcm->runtime->no_period_wakeup) { + if (in_softirq()) { + // In software IRQ context for 1394 OHCI. + snd_pcm_period_elapsed(pcm); + } else { + // In process context of ALSA PCM application under acquired lock of + // PCM substream. + snd_pcm_period_elapsed_under_stream_lock(pcm); + } + } + } } static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params, @@ -505,7 +676,7 @@ static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2], } static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, - struct fw_iso_packet *params, + struct fw_iso_packet *params, unsigned int header_length, unsigned int data_blocks, unsigned int data_block_counter, unsigned int syt, unsigned int index) @@ -516,16 +687,15 @@ static void build_it_pkt_header(struct amdtp_stream *s, unsigned int cycle, payload_length = data_blocks * sizeof(__be32) * s->data_block_quadlets; params->payload_length = payload_length; - if (!(s->flags & CIP_NO_HEADER)) { + if (header_length > 0) { cip_header = (__be32 *)params->header; generate_cip_header(s, cip_header, data_block_counter, syt); - params->header_length = 2 * sizeof(__be32); - payload_length += params->header_length; + params->header_length = header_length; } else { cip_header = NULL; } - trace_amdtp_packet(s, cycle, cip_header, payload_length, data_blocks, + trace_amdtp_packet(s, cycle, cip_header, payload_length + header_length, data_blocks, data_block_counter, s->packet_index, index); } @@ -569,8 +739,7 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, /* Calculate data blocks */ fdf = (cip_header[1] & CIP_FDF_MASK) >> CIP_FDF_SHIFT; - if (payload_length < sizeof(__be32) * 2 || - (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) { + if (payload_length == 0 || (fmt == CIP_FMT_AM && fdf == AMDTP_FDF_NO_DATA)) { *data_blocks = 0; } else { unsigned int data_block_quadlets = @@ -585,8 +754,7 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, if (s->flags & CIP_WRONG_DBS) data_block_quadlets = s->data_block_quadlets; - *data_blocks = (payload_length / sizeof(__be32) - 2) / - data_block_quadlets; + *data_blocks = payload_length / sizeof(__be32) / data_block_quadlets; } /* Check data block counter continuity */ @@ -620,109 +788,163 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, *data_block_counter = dbc; - *syt = cip_header[1] & CIP_SYT_MASK; + if (!(s->flags & CIP_UNAWARE_SYT)) + *syt = cip_header[1] & CIP_SYT_MASK; return 0; } static int parse_ir_ctx_header(struct amdtp_stream *s, unsigned int cycle, const __be32 *ctx_header, - unsigned int *payload_length, unsigned int *data_blocks, unsigned int *data_block_counter, unsigned int *syt, unsigned int packet_index, unsigned int index) { + unsigned int payload_length; const __be32 *cip_header; unsigned int cip_header_size; - int err; - *payload_length = be32_to_cpu(ctx_header[0]) >> ISO_DATA_LENGTH_SHIFT; + payload_length = be32_to_cpu(ctx_header[0]) >> ISO_DATA_LENGTH_SHIFT; if (!(s->flags & CIP_NO_HEADER)) - cip_header_size = 8; + cip_header_size = CIP_HEADER_SIZE; else cip_header_size = 0; - if (*payload_length > cip_header_size + s->ctx_data.tx.max_ctx_payload_length) { + if (payload_length > cip_header_size + s->ctx_data.tx.max_ctx_payload_length) { dev_err(&s->unit->device, "Detect jumbo payload: %04x %04x\n", - *payload_length, cip_header_size + s->ctx_data.tx.max_ctx_payload_length); + payload_length, cip_header_size + s->ctx_data.tx.max_ctx_payload_length); return -EIO; } if (cip_header_size > 0) { - cip_header = ctx_header + 2; - err = check_cip_header(s, cip_header, *payload_length, - data_blocks, data_block_counter, syt); - if (err < 0) - return err; + if (payload_length >= cip_header_size) { + int err; + + cip_header = ctx_header + IR_CTX_HEADER_DEFAULT_QUADLETS; + err = check_cip_header(s, cip_header, payload_length - cip_header_size, + data_blocks, data_block_counter, syt); + if (err < 0) + return err; + } else { + // Handle the cycle so that empty packet arrives. + cip_header = NULL; + *data_blocks = 0; + *syt = 0; + } } else { cip_header = NULL; - err = 0; - *data_blocks = *payload_length / sizeof(__be32) / - s->data_block_quadlets; + *data_blocks = payload_length / sizeof(__be32) / s->data_block_quadlets; *syt = 0; if (*data_block_counter == UINT_MAX) *data_block_counter = 0; } - trace_amdtp_packet(s, cycle, cip_header, *payload_length, *data_blocks, + trace_amdtp_packet(s, cycle, cip_header, payload_length, *data_blocks, *data_block_counter, packet_index, index); - return err; + return 0; } // In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On // the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent // it. Thus, via Linux firewire subsystem, we can get the 3 bits for second. -static inline u32 compute_cycle_count(__be32 ctx_header_tstamp) +static inline u32 compute_ohci_cycle_count(__be32 ctx_header_tstamp) { u32 tstamp = be32_to_cpu(ctx_header_tstamp) & HEADER_TSTAMP_MASK; return (((tstamp >> 13) & 0x07) * 8000) + (tstamp & 0x1fff); } -static inline u32 increment_cycle_count(u32 cycle, unsigned int addend) +static inline u32 increment_ohci_cycle_count(u32 cycle, unsigned int addend) { cycle += addend; - if (cycle >= OHCI_MAX_SECOND * CYCLES_PER_SECOND) - cycle -= OHCI_MAX_SECOND * CYCLES_PER_SECOND; + if (cycle >= OHCI_SECOND_MODULUS * CYCLES_PER_SECOND) + cycle -= OHCI_SECOND_MODULUS * CYCLES_PER_SECOND; return cycle; } +static int compare_ohci_cycle_count(u32 lval, u32 rval) +{ + if (lval == rval) + return 0; + else if (lval < rval && rval - lval < OHCI_SECOND_MODULUS * CYCLES_PER_SECOND / 2) + return -1; + else + return 1; +} + // Align to actual cycle count for the packet which is going to be scheduled. // This module queued the same number of isochronous cycle as the size of queue // to kip isochronous cycle, therefore it's OK to just increment the cycle by // the size of queue for scheduled cycle. -static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp, - unsigned int queue_size) +static inline u32 compute_ohci_it_cycle(const __be32 ctx_header_tstamp, + unsigned int queue_size) { - u32 cycle = compute_cycle_count(ctx_header_tstamp); - return increment_cycle_count(cycle, queue_size); + u32 cycle = compute_ohci_cycle_count(ctx_header_tstamp); + return increment_ohci_cycle_count(cycle, queue_size); } static int generate_device_pkt_descs(struct amdtp_stream *s, struct pkt_desc *descs, const __be32 *ctx_header, - unsigned int packets) + unsigned int packets, + unsigned int *desc_count) { + unsigned int next_cycle = s->next_cycle; unsigned int dbc = s->data_block_counter; unsigned int packet_index = s->packet_index; unsigned int queue_size = s->queue_size; int i; int err; + *desc_count = 0; for (i = 0; i < packets; ++i) { - struct pkt_desc *desc = descs + i; + struct pkt_desc *desc = descs + *desc_count; unsigned int cycle; - unsigned int payload_length; + bool lost; unsigned int data_blocks; unsigned int syt; - cycle = compute_cycle_count(ctx_header[1]); + cycle = compute_ohci_cycle_count(ctx_header[1]); + lost = (next_cycle != cycle); + if (lost) { + if (s->flags & CIP_NO_HEADER) { + // Fireface skips transmission just for an isoc cycle corresponding + // to empty packet. + unsigned int prev_cycle = next_cycle; + + next_cycle = increment_ohci_cycle_count(next_cycle, 1); + lost = (next_cycle != cycle); + if (!lost) { + // Prepare a description for the skipped cycle for + // sequence replay. + desc->cycle = prev_cycle; + desc->syt = 0; + desc->data_blocks = 0; + desc->data_block_counter = dbc; + desc->ctx_payload = NULL; + ++desc; + ++(*desc_count); + } + } else if (s->flags & CIP_JUMBO_PAYLOAD) { + // OXFW970 skips transmission for several isoc cycles during + // asynchronous transaction. The sequence replay is impossible due + // to the reason. + unsigned int safe_cycle = increment_ohci_cycle_count(next_cycle, + IR_JUMBO_PAYLOAD_MAX_SKIP_CYCLES); + lost = (compare_ohci_cycle_count(safe_cycle, cycle) > 0); + } + if (lost) { + dev_err(&s->unit->device, "Detect discontinuity of cycle: %d %d\n", + next_cycle, cycle); + return -EIO; + } + } - err = parse_ir_ctx_header(s, cycle, ctx_header, &payload_length, - &data_blocks, &dbc, &syt, packet_index, i); + err = parse_ir_ctx_header(s, cycle, ctx_header, &data_blocks, &dbc, &syt, + packet_index, i); if (err < 0) return err; @@ -735,12 +957,13 @@ static int generate_device_pkt_descs(struct amdtp_stream *s, if (!(s->flags & CIP_DBC_IS_END_EVENT)) dbc = (dbc + desc->data_blocks) & 0xff; - ctx_header += - s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header); - + next_cycle = increment_ohci_cycle_count(next_cycle, 1); + ++(*desc_count); + ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header); packet_index = (packet_index + 1) % queue_size; } + s->next_cycle = next_cycle; s->data_block_counter = dbc; return 0; @@ -757,29 +980,28 @@ static unsigned int compute_syt(unsigned int syt_offset, unsigned int cycle, return syt & CIP_SYT_MASK; } -static void generate_pkt_descs(struct amdtp_stream *s, struct pkt_desc *descs, - const __be32 *ctx_header, unsigned int packets, - const struct seq_desc *seq_descs, - unsigned int seq_size) +static void generate_pkt_descs(struct amdtp_stream *s, const __be32 *ctx_header, unsigned int packets) { + struct pkt_desc *descs = s->pkt_descs; + const struct seq_desc *seq_descs = s->ctx_data.rx.seq.descs; + const unsigned int seq_size = s->ctx_data.rx.seq.size; unsigned int dbc = s->data_block_counter; - unsigned int seq_index = s->ctx_data.rx.seq_index; + unsigned int seq_head = s->ctx_data.rx.seq.head; + bool aware_syt = !(s->flags & CIP_UNAWARE_SYT); int i; for (i = 0; i < packets; ++i) { struct pkt_desc *desc = descs + i; unsigned int index = (s->packet_index + i) % s->queue_size; - const struct seq_desc *seq = seq_descs + seq_index; - unsigned int syt; + const struct seq_desc *seq = seq_descs + seq_head; - desc->cycle = compute_it_cycle(*ctx_header, s->queue_size); + desc->cycle = compute_ohci_it_cycle(*ctx_header, s->queue_size); + + if (aware_syt && seq->syt_offset != CIP_SYT_NO_INFO) + desc->syt = compute_syt(seq->syt_offset, desc->cycle, s->transfer_delay); + else + desc->syt = CIP_SYT_NO_INFO; - syt = seq->syt_offset; - if (syt != CIP_SYT_NO_INFO) { - syt = compute_syt(syt, desc->cycle, - s->ctx_data.rx.transfer_delay); - } - desc->syt = syt; desc->data_blocks = seq->data_blocks; if (s->flags & CIP_DBC_IS_END_EVENT) @@ -792,19 +1014,19 @@ static void generate_pkt_descs(struct amdtp_stream *s, struct pkt_desc *descs, desc->ctx_payload = s->buffer.packets[index].buffer; - seq_index = (seq_index + 1) % seq_size; + seq_head = (seq_head + 1) % seq_size; ++ctx_header; } s->data_block_counter = dbc; - s->ctx_data.rx.seq_index = seq_index; + s->ctx_data.rx.seq.head = seq_head; } static inline void cancel_stream(struct amdtp_stream *s) { s->packet_index = -1; - if (in_interrupt()) + if (in_softirq()) amdtp_stream_pcm_abort(s); WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); } @@ -822,16 +1044,17 @@ static void process_ctx_payloads(struct amdtp_stream *s, update_pcm_pointers(s, pcm, pcm_frames); } -static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, - size_t header_length, void *header, - void *private_data) +static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_t header_length, + void *header, void *private_data) { struct amdtp_stream *s = private_data; const struct amdtp_domain *d = s->domain; const __be32 *ctx_header = header; - unsigned int events_per_period = s->ctx_data.rx.events_per_period; + const unsigned int events_per_period = d->events_per_period; unsigned int event_count = s->ctx_data.rx.event_count; + unsigned int pkt_header_length; unsigned int packets; + bool need_hw_irq; int i; if (s->packet_index < 0) @@ -840,34 +1063,44 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, // Calculate the number of packets in buffer and check XRUN. packets = header_length / sizeof(*ctx_header); - generate_pkt_descs(s, s->pkt_descs, ctx_header, packets, d->seq_descs, - d->seq_size); + pool_seq_descs(s, packets); + + generate_pkt_descs(s, ctx_header, packets); process_ctx_payloads(s, s->pkt_descs, packets); + if (!(s->flags & CIP_NO_HEADER)) + pkt_header_length = IT_PKT_HEADER_SIZE_CIP; + else + pkt_header_length = 0; + + if (s == d->irq_target) { + // At NO_PERIOD_WAKEUP mode, the packets for all IT/IR contexts are processed by + // the tasks of user process operating ALSA PCM character device by calling ioctl(2) + // with some requests, instead of scheduled hardware IRQ of an IT context. + struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); + need_hw_irq = !pcm || !pcm->runtime->no_period_wakeup; + } else { + need_hw_irq = false; + } + for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = s->pkt_descs + i; - unsigned int syt; struct { struct fw_iso_packet params; - __be32 header[IT_PKT_HEADER_SIZE_CIP / sizeof(__be32)]; + __be32 header[CIP_HEADER_QUADLETS]; } template = { {0}, {0} }; bool sched_irq = false; - if (s->ctx_data.rx.syt_override < 0) - syt = desc->syt; - else - syt = s->ctx_data.rx.syt_override; - - build_it_pkt_header(s, desc->cycle, &template.params, + build_it_pkt_header(s, desc->cycle, &template.params, pkt_header_length, desc->data_blocks, desc->data_block_counter, - syt, i); + desc->syt, i); if (s == s->domain->irq_target) { event_count += desc->data_blocks; if (event_count >= events_per_period) { event_count -= events_per_period; - sched_irq = true; + sched_irq = need_hw_irq; } } @@ -880,13 +1113,99 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, s->ctx_data.rx.event_count = event_count; } -static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, - size_t header_length, void *header, - void *private_data) +static void skip_rx_packets(struct fw_iso_context *context, u32 tstamp, size_t header_length, + void *header, void *private_data) +{ + struct amdtp_stream *s = private_data; + struct amdtp_domain *d = s->domain; + const __be32 *ctx_header = header; + unsigned int packets; + unsigned int cycle; + int i; + + if (s->packet_index < 0) + return; + + packets = header_length / sizeof(*ctx_header); + + cycle = compute_ohci_it_cycle(ctx_header[packets - 1], s->queue_size); + s->next_cycle = increment_ohci_cycle_count(cycle, 1); + + for (i = 0; i < packets; ++i) { + struct fw_iso_packet params = { + .header_length = 0, + .payload_length = 0, + }; + bool sched_irq = (s == d->irq_target && i == packets - 1); + + if (queue_out_packet(s, ¶ms, sched_irq) < 0) { + cancel_stream(s); + return; + } + } +} + +static void irq_target_callback(struct fw_iso_context *context, u32 tstamp, size_t header_length, + void *header, void *private_data); + +static void process_rx_packets_intermediately(struct fw_iso_context *context, u32 tstamp, + size_t header_length, void *header, void *private_data) +{ + struct amdtp_stream *s = private_data; + struct amdtp_domain *d = s->domain; + __be32 *ctx_header = header; + const unsigned int queue_size = s->queue_size; + unsigned int packets; + unsigned int offset; + + if (s->packet_index < 0) + return; + + packets = header_length / sizeof(*ctx_header); + + offset = 0; + while (offset < packets) { + unsigned int cycle = compute_ohci_it_cycle(ctx_header[offset], queue_size); + + if (compare_ohci_cycle_count(cycle, d->processing_cycle.rx_start) >= 0) + break; + + ++offset; + } + + if (offset > 0) { + unsigned int length = sizeof(*ctx_header) * offset; + + skip_rx_packets(context, tstamp, length, ctx_header, private_data); + if (amdtp_streaming_error(s)) + return; + + ctx_header += offset; + header_length -= length; + } + + if (offset < packets) { + s->ready_processing = true; + wake_up(&s->ready_wait); + + process_rx_packets(context, tstamp, header_length, ctx_header, private_data); + if (amdtp_streaming_error(s)) + return; + + if (s == d->irq_target) + s->context->callback.sc = irq_target_callback; + else + s->context->callback.sc = process_rx_packets; + } +} + +static void process_tx_packets(struct fw_iso_context *context, u32 tstamp, size_t header_length, + void *header, void *private_data) { struct amdtp_stream *s = private_data; __be32 *ctx_header = header; unsigned int packets; + unsigned int desc_count; int i; int err; @@ -896,14 +1215,20 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, // Calculate the number of packets in buffer and check XRUN. packets = header_length / s->ctx_data.tx.ctx_header_size; - err = generate_device_pkt_descs(s, s->pkt_descs, ctx_header, packets); + desc_count = 0; + err = generate_device_pkt_descs(s, s->pkt_descs, ctx_header, packets, &desc_count); if (err < 0) { if (err != -EAGAIN) { cancel_stream(s); return; } } else { - process_ctx_payloads(s, s->pkt_descs, packets); + struct amdtp_domain *d = s->domain; + + process_ctx_payloads(s, s->pkt_descs, desc_count); + + if (d->replay.enable) + cache_seq(s, s->pkt_descs, desc_count); } for (i = 0; i < packets; ++i) { @@ -916,79 +1241,194 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, } } -static void pool_ideal_seq_descs(struct amdtp_domain *d, unsigned int packets) +static void drop_tx_packets(struct fw_iso_context *context, u32 tstamp, size_t header_length, + void *header, void *private_data) { - struct amdtp_stream *irq_target = d->irq_target; - unsigned int seq_tail = d->seq_tail; - unsigned int seq_size = d->seq_size; - unsigned int min_avail; - struct amdtp_stream *s; + struct amdtp_stream *s = private_data; + const __be32 *ctx_header = header; + unsigned int packets; + unsigned int cycle; + int i; - min_avail = d->seq_size; - list_for_each_entry(s, &d->streams, list) { - unsigned int seq_index; - unsigned int avail; + if (s->packet_index < 0) + return; + + packets = header_length / s->ctx_data.tx.ctx_header_size; - if (s->direction == AMDTP_IN_STREAM) - continue; + ctx_header += (packets - 1) * s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header); + cycle = compute_ohci_cycle_count(ctx_header[1]); + s->next_cycle = increment_ohci_cycle_count(cycle, 1); - seq_index = s->ctx_data.rx.seq_index; - avail = d->seq_tail; - if (seq_index > avail) - avail += d->seq_size; - avail -= seq_index; + for (i = 0; i < packets; ++i) { + struct fw_iso_packet params = {0}; - if (avail < min_avail) - min_avail = avail; + if (queue_in_packet(s, ¶ms) < 0) { + cancel_stream(s); + return; + } } +} - while (min_avail < packets) { - struct seq_desc *desc = d->seq_descs + seq_tail; +static void process_tx_packets_intermediately(struct fw_iso_context *context, u32 tstamp, + size_t header_length, void *header, void *private_data) +{ + struct amdtp_stream *s = private_data; + struct amdtp_domain *d = s->domain; + __be32 *ctx_header; + unsigned int packets; + unsigned int offset; - desc->syt_offset = calculate_syt_offset(&d->last_syt_offset, - &d->syt_offset_state, irq_target->sfc); - desc->data_blocks = calculate_data_blocks(&d->data_block_state, - !!(irq_target->flags & CIP_BLOCKING), - desc->syt_offset == CIP_SYT_NO_INFO, - irq_target->syt_interval, irq_target->sfc); + if (s->packet_index < 0) + return; - ++seq_tail; - seq_tail %= seq_size; + packets = header_length / s->ctx_data.tx.ctx_header_size; - ++min_avail; + offset = 0; + ctx_header = header; + while (offset < packets) { + unsigned int cycle = compute_ohci_cycle_count(ctx_header[1]); + + if (compare_ohci_cycle_count(cycle, d->processing_cycle.tx_start) >= 0) + break; + + ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(__be32); + ++offset; } - d->seq_tail = seq_tail; + ctx_header = header; + + if (offset > 0) { + size_t length = s->ctx_data.tx.ctx_header_size * offset; + + drop_tx_packets(context, tstamp, length, ctx_header, s); + if (amdtp_streaming_error(s)) + return; + + ctx_header += length / sizeof(*ctx_header); + header_length -= length; + } + + if (offset < packets) { + s->ready_processing = true; + wake_up(&s->ready_wait); + + process_tx_packets(context, tstamp, header_length, ctx_header, s); + if (amdtp_streaming_error(s)) + return; + + context->callback.sc = process_tx_packets; + } } -static void irq_target_callback(struct fw_iso_context *context, u32 tstamp, - size_t header_length, void *header, - void *private_data) +static void drop_tx_packets_initially(struct fw_iso_context *context, u32 tstamp, + size_t header_length, void *header, void *private_data) { - struct amdtp_stream *irq_target = private_data; - struct amdtp_domain *d = irq_target->domain; - unsigned int packets = header_length / sizeof(__be32); - struct amdtp_stream *s; + struct amdtp_stream *s = private_data; + struct amdtp_domain *d = s->domain; + __be32 *ctx_header; + unsigned int count; + unsigned int events; + int i; + + if (s->packet_index < 0) + return; + + count = header_length / s->ctx_data.tx.ctx_header_size; + + // Attempt to detect any event in the batch of packets. + events = 0; + ctx_header = header; + for (i = 0; i < count; ++i) { + unsigned int payload_quads = + (be32_to_cpu(*ctx_header) >> ISO_DATA_LENGTH_SHIFT) / sizeof(__be32); + unsigned int data_blocks; + + if (s->flags & CIP_NO_HEADER) { + data_blocks = payload_quads / s->data_block_quadlets; + } else { + __be32 *cip_headers = ctx_header + IR_CTX_HEADER_DEFAULT_QUADLETS; + + if (payload_quads < CIP_HEADER_QUADLETS) { + data_blocks = 0; + } else { + payload_quads -= CIP_HEADER_QUADLETS; + + if (s->flags & CIP_UNAWARE_SYT) { + data_blocks = payload_quads / s->data_block_quadlets; + } else { + u32 cip1 = be32_to_cpu(cip_headers[1]); + + // NODATA packet can includes any data blocks but they are + // not available as event. + if ((cip1 & CIP_NO_DATA) == CIP_NO_DATA) + data_blocks = 0; + else + data_blocks = payload_quads / s->data_block_quadlets; + } + } + } - // Record enough entries with extra 3 cycles at least. - pool_ideal_seq_descs(d, packets + 3); + events += data_blocks; - out_stream_callback(context, tstamp, header_length, header, irq_target); - if (amdtp_streaming_error(irq_target)) - goto error; + ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(__be32); + } + + drop_tx_packets(context, tstamp, header_length, header, s); + + if (events > 0) + s->ctx_data.tx.event_starts = true; + + // Decide the cycle count to begin processing content of packet in IR contexts. + { + unsigned int stream_count = 0; + unsigned int event_starts_count = 0; + unsigned int cycle = UINT_MAX; + + list_for_each_entry(s, &d->streams, list) { + if (s->direction == AMDTP_IN_STREAM) { + ++stream_count; + if (s->ctx_data.tx.event_starts) + ++event_starts_count; + } + } + + if (stream_count == event_starts_count) { + unsigned int next_cycle; + + list_for_each_entry(s, &d->streams, list) { + if (s->direction != AMDTP_IN_STREAM) + continue; + + next_cycle = increment_ohci_cycle_count(s->next_cycle, + d->processing_cycle.tx_init_skip); + if (cycle == UINT_MAX || + compare_ohci_cycle_count(next_cycle, cycle) > 0) + cycle = next_cycle; + + s->context->callback.sc = process_tx_packets_intermediately; + } + + d->processing_cycle.tx_start = cycle; + } + } +} + +static void process_ctxs_in_domain(struct amdtp_domain *d) +{ + struct amdtp_stream *s; list_for_each_entry(s, &d->streams, list) { - if (s != irq_target && amdtp_stream_running(s)) { + if (s != d->irq_target && amdtp_stream_running(s)) fw_iso_context_flush_completions(s->context); - if (amdtp_streaming_error(s)) - goto error; - } + + if (amdtp_streaming_error(s)) + goto error; } return; error: - if (amdtp_stream_running(irq_target)) - cancel_stream(irq_target); + if (amdtp_stream_running(d->irq_target)) + cancel_stream(d->irq_target); list_for_each_entry(s, &d->streams, list) { if (amdtp_stream_running(s)) @@ -996,37 +1436,99 @@ error: } } -// this is executed one time. +static void irq_target_callback(struct fw_iso_context *context, u32 tstamp, size_t header_length, + void *header, void *private_data) +{ + struct amdtp_stream *s = private_data; + struct amdtp_domain *d = s->domain; + + process_rx_packets(context, tstamp, header_length, header, private_data); + process_ctxs_in_domain(d); +} + +static void irq_target_callback_intermediately(struct fw_iso_context *context, u32 tstamp, + size_t header_length, void *header, void *private_data) +{ + struct amdtp_stream *s = private_data; + struct amdtp_domain *d = s->domain; + + process_rx_packets_intermediately(context, tstamp, header_length, header, private_data); + process_ctxs_in_domain(d); +} + +static void irq_target_callback_skip(struct fw_iso_context *context, u32 tstamp, + size_t header_length, void *header, void *private_data) +{ + struct amdtp_stream *s = private_data; + struct amdtp_domain *d = s->domain; + bool ready_to_start; + + skip_rx_packets(context, tstamp, header_length, header, private_data); + process_ctxs_in_domain(d); + + if (d->replay.enable && !d->replay.on_the_fly) { + unsigned int rx_count = 0; + unsigned int rx_ready_count = 0; + struct amdtp_stream *rx; + + list_for_each_entry(rx, &d->streams, list) { + struct amdtp_stream *tx; + unsigned int cached_cycles; + + if (rx->direction != AMDTP_OUT_STREAM) + continue; + ++rx_count; + + tx = rx->ctx_data.rx.replay_target; + cached_cycles = calculate_cached_cycle_count(tx, 0); + if (cached_cycles > tx->ctx_data.tx.cache.size / 2) + ++rx_ready_count; + } + + ready_to_start = (rx_count == rx_ready_count); + } else { + ready_to_start = true; + } + + // Decide the cycle count to begin processing content of packet in IT contexts. All of IT + // contexts are expected to start and get callback when reaching here. + if (ready_to_start) { + unsigned int cycle = s->next_cycle; + list_for_each_entry(s, &d->streams, list) { + if (s->direction != AMDTP_OUT_STREAM) + continue; + + if (compare_ohci_cycle_count(s->next_cycle, cycle) > 0) + cycle = s->next_cycle; + + if (s == d->irq_target) + s->context->callback.sc = irq_target_callback_intermediately; + else + s->context->callback.sc = process_rx_packets_intermediately; + } + + d->processing_cycle.rx_start = cycle; + } +} + +// This is executed one time. For in-stream, first packet has come. For out-stream, prepared to +// transmit first packet. static void amdtp_stream_first_callback(struct fw_iso_context *context, u32 tstamp, size_t header_length, void *header, void *private_data) { struct amdtp_stream *s = private_data; - const __be32 *ctx_header = header; - u32 cycle; - - /* - * For in-stream, first packet has come. - * For out-stream, prepared to transmit first packet - */ - s->callbacked = true; - wake_up(&s->callback_wait); + struct amdtp_domain *d = s->domain; if (s->direction == AMDTP_IN_STREAM) { - cycle = compute_cycle_count(ctx_header[1]); - - context->callback.sc = in_stream_callback; + context->callback.sc = drop_tx_packets_initially; } else { - cycle = compute_it_cycle(*ctx_header, s->queue_size); - - if (s == s->domain->irq_target) - context->callback.sc = irq_target_callback; + if (s == d->irq_target) + context->callback.sc = irq_target_callback_skip; else - context->callback.sc = out_stream_callback; + context->callback.sc = skip_rx_packets; } - s->start_cycle = cycle; - context->callback.sc(context, tstamp, header_length, header, s); } @@ -1035,8 +1537,6 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, * @s: the AMDTP stream to start * @channel: the isochronous channel on the bus * @speed: firewire speed code - * @start_cycle: the isochronous cycle to start the context. Start immediately - * if negative value is given. * @queue_size: The number of packets in the queue. * @idle_irq_interval: the interval to queue packet during initial state. * @@ -1045,8 +1545,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, * device can be started. */ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, - int start_cycle, unsigned int queue_size, - unsigned int idle_irq_interval) + unsigned int queue_size, unsigned int idle_irq_interval) { bool is_irq_target = (s == s->domain->irq_target); unsigned int ctx_header_size; @@ -1075,27 +1574,21 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, } // initialize packet buffer. - max_ctx_payload_size = amdtp_stream_get_max_payload(s); if (s->direction == AMDTP_IN_STREAM) { dir = DMA_FROM_DEVICE; type = FW_ISO_CONTEXT_RECEIVE; - if (!(s->flags & CIP_NO_HEADER)) { - max_ctx_payload_size -= 8; + if (!(s->flags & CIP_NO_HEADER)) ctx_header_size = IR_CTX_HEADER_SIZE_CIP; - } else { + else ctx_header_size = IR_CTX_HEADER_SIZE_NO_CIP; - } } else { dir = DMA_TO_DEVICE; type = FW_ISO_CONTEXT_TRANSMIT; ctx_header_size = 0; // No effect for IT context. - - if (!(s->flags & CIP_NO_HEADER)) - max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP; } + max_ctx_payload_size = amdtp_stream_get_max_ctx_payload_size(s); - err = iso_packets_buffer_init(&s->buffer, s->unit, queue_size, - max_ctx_payload_size, dir); + err = iso_packets_buffer_init(&s->buffer, s->unit, queue_size, max_ctx_payload_size, dir); if (err < 0) goto err_unlock; s->queue_size = queue_size; @@ -1116,6 +1609,50 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, if (s->direction == AMDTP_IN_STREAM) { s->ctx_data.tx.max_ctx_payload_length = max_ctx_payload_size; s->ctx_data.tx.ctx_header_size = ctx_header_size; + s->ctx_data.tx.event_starts = false; + + if (s->domain->replay.enable) { + // struct fw_iso_context.drop_overflow_headers is false therefore it's + // possible to cache much unexpectedly. + s->ctx_data.tx.cache.size = max_t(unsigned int, s->syt_interval * 2, + queue_size * 3 / 2); + s->ctx_data.tx.cache.tail = 0; + s->ctx_data.tx.cache.descs = kcalloc(s->ctx_data.tx.cache.size, + sizeof(*s->ctx_data.tx.cache.descs), GFP_KERNEL); + if (!s->ctx_data.tx.cache.descs) { + err = -ENOMEM; + goto err_context; + } + } + } else { + static const struct { + unsigned int data_block; + unsigned int syt_offset; + } *entry, initial_state[] = { + [CIP_SFC_32000] = { 4, 3072 }, + [CIP_SFC_48000] = { 6, 1024 }, + [CIP_SFC_96000] = { 12, 1024 }, + [CIP_SFC_192000] = { 24, 1024 }, + [CIP_SFC_44100] = { 0, 67 }, + [CIP_SFC_88200] = { 0, 67 }, + [CIP_SFC_176400] = { 0, 67 }, + }; + + s->ctx_data.rx.seq.descs = kcalloc(queue_size, sizeof(*s->ctx_data.rx.seq.descs), GFP_KERNEL); + if (!s->ctx_data.rx.seq.descs) { + err = -ENOMEM; + goto err_context; + } + s->ctx_data.rx.seq.size = queue_size; + s->ctx_data.rx.seq.tail = 0; + s->ctx_data.rx.seq.head = 0; + + entry = &initial_state[s->sfc]; + s->ctx_data.rx.data_block_state = entry->data_block; + s->ctx_data.rx.syt_offset_state = entry->syt_offset; + s->ctx_data.rx.last_syt_offset = TICKS_PER_CYCLE; + + s->ctx_data.rx.event_count = 0; } if (s->flags & CIP_NO_HEADER) @@ -1158,8 +1695,8 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, if ((s->flags & CIP_EMPTY_WITH_TAG0) || (s->flags & CIP_NO_HEADER)) tag |= FW_ISO_CONTEXT_MATCH_TAG0; - s->callbacked = false; - err = fw_iso_context_start(s->context, start_cycle, 0, tag); + s->ready_processing = false; + err = fw_iso_context_start(s->context, -1, 0, tag); if (err < 0) goto err_pkt_descs; @@ -1169,6 +1706,12 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed, err_pkt_descs: kfree(s->pkt_descs); err_context: + if (s->direction == AMDTP_OUT_STREAM) { + kfree(s->ctx_data.rx.seq.descs); + } else { + if (s->domain->replay.enable) + kfree(s->ctx_data.tx.cache.descs); + } fw_iso_context_destroy(s->context); s->context = ERR_PTR(-1); err_buffer: @@ -1191,28 +1734,12 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, { struct amdtp_stream *irq_target = d->irq_target; + // Process isochronous packets queued till recent isochronous cycle to handle PCM frames. if (irq_target && amdtp_stream_running(irq_target)) { - // This function is called in software IRQ context of - // period_work or process context. - // - // When the software IRQ context was scheduled by software IRQ - // context of IT contexts, queued packets were already handled. - // Therefore, no need to flush the queue in buffer furthermore. - // - // When the process context reach here, some packets will be - // already queued in the buffer. These packets should be handled - // immediately to keep better granularity of PCM pointer. - // - // Later, the process context will sometimes schedules software - // IRQ context of the period_work. Then, no need to flush the - // queue by the same reason as described in the above - if (current_work() != &s->period_work) { - // Queued packet should be processed without any kernel - // preemption to keep latency against bus cycle. - preempt_disable(); + // In software IRQ context, the call causes dead-lock to disable the tasklet + // synchronously. + if (!in_softirq()) fw_iso_context_flush_completions(irq_target->context); - preempt_enable(); - } } return READ_ONCE(s->pcm_buffer_pointer); @@ -1232,13 +1759,8 @@ int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s) // Process isochronous packets for recent isochronous cycle to handle // queued PCM frames. - if (irq_target && amdtp_stream_running(irq_target)) { - // Queued packet should be processed without any kernel - // preemption to keep latency against bus cycle. - preempt_disable(); + if (irq_target && amdtp_stream_running(irq_target)) fw_iso_context_flush_completions(irq_target->context); - preempt_enable(); - } return 0; } @@ -1272,14 +1794,18 @@ static void amdtp_stream_stop(struct amdtp_stream *s) return; } - cancel_work_sync(&s->period_work); fw_iso_context_stop(s->context); fw_iso_context_destroy(s->context); s->context = ERR_PTR(-1); iso_packets_buffer_destroy(&s->buffer, s->unit); kfree(s->pkt_descs); - s->callbacked = false; + if (s->direction == AMDTP_OUT_STREAM) { + kfree(s->ctx_data.rx.seq.descs); + } else { + if (s->domain->replay.enable) + kfree(s->ctx_data.tx.cache.descs); + } mutex_unlock(&s->mutex); } @@ -1311,8 +1837,6 @@ int amdtp_domain_init(struct amdtp_domain *d) d->events_per_period = 0; - d->seq_descs = NULL; - return 0; } EXPORT_SYMBOL_GPL(amdtp_domain_init); @@ -1355,26 +1879,49 @@ int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, } EXPORT_SYMBOL_GPL(amdtp_domain_add_stream); -static int get_current_cycle_time(struct fw_card *fw_card, int *cur_cycle) +// Make the reference from rx stream to tx stream for sequence replay. When the number of tx streams +// is less than the number of rx streams, the first tx stream is selected. +static int make_association(struct amdtp_domain *d) { - int generation; - int rcode; - __be32 reg; - u32 data; - - // This is a request to local 1394 OHCI controller and expected to - // complete without any event waiting. - generation = fw_card->generation; - smp_rmb(); // node_id vs. generation. - rcode = fw_run_transaction(fw_card, TCODE_READ_QUADLET_REQUEST, - fw_card->node_id, generation, SCODE_100, - CSR_REGISTER_BASE + CSR_CYCLE_TIME, - ®, sizeof(reg)); - if (rcode != RCODE_COMPLETE) - return -EIO; + unsigned int dst_index = 0; + struct amdtp_stream *rx; + + // Make association to replay target. + list_for_each_entry(rx, &d->streams, list) { + if (rx->direction == AMDTP_OUT_STREAM) { + unsigned int src_index = 0; + struct amdtp_stream *tx = NULL; + struct amdtp_stream *s; + + list_for_each_entry(s, &d->streams, list) { + if (s->direction == AMDTP_IN_STREAM) { + if (dst_index == src_index) { + tx = s; + break; + } + + ++src_index; + } + } + if (!tx) { + // Select the first entry. + list_for_each_entry(s, &d->streams, list) { + if (s->direction == AMDTP_IN_STREAM) { + tx = s; + break; + } + } + // No target is available to replay sequence. + if (!tx) + return -EINVAL; + } - data = be32_to_cpu(reg); - *cur_cycle = data >> 12; + rx->ctx_data.rx.replay_target = tx; + rx->ctx_data.rx.cache_head = 0; + + ++dst_index; + } + } return 0; } @@ -1382,39 +1929,44 @@ static int get_current_cycle_time(struct fw_card *fw_card, int *cur_cycle) /** * amdtp_domain_start - start sending packets for isoc context in the domain. * @d: the AMDTP domain. - * @ir_delay_cycle: the cycle delay to start all IR contexts. + * @tx_init_skip_cycles: the number of cycles to skip processing packets at initial stage of IR + * contexts. + * @replay_seq: whether to replay the sequence of packet in IR context for the sequence of packet in + * IT context. + * @replay_on_the_fly: transfer rx packets according to nominal frequency, then begin to replay + * according to arrival of events in tx packets. */ -int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle) +int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles, bool replay_seq, + bool replay_on_the_fly) { - static const struct { - unsigned int data_block; - unsigned int syt_offset; - } *entry, initial_state[] = { - [CIP_SFC_32000] = { 4, 3072 }, - [CIP_SFC_48000] = { 6, 1024 }, - [CIP_SFC_96000] = { 12, 1024 }, - [CIP_SFC_192000] = { 24, 1024 }, - [CIP_SFC_44100] = { 0, 67 }, - [CIP_SFC_88200] = { 0, 67 }, - [CIP_SFC_176400] = { 0, 67 }, - }; unsigned int events_per_buffer = d->events_per_buffer; unsigned int events_per_period = d->events_per_period; - unsigned int idle_irq_interval; unsigned int queue_size; struct amdtp_stream *s; - int cycle; + bool found = false; int err; + if (replay_seq) { + err = make_association(d); + if (err < 0) + return err; + } + d->replay.enable = replay_seq; + d->replay.on_the_fly = replay_on_the_fly; + // Select an IT context as IRQ target. list_for_each_entry(s, &d->streams, list) { - if (s->direction == AMDTP_OUT_STREAM) + if (s->direction == AMDTP_OUT_STREAM) { + found = true; break; + } } - if (!s) + if (!found) return -ENXIO; d->irq_target = s; + d->processing_cycle.tx_init_skip = tx_init_skip_cycles; + // This is a case that AMDTP streams in domain run just for MIDI // substream. Use the number of events equivalent to 10 msec as // interval of hardware IRQ. @@ -1426,82 +1978,24 @@ int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle) queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer, amdtp_rate_table[d->irq_target->sfc]); - d->seq_descs = kcalloc(queue_size, sizeof(*d->seq_descs), GFP_KERNEL); - if (!d->seq_descs) - return -ENOMEM; - d->seq_size = queue_size; - d->seq_tail = 0; - - entry = &initial_state[s->sfc]; - d->data_block_state = entry->data_block; - d->syt_offset_state = entry->syt_offset; - d->last_syt_offset = TICKS_PER_CYCLE; - - if (ir_delay_cycle > 0) { - struct fw_card *fw_card = fw_parent_device(s->unit)->card; - - err = get_current_cycle_time(fw_card, &cycle); - if (err < 0) - goto error; - - // No need to care overflow in cycle field because of enough - // width. - cycle += ir_delay_cycle; - - // Round up to sec field. - if ((cycle & 0x00001fff) >= CYCLES_PER_SECOND) { - unsigned int sec; - - // The sec field can overflow. - sec = (cycle & 0xffffe000) >> 13; - cycle = (++sec << 13) | - ((cycle & 0x00001fff) / CYCLES_PER_SECOND); - } - - // In OHCI 1394 specification, lower 2 bits are available for - // sec field. - cycle &= 0x00007fff; - } else { - cycle = -1; - } - list_for_each_entry(s, &d->streams, list) { - int cycle_match; + unsigned int idle_irq_interval = 0; - if (s->direction == AMDTP_IN_STREAM) { - cycle_match = cycle; - } else { - // IT context starts immediately. - cycle_match = -1; - s->ctx_data.rx.seq_index = 0; + if (s->direction == AMDTP_OUT_STREAM && s == d->irq_target) { + idle_irq_interval = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period, + amdtp_rate_table[d->irq_target->sfc]); } - if (s != d->irq_target) { - err = amdtp_stream_start(s, s->channel, s->speed, - cycle_match, queue_size, 0); - if (err < 0) - goto error; - } + // Starts immediately but actually DMA context starts several hundred cycles later. + err = amdtp_stream_start(s, s->channel, s->speed, queue_size, idle_irq_interval); + if (err < 0) + goto error; } - s = d->irq_target; - s->ctx_data.rx.events_per_period = events_per_period; - s->ctx_data.rx.event_count = 0; - s->ctx_data.rx.seq_index = 0; - - idle_irq_interval = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period, - amdtp_rate_table[d->irq_target->sfc]); - err = amdtp_stream_start(s, s->channel, s->speed, -1, queue_size, - idle_irq_interval); - if (err < 0) - goto error; - return 0; error: list_for_each_entry(s, &d->streams, list) amdtp_stream_stop(s); - kfree(d->seq_descs); - d->seq_descs = NULL; return err; } EXPORT_SYMBOL_GPL(amdtp_domain_start); @@ -1526,8 +2020,5 @@ void amdtp_domain_stop(struct amdtp_domain *d) d->events_per_period = 0; d->irq_target = NULL; - - kfree(d->seq_descs); - d->seq_descs = NULL; } EXPORT_SYMBOL_GPL(amdtp_domain_stop); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index a3daa1f2c1c4..1f957c946c95 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -35,6 +35,8 @@ * @CIP_NO_HEADERS: a lack of headers in packets * @CIP_UNALIGHED_DBC: Only for in-stream. The value of dbc is not alighed to * the value of current SYT_INTERVAL; e.g. initial value is not zero. + * @CIP_UNAWARE_SYT: For outgoing packet, the value in SYT field of CIP is 0xffff. + * For incoming packet, the value in SYT field of CIP is not handled. */ enum cip_flags { CIP_NONBLOCKING = 0x00, @@ -48,6 +50,7 @@ enum cip_flags { CIP_HEADER_WITHOUT_EOH = 0x80, CIP_NO_HEADER = 0x100, CIP_UNALIGHED_DBC = 0x200, + CIP_UNAWARE_SYT = 0x400, }; /** @@ -112,7 +115,8 @@ typedef unsigned int (*amdtp_stream_process_ctx_payloads_t)( struct amdtp_domain; struct amdtp_stream { struct fw_unit *unit; - enum cip_flags flags; + // The combination of cip_flags enumeration-constants. + unsigned int flags; enum amdtp_stream_direction direction; struct mutex mutex; @@ -134,19 +138,37 @@ struct amdtp_stream { // Fixed interval of dbc between previos/current // packets. unsigned int dbc_interval; + + // The device starts multiplexing events to the packet. + bool event_starts; + + struct { + struct seq_desc *descs; + unsigned int size; + unsigned int tail; + } cache; } tx; struct { - // To calculate CIP data blocks and tstamp. - unsigned int transfer_delay; - unsigned int seq_index; - // To generate CIP header. unsigned int fdf; - int syt_override; // To generate constant hardware IRQ. unsigned int event_count; - unsigned int events_per_period; + + // To calculate CIP data blocks and tstamp. + struct { + struct seq_desc *descs; + unsigned int size; + unsigned int tail; + unsigned int head; + } seq; + + unsigned int data_block_state; + unsigned int syt_offset_state; + unsigned int last_syt_offset; + + struct amdtp_stream *replay_target; + unsigned int cache_head; } rx; } ctx_data; @@ -157,20 +179,21 @@ struct amdtp_stream { unsigned int sph; unsigned int fmt; - /* Internal flags. */ + // Internal flags. + unsigned int transfer_delay; enum cip_sfc sfc; unsigned int syt_interval; /* For a PCM substream processing. */ struct snd_pcm_substream *pcm; - struct work_struct period_work; snd_pcm_uframes_t pcm_buffer_pointer; unsigned int pcm_period_pointer; - /* To wait for first packet. */ - bool callbacked; - wait_queue_head_t callback_wait; - u32 start_cycle; + // To start processing content of packets at the same cycle in several contexts for + // each direction. + bool ready_processing; + wait_queue_head_t ready_wait; + unsigned int next_cycle; /* For backends to process data blocks. */ void *protocol; @@ -184,7 +207,7 @@ struct amdtp_stream { }; int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, - enum amdtp_stream_direction dir, enum cip_flags flags, + enum amdtp_stream_direction dir, unsigned int flags, unsigned int fmt, amdtp_stream_process_ctx_payloads_t process_ctx_payloads, unsigned int protocol_size); @@ -259,21 +282,6 @@ static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) return sfc & 1; } -/** - * amdtp_stream_wait_callback - sleep till callbacked or timeout - * @s: the AMDTP stream - * @timeout: msec till timeout - * - * If this function return false, the AMDTP stream should be stopped. - */ -static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s, - unsigned int timeout) -{ - return wait_event_timeout(s->callback_wait, - s->callbacked, - msecs_to_jiffies(timeout)) > 0; -} - struct seq_desc { unsigned int syt_offset; unsigned int data_blocks; @@ -287,13 +295,16 @@ struct amdtp_domain { struct amdtp_stream *irq_target; - struct seq_desc *seq_descs; - unsigned int seq_size; - unsigned int seq_tail; + struct { + unsigned int tx_init_skip; + unsigned int tx_start; + unsigned int rx_start; + } processing_cycle; - unsigned int data_block_state; - unsigned int syt_offset_state; - unsigned int last_syt_offset; + struct { + bool enable:1; + bool on_the_fly:1; + } replay; }; int amdtp_domain_init(struct amdtp_domain *d); @@ -302,7 +313,8 @@ void amdtp_domain_destroy(struct amdtp_domain *d); int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, int channel, int speed); -int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle); +int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles, bool replay_seq, + bool replay_on_the_fly); void amdtp_domain_stop(struct amdtp_domain *d); static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d, @@ -319,4 +331,25 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, struct amdtp_stream *s); int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s); +/** + * amdtp_domain_wait_ready - sleep till being ready to process packets or timeout + * @d: the AMDTP domain + * @timeout_ms: msec till timeout + * + * If this function return false, the AMDTP domain should be stopped. + */ +static inline bool amdtp_domain_wait_ready(struct amdtp_domain *d, unsigned int timeout_ms) +{ + struct amdtp_stream *s; + + list_for_each_entry(s, &d->streams, list) { + unsigned int j = msecs_to_jiffies(timeout_ms); + + if (wait_event_interruptible_timeout(s->ready_wait, s->ready_processing, j) <= 0) + return false; + } + + return true; +} + #endif diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index daeecfa8b9aa..42980da45fbf 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -40,14 +40,12 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS); #define VEN_EDIROL 0x000040ab #define VEN_PRESONUS 0x00000a92 #define VEN_BRIDGECO 0x000007f5 -#define VEN_MACKIE1 0x0000000f -#define VEN_MACKIE2 0x00000ff2 +#define VEN_MACKIE 0x00000ff2 #define VEN_STANTON 0x00001260 #define VEN_TASCAM 0x0000022e #define VEN_BEHRINGER 0x00001564 #define VEN_APOGEE 0x000003db #define VEN_ESI 0x00000f1b -#define VEN_ACOUSTIC 0x00000002 #define VEN_CME 0x0000000a #define VEN_PHONIC 0x00001496 #define VEN_LYNX 0x000019e5 @@ -56,14 +54,15 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS); #define VEN_TERRATEC 0x00000aac #define VEN_YAMAHA 0x0000a0de #define VEN_FOCUSRITE 0x0000130e -#define VEN_MAUDIO1 0x00000d6c -#define VEN_MAUDIO2 0x000007f5 +#define VEN_MAUDIO 0x00000d6c #define VEN_DIGIDESIGN 0x00a07e +#define OUI_SHOUYO 0x002327 #define MODEL_FOCUSRITE_SAFFIRE_BOTH 0x00000000 #define MODEL_MAUDIO_AUDIOPHILE_BOTH 0x00010060 #define MODEL_MAUDIO_FW1814 0x00010071 #define MODEL_MAUDIO_PROJECTMIX 0x00010091 +#define MODEL_MAUDIO_PROFIRELIGHTBRIDGE 0x000100a1 static int name_device(struct snd_bebob *bebob) @@ -74,7 +73,6 @@ name_device(struct snd_bebob *bebob) u32 hw_id; u32 data[2] = {0}; u32 revision; - u32 version; int err; /* get vendor name from root directory */ @@ -107,12 +105,6 @@ name_device(struct snd_bebob *bebob) if (err < 0) goto end; - err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_BEBOB_VERSION, - &version); - if (err < 0) - goto end; - bebob->version = version; - strcpy(bebob->card->driver, "BeBoB"); strcpy(bebob->card->shortname, model); strcpy(bebob->card->mixername, model); @@ -135,6 +127,9 @@ bebob_card_free(struct snd_card *card) mutex_unlock(&devices_mutex); snd_bebob_stream_destroy_duplex(bebob); + + mutex_destroy(&bebob->mutex); + fw_unit_put(bebob->unit); } static const struct snd_bebob_spec * @@ -162,16 +157,55 @@ check_audiophile_booted(struct fw_unit *unit) return strncmp(name, "FW Audiophile Bootloader", 24) != 0; } -static void -do_registration(struct work_struct *work) +static int detect_quirks(struct snd_bebob *bebob, const struct ieee1394_device_id *entry) +{ + if (entry->vendor_id == VEN_MAUDIO) { + switch (entry->model_id) { + case MODEL_MAUDIO_PROFIRELIGHTBRIDGE: + // M-Audio ProFire Lightbridge has a quirk to transfer packets with + // discontinuous cycle or data block counter in early stage of packet + // streaming. The cycle span from the first packet with event is variable. + bebob->quirks |= SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC; + break; + case MODEL_MAUDIO_FW1814: + case MODEL_MAUDIO_PROJECTMIX: + // At high sampling rate, M-Audio special firmware transmits empty packet + // with the value of dbc incremented by 8. + bebob->quirks |= SND_BEBOB_QUIRK_WRONG_DBC; + break; + default: + break; + } + } + + return 0; +} + +static int bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { - struct snd_bebob *bebob = - container_of(work, struct snd_bebob, dwork.work); unsigned int card_index; + struct snd_card *card; + struct snd_bebob *bebob; + const struct snd_bebob_spec *spec; int err; - if (bebob->registered) - return; + if (entry->vendor_id == VEN_FOCUSRITE && + entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH) + spec = get_saffire_spec(unit); + else if (entry->vendor_id == VEN_MAUDIO && + entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH && + !check_audiophile_booted(unit)) + spec = NULL; + else + spec = (const struct snd_bebob_spec *)entry->driver_data; + + if (spec == NULL) { + // To boot up M-Audio models. + if (entry->vendor_id == VEN_MAUDIO || entry->vendor_id == VEN_BRIDGECO) + return snd_bebob_maudio_load_firmware(unit); + else + return -ENODEV; + } mutex_lock(&devices_mutex); for (card_index = 0; card_index < SNDRV_CARDS; card_index++) { @@ -180,27 +214,40 @@ do_registration(struct work_struct *work) } if (card_index >= SNDRV_CARDS) { mutex_unlock(&devices_mutex); - return; + return -ENOENT; } - err = snd_card_new(&bebob->unit->device, index[card_index], - id[card_index], THIS_MODULE, 0, &bebob->card); + err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE, + sizeof(*bebob), &card); if (err < 0) { mutex_unlock(&devices_mutex); - return; + return err; } + card->private_free = bebob_card_free; set_bit(card_index, devices_used); mutex_unlock(&devices_mutex); - bebob->card->private_free = bebob_card_free; - bebob->card->private_data = bebob; + bebob = card->private_data; + bebob->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, bebob); + bebob->card = card; + bebob->card_index = card_index; + + bebob->spec = spec; + mutex_init(&bebob->mutex); + spin_lock_init(&bebob->lock); + init_waitqueue_head(&bebob->hwdep_wait); err = name_device(bebob); if (err < 0) goto error; + err = detect_quirks(bebob, entry); + if (err < 0) + goto error; + if (bebob->spec == &maudio_special_spec) { - if (bebob->entry->model_id == MODEL_MAUDIO_FW1814) + if (entry->model_id == MODEL_MAUDIO_FW1814) err = snd_bebob_maudio_special_discover(bebob, true); else err = snd_bebob_maudio_special_discover(bebob, false); @@ -230,80 +277,26 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - err = snd_card_register(bebob->card); + err = snd_card_register(card); if (err < 0) goto error; - bebob->registered = true; - - return; -error: - snd_card_free(bebob->card); - dev_info(&bebob->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int -bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) -{ - struct snd_bebob *bebob; - const struct snd_bebob_spec *spec; - - if (entry->vendor_id == VEN_FOCUSRITE && - entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH) - spec = get_saffire_spec(unit); - else if (entry->vendor_id == VEN_MAUDIO1 && - entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH && - !check_audiophile_booted(unit)) - spec = NULL; - else - spec = (const struct snd_bebob_spec *)entry->driver_data; - - if (spec == NULL) { - if (entry->vendor_id == VEN_MAUDIO1 || - entry->vendor_id == VEN_MAUDIO2) - return snd_bebob_maudio_load_firmware(unit); - else - return -ENODEV; - } - - /* Allocate this independent of sound card instance. */ - bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob), - GFP_KERNEL); - if (!bebob) - return -ENOMEM; - bebob->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, bebob); - - bebob->entry = entry; - bebob->spec = spec; - mutex_init(&bebob->mutex); - spin_lock_init(&bebob->lock); - init_waitqueue_head(&bebob->hwdep_wait); - - /* Allocate and register this sound card later. */ - INIT_DEFERRABLE_WORK(&bebob->dwork, do_registration); - - if (entry->vendor_id != VEN_MAUDIO1 || - (entry->model_id != MODEL_MAUDIO_FW1814 && - entry->model_id != MODEL_MAUDIO_PROJECTMIX)) { - snd_fw_schedule_registration(unit, &bebob->dwork); - } else { - /* - * This is a workaround. This bus reset seems to have an effect - * to make devices correctly handling transactions. Without - * this, the devices have gap_count mismatch. This causes much - * failure of transaction. - * - * Just after registration, user-land application receive - * signals from dbus and starts I/Os. To avoid I/Os till the - * future bus reset, registration is done in next update(). - */ - fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card, - false, true); + if (entry->vendor_id == VEN_MAUDIO && + (entry->model_id == MODEL_MAUDIO_FW1814 || entry->model_id == MODEL_MAUDIO_PROJECTMIX)) { + // This is a workaround. This bus reset seems to have an effect to make devices + // correctly handling transactions. Without this, the devices have gap_count + // mismatch. This causes much failure of transaction. + // + // Just after registration, user-land application receive signals from dbus and + // starts I/Os. To avoid I/Os till the future bus reset, registration is done in + // next update(). + fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card, false, true); } return 0; +error: + snd_card_free(card); + return err; } /* @@ -330,11 +323,7 @@ bebob_update(struct fw_unit *unit) if (bebob == NULL) return; - /* Postpone a workqueue for deferred registration. */ - if (!bebob->registered) - snd_fw_schedule_registration(unit, &bebob->dwork); - else - fcp_bus_reset(bebob->unit); + fcp_bus_reset(bebob->unit); } static void bebob_remove(struct fw_unit *unit) @@ -344,20 +333,8 @@ static void bebob_remove(struct fw_unit *unit) if (bebob == NULL) return; - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_delayed_work_sync(&bebob->dwork); - - if (bebob->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(bebob->card); - } - - mutex_destroy(&bebob->mutex); - fw_unit_put(bebob->unit); + // Block till all of ALSA character devices are released. + snd_card_free(bebob->card); } static const struct snd_bebob_rate_spec normal_rate_spec = { @@ -370,6 +347,22 @@ static const struct snd_bebob_spec spec_normal = { .meter = NULL }; +#define SPECIFIER_1394TA 0x00a02d + +// The immediate entry for version in unit directory differs depending on models: +// * 0x010001 +// * 0x014001 +#define SND_BEBOB_DEV_ENTRY(vendor, model, data) \ +{ \ + .match_flags = IEEE1394_MATCH_VENDOR_ID | \ + IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID, \ + .vendor_id = vendor, \ + .model_id = model, \ + .specifier_id = SPECIFIER_1394TA, \ + .driver_data = (kernel_ulong_t)data \ +} + static const struct ieee1394_device_id bebob_id_table[] = { /* Edirol, FA-66 */ SND_BEBOB_DEV_ENTRY(VEN_EDIROL, 0x00010049, &spec_normal), @@ -386,9 +379,9 @@ static const struct ieee1394_device_id bebob_id_table[] = { /* BridgeCo, Audio5 */ SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal), /* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */ - SND_BEBOB_DEV_ENTRY(VEN_MACKIE2, 0x00010065, &spec_normal), - // Mackie, d.2 (Firewire option card) and d.2 Pro (the card is built-in). - SND_BEBOB_DEV_ENTRY(VEN_MACKIE1, 0x00010067, &spec_normal), + SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010065, &spec_normal), + // Mackie, d.2 (optional Firewire card with DM1000). + SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010067, &spec_normal), /* Stanton, ScratchAmp */ SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal), /* Tascam, IF-FW DM */ @@ -410,17 +403,20 @@ static const struct ieee1394_device_id bebob_id_table[] = { SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal), /* ESI, Quatafire610 */ SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal), - /* AcousticReality, eARMasterOne */ - SND_BEBOB_DEV_ENTRY(VEN_ACOUSTIC, 0x00000002, &spec_normal), + // AcousticReality, eARMasterOne. Terratec OEM. + SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000002, &spec_normal), /* CME, MatrixKFW */ SND_BEBOB_DEV_ENTRY(VEN_CME, 0x00030000, &spec_normal), - /* Phonic, Helix Board 12 MkII */ + // Phonic Helix Board 12 FireWire MkII. SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00050000, &spec_normal), - /* Phonic, Helix Board 18 MkII */ + // Phonic Helix Board 18 FireWire MkII. SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00060000, &spec_normal), - /* Phonic, Helix Board 24 MkII */ + // Phonic Helix Board 24 FireWire MkII. SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00070000, &spec_normal), - /* Phonic, Helix Board 12 Universal/18 Universal/24 Universal */ + // Phonic FireFly 808 FireWire. + SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00080000, &spec_normal), + // Phonic FireFly 202, 302, 808 Universal. + // Phinic Helix Board 12/18/24 FireWire, 12/18/24 Universal SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00000000, &spec_normal), /* Lynx, Aurora 8/16 (LT-FW) */ SND_BEBOB_DEV_ENTRY(VEN_LYNX, 0x00000001, &spec_normal), @@ -447,45 +443,35 @@ static const struct ieee1394_device_id bebob_id_table[] = { /* Focusrite, SaffirePro 26 I/O */ SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec), /* Focusrite, SaffirePro 10 I/O */ - { - // The combination of vendor_id and model_id is the same as the - // same as the one of Liquid Saffire 56. - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VEN_FOCUSRITE, - .model_id = 0x000006, - .specifier_id = 0x00a02d, - .version = 0x010001, - .driver_data = (kernel_ulong_t)&saffirepro_10_spec, - }, + SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x000006, &saffirepro_10_spec), /* Focusrite, Saffire(no label and LE) */ SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH, &saffire_spec), - /* M-Audio, Firewire 410 */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010058, NULL), /* bootloader */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010046, &maudio_fw410_spec), + // M-Audio, Firewire 410. The vendor field is left as BridgeCo. AG. + SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010058, NULL), + SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010046, &maudio_fw410_spec), /* M-Audio, Firewire Audiophile */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_AUDIOPHILE_BOTH, + SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_AUDIOPHILE_BOTH, &maudio_audiophile_spec), /* M-Audio, Firewire Solo */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010062, &maudio_solo_spec), + SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010062, &maudio_solo_spec), /* M-Audio, Ozonic */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x0000000a, &maudio_ozonic_spec), + SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x0000000a, &maudio_ozonic_spec), /* M-Audio NRV10 */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010081, &maudio_nrv10_spec), + SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010081, &maudio_nrv10_spec), /* M-Audio, ProFireLightbridge */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x000100a1, &spec_normal), + SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_PROFIRELIGHTBRIDGE, &spec_normal), /* Firewire 1814 */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010070, NULL), /* bootloader */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_FW1814, + SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010070, NULL), /* bootloader */ + SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_FW1814, &maudio_special_spec), /* M-Audio ProjectMix */ - SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_PROJECTMIX, + SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_PROJECTMIX, &maudio_special_spec), /* Digidesign Mbox 2 Pro */ SND_BEBOB_DEV_ENTRY(VEN_DIGIDESIGN, 0x0000a9, &spec_normal), + // Toneweal FW66. + SND_BEBOB_DEV_ENTRY(OUI_SHOUYO, 0x020002, &spec_normal), /* IDs are unknown but able to be supported */ /* Apogee, Mini-ME Firewire */ /* Apogee, Mini-DAC Firewire */ @@ -496,11 +482,6 @@ static const struct ieee1394_device_id bebob_id_table[] = { /* Infrasonic, Windy6 */ /* Mackie, Digital X Bus x.200 */ /* Mackie, Digital X Bus x.400 */ - /* Phonic, HB 12 */ - /* Phonic, HB 24 */ - /* Phonic, HB 18 */ - /* Phonic, FireFly 202 */ - /* Phonic, FireFly 302 */ /* Rolf Spuler, Firewire Guitar */ {} }; diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 4e0ed84adbee..4d73ecb30d79 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -75,6 +75,11 @@ struct snd_bebob_spec { const struct snd_bebob_meter_spec *meter; }; +enum snd_bebob_quirk { + SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC = (1 << 0), + SND_BEBOB_QUIRK_WRONG_DBC = (1 << 1), +}; + struct snd_bebob { struct snd_card *card; struct fw_unit *unit; @@ -83,11 +88,8 @@ struct snd_bebob { struct mutex mutex; spinlock_t lock; - bool registered; - struct delayed_work dwork; - - const struct ieee1394_device_id *entry; const struct snd_bebob_spec *spec; + unsigned int quirks; // Combination of snd_bebob_quirk enumerations. unsigned int midi_input_ports; unsigned int midi_output_ports; @@ -113,9 +115,6 @@ struct snd_bebob { /* for M-Audio special devices */ void *maudio_special_quirk; - /* For BeBoB version quirk. */ - unsigned int version; - struct amdtp_domain domain; }; @@ -254,13 +253,4 @@ extern const struct snd_bebob_spec maudio_special_spec; int snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814); int snd_bebob_maudio_load_firmware(struct fw_unit *unit); -#define SND_BEBOB_DEV_ENTRY(vendor, model, data) \ -{ \ - .match_flags = IEEE1394_MATCH_VENDOR_ID | \ - IEEE1394_MATCH_MODEL_ID, \ - .vendor_id = vendor, \ - .model_id = model, \ - .driver_data = (kernel_ulong_t)data \ -} - #endif diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index b612ee3e33b6..8629b14ded76 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -7,8 +7,7 @@ #include "./bebob.h" -#define CALLBACK_TIMEOUT 2500 -#define FW_ISO_RESOURCE_DELAY 1000 +#define READY_TIMEOUT_MS 4000 /* * NOTE; @@ -402,12 +401,6 @@ static void break_both_connections(struct snd_bebob *bebob) { cmp_connection_break(&bebob->in_conn); cmp_connection_break(&bebob->out_conn); - - // These models seem to be in transition state for a longer time. When - // accessing in the state, any transactions is corrupted. In the worst - // case, the device is going to reboot. - if (bebob->version < 2) - msleep(600); } static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) @@ -437,6 +430,7 @@ static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) { + unsigned int flags = CIP_BLOCKING; enum amdtp_stream_direction dir_stream; struct cmp_connection *conn; enum cmp_direction dir_conn; @@ -452,32 +446,21 @@ static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) dir_conn = CMP_INPUT; } + if (stream == &bebob->tx_stream) { + if (bebob->quirks & SND_BEBOB_QUIRK_WRONG_DBC) + flags |= CIP_EMPTY_HAS_WRONG_DBC; + } + err = cmp_connection_init(conn, bebob->unit, dir_conn, 0); if (err < 0) return err; - err = amdtp_am824_init(stream, bebob->unit, dir_stream, CIP_BLOCKING); + err = amdtp_am824_init(stream, bebob->unit, dir_stream, flags); if (err < 0) { cmp_connection_destroy(conn); return err; } - if (stream == &bebob->tx_stream) { - // BeBoB v3 transfers packets with these qurks: - // - In the beginning of streaming, the value of dbc is - // incremented even if no data blocks are transferred. - // - The value of dbc is reset suddenly. - if (bebob->version > 2) - bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC | - CIP_SKIP_DBC_ZERO_CHECK; - - // At high sampling rate, M-Audio special firmware transmits - // empty packet with the value of dbc incremented by 8 but the - // others are valid to IEC 61883-1. - if (bebob->maudio_special_quirk) - bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC; - } - return 0; } @@ -624,9 +607,8 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) if (!amdtp_stream_running(&bebob->rx_stream)) { enum snd_bebob_clock_type src; - struct amdtp_stream *master, *slave; unsigned int curr_rate; - unsigned int ir_delay_cycle; + unsigned int tx_init_skip_cycles; if (bebob->maudio_special_quirk) { err = bebob->spec->rate->get(bebob, &curr_rate); @@ -638,36 +620,28 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) if (err < 0) return err; - if (src != SND_BEBOB_CLOCK_TYPE_SYT) { - master = &bebob->tx_stream; - slave = &bebob->rx_stream; - } else { - master = &bebob->rx_stream; - slave = &bebob->tx_stream; - } - - err = start_stream(bebob, master); + err = start_stream(bebob, &bebob->rx_stream); if (err < 0) goto error; - err = start_stream(bebob, slave); + err = start_stream(bebob, &bebob->tx_stream); if (err < 0) goto error; - // The device postpones start of transmission mostly for 1 sec - // after receives packets firstly. For safe, IR context starts - // 0.4 sec (=3200 cycles) later to version 1 or 2 firmware, - // 2.0 sec (=16000 cycles) for version 3 firmware. This is - // within 2.5 sec (=CALLBACK_TIMEOUT). - // Furthermore, some devices transfer isoc packets with - // discontinuous counter in the beginning of packet streaming. - // The delay has an effect to avoid detection of this - // discontinuity. - if (bebob->version < 2) - ir_delay_cycle = 3200; + if (!(bebob->quirks & SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC)) + tx_init_skip_cycles = 0; else - ir_delay_cycle = 16000; - err = amdtp_domain_start(&bebob->domain, ir_delay_cycle); + tx_init_skip_cycles = 16000; + + // MEMO: Some devices start packet transmission long enough after establishment of + // CMP connection. In the early stage of packet streaming, any device transfers + // NODATA packets. After several hundred cycles, it begins to multiplex event into + // the packet with adequate value of syt field in CIP header. Some devices are + // strictly to generate any discontinuity in the sequence of tx packet when they + // receives inadequate sequence of value in syt field of CIP header. In the case, + // the request to break CMP connection is often corrupted, then any transaction + // results in unrecoverable error, sometimes generate bus-reset. + err = amdtp_domain_start(&bebob->domain, tx_init_skip_cycles, true, false); if (err < 0) goto error; @@ -684,10 +658,9 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) } } - if (!amdtp_stream_wait_callback(&bebob->rx_stream, - CALLBACK_TIMEOUT) || - !amdtp_stream_wait_callback(&bebob->tx_stream, - CALLBACK_TIMEOUT)) { + // Some devices postpone start of transmission mostly for 1 sec after receives + // packets firstly. + if (!amdtp_domain_wait_ready(&bebob->domain, READY_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } @@ -883,6 +856,11 @@ static int detect_midi_ports(struct snd_bebob *bebob, err = avc_bridgeco_get_plug_ch_count(bebob->unit, addr, &ch_count); if (err < 0) break; + // Yamaha GO44, GO46, Terratec Phase 24, Phase x24 reports 0 for the number of + // channels in external output plug 3 (MIDI type) even if it has a pair of physical + // MIDI jacks. As a workaround, assume it as one. + if (ch_count == 0) + ch_count = 1; *midi_ports += ch_count; } @@ -961,12 +939,12 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob) if (err < 0) goto end; - err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN, + err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN, plugs[2], &bebob->midi_input_ports); if (err < 0) goto end; - err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT, + err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT, plugs[3], &bebob->midi_output_ports); if (err < 0) goto end; diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index c4dfe76500c2..f99e00083141 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -8,8 +8,8 @@ #include "dice.h" -#define CALLBACK_TIMEOUT 200 -#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC) +#define READY_TIMEOUT_MS 200 +#define NOTIFICATION_TIMEOUT_MS 100 struct reg_params { unsigned int count; @@ -57,13 +57,9 @@ int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, return -EINVAL; } -/* - * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE - * to GLOBAL_STATUS. Especially, just after powering on, these are different. - */ -static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate) +static int select_clock(struct snd_dice *dice, unsigned int rate) { - __be32 reg, nominal; + __be32 reg; u32 data; int i; int err; @@ -94,19 +90,8 @@ static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate) return err; if (wait_for_completion_timeout(&dice->clock_accepted, - msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { - /* - * Old versions of Dice firmware transfer no notification when - * the same clock status as current one is set. In this case, - * just check current clock status. - */ - err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS, - &nominal, sizeof(nominal)); - if (err < 0) - return err; - if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED)) - return -ETIMEDOUT; - } + msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) + return -ETIMEDOUT; return 0; } @@ -304,7 +289,7 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, // Just after owning the unit (GLOBAL_OWNER), the unit can // return invalid stream formats. Selecting clock parameters // have an effect for the unit to refine it. - err = ensure_phase_lock(dice, rate); + err = select_clock(dice, rate); if (err < 0) return err; @@ -459,20 +444,17 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) goto error; } - err = amdtp_domain_start(&dice->domain, 0); + // MEMO: The device immediately starts packet transmission when enabled. Some + // devices are strictly to generate any discontinuity in the sequence of tx packet + // when they receives invalid sequence of presentation time in CIP header. The + // sequence replay for media clock recovery can suppress the behaviour. + err = amdtp_domain_start(&dice->domain, 0, true, false); if (err < 0) goto error; - for (i = 0; i < MAX_STREAMS; i++) { - if ((i < tx_params.count && - !amdtp_stream_wait_callback(&dice->tx_stream[i], - CALLBACK_TIMEOUT)) || - (i < rx_params.count && - !amdtp_stream_wait_callback(&dice->rx_stream[i], - CALLBACK_TIMEOUT))) { - err = -ETIMEDOUT; - goto error; - } + if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) { + err = -ETIMEDOUT; + goto error; } } @@ -653,7 +635,7 @@ int snd_dice_stream_detect_current_formats(struct snd_dice *dice) * invalid stream formats. Selecting clock parameters have an effect * for the unit to refine it. */ - err = ensure_phase_lock(dice, rate); + err = select_clock(dice, rate); if (err < 0) return err; diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c index 2c0dde29a024..92941ef83cd5 100644 --- a/sound/firewire/dice/dice-transaction.c +++ b/sound/firewire/dice/dice-transaction.c @@ -155,7 +155,7 @@ static void dice_notification(struct fw_card *card, struct fw_request *request, fw_send_response(card, request, RCODE_COMPLETE); - if (bits & NOTIFY_LOCK_CHG) + if (bits & NOTIFY_CLOCK_ACCEPTED) complete(&dice->clock_accepted); wake_up(&dice->hwdep_wait); } diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 239d164b0eea..f75902bc8e74 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -135,22 +135,51 @@ static void dice_card_free(struct snd_card *card) snd_dice_stream_destroy_duplex(dice); snd_dice_transaction_destroy(dice); + + mutex_destroy(&dice->mutex); + fw_unit_put(dice->unit); } -static void do_registration(struct work_struct *work) +static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { - struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work); + struct snd_card *card; + struct snd_dice *dice; + snd_dice_detect_formats_t detect_formats; int err; - if (dice->registered) - return; + if (!entry->driver_data && entry->vendor_id != OUI_SSL) { + err = check_dice_category(unit); + if (err < 0) + return -ENODEV; + } - err = snd_card_new(&dice->unit->device, -1, NULL, THIS_MODULE, 0, - &dice->card); + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*dice), &card); if (err < 0) - return; - dice->card->private_free = dice_card_free; - dice->card->private_data = dice; + return err; + card->private_free = dice_card_free; + + dice = card->private_data; + dice->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, dice); + dice->card = card; + + if (!entry->driver_data) + detect_formats = snd_dice_stream_detect_current_formats; + else + detect_formats = (snd_dice_detect_formats_t)entry->driver_data; + + // Below models are compliant to IEC 61883-1/6 and have no quirk at high sampling transfer + // frequency. + // * Avid M-Box 3 Pro + // * M-Audio Profire 610 + // * M-Audio Profire 2626 + if (entry->vendor_id == OUI_MAUDIO || entry->vendor_id == OUI_AVID) + dice->disable_double_pcm_frames = true; + + spin_lock_init(&dice->lock); + mutex_init(&dice->mutex); + init_completion(&dice->clock_accepted); + init_waitqueue_head(&dice->hwdep_wait); err = snd_dice_transaction_init(dice); if (err < 0) @@ -162,7 +191,7 @@ static void do_registration(struct work_struct *work) dice_card_strings(dice); - err = dice->detect_formats(dice); + err = detect_formats(dice); if (err < 0) goto error; @@ -184,105 +213,34 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - err = snd_card_register(dice->card); + err = snd_card_register(card); if (err < 0) goto error; - dice->registered = true; - - return; -error: - snd_card_free(dice->card); - dev_info(&dice->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int dice_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) -{ - struct snd_dice *dice; - int err; - - if (!entry->driver_data && entry->vendor_id != OUI_SSL) { - err = check_dice_category(unit); - if (err < 0) - return -ENODEV; - } - - /* Allocate this independent of sound card instance. */ - dice = devm_kzalloc(&unit->device, sizeof(struct snd_dice), GFP_KERNEL); - if (!dice) - return -ENOMEM; - dice->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, dice); - - if (!entry->driver_data) { - dice->detect_formats = snd_dice_stream_detect_current_formats; - } else { - dice->detect_formats = - (snd_dice_detect_formats_t)entry->driver_data; - } - - // Below models are compliant to IEC 61883-1/6 and have no quirk at high sampling transfer - // frequency. - // * Avid M-Box 3 Pro - // * M-Audio Profire 610 - // * M-Audio Profire 2626 - if (entry->vendor_id == OUI_MAUDIO || entry->vendor_id == OUI_AVID) - dice->disable_double_pcm_frames = true; - - spin_lock_init(&dice->lock); - mutex_init(&dice->mutex); - init_completion(&dice->clock_accepted); - init_waitqueue_head(&dice->hwdep_wait); - - /* Allocate and register this sound card later. */ - INIT_DEFERRABLE_WORK(&dice->dwork, do_registration); - snd_fw_schedule_registration(unit, &dice->dwork); - return 0; +error: + snd_card_free(card); + return err; } static void dice_remove(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_delayed_work_sync(&dice->dwork); - - if (dice->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(dice->card); - } - - mutex_destroy(&dice->mutex); - fw_unit_put(dice->unit); + // Block till all of ALSA character devices are released. + snd_card_free(dice->card); } static void dice_bus_reset(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); - /* Postpone a workqueue for deferred registration. */ - if (!dice->registered) - snd_fw_schedule_registration(unit, &dice->dwork); - /* The handler address register becomes initialized. */ snd_dice_transaction_reinit(dice); - /* - * After registration, userspace can start packet streaming, then this - * code block works fine. - */ - if (dice->registered) { - mutex_lock(&dice->mutex); - snd_dice_stream_update_duplex(dice); - mutex_unlock(&dice->mutex); - } + mutex_lock(&dice->mutex); + snd_dice_stream_update_duplex(dice); + mutex_unlock(&dice->mutex); } #define DICE_INTERFACE 0x000001 diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 3c967d1b3605..fd440cc625f9 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -78,9 +78,6 @@ struct snd_dice { spinlock_t lock; struct mutex mutex; - bool registered; - struct delayed_work dwork; - /* Offsets for sub-addresses */ unsigned int global_offset; unsigned int rx_offset; @@ -93,7 +90,6 @@ struct snd_dice { unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; unsigned int tx_midi_ports[MAX_STREAMS]; unsigned int rx_midi_ports[MAX_STREAMS]; - snd_dice_detect_formats_t detect_formats; struct fw_address_handler notification_handler; int owner_generation; diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index d613642a2ce3..59b86c8d89e1 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -396,16 +396,13 @@ int amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir) { amdtp_stream_process_ctx_payloads_t process_ctx_payloads; - enum cip_flags flags; + unsigned int flags = CIP_NONBLOCKING | CIP_UNAWARE_SYT; // Use different mode between incoming/outgoing. - if (dir == AMDTP_IN_STREAM) { - flags = CIP_NONBLOCKING; + if (dir == AMDTP_IN_STREAM) process_ctx_payloads = process_ir_ctx_payloads; - } else { - flags = CIP_BLOCKING; + else process_ctx_payloads = process_it_ctx_payloads; - } return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, process_ctx_payloads, sizeof(struct amdtp_dot)); diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 405d6903bfbc..a15f55b0dce3 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -7,7 +7,7 @@ #include "digi00x.h" -#define CALLBACK_TIMEOUT 500 +#define READY_TIMEOUT_MS 200 const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = { [SND_DG00X_RATE_44100] = 44100, @@ -375,14 +375,15 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) if (err < 0) goto error; - err = amdtp_domain_start(&dg00x->domain, 0); + // NOTE: The device doesn't start packet transmission till receiving any packet. + // It ignores presentation time expressed by the value of syt field of CIP header + // in received packets. The sequence of the number of data blocks per packet is + // important for media clock recovery. + err = amdtp_domain_start(&dg00x->domain, 0, true, true); if (err < 0) goto error; - if (!amdtp_stream_wait_callback(&dg00x->rx_stream, - CALLBACK_TIMEOUT) || - !amdtp_stream_wait_callback(&dg00x->tx_stream, - CALLBACK_TIMEOUT)) { + if (!amdtp_domain_wait_ready(&dg00x->domain, READY_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index ab8408966ec3..995302808c27 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -47,23 +47,32 @@ static void dg00x_card_free(struct snd_card *card) snd_dg00x_stream_destroy_duplex(dg00x); snd_dg00x_transaction_unregister(dg00x); + + mutex_destroy(&dg00x->mutex); + fw_unit_put(dg00x->unit); } -static void do_registration(struct work_struct *work) +static int snd_dg00x_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { - struct snd_dg00x *dg00x = - container_of(work, struct snd_dg00x, dwork.work); + struct snd_card *card; + struct snd_dg00x *dg00x; int err; - if (dg00x->registered) - return; - - err = snd_card_new(&dg00x->unit->device, -1, NULL, THIS_MODULE, 0, - &dg00x->card); + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*dg00x), &card); if (err < 0) - return; - dg00x->card->private_free = dg00x_card_free; - dg00x->card->private_data = dg00x; + return err; + card->private_free = dg00x_card_free; + + dg00x = card->private_data; + dg00x->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, dg00x); + dg00x->card = card; + + mutex_init(&dg00x->mutex); + spin_lock_init(&dg00x->lock); + init_waitqueue_head(&dg00x->hwdep_wait); + + dg00x->is_console = entry->model_id == MODEL_CONSOLE; err = name_card(dg00x); if (err < 0) @@ -91,85 +100,33 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - err = snd_card_register(dg00x->card); + err = snd_card_register(card); if (err < 0) goto error; - dg00x->registered = true; - - return; -error: - snd_card_free(dg00x->card); - dev_info(&dg00x->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int snd_dg00x_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) -{ - struct snd_dg00x *dg00x; - - /* Allocate this independent of sound card instance. */ - dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x), - GFP_KERNEL); - if (!dg00x) - return -ENOMEM; - - dg00x->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, dg00x); - - mutex_init(&dg00x->mutex); - spin_lock_init(&dg00x->lock); - init_waitqueue_head(&dg00x->hwdep_wait); - - dg00x->is_console = entry->model_id == MODEL_CONSOLE; - - /* Allocate and register this sound card later. */ - INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration); - snd_fw_schedule_registration(unit, &dg00x->dwork); - return 0; +error: + snd_card_free(card); + return err; } static void snd_dg00x_update(struct fw_unit *unit) { struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); - /* Postpone a workqueue for deferred registration. */ - if (!dg00x->registered) - snd_fw_schedule_registration(unit, &dg00x->dwork); - snd_dg00x_transaction_reregister(dg00x); - /* - * After registration, userspace can start packet streaming, then this - * code block works fine. - */ - if (dg00x->registered) { - mutex_lock(&dg00x->mutex); - snd_dg00x_stream_update_duplex(dg00x); - mutex_unlock(&dg00x->mutex); - } + mutex_lock(&dg00x->mutex); + snd_dg00x_stream_update_duplex(dg00x); + mutex_unlock(&dg00x->mutex); } static void snd_dg00x_remove(struct fw_unit *unit) { struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_delayed_work_sync(&dg00x->dwork); - - if (dg00x->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(dg00x->card); - } - - mutex_destroy(&dg00x->mutex); - fw_unit_put(dg00x->unit); + // Block till all of ALSA character devices are released. + snd_card_free(dg00x->card); } static const struct ieee1394_device_id snd_dg00x_id_table[] = { diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 129de8edd5ea..82b647d383c5 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -37,9 +37,6 @@ struct snd_dg00x { struct mutex mutex; spinlock_t lock; - bool registered; - struct delayed_work dwork; - struct amdtp_stream tx_stream; struct fw_iso_resources tx_resources; diff --git a/sound/firewire/fireface/amdtp-ff.c b/sound/firewire/fireface/amdtp-ff.c index 119c0076b17a..98177b0666d3 100644 --- a/sound/firewire/fireface/amdtp-ff.c +++ b/sound/firewire/fireface/amdtp-ff.c @@ -168,6 +168,6 @@ int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit, else process_ctx_payloads = process_it_ctx_payloads; - return amdtp_stream_init(s, unit, dir, CIP_NO_HEADER, 0, + return amdtp_stream_init(s, unit, dir, CIP_BLOCKING | CIP_UNAWARE_SYT | CIP_NO_HEADER, 0, process_ctx_payloads, sizeof(struct amdtp_ff)); } diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index 5452115c0ef9..95bf405adb3d 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -7,7 +7,7 @@ #include "ff.h" -#define CALLBACK_TIMEOUT_MS 200 +#define READY_TIMEOUT_MS 200 int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc, enum snd_ff_stream_mode *mode) @@ -199,14 +199,15 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) if (err < 0) goto error; - err = amdtp_domain_start(&ff->domain, 0); + // NOTE: The device doesn't transfer packets unless receiving any packet. The + // sequence of tx packets includes cycle skip corresponding to empty packet or + // NODATA packet in IEC 61883-1/6. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&ff->domain, 0, true, true); if (err < 0) goto error; - if (!amdtp_stream_wait_callback(&ff->rx_stream, - CALLBACK_TIMEOUT_MS) || - !amdtp_stream_wait_callback(&ff->tx_stream, - CALLBACK_TIMEOUT_MS)) { + if (!amdtp_domain_wait_ready(&ff->domain, READY_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index bc39269415d2..7bf51d062021 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -42,22 +42,33 @@ static void ff_card_free(struct snd_card *card) snd_ff_stream_destroy_duplex(ff); snd_ff_transaction_unregister(ff); + + mutex_destroy(&ff->mutex); + fw_unit_put(ff->unit); } -static void do_registration(struct work_struct *work) +static int snd_ff_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { - struct snd_ff *ff = container_of(work, struct snd_ff, dwork.work); + struct snd_card *card; + struct snd_ff *ff; int err; - if (ff->registered) - return; - - err = snd_card_new(&ff->unit->device, -1, NULL, THIS_MODULE, 0, - &ff->card); + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*ff), &card); if (err < 0) - return; - ff->card->private_free = ff_card_free; - ff->card->private_data = ff; + return err; + card->private_free = ff_card_free; + + ff = card->private_data; + ff->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, ff); + ff->card = card; + + mutex_init(&ff->mutex); + spin_lock_init(&ff->lock); + init_waitqueue_head(&ff->hwdep_wait); + + ff->unit_version = entry->version; + ff->spec = (const struct snd_ff_spec *)entry->driver_data; err = snd_ff_transaction_register(ff); if (err < 0) @@ -83,76 +94,31 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - err = snd_card_register(ff->card); + err = snd_card_register(card); if (err < 0) goto error; - ff->registered = true; - - return; -error: - snd_card_free(ff->card); - dev_info(&ff->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int snd_ff_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) -{ - struct snd_ff *ff; - - ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL); - if (!ff) - return -ENOMEM; - ff->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, ff); - - mutex_init(&ff->mutex); - spin_lock_init(&ff->lock); - init_waitqueue_head(&ff->hwdep_wait); - - ff->unit_version = entry->version; - ff->spec = (const struct snd_ff_spec *)entry->driver_data; - - /* Register this sound card later. */ - INIT_DEFERRABLE_WORK(&ff->dwork, do_registration); - snd_fw_schedule_registration(unit, &ff->dwork); - return 0; +error: + snd_card_free(card); + return err; } static void snd_ff_update(struct fw_unit *unit) { struct snd_ff *ff = dev_get_drvdata(&unit->device); - /* Postpone a workqueue for deferred registration. */ - if (!ff->registered) - snd_fw_schedule_registration(unit, &ff->dwork); - snd_ff_transaction_reregister(ff); - if (ff->registered) - snd_ff_stream_update_duplex(ff); + snd_ff_stream_update_duplex(ff); } static void snd_ff_remove(struct fw_unit *unit) { struct snd_ff *ff = dev_get_drvdata(&unit->device); - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_work_sync(&ff->dwork.work); - - if (ff->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(ff->card); - } - - mutex_destroy(&ff->mutex); - fw_unit_put(ff->unit); + // Block till all of ALSA character devices are released. + snd_card_free(ff->card); } static const struct snd_ff_spec spec_ff800 = { diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 705e7df4f929..0535f0b58b67 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -69,9 +69,6 @@ struct snd_ff { struct mutex mutex; spinlock_t lock; - bool registered; - struct delayed_work dwork; - enum snd_ff_unit_version unit_version; const struct snd_ff_spec *spec; diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index b1cc013a3540..ffb6dd796243 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -194,19 +194,19 @@ efw_card_free(struct snd_card *card) snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); + + mutex_destroy(&efw->mutex); + fw_unit_put(efw->unit); } -static void -do_registration(struct work_struct *work) +static int efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { - struct snd_efw *efw = container_of(work, struct snd_efw, dwork.work); unsigned int card_index; + struct snd_card *card; + struct snd_efw *efw; int err; - if (efw->registered) - return; - - /* check registered cards */ + // check registered cards. mutex_lock(&devices_mutex); for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) { if (!test_bit(card_index, devices_used) && enable[card_index]) @@ -214,26 +214,32 @@ do_registration(struct work_struct *work) } if (card_index >= SNDRV_CARDS) { mutex_unlock(&devices_mutex); - return; + return -ENOENT; } - err = snd_card_new(&efw->unit->device, index[card_index], - id[card_index], THIS_MODULE, 0, &efw->card); + err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE, + sizeof(*efw), &card); if (err < 0) { mutex_unlock(&devices_mutex); - return; + return err; } + card->private_free = efw_card_free; set_bit(card_index, devices_used); mutex_unlock(&devices_mutex); - efw->card->private_free = efw_card_free; - efw->card->private_data = efw; + efw = card->private_data; + efw->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, efw); + efw->card = card; + efw->card_index = card_index; + + mutex_init(&efw->mutex); + spin_lock_init(&efw->lock); + init_waitqueue_head(&efw->hwdep_wait); - /* prepare response buffer */ - snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, - SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U); - efw->resp_buf = devm_kzalloc(&efw->card->card_dev, - snd_efw_resp_buf_size, GFP_KERNEL); + // prepare response buffer. + snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U); + efw->resp_buf = devm_kzalloc(&card->card_dev, snd_efw_resp_buf_size, GFP_KERNEL); if (!efw->resp_buf) { err = -ENOMEM; goto error; @@ -265,80 +271,48 @@ do_registration(struct work_struct *work) if (err < 0) goto error; - err = snd_card_register(efw->card); + err = snd_card_register(card); if (err < 0) goto error; - efw->registered = true; - - return; -error: - snd_card_free(efw->card); - dev_info(&efw->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int -efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) -{ - struct snd_efw *efw; - - efw = devm_kzalloc(&unit->device, sizeof(struct snd_efw), GFP_KERNEL); - if (efw == NULL) - return -ENOMEM; - efw->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, efw); - - mutex_init(&efw->mutex); - spin_lock_init(&efw->lock); - init_waitqueue_head(&efw->hwdep_wait); - - /* Allocate and register this sound card later. */ - INIT_DEFERRABLE_WORK(&efw->dwork, do_registration); - snd_fw_schedule_registration(unit, &efw->dwork); - return 0; +error: + snd_card_free(card); + return err; } static void efw_update(struct fw_unit *unit) { struct snd_efw *efw = dev_get_drvdata(&unit->device); - /* Postpone a workqueue for deferred registration. */ - if (!efw->registered) - snd_fw_schedule_registration(unit, &efw->dwork); - snd_efw_transaction_bus_reset(efw->unit); - /* - * After registration, userspace can start packet streaming, then this - * code block works fine. - */ - if (efw->registered) { - mutex_lock(&efw->mutex); - snd_efw_stream_update_duplex(efw); - mutex_unlock(&efw->mutex); - } + mutex_lock(&efw->mutex); + snd_efw_stream_update_duplex(efw); + mutex_unlock(&efw->mutex); } static void efw_remove(struct fw_unit *unit) { struct snd_efw *efw = dev_get_drvdata(&unit->device); - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_delayed_work_sync(&efw->dwork); - - if (efw->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(efw->card); - } + // Block till all of ALSA character devices are released. + snd_card_free(efw->card); +} - mutex_destroy(&efw->mutex); - fw_unit_put(efw->unit); +#define SPECIFIER_1394TA 0x00a02d +#define VERSION_EFW 0x010000 + +#define SND_EFW_DEV_ENTRY(vendor, model) \ +{ \ + .match_flags = IEEE1394_MATCH_VENDOR_ID | \ + IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | \ + IEEE1394_MATCH_VERSION, \ + .vendor_id = vendor,\ + .model_id = model, \ + .specifier_id = SPECIFIER_1394TA, \ + .version = VERSION_EFW, \ } static const struct ieee1394_device_id efw_id_table[] = { diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 654e28a6669f..c8d5879efe28 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -65,9 +65,6 @@ struct snd_efw { struct mutex mutex; spinlock_t lock; - bool registered; - struct delayed_work dwork; - /* for transaction */ u32 seqnum; bool resp_addr_changable; @@ -181,7 +178,7 @@ struct snd_efw_phys_meters { } __packed; enum snd_efw_clock_source { SND_EFW_CLOCK_SOURCE_INTERNAL = 0, - SND_EFW_CLOCK_SOURCE_SYTMATCH = 1, + // Unused. SND_EFW_CLOCK_SOURCE_WORDCLOCK = 2, SND_EFW_CLOCK_SOURCE_SPDIF = 3, SND_EFW_CLOCK_SOURCE_ADAT_1 = 4, @@ -227,12 +224,4 @@ int snd_efw_get_multiplier_mode(unsigned int sampling_rate, unsigned int *mode); int snd_efw_create_hwdep_device(struct snd_efw *efw); -#define SND_EFW_DEV_ENTRY(vendor, model) \ -{ \ - .match_flags = IEEE1394_MATCH_VENDOR_ID | \ - IEEE1394_MATCH_MODEL_ID, \ - .vendor_id = vendor,\ - .model_id = model \ -} - #endif diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 2206af0fef42..ac66f08acd6b 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -6,7 +6,7 @@ */ #include "./fireworks.h" -#define CALLBACK_TIMEOUT 100 +#define READY_TIMEOUT_MS 1000 static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream) { @@ -29,7 +29,7 @@ static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream) if (err < 0) return err; - err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING); + err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING | CIP_UNAWARE_SYT); if (err < 0) { amdtp_stream_destroy(stream); cmp_connection_destroy(conn); @@ -264,6 +264,15 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw) return err; if (!amdtp_stream_running(&efw->rx_stream)) { + unsigned int tx_init_skip_cycles; + + // Audiofire 2/4 skip an isochronous cycle several thousands after starting + // packet transmission. + if (efw->is_fireworks3 && !efw->is_af9) + tx_init_skip_cycles = 6000; + else + tx_init_skip_cycles = 0; + err = start_stream(efw, &efw->rx_stream, rate); if (err < 0) goto error; @@ -272,15 +281,14 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw) if (err < 0) goto error; - err = amdtp_domain_start(&efw->domain, 0); + // NOTE: The device ignores presentation time expressed by the value of syt field + // of CIP header in received packets. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&efw->domain, tx_init_skip_cycles, true, false); if (err < 0) goto error; - // Wait first callback. - if (!amdtp_stream_wait_callback(&efw->rx_stream, - CALLBACK_TIMEOUT) || - !amdtp_stream_wait_callback(&efw->tx_stream, - CALLBACK_TIMEOUT)) { + if (!amdtp_domain_wait_ready(&efw->domain, READY_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c index 85c4f4477c7f..e0a2337e8f27 100644 --- a/sound/firewire/lib.c +++ b/sound/firewire/lib.c @@ -67,38 +67,6 @@ int snd_fw_transaction(struct fw_unit *unit, int tcode, } EXPORT_SYMBOL(snd_fw_transaction); -#define PROBE_DELAY_MS (2 * MSEC_PER_SEC) - -/** - * snd_fw_schedule_registration - schedule work for sound card registration - * @unit: an instance for unit on IEEE 1394 bus - * @dwork: delayed work with callback function - * - * This function is not designed for general purposes. When new unit is - * connected to IEEE 1394 bus, the bus is under bus-reset state because of - * topological change. In this state, units tend to fail both of asynchronous - * and isochronous communication. To avoid this problem, this function is used - * to postpone sound card registration after the state. The callers must - * set up instance of delayed work in advance. - */ -void snd_fw_schedule_registration(struct fw_unit *unit, - struct delayed_work *dwork) -{ - u64 now, delay; - - now = get_jiffies_64(); - delay = fw_parent_device(unit)->card->reset_jiffies - + msecs_to_jiffies(PROBE_DELAY_MS); - - if (time_after64(delay, now)) - delay -= now; - else - delay = 0; - - mod_delayed_work(system_wq, dwork, delay); -} -EXPORT_SYMBOL(snd_fw_schedule_registration); - MODULE_DESCRIPTION("FireWire audio helper functions"); MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); MODULE_LICENSE("GPL v2"); diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h index dc815dc3933e..664dfdb9e58d 100644 --- a/sound/firewire/lib.h +++ b/sound/firewire/lib.h @@ -23,7 +23,4 @@ static inline bool rcode_is_permanent_error(int rcode) return rcode == RCODE_TYPE_ERROR || rcode == RCODE_ADDRESS_ERROR; } -void snd_fw_schedule_registration(struct fw_unit *unit, - struct delayed_work *dwork); - #endif diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile index 7c502d35103c..acdf66564fb0 100644 --- a/sound/firewire/motu/Makefile +++ b/sound/firewire/motu/Makefile @@ -3,5 +3,6 @@ CFLAGS_amdtp-motu.o := -I$(src) snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \ motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \ - motu-protocol-v2.o motu-protocol-v3.o + motu-protocol-v2.o motu-protocol-v3.o \ + motu-protocol-v1.o obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index edb31ac26868..5388b85fb60e 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -16,6 +16,14 @@ #define CIP_FMT_MOTU_TX_V3 0x22 #define MOTU_FDF_AM824 0x22 +#define TICKS_PER_CYCLE 3072 +#define CYCLES_PER_SECOND 8000 +#define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND) + +#define CIP_SPH_CYCLE_SHIFT 12 +#define CIP_SPH_CYCLE_MASK 0x01fff000 +#define CIP_SPH_OFFSET_MASK 0x00000fff + /* * Nominally 3125 bytes/second, but the MIDI port's clock might be * 1% too slow, and the bus clock 100 ppm too fast. @@ -23,14 +31,6 @@ #define MIDI_BYTES_PER_SECOND 3093 struct amdtp_motu { - /* For timestamp processing. */ - unsigned int quotient_ticks_per_event; - unsigned int remainder_ticks_per_event; - unsigned int next_ticks; - unsigned int next_accumulated; - unsigned int next_cycles; - unsigned int next_seconds; - unsigned int pcm_chunks; unsigned int pcm_byte_offset; @@ -41,26 +41,16 @@ struct amdtp_motu { int midi_db_count; unsigned int midi_db_interval; + + struct amdtp_motu_cache *cache; }; int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int midi_ports, struct snd_motu_packet_format *formats) { - static const struct { - unsigned int quotient_ticks_per_event; - unsigned int remainder_ticks_per_event; - } params[] = { - [CIP_SFC_44100] = { 557, 123 }, - [CIP_SFC_48000] = { 512, 0 }, - [CIP_SFC_88200] = { 278, 282 }, - [CIP_SFC_96000] = { 256, 0 }, - [CIP_SFC_176400] = { 139, 141 }, - [CIP_SFC_192000] = { 128, 0 }, - }; struct amdtp_motu *p = s->protocol; unsigned int pcm_chunks, data_chunks, data_block_quadlets; - unsigned int delay; unsigned int mode; int i, err; @@ -97,19 +87,6 @@ int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, p->midi_db_count = 0; p->midi_db_interval = rate / MIDI_BYTES_PER_SECOND; - /* IEEE 1394 bus requires. */ - delay = 0x2e00; - - /* For no-data or empty packets to adjust PCM sampling frequency. */ - delay += 8000 * 3072 * s->syt_interval / rate; - - p->next_seconds = 0; - p->next_cycles = delay / 3072; - p->quotient_ticks_per_event = params[s->sfc].quotient_ticks_per_event; - p->remainder_ticks_per_event = params[s->sfc].remainder_ticks_per_event; - p->next_ticks = delay % 3072; - p->next_accumulated = 0; - return 0; } @@ -322,6 +299,34 @@ static void probe_tracepoints_events(struct amdtp_stream *s, } } +static void cache_event_offsets(struct amdtp_motu_cache *cache, const __be32 *buf, + unsigned int data_blocks, unsigned int data_block_quadlets) +{ + unsigned int *event_offsets = cache->event_offsets; + const unsigned int cache_size = cache->size; + unsigned int cache_tail = cache->tail; + unsigned int base_tick = cache->tx_cycle_count * TICKS_PER_CYCLE; + int i; + + for (i = 0; i < data_blocks; ++i) { + u32 sph = be32_to_cpu(*buf); + unsigned int tick; + + tick = ((sph & CIP_SPH_CYCLE_MASK) >> CIP_SPH_CYCLE_SHIFT) * TICKS_PER_CYCLE + + (sph & CIP_SPH_OFFSET_MASK); + + if (tick < base_tick) + tick += TICKS_PER_SECOND; + event_offsets[cache_tail] = tick - base_tick; + + cache_tail = (cache_tail + 1) % cache_size; + buf += data_block_quadlets; + } + + cache->tail = cache_tail; + cache->tx_cycle_count = (cache->tx_cycle_count + 1) % CYCLES_PER_SECOND; +} + static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *descs, unsigned int packets, @@ -331,12 +336,17 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, unsigned int pcm_frames = 0; int i; + if (p->cache->tx_cycle_count == UINT_MAX) + p->cache->tx_cycle_count = (s->domain->processing_cycle.tx_start % CYCLES_PER_SECOND); + // For data block processing. for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = descs + i; __be32 *buf = desc->ctx_payload; unsigned int data_blocks = desc->data_blocks; + cache_event_offsets(p->cache, buf, data_blocks, s->data_block_quadlets); + if (pcm) { read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); pcm_frames += data_blocks; @@ -354,46 +364,26 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, return pcm_frames; } -static inline void compute_next_elapse_from_start(struct amdtp_motu *p) -{ - p->next_accumulated += p->remainder_ticks_per_event; - if (p->next_accumulated >= 441) { - p->next_accumulated -= 441; - p->next_ticks++; - } - - p->next_ticks += p->quotient_ticks_per_event; - if (p->next_ticks >= 3072) { - p->next_ticks -= 3072; - p->next_cycles++; - } - - if (p->next_cycles >= 8000) { - p->next_cycles -= 8000; - p->next_seconds++; - } - - if (p->next_seconds >= 128) - p->next_seconds -= 128; -} - -static void write_sph(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks) +static void write_sph(struct amdtp_motu_cache *cache, __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_quadlets) { - struct amdtp_motu *p = s->protocol; - unsigned int next_cycles; - unsigned int i; - u32 sph; + unsigned int *event_offsets = cache->event_offsets; + const unsigned int cache_size = cache->size; + unsigned int cache_head = cache->head; + unsigned int base_tick = cache->rx_cycle_count * TICKS_PER_CYCLE; + int i; for (i = 0; i < data_blocks; i++) { - next_cycles = (s->start_cycle + p->next_cycles) % 8000; - sph = ((next_cycles << 12) | p->next_ticks) & 0x01ffffff; + unsigned int tick = (base_tick + event_offsets[cache_head]) % TICKS_PER_SECOND; + u32 sph = ((tick / TICKS_PER_CYCLE) << CIP_SPH_CYCLE_SHIFT) | (tick % TICKS_PER_CYCLE); *buffer = cpu_to_be32(sph); - compute_next_elapse_from_start(p); - - buffer += s->data_block_quadlets; + cache_head = (cache_head + 1) % cache_size; + buffer += data_block_quadlets; } + + cache->head = cache_head; + cache->rx_cycle_count = (cache->rx_cycle_count + 1) % CYCLES_PER_SECOND; } static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, @@ -405,6 +395,9 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, unsigned int pcm_frames = 0; int i; + if (p->cache->rx_cycle_count == UINT_MAX) + p->cache->rx_cycle_count = (s->domain->processing_cycle.rx_start % CYCLES_PER_SECOND); + // For data block processing. for (i = 0; i < packets; ++i) { const struct pkt_desc *desc = descs + i; @@ -423,7 +416,7 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, // TODO: how to interact control messages between userspace? - write_sph(s, buf, data_blocks); + write_sph(p->cache, buf, data_blocks, s->data_block_quadlets); } // For tracepoints. @@ -436,11 +429,12 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, - const struct snd_motu_spec *spec) + const struct snd_motu_spec *spec, struct amdtp_motu_cache *cache) { amdtp_stream_process_ctx_payloads_t process_ctx_payloads; int fmt = CIP_FMT_MOTU; - int flags = CIP_BLOCKING; + unsigned int flags = CIP_BLOCKING | CIP_UNAWARE_SYT; + struct amdtp_motu *p; int err; if (dir == AMDTP_IN_STREAM) { @@ -478,9 +472,10 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, if (dir == AMDTP_OUT_STREAM) { // Use fixed value for FDF field. s->ctx_data.rx.fdf = MOTU_FDF_AM824; - // Not used. - s->ctx_data.rx.syt_override = 0xffff; } + p = s->protocol; + p->cache = cache; + return 0; } diff --git a/sound/firewire/motu/motu-protocol-v1.c b/sound/firewire/motu/motu-protocol-v1.c new file mode 100644 index 000000000000..f1d6a326dc07 --- /dev/null +++ b/sound/firewire/motu/motu-protocol-v1.c @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: GPL-2.0-only + +// motu-protocol-v1.c - a part of driver for MOTU FireWire series +// +// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp> +// +// Licensed under the terms of the GNU General Public License, version 2. + +#include "motu.h" + +#include <linux/delay.h> + +// Status register for MOTU 828 (0x'ffff'f000'0b00). +// +// 0xffff0000: ISOC_COMM_CONTROL_MASK in motu-stream.c. +// 0x00008000: mode of optical input interface. +// 0x00008000: for S/PDIF signal. +// 0x00000000: disabled or for ADAT signal. +// 0x00004000: mode of optical output interface. +// 0x00004000: for S/PDIF signal. +// 0x00000000: disabled or for ADAT signal. +// 0x00003f00: monitor input mode. +// 0x00000800: analog-1/2 +// 0x00001a00: analog-3/4 +// 0x00002c00: analog-5/6 +// 0x00003e00: analog-7/8 +// 0x00000000: analog-1 +// 0x00000900: analog-2 +// 0x00001200: analog-3 +// 0x00001b00: analog-4 +// 0x00002400: analog-5 +// 0x00002d00: analog-6 +// 0x00003600: analog-7 +// 0x00003f00: analog-8 +// 0x00000080: enable stream input. +// 0x00000040: disable monitor input. +// 0x00000008: enable main out. +// 0x00000004: rate of sampling clock. +// 0x00000004: 48.0 kHz +// 0x00000000: 44.1 kHz +// 0x00000023: source of sampling clock. +// 0x00000003: source packet header (SPH) +// 0x00000002: S/PDIF on optical/coaxial interface. +// 0x00000021: ADAT on optical interface +// 0x00000001: ADAT on Dsub 9pin +// 0x00000000: internal + +#define CLK_828_STATUS_OFFSET 0x0b00 +#define CLK_828_STATUS_MASK 0x0000ffff +#define CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF 0x00008000 +#define CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF 0x00004000 +#define CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES 0x00000080 +#define CLK_828_STATUS_FLAG_ENABLE_OUTPUT 0x00000008 +#define CLK_828_STATUS_FLAG_RATE_48000 0x00000004 +#define CLK_828_STATUS_MASK_SRC 0x00000023 +#define CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT 0x00000021 +#define CLK_828_STATUS_FLAG_SRC_SPH 0x00000003 +#define CLK_828_STATUS_FLAG_SRC_SPDIF 0x00000002 +#define CLK_828_STATUS_FLAG_SRC_ADAT_ON_DSUB 0x00000001 +#define CLK_828_STATUS_FLAG_SRC_INTERNAL 0x00000000 + +// Status register for MOTU 896 (0x'ffff'f000'0b14). +// +// 0xf0000000: enable physical and stream input to DAC. +// 0x80000000: disable +// 0x40000000: disable +// 0x20000000: enable (prior to the other bits) +// 0x10000000: disable +// 0x00000000: disable +// 0x08000000: speed of word clock signal output on BNC interface. +// 0x00000000: force to low rate (44.1/48.0 kHz). +// 0x08000000: follow to system clock. +// 0x04000000: something relevant to clock. +// 0x03000000: enable output. +// 0x02000000: enabled irreversibly once standing unless the device voluntarily disables it. +// 0x01000000: enabled irreversibly once standing unless the device voluntarily disables it. +// 0x00ffff00: monitor input mode. +// 0x00000000: disabled +// 0x00004800: analog-1/2 +// 0x00005a00: analog-3/4 +// 0x00006c00: analog-5/6 +// 0x00007e00: analog-7/8 +// 0x00104800: AES/EBU-1/2 +// 0x00004000: analog-1 +// 0x00004900: analog-2 +// 0x00005200: analog-3 +// 0x00005b00: analog-4 +// 0x00006400: analog-5 +// 0x00006d00: analog-6 +// 0x00007600: analog-7 +// 0x00007f00: analog-8 +// 0x00104000: AES/EBU-1 +// 0x00104900: AES/EBU-2 +// 0x00000060: sample rate conversion for AES/EBU input/output. +// 0x00000000: None +// 0x00000020: input signal is converted to system rate +// 0x00000040: output is slave to input, ignoring system rate +// 0x00000060: output is double rate than system rate +// 0x00000018: nominal rate of sampling clock. +// 0x00000000: 44.1 kHz +// 0x00000008: 48.0 kHz +// 0x00000010: 88.2 kHz +// 0x00000018: 96.0 kHz +// 0x00000007: source of sampling clock. +// 0x00000000: internal +// 0x00000001: ADAT on optical interface +// 0x00000002: AES/EBU on XLR +// 0x00000003: source packet header (SPH) +// 0x00000004: word clock on BNC +// 0x00000005: ADAT on Dsub 9pin + +#define CLK_896_STATUS_OFFSET 0x0b14 +#define CLK_896_STATUS_FLAG_FETCH_ENABLE 0x20000000 +#define CLK_896_STATUS_FLAG_OUTPUT_ON 0x03000000 +#define CLK_896_STATUS_MASK_SRC 0x00000007 +#define CLK_896_STATUS_FLAG_SRC_INTERNAL 0x00000000 +#define CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT 0x00000001 +#define CLK_896_STATUS_FLAG_SRC_AESEBU 0x00000002 +#define CLK_896_STATUS_FLAG_SRC_SPH 0x00000003 +#define CLK_896_STATUS_FLAG_SRC_WORD 0x00000004 +#define CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB 0x00000005 +#define CLK_896_STATUS_MASK_RATE 0x00000018 +#define CLK_896_STATUS_FLAG_RATE_44100 0x00000000 +#define CLK_896_STATUS_FLAG_RATE_48000 0x00000008 +#define CLK_896_STATUS_FLAG_RATE_88200 0x00000010 +#define CLK_896_STATUS_FLAG_RATE_96000 0x00000018 + +static void parse_clock_rate_828(u32 data, unsigned int *rate) +{ + if (data & CLK_828_STATUS_FLAG_RATE_48000) + *rate = 48000; + else + *rate = 44100; +} + +static int get_clock_rate_828(struct snd_motu *motu, unsigned int *rate) +{ + __be32 reg; + int err; + + err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + parse_clock_rate_828(be32_to_cpu(reg), rate); + + return 0; +} + +static int parse_clock_rate_896(u32 data, unsigned int *rate) +{ + switch (data & CLK_896_STATUS_MASK_RATE) { + case CLK_896_STATUS_FLAG_RATE_44100: + *rate = 44100; + break; + case CLK_896_STATUS_FLAG_RATE_48000: + *rate = 48000; + break; + case CLK_896_STATUS_FLAG_RATE_88200: + *rate = 88200; + break; + case CLK_896_STATUS_FLAG_RATE_96000: + *rate = 96000; + break; + default: + return -ENXIO; + } + + return 0; +} + +static int get_clock_rate_896(struct snd_motu *motu, unsigned int *rate) +{ + __be32 reg; + int err; + + err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + return parse_clock_rate_896(be32_to_cpu(reg), rate); +} + +int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu, unsigned int *rate) +{ + if (motu->spec == &snd_motu_spec_828) + return get_clock_rate_828(motu, rate); + else if (motu->spec == &snd_motu_spec_896) + return get_clock_rate_896(motu, rate); + else + return -ENXIO; +} + +static int set_clock_rate_828(struct snd_motu *motu, unsigned int rate) +{ + __be32 reg; + u32 data; + int err; + + err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg) & CLK_828_STATUS_MASK; + + data &= ~CLK_828_STATUS_FLAG_RATE_48000; + if (rate == 48000) + data |= CLK_828_STATUS_FLAG_RATE_48000; + + reg = cpu_to_be32(data); + return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, ®, sizeof(reg)); +} + +static int set_clock_rate_896(struct snd_motu *motu, unsigned int rate) +{ + unsigned int flag; + __be32 reg; + u32 data; + int err; + + err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg); + + switch (rate) { + case 44100: + flag = CLK_896_STATUS_FLAG_RATE_44100; + break; + case 48000: + flag = CLK_896_STATUS_FLAG_RATE_48000; + break; + case 88200: + flag = CLK_896_STATUS_FLAG_RATE_88200; + break; + case 96000: + flag = CLK_896_STATUS_FLAG_RATE_96000; + break; + default: + return -EINVAL; + } + + data &= ~CLK_896_STATUS_MASK_RATE; + data |= flag; + + reg = cpu_to_be32(data); + return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, ®, sizeof(reg)); +} + +int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu, unsigned int rate) +{ + if (motu->spec == &snd_motu_spec_828) + return set_clock_rate_828(motu, rate); + else if (motu->spec == &snd_motu_spec_896) + return set_clock_rate_896(motu, rate); + else + return -ENXIO; +} + +static int get_clock_source_828(struct snd_motu *motu, enum snd_motu_clock_source *src) +{ + __be32 reg; + u32 data; + int err; + + err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg) & CLK_828_STATUS_MASK; + + switch (data & CLK_828_STATUS_MASK_SRC) { + case CLK_828_STATUS_FLAG_SRC_ADAT_ON_OPT: + *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT; + break; + case CLK_828_STATUS_FLAG_SRC_SPH: + *src = SND_MOTU_CLOCK_SOURCE_SPH; + break; + case CLK_828_STATUS_FLAG_SRC_SPDIF: + { + if (data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF) + *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; + else + *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT; + break; + } + case CLK_828_STATUS_FLAG_SRC_ADAT_ON_DSUB: + *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB; + break; + case CLK_828_STATUS_FLAG_SRC_INTERNAL: + *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; + break; + default: + return -ENXIO; + } + + return 0; +} + +static int get_clock_source_896(struct snd_motu *motu, enum snd_motu_clock_source *src) +{ + __be32 reg; + u32 data; + int err; + + err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg); + + switch (data & CLK_896_STATUS_MASK_SRC) { + case CLK_896_STATUS_FLAG_SRC_INTERNAL: + *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; + break; + case CLK_896_STATUS_FLAG_SRC_ADAT_ON_OPT: + *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT; + break; + case CLK_896_STATUS_FLAG_SRC_AESEBU: + *src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR; + break; + case CLK_896_STATUS_FLAG_SRC_SPH: + *src = SND_MOTU_CLOCK_SOURCE_SPH; + break; + case CLK_896_STATUS_FLAG_SRC_WORD: + *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; + break; + case CLK_896_STATUS_FLAG_SRC_ADAT_ON_DSUB: + *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB; + break; + default: + return -ENXIO; + } + + return 0; +} + +int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu, enum snd_motu_clock_source *src) +{ + if (motu->spec == &snd_motu_spec_828) + return get_clock_source_828(motu, src); + else if (motu->spec == &snd_motu_spec_896) + return get_clock_source_896(motu, src); + else + return -ENXIO; +} + +static int switch_fetching_mode_828(struct snd_motu *motu, bool enable) +{ + __be32 reg; + u32 data; + int err; + + err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg) & CLK_828_STATUS_MASK; + + data &= ~(CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_ENABLE_OUTPUT); + if (enable) { + // This transaction should be initiated after the device receives batch of packets + // since the device voluntarily mutes outputs. As a workaround, yield processor over + // 100 msec. + msleep(100); + data |= CLK_828_STATUS_FLAG_FETCH_PCM_FRAMES | CLK_828_STATUS_FLAG_ENABLE_OUTPUT; + } + + reg = cpu_to_be32(data); + return snd_motu_transaction_write(motu, CLK_828_STATUS_OFFSET, ®, sizeof(reg)); +} + +static int switch_fetching_mode_896(struct snd_motu *motu, bool enable) +{ + __be32 reg; + u32 data; + int err; + + err = snd_motu_transaction_read(motu, CLK_896_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg); + + data &= ~CLK_896_STATUS_FLAG_FETCH_ENABLE; + if (enable) + data |= CLK_896_STATUS_FLAG_FETCH_ENABLE | CLK_896_STATUS_FLAG_OUTPUT_ON; + + reg = cpu_to_be32(data); + return snd_motu_transaction_write(motu, CLK_896_STATUS_OFFSET, ®, sizeof(reg)); +} + +int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu, bool enable) +{ + if (motu->spec == &snd_motu_spec_828) + return switch_fetching_mode_828(motu, enable); + else if (motu->spec == &snd_motu_spec_896) + return switch_fetching_mode_896(motu, enable); + else + return -ENXIO; +} + +static int detect_packet_formats_828(struct snd_motu *motu) +{ + __be32 reg; + u32 data; + int err; + + motu->tx_packet_formats.pcm_byte_offset = 4; + motu->tx_packet_formats.msg_chunks = 2; + + motu->rx_packet_formats.pcm_byte_offset = 4; + motu->rx_packet_formats.msg_chunks = 0; + + err = snd_motu_transaction_read(motu, CLK_828_STATUS_OFFSET, ®, sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg) & CLK_828_STATUS_MASK; + + // The number of chunks is just reduced when SPDIF is activated. + if (!(data & CLK_828_STATUS_FLAG_OPT_IN_IFACE_IS_SPDIF)) + motu->tx_packet_formats.pcm_chunks[0] += 8; + + if (!(data & CLK_828_STATUS_FLAG_OPT_OUT_IFACE_IS_SPDIF)) + motu->rx_packet_formats.pcm_chunks[0] += 8; + + return 0; +} + +static int detect_packet_formats_896(struct snd_motu *motu) +{ + // 24bit PCM frames follow to source packet header without message chunk. + motu->tx_packet_formats.pcm_byte_offset = 4; + motu->rx_packet_formats.pcm_byte_offset = 4; + + // No message chunk in data block. + motu->tx_packet_formats.msg_chunks = 0; + motu->rx_packet_formats.msg_chunks = 0; + + // Always enable optical interface for ADAT signal since the device have no registers + // to refer to current configuration. + motu->tx_packet_formats.pcm_chunks[0] += 8; + motu->tx_packet_formats.pcm_chunks[1] += 8; + + motu->rx_packet_formats.pcm_chunks[0] += 8; + motu->rx_packet_formats.pcm_chunks[1] += 8; + + return 0; +} + +int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu) +{ + memcpy(motu->tx_packet_formats.pcm_chunks, motu->spec->tx_fixed_pcm_chunks, + sizeof(motu->tx_packet_formats.pcm_chunks)); + memcpy(motu->rx_packet_formats.pcm_chunks, motu->spec->rx_fixed_pcm_chunks, + sizeof(motu->rx_packet_formats.pcm_chunks)); + + if (motu->spec == &snd_motu_spec_828) + return detect_packet_formats_828(motu); + else if (motu->spec == &snd_motu_spec_896) + return detect_packet_formats_896(motu); + else + return 0; +} + +const struct snd_motu_spec snd_motu_spec_828 = { + .name = "828", + .protocol_version = SND_MOTU_PROTOCOL_V1, + .tx_fixed_pcm_chunks = {10, 0, 0}, + .rx_fixed_pcm_chunks = {10, 0, 0}, +}; + +const struct snd_motu_spec snd_motu_spec_896 = { + .name = "896", + .tx_fixed_pcm_chunks = {10, 10, 0}, + .rx_fixed_pcm_chunks = {10, 10, 0}, +}; diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c index e59e69ab1538..93d5df1ae550 100644 --- a/sound/firewire/motu/motu-protocol-v2.c +++ b/sound/firewire/motu/motu-protocol-v2.c @@ -12,6 +12,13 @@ #define V2_CLOCK_RATE_SHIFT 3 #define V2_CLOCK_SRC_MASK 0x00000007 #define V2_CLOCK_SRC_SHIFT 0 +#define V2_CLOCK_SRC_AESEBU_ON_XLR 0x07 +#define V2_CLOCK_SRC_ADAT_ON_DSUB 0x05 +#define V2_CLOCK_SRC_WORD_ON_BNC 0x04 +#define V2_CLOCK_SRC_SPH 0x03 +#define V2_CLOCK_SRC_SPDIF 0x02 // on either coaxial or optical +#define V2_CLOCK_SRC_ADAT_ON_OPT 0x01 +#define V2_CLOCK_SRC_INTERNAL 0x00 #define V2_CLOCK_FETCH_ENABLE 0x02000000 #define V2_CLOCK_MODEL_SPECIFIC 0x04000000 @@ -78,64 +85,51 @@ int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu, sizeof(reg)); } -static int detect_clock_source_optical_model(struct snd_motu *motu, u32 data, - enum snd_motu_clock_source *src) +static int get_clock_source(struct snd_motu *motu, u32 data, + enum snd_motu_clock_source *src) { - switch (data) { - case 0: + switch (data & V2_CLOCK_SRC_MASK) { + case V2_CLOCK_SRC_INTERNAL: *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; break; - case 1: + case V2_CLOCK_SRC_ADAT_ON_OPT: + *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT; + break; + case V2_CLOCK_SRC_SPDIF: { - __be32 reg; - - // To check the configuration of optical interface. - int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, - ®, sizeof(reg)); - if (err < 0) - return err; - - if (be32_to_cpu(reg) & 0x00000200) - *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT; - else - *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT; + bool support_iec60958_on_opt = (motu->spec == &snd_motu_spec_828mk2 || + motu->spec == &snd_motu_spec_traveler); + + if (!support_iec60958_on_opt) { + *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; + } else { + __be32 reg; + + // To check the configuration of optical interface. + int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, ®, + sizeof(reg)); + if (err < 0) + return err; + + if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == + V2_OPT_IFACE_MODE_SPDIF) + *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT; + else + *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; + } break; } - case 2: - *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; - break; - case 3: + case V2_CLOCK_SRC_SPH: *src = SND_MOTU_CLOCK_SOURCE_SPH; break; - case 4: + case V2_CLOCK_SRC_WORD_ON_BNC: *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; break; - case 5: + case V2_CLOCK_SRC_ADAT_ON_DSUB: *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB; break; - default: - *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN; - break; - } - - return 0; -} - -static int v2_detect_clock_source(struct snd_motu *motu, u32 data, - enum snd_motu_clock_source *src) -{ - switch (data) { - case 0: - *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; - break; - case 2: - *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; - break; - case 3: - *src = SND_MOTU_CLOCK_SOURCE_SPH; - break; - case 4: - *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; + case V2_CLOCK_SRC_AESEBU_ON_XLR: + *src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR; break; default: *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN; @@ -145,17 +139,6 @@ static int v2_detect_clock_source(struct snd_motu *motu, u32 data, return 0; } -static int get_clock_source(struct snd_motu *motu, u32 data, - enum snd_motu_clock_source *src) -{ - data &= V2_CLOCK_SRC_MASK; - if (motu->spec == &snd_motu_spec_828mk2 || - motu->spec == &snd_motu_spec_traveler) - return detect_clock_source_optical_model(motu, data, src); - else - return v2_detect_clock_source(motu, data, src); -} - int snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu, enum snd_motu_clock_source *src) { @@ -235,59 +218,9 @@ int snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu, } } -static int detect_packet_formats_828mk2(struct snd_motu *motu, u32 data) -{ - if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == - V2_OPT_IFACE_MODE_ADAT) { - motu->tx_packet_formats.pcm_chunks[0] += 8; - motu->tx_packet_formats.pcm_chunks[1] += 4; - } - - if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == - V2_OPT_IFACE_MODE_ADAT) { - motu->rx_packet_formats.pcm_chunks[0] += 8; - motu->rx_packet_formats.pcm_chunks[1] += 4; - } - - return 0; -} - -static int detect_packet_formats_traveler(struct snd_motu *motu, u32 data) -{ - if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == - V2_OPT_IFACE_MODE_ADAT) { - motu->tx_packet_formats.pcm_chunks[0] += 8; - motu->tx_packet_formats.pcm_chunks[1] += 4; - } - - if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == - V2_OPT_IFACE_MODE_ADAT) { - motu->rx_packet_formats.pcm_chunks[0] += 8; - motu->rx_packet_formats.pcm_chunks[1] += 4; - } - - return 0; -} - -static int detect_packet_formats_8pre(struct snd_motu *motu, u32 data) -{ - if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == - V2_OPT_IFACE_MODE_ADAT) { - motu->tx_packet_formats.pcm_chunks[0] += 8; - motu->tx_packet_formats.pcm_chunks[1] += 8; - } - - if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == - V2_OPT_IFACE_MODE_ADAT) { - motu->rx_packet_formats.pcm_chunks[0] += 8; - motu->rx_packet_formats.pcm_chunks[1] += 8; - } - - return 0; -} - int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu) { + bool has_two_opt_ifaces = (motu->spec == &snd_motu_spec_8pre); __be32 reg; u32 data; int err; @@ -311,14 +244,25 @@ int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu) motu->spec->rx_fixed_pcm_chunks, sizeof(motu->rx_packet_formats.pcm_chunks)); - if (motu->spec == &snd_motu_spec_828mk2) - return detect_packet_formats_828mk2(motu, data); - else if (motu->spec == &snd_motu_spec_traveler) - return detect_packet_formats_traveler(motu, data); - else if (motu->spec == &snd_motu_spec_8pre) - return detect_packet_formats_8pre(motu, data); - else - return 0; + if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) { + motu->tx_packet_formats.pcm_chunks[0] += 8; + + if (!has_two_opt_ifaces) + motu->tx_packet_formats.pcm_chunks[1] += 4; + else + motu->tx_packet_formats.pcm_chunks[1] += 8; + } + + if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) { + motu->rx_packet_formats.pcm_chunks[0] += 8; + + if (!has_two_opt_ifaces) + motu->rx_packet_formats.pcm_chunks[1] += 4; + else + motu->rx_packet_formats.pcm_chunks[1] += 8; + } + + return 0; } const struct snd_motu_spec snd_motu_spec_828mk2 = { @@ -353,6 +297,7 @@ const struct snd_motu_spec snd_motu_spec_8pre = { .protocol_version = SND_MOTU_PROTOCOL_V2, .flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q | SND_MOTU_SPEC_TX_MIDI_2ND_Q, - .tx_fixed_pcm_chunks = {10, 6, 0}, - .rx_fixed_pcm_chunks = {10, 6, 0}, + // Two dummy chunks always in the end of data block. + .tx_fixed_pcm_chunks = {10, 10, 0}, + .rx_fixed_pcm_chunks = {6, 6, 0}, }; diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c index 4e6b0e449ee4..56e4504e7ec9 100644 --- a/sound/firewire/motu/motu-protocol-v3.c +++ b/sound/firewire/motu/motu-protocol-v3.c @@ -13,6 +13,12 @@ #define V3_CLOCK_RATE_MASK 0x0000ff00 #define V3_CLOCK_RATE_SHIFT 8 #define V3_CLOCK_SOURCE_MASK 0x000000ff +#define V3_CLOCK_SRC_INTERNAL 0x00 +#define V3_CLOCK_SRC_WORD_ON_BNC 0x01 +#define V3_CLOCK_SRC_SPH 0x02 +#define V3_CLOCK_SRC_SPDIF_ON_COAX 0x10 +#define V3_CLOCK_SRC_OPT_IFACE_A 0x18 +#define V3_CLOCK_SRC_OPT_IFACE_B 0x19 #define V3_OPT_IFACE_MODE_OFFSET 0x0c94 #define V3_ENABLE_OPT_IN_IFACE_A 0x00000001 @@ -97,28 +103,37 @@ int snd_motu_protocol_v3_set_clock_rate(struct snd_motu *motu, return 0; } -static int detect_clock_source_828mk3(struct snd_motu *motu, u32 data, - enum snd_motu_clock_source *src) +int snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu, + enum snd_motu_clock_source *src) { + __be32 reg; + u32 data; + int err; + + err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, + sizeof(reg)); + if (err < 0) + return err; + data = be32_to_cpu(reg) & V3_CLOCK_SOURCE_MASK; + switch (data) { - case 0x00: + case V3_CLOCK_SRC_INTERNAL: *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; break; - case 0x01: + case V3_CLOCK_SRC_WORD_ON_BNC: *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; break; - case 0x02: + case V3_CLOCK_SRC_SPH: *src = SND_MOTU_CLOCK_SOURCE_SPH; break; - case 0x10: + case V3_CLOCK_SRC_SPDIF_ON_COAX: *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; break; - case 0x18: - case 0x19: + case V3_CLOCK_SRC_OPT_IFACE_A: + case V3_CLOCK_SRC_OPT_IFACE_B: { __be32 reg; u32 options; - int err; err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, ®, sizeof(reg)); @@ -126,7 +141,7 @@ static int detect_clock_source_828mk3(struct snd_motu *motu, u32 data, return err; options = be32_to_cpu(reg); - if (data == 0x18) { + if (data == V3_CLOCK_SRC_OPT_IFACE_A) { if (options & V3_NO_ADAT_OPT_IN_IFACE_A) *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A; else @@ -137,7 +152,6 @@ static int detect_clock_source_828mk3(struct snd_motu *motu, u32 data, else *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B; } - break; } default: @@ -148,49 +162,6 @@ static int detect_clock_source_828mk3(struct snd_motu *motu, u32 data, return 0; } -static int v3_detect_clock_source(struct snd_motu *motu, u32 data, - enum snd_motu_clock_source *src) -{ - switch (data) { - case 0x00: - *src = SND_MOTU_CLOCK_SOURCE_INTERNAL; - break; - case 0x01: - *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC; - break; - case 0x02: - *src = SND_MOTU_CLOCK_SOURCE_SPH; - break; - case 0x10: - *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX; - break; - default: - *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN; - break; - } - - return 0; -} - -int snd_motu_protocol_v3_get_clock_source(struct snd_motu *motu, - enum snd_motu_clock_source *src) -{ - __be32 reg; - u32 data; - int err; - - err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, ®, - sizeof(reg)); - if (err < 0) - return err; - data = be32_to_cpu(reg) & V3_CLOCK_SOURCE_MASK; - - if (motu->spec == &snd_motu_spec_828mk3) - return detect_clock_source_828mk3(motu, data, src); - else - return v3_detect_clock_source(motu, data, src); -} - int snd_motu_protocol_v3_switch_fetching_mode(struct snd_motu *motu, bool enable) { @@ -284,14 +255,14 @@ int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu) motu->spec->rx_fixed_pcm_chunks, sizeof(motu->rx_packet_formats.pcm_chunks)); - if (motu->spec == &snd_motu_spec_828mk3) + if (motu->spec == &snd_motu_spec_828mk3_fw || motu->spec == &snd_motu_spec_828mk3_hybrid) return detect_packet_formats_828mk3(motu, data); else return 0; } -const struct snd_motu_spec snd_motu_spec_828mk3 = { +const struct snd_motu_spec snd_motu_spec_828mk3_fw = { .name = "828mk3", .protocol_version = SND_MOTU_PROTOCOL_V3, .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q | @@ -300,6 +271,15 @@ const struct snd_motu_spec snd_motu_spec_828mk3 = { .rx_fixed_pcm_chunks = {14, 14, 10}, }; +const struct snd_motu_spec snd_motu_spec_828mk3_hybrid = { + .name = "828mk3", + .protocol_version = SND_MOTU_PROTOCOL_V3, + .flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q | + SND_MOTU_SPEC_TX_MIDI_3RD_Q, + .tx_fixed_pcm_chunks = {18, 18, 14}, + .rx_fixed_pcm_chunks = {14, 14, 14}, // Additional 4 dummy chunks at higher rate. +}; + const struct snd_motu_spec snd_motu_spec_ultralite_mk3 = { .name = "UltraLiteMk3", .protocol_version = SND_MOTU_PROTOCOL_V3, diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 2028c5419f6f..9e6ca39ebd7f 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -7,7 +7,7 @@ #include "motu.h" -#define CALLBACK_TIMEOUT 200 +#define READY_TIMEOUT_MS 200 #define ISOC_COMM_CONTROL_OFFSET 0x0b00 #define ISOC_COMM_CONTROL_MASK 0xffff0000 @@ -153,6 +153,9 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, fw_iso_resources_free(&motu->tx_resources); fw_iso_resources_free(&motu->rx_resources); + kfree(motu->cache.event_offsets); + motu->cache.event_offsets = NULL; + err = snd_motu_protocol_set_clock_rate(motu, rate); if (err < 0) { dev_err(&motu->unit->device, @@ -181,6 +184,15 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, fw_iso_resources_free(&motu->rx_resources); return err; } + + motu->cache.size = motu->tx_stream.syt_interval * frames_per_buffer; + motu->cache.event_offsets = kcalloc(motu->cache.size, sizeof(*motu->cache.event_offsets), + GFP_KERNEL); + if (!motu->cache.event_offsets) { + fw_iso_resources_free(&motu->tx_resources); + fw_iso_resources_free(&motu->rx_resources); + return -ENOMEM; + } } return 0; @@ -260,14 +272,19 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) if (err < 0) goto stop_streams; - err = amdtp_domain_start(&motu->domain, 0); + motu->cache.tail = 0; + motu->cache.tx_cycle_count = UINT_MAX; + motu->cache.head = 0; + motu->cache.rx_cycle_count = UINT_MAX; + + // NOTE: The device requires both of replay; the sequence of the number of data + // blocks per packet, and the sequence of source packet header per data block as + // presentation time. + err = amdtp_domain_start(&motu->domain, 0, true, false); if (err < 0) goto stop_streams; - if (!amdtp_stream_wait_callback(&motu->tx_stream, - CALLBACK_TIMEOUT) || - !amdtp_stream_wait_callback(&motu->rx_stream, - CALLBACK_TIMEOUT)) { + if (!amdtp_domain_wait_ready(&motu->domain, READY_TIMEOUT_MS)) { err = -ETIMEDOUT; goto stop_streams; } @@ -296,6 +313,9 @@ void snd_motu_stream_stop_duplex(struct snd_motu *motu) fw_iso_resources_free(&motu->tx_resources); fw_iso_resources_free(&motu->rx_resources); + + kfree(motu->cache.event_offsets); + motu->cache.event_offsets = NULL; } } @@ -317,7 +337,7 @@ static int init_stream(struct snd_motu *motu, struct amdtp_stream *s) if (err < 0) return err; - err = amdtp_motu_init(s, motu->unit, dir, motu->spec); + err = amdtp_motu_init(s, motu->unit, dir, motu->spec, &motu->cache); if (err < 0) fw_iso_resources_destroy(resources); diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index a4929c1302dc..543136578c70 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -57,22 +57,31 @@ static void motu_card_free(struct snd_card *card) snd_motu_transaction_unregister(motu); snd_motu_stream_destroy_duplex(motu); + + mutex_destroy(&motu->mutex); + fw_unit_put(motu->unit); } -static void do_registration(struct work_struct *work) +static int motu_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { - struct snd_motu *motu = container_of(work, struct snd_motu, dwork.work); + struct snd_card *card; + struct snd_motu *motu; int err; - if (motu->registered) - return; - - err = snd_card_new(&motu->unit->device, -1, NULL, THIS_MODULE, 0, - &motu->card); + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*motu), &card); if (err < 0) - return; - motu->card->private_free = motu_card_free; - motu->card->private_data = motu; + return err; + card->private_free = motu_card_free; + + motu = card->private_data; + motu->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, motu); + motu->card = card; + + motu->spec = (const struct snd_motu_spec *)entry->driver_data; + mutex_init(&motu->mutex); + spin_lock_init(&motu->lock); + init_waitqueue_head(&motu->hwdep_wait); name_card(motu); @@ -103,71 +112,28 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - err = snd_card_register(motu->card); + err = snd_card_register(card); if (err < 0) goto error; - motu->registered = true; - - return; -error: - snd_card_free(motu->card); - dev_info(&motu->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int motu_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) -{ - struct snd_motu *motu; - - /* Allocate this independently of sound card instance. */ - motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL); - if (!motu) - return -ENOMEM; - motu->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, motu); - - motu->spec = (const struct snd_motu_spec *)entry->driver_data; - mutex_init(&motu->mutex); - spin_lock_init(&motu->lock); - init_waitqueue_head(&motu->hwdep_wait); - - /* Allocate and register this sound card later. */ - INIT_DEFERRABLE_WORK(&motu->dwork, do_registration); - snd_fw_schedule_registration(unit, &motu->dwork); - return 0; +error: + snd_card_free(card); + return err; } static void motu_remove(struct fw_unit *unit) { struct snd_motu *motu = dev_get_drvdata(&unit->device); - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_delayed_work_sync(&motu->dwork); - - if (motu->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(motu->card); - } - - mutex_destroy(&motu->mutex); - fw_unit_put(motu->unit); + // Block till all of ALSA character devices are released. + snd_card_free(motu->card); } static void motu_bus_update(struct fw_unit *unit) { struct snd_motu *motu = dev_get_drvdata(&unit->device); - /* Postpone a workqueue for deferred registration. */ - if (!motu->registered) - snd_fw_schedule_registration(unit, &motu->dwork); - /* The handler address register becomes initialized. */ snd_motu_transaction_reregister(motu); } @@ -184,13 +150,16 @@ static void motu_bus_update(struct fw_unit *unit) } static const struct ieee1394_device_id motu_id_table[] = { + SND_MOTU_DEV_ENTRY(0x000001, &snd_motu_spec_828), + SND_MOTU_DEV_ENTRY(0x000002, &snd_motu_spec_896), SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2), SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler), SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite), SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre), - SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3), // FireWire only. + SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3_fw), // FireWire only. SND_MOTU_DEV_ENTRY(0x000019, &snd_motu_spec_ultralite_mk3), // FireWire only. - SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3), // Hybrid. + SND_MOTU_DEV_ENTRY(0x000030, &snd_motu_spec_ultralite_mk3), // Hybrid. + SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3_hybrid), // Hybrid. SND_MOTU_DEV_ENTRY(0x000033, &snd_motu_spec_audio_express), SND_MOTU_DEV_ENTRY(0x000045, &snd_motu_spec_4pre), { } diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 3d0236ee6716..73f36d1be515 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -39,15 +39,21 @@ struct snd_motu_packet_format { unsigned char pcm_chunks[3]; }; +struct amdtp_motu_cache { + unsigned int *event_offsets; + unsigned int size; + unsigned int tail; + unsigned int tx_cycle_count; + unsigned int head; + unsigned int rx_cycle_count; +}; + struct snd_motu { struct snd_card *card; struct fw_unit *unit; struct mutex mutex; spinlock_t lock; - bool registered; - struct delayed_work dwork; - /* Model dependent information. */ const struct snd_motu_spec *spec; @@ -70,6 +76,8 @@ struct snd_motu { wait_queue_head_t hwdep_wait; struct amdtp_domain domain; + + struct amdtp_motu_cache cache; }; enum snd_motu_spec_flags { @@ -99,6 +107,7 @@ enum snd_motu_clock_source { }; enum snd_motu_protocol_version { + SND_MOTU_PROTOCOL_V1, SND_MOTU_PROTOCOL_V2, SND_MOTU_PROTOCOL_V3, }; @@ -106,25 +115,31 @@ enum snd_motu_protocol_version { struct snd_motu_spec { const char *const name; enum snd_motu_protocol_version protocol_version; - enum snd_motu_spec_flags flags; + // The combination of snd_motu_spec_flags enumeration-constants. + unsigned int flags; unsigned char tx_fixed_pcm_chunks[3]; unsigned char rx_fixed_pcm_chunks[3]; }; +extern const struct snd_motu_spec snd_motu_spec_828; +extern const struct snd_motu_spec snd_motu_spec_896; + extern const struct snd_motu_spec snd_motu_spec_828mk2; extern const struct snd_motu_spec snd_motu_spec_traveler; extern const struct snd_motu_spec snd_motu_spec_ultralite; extern const struct snd_motu_spec snd_motu_spec_8pre; -extern const struct snd_motu_spec snd_motu_spec_828mk3; +extern const struct snd_motu_spec snd_motu_spec_828mk3_fw; +extern const struct snd_motu_spec snd_motu_spec_828mk3_hybrid; extern const struct snd_motu_spec snd_motu_spec_ultralite_mk3; extern const struct snd_motu_spec snd_motu_spec_audio_express; extern const struct snd_motu_spec snd_motu_spec_4pre; int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, - const struct snd_motu_spec *spec); + const struct snd_motu_spec *spec, + struct amdtp_motu_cache *cache); int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int midi_ports, struct snd_motu_packet_format *formats); @@ -160,6 +175,16 @@ int snd_motu_create_midi_devices(struct snd_motu *motu); int snd_motu_create_hwdep_device(struct snd_motu *motu); +int snd_motu_protocol_v1_get_clock_rate(struct snd_motu *motu, + unsigned int *rate); +int snd_motu_protocol_v1_set_clock_rate(struct snd_motu *motu, + unsigned int rate); +int snd_motu_protocol_v1_get_clock_source(struct snd_motu *motu, + enum snd_motu_clock_source *src); +int snd_motu_protocol_v1_switch_fetching_mode(struct snd_motu *motu, + bool enable); +int snd_motu_protocol_v1_cache_packet_formats(struct snd_motu *motu); + int snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate); int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu, @@ -187,6 +212,8 @@ static inline int snd_motu_protocol_get_clock_rate(struct snd_motu *motu, return snd_motu_protocol_v2_get_clock_rate(motu, rate); else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) return snd_motu_protocol_v3_get_clock_rate(motu, rate); + else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1) + return snd_motu_protocol_v1_get_clock_rate(motu, rate); else return -ENXIO; } @@ -198,6 +225,8 @@ static inline int snd_motu_protocol_set_clock_rate(struct snd_motu *motu, return snd_motu_protocol_v2_set_clock_rate(motu, rate); else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) return snd_motu_protocol_v3_set_clock_rate(motu, rate); + else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1) + return snd_motu_protocol_v1_set_clock_rate(motu, rate); else return -ENXIO; } @@ -209,6 +238,8 @@ static inline int snd_motu_protocol_get_clock_source(struct snd_motu *motu, return snd_motu_protocol_v2_get_clock_source(motu, source); else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) return snd_motu_protocol_v3_get_clock_source(motu, source); + else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1) + return snd_motu_protocol_v1_get_clock_source(motu, source); else return -ENXIO; } @@ -220,6 +251,8 @@ static inline int snd_motu_protocol_switch_fetching_mode(struct snd_motu *motu, return snd_motu_protocol_v2_switch_fetching_mode(motu, enable); else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) return snd_motu_protocol_v3_switch_fetching_mode(motu, enable); + else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1) + return snd_motu_protocol_v1_switch_fetching_mode(motu, enable); else return -ENXIO; } @@ -230,6 +263,8 @@ static inline int snd_motu_protocol_cache_packet_formats(struct snd_motu *motu) return snd_motu_protocol_v2_cache_packet_formats(motu); else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V3) return snd_motu_protocol_v3_cache_packet_formats(motu); + else if (motu->spec->protocol_version == SND_MOTU_PROTOCOL_V1) + return snd_motu_protocol_v1_cache_packet_formats(motu); else return -ENXIO; } diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 80c9dc13f1b5..0ef242fdd3bc 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -9,7 +9,7 @@ #include <linux/delay.h> #define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512 -#define CALLBACK_TIMEOUT 200 +#define READY_TIMEOUT_MS 200 /* * According to datasheet of Oxford Semiconductor: @@ -153,12 +153,23 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) struct cmp_connection *conn; enum cmp_direction c_dir; enum amdtp_stream_direction s_dir; + unsigned int flags = CIP_UNAWARE_SYT; int err; + if (!(oxfw->quirks & SND_OXFW_QUIRK_BLOCKING_TRANSMISSION)) + flags |= CIP_NONBLOCKING; + else + flags |= CIP_BLOCKING; + if (stream == &oxfw->tx_stream) { conn = &oxfw->out_conn; c_dir = CMP_OUTPUT; s_dir = AMDTP_IN_STREAM; + + if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) + flags |= CIP_JUMBO_PAYLOAD; + if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS) + flags |= CIP_WRONG_DBS; } else { conn = &oxfw->in_conn; c_dir = CMP_INPUT; @@ -169,24 +180,12 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) if (err < 0) return err; - err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING); + err = amdtp_am824_init(stream, oxfw->unit, s_dir, flags); if (err < 0) { cmp_connection_destroy(conn); return err; } - /* - * OXFW starts to transmit packets with non-zero dbc. - * OXFW postpone transferring packets till handling any asynchronous - * packets. As a result, next isochronous packet includes more data - * blocks than IEC 61883-6 defines. - */ - if (stream == &oxfw->tx_stream) { - oxfw->tx_stream.flags |= CIP_JUMBO_PAYLOAD; - if (oxfw->wrong_dbs) - oxfw->tx_stream.flags |= CIP_WRONG_DBS; - } - return 0; } @@ -338,6 +337,9 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) } if (!amdtp_stream_running(&oxfw->rx_stream)) { + unsigned int tx_init_skip_cycles = 0; + bool replay_seq = false; + err = start_stream(oxfw, &oxfw->rx_stream); if (err < 0) { dev_err(&oxfw->unit->device, @@ -353,26 +355,27 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) "fail to prepare tx stream: %d\n", err); goto error; } + + if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) { + // Just after changing sampling transfer frequency, many cycles are + // skipped for packet transmission. + tx_init_skip_cycles = 400; + } else { + replay_seq = true; + } } - err = amdtp_domain_start(&oxfw->domain, 0); + // NOTE: The device ignores presentation time expressed by the value of syt field + // of CIP header in received packets. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false); if (err < 0) goto error; - // Wait first packet. - if (!amdtp_stream_wait_callback(&oxfw->rx_stream, - CALLBACK_TIMEOUT)) { + if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } - - if (oxfw->has_output) { - if (!amdtp_stream_wait_callback(&oxfw->tx_stream, - CALLBACK_TIMEOUT)) { - err = -ETIMEDOUT; - goto error; - } - } } return 0; diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 9eea25c46dc7..84971d78d152 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -23,6 +23,8 @@ #define OUI_APOGEE 0x0003db #define MODEL_SATELLITE 0x00200f +#define MODEL_SCS1M 0x001000 +#define MODEL_DUET_FW 0x01dddd #define SPECIFIER_1394TA 0x00a02d #define VERSION_AVC 0x010001 @@ -46,8 +48,6 @@ static bool detect_loud_models(struct fw_unit *unit) "Onyx-i", "Onyx 1640i", "d.Pro", - "Mackie Onyx Satellite", - "Tapco LINK.firewire 4x6", "U.420"}; char model[32]; int err; @@ -60,7 +60,7 @@ static bool detect_loud_models(struct fw_unit *unit) return match_string(models, ARRAY_SIZE(models), model) >= 0; } -static int name_card(struct snd_oxfw *oxfw) +static int name_card(struct snd_oxfw *oxfw, const struct ieee1394_device_id *entry) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); const struct compat_info *info; @@ -88,10 +88,12 @@ static int name_card(struct snd_oxfw *oxfw) goto end; be32_to_cpus(&firmware); + if (firmware >> 20 == 0x970) + oxfw->quirks |= SND_OXFW_QUIRK_JUMBO_PAYLOAD; + /* to apply card definitions */ - if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || - oxfw->entry->vendor_id == VENDOR_LACIE) { - info = (const struct compat_info *)oxfw->entry->driver_data; + if (entry->vendor_id == VENDOR_GRIFFIN || entry->vendor_id == VENDOR_LACIE) { + info = (const struct compat_info *)entry->driver_data; d = info->driver_name; v = info->vendor_name; m = info->model_name; @@ -120,9 +122,12 @@ static void oxfw_card_free(struct snd_card *card) if (oxfw->has_output || oxfw->has_input) snd_oxfw_stream_destroy_duplex(oxfw); + + mutex_destroy(&oxfw->mutex); + fw_unit_put(oxfw->unit); } -static int detect_quirks(struct snd_oxfw *oxfw) +static int detect_quirks(struct snd_oxfw *oxfw, const struct ieee1394_device_id *entry) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); struct fw_csr_iterator it; @@ -133,28 +138,35 @@ static int detect_quirks(struct snd_oxfw *oxfw) * Add ALSA control elements for two models to keep compatibility to * old firewire-speaker module. */ - if (oxfw->entry->vendor_id == VENDOR_GRIFFIN) + if (entry->vendor_id == VENDOR_GRIFFIN) return snd_oxfw_add_spkr(oxfw, false); - if (oxfw->entry->vendor_id == VENDOR_LACIE) + if (entry->vendor_id == VENDOR_LACIE) return snd_oxfw_add_spkr(oxfw, true); /* * Stanton models supports asynchronous transactions for unique MIDI * messages. */ - if (oxfw->entry->vendor_id == OUI_STANTON) { - /* No physical MIDI ports. */ + if (entry->vendor_id == OUI_STANTON) { + oxfw->quirks |= SND_OXFW_QUIRK_SCS_TRANSACTION; + if (entry->model_id == MODEL_SCS1M) + oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION; + + // No physical MIDI ports. oxfw->midi_input_ports = 0; oxfw->midi_output_ports = 0; return snd_oxfw_scs1x_add(oxfw); } + if (entry->vendor_id == OUI_APOGEE && entry->model_id == MODEL_DUET_FW) + oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION; + /* * TASCAM FireOne has physical control and requires a pair of additional * MIDI ports. */ - if (oxfw->entry->vendor_id == VENDOR_TASCAM) { + if (entry->vendor_id == VENDOR_TASCAM) { oxfw->midi_input_ports++; oxfw->midi_output_ports++; return 0; @@ -175,27 +187,35 @@ static int detect_quirks(struct snd_oxfw *oxfw) * value in 'dbs' field of CIP header against its format information. */ if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE) - oxfw->wrong_dbs = true; + oxfw->quirks |= SND_OXFW_QUIRK_WRONG_DBS; return 0; } -static void do_registration(struct work_struct *work) +static int oxfw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { - struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work); + struct snd_card *card; + struct snd_oxfw *oxfw; int err; - if (oxfw->registered) - return; + if (entry->vendor_id == VENDOR_LOUD && entry->model_id == 0 && !detect_loud_models(unit)) + return -ENODEV; - err = snd_card_new(&oxfw->unit->device, -1, NULL, THIS_MODULE, 0, - &oxfw->card); + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*oxfw), &card); if (err < 0) - return; - oxfw->card->private_free = oxfw_card_free; - oxfw->card->private_data = oxfw; + return err; + card->private_free = oxfw_card_free; + + oxfw = card->private_data; + oxfw->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, oxfw); + oxfw->card = card; - err = name_card(oxfw); + mutex_init(&oxfw->mutex); + spin_lock_init(&oxfw->lock); + init_waitqueue_head(&oxfw->hwdep_wait); + + err = name_card(oxfw, entry); if (err < 0) goto error; @@ -203,7 +223,7 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - err = detect_quirks(oxfw); + err = detect_quirks(oxfw, entry); if (err < 0) goto error; @@ -227,85 +247,38 @@ static void do_registration(struct work_struct *work) goto error; } - err = snd_card_register(oxfw->card); + err = snd_card_register(card); if (err < 0) goto error; - oxfw->registered = true; - - return; -error: - snd_card_free(oxfw->card); - dev_info(&oxfw->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int oxfw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) -{ - struct snd_oxfw *oxfw; - - if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) - return -ENODEV; - - /* Allocate this independent of sound card instance. */ - oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL); - if (!oxfw) - return -ENOMEM; - oxfw->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, oxfw); - - oxfw->entry = entry; - mutex_init(&oxfw->mutex); - spin_lock_init(&oxfw->lock); - init_waitqueue_head(&oxfw->hwdep_wait); - - /* Allocate and register this sound card later. */ - INIT_DEFERRABLE_WORK(&oxfw->dwork, do_registration); - snd_fw_schedule_registration(unit, &oxfw->dwork); - return 0; +error: + snd_card_free(card); + return err; } static void oxfw_bus_reset(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - if (!oxfw->registered) - snd_fw_schedule_registration(unit, &oxfw->dwork); - fcp_bus_reset(oxfw->unit); - if (oxfw->registered) { - if (oxfw->has_output || oxfw->has_input) { - mutex_lock(&oxfw->mutex); - snd_oxfw_stream_update_duplex(oxfw); - mutex_unlock(&oxfw->mutex); - } - - if (oxfw->entry->vendor_id == OUI_STANTON) - snd_oxfw_scs1x_update(oxfw); + if (oxfw->has_output || oxfw->has_input) { + mutex_lock(&oxfw->mutex); + snd_oxfw_stream_update_duplex(oxfw); + mutex_unlock(&oxfw->mutex); } + + if (oxfw->quirks & SND_OXFW_QUIRK_SCS_TRANSACTION) + snd_oxfw_scs1x_update(oxfw); } static void oxfw_remove(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_delayed_work_sync(&oxfw->dwork); - - if (oxfw->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(oxfw->card); - } - - mutex_destroy(&oxfw->mutex); - fw_unit_put(oxfw->unit); + // Block till all of ALSA character devices are released. + snd_card_free(oxfw->card); } static const struct compat_info griffin_firewave = { @@ -320,81 +293,67 @@ static const struct compat_info lacie_speakers = { .model_name = "FireWire Speakers", }; +#define OXFW_DEV_ENTRY(vendor, model, data) \ +{ \ + .match_flags = IEEE1394_MATCH_VENDOR_ID | \ + IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | \ + IEEE1394_MATCH_VERSION, \ + .vendor_id = vendor, \ + .model_id = model, \ + .specifier_id = SPECIFIER_1394TA, \ + .version = VERSION_AVC, \ + .driver_data = (kernel_ulong_t)data, \ +} + static const struct ieee1394_device_id oxfw_id_table[] = { - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_GRIFFIN, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - .driver_data = (kernel_ulong_t)&griffin_firewave, - }, - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_LACIE, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - .driver_data = (kernel_ulong_t)&lacie_speakers, - }, - /* Behringer,F-Control Audio 202 */ - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = VENDOR_BEHRINGER, - .model_id = 0x00fc22, - }, - /* - * Any Mackie(Loud) models (name string/model id): - * Onyx-i series (former models): 0x081216 - * Mackie Onyx Satellite: 0x00200f - * Tapco LINK.firewire 4x6: 0x000460 - * d.4 pro: Unknown - * U.420: Unknown - * U.420d: Unknown - */ + // + // OXFW970 devices: + // Initial firmware has a quirk to postpone isoc packet transmission during finishing async + // transaction. As a result, several isochronous cycles are skipped to transfer the packets + // and the audio data frames which should have been transferred during the cycles are put + // into packet at the first isoc cycle after the postpone. Furthermore, the value of SYT + // field in CIP header is not reliable as synchronization timing, + // + OXFW_DEV_ENTRY(VENDOR_GRIFFIN, 0x00f970, &griffin_firewave), + OXFW_DEV_ENTRY(VENDOR_LACIE, 0x00f970, &lacie_speakers), + // Behringer,F-Control Audio 202. The value of SYT field is not reliable at all. + OXFW_DEV_ENTRY(VENDOR_BEHRINGER, 0x00fc22, NULL), + // Loud Technologies, Tapco Link.FireWire 4x6. The value of SYT field is always 0xffff. + OXFW_DEV_ENTRY(VENDOR_LOUD, 0x000460, NULL), + // Loud Technologies, Mackie Onyx Satellite. Although revised version of firmware is + // installed to avoid the postpone, the value of SYT field is always 0xffff. + OXFW_DEV_ENTRY(VENDOR_LOUD, MODEL_SATELLITE, NULL), + // Miglia HarmonyAudio. Not yet identified. + + // + // OXFW971 devices: + // The value of SYT field in CIP header is enough reliable. Both of blocking and non-blocking + // transmission methods are available. + // + // Any Mackie(Loud) models (name string/model id): + // Onyx-i series (former models): 0x081216 + // Onyx 1640i: 0x001640 + // d.2 pro/d.4 pro (built-in card): Unknown + // U.420: Unknown + // U.420d: Unknown { .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, .vendor_id = VENDOR_LOUD, + .model_id = 0, .specifier_id = SPECIFIER_1394TA, .version = VERSION_AVC, }, - /* TASCAM, FireOne */ - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = VENDOR_TASCAM, - .model_id = 0x800007, - }, - /* Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m) */ - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = OUI_STANTON, - .model_id = 0x001000, - }, - /* Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d) */ - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = OUI_STANTON, - .model_id = 0x002000, - }, - // APOGEE, duet FireWire - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = OUI_APOGEE, - .model_id = 0x01dddd, - }, + // TASCAM, FireOne. + OXFW_DEV_ENTRY(VENDOR_TASCAM, 0x800007, NULL), + // Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m). + OXFW_DEV_ENTRY(OUI_STANTON, MODEL_SCS1M, NULL), + // Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d). + OXFW_DEV_ENTRY(OUI_STANTON, 0x002000, NULL), + // APOGEE, duet FireWire. + OXFW_DEV_ENTRY(OUI_APOGEE, MODEL_DUET_FW, NULL), { } }; MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table); diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index fa2d7f9e2dc3..ee47abcb0c90 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -32,6 +32,18 @@ #include "../amdtp-am824.h" #include "../cmp.h" +enum snd_oxfw_quirk { + // Postpone transferring packets during handling asynchronous transaction. As a result, + // next isochronous packet includes more events than one packet can include. + SND_OXFW_QUIRK_JUMBO_PAYLOAD = 0x01, + // The dbs field of CIP header in tx packet is wrong. + SND_OXFW_QUIRK_WRONG_DBS = 0x02, + // Blocking transmission mode is used. + SND_OXFW_QUIRK_BLOCKING_TRANSMISSION = 0x04, + // Stanton SCS1.d and SCS1.m support unique transaction. + SND_OXFW_QUIRK_SCS_TRANSACTION = 0x08, +}; + /* This is an arbitrary number for convinience. */ #define SND_OXFW_STREAM_FORMAT_ENTRIES 10 struct snd_oxfw { @@ -40,10 +52,8 @@ struct snd_oxfw { struct mutex mutex; spinlock_t lock; - bool registered; - struct delayed_work dwork; - - bool wrong_dbs; + // The combination of snd_oxfw_quirk enumeration-constants. + unsigned int quirks; bool has_output; bool has_input; u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES]; @@ -62,7 +72,6 @@ struct snd_oxfw { bool dev_lock_changed; wait_queue_head_t hwdep_wait; - const struct ieee1394_device_id *entry; void *spec; struct amdtp_domain domain; diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c index f823a2ab3544..64d66a802545 100644 --- a/sound/firewire/tascam/amdtp-tascam.c +++ b/sound/firewire/tascam/amdtp-tascam.c @@ -228,6 +228,7 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, unsigned int pcm_channels) { amdtp_stream_process_ctx_payloads_t process_ctx_payloads; + unsigned int flags = CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK | CIP_UNAWARE_SYT; struct amdtp_tscm *p; unsigned int fmt; int err; @@ -240,8 +241,7 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, process_ctx_payloads = process_it_ctx_payloads; } - err = amdtp_stream_init(s, unit, dir, - CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK, fmt, + err = amdtp_stream_init(s, unit, dir, flags, fmt, process_ctx_payloads, sizeof(struct amdtp_tscm)); if (err < 0) return 0; @@ -249,8 +249,6 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit, if (dir == AMDTP_OUT_STREAM) { // Use fixed value for FDF field. s->ctx_data.rx.fdf = 0x00; - // Not used. - s->ctx_data.rx.syt_override = 0x0000; } /* This protocol uses fixed number of data channels for PCM samples. */ diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index eb07e1decf9b..53e094cc411f 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -11,7 +11,7 @@ #define CLOCK_STATUS_MASK 0xffff0000 #define CLOCK_CONFIG_MASK 0x0000ffff -#define CALLBACK_TIMEOUT 500 +#define READY_TIMEOUT_MS 4000 static int get_clock(struct snd_tscm *tscm, u32 *data) { @@ -423,6 +423,8 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, fw_iso_resources_free(&tscm->rx_resources); return err; } + + tscm->need_long_tx_init_skip = (rate != curr_rate); } return 0; @@ -454,6 +456,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) if (!amdtp_stream_running(&tscm->rx_stream)) { int spd = fw_parent_device(tscm->unit)->max_speed; + unsigned int tx_init_skip_cycles; err = set_stream_formats(tscm, rate); if (err < 0) @@ -473,14 +476,23 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) if (err < 0) goto error; - err = amdtp_domain_start(&tscm->domain, 0); + if (tscm->need_long_tx_init_skip) + tx_init_skip_cycles = 16000; + else + tx_init_skip_cycles = 0; + + // MEMO: Just after starting packet streaming, it transfers packets without any + // event. Enough after receiving the sequence of packets, it multiplexes events into + // the packet. However, just after changing sampling transfer frequency, it stops + // multiplexing during packet transmission. Enough after, it restarts multiplexing + // again. The device ignores presentation time expressed by the value of syt field + // of CIP header in received packets. The sequence of the number of data blocks per + // packet is important for media clock recovery. + err = amdtp_domain_start(&tscm->domain, tx_init_skip_cycles, true, true); if (err < 0) return err; - if (!amdtp_stream_wait_callback(&tscm->rx_stream, - CALLBACK_TIMEOUT) || - !amdtp_stream_wait_callback(&tscm->tx_stream, - CALLBACK_TIMEOUT)) { + if (!amdtp_domain_wait_ready(&tscm->domain, READY_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } @@ -502,6 +514,8 @@ void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm) fw_iso_resources_free(&tscm->tx_resources); fw_iso_resources_free(&tscm->rx_resources); + + tscm->need_long_tx_init_skip = false; } } diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c index 75f2edd8e78f..eb58d3fcf087 100644 --- a/sound/firewire/tascam/tascam.c +++ b/sound/firewire/tascam/tascam.c @@ -90,19 +90,31 @@ static void tscm_card_free(struct snd_card *card) snd_tscm_transaction_unregister(tscm); snd_tscm_stream_destroy_duplex(tscm); + + mutex_destroy(&tscm->mutex); + fw_unit_put(tscm->unit); } -static void do_registration(struct work_struct *work) +static int snd_tscm_probe(struct fw_unit *unit, + const struct ieee1394_device_id *entry) { - struct snd_tscm *tscm = container_of(work, struct snd_tscm, dwork.work); + struct snd_card *card; + struct snd_tscm *tscm; int err; - err = snd_card_new(&tscm->unit->device, -1, NULL, THIS_MODULE, 0, - &tscm->card); + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*tscm), &card); if (err < 0) - return; - tscm->card->private_free = tscm_card_free; - tscm->card->private_data = tscm; + return err; + card->private_free = tscm_card_free; + + tscm = card->private_data; + tscm->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, tscm); + tscm->card = card; + + mutex_init(&tscm->mutex); + spin_lock_init(&tscm->lock); + init_waitqueue_head(&tscm->hwdep_wait); err = identify_model(tscm); if (err < 0) @@ -130,81 +142,33 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - err = snd_card_register(tscm->card); + err = snd_card_register(card); if (err < 0) goto error; - tscm->registered = true; - - return; -error: - snd_card_free(tscm->card); - dev_info(&tscm->unit->device, - "Sound card registration failed: %d\n", err); -} - -static int snd_tscm_probe(struct fw_unit *unit, - const struct ieee1394_device_id *entry) -{ - struct snd_tscm *tscm; - - /* Allocate this independent of sound card instance. */ - tscm = devm_kzalloc(&unit->device, sizeof(struct snd_tscm), GFP_KERNEL); - if (!tscm) - return -ENOMEM; - tscm->unit = fw_unit_get(unit); - dev_set_drvdata(&unit->device, tscm); - - mutex_init(&tscm->mutex); - spin_lock_init(&tscm->lock); - init_waitqueue_head(&tscm->hwdep_wait); - - /* Allocate and register this sound card later. */ - INIT_DEFERRABLE_WORK(&tscm->dwork, do_registration); - snd_fw_schedule_registration(unit, &tscm->dwork); - return 0; +error: + snd_card_free(card); + return err; } static void snd_tscm_update(struct fw_unit *unit) { struct snd_tscm *tscm = dev_get_drvdata(&unit->device); - /* Postpone a workqueue for deferred registration. */ - if (!tscm->registered) - snd_fw_schedule_registration(unit, &tscm->dwork); - snd_tscm_transaction_reregister(tscm); - /* - * After registration, userspace can start packet streaming, then this - * code block works fine. - */ - if (tscm->registered) { - mutex_lock(&tscm->mutex); - snd_tscm_stream_update_duplex(tscm); - mutex_unlock(&tscm->mutex); - } + mutex_lock(&tscm->mutex); + snd_tscm_stream_update_duplex(tscm); + mutex_unlock(&tscm->mutex); } static void snd_tscm_remove(struct fw_unit *unit) { struct snd_tscm *tscm = dev_get_drvdata(&unit->device); - /* - * Confirm to stop the work for registration before the sound card is - * going to be released. The work is not scheduled again because bus - * reset handler is not called anymore. - */ - cancel_delayed_work_sync(&tscm->dwork); - - if (tscm->registered) { - // Block till all of ALSA character devices are released. - snd_card_free(tscm->card); - } - - mutex_destroy(&tscm->mutex); - fw_unit_put(tscm->unit); + // Block till all of ALSA character devices are released. + snd_card_free(tscm->card); } static const struct ieee1394_device_id snd_tscm_id_table[] = { diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 78b7a08986a1..d07ffcb27be6 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -70,8 +70,6 @@ struct snd_tscm { struct mutex mutex; spinlock_t lock; - bool registered; - struct delayed_work dwork; const struct snd_tscm_spec *spec; struct fw_iso_resources tx_resources; @@ -99,6 +97,7 @@ struct snd_tscm { unsigned int push_pos; struct amdtp_domain domain; + bool need_long_tx_init_skip; }; #define TSCM_ADDR_BASE 0xffff00000000ull diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 8634d4f466b3..65012af6a36e 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -50,7 +50,8 @@ int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg, buf[0] = reg & 0x7f; buf[1] = val; - if ((err = snd_i2c_sendbytes(device, buf, 2)) != 2) { + err = snd_i2c_sendbytes(device, buf, 2); + if (err != 2) { snd_printk(KERN_ERR "unable to send bytes 0x%02x:0x%02x " "to CS8427 (%i)\n", buf[0], buf[1], err); return err < 0 ? err : -EIO; @@ -65,12 +66,14 @@ static int snd_cs8427_reg_read(struct snd_i2c_device *device, unsigned char reg) int err; unsigned char buf; - if ((err = snd_i2c_sendbytes(device, ®, 1)) != 1) { + err = snd_i2c_sendbytes(device, ®, 1); + if (err != 1) { snd_printk(KERN_ERR "unable to send register 0x%x byte " "to CS8427\n", reg); return err < 0 ? err : -EIO; } - if ((err = snd_i2c_readbytes(device, &buf, 1)) != 1) { + err = snd_i2c_readbytes(device, &buf, 1); + if (err != 1) { snd_printk(KERN_ERR "unable to read register 0x%x byte " "from CS8427\n", reg); return err < 0 ? err : -EIO; @@ -108,7 +111,8 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device, if (!memcmp(hw_data, ndata, count)) return 0; - if ((err = snd_cs8427_select_corudata(device, udata)) < 0) + err = snd_cs8427_select_corudata(device, udata); + if (err < 0) return err; memcpy(hw_data, ndata, count); if (udata) { @@ -209,7 +213,8 @@ int snd_cs8427_init(struct snd_i2c_bus *bus, goto __fail; /* send initial values */ memcpy(chip->regmap + (initvals1[0] & 0x7f), initvals1 + 1, 6); - if ((err = snd_i2c_sendbytes(device, initvals1, 7)) != 7) { + err = snd_i2c_sendbytes(device, initvals1, 7); + if (err != 7) { err = err < 0 ? err : -EIO; goto __fail; } @@ -217,11 +222,13 @@ int snd_cs8427_init(struct snd_i2c_bus *bus, memset(buf, 0, 7); /* from address 9 to 15 */ buf[0] = 9; /* register */ - if ((err = snd_i2c_sendbytes(device, buf, 7)) != 7) + err = snd_i2c_sendbytes(device, buf, 7); + if (err != 7) goto __fail; /* send transfer initialization sequence */ memcpy(chip->regmap + (initvals2[0] & 0x7f), initvals2 + 1, 3); - if ((err = snd_i2c_sendbytes(device, initvals2, 4)) != 4) { + err = snd_i2c_sendbytes(device, initvals2, 4); + if (err != 4) { err = err < 0 ? err : -EIO; goto __fail; } @@ -383,7 +390,8 @@ static int snd_cs8427_qsubcode_get(struct snd_kcontrol *kcontrol, int err; snd_i2c_lock(device->bus); - if ((err = snd_i2c_sendbytes(device, ®, 1)) != 1) { + err = snd_i2c_sendbytes(device, ®, 1); + if (err != 1) { snd_printk(KERN_ERR "unable to send register 0x%x byte " "to CS8427\n", reg); snd_i2c_unlock(device->bus); diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 2ce0a97957ab..c0cffe28989b 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -97,7 +97,8 @@ int snd_ak4114_create(struct snd_card *card, chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT); chip->rcs1 = reg_read(chip, AK4114_REG_RCS1); - if ((err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops)) < 0) + err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops); + if (err < 0) goto __fail; if (r_ak4114) diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 905be2d0780b..1bc43e927d82 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -86,7 +86,8 @@ int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t chip->rcs1 = reg_read(chip, AK4117_REG_RCS1); chip->rcs2 = reg_read(chip, AK4117_REG_RCS2); - if ((err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops)) < 0) + err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops); + if (err < 0) goto __fail; if (r_ak4117) diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index 08eb6a873768..037d6293f728 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c @@ -115,7 +115,8 @@ static int snd_tea6330t_put_master_volume(struct snd_kcontrol *kcontrol, bytes[count++] = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] = tea->mright; } if (count > 0) { - if ((err = snd_i2c_sendbytes(tea->device, bytes, count)) < 0) + err = snd_i2c_sendbytes(tea->device, bytes, count); + if (err < 0) change = err; } snd_i2c_unlock(tea->bus); @@ -160,7 +161,8 @@ static int snd_tea6330t_put_master_switch(struct snd_kcontrol *kcontrol, bytes[0] = TEA6330T_SADDR_VOLUME_LEFT; bytes[1] = tea->regs[TEA6330T_SADDR_VOLUME_LEFT]; bytes[2] = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT]; - if ((err = snd_i2c_sendbytes(tea->device, bytes, 3)) < 0) + err = snd_i2c_sendbytes(tea->device, bytes, 3); + if (err < 0) change = err; snd_i2c_unlock(tea->bus); return change; @@ -207,7 +209,8 @@ static int snd_tea6330t_put_bass(struct snd_kcontrol *kcontrol, change = tea->regs[TEA6330T_SADDR_BASS] != val1; bytes[0] = TEA6330T_SADDR_BASS; bytes[1] = tea->regs[TEA6330T_SADDR_BASS] = val1; - if ((err = snd_i2c_sendbytes(tea->device, bytes, 2)) < 0) + err = snd_i2c_sendbytes(tea->device, bytes, 2); + if (err < 0) change = err; snd_i2c_unlock(tea->bus); return change; @@ -254,7 +257,8 @@ static int snd_tea6330t_put_treble(struct snd_kcontrol *kcontrol, change = tea->regs[TEA6330T_SADDR_TREBLE] != val1; bytes[0] = TEA6330T_SADDR_TREBLE; bytes[1] = tea->regs[TEA6330T_SADDR_TREBLE] = val1; - if ((err = snd_i2c_sendbytes(tea->device, bytes, 2)) < 0) + err = snd_i2c_sendbytes(tea->device, bytes, 2); + if (err < 0) change = err; snd_i2c_unlock(tea->bus); return change; @@ -280,14 +284,15 @@ int snd_tea6330t_update_mixer(struct snd_card *card, struct tea6330t *tea; const struct snd_kcontrol_new *knew; unsigned int idx; - int err = -ENOMEM; + int err; u8 default_treble, default_bass; unsigned char bytes[7]; tea = kzalloc(sizeof(*tea), GFP_KERNEL); if (tea == NULL) return -ENOMEM; - if ((err = snd_i2c_device_create(bus, "TEA6330T", TEA6330T_ADDR, &device)) < 0) { + err = snd_i2c_device_create(bus, "TEA6330T", TEA6330T_ADDR, &device); + if (err < 0) { kfree(tea); return err; } @@ -327,18 +332,21 @@ int snd_tea6330t_update_mixer(struct snd_card *card, bytes[0] = TEA6330T_SADDR_VOLUME_LEFT; for (idx = 0; idx < 6; idx++) bytes[idx+1] = tea->regs[idx]; - if ((err = snd_i2c_sendbytes(device, bytes, 7)) < 0) + err = snd_i2c_sendbytes(device, bytes, 7); + if (err < 0) goto __error; strcat(card->mixername, ",TEA6330T"); - if ((err = snd_component_add(card, "TEA6330T")) < 0) + err = snd_component_add(card, "TEA6330T"); + if (err < 0) goto __error; for (idx = 0; idx < ARRAY_SIZE(snd_tea6330t_controls); idx++) { knew = &snd_tea6330t_controls[idx]; if (tea->treble == 0 && !strcmp(knew->name, "Tone Control - Treble")) continue; - if ((err = snd_ctl_add(card, snd_ctl_new1(knew, tea))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(knew, tea)); + if (err < 0) goto __error; } diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index f11af983b3b6..fa5bed0d5a6f 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -131,16 +131,18 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, return error; chip = card->private_data; - if ((error = snd_card_ad1816a_pnp(dev, pcard, pid))) { + error = snd_card_ad1816a_pnp(dev, pcard, pid); + if (error) { snd_card_free(card); return error; } - if ((error = snd_ad1816a_create(card, port[dev], - irq[dev], - dma1[dev], - dma2[dev], - chip)) < 0) { + error = snd_ad1816a_create(card, port[dev], + irq[dev], + dma1[dev], + dma2[dev], + chip); + if (error) { snd_card_free(card); return error; } @@ -152,12 +154,14 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d", card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); - if ((error = snd_ad1816a_pcm(chip, 0)) < 0) { + error = snd_ad1816a_pcm(chip, 0); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_ad1816a_mixer(chip)) < 0) { + error = snd_ad1816a_mixer(chip); + if (error < 0) { snd_card_free(card); return error; } @@ -189,7 +193,8 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard, } } - if ((error = snd_card_register(card)) < 0) { + error = snd_card_register(card); + if (error < 0) { snd_card_free(card); return error; } diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 01381fe7c0c9..6d4999b30461 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -155,7 +155,8 @@ static void snd_ad1816a_close(struct snd_ad1816a *chip, unsigned int mode) snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE, AD1816A_TIMER_IRQ_ENABLE, 0x0000); } - if (!((chip->mode &= ~mode) & AD1816A_MODE_OPEN)) + chip->mode &= ~mode; + if (!(chip->mode & AD1816A_MODE_OPEN)) chip->mode = 0; spin_unlock_irqrestore(&chip->lock, flags); @@ -426,7 +427,8 @@ static int snd_ad1816a_playback_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int error; - if ((error = snd_ad1816a_open(chip, AD1816A_MODE_PLAYBACK)) < 0) + error = snd_ad1816a_open(chip, AD1816A_MODE_PLAYBACK); + if (error < 0) return error; runtime->hw = snd_ad1816a_playback; snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); @@ -441,7 +443,8 @@ static int snd_ad1816a_capture_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int error; - if ((error = snd_ad1816a_open(chip, AD1816A_MODE_CAPTURE)) < 0) + error = snd_ad1816a_open(chip, AD1816A_MODE_CAPTURE); + if (error < 0) return error; runtime->hw = snd_ad1816a_capture; snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); @@ -586,7 +589,8 @@ int snd_ad1816a_create(struct snd_card *card, chip->dma1 = -1; chip->dma2 = -1; - if ((chip->res_port = request_region(port, 16, "AD1816A")) == NULL) { + chip->res_port = request_region(port, 16, "AD1816A"); + if (!chip->res_port) { snd_printk(KERN_ERR "ad1816a: can't grab port 0x%lx\n", port); snd_ad1816a_free(chip); return -EBUSY; @@ -615,7 +619,8 @@ int snd_ad1816a_create(struct snd_card *card, chip->port = port; spin_lock_init(&chip->lock); - if ((error = snd_ad1816a_probe(chip))) { + error = snd_ad1816a_probe(chip); + if (error) { snd_ad1816a_free(chip); return error; } @@ -623,7 +628,8 @@ int snd_ad1816a_create(struct snd_card *card, snd_ad1816a_init(chip); /* Register device */ - if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (error < 0) { snd_ad1816a_free(chip); return error; } @@ -652,7 +658,8 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device) int error; struct snd_pcm *pcm; - if ((error = snd_pcm_new(chip->card, "AD1816A", device, 1, 1, &pcm))) + error = snd_pcm_new(chip->card, "AD1816A", device, 1, 1, &pcm); + if (error) return error; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ad1816a_playback_ops); @@ -682,7 +689,8 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device) tid.card = chip->card->number; tid.device = device; tid.subdevice = 0; - if ((error = snd_timer_new(chip->card, "AD1816A", &tid, &timer)) < 0) + error = snd_timer_new(chip->card, "AD1816A", &tid, &timer); + if (error < 0) return error; strcpy(timer->name, snd_ad1816a_chip_id(chip)); timer->private_data = chip; @@ -944,7 +952,8 @@ int snd_ad1816a_mixer(struct snd_ad1816a *chip) strcpy(card->mixername, snd_ad1816a_chip_id(chip)); for (idx = 0; idx < ARRAY_SIZE(snd_ad1816a_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ad1816a_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_ad1816a_controls[idx], chip)); + if (err < 0) return err; } return 0; diff --git a/sound/isa/als100.c b/sound/isa/als100.c index bacb7a1b930c..d4597fdfe091 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -177,7 +177,8 @@ static int snd_card_als100_probe(int dev, return error; acard = card->private_data; - if ((error = snd_card_als100_pnp(dev, acard, pcard, pid))) { + error = snd_card_als100_pnp(dev, acard, pcard, pid); + if (error) { snd_card_free(card); return error; } @@ -211,12 +212,14 @@ static int snd_card_als100_probe(int dev, dma16[dev]); } - if ((error = snd_sb16dsp_pcm(chip, 0)) < 0) { + error = snd_sb16dsp_pcm(chip, 0); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_sbmixer_new(chip)) < 0) { + error = snd_sbmixer_new(chip); + if (error < 0) { snd_card_free(card); return error; } @@ -245,18 +248,21 @@ static int snd_card_als100_probe(int dev, snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n", fm_port[dev], fm_port[dev] + 2); } else { - if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) { + error = snd_opl3_timer_new(opl3, 0, 1); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + error = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (error < 0) { snd_card_free(card); return error; } } } - if ((error = snd_card_register(card)) < 0) { + error = snd_card_register(card); + if (error < 0) { snd_card_free(card); return error; } diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index 867e9ae8f65a..dd5c059b3744 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c @@ -148,9 +148,11 @@ static int snd_card_azt2320_enable_wss(unsigned long port) { int error; - if ((error = snd_card_azt2320_command(port, 0x09))) + error = snd_card_azt2320_command(port, 0x09); + if (error) return error; - if ((error = snd_card_azt2320_command(port, 0x00))) + error = snd_card_azt2320_command(port, 0x00); + if (error) return error; mdelay(5); @@ -174,12 +176,14 @@ static int snd_card_azt2320_probe(int dev, return error; acard = card->private_data; - if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { + error = snd_card_azt2320_pnp(dev, acard, pcard, pid); + if (error) { snd_card_free(card); return error; } - if ((error = snd_card_azt2320_enable_wss(port[dev]))) { + error = snd_card_azt2320_enable_wss(port[dev]); + if (error) { snd_card_free(card); return error; } @@ -228,18 +232,21 @@ static int snd_card_azt2320_probe(int dev, snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n", fm_port[dev], fm_port[dev] + 2); } else { - if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) { + error = snd_opl3_timer_new(opl3, 1, 2); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + error = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (error < 0) { snd_card_free(card); return error; } } } - if ((error = snd_card_register(card)) < 0) { + error = snd_card_register(card); + if (error < 0) { snd_card_free(card); return error; } diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index bc112df10fc5..6c59a3eec59b 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -284,7 +284,8 @@ static int cmi8330_add_sb_mixers(struct snd_sb *chip) } for (idx = 0; idx < ARRAY_SIZE(cmi8330_sb_mixers); idx++) { - if ((err = snd_sbmixer_add_ctl_elem(chip, &cmi8330_sb_mixers[idx])) < 0) + err = snd_sbmixer_add_ctl_elem(chip, &cmi8330_sb_mixers[idx]); + if (err < 0) return err; } return 0; @@ -307,7 +308,8 @@ static int snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 *acard) } #ifdef ENABLE_SB_MIXER - if ((err = cmi8330_add_sb_mixers(acard->sb)) < 0) + err = cmi8330_add_sb_mixers(acard->sb); + if (err < 0) return err; #endif return 0; @@ -432,7 +434,8 @@ static int snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip) snd_cmi8330_capture_open }; - if ((err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm)) < 0) + err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm); + if (err < 0) return err; strcpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330"); pcm->private_data = chip; @@ -536,12 +539,13 @@ static int snd_cmi8330_probe(struct snd_card *card, int dev) return -ENODEV; } - if ((err = snd_sbdsp_create(card, sbport[dev], - sbirq[dev], - snd_sb16dsp_interrupt, - sbdma8[dev], - sbdma16[dev], - SB_HW_AUTO, &acard->sb)) < 0) { + err = snd_sbdsp_create(card, sbport[dev], + sbirq[dev], + snd_sb16dsp_interrupt, + sbdma8[dev], + sbdma16[dev], + SB_HW_AUTO, &acard->sb); + if (err < 0) { snd_printk(KERN_ERR PFX "SB16 device busy??\n"); return err; } @@ -555,12 +559,14 @@ static int snd_cmi8330_probe(struct snd_card *card, int dev) snd_wss_out(acard->wss, i, snd_cmi8330_image[i - CMI8330_RMUX3D]); - if ((err = snd_cmi8330_mixer(card, acard)) < 0) { + err = snd_cmi8330_mixer(card, acard); + if (err < 0) { snd_printk(KERN_ERR PFX "failed to create mixers\n"); return err; } - if ((err = snd_cmi8330_pcm(card, acard)) < 0) { + err = snd_cmi8330_pcm(card, acard); + if (err < 0) { snd_printk(KERN_ERR PFX "failed to create pcms\n"); return err; } @@ -622,7 +628,8 @@ static int snd_cmi8330_isa_probe(struct device *pdev, err = snd_cmi8330_card_new(pdev, dev, &card); if (err < 0) return err; - if ((err = snd_cmi8330_probe(card, dev)) < 0) { + err = snd_cmi8330_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -683,12 +690,14 @@ static int snd_cmi8330_pnp_detect(struct pnp_card_link *pcard, res = snd_cmi8330_card_new(&pcard->card->dev, dev, &card); if (res < 0) return res; - if ((res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid)) < 0) { + res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid); + if (res < 0) { snd_printk(KERN_ERR PFX "PnP detection failed\n"); snd_card_free(card); return res; } - if ((res = snd_cmi8330_probe(card, dev)) < 0) { + res = snd_cmi8330_probe(card, dev); + if (res < 0) { snd_card_free(card); return res; } diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 186d7d4db45e..0b7fd17f8ecc 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -339,11 +339,13 @@ static int snd_cs423x_probe(struct snd_card *card, int dev) int err; acard = card->private_data; - if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT) - if ((acard->res_sb_port = request_region(sb_port[dev], 16, IDENT " SB")) == NULL) { + if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT) { + acard->res_sb_port = request_region(sb_port[dev], 16, IDENT " SB"); + if (!acard->res_sb_port) { printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", sb_port[dev]); return -EBUSY; } + } err = snd_cs4236_create(card, port[dev], cport[dev], irq[dev], @@ -393,7 +395,8 @@ static int snd_cs423x_probe(struct snd_card *card, int dev) OPL3_HW_OPL3_CS, 0, &opl3) < 0) { printk(KERN_WARNING IDENT ": OPL3 not detected\n"); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) return err; } } @@ -444,7 +447,8 @@ static int snd_cs423x_isa_probe(struct device *pdev, err = snd_cs423x_card_new(pdev, dev, &card); if (err < 0) return err; - if ((err = snd_cs423x_probe(card, dev)) < 0) { + err = snd_cs423x_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -538,7 +542,8 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, snd_card_free(card); return err; } - if ((err = snd_cs423x_probe(card, dev)) < 0) { + err = snd_cs423x_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -592,13 +597,15 @@ static int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard, res = snd_cs423x_card_new(&pcard->card->dev, dev, &card); if (res < 0) return res; - if ((res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid)) < 0) { + res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid); + if (res < 0) { printk(KERN_ERR "isapnp detection failed and probing for " IDENT " is not supported\n"); snd_card_free(card); return res; } - if ((res = snd_cs423x_probe(card, dev)) < 0) { + res = snd_cs423x_probe(card, dev); + if (res < 0) { snd_card_free(card); return res; } diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 52f05adb1870..63957aea456b 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -1030,12 +1030,14 @@ int snd_cs4236_mixer(struct snd_wss *chip) if (chip->hardware == WSS_HW_CS4235 || chip->hardware == WSS_HW_CS4239) { for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip)); + if (err < 0) return err; } } else { for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip)); + if (err < 0) return err; } } @@ -1058,13 +1060,15 @@ int snd_cs4236_mixer(struct snd_wss *chip) kcontrol = NULL; } for (idx = 0; idx < count; idx++, kcontrol++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip)); + if (err < 0) return err; } if (chip->hardware == WSS_HW_CS4237B || chip->hardware == WSS_HW_CS4238B) { for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip)); + if (err < 0) return err; } } diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 1816e55c6edf..8554cb2263c1 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -971,7 +971,8 @@ int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip) strcpy(card->mixername, snd_es1688_chip_id(chip)); for (idx = 0; idx < ARRAY_SIZE(snd_es1688_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es1688_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_es1688_controls[idx], chip)); + if (err < 0) return err; } for (idx = 0; idx < ES1688_INIT_TABLE_SIZE; idx++) { diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 375a4a6a4717..68b9c59e1127 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1573,7 +1573,8 @@ static int snd_es18xx_identify(struct snd_es18xx *chip) udelay(10); chip->ctrl_port += inb(chip->port + 0x05); - if ((chip->res_ctrl_port = request_region(chip->ctrl_port, 8, "ES18xx - CTRL")) == NULL) { + chip->res_ctrl_port = request_region(chip->ctrl_port, 8, "ES18xx - CTRL"); + if (!chip->res_ctrl_port) { snd_printk(KERN_ERR PFX "unable go grab port 0x%lx\n", chip->ctrl_port); return -EBUSY; } @@ -1832,41 +1833,48 @@ static int snd_es18xx_mixer(struct snd_card *card) break; } } - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) return err; } if (chip->caps & ES18XX_PCM2) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_pcm2_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_pcm2_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_pcm2_controls[idx], chip)); + if (err < 0) return err; } } else { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_pcm1_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_pcm1_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_pcm1_controls[idx], chip)); + if (err < 0) return err; } } if (chip->caps & ES18XX_RECMIX) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_recmix_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_recmix_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_recmix_controls[idx], chip)); + if (err < 0) return err; } } switch (chip->version) { default: - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_micpre1_control, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_micpre1_control, chip)); + if (err < 0) return err; break; case 0x1869: case 0x1879: - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_micpre2_control, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_micpre2_control, chip)); + if (err < 0) return err; break; } if (chip->caps & ES18XX_SPATIALIZER) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_spatializer_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_spatializer_controls[idx], chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_spatializer_controls[idx], chip)); + if (err < 0) return err; } } @@ -1879,7 +1887,8 @@ static int snd_es18xx_mixer(struct snd_card *card) else chip->hw_switch = kctl; kctl->private_free = snd_es18xx_hwv_free; - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) return err; } @@ -2154,7 +2163,8 @@ static int snd_es18xx_isa_probe1(int dev, struct device *devptr) err = snd_es18xx_card_new(devptr, dev, &card); if (err < 0) return err; - if ((err = snd_audiodrive_probe(card, dev)) < 0) { + err = snd_audiodrive_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -2169,19 +2179,22 @@ static int snd_es18xx_isa_probe(struct device *pdev, unsigned int dev) static const int possible_dmas[] = {1, 0, 3, 5, -1}; if (irq[dev] == SNDRV_AUTO_IRQ) { - if ((irq[dev] = snd_legacy_find_free_irq(possible_irqs)) < 0) { + irq[dev] = snd_legacy_find_free_irq(possible_irqs); + if (irq[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); return -EBUSY; } } if (dma1[dev] == SNDRV_AUTO_DMA) { - if ((dma1[dev] = snd_legacy_find_free_dma(possible_dmas)) < 0) { + dma1[dev] = snd_legacy_find_free_dma(possible_dmas); + if (dma1[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free DMA1\n"); return -EBUSY; } } if (dma2[dev] == SNDRV_AUTO_DMA) { - if ((dma2[dev] = snd_legacy_find_free_dma(possible_dmas)) < 0) { + dma2[dev] = snd_legacy_find_free_dma(possible_dmas); + if (dma2[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free DMA2\n"); return -EBUSY; } @@ -2257,11 +2270,13 @@ static int snd_audiodrive_pnp_detect(struct pnp_dev *pdev, err = snd_es18xx_card_new(&pdev->dev, dev, &card); if (err < 0) return err; - if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) { + err = snd_audiodrive_pnp(dev, card->private_data, pdev); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_audiodrive_probe(card, dev)) < 0) { + err = snd_audiodrive_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -2315,11 +2330,13 @@ static int snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard, if (res < 0) return res; - if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) { + res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid); + if (res < 0) { snd_card_free(card); return res; } - if ((res = snd_audiodrive_probe(card, dev)) < 0) { + res = snd_audiodrive_probe(card, dev); + if (res < 0) { snd_card_free(card); return res; } diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index b7518122a10d..3b46490271fe 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -156,12 +156,14 @@ int snd_gus_create(struct snd_card *card, gus->gf1.reg_timerctrl = GUSP(gus, TIMERCNTRL); gus->gf1.reg_timerdata = GUSP(gus, TIMERDATA); /* allocate resources */ - if ((gus->gf1.res_port1 = request_region(port, 16, "GUS GF1 (Adlib/SB)")) == NULL) { + gus->gf1.res_port1 = request_region(port, 16, "GUS GF1 (Adlib/SB)"); + if (!gus->gf1.res_port1) { snd_printk(KERN_ERR "gus: can't grab SB port 0x%lx\n", port); snd_gus_free(gus); return -EBUSY; } - if ((gus->gf1.res_port2 = request_region(port + 0x100, 12, "GUS GF1 (Synth)")) == NULL) { + gus->gf1.res_port2 = request_region(port + 0x100, 12, "GUS GF1 (Synth)"); + if (!gus->gf1.res_port2) { snd_printk(KERN_ERR "gus: can't grab synth port 0x%lx\n", port + 0x100); snd_gus_free(gus); return -EBUSY; @@ -206,7 +208,8 @@ int snd_gus_create(struct snd_card *card, gus->gf1.pcm_channels = pcm_channels; gus->gf1.volume_ramp = 25; gus->gf1.smooth_pan = 1; - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops); + if (err < 0) { snd_gus_free(gus); return err; } @@ -384,7 +387,7 @@ static int snd_gus_check_version(struct snd_gus_card * gus) } } } - strcpy(card->shortname, card->longname); + strscpy(card->shortname, card->longname, sizeof(card->shortname)); gus->uart_enable = 1; /* standard GUSes doesn't have midi uart trouble */ snd_gus_init_control(gus); return 0; @@ -395,14 +398,17 @@ int snd_gus_initialize(struct snd_gus_card *gus) int err; if (!gus->interwave) { - if ((err = snd_gus_check_version(gus)) < 0) { + err = snd_gus_check_version(gus); + if (err < 0) { snd_printk(KERN_ERR "version check failed\n"); return err; } - if ((err = snd_gus_detect_memory(gus)) < 0) + err = snd_gus_detect_memory(gus); + if (err < 0) return err; } - if ((err = snd_gus_init_dma_irq(gus, 1)) < 0) + err = snd_gus_init_dma_irq(gus, 1); + if (err < 0) return err; snd_gf1_start(gus); gus->initialized = 1; diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index cb02d18dde60..ff9480f249fe 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -210,7 +210,8 @@ int snd_gf1_mem_free(struct snd_gf1_mem * alloc, unsigned int address) struct snd_gf1_mem_block *block; snd_gf1_mem_lock(alloc, 0); - if ((block = snd_gf1_mem_look(alloc, address)) != NULL) { + block = snd_gf1_mem_look(alloc, address); + if (block) { result = snd_gf1_mem_xfree(alloc, block); snd_gf1_mem_lock(alloc, 1); return result; diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c index 201d0c40d0d9..03f9cfcbf601 100644 --- a/sound/isa/gus/gus_mixer.c +++ b/sound/isa/gus/gus_mixer.c @@ -162,12 +162,14 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus) if (!gus->ics_flag) { max = gus->ess_flag ? 1 : ARRAY_SIZE(snd_gf1_controls); for (idx = 0; idx < max; idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_gf1_controls[idx], gus))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_gf1_controls[idx], gus)); + if (err < 0) return err; } } else { for (idx = 0; idx < ARRAY_SIZE(snd_ics_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ics_controls[idx], gus))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_ics_controls[idx], gus)); + if (err < 0) return err; } } diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index aca4ab90e5bc..230f65a0e4b0 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -430,17 +430,19 @@ static int snd_gf1_pcm_playback_hw_params(struct snd_pcm_substream *substream, snd_gf1_mem_free(&gus->gf1.mem_alloc, pcmp->memory); pcmp->memory = 0; } - if ((block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc, - SNDRV_GF1_MEM_OWNER_DRIVER, - "GF1 PCM", - runtime->dma_bytes, 1, 32, - NULL)) == NULL) + block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc, + SNDRV_GF1_MEM_OWNER_DRIVER, + "GF1 PCM", + runtime->dma_bytes, 1, 32, + NULL); + if (!block) return -ENOMEM; pcmp->memory = block->ptr; } pcmp->voices = params_channels(hw_params); if (pcmp->pvoices[0] == NULL) { - if ((pcmp->pvoices[0] = snd_gf1_alloc_voice(pcmp->gus, SNDRV_GF1_VOICE_TYPE_PCM, 0, 0)) == NULL) + pcmp->pvoices[0] = snd_gf1_alloc_voice(pcmp->gus, SNDRV_GF1_VOICE_TYPE_PCM, 0, 0); + if (!pcmp->pvoices[0]) return -ENOMEM; pcmp->pvoices[0]->handler_wave = snd_gf1_pcm_interrupt_wave; pcmp->pvoices[0]->handler_volume = snd_gf1_pcm_interrupt_volume; @@ -448,7 +450,8 @@ static int snd_gf1_pcm_playback_hw_params(struct snd_pcm_substream *substream, pcmp->pvoices[0]->private_data = pcmp; } if (pcmp->voices > 1 && pcmp->pvoices[1] == NULL) { - if ((pcmp->pvoices[1] = snd_gf1_alloc_voice(pcmp->gus, SNDRV_GF1_VOICE_TYPE_PCM, 0, 0)) == NULL) + pcmp->pvoices[1] = snd_gf1_alloc_voice(pcmp->gus, SNDRV_GF1_VOICE_TYPE_PCM, 0, 0); + if (!pcmp->pvoices[1]) return -ENOMEM; pcmp->pvoices[1]->handler_wave = snd_gf1_pcm_interrupt_wave; pcmp->pvoices[1]->handler_volume = snd_gf1_pcm_interrupt_volume; @@ -689,7 +692,8 @@ static int snd_gf1_pcm_playback_open(struct snd_pcm_substream *substream) printk(KERN_DEBUG "playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n", (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer); #endif - if ((err = snd_gf1_dma_init(gus)) < 0) + err = snd_gf1_dma_init(gus); + if (err < 0) return err; pcmp->flags = SNDRV_GF1_PCM_PFLG_NONE; pcmp->substream = substream; @@ -888,7 +892,8 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index) kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus); else kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus); - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) return err; kctl->id.index = control_index; diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index 4fb4ed79e262..3975848160e7 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c @@ -232,7 +232,8 @@ int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device) struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi); + if (err < 0) return err; strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_gf1_uart_output); diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index 0fba5d8fe84f..bca1caa4968c 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c @@ -113,14 +113,16 @@ static int snd_gusclassic_detect(struct snd_gus_card *gus) unsigned char d; snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { + d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET); + if ((d & 0x07) != 0) { snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; } udelay(160); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */ udelay(160); - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { + d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET); + if ((d & 0x07) != 1) { snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; } diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index da2b2ca6b721..a409a4a29afc 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -177,14 +177,16 @@ static int snd_gusextreme_detect(struct snd_gus_card *gus, udelay(100); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { + d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET); + if ((d & 0x07) != 0) { snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); return -EIO; } udelay(160); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */ udelay(160); - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { + d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET); + if ((d & 0x07) != 1) { snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -EIO; } diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 24b945f1768d..ad118d462142 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -71,14 +71,16 @@ static int snd_gusmax_detect(struct snd_gus_card *gus) unsigned char d; snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { + d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET); + if ((d & 0x07) != 0) { snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; } udelay(160); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */ udelay(160); - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { + d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET); + if ((d & 0x07) != 1) { snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; } @@ -136,20 +138,24 @@ static int snd_gusmax_mixer(struct snd_wss *chip) /* reassign AUXA to SYNTHESIZER */ strcpy(id1.name, "Aux Playback Switch"); strcpy(id2.name, "Synth Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; strcpy(id1.name, "Aux Playback Volume"); strcpy(id2.name, "Synth Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; /* reassign AUXB to CD */ strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; strcpy(id2.name, "CD Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; strcpy(id1.name, "Aux Playback Volume"); strcpy(id2.name, "CD Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; #if 0 /* reassign Mono Input to MIC */ @@ -209,7 +215,8 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) xirq = irq[dev]; if (xirq == SNDRV_AUTO_IRQ) { - if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { + xirq = snd_legacy_find_free_irq(possible_irqs); + if (xirq < 0) { snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); err = -EBUSY; goto _err; @@ -217,7 +224,8 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) } xdma1 = dma1[dev]; if (xdma1 == SNDRV_AUTO_DMA) { - if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { + xdma1 = snd_legacy_find_free_dma(possible_dmas); + if (xdma1 < 0) { snd_printk(KERN_ERR PFX "unable to find a free DMA1\n"); err = -EBUSY; goto _err; @@ -225,7 +233,8 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) } xdma2 = dma2[dev]; if (xdma2 == SNDRV_AUTO_DMA) { - if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) { + xdma2 = snd_legacy_find_free_dma(possible_dmas); + if (xdma2 < 0) { snd_printk(KERN_ERR PFX "unable to find a free DMA2\n"); err = -EBUSY; goto _err; @@ -260,13 +269,15 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) if (err < 0) goto _err; - if ((err = snd_gusmax_detect(gus)) < 0) + err = snd_gusmax_detect(gus); + if (err < 0) goto _err; maxcard->gus_status_reg = gus->gf1.reg_irqstat; maxcard->pcm_status_reg = gus->gf1.port + 0x10c + 2; snd_gusmax_init(dev, card, gus); - if ((err = snd_gus_initialize(gus)) < 0) + err = snd_gus_initialize(gus); + if (err < 0) goto _err; if (!gus->max_flag) { @@ -307,7 +318,8 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev) goto _err; if (pcm_channels[dev] > 0) { - if ((err = snd_gf1_pcm_new(gus, 1, 1)) < 0) + err = snd_gf1_pcm_new(gus, 1, 1); + if (err < 0) goto _err; } err = snd_gusmax_mixer(wss); diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 99581fba4ca8..755de47d0bb6 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -204,7 +204,8 @@ static int snd_interwave_detect_stb(struct snd_interwave *iwcard, port = 0x360; } while (port <= 0x380) { - if ((iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)")) != NULL) + iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)"); + if (iwcard->i2c_res) break; port += 0x10; } @@ -217,11 +218,13 @@ static int snd_interwave_detect_stb(struct snd_interwave *iwcard, } sprintf(name, "InterWave-%i", card->number); - if ((err = snd_i2c_bus_create(card, name, NULL, &bus)) < 0) + err = snd_i2c_bus_create(card, name, NULL, &bus); + if (err < 0) return err; bus->private_value = port; bus->hw_ops.bit = &snd_interwave_i2c_bit_ops; - if ((err = snd_tea6330t_detect(bus, 0)) < 0) + err = snd_tea6330t_detect(bus, 0); + if (err < 0) return err; *rbus = bus; return 0; @@ -241,14 +244,16 @@ static int snd_interwave_detect(struct snd_interwave *iwcard, int d; snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { + d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET); + if ((d & 0x07) != 0) { snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; } udelay(160); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */ udelay(160); - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { + d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET); + if ((d & 0x07) != 1) { snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; } @@ -493,16 +498,20 @@ static int snd_interwave_mixer(struct snd_wss *chip) #if 0 /* remove mono microphone controls */ strcpy(id1.name, "Mic Playback Switch"); - if ((err = snd_ctl_remove_id(card, &id1)) < 0) + err = snd_ctl_remove_id(card, &id1); + if (err < 0) return err; strcpy(id1.name, "Mic Playback Volume"); - if ((err = snd_ctl_remove_id(card, &id1)) < 0) + err = snd_ctl_remove_id(card, &id1); + if (err < 0) return err; #endif /* add new master and mic controls */ - for (idx = 0; idx < ARRAY_SIZE(snd_interwave_controls); idx++) - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip))) < 0) + for (idx = 0; idx < ARRAY_SIZE(snd_interwave_controls); idx++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip)); + if (err < 0) return err; + } snd_wss_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f); snd_wss_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f); snd_wss_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f); @@ -510,20 +519,24 @@ static int snd_interwave_mixer(struct snd_wss *chip) /* reassign AUXA to SYNTHESIZER */ strcpy(id1.name, "Aux Playback Switch"); strcpy(id2.name, "Synth Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; strcpy(id1.name, "Aux Playback Volume"); strcpy(id2.name, "Synth Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; /* reassign AUXB to CD */ strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; strcpy(id2.name, "CD Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; strcpy(id1.name, "Aux Playback Volume"); strcpy(id2.name, "CD Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; return 0; } @@ -633,18 +646,20 @@ static int snd_interwave_probe(struct snd_card *card, int dev) xdma1 = dma1[dev]; xdma2 = dma2[dev]; - if ((err = snd_gus_create(card, - port[dev], - -xirq, xdma1, xdma2, - 0, 32, - pcm_channels[dev], effect[dev], &gus)) < 0) + err = snd_gus_create(card, + port[dev], + -xirq, xdma1, xdma2, + 0, 32, + pcm_channels[dev], effect[dev], &gus); + if (err < 0) return err; - if ((err = snd_interwave_detect(iwcard, gus, dev + err = snd_interwave_detect(iwcard, gus, dev #ifdef SNDRV_STB - , &i2c_bus + , &i2c_bus #endif - )) < 0) + ); + if (err < 0) return err; iwcard->gus_status_reg = gus->gf1.reg_irqstat; @@ -652,7 +667,8 @@ static int snd_interwave_probe(struct snd_card *card, int dev) snd_interwave_init(dev, gus); snd_interwave_detect_memory(gus); - if ((err = snd_gus_initialize(gus)) < 0) + err = snd_gus_initialize(gus); + if (err < 0) return err; if (request_irq(xirq, snd_interwave_interrupt, 0, @@ -708,19 +724,23 @@ static int snd_interwave_probe(struct snd_card *card, int dev) strcpy(id1.name, "Master Playback Switch"); strcpy(id2.name, id1.name); id2.index = 1; - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; strcpy(id1.name, "Master Playback Volume"); strcpy(id2.name, id1.name); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) return err; - if ((err = snd_tea6330t_update_mixer(card, i2c_bus, 0, 1)) < 0) + err = snd_tea6330t_update_mixer(card, i2c_bus, 0, 1); + if (err < 0) return err; } #endif gus->uart_enable = midi[dev]; - if ((err = snd_gf1_rawmidi_new(gus, 0)) < 0) + err = snd_gf1_rawmidi_new(gus, 0); + if (err < 0) return err; #ifndef SNDRV_STB @@ -758,7 +778,8 @@ static int snd_interwave_isa_probe1(int dev, struct device *devptr) if (err < 0) return err; - if ((err = snd_interwave_probe(card, dev)) < 0) { + err = snd_interwave_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -786,19 +807,22 @@ static int snd_interwave_isa_probe(struct device *pdev, static const int possible_dmas[] = {0, 1, 3, 5, 6, 7, -1}; if (irq[dev] == SNDRV_AUTO_IRQ) { - if ((irq[dev] = snd_legacy_find_free_irq(possible_irqs)) < 0) { + irq[dev] = snd_legacy_find_free_irq(possible_irqs); + if (irq[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); return -EBUSY; } } if (dma1[dev] == SNDRV_AUTO_DMA) { - if ((dma1[dev] = snd_legacy_find_free_dma(possible_dmas)) < 0) { + dma1[dev] = snd_legacy_find_free_dma(possible_dmas); + if (dma1[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free DMA1\n"); return -EBUSY; } } if (dma2[dev] == SNDRV_AUTO_DMA) { - if ((dma2[dev] = snd_legacy_find_free_dma(possible_dmas)) < 0) { + dma2[dev] = snd_legacy_find_free_dma(possible_dmas); + if (dma2[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free DMA2\n"); return -EBUSY; } @@ -853,11 +877,13 @@ static int snd_interwave_pnp_detect(struct pnp_card_link *pcard, if (res < 0) return res; - if ((res = snd_interwave_pnp(dev, card->private_data, pcard, pid)) < 0) { + res = snd_interwave_pnp(dev, card->private_data, pcard, pid); + if (res < 0) { snd_card_free(card); return res; } - if ((res = snd_interwave_probe(card, dev)) < 0) { + res = snd_interwave_probe(card, dev); + if (res < 0) { snd_card_free(card); return res; } diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 9bde11d1cfe8..6f42f869928c 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -208,7 +208,8 @@ static int snd_opl3sa2_detect(struct snd_card *card) char str[2]; port = chip->port; - if ((chip->res_port = request_region(port, 2, "OPL3-SA control")) == NULL) { + chip->res_port = request_region(port, 2, "OPL3-SA control"); + if (!chip->res_port) { snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port); return -EBUSY; } @@ -239,14 +240,16 @@ static int snd_opl3sa2_detect(struct snd_card *card) str[1] = 0; strcat(card->shortname, str); snd_opl3sa2_write(chip, OPL3SA2_MISC, tmp ^ 7); - if ((tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MISC)) != tmp) { + tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MISC); + if (tmp1 != tmp) { snd_printd("OPL3-SA [0x%lx] detect (1) = 0x%x (0x%x)\n", port, tmp, tmp1); return -ENODEV; } /* try if the MIC register is accessible */ tmp = snd_opl3sa2_read(chip, OPL3SA2_MIC); snd_opl3sa2_write(chip, OPL3SA2_MIC, 0x8a); - if (((tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MIC)) & 0x9f) != 0x8a) { + tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MIC); + if ((tmp1 & 0x9f) != 0x8a) { snd_printd("OPL3-SA [0x%lx] detect (2) = 0x%x (0x%x)\n", port, tmp, tmp1); return -ENODEV; } @@ -489,32 +492,38 @@ static int snd_opl3sa2_mixer(struct snd_card *card) /* reassign AUX0 to CD */ strcpy(id1.name, "Aux Playback Switch"); strcpy(id2.name, "CD Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) { snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n"); return err; } strcpy(id1.name, "Aux Playback Volume"); strcpy(id2.name, "CD Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) { snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n"); return err; } /* reassign AUX1 to FM */ strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; strcpy(id2.name, "FM Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) { snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n"); return err; } strcpy(id1.name, "Aux Playback Volume"); strcpy(id2.name, "FM Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) { snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n"); return err; } /* add OPL3SA2 controls */ for (idx = 0; idx < ARRAY_SIZE(snd_opl3sa2_controls); idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_opl3sa2_controls[idx], chip))) < 0) + kctl = snd_ctl_new1(&snd_opl3sa2_controls[idx], chip); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; switch (idx) { case 0: chip->master_switch = kctl; kctl->private_free = snd_opl3sa2_master_free; break; @@ -522,9 +531,11 @@ static int snd_opl3sa2_mixer(struct snd_card *card) } } if (chip->version > 2) { - for (idx = 0; idx < ARRAY_SIZE(snd_opl3sa2_tone_controls); idx++) - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_opl3sa2_tone_controls[idx], chip))) < 0) + for (idx = 0; idx < ARRAY_SIZE(snd_opl3sa2_tone_controls); idx++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_opl3sa2_tone_controls[idx], chip)); + if (err < 0) return err; + } } return 0; } @@ -677,20 +688,24 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev) if (err < 0) return err; if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) { - if ((err = snd_opl3_create(card, fm_port[dev], - fm_port[dev] + 2, - OPL3_HW_OPL3, 0, &opl3)) < 0) + err = snd_opl3_create(card, fm_port[dev], + fm_port[dev] + 2, + OPL3_HW_OPL3, 0, &opl3); + if (err < 0) return err; - if ((err = snd_opl3_timer_new(opl3, 1, 2)) < 0) + err = snd_opl3_timer_new(opl3, 1, 2); + if (err < 0) return err; - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, &chip->synth)) < 0) + err = snd_opl3_hwdep_new(opl3, 0, 1, &chip->synth); + if (err < 0) return err; } if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2, - midi_port[dev], - MPU401_INFO_IRQ_HOOK, -1, - &chip->rmidi)) < 0) + err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2, + midi_port[dev], + MPU401_INFO_IRQ_HOOK, -1, + &chip->rmidi); + if (err < 0) return err; } sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", @@ -721,11 +736,13 @@ static int snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, err = snd_opl3sa2_card_new(&pdev->dev, dev, &card); if (err < 0) return err; - if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) { + err = snd_opl3sa2_pnp(dev, card->private_data, pdev); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3sa2_probe(card, dev)) < 0) { + err = snd_opl3sa2_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -785,11 +802,13 @@ static int snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard, err = snd_opl3sa2_card_new(&pdev->dev, dev, &card); if (err < 0) return err; - if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) { + err = snd_opl3sa2_pnp(dev, card->private_data, pdev); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3sa2_probe(card, dev)) < 0) { + err = snd_opl3sa2_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -865,7 +884,8 @@ static int snd_opl3sa2_isa_probe(struct device *pdev, err = snd_opl3sa2_card_new(pdev, dev, &card); if (err < 0) return err; - if ((err = snd_opl3sa2_probe(card, dev)) < 0) { + err = snd_opl3sa2_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index a510b201143c..e1fb7567fdcc 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -722,35 +722,43 @@ static int snd_miro_mixer(struct snd_card *card, } for (idx = 0; idx < ARRAY_SIZE(snd_miro_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_controls[idx], miro))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_controls[idx], miro)); + if (err < 0) return err; } if ((miro->aci->aci_product == 'A') || (miro->aci->aci_product == 'B')) { /* PCM1/PCM12 with power-amp and Line 2 */ - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro)); + if (err < 0) return err; - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_amp_control[0], miro))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_amp_control[0], miro)); + if (err < 0) return err; } if ((miro->aci->aci_product == 'B') || (miro->aci->aci_product == 'C')) { /* PCM12/PCM20 with mic-preamp */ - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro)); + if (err < 0) return err; - if (miro->aci->aci_version >= 176) - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0) + if (miro->aci->aci_version >= 176) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro)); + if (err < 0) return err; + } } if (miro->aci->aci_product == 'C') { /* PCM20 with radio and 7 band equalizer */ - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro)); + if (err < 0) return err; for (idx = 0; idx < ARRAY_SIZE(snd_miro_eq_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_eq_controls[idx], miro))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_eq_controls[idx], miro)); + if (err < 0) return err; } } @@ -1178,7 +1186,8 @@ static int snd_card_miro_detect(struct snd_card *card, for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) { - if ((err = snd_miro_init(chip, i)) < 0) + err = snd_miro_init(chip, i); + if (err < 0) return err; err = snd_miro_opti_check(chip); diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 08e61d90057b..4bd1dc6707fc 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -970,32 +970,37 @@ static int snd_opti9xx_isa_probe(struct device *devptr, #endif /* CS4231 || OPTi93X */ if (mpu_port == SNDRV_AUTO_PORT) { - if ((mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) { + mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); + if (mpu_port < 0) { snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); return -EBUSY; } } if (irq == SNDRV_AUTO_IRQ) { - if ((irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { + irq = snd_legacy_find_free_irq(possible_irqs); + if (irq < 0) { snd_printk(KERN_ERR "unable to find a free IRQ\n"); return -EBUSY; } } if (mpu_irq == SNDRV_AUTO_IRQ) { - if ((mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) { + mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs); + if (mpu_irq < 0) { snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n"); return -EBUSY; } } if (dma1 == SNDRV_AUTO_DMA) { - if ((dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) { + dma1 = snd_legacy_find_free_dma(possible_dma1s); + if (dma1 < 0) { snd_printk(KERN_ERR "unable to find a free DMA1\n"); return -EBUSY; } } #if defined(CS4231) || defined(OPTi93X) if (dma2 == SNDRV_AUTO_DMA) { - if ((dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4])) < 0) { + dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]); + if (dma2 < 0) { snd_printk(KERN_ERR "unable to find a free DMA2\n"); return -EBUSY; } @@ -1006,11 +1011,13 @@ static int snd_opti9xx_isa_probe(struct device *devptr, if (error < 0) return error; - if ((error = snd_card_opti9xx_detect(card, card->private_data)) < 0) { + error = snd_card_opti9xx_detect(card, card->private_data); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_opti9xx_probe(card)) < 0) { + error = snd_opti9xx_probe(card); + if (error < 0) { snd_card_free(card); return error; } @@ -1111,7 +1118,8 @@ static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, return -ENODEV; } - if ((error = snd_opti9xx_init(chip, hw))) { + error = snd_opti9xx_init(chip, hw); + if (error) { snd_card_free(card); return error; } @@ -1121,7 +1129,8 @@ static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, snd_card_free(card); return error; } - if ((error = snd_opti9xx_probe(card)) < 0) { + error = snd_opti9xx_probe(card); + if (error < 0) { snd_card_free(card); return error; } diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 1c90421a88dc..5e4187940265 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1020,6 +1020,7 @@ static const struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = { static int snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) { + struct snd_kcontrol *kctl; int i, err = 0; if (snd_BUG_ON(!emu || !card)) @@ -1029,10 +1030,11 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) memset(emu->controls, 0, sizeof(emu->controls)); for (i = 0; i < EMU8000_NUM_CONTROLS; i++) { - if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0) { - emu->controls[i] = NULL; + kctl = snd_ctl_new1(mixer_defs[i], emu); + err = snd_ctl_add(card, kctl); + if (err < 0) goto __error; - } + emu->controls[i] = kctl; } return 0; @@ -1095,9 +1097,10 @@ snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, hw->port1 = port; hw->port2 = port + 0x400; hw->port3 = port + 0x800; - if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) || - !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) || - !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) { + hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1"); + hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2"); + hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"); + if (!hw->res_port1 || !hw->res_port2 || !hw->res_port3) { snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3); snd_emu8000_free(hw); return -EBUSY; @@ -1118,12 +1121,14 @@ snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, } snd_emu8000_init_hw(hw); - if ((err = snd_emu8000_create_mixer(card, hw)) < 0) { + err = snd_emu8000_create_mixer(card, hw); + if (err < 0) { snd_emu8000_free(hw); return err; } - if ((err = snd_device_new(card, SNDRV_DEV_CODEC, hw, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_CODEC, hw, &ops); + if (err < 0) { snd_emu8000_free(hw); return err; } diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c index 0cb94cafb4c9..8c1e7f2bfc34 100644 --- a/sound/isa/sb/emu8000_patch.c +++ b/sound/isa/sb/emu8000_patch.c @@ -191,7 +191,8 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, sp->v.truesize = truesize * 2; /* in bytes */ snd_emux_terminate_all(emu->emu); - if ((rc = snd_emu8000_open_dma(emu, EMU8000_RAM_WRITE)) != 0) + rc = snd_emu8000_open_dma(emu, EMU8000_RAM_WRITE); + if (rc) return rc; /* Set the address to start writing at */ diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index 8e8257c574b0..f8d90a1e989b 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -626,7 +626,8 @@ static int emu8k_pcm_prepare(struct snd_pcm_substream *subs) int err, i, ch; snd_emux_terminate_all(rec->emu->emu); - if ((err = emu8k_open_dram_for_pcm(rec->emu, rec->voices)) != 0) + err = emu8k_open_dram_for_pcm(rec->emu, rec->voices); + if (err) return err; rec->dram_opened = 1; @@ -682,7 +683,8 @@ int snd_emu8000_pcm_new(struct snd_card *card, struct snd_emu8000 *emu, int inde struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(card, "Emu8000 PCM", index, 1, 0, &pcm)) < 0) + err = snd_pcm_new(card, "Emu8000 PCM", index, 1, 0, &pcm); + if (err < 0) return err; pcm->private_data = emu; pcm->private_free = snd_emu8000_pcm_free; diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 63ef960abd25..d0f797c02841 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -332,14 +332,9 @@ static int snd_sb16_probe(struct snd_card *card, int dev) xdma8 = dma8[dev]; xdma16 = dma16[dev]; - if ((err = snd_sbdsp_create(card, - port[dev], - xirq, - snd_sb16dsp_interrupt, - xdma8, - xdma16, - SB_HW_AUTO, - &chip)) < 0) + err = snd_sbdsp_create(card, port[dev], xirq, snd_sb16dsp_interrupt, + xdma8, xdma16, SB_HW_AUTO, &chip); + if (err < 0) return err; acard->chip = chip; @@ -348,10 +343,14 @@ static int snd_sb16_probe(struct snd_card *card, int dev) return -ENODEV; } chip->mpu_port = mpu_port[dev]; - if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0) - return err; + if (!is_isapnp_selected(dev)) { + err = snd_sb16dsp_configure(chip); + if (err < 0) + return err; + } - if ((err = snd_sb16dsp_pcm(chip, 0)) < 0) + err = snd_sb16dsp_pcm(chip, 0); + if (err < 0) return err; strcpy(card->driver, @@ -371,10 +370,11 @@ static int snd_sb16_probe(struct snd_card *card, int dev) xdma8 >= 0 ? "&" : "", xdma16); if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, - chip->mpu_port, - MPU401_INFO_IRQ_HOOK, -1, - &chip->rmidi)) < 0) + err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, + chip->mpu_port, + MPU401_INFO_IRQ_HOOK, -1, + &chip->rmidi); + if (err < 0) return err; chip->rmidi_callback = snd_mpu401_uart_interrupt; } @@ -397,12 +397,14 @@ static int snd_sb16_probe(struct snd_card *card, int dev) #else int seqdev = 1; #endif - if ((err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth)) < 0) + err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth); + if (err < 0) return err; } } - if ((err = snd_sbmixer_new(chip)) < 0) + err = snd_sbmixer_new(chip); + if (err < 0) return err; #ifdef CONFIG_SND_SB16_CSP @@ -419,8 +421,9 @@ static int snd_sb16_probe(struct snd_card *card, int dev) #endif #ifdef SNDRV_SBAWE_EMU8000 if (awe_port[dev] > 0) { - if ((err = snd_emu8000_new(card, 1, awe_port[dev], - seq_ports[dev], NULL)) < 0) { + err = snd_emu8000_new(card, 1, awe_port[dev], + seq_ports[dev], NULL); + if (err < 0) { snd_printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", awe_port[dev]); return err; @@ -435,7 +438,8 @@ static int snd_sb16_probe(struct snd_card *card, int dev) (mic_agc[dev] ? 0x00 : 0x01)); spin_unlock_irqrestore(&chip->mixer_lock, flags); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) return err; return 0; @@ -484,7 +488,8 @@ static int snd_sb16_isa_probe1(int dev, struct device *pdev) awe_port[dev] = port[dev] + 0x400; #endif - if ((err = snd_sb16_probe(card, dev)) < 0) { + err = snd_sb16_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -506,19 +511,22 @@ static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev) static const int possible_dmas16[] = {5, 6, 7, -1}; if (irq[dev] == SNDRV_AUTO_IRQ) { - if ((irq[dev] = snd_legacy_find_free_irq(possible_irqs)) < 0) { + irq[dev] = snd_legacy_find_free_irq(possible_irqs); + if (irq[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); return -EBUSY; } } if (dma8[dev] == SNDRV_AUTO_DMA) { - if ((dma8[dev] = snd_legacy_find_free_dma(possible_dmas8)) < 0) { + dma8[dev] = snd_legacy_find_free_dma(possible_dmas8); + if (dma8[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n"); return -EBUSY; } } if (dma16[dev] == SNDRV_AUTO_DMA) { - if ((dma16[dev] = snd_legacy_find_free_dma(possible_dmas16)) < 0) { + dma16[dev] = snd_legacy_find_free_dma(possible_dmas16); + if (dma16[dev] < 0) { snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n"); return -EBUSY; } @@ -591,8 +599,13 @@ static int snd_sb16_pnp_detect(struct pnp_card_link *pcard, res = snd_sb16_card_new(&pcard->card->dev, dev, &card); if (res < 0) return res; - if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 || - (res = snd_sb16_probe(card, dev)) < 0) { + res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid); + if (res < 0) { + snd_card_free(card); + return res; + } + res = snd_sb16_probe(card, dev); + if (res < 0) { snd_card_free(card); return res; } diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 4789345a8fdd..5bbe6695689d 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -112,10 +112,12 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep) if (csp_detect(chip, &version)) return -ENODEV; - if ((err = snd_hwdep_new(chip->card, "SB16-CSP", device, &hw)) < 0) + err = snd_hwdep_new(chip->card, "SB16-CSP", device, &hw); + if (err < 0) return err; - if ((p = kzalloc(sizeof(*p), GFP_KERNEL)) == NULL) { + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) { snd_device_free(chip->card, hw); return -ENOMEM; } @@ -1034,6 +1036,7 @@ static const struct snd_kcontrol_new snd_sb_qsound_space = { static int snd_sb_qsound_build(struct snd_sb_csp * p) { struct snd_card *card; + struct snd_kcontrol *kctl; int err; if (snd_BUG_ON(!p)) @@ -1045,14 +1048,16 @@ static int snd_sb_qsound_build(struct snd_sb_csp * p) spin_lock_init(&p->q_lock); - if ((err = snd_ctl_add(card, p->qsound_switch = snd_ctl_new1(&snd_sb_qsound_switch, p))) < 0) { - p->qsound_switch = NULL; + kctl = snd_ctl_new1(&snd_sb_qsound_switch, p); + err = snd_ctl_add(card, kctl); + if (err < 0) goto __error; - } - if ((err = snd_ctl_add(card, p->qsound_space = snd_ctl_new1(&snd_sb_qsound_space, p))) < 0) { - p->qsound_space = NULL; + p->qsound_switch = kctl; + kctl = snd_ctl_new1(&snd_sb_qsound_space, p); + err = snd_ctl_add(card, kctl); + if (err < 0) goto __error; - } + p->qsound_space = kctl; return 0; @@ -1072,10 +1077,14 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p) card = p->chip->card; down_write(&card->controls_rwsem); - if (p->qsound_switch) + if (p->qsound_switch) { snd_ctl_remove(card, p->qsound_switch); - if (p->qsound_space) + p->qsound_switch = NULL; + } + if (p->qsound_space) { snd_ctl_remove(card, p->qsound_space); + p->qsound_space = NULL; + } up_write(&card->controls_rwsem); /* cancel pending transfer of QSound parameters */ diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index aa4870531023..a9b87e159b2d 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -703,7 +703,8 @@ static int snd_sb16_dma_control_put(struct snd_kcontrol *kcontrol, struct snd_ct unsigned char nval, oval; int change; - if ((nval = ucontrol->value.enumerated.item[0]) > 2) + nval = ucontrol->value.enumerated.item[0]; + if (nval > 2) return -EINVAL; spin_lock_irqsave(&chip->reg_lock, flags); oval = snd_sb16_get_dma_mode(chip); @@ -836,7 +837,8 @@ int snd_sb16dsp_pcm(struct snd_sb *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0) + err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm); + if (err < 0) return err; sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index ed3a87ebe3f4..b08e6e7690c9 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -101,12 +101,10 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); if (port[dev] != SNDRV_AUTO_PORT) { - if ((err = snd_sbdsp_create(card, port[dev], irq[dev], - snd_sb8_interrupt, - dma8[dev], - -1, - SB_HW_AUTO, - &chip)) < 0) + err = snd_sbdsp_create(card, port[dev], irq[dev], + snd_sb8_interrupt, dma8[dev], + -1, SB_HW_AUTO, &chip); + if (err < 0) goto _err; } else { /* auto-probe legacy ports */ @@ -145,32 +143,35 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) goto _err; } - if ((err = snd_sb8dsp_pcm(chip, 0)) < 0) + err = snd_sb8dsp_pcm(chip, 0); + if (err < 0) goto _err; - if ((err = snd_sbmixer_new(chip)) < 0) + err = snd_sbmixer_new(chip); + if (err < 0) goto _err; if (chip->hardware == SB_HW_10 || chip->hardware == SB_HW_20) { - if ((err = snd_opl3_create(card, chip->port + 8, 0, - OPL3_HW_AUTO, 1, - &opl3)) < 0) { + err = snd_opl3_create(card, chip->port + 8, 0, + OPL3_HW_AUTO, 1, &opl3); + if (err < 0) snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx\n", chip->port + 8); - } } else { - if ((err = snd_opl3_create(card, chip->port, chip->port + 2, - OPL3_HW_AUTO, 1, - &opl3)) < 0) { + err = snd_opl3_create(card, chip->port, chip->port + 2, + OPL3_HW_AUTO, 1, &opl3); + if (err < 0) { snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx-0x%lx\n", chip->port, chip->port + 2); } } if (err >= 0) { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) goto _err; } - if ((err = snd_sb8dsp_midi(chip, 0)) < 0) + err = snd_sb8dsp_midi(chip, 0); + if (err < 0) goto _err; strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8"); @@ -180,7 +181,8 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev) chip->port, irq[dev], dma8[dev]); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto _err; dev_set_drvdata(pdev, card); diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 8d01692c4f2a..2ed176a5a574 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -567,7 +567,8 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device) int err; size_t max_prealloc = 64 * 1024; - if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0) + err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm); + if (err < 0) return err; sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index 8c01460539ed..618366d5d984 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -251,7 +251,8 @@ int snd_sb8dsp_midi(struct snd_sb *chip, int device) struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi); + if (err < 0) return err; strcpy(rmidi->name, "SB8 MIDI"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_sb8dsp_midi_output); diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 61ea4078aa95..57121218ed24 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -238,7 +238,8 @@ int snd_sbdsp_create(struct snd_card *card, if (hardware == SB_HW_ALS4000) goto __skip_allocation; - if ((chip->res_port = request_region(port, 16, "SoundBlaster")) == NULL) { + chip->res_port = request_region(port, 16, "SoundBlaster"); + if (!chip->res_port) { snd_printk(KERN_ERR "sb: can't grab port 0x%lx\n", port); snd_sbdsp_free(chip); return -EBUSY; @@ -267,11 +268,13 @@ int snd_sbdsp_create(struct snd_card *card, __skip_allocation: chip->card = card; chip->hardware = hardware; - if ((err = snd_sbdsp_probe(chip)) < 0) { + err = snd_sbdsp_probe(chip); + if (err < 0) { snd_sbdsp_free(chip); return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_sbdsp_free(chip); return err; } diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 5de5506e7e60..fffd681e5bf7 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -485,7 +485,8 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty strscpy(ctl->id.name, name, sizeof(ctl->id.name)); ctl->id.index = index; ctl->private_value = value; - if ((err = snd_ctl_add(chip->card, ctl)) < 0) + err = snd_ctl_add(chip->card, ctl); + if (err < 0) return err; return 0; } @@ -736,33 +737,36 @@ int snd_sbmixer_new(struct snd_sb *chip) return 0; /* no mixer chip on SB1.x */ case SB_HW_20: case SB_HW_201: - if ((err = snd_sbmixer_init(chip, - snd_sb20_controls, - ARRAY_SIZE(snd_sb20_controls), - snd_sb20_init_values, - ARRAY_SIZE(snd_sb20_init_values), - "CTL1335")) < 0) + err = snd_sbmixer_init(chip, + snd_sb20_controls, + ARRAY_SIZE(snd_sb20_controls), + snd_sb20_init_values, + ARRAY_SIZE(snd_sb20_init_values), + "CTL1335"); + if (err < 0) return err; break; case SB_HW_PRO: case SB_HW_JAZZ16: - if ((err = snd_sbmixer_init(chip, - snd_sbpro_controls, - ARRAY_SIZE(snd_sbpro_controls), - snd_sbpro_init_values, - ARRAY_SIZE(snd_sbpro_init_values), - "CTL1345")) < 0) + err = snd_sbmixer_init(chip, + snd_sbpro_controls, + ARRAY_SIZE(snd_sbpro_controls), + snd_sbpro_init_values, + ARRAY_SIZE(snd_sbpro_init_values), + "CTL1345"); + if (err < 0) return err; break; case SB_HW_16: case SB_HW_ALS100: case SB_HW_CS5530: - if ((err = snd_sbmixer_init(chip, - snd_sb16_controls, - ARRAY_SIZE(snd_sb16_controls), - snd_sb16_init_values, - ARRAY_SIZE(snd_sb16_init_values), - "CTL1745")) < 0) + err = snd_sbmixer_init(chip, + snd_sb16_controls, + ARRAY_SIZE(snd_sb16_controls), + snd_sb16_init_values, + ARRAY_SIZE(snd_sb16_init_values), + "CTL1745"); + if (err < 0) return err; break; case SB_HW_ALS4000: @@ -775,12 +779,13 @@ int snd_sbmixer_new(struct snd_sb *chip) "ALS4000"); if (err < 0) return err; - if ((err = snd_sbmixer_init(chip, - snd_als4000_controls, - ARRAY_SIZE(snd_als4000_controls), - snd_als4000_init_values, - ARRAY_SIZE(snd_als4000_init_values), - "ALS4000")) < 0) + err = snd_sbmixer_init(chip, + snd_als4000_controls, + ARRAY_SIZE(snd_als4000_controls), + snd_als4000_init_values, + ARRAY_SIZE(snd_als4000_init_values), + "ALS4000"); + if (err < 0) return err; break; case SB_HW_DT019X: diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index a4437971df2f..dfdeaf7b6bf4 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -555,7 +555,8 @@ static int snd_wavefront_isa_probe(struct device *pdev, err = snd_wavefront_card_new(pdev, dev, &card); if (err < 0) return err; - if ((err = snd_wavefront_probe(card, dev)) < 0) { + err = snd_wavefront_probe(card, dev); + if (err < 0) { snd_card_free(card); return err; } @@ -610,7 +611,8 @@ static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard, } } - if ((res = snd_wavefront_probe(card, dev)) < 0) + res = snd_wavefront_probe(card, dev); + if (res < 0) return res; pnp_set_card_drvdata(pcard, card); diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index a337a86f7a65..72e775ac7ad7 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -239,7 +239,8 @@ static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); - if ((midi = get_wavefront_midi (substream)) == NULL) + midi = get_wavefront_midi(substream); + if (!midi) return -EIO; spin_lock_irqsave (&midi->open, flags); @@ -263,7 +264,8 @@ static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substrea mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); - if ((midi = get_wavefront_midi (substream)) == NULL) + midi = get_wavefront_midi(substream); + if (!midi) return -EIO; spin_lock_irqsave (&midi->open, flags); @@ -287,7 +289,8 @@ static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substrea mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); - if ((midi = get_wavefront_midi (substream)) == NULL) + midi = get_wavefront_midi(substream); + if (!midi) return -EIO; spin_lock_irqsave (&midi->open, flags); @@ -310,7 +313,8 @@ static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substre mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); - if ((midi = get_wavefront_midi (substream)) == NULL) + midi = get_wavefront_midi(substream); + if (!midi) return -EIO; spin_lock_irqsave (&midi->open, flags); @@ -333,9 +337,9 @@ static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *subst mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); - if ((midi = get_wavefront_midi (substream)) == NULL) { + midi = get_wavefront_midi(substream); + if (!midi) return; - } spin_lock_irqsave (&midi->virtual, flags); if (up) { @@ -372,9 +376,9 @@ static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *subs mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); - if ((midi = get_wavefront_midi (substream)) == NULL) { + midi = get_wavefront_midi(substream); + if (!midi) return; - } spin_lock_irqsave (&midi->virtual, flags); if (up) { diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index d6420d224d09..69cbc79fbb71 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -339,7 +339,8 @@ snd_wavefront_cmd (snd_wavefront_t *dev, int c; struct wavefront_command *wfcmd; - if ((wfcmd = wavefront_get_command (cmd)) == NULL) { + wfcmd = wavefront_get_command(cmd); + if (!wfcmd) { snd_printk ("command 0x%x not supported.\n", cmd); return 1; @@ -391,7 +392,8 @@ snd_wavefront_cmd (snd_wavefront_t *dev, for (i = 0; i < wfcmd->read_cnt; i++) { - if ((c = wavefront_read (dev)) == -1) { + c = wavefront_read(dev); + if (c == -1) { DPRINT (WF_DEBUG_IO, "bad read for byte " "%d of 0x%x [%s].\n", i, cmd, wfcmd->action); @@ -401,7 +403,8 @@ snd_wavefront_cmd (snd_wavefront_t *dev, /* Now handle errors. Lots of special cases here */ if (c == 0xff) { - if ((c = wavefront_read (dev)) == -1) { + c = wavefront_read(dev); + if (c == -1) { DPRINT (WF_DEBUG_IO, "bad read for " "error byte at " "read byte %d " @@ -459,9 +462,9 @@ snd_wavefront_cmd (snd_wavefront_t *dev, of the standard value. */ - if ((ack = wavefront_read (dev)) == 0) { + ack = wavefront_read(dev); + if (ack == 0) ack = WF_ACK; - } if (ack != WF_ACK) { if (ack == -1) { @@ -475,7 +478,8 @@ snd_wavefront_cmd (snd_wavefront_t *dev, if (ack == 0xff) { /* explicit error */ - if ((err = wavefront_read (dev)) == -1) { + err = wavefront_read(dev); + if (err == -1) { DPRINT (WF_DEBUG_DATA, "cannot read err " "for 0x%x [%s].\n", @@ -603,9 +607,9 @@ wavefront_delete_sample (snd_wavefront_t *dev, int sample_num) wbuf[0] = sample_num & 0x7f; wbuf[1] = sample_num >> 7; - if ((x = snd_wavefront_cmd (dev, WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) { + x = snd_wavefront_cmd(dev, WFC_DELETE_SAMPLE, NULL, wbuf); + if (!x) dev->sample_status[sample_num] = WF_ST_EMPTY; - } return x; } @@ -691,8 +695,9 @@ wavefront_get_patch_status (snd_wavefront_t *dev) patchnum[0] = i & 0x7f; patchnum[1] = i >> 7; - if ((x = snd_wavefront_cmd (dev, WFC_UPLOAD_PATCH, patchbuf, - patchnum)) == 0) { + x = snd_wavefront_cmd(dev, WFC_UPLOAD_PATCH, patchbuf, + patchnum); + if (x == 0) { dev->patch_status[i] |= WF_SLOT_FILLED; p = (wavefront_patch *) patchbuf; @@ -738,8 +743,9 @@ wavefront_get_program_status (snd_wavefront_t *dev) for (i = 0; i < WF_MAX_PROGRAM; i++) { prognum = i; - if ((x = snd_wavefront_cmd (dev, WFC_UPLOAD_PROGRAM, progbuf, - &prognum)) == 0) { + x = snd_wavefront_cmd(dev, WFC_UPLOAD_PROGRAM, progbuf, + &prognum); + if (x == 0) { dev->prog_status[i] |= WF_SLOT_USED; @@ -894,9 +900,9 @@ wavefront_send_sample (snd_wavefront_t *dev, if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { int x; - if ((x = wavefront_find_free_sample (dev)) < 0) { + x = wavefront_find_free_sample(dev); + if (x < 0) return -ENOMEM; - } snd_printk ("unspecified sample => %d\n", x); header->number = x; } @@ -1137,7 +1143,8 @@ wavefront_send_sample (snd_wavefront_t *dev, nothing to do with DMA at all. */ - if ((dma_ack = wavefront_read (dev)) != WF_DMA_ACK) { + dma_ack = wavefront_read(dev); + if (dma_ack != WF_DMA_ACK) { if (dma_ack == -1) { snd_printk ("upload sample " "DMA ack timeout\n"); @@ -1282,14 +1289,16 @@ wavefront_fetch_multisample (snd_wavefront_t *dev, char d[2]; int val; - if ((val = wavefront_read (dev)) == -1) { + val = wavefront_read(dev); + if (val == -1) { snd_printk ("upload multisample failed " "during sample loop.\n"); return -EIO; } d[0] = val; - if ((val = wavefront_read (dev)) == -1) { + val = wavefront_read(dev); + if (val == -1) { snd_printk ("upload multisample failed " "during sample loop.\n"); return -EIO; @@ -1910,7 +1919,8 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev) goto gone_bad; } - if ((hwv[0] = wavefront_read (dev)) == -1) { + hwv[0] = wavefront_read(dev); + if (hwv[0] == -1) { snd_printk ("board not responding correctly.\n"); goto gone_bad; } @@ -1921,7 +1931,8 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev) and tell us about it either way. */ - if ((hwv[0] = wavefront_read (dev)) == -1) { + hwv[0] = wavefront_read(dev); + if (hwv[0] == -1) { snd_printk ("on-board RAM test failed " "(bad error code).\n"); } else { @@ -1934,7 +1945,8 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev) /* We're OK, just get the next byte of the HW version response */ - if ((hwv[1] = wavefront_read (dev)) == -1) { + hwv[1] = wavefront_read(dev); + if (hwv[1] == -1) { snd_printk ("incorrect h/w response.\n"); goto gone_bad; } @@ -2079,9 +2091,9 @@ wavefront_do_reset (snd_wavefront_t *dev) about it. */ - if ((dev->freemem = wavefront_freemem (dev)) < 0) { + dev->freemem = wavefront_freemem(dev); + if (dev->freemem < 0) goto gone_bad; - } snd_printk ("available DRAM %dk\n", dev->freemem / 1024); diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index ea5d3cdfe4e4..743e0f05e335 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1493,7 +1493,8 @@ static int snd_wss_playback_open(struct snd_pcm_substream *substream) snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max); if (chip->claim_dma) { - if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0) + err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1); + if (err < 0) return err; } @@ -1533,7 +1534,8 @@ static int snd_wss_capture_open(struct snd_pcm_substream *substream) snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max); if (chip->claim_dma) { - if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0) + err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2); + if (err < 0) return err; } @@ -1934,7 +1936,8 @@ int snd_wss_timer(struct snd_wss *chip, int device) tid.card = chip->card->number; tid.device = device; tid.subdevice = 0; - if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0) + err = snd_timer_new(chip->card, "CS4231", &tid, &timer); + if (err < 0) return err; strcpy(timer->name, snd_wss_chip_id(chip)); timer->private_data = chip; diff --git a/sound/mips/snd-n64.c b/sound/mips/snd-n64.c index e35e93157755..463a6fe589eb 100644 --- a/sound/mips/snd-n64.c +++ b/sound/mips/snd-n64.c @@ -338,6 +338,10 @@ static int __init n64audio_probe(struct platform_device *pdev) strcpy(card->longname, "N64 Audio"); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + err = -EINVAL; + goto fail_dma_alloc; + } if (devm_request_irq(&pdev->dev, res->start, n64audio_isr, IRQF_SHARED, "N64 Audio", priv)) { err = -EBUSY; diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 49679aa8631d..0c95828ac0b1 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -999,11 +999,9 @@ static int sq_ioctl(struct file *file, u_int cmd, u_long arg) case SNDCTL_DSP_RESET: sq_reset(); return 0; - break ; case SNDCTL_DSP_GETFMTS: fmt = dmasound.mach.hardware_afmts ; /* this is what OSS says.. */ return IOCTL_OUT(arg, fmt); - break ; case SNDCTL_DSP_GETBLKSIZE: /* this should tell the caller about bytes that the app can read/write - the app doesn't care about our internal buffers. @@ -1020,7 +1018,6 @@ static int sq_ioctl(struct file *file, u_int cmd, u_long arg) size = write_sq.user_frag_size ; } return IOCTL_OUT(arg, size); - break ; case SNDCTL_DSP_POST: /* all we are going to do is to tell the LL that any partial frags can be queued for output. @@ -1044,7 +1041,6 @@ static int sq_ioctl(struct file *file, u_int cmd, u_long arg) if (file->f_mode & shared_resource_owner) shared_resources_initialised = 0 ; return result ; - break ; case SOUND_PCM_READ_RATE: return IOCTL_OUT(arg, dmasound.soft.speed); case SNDCTL_DSP_SPEED: @@ -1123,7 +1119,6 @@ static int sq_ioctl(struct file *file, u_int cmd, u_long arg) the value is 'random' and that the user _must_ check the actual frags values using SNDCTL_DSP_GETBLKSIZE or similar */ return IOCTL_OUT(arg, data); - break ; case SNDCTL_DSP_GETOSPACE: /* */ @@ -1234,31 +1229,22 @@ static char *get_afmt_string(int afmt) switch(afmt) { case AFMT_MU_LAW: return "mu-law"; - break; case AFMT_A_LAW: return "A-law"; - break; case AFMT_U8: return "unsigned 8 bit"; - break; case AFMT_S8: return "signed 8 bit"; - break; case AFMT_S16_BE: return "signed 16 bit BE"; - break; case AFMT_U16_BE: return "unsigned 16 bit BE"; - break; case AFMT_S16_LE: return "signed 16 bit LE"; - break; case AFMT_U16_LE: return "unsigned 16 bit LE"; - break; case 0: return "format not set" ; - break ; default: break ; } diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index f2ca0a701987..1440db8b4177 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -915,10 +915,9 @@ snd_harmony_create(struct snd_card *card, spin_lock_init(&h->mixer_lock); spin_lock_init(&h->lock); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - h, &ops)) < 0) { - goto free_and_ret; - } + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, h, &ops); + if (err < 0) + goto free_and_ret; *rchip = h; diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 012a7ee849e8..01f296d524ce 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1286,15 +1286,17 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, if (snd_ac97_try_bit(ac97, reg, 15)) { sprintf(name, "%s Switch", pfx); - if ((err = snd_ac97_cmute_new_stereo(card, name, reg, - check_stereo, check_amix, - ac97)) < 0) + err = snd_ac97_cmute_new_stereo(card, name, reg, + check_stereo, check_amix, + ac97); + if (err < 0) return err; } check_volume_resolution(ac97, reg, &lo_max, &hi_max); if (lo_max) { sprintf(name, "%s Volume", pfx); - if ((err = snd_ac97_cvol_new(card, name, reg, lo_max, hi_max, ac97)) < 0) + err = snd_ac97_cvol_new(card, name, reg, lo_max, hi_max, ac97); + if (err < 0) return err; } return 0; @@ -1333,9 +1335,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) /* build center controls */ if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) && !(ac97->flags & AC97_AD_MULTI)) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97)); + if (err < 0) return err; - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97))) < 0) + err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97)); + if (err < 0) return err; snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max); kctl->private_value &= ~(0xff << 16); @@ -1347,9 +1351,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) /* build LFE controls */ if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1)) && !(ac97->flags & AC97_AD_MULTI)) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97)); + if (err < 0) return err; - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97))) < 0) + err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97)); + if (err < 0) return err; snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max); kctl->private_value &= ~(0xff << 16); @@ -1362,23 +1368,26 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) && !(ac97->flags & AC97_AD_MULTI)) { /* Surround Master (0x38) is with stereo mutes */ - if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", - AC97_SURROUND_MASTER, 1, 0, - ac97)) < 0) + err = snd_ac97_cmix_new_stereo(card, "Surround Playback", + AC97_SURROUND_MASTER, 1, 0, + ac97); + if (err < 0) return err; } /* build headphone controls */ if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { - if ((err = snd_ac97_cmix_new(card, "Headphone Playback", - AC97_HEADPHONE, 0, ac97)) < 0) + err = snd_ac97_cmix_new(card, "Headphone Playback", + AC97_HEADPHONE, 0, ac97); + if (err < 0) return err; } /* build master mono controls */ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { - if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", - AC97_MASTER_MONO, 0, ac97)) < 0) + err = snd_ac97_cmix_new(card, "Master Mono Playback", + AC97_MASTER_MONO, 0, ac97); + if (err < 0) return err; } @@ -1386,7 +1395,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) if (!(ac97->flags & AC97_HAS_NO_TONE)) { if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) { for (idx = 0; idx < 2; idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0) + kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; if (ac97->id == AC97_ID_YMF743 || ac97->id == AC97_ID_YMF753) { @@ -1402,9 +1413,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) if (!(ac97->flags & AC97_HAS_NO_PC_BEEP) && ((ac97->flags & AC97_HAS_PC_BEEP) || snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { - for (idx = 0; idx < 2; idx++) - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) + for (idx = 0; idx < 2; idx++) { + kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; + } set_tlv_db_scale(kctl, db_scale_4bit); snd_ac97_write_cache( ac97, @@ -1417,8 +1431,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) /* build Phone controls */ if (!(ac97->flags & AC97_HAS_NO_PHONE)) { if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { - if ((err = snd_ac97_cmix_new(card, "Phone Playback", - AC97_PHONE, 1, ac97)) < 0) + err = snd_ac97_cmix_new(card, "Phone Playback", + AC97_PHONE, 1, ac97); + if (err < 0) return err; } } @@ -1426,26 +1441,30 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) /* build MIC controls */ if (!(ac97->flags & AC97_HAS_NO_MIC)) { if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { - if ((err = snd_ac97_cmix_new(card, "Mic Playback", - AC97_MIC, 1, ac97)) < 0) + err = snd_ac97_cmix_new(card, "Mic Playback", + AC97_MIC, 1, ac97); + if (err < 0) return err; - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97)); + if (err < 0) return err; } } /* build Line controls */ if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { - if ((err = snd_ac97_cmix_new(card, "Line Playback", - AC97_LINE, 1, ac97)) < 0) + err = snd_ac97_cmix_new(card, "Line Playback", + AC97_LINE, 1, ac97); + if (err < 0) return err; } /* build CD controls */ if (!(ac97->flags & AC97_HAS_NO_CD)) { if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { - if ((err = snd_ac97_cmix_new(card, "CD Playback", - AC97_CD, 1, ac97)) < 0) + err = snd_ac97_cmix_new(card, "CD Playback", + AC97_CD, 1, ac97); + if (err < 0) return err; } } @@ -1453,8 +1472,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) /* build Video controls */ if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { - if ((err = snd_ac97_cmix_new(card, "Video Playback", - AC97_VIDEO, 1, ac97)) < 0) + err = snd_ac97_cmix_new(card, "Video Playback", + AC97_VIDEO, 1, ac97); + if (err < 0) return err; } } @@ -1462,8 +1482,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) /* build Aux controls */ if (!(ac97->flags & AC97_HAS_NO_AUX)) { if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { - if ((err = snd_ac97_cmix_new(card, "Aux Playback", - AC97_AUX, 1, ac97)) < 0) + err = snd_ac97_cmix_new(card, "Aux Playback", + AC97_AUX, 1, ac97); + if (err < 0) return err; } } @@ -1475,26 +1496,38 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) init_val = 0x9f9f; else init_val = 0x9f1f; - for (idx = 0; idx < 2; idx++) - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) + for (idx = 0; idx < 2; idx++) { + kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; + } set_tlv_db_scale(kctl, db_scale_5bit); ac97->spec.ad18xx.pcmreg[0] = init_val; if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { - for (idx = 0; idx < 2; idx++) - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) + for (idx = 0; idx < 2; idx++) { + kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; + } set_tlv_db_scale(kctl, db_scale_5bit); ac97->spec.ad18xx.pcmreg[1] = init_val; } if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { - for (idx = 0; idx < 2; idx++) - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) + for (idx = 0; idx < 2; idx++) { + kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; + } set_tlv_db_scale(kctl, db_scale_5bit); - for (idx = 0; idx < 2; idx++) - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0) + for (idx = 0; idx < 2; idx++) { + kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; + } set_tlv_db_scale(kctl, db_scale_5bit); ac97->spec.ad18xx.pcmreg[2] = init_val; } @@ -1515,7 +1548,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) /* build Capture controls */ if (!(ac97->flags & AC97_HAS_NO_REC_GAIN)) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97)); + if (err < 0) return err; if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { err = snd_ac97_cmute_new(card, "Capture Switch", @@ -1523,7 +1557,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) if (err < 0) return err; } - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) + kctl = snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; set_tlv_db_scale(kctl, db_scale_rec_gain); snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); @@ -1531,52 +1567,62 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) } /* build MIC Capture controls */ if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { - for (idx = 0; idx < 2; idx++) - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0) + for (idx = 0; idx < 2; idx++) { + kctl = snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; + } set_tlv_db_scale(kctl, db_scale_rec_gain); snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000); } /* build PCM out path & mute control */ if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 15)) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_PCM_OUT], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_PCM_OUT], ac97)); + if (err < 0) return err; } /* build Simulated Stereo Enhancement control */ if (ac97->caps & AC97_BC_SIM_STEREO) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_STEREO_ENHANCEMENT], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_STEREO_ENHANCEMENT], ac97)); + if (err < 0) return err; } /* build 3D Stereo Enhancement control */ if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 13)) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_3D], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_3D], ac97)); + if (err < 0) return err; } /* build Loudness control */ if (ac97->caps & AC97_BC_LOUDNESS) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOUDNESS], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOUDNESS], ac97)); + if (err < 0) return err; } /* build Mono output select control */ if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 9)) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MONO], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MONO], ac97)); + if (err < 0) return err; } /* build Mic select control */ if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 8)) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MIC], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MIC], ac97)); + if (err < 0) return err; } /* build ADC/DAC loopback control */ if (enable_loopback && snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 7)) { - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOOPBACK], ac97))) < 0) + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOOPBACK], ac97)); + if (err < 0) return err; } @@ -1592,11 +1638,15 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) snd_ac97_write(ac97, AC97_3D_CONTROL, val); val = snd_ac97_read(ac97, AC97_3D_CONTROL); val = val == 0x0606; - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; if (val) kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16); - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[1], ac97))) < 0) + kctl = snd_ac97_cnew(&snd_ac97_controls_3d[1], ac97); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; if (val) kctl->private_value = AC97_3D_CONTROL | (1 << 8) | (7 << 16); @@ -1613,14 +1663,18 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) { if (ac97->build_ops->build_spdif) { - if ((err = ac97->build_ops->build_spdif(ac97)) < 0) + err = ac97->build_ops->build_spdif(ac97); + if (err < 0) return err; } else { - for (idx = 0; idx < 5; idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) + for (idx = 0; idx < 5; idx++) { + err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97)); + if (err < 0) return err; + } if (ac97->build_ops->build_post_spdif) { - if ((err = ac97->build_ops->build_post_spdif(ac97)) < 0) + err = ac97->build_ops->build_post_spdif(ac97); + if (err < 0) return err; } /* set default PCM S/PDIF params */ @@ -1632,9 +1686,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) } /* build chip specific controls */ - if (ac97->build_ops->build_specific) - if ((err = ac97->build_ops->build_specific(ac97)) < 0) + if (ac97->build_ops->build_specific) { + err = ac97->build_ops->build_specific(ac97); + if (err < 0) return err; + } if (snd_ac97_try_bit(ac97, AC97_POWERDOWN, 15)) { kctl = snd_ac97_cnew(&snd_ac97_control_eapd, ac97); @@ -1642,7 +1698,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) return -ENOMEM; if (ac97->scaps & AC97_SCAP_INV_EAPD) set_inv_eapd(ac97, kctl); - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) return err; } @@ -1664,14 +1721,18 @@ static int snd_ac97_modem_build(struct snd_card *card, struct snd_ac97 * ac97) snd_ac97_write(ac97, AC97_MISC_AFE, 0x0); /* build modem switches */ - for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++) - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ac97_controls_modem_switches[idx], ac97))) < 0) + for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_ac97_controls_modem_switches[idx], ac97)); + if (err < 0) return err; + } /* build chip specific controls */ - if (ac97->build_ops->build_specific) - if ((err = ac97->build_ops->build_specific(ac97)) < 0) + if (ac97->build_ops->build_specific) { + err = ac97->build_ops->build_specific(ac97); + if (err < 0) return err; + } return 0; } @@ -1916,7 +1977,8 @@ int snd_ac97_bus(struct snd_card *card, int num, bus->clock = 48000; spin_lock_init(&bus->bus_lock); snd_ac97_bus_proc_init(bus); - if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); + if (err < 0) { snd_ac97_bus_free(bus); return err; } @@ -1944,7 +2006,8 @@ static int snd_ac97_dev_register(struct snd_device *device) dev_set_name(&ac97->dev, "%d-%d:%s", ac97->bus->card->number, ac97->num, snd_ac97_get_short_name(ac97)); - if ((err = device_register(&ac97->dev)) < 0) { + err = device_register(&ac97->dev); + if (err < 0) { ac97_err(ac97, "Can't register ac97 bus\n"); ac97->dev.bus = NULL; return err; @@ -2095,7 +2158,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) { /* test if we can write to the record gain volume register */ snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a06); - if (((err = snd_ac97_read(ac97, AC97_REC_GAIN)) & 0x7fff) == 0x0a06) + err = snd_ac97_read(ac97, AC97_REC_GAIN); + if ((err & 0x7fff) == 0x0a06) ac97->scaps |= AC97_SCAP_AUDIO; } if (ac97->scaps & AC97_SCAP_AUDIO) { @@ -2248,7 +2312,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, } } sprintf(comp, "AC97a:%08x", ac97->id); - if ((err = snd_component_add(card, comp)) < 0) { + err = snd_component_add(card, comp); + if (err < 0) { snd_ac97_free(ac97); return err; } @@ -2268,7 +2333,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, } } sprintf(comp, "AC97m:%08x", ac97->id); - if ((err = snd_component_add(card, comp)) < 0) { + err = snd_component_add(card, comp); + if (err < 0) { snd_ac97_free(ac97); return err; } @@ -2280,7 +2346,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, if (ac97_is_audio(ac97)) update_power_regs(ac97); snd_ac97_proc_init(ac97); - if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops); + if (err < 0) { snd_ac97_free(ac97); return err; } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1627a74baf3c..025c1666c1fc 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -29,9 +29,11 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro { int idx, err; - for (idx = 0; idx < count; idx++) - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&controls[idx], ac97))) < 0) + for (idx = 0; idx < count; idx++) { + err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&controls[idx], ac97)); + if (err < 0) return err; + } return 0; } @@ -416,7 +418,8 @@ static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) { int err; - if ((err = patch_build_controls(ac97, snd_ac97_ymf753_controls_spdif, ARRAY_SIZE(snd_ac97_ymf753_controls_spdif))) < 0) + err = patch_build_controls(ac97, snd_ac97_ymf753_controls_spdif, ARRAY_SIZE(snd_ac97_ymf753_controls_spdif)); + if (err < 0) return err; return 0; } @@ -461,7 +464,8 @@ static int patch_wolfson_wm9703_specific(struct snd_ac97 * ac97) int err, i; for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) { - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0) + err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97)); + if (err < 0) return err; } snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808); @@ -491,7 +495,8 @@ static int patch_wolfson_wm9704_specific(struct snd_ac97 * ac97) { int err, i; for (i = 0; i < ARRAY_SIZE(wm9704_snd_ac97_controls); i++) { - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9704_snd_ac97_controls[i], ac97))) < 0) + err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9704_snd_ac97_controls[i], ac97)); + if (err < 0) return err; } /* patch for DVD noise */ @@ -631,7 +636,8 @@ static int patch_wolfson_wm9711_specific(struct snd_ac97 * ac97) int err, i; for (i = 0; i < ARRAY_SIZE(wm9711_snd_ac97_controls); i++) { - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9711_snd_ac97_controls[i], ac97))) < 0) + err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9711_snd_ac97_controls[i], ac97)); + if (err < 0) return err; } snd_ac97_write_cache(ac97, AC97_CODEC_CLASS_REV, 0x0808); @@ -798,7 +804,8 @@ static int patch_wolfson_wm9713_3d (struct snd_ac97 * ac97) int err, i; for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_3d); i++) { - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_3d[i], ac97))) < 0) + err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_3d[i], ac97)); + if (err < 0) return err; } return 0; @@ -809,7 +816,8 @@ static int patch_wolfson_wm9713_specific(struct snd_ac97 * ac97) int err, i; for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls); i++) { - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls[i], ac97))) < 0) + err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls[i], ac97)); + if (err < 0) return err; } snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808); @@ -883,7 +891,8 @@ static int patch_sigmatel_stac9700_3d(struct snd_ac97 * ac97) struct snd_kcontrol *kctl; int err; - if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97)); + if (err < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0); @@ -896,11 +905,15 @@ static int patch_sigmatel_stac9708_3d(struct snd_ac97 * ac97) struct snd_kcontrol *kctl; int err; - if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97); + err = snd_ctl_add(ac97->bus->card, kctl); + if (err < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 0, 3, 0); - if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97); + err = snd_ctl_add(ac97->bus->card, kctl); + if (err < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0); @@ -927,18 +940,26 @@ static int patch_sigmatel_stac97xx_specific(struct snd_ac97 * ac97) int err; snd_ac97_write_cache(ac97, AC97_SIGMATEL_ANALOG, snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) & ~0x0003); - if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1)) - if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[0], 1)) < 0) + if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1)) { + err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[0], 1); + if (err < 0) return err; - if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0)) - if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[1], 1)) < 0) + } + if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0)) { + err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[1], 1); + if (err < 0) return err; - if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 2)) - if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_4speaker, 1)) < 0) + } + if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 2)) { + err = patch_build_controls(ac97, &snd_ac97_sigmatel_4speaker, 1); + if (err < 0) return err; - if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 3)) - if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_phaseinvert, 1)) < 0) + } + if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 3)) { + err = patch_build_controls(ac97, &snd_ac97_sigmatel_phaseinvert, 1); + if (err < 0) return err; + } return 0; } @@ -984,7 +1005,8 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97) snd_ac97_remove_ctl(ac97, "PCM Out Path & Mute", NULL); snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback"); - if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0) + err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1); + if (err < 0) return err; return patch_sigmatel_stac97xx_specific(ac97); } @@ -1262,14 +1284,17 @@ static int patch_cirrus_build_spdif(struct snd_ac97 * ac97) int err; /* con mask, pro mask, default */ - if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0) + err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3); + if (err < 0) return err; /* switch, spsa */ - if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1)) < 0) + err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1); + if (err < 0) return err; switch (ac97->id & AC97_ID_CS_MASK) { case AC97_ID_CS4205: - if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[1], 1)) < 0) + err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[1], 1); + if (err < 0) return err; break; } @@ -1324,10 +1349,12 @@ static int patch_conexant_build_spdif(struct snd_ac97 * ac97) int err; /* con mask, pro mask, default */ - if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0) + err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3); + if (err < 0) return err; /* switch */ - if ((err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1)) < 0) + err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1); + if (err < 0) return err; /* set default PCM S/PDIF params */ /* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ @@ -1592,7 +1619,8 @@ static int patch_ad1885_specific(struct snd_ac97 * ac97) { int err; - if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) + err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885)); + if (err < 0) return err; reset_tlv(ac97, "Headphone Playback Volume", db_scale_6bit_6db_max); @@ -1875,7 +1903,8 @@ static int patch_ad1981b_specific(struct snd_ac97 *ac97) { int err; - if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) + err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); + if (err < 0) return err; if (check_list(ac97, ad1981_jacks_denylist)) return 0; @@ -2060,7 +2089,8 @@ static int patch_ad1980_specific(struct snd_ac97 *ac97) { int err; - if ((err = patch_ad1888_specific(ac97)) < 0) + err = patch_ad1888_specific(ac97); + if (err < 0) return err; return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); } @@ -2168,7 +2198,8 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97) "Master Surround Playback"); snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback"); - if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) + err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); + if (err < 0) return err; return patch_build_controls(ac97, snd_ac97_ad1985_controls, @@ -2460,7 +2491,8 @@ static int patch_ad1986_specific(struct snd_ac97 *ac97) { int err; - if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) + err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); + if (err < 0) return err; return patch_build_controls(ac97, snd_ac97_ad1986_controls, @@ -2582,10 +2614,12 @@ static int patch_alc650_specific(struct snd_ac97 * ac97) { int err; - if ((err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650))) < 0) + err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650)); + if (err < 0) return err; if (ac97->ext_id & AC97_EI_SPDIF) { - if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) + err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650)); + if (err < 0) return err; } if (ac97->id != AC97_ID_ALC650F) @@ -2735,10 +2769,12 @@ static int patch_alc655_specific(struct snd_ac97 * ac97) { int err; - if ((err = patch_build_controls(ac97, snd_ac97_controls_alc655, ARRAY_SIZE(snd_ac97_controls_alc655))) < 0) + err = patch_build_controls(ac97, snd_ac97_controls_alc655, ARRAY_SIZE(snd_ac97_controls_alc655)); + if (err < 0) return err; if (ac97->ext_id & AC97_EI_SPDIF) { - if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0) + err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655)); + if (err < 0) return err; } return 0; @@ -2847,10 +2883,12 @@ static int patch_alc850_specific(struct snd_ac97 *ac97) { int err; - if ((err = patch_build_controls(ac97, snd_ac97_controls_alc850, ARRAY_SIZE(snd_ac97_controls_alc850))) < 0) + err = patch_build_controls(ac97, snd_ac97_controls_alc850, ARRAY_SIZE(snd_ac97_controls_alc850)); + if (err < 0) return err; if (ac97->ext_id & AC97_EI_SPDIF) { - if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0) + err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655)); + if (err < 0) return err; } return 0; @@ -3437,10 +3475,13 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97) struct snd_kcontrol *kctl; int err; - if (snd_ac97_try_bit(ac97, 0x5a, 9)) - if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[0], 1)) < 0) + if (snd_ac97_try_bit(ac97, 0x5a, 9)) { + err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[0], 1); + if (err < 0) return err; - if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) + } + err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1); + if (err < 0) return err; /* There is already a misnamed master switch. Rename it. */ @@ -3810,9 +3851,11 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_it2646[] = { static int patch_it2646_specific(struct snd_ac97 * ac97) { int err; - if ((err = patch_build_controls(ac97, snd_ac97_controls_it2646, ARRAY_SIZE(snd_ac97_controls_it2646))) < 0) + err = patch_build_controls(ac97, snd_ac97_controls_it2646, ARRAY_SIZE(snd_ac97_controls_it2646)); + if (err < 0) return err; - if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_it2646, ARRAY_SIZE(snd_ac97_spdif_controls_it2646))) < 0) + err = patch_build_controls(ac97, snd_ac97_spdif_controls_it2646, ARRAY_SIZE(snd_ac97_spdif_controls_it2646)); + if (err < 0) return err; return 0; } @@ -3845,9 +3888,11 @@ AC97_DOUBLE("Modem Speaker Volume", 0x5c, 14, 12, 3, 1) static int patch_si3036_specific(struct snd_ac97 * ac97) { int idx, err; - for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_si3036); idx++) - if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_si3036[idx], ac97))) < 0) + for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_si3036); idx++) { + err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_si3036[idx], ac97)); + if (err < 0) return err; + } return 0; } @@ -3912,9 +3957,11 @@ AC97_SINGLE("Smart Low Power Mode", 0x6c, 4, 3, 0), static int patch_ucb1400_specific(struct snd_ac97 * ac97) { int idx, err; - for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++) - if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97))) < 0) + for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++) { + err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97)); + if (err < 0) return err; + } return 0; } diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 4520022801d9..5c78951dd596 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -852,7 +852,8 @@ snd_ad1889_create(struct snd_card *card, *rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; /* check PCI availability (32bit DMA) */ @@ -863,7 +864,8 @@ snd_ad1889_create(struct snd_card *card, } /* allocate chip specific data with zero-filled memory */ - if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) { + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { pci_disable_device(pci); return -ENOMEM; } @@ -874,7 +876,8 @@ snd_ad1889_create(struct snd_card *card, chip->irq = -1; /* (1) PCI resource allocation */ - if ((err = pci_request_regions(pci, card->driver)) < 0) + err = pci_request_regions(pci, card->driver); + if (err < 0) goto free_and_ret; chip->bar = pci_resource_start(pci, 0); @@ -900,12 +903,14 @@ snd_ad1889_create(struct snd_card *card, card->sync_irq = chip->irq; /* (2) initialization of the chip hardware */ - if ((err = snd_ad1889_init(chip)) < 0) { + err = snd_ad1889_init(chip); + if (err < 0) { snd_ad1889_free(chip); return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_ad1889_free(chip); return err; } diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c index e0a81f99f79a..6af88e7b86f8 100644 --- a/sound/pci/ak4531_codec.c +++ b/sound/pci/ak4531_codec.c @@ -384,7 +384,8 @@ int snd_ak4531_mixer(struct snd_card *card, return -ENOMEM; *ak4531 = *_ak4531; mutex_init(&ak4531->reg_mutex); - if ((err = snd_component_add(card, "AK4531")) < 0) { + err = snd_component_add(card, "AK4531"); + if (err < 0) { snd_ak4531_free(ak4531); return err; } @@ -398,13 +399,15 @@ int snd_ak4531_mixer(struct snd_card *card, ak4531->write(ak4531, idx, ak4531->regs[idx] = snd_ak4531_initial_map[idx]); /* recording source is mixer */ } for (idx = 0; idx < ARRAY_SIZE(snd_ak4531_controls); idx++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ak4531_controls[idx], ak4531))) < 0) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_ak4531_controls[idx], ak4531)); + if (err < 0) { snd_ak4531_free(ak4531); return err; } } snd_ak4531_proc_init(card, ak4531); - if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ak4531, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_CODEC, ak4531, &ops); + if (err < 0) { snd_ak4531_free(ak4531); return err; } diff --git a/sound/pci/als300.c b/sound/pci/als300.c index bd4fd09e982b..668008fc21f7 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -298,7 +298,8 @@ static int snd_als300_ac97(struct snd_als300 *chip) .read = snd_als300_ac97_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus); + if (err < 0) return err; memset(&ac97, 0, sizeof(ac97)); @@ -621,7 +622,8 @@ static int snd_als300_create(struct snd_card *card, }; *rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) { @@ -643,7 +645,8 @@ static int snd_als300_create(struct snd_card *card, chip->chip_type = chip_type; spin_lock_init(&chip->reg_lock); - if ((err = pci_request_regions(pci, "ALS300")) < 0) { + err = pci_request_regions(pci, "ALS300"); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -673,14 +676,15 @@ static int snd_als300_create(struct snd_card *card, return err; } - if ((err = snd_als300_new_pcm(chip)) < 0) { + err = snd_als300_new_pcm(chip); + if (err < 0) { dev_err(card->dev, "Could not create PCM\n"); snd_als300_free(chip); return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_als300_free(chip); return err; } @@ -741,7 +745,8 @@ static int snd_als300_probe(struct pci_dev *pci, chip_type = pci_id->driver_data; - if ((err = snd_als300_create(card, pci, chip_type, &chip)) < 0) { + err = snd_als300_create(card, pci, chip_type, &chip); + if (err < 0) { snd_card_free(card); return err; } @@ -758,7 +763,8 @@ static int snd_als300_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->port, chip->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 139ac2a3a0ef..509f317ee682 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -832,9 +832,10 @@ static int snd_card_als4000_probe(struct pci_dev *pci, } /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) { + err = pci_enable_device(pci); + if (err < 0) return err; - } + /* check, if we can restrict PCI DMA transfers to 24 bits */ if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) { dev_err(&pci->dev, "architecture does not support 24bit PCI busmaster DMA\n"); @@ -842,7 +843,8 @@ static int snd_card_als4000_probe(struct pci_dev *pci, return -ENXIO; } - if ((err = pci_request_regions(pci, "ALS4000")) < 0) { + err = pci_request_regions(pci, "ALS4000"); + if (err < 0) { pci_disable_device(pci); return err; } @@ -869,17 +871,17 @@ static int snd_card_als4000_probe(struct pci_dev *pci, /* disable all legacy ISA stuff */ snd_als4000_set_addr(acard->iobase, 0, 0, 0, 0); - if ((err = snd_sbdsp_create(card, - iobase + ALS4K_IOB_10_ADLIB_ADDR0, - pci->irq, + err = snd_sbdsp_create(card, + iobase + ALS4K_IOB_10_ADLIB_ADDR0, + pci->irq, /* internally registered as IRQF_SHARED in case of ALS4000 SB */ - snd_als4000_interrupt, - -1, - -1, - SB_HW_ALS4000, - &chip)) < 0) { + snd_als4000_interrupt, + -1, + -1, + SB_HW_ALS4000, + &chip); + if (err < 0) goto out_err; - } acard->chip = chip; chip->pci = pci; @@ -892,11 +894,12 @@ static int snd_card_als4000_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->alt_port, chip->irq); - if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, - iobase + ALS4K_IOB_30_MIDI_DATA, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi)) < 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_ALS4000, + iobase + ALS4K_IOB_30_MIDI_DATA, + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi); + if (err < 0) { dev_err(&pci->dev, "no MPU-401 device at 0x%lx?\n", iobase + ALS4K_IOB_30_MIDI_DATA); goto out_err; @@ -907,12 +910,13 @@ static int snd_card_als4000_probe(struct pci_dev *pci, * however there doesn't seem to be an ALSA API for this... * SPECS_PAGE: 21 */ - if ((err = snd_als4000_pcm(chip, 0)) < 0) { + err = snd_als4000_pcm(chip, 0); + if (err < 0) goto out_err; - } - if ((err = snd_sbmixer_new(chip)) < 0) { + + err = snd_sbmixer_new(chip); + if (err < 0) goto out_err; - } if (snd_opl3_create(card, iobase + ALS4K_IOB_10_ADLIB_ADDR0, @@ -922,16 +926,17 @@ static int snd_card_als4000_probe(struct pci_dev *pci, iobase + ALS4K_IOB_10_ADLIB_ADDR0, iobase + ALS4K_IOB_12_ADLIB_ADDR2); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) goto out_err; - } } snd_als4000_create_gameport(acard, dev); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) goto out_err; - } + pci_set_drvdata(pci, card); dev++; err = 0; diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 579425ccbb6a..5f8aa35c4bea 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1039,7 +1039,8 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream, /* direct SPDIF */ runtime->hw.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; } - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; runtime->private_data = dma; @@ -1415,7 +1416,8 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock, if (snd_atiixp_codec_detect(chip) < 0) return -ENXIO; - if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus); + if (err < 0) return err; pbus->clock = clock; chip->ac97_bus = pbus; @@ -1431,7 +1433,8 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock, ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; if (! chip->spdif_over_aclink) ac97.scaps |= AC97_SCAP_NO_SPDIF; - if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { + err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i]); + if (err < 0) { chip->ac97[i] = NULL; /* to be sure */ dev_dbg(chip->card->dev, "codec %d not available for audio\n", i); @@ -1562,7 +1565,8 @@ static int snd_atiixp_create(struct snd_card *card, struct atiixp *chip; int err; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -1576,7 +1580,8 @@ static int snd_atiixp_create(struct snd_card *card, chip->card = card; chip->pci = pci; chip->irq = -1; - if ((err = pci_request_regions(pci, "ATI IXP AC97")) < 0) { + err = pci_request_regions(pci, "ATI IXP AC97"); + if (err < 0) { pci_disable_device(pci); kfree(chip); return err; @@ -1599,7 +1604,8 @@ static int snd_atiixp_create(struct snd_card *card, card->sync_irq = chip->irq; pci_set_master(pci); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_atiixp_free(chip); return err; } @@ -1622,19 +1628,23 @@ static int snd_atiixp_probe(struct pci_dev *pci, strcpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA"); strcpy(card->shortname, "ATI IXP"); - if ((err = snd_atiixp_create(card, pci, &chip)) < 0) + err = snd_atiixp_create(card, pci, &chip); + if (err < 0) goto __error; card->private_data = chip; - if ((err = snd_atiixp_aclink_reset(chip)) < 0) + err = snd_atiixp_aclink_reset(chip); + if (err < 0) goto __error; chip->spdif_over_aclink = spdif_aclink; - if ((err = snd_atiixp_mixer_new(chip, ac97_clock, ac97_quirk)) < 0) + err = snd_atiixp_mixer_new(chip, ac97_clock, ac97_quirk); + if (err < 0) goto __error; - if ((err = snd_atiixp_pcm_new(chip)) < 0) + err = snd_atiixp_pcm_new(chip); + if (err < 0) goto __error; snd_atiixp_proc_init(chip); @@ -1647,7 +1657,8 @@ static int snd_atiixp_probe(struct pci_dev *pci, chip->ac97[0] ? snd_ac97_get_short_name(chip->ac97[0]) : "?", chip->addr, chip->irq); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto __error; pci_set_drvdata(pci, card); diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 45e75afec7a0..9739c3a82777 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -856,12 +856,12 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream, dma->substream = substream; runtime->hw = snd_atiixp_pcm_hw; dma->ac97_pcm_type = pcm_type; - if ((err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &hw_constraints_rates)) < 0) + err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &hw_constraints_rates); + if (err < 0) return err; - if ((err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; runtime->private_data = dma; @@ -1058,7 +1058,8 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) if (snd_atiixp_codec_detect(chip) < 0) return -ENXIO; - if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus); + if (err < 0) return err; pbus->clock = clock; chip->ac97_bus = pbus; @@ -1072,7 +1073,8 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) ac97.pci = chip->pci; ac97.num = i; ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; - if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { + err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i]); + if (err < 0) { chip->ac97[i] = NULL; /* to be sure */ dev_dbg(chip->card->dev, "codec %d not available for modem\n", i); @@ -1192,7 +1194,8 @@ static int snd_atiixp_create(struct snd_card *card, struct atiixp_modem *chip; int err; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -1206,7 +1209,8 @@ static int snd_atiixp_create(struct snd_card *card, chip->card = card; chip->pci = pci; chip->irq = -1; - if ((err = pci_request_regions(pci, "ATI IXP MC97")) < 0) { + err = pci_request_regions(pci, "ATI IXP MC97"); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -1229,7 +1233,8 @@ static int snd_atiixp_create(struct snd_card *card, card->sync_irq = chip->irq; pci_set_master(pci); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_atiixp_free(chip); return err; } @@ -1252,17 +1257,21 @@ static int snd_atiixp_probe(struct pci_dev *pci, strcpy(card->driver, "ATIIXP-MODEM"); strcpy(card->shortname, "ATI IXP Modem"); - if ((err = snd_atiixp_create(card, pci, &chip)) < 0) + err = snd_atiixp_create(card, pci, &chip); + if (err < 0) goto __error; card->private_data = chip; - if ((err = snd_atiixp_aclink_reset(chip)) < 0) + err = snd_atiixp_aclink_reset(chip); + if (err < 0) goto __error; - if ((err = snd_atiixp_mixer_new(chip, ac97_clock)) < 0) + err = snd_atiixp_mixer_new(chip, ac97_clock); + if (err < 0) goto __error; - if ((err = snd_atiixp_pcm_new(chip)) < 0) + err = snd_atiixp_pcm_new(chip); + if (err < 0) goto __error; snd_atiixp_proc_init(chip); @@ -1272,7 +1281,8 @@ static int snd_atiixp_probe(struct pci_dev *pci, sprintf(card->longname, "%s rev %x at 0x%lx, irq %i", card->shortname, pci->revision, chip->addr, chip->irq); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto __error; pci_set_drvdata(pci, card); diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 1b37b7225b1d..1f7fee470266 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -46,8 +46,9 @@ MODULE_DEVICE_TABLE(pci, snd_vortex_ids); static void vortex_fix_latency(struct pci_dev *vortex) { int rc; - if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) { - dev_info(&vortex->dev, "vortex latency is 0xff\n"); + rc = pci_write_config_byte(vortex, 0x40, 0xff); + if (!rc) { + dev_info(&vortex->dev, "vortex latency is 0xff\n"); } else { dev_warn(&vortex->dev, "could not set vortex latency: pci error 0x%x\n", rc); @@ -65,9 +66,12 @@ static void vortex_fix_agp_bridge(struct pci_dev *via) * read the config and it is not already set */ - if (!(rc = pci_read_config_byte(via, 0x42, &value)) - && ((value & 0x10) - || !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) { + rc = pci_read_config_byte(via, 0x42, &value); + if (!rc) { + if (!(value & 0x10)) + rc = pci_write_config_byte(via, 0x42, value | 0x10); + } + if (!rc) { dev_info(&via->dev, "bridge config is 0x%x\n", value | 0x10); } else { dev_warn(&via->dev, @@ -102,14 +106,16 @@ static void snd_vortex_workaround(struct pci_dev *vortex, int fix) } else { if (fix & 0x1) vortex_fix_latency(vortex); - if ((fix & 0x2) && (via = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_8365_1, NULL))) - vortex_fix_agp_bridge(via); - if ((fix & 0x4) && (via = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_82C598_1, NULL))) - vortex_fix_agp_bridge(via); - if ((fix & 0x8) && (via = pci_get_device(PCI_VENDOR_ID_AMD, - PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL))) + if (fix & 0x2) + via = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8365_1, NULL); + else if (fix & 0x4) + via = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C598_1, NULL); + else if (fix & 0x8) + via = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL); + if (via) vortex_fix_agp_bridge(via); } pci_dev_put(via); @@ -147,7 +153,8 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) *rchip = NULL; // check PCI availability (DMA). - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) { dev_err(card->dev, "error to set DMA mask\n"); @@ -174,7 +181,8 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) // (1) PCI resource allocation // Get MMIO area // - if ((err = pci_request_regions(pci, CARD_NAME_SHORT)) != 0) + err = pci_request_regions(pci, CARD_NAME_SHORT); + if (err) goto regions_out; chip->mmio = pci_ioremap_bar(pci, 0); @@ -187,14 +195,15 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) /* Init audio core. * This must be done before we do request_irq otherwise we can get spurious * interrupts that we do not handle properly and make a mess of things */ - if ((err = vortex_core_init(chip)) != 0) { + err = vortex_core_init(chip); + if (err) { dev_err(card->dev, "hw core init failed\n"); goto core_out; } - if ((err = request_irq(pci->irq, vortex_interrupt, - IRQF_SHARED, KBUILD_MODNAME, - chip)) != 0) { + err = request_irq(pci->irq, vortex_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip); + if (err) { dev_err(card->dev, "cannot grab irq\n"); goto irq_out; } @@ -205,9 +214,9 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) // End of PCI setup. // Register alsa root device. - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) goto alloc_out; - } *rchip = chip; @@ -252,7 +261,8 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return err; // (3) - if ((err = snd_vortex_create(card, pci, &chip)) < 0) { + err = snd_vortex_create(card, pci, &chip); + if (err < 0) { snd_card_free(card); return err; } @@ -278,12 +288,14 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) } #ifndef CHIP_AU8820 // ADB SPDIF - if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_SPDIF, 1)) < 0) { + err = snd_vortex_new_pcm(chip, VORTEX_PCM_SPDIF, 1); + if (err < 0) { snd_card_free(card); return err; } // A3D - if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_A3D, NR_A3D)) < 0) { + err = snd_vortex_new_pcm(chip, VORTEX_PCM_A3D, NR_A3D); + if (err < 0) { snd_card_free(card); return err; } @@ -297,12 +309,14 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) */ #ifndef CHIP_AU8810 // WT pcm. - if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_WT, NR_WT)) < 0) { + err = snd_vortex_new_pcm(chip, VORTEX_PCM_WT, NR_WT); + if (err < 0) { snd_card_free(card); return err; } #endif - if ((err = snd_vortex_midi(chip)) < 0) { + err = snd_vortex_midi(chip); + if (err < 0) { snd_card_free(card); return err; } @@ -327,13 +341,13 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) #endif // (5) - if ((err = pci_read_config_word(pci, PCI_DEVICE_ID, - &(chip->device))) < 0) { + err = pci_read_config_word(pci, PCI_DEVICE_ID, &chip->device); + if (err < 0) { snd_card_free(card); return err; } - if ((err = pci_read_config_word(pci, PCI_VENDOR_ID, - &(chip->vendor))) < 0) { + err = pci_read_config_word(pci, PCI_VENDOR_ID, &chip->vendor); + if (err < 0) { snd_card_free(card); return err; } @@ -352,7 +366,8 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) #endif // (6) - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index 2db183f8826a..eabaee0463fe 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -849,46 +849,50 @@ static int vortex_a3d_register_controls(vortex_t *vortex) int err, i; /* HRTF controls. */ for (i = 0; i < NR_A3D; i++) { - if ((kcontrol = - snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL) + kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i]); + if (!kcontrol) return -ENOMEM; kcontrol->id.numid = CTRLID_HRTF; kcontrol->info = snd_vortex_a3d_hrtf_info; kcontrol->put = snd_vortex_a3d_hrtf_put; - if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + err = snd_ctl_add(vortex->card, kcontrol); + if (err < 0) return err; } /* ITD controls. */ for (i = 0; i < NR_A3D; i++) { - if ((kcontrol = - snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL) + kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i]); + if (!kcontrol) return -ENOMEM; kcontrol->id.numid = CTRLID_ITD; kcontrol->info = snd_vortex_a3d_itd_info; kcontrol->put = snd_vortex_a3d_itd_put; - if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + err = snd_ctl_add(vortex->card, kcontrol); + if (err < 0) return err; } /* ILD (gains) controls. */ for (i = 0; i < NR_A3D; i++) { - if ((kcontrol = - snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL) + kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i]); + if (!kcontrol) return -ENOMEM; kcontrol->id.numid = CTRLID_GAINS; kcontrol->info = snd_vortex_a3d_ild_info; kcontrol->put = snd_vortex_a3d_ild_put; - if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + err = snd_ctl_add(vortex->card, kcontrol); + if (err < 0) return err; } /* Filter controls. */ for (i = 0; i < NR_A3D; i++) { - if ((kcontrol = - snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL) + kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i]); + if (!kcontrol) return -ENOMEM; kcontrol->id.numid = CTRLID_FILTER; kcontrol->info = snd_vortex_a3d_filter_info; kcontrol->put = snd_vortex_a3d_filter_put; - if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + err = snd_ctl_add(vortex->card, kcontrol); + if (err < 0) return err; } return 0; diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 5180f1bd1326..2ed5100b8cae 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2120,9 +2120,9 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, VORTEX_RESOURCE_DMA); } else { en = 1; - if ((dma = - vortex_adb_checkinout(vortex, NULL, en, - VORTEX_RESOURCE_DMA)) < 0) + dma = vortex_adb_checkinout(vortex, NULL, en, + VORTEX_RESOURCE_DMA); + if (dma < 0) return -EBUSY; } @@ -2140,18 +2140,20 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, /* Get SRC and MIXER hardware resources. */ if (stream->type != VORTEX_PCM_SPDIF) { for (i = 0; i < nr_ch; i++) { - if ((src[i] = vortex_adb_checkinout(vortex, - stream->resources, en, - VORTEX_RESOURCE_SRC)) < 0) { + src[i] = vortex_adb_checkinout(vortex, + stream->resources, en, + VORTEX_RESOURCE_SRC); + if (src[i] < 0) { memset(stream->resources, 0, sizeof(stream->resources)); return -EBUSY; } if (stream->type != VORTEX_PCM_A3D) { - if ((mix[i] = vortex_adb_checkinout(vortex, - stream->resources, - en, - VORTEX_RESOURCE_MIXIN)) < 0) { + mix[i] = vortex_adb_checkinout(vortex, + stream->resources, + en, + VORTEX_RESOURCE_MIXIN); + if (mix[i] < 0) { memset(stream->resources, 0, sizeof(stream->resources)); @@ -2162,10 +2164,10 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, } #ifndef CHIP_AU8820 if (stream->type == VORTEX_PCM_A3D) { - if ((a3d = - vortex_adb_checkinout(vortex, - stream->resources, en, - VORTEX_RESOURCE_A3D)) < 0) { + a3d = vortex_adb_checkinout(vortex, + stream->resources, en, + VORTEX_RESOURCE_A3D); + if (a3d < 0) { memset(stream->resources, 0, sizeof(stream->resources)); dev_err(vortex->card->dev, @@ -2278,19 +2280,18 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, /* Get SRC and MIXER hardware resources. */ for (i = 0; i < nr_ch; i++) { - if ((mix[i] = - vortex_adb_checkinout(vortex, - stream->resources, en, - VORTEX_RESOURCE_MIXOUT)) - < 0) { + mix[i] = vortex_adb_checkinout(vortex, + stream->resources, en, + VORTEX_RESOURCE_MIXOUT); + if (mix[i] < 0) { memset(stream->resources, 0, sizeof(stream->resources)); return -EBUSY; } - if ((src[i] = - vortex_adb_checkinout(vortex, - stream->resources, en, - VORTEX_RESOURCE_SRC)) < 0) { + src[i] = vortex_adb_checkinout(vortex, + stream->resources, en, + VORTEX_RESOURCE_SRC); + if (src[i] < 0) { memset(stream->resources, 0, sizeof(stream->resources)); return -EBUSY; diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index 58e92f2a72c0..71c13100d7ef 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -873,29 +873,33 @@ static int vortex_eq_init(vortex_t *vortex) vortex_Eqlzr_init(vortex); - if ((kcontrol = - snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL) + kcontrol = snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex); + if (!kcontrol) return -ENOMEM; kcontrol->private_value = 0; - if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + err = snd_ctl_add(vortex->card, kcontrol); + if (err < 0) return err; /* EQ gain controls */ for (i = 0; i < 10; i++) { - if ((kcontrol = - snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL) + kcontrol = snd_ctl_new1(&vortex_eq_kcontrol, vortex); + if (!kcontrol) return -ENOMEM; snprintf(kcontrol->id.name, sizeof(kcontrol->id.name), "%s Playback Volume", EqBandLabels[i]); kcontrol->private_value = i; - if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + err = snd_ctl_add(vortex->card, kcontrol); + if (err < 0) return err; //vortex->eqctrl[i] = kcontrol; } /* EQ band levels */ - if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL) + kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex); + if (!kcontrol) return -ENOMEM; - if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + err = snd_ctl_add(vortex->card, kcontrol); + if (err < 0) return err; return 0; diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index 5b647682b683..aeba684b8d18 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c @@ -30,7 +30,8 @@ static int snd_vortex_mixer(vortex_t *vortex) .read = vortex_codec_read, }; - if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; memset(&ac97, 0, sizeof(ac97)); // Initialize AC97 codec stuff. diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 603494e7d30e..164f6b7039ab 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c @@ -68,9 +68,9 @@ static int snd_vortex_midi(vortex_t *vortex) /* Create MPU401 instance. */ #ifdef VORTEX_MPU401_LEGACY - if ((temp = - snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, - MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) { + temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, + MPU401_INFO_IRQ_HOOK, -1, &rmidi); + if (temp) { hwwrite(vortex->mmio, VORTEX_CTRL, (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); @@ -78,10 +78,10 @@ static int snd_vortex_midi(vortex_t *vortex) } #else port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); - if ((temp = - snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, - MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO | - MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) { + temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, + MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO | + MPU401_INFO_IRQ_HOOK, -1, &rmidi); + if (temp) { hwwrite(vortex->mmio, VORTEX_CTRL, (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index d019aa566de3..546f71220604 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -130,14 +130,14 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) int err; /* Force equal size periods */ - if ((err = - snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; /* Avoid PAGE_SIZE boundary to fall inside of a period. */ - if ((err = - snd_pcm_hw_constraint_pow2(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) + err = snd_pcm_hw_constraint_pow2(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES); + if (err < 0) return err; snd_pcm_hw_constraint_step(runtime, 0, @@ -658,7 +658,8 @@ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip); if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(chip->card, kctl)) < 0) + err = snd_ctl_add(chip->card, kctl); + if (err < 0) return err; } } diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 51dcf1bc4c0c..4ee7ab409807 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1194,7 +1194,8 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip) sw = snd_azf3328_mixer_controls; for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); ++idx, ++sw) { - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip)); + if (err < 0) return err; } snd_component_add(card, "AZF3328 mixer"); diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 91512b345d19..39bcfb81e81c 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -719,7 +719,8 @@ static int snd_bt87x_create(struct snd_card *card, chip->irq = -1; spin_lock_init(&chip->reg_lock); - if ((err = pci_request_regions(pci, "Bt87x audio")) < 0) { + err = pci_request_regions(pci, "Bt87x audio"); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index bee4710916c4..99778711006a 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -575,9 +575,11 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr */ //channel->interrupt = snd_ca0106_pcm_channel_interrupt; channel->epcm = epcm; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; - if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) + err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (err < 0) return err; snd_pcm_set_sync(substream); @@ -668,10 +670,12 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre */ //channel->interrupt = snd_ca0106_pcm_channel_interrupt; channel->epcm = epcm; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; //snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_capture_period_sizes); - if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) + err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (err < 0) return err; return 0; } @@ -1166,7 +1170,8 @@ static int snd_ca0106_ac97(struct snd_ca0106 *chip) .read = snd_ca0106_ac97_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; pbus->no_vra = 1; /* we don't need VRA */ @@ -1759,7 +1764,8 @@ static int snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int channel) midi->dev_id = chip; - if ((err = ca_midi_init(chip, midi, 0, name)) < 0) + err = ca_midi_init(chip, midi, 0, name); + if (err < 0) return err; return 0; diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index 18524e0a9102..957e60f64821 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c @@ -276,7 +276,8 @@ int ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name) struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(midi->get_dev_id_card(midi->dev_id), name, device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(midi->get_dev_id_card(midi->dev_id), name, device, 1, 1, &rmidi); + if (err < 0) return err; midi->dev_id = dev_id; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 598446348da6..f44f118aacad 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -1225,9 +1225,11 @@ static int setup_spdif_playback(struct cmipci *cm, struct snd_pcm_substream *sub rate = subs->runtime->rate; - if (up && do_ac3) - if ((err = save_mixer_state(cm)) < 0) + if (up && do_ac3) { + err = save_mixer_state(cm); + if (err < 0) return err; + } spin_lock_irq(&cm->reg_lock); cm->spdif_playback_avail = up; @@ -1276,7 +1278,8 @@ static int snd_cmipci_playback_prepare(struct snd_pcm_substream *substream) substream->runtime->channels == 2); if (do_spdif && cm->can_ac3_hw) do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO; - if ((err = setup_spdif_playback(cm, substream, do_spdif, do_ac3)) < 0) + err = setup_spdif_playback(cm, substream, do_spdif, do_ac3); + if (err < 0) return err; return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); } @@ -1291,7 +1294,8 @@ static int snd_cmipci_playback_spdif_prepare(struct snd_pcm_substream *substream do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO; else do_ac3 = 1; /* doesn't matter */ - if ((err = setup_spdif_playback(cm, substream, 1, do_ac3)) < 0) + err = setup_spdif_playback(cm, substream, 1, do_ac3); + if (err < 0) return err; return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); } @@ -1639,7 +1643,8 @@ static int snd_cmipci_playback_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = open_device_check(cm, CM_OPEN_PLAYBACK, substream)) < 0) + err = open_device_check(cm, CM_OPEN_PLAYBACK, substream); + if (err < 0) return err; runtime->hw = snd_cmipci_playback; if (cm->chip_version == 68) { @@ -1665,7 +1670,8 @@ static int snd_cmipci_capture_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = open_device_check(cm, CM_OPEN_CAPTURE, substream)) < 0) + err = open_device_check(cm, CM_OPEN_CAPTURE, substream); + if (err < 0) return err; runtime->hw = snd_cmipci_capture; if (cm->chip_version == 68) { // 8768 only supports 44k/48k recording @@ -1689,7 +1695,9 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = open_device_check(cm, CM_OPEN_PLAYBACK2, substream)) < 0) /* use channel B */ + /* use channel B */ + err = open_device_check(cm, CM_OPEN_PLAYBACK2, substream); + if (err < 0) return err; runtime->hw = snd_cmipci_playback2; mutex_lock(&cm->open_mutex); @@ -1727,7 +1735,9 @@ static int snd_cmipci_playback_spdif_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = open_device_check(cm, CM_OPEN_SPDIF_PLAYBACK, substream)) < 0) /* use channel A */ + /* use channel A */ + err = open_device_check(cm, CM_OPEN_SPDIF_PLAYBACK, substream); + if (err < 0) return err; if (cm->can_ac3_hw) { runtime->hw = snd_cmipci_playback_spdif; @@ -1754,7 +1764,9 @@ static int snd_cmipci_capture_spdif_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream)) < 0) /* use channel B */ + /* use channel B */ + err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream); + if (err < 0) return err; runtime->hw = snd_cmipci_capture_spdif; if (cm->can_96k && !(cm->chip_version == 68)) { @@ -2650,7 +2662,8 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) "PCM Playback Volume")) continue; } - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cmipci_mixers[idx], cm))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_cmipci_mixers[idx], cm)); + if (err < 0) return err; } @@ -2675,13 +2688,19 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) return err; } if (cm->can_ac3_hw) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_default, cm))) < 0) + kctl = snd_ctl_new1(&snd_cmipci_spdif_default, cm); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; kctl->id.device = pcm_spdif_device; - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_mask, cm))) < 0) + kctl = snd_ctl_new1(&snd_cmipci_spdif_mask, cm); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; kctl->id.device = pcm_spdif_device; - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_cmipci_spdif_stream, cm))) < 0) + kctl = snd_ctl_new1(&snd_cmipci_spdif_stream, cm); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; kctl->id.device = pcm_spdif_device; } @@ -2955,7 +2974,8 @@ static int snd_cmipci_create_fm(struct cmipci *cm, long fm_port) goto disable_fm; } } - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) { dev_err(cm->card->dev, "cannot create OPL3 hwdep\n"); return err; } @@ -2987,7 +3007,8 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, *rcmipci = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; cm = kzalloc(sizeof(*cm), GFP_KERNEL); @@ -3006,7 +3027,8 @@ 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 */ - if ((err = pci_request_regions(pci, card->driver)) < 0) { + err = pci_request_regions(pci, card->driver); + if (err < 0) { kfree(cm); pci_disable_device(pci); return err; @@ -3120,7 +3142,8 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, sprintf(card->longname, "%s%s at %#lx, irq %i", card->shortname, modelstr, cm->iobase, cm->irq); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, cm, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, cm, &ops); + if (err < 0) { snd_cmipci_free(cm); return err; } @@ -3172,32 +3195,36 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, /* create pcm devices */ pcm_index = pcm_spdif_index = 0; - if ((err = snd_cmipci_pcm_new(cm, pcm_index)) < 0) + err = snd_cmipci_pcm_new(cm, pcm_index); + if (err < 0) return err; pcm_index++; - if ((err = snd_cmipci_pcm2_new(cm, pcm_index)) < 0) + err = snd_cmipci_pcm2_new(cm, pcm_index); + if (err < 0) return err; pcm_index++; if (cm->can_ac3_hw || cm->can_ac3_sw) { pcm_spdif_index = pcm_index; - if ((err = snd_cmipci_pcm_spdif_new(cm, pcm_index)) < 0) + err = snd_cmipci_pcm_spdif_new(cm, pcm_index); + if (err < 0) return err; } /* create mixer interface & switches */ - if ((err = snd_cmipci_mixer_new(cm, pcm_spdif_index)) < 0) + err = snd_cmipci_mixer_new(cm, pcm_spdif_index); + if (err < 0) return err; if (iomidi > 0) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, - iomidi, - (integrated_midi ? - MPU401_INFO_INTEGRATED : 0) | - MPU401_INFO_IRQ_HOOK, - -1, &cm->rmidi)) < 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, + iomidi, + (integrated_midi ? + MPU401_INFO_INTEGRATED : 0) | + MPU401_INFO_IRQ_HOOK, + -1, &cm->rmidi); + if (err < 0) dev_err(cm->card->dev, "no UART401 device at 0x%lx\n", iomidi); - } } #ifdef USE_VAR48KRATE diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index bf3bb70ffaf9..e122a168c148 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1068,23 +1068,28 @@ static int snd_cs4281_mixer(struct cs4281 *chip) .read = snd_cs4281_ac97_read, }; - if ((err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus)) < 0) + err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus); + if (err < 0) return err; chip->ac97_bus->private_free = snd_cs4281_mixer_free_ac97_bus; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_cs4281_mixer_free_ac97; - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97); + if (err < 0) return err; if (chip->dual_codec) { ac97.num = 1; - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_secondary)) < 0) + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_secondary); + if (err < 0) return err; } - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_fm_vol, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_fm_vol, chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_pcm_vol, chip))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_pcm_vol, chip)); + if (err < 0) return err; return 0; } @@ -1308,7 +1313,8 @@ static int snd_cs4281_create(struct snd_card *card, }; *rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { @@ -1326,7 +1332,8 @@ static int snd_cs4281_create(struct snd_card *card, } chip->dual_codec = dual_codec; - if ((err = pci_request_regions(pci, "CS4281")) < 0) { + err = pci_request_regions(pci, "CS4281"); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -1356,7 +1363,8 @@ static int snd_cs4281_create(struct snd_card *card, return tmp; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_cs4281_free(chip); return err; } @@ -1395,12 +1403,14 @@ static int snd_cs4281_chip_init(struct cs4281 *chip) * space between 0e4h and 0ffh to be written. */ snd_cs4281_pokeBA0(chip, BA0_CWPR, 0x4281); - if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC1)) != (BA0_SERC1_SO1EN | BA0_SERC1_AC97)) { + tmp = snd_cs4281_peekBA0(chip, BA0_SERC1); + if (tmp != (BA0_SERC1_SO1EN | BA0_SERC1_AC97)) { dev_err(chip->card->dev, "SERC1 AC'97 check failed (0x%x)\n", tmp); return -EIO; } - if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC2)) != (BA0_SERC2_SI1EN | BA0_SERC2_AC97)) { + tmp = snd_cs4281_peekBA0(chip, BA0_SERC2); + if (tmp != (BA0_SERC2_SI1EN | BA0_SERC2_AC97)) { dev_err(chip->card->dev, "SERC2 AC'97 check failed (0x%x)\n", tmp); return -EIO; @@ -1748,7 +1758,8 @@ static int snd_cs4281_midi(struct cs4281 *chip, int device) struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi); + if (err < 0) return err; strcpy(rmidi->name, "CS4281"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_cs4281_midi_output); @@ -1881,32 +1892,38 @@ static int snd_cs4281_probe(struct pci_dev *pci, if (err < 0) return err; - if ((err = snd_cs4281_create(card, pci, &chip, dual_codec[dev])) < 0) { + err = snd_cs4281_create(card, pci, &chip, dual_codec[dev]); + if (err < 0) { snd_card_free(card); return err; } card->private_data = chip; - if ((err = snd_cs4281_mixer(chip)) < 0) { + err = snd_cs4281_mixer(chip); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_cs4281_pcm(chip, 0)) < 0) { + err = snd_cs4281_pcm(chip, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_cs4281_midi(chip, 0)) < 0) { + err = snd_cs4281_midi(chip, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3_new(card, OPL3_HW_OPL3_CS4281, &opl3)) < 0) { + err = snd_opl3_new(card, OPL3_HW_OPL3_CS4281, &opl3); + if (err < 0) { snd_card_free(card); return err; } opl3->private_data = chip; opl3->command = snd_cs4281_opl3_command; snd_opl3_init(opl3); - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) { snd_card_free(card); return err; } @@ -1918,7 +1935,8 @@ static int snd_cs4281_probe(struct pci_dev *pci, chip->ba0_addr, chip->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 1db7b4112840..358ca84cbdea 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -70,45 +70,53 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, 0, &card); if (err < 0) return err; - if ((err = snd_cs46xx_create(card, pci, - external_amp[dev], thinkpad[dev], - &chip)) < 0) { + err = snd_cs46xx_create(card, pci, + external_amp[dev], thinkpad[dev], + &chip); + if (err < 0) { snd_card_free(card); return err; } card->private_data = chip; chip->accept_valid = mmap_valid[dev]; - if ((err = snd_cs46xx_pcm(chip, 0)) < 0) { + err = snd_cs46xx_pcm(chip, 0); + if (err < 0) { snd_card_free(card); return err; } #ifdef CONFIG_SND_CS46XX_NEW_DSP - if ((err = snd_cs46xx_pcm_rear(chip, 1)) < 0) { + err = snd_cs46xx_pcm_rear(chip, 1); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_cs46xx_pcm_iec958(chip, 2)) < 0) { + err = snd_cs46xx_pcm_iec958(chip, 2); + if (err < 0) { snd_card_free(card); return err; } #endif - if ((err = snd_cs46xx_mixer(chip, 2)) < 0) { + err = snd_cs46xx_mixer(chip, 2); + if (err < 0) { snd_card_free(card); return err; } #ifdef CONFIG_SND_CS46XX_NEW_DSP if (chip->nr_ac97_codecs ==2) { - if ((err = snd_cs46xx_pcm_center_lfe(chip, 3)) < 0) { + err = snd_cs46xx_pcm_center_lfe(chip, 3); + if (err < 0) { snd_card_free(card); return err; } } #endif - if ((err = snd_cs46xx_midi(chip, 0)) < 0) { + err = snd_cs46xx_midi(chip, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_cs46xx_start_dsp(chip)) < 0) { + err = snd_cs46xx_start_dsp(chip); + if (err < 0) { snd_card_free(card); return err; } @@ -124,7 +132,8 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci, chip->ba1_addr, chip->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 37f516e6a5c2..1e1eb17f8e07 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1058,9 +1058,10 @@ static int _cs46xx_adjust_sample_rate (struct snd_cs46xx *chip, struct snd_cs46x int unlinked = cpcm->pcm_channel->unlinked; cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel); - if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, - cpcm->hw_buf.addr, - cpcm->pcm_channel_id)) == NULL) { + cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel(chip, sample_rate, cpcm, + cpcm->hw_buf.addr, + cpcm->pcm_channel_id); + if (!cpcm->pcm_channel) { dev_err(chip->card->dev, "failed to re-create virtual PCM channel\n"); return -ENOMEM; @@ -1147,7 +1148,8 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream, runtime->dma_addr = 0; runtime->dma_bytes = 0; } - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) { + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (err < 0) { #ifdef CONFIG_SND_CS46XX_NEW_DSP mutex_unlock(&chip->spos_mutex); #endif @@ -1295,7 +1297,8 @@ static int snd_cs46xx_capture_hw_params(struct snd_pcm_substream *substream, runtime->dma_addr = 0; runtime->dma_bytes = 0; } - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (err < 0) return err; substream->ops = &snd_cs46xx_capture_indirect_ops; } @@ -1760,7 +1763,8 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0) + err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -1787,7 +1791,8 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0) + err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -1811,7 +1816,8 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "CS46xx - Center LFE", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0) + err = snd_pcm_new(chip->card, "CS46xx - Center LFE", device, MAX_PLAYBACK_CHANNELS, 0, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -1835,7 +1841,8 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0) + err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -2414,7 +2421,8 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97) /* test if we can write to the record gain volume register */ snd_ac97_write(ac97, AC97_REC_GAIN, 0x8a05); - if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05) + err = snd_ac97_read(ac97, AC97_REC_GAIN); + if (err == 0x8a05) return; msleep(10); @@ -2476,7 +2484,8 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) /* detect primary codec */ chip->nr_ac97_codecs = 0; dev_dbg(chip->card->dev, "detecting primary codec\n"); - if ((err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus)) < 0) + err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus); + if (err < 0) return err; chip->ac97_bus->private_free = snd_cs46xx_mixer_free_ac97_bus; @@ -2497,7 +2506,8 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) kctl = snd_ctl_new1(&snd_cs46xx_controls[idx], chip); if (kctl && kctl->id.iface == SNDRV_CTL_ELEM_IFACE_PCM) kctl->id.device = spdif_device; - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) return err; } @@ -2684,7 +2694,8 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device) struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi); + if (err < 0) return err; strcpy(rmidi->name, "CS46XX"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_cs46xx_midi_output); @@ -3526,7 +3537,8 @@ static void hercules_mixer_init (struct snd_cs46xx *chip) struct snd_kcontrol *kctl; kctl = snd_ctl_new1(&snd_hercules_controls[idx], chip); - if ((err = snd_ctl_add(card, kctl)) < 0) { + err = snd_ctl_add(card, kctl); + if (err < 0) { dev_err(card->dev, "failed to initialize Hercules mixer (%d)\n", err); @@ -3871,7 +3883,8 @@ int snd_cs46xx_create(struct snd_card *card, *rchip = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -3965,8 +3978,9 @@ int snd_cs46xx_create(struct snd_card *card, for (idx = 0; idx < 5; idx++) { region = &chip->region.idx[idx]; - if ((region->resource = request_mem_region(region->base, region->size, - region->name)) == NULL) { + region->resource = request_mem_region(region->base, region->size, + region->name); + if (!region->resource) { dev_err(chip->card->dev, "unable to request memory region 0x%lx-0x%lx\n", region->base, region->base + region->size - 1); @@ -4005,7 +4019,8 @@ int snd_cs46xx_create(struct snd_card *card, return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_cs46xx_free(chip); return err; } diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 05f3f6dc918d..1db6bc58d6a6 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -617,7 +617,8 @@ static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry, col = 0; } - if ( (symbol = cs46xx_dsp_lookup_symbol_addr (chip,i / sizeof(u32), SYMBOL_PARAMETER)) != NULL) { + symbol = cs46xx_dsp_lookup_symbol_addr(chip, i / sizeof(u32), SYMBOL_PARAMETER); + if (symbol) { col = 0; snd_iprintf (buffer,"\n%s:\n",symbol->symbol_name); } diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 9b716b56d739..e048b45d9e7e 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -143,7 +143,8 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) .read = snd_cs5535audio_ac97_codec_read, }; - if ((err = snd_ac97_bus(card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(card, 0, &ops, NULL, &pbus); + if (err < 0) return err; memset(&ac97, 0, sizeof(ac97)); @@ -155,7 +156,8 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) /* set any OLPC-specific scaps */ olpc_prequirks(card, &ac97); - if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) { + err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97); + if (err < 0) { dev_err(card->dev, "mixer failed\n"); return err; } @@ -266,7 +268,8 @@ static int snd_cs5535audio_create(struct snd_card *card, }; *rcs5535au = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) { @@ -286,7 +289,8 @@ static int snd_cs5535audio_create(struct snd_card *card, cs5535au->pci = pci; cs5535au->irq = -1; - if ((err = pci_request_regions(pci, "CS5535 Audio")) < 0) { + err = pci_request_regions(pci, "CS5535 Audio"); + if (err < 0) { kfree(cs5535au); goto pcifail; } @@ -304,8 +308,8 @@ static int snd_cs5535audio_create(struct snd_card *card, card->sync_irq = cs5535au->irq; pci_set_master(pci); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - cs5535au, &ops)) < 0) + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, cs5535au, &ops); + if (err < 0) goto sndfail; *rcs5535au = cs5535au; @@ -340,15 +344,18 @@ static int snd_cs5535audio_probe(struct pci_dev *pci, if (err < 0) return err; - if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0) + err = snd_cs5535audio_create(card, pci, &cs5535au); + if (err < 0) goto probefail_out; card->private_data = cs5535au; - if ((err = snd_cs5535audio_mixer(cs5535au)) < 0) + err = snd_cs5535audio_mixer(cs5535au); + if (err < 0) goto probefail_out; - if ((err = snd_cs5535audio_pcm(cs5535au)) < 0) + err = snd_cs5535audio_pcm(cs5535au); + if (err < 0) goto probefail_out; strcpy(card->driver, DRIVER_NAME); @@ -358,7 +365,8 @@ static int snd_cs5535audio_probe(struct pci_dev *pci, card->shortname, card->driver, cs5535au->port, cs5535au->irq); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto probefail_out; pci_set_drvdata(pci, card); diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 4032b89b1fc1..5ff10fec7b90 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -87,8 +87,9 @@ static int snd_cs5535audio_playback_open(struct snd_pcm_substream *substream) snd_pcm_limit_hw_rates(runtime); cs5535au->playback_substream = substream; runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]); - if ((err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; return 0; @@ -342,8 +343,9 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) snd_pcm_limit_hw_rates(runtime); cs5535au->capture_substream = substream; runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]); - if ((err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; olpc_capture_open(cs5535au->ac97); return 0; diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index 320837ba7bab..0356efad7528 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c @@ -36,7 +36,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA20)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw: could not initialize DSP comm page\n"); return err; @@ -53,7 +54,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->asic_loaded = true; chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index 8736b5e81ca3..b96300772aee 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c @@ -36,7 +36,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA24)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw: could not initialize DSP comm page\n"); return err; @@ -52,7 +53,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_ESYNC; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index 6deb80c42f11..9e1f2cad0909 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -49,7 +49,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != ECHO3G)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 9bd67ac33657..a62e5581ad14 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -301,38 +301,42 @@ static int pcm_open(struct snd_pcm_substream *substream, snd_pcm_set_sync(substream); /* Only mono and any even number of channels are allowed */ - if ((err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &pipe->constr)) < 0) + err = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &pipe->constr); + if (err < 0) return err; /* All periods should have the same size */ - if ((err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; /* The hw accesses memory in chunks 32 frames long and they should be 32-bytes-aligned. It's not a requirement, but it seems that IRQs are generated with a resolution of 32 frames. Thus we need the following */ - if ((err = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 32)) < 0) + err = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); + if (err < 0) return err; - if ((err = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - 32)) < 0) + err = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); + if (err < 0) return err; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - hw_rule_sample_rate, chip, - SNDRV_PCM_HW_PARAM_RATE, -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + hw_rule_sample_rate, chip, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) return err; /* Allocate a page for the scatter-gather list */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - &chip->pci->dev, - PAGE_SIZE, &pipe->sgpage)) < 0) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + &chip->pci->dev, + PAGE_SIZE, &pipe->sgpage); + if (err < 0) { dev_err(chip->card->dev, "s-g list allocation failed\n"); return err; } @@ -358,18 +362,21 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream) struct echoaudio *chip = snd_pcm_substream_chip(substream); int err; - if ((err = pcm_open(substream, num_analog_busses_in(chip) - - substream->number)) < 0) + err = pcm_open(substream, + num_analog_busses_in(chip) - substream->number); + if (err < 0) return err; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - hw_rule_capture_channels_by_format, NULL, - SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_capture_channels_by_format, NULL, + SNDRV_PCM_HW_PARAM_FORMAT, -1); + if (err < 0) return err; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_FORMAT, - hw_rule_capture_format_by_channels, NULL, - SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_capture_format_by_channels, NULL, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) return err; return 0; @@ -387,19 +394,22 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream) #else max_channels = num_analog_busses_out(chip); #endif - if ((err = pcm_open(substream, max_channels - substream->number)) < 0) + err = pcm_open(substream, max_channels - substream->number); + if (err < 0) return err; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - hw_rule_playback_channels_by_format, - NULL, - SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_playback_channels_by_format, + NULL, + SNDRV_PCM_HW_PARAM_FORMAT, -1); + if (err < 0) return err; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_FORMAT, - hw_rule_playback_format_by_channels, - NULL, - SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_playback_format_by_channels, + NULL, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) return err; return 0; @@ -426,15 +436,17 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) if (err < 0) goto din_exit; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - hw_rule_capture_channels_by_format, NULL, - SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_capture_channels_by_format, NULL, + SNDRV_PCM_HW_PARAM_FORMAT, -1); + if (err < 0) goto din_exit; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_FORMAT, - hw_rule_capture_format_by_channels, NULL, - SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_capture_format_by_channels, NULL, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) goto din_exit; din_exit: @@ -463,17 +475,19 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) if (err < 0) goto dout_exit; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - hw_rule_playback_channels_by_format, - NULL, SNDRV_PCM_HW_PARAM_FORMAT, - -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_playback_channels_by_format, + NULL, SNDRV_PCM_HW_PARAM_FORMAT, + -1); + if (err < 0) goto dout_exit; - if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_FORMAT, - hw_rule_playback_format_by_channels, - NULL, SNDRV_PCM_HW_PARAM_CHANNELS, - -1)) < 0) + err = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_playback_format_by_channels, + NULL, SNDRV_PCM_HW_PARAM_CHANNELS, + -1); + if (err < 0) goto dout_exit; dout_exit: @@ -907,8 +921,9 @@ static int snd_echo_new_pcm(struct echoaudio *chip) separated */ /* PCM#0 Virtual outputs and analog inputs */ - if ((err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip), - num_analog_busses_in(chip), &pcm)) < 0) + err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip), + num_analog_busses_in(chip), &pcm); + if (err < 0) return err; pcm->private_data = chip; chip->analog_pcm = pcm; @@ -919,8 +934,9 @@ static int snd_echo_new_pcm(struct echoaudio *chip) #ifdef ECHOCARD_HAS_DIGITAL_IO /* PCM#1 Digital inputs, no outputs */ - if ((err = snd_pcm_new(chip->card, "Digital PCM", 1, 0, - num_digital_busses_in(chip), &pcm)) < 0) + err = snd_pcm_new(chip->card, "Digital PCM", 1, 0, + num_digital_busses_in(chip), &pcm); + if (err < 0) return err; pcm->private_data = chip; chip->digital_pcm = pcm; @@ -937,9 +953,10 @@ static int snd_echo_new_pcm(struct echoaudio *chip) register two PCM devices: */ /* PCM#0 Analog i/o */ - if ((err = snd_pcm_new(chip->card, "Analog PCM", 0, - num_analog_busses_out(chip), - num_analog_busses_in(chip), &pcm)) < 0) + err = snd_pcm_new(chip->card, "Analog PCM", 0, + num_analog_busses_out(chip), + num_analog_busses_in(chip), &pcm); + if (err < 0) return err; pcm->private_data = chip; chip->analog_pcm = pcm; @@ -950,9 +967,10 @@ static int snd_echo_new_pcm(struct echoaudio *chip) #ifdef ECHOCARD_HAS_DIGITAL_IO /* PCM#1 Digital i/o */ - if ((err = snd_pcm_new(chip->card, "Digital PCM", 1, - num_digital_busses_out(chip), - num_digital_busses_in(chip), &pcm)) < 0) + err = snd_pcm_new(chip->card, "Digital PCM", 1, + num_digital_busses_out(chip), + num_digital_busses_in(chip), &pcm); + if (err < 0) return err; pcm->private_data = chip; chip->digital_pcm = pcm; @@ -1567,7 +1585,8 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, if (chip->input_clock != dclock) { mutex_lock(&chip->mode_mutex); spin_lock_irq(&chip->lock); - if ((changed = set_input_clock(chip, dclock)) == 0) + changed = set_input_clock(chip, dclock); + if (!changed) changed = 1; /* no errors */ spin_unlock_irq(&chip->lock); mutex_unlock(&chip->mode_mutex); @@ -1911,7 +1930,8 @@ static int snd_echo_create(struct snd_card *card, pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0xC0); - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; pci_set_master(pci); @@ -1943,8 +1963,9 @@ static int snd_echo_create(struct snd_card *card, if (sz > PAGE_SIZE) sz = PAGE_SIZE; /* We map only the required part */ - if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz, - ECHOCARD_NAME)) == NULL) { + chip->iores = request_mem_region(chip->dsp_registers_phys, sz, + ECHOCARD_NAME); + if (!chip->iores) { dev_err(chip->card->dev, "cannot get memory region\n"); snd_echo_free(chip); return -EBUSY; @@ -1988,7 +2009,8 @@ static int snd_echo_create(struct snd_card *card, return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_echo_free(chip); return err; } @@ -2024,7 +2046,8 @@ static int snd_echo_probe(struct pci_dev *pci, return err; chip = NULL; /* Tells snd_echo_create to allocate chip */ - if ((err = snd_echo_create(card, pci, &chip)) < 0) { + err = snd_echo_create(card, pci, &chip); + if (err < 0) { snd_card_free(card); return err; } @@ -2040,7 +2063,8 @@ static int snd_echo_probe(struct pci_dev *pci, card->shortname, pci_id->subdevice & 0x000f, dsp, chip->dsp_registers_phys, chip->irq); - if ((err = snd_echo_new_pcm(chip)) < 0) { + err = snd_echo_new_pcm(chip); + if (err < 0) { dev_err(chip->card->dev, "new pcm error %d\n", err); snd_card_free(card); return err; @@ -2048,7 +2072,8 @@ static int snd_echo_probe(struct pci_dev *pci, #ifdef ECHOCARD_HAS_MIDI if (chip->has_midi) { /* Some Mia's do not have midi */ - if ((err = snd_echo_midi_create(card, chip)) < 0) { + err = snd_echo_midi_create(card, chip); + if (err < 0) { dev_err(chip->card->dev, "new midi error %d\n", err); snd_card_free(card); return err; @@ -2058,7 +2083,8 @@ static int snd_echo_probe(struct pci_dev *pci, #ifdef ECHOCARD_HAS_VMIXER snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip); - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip)); + if (err < 0) goto ctl_error; #ifdef ECHOCARD_HAS_LINE_OUT_GAIN err = snd_ctl_add(chip->card, @@ -2074,39 +2100,48 @@ static int snd_echo_probe(struct pci_dev *pci, #endif /* ECHOCARD_HAS_VMIXER */ #ifdef ECHOCARD_HAS_INPUT_GAIN - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip)); + if (err < 0) goto ctl_error; #endif #ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL - if (!chip->hasnt_input_nominal_level) - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip))) < 0) + if (!chip->hasnt_input_nominal_level) { + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip)); + if (err < 0) goto ctl_error; + } #endif #ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip)); + if (err < 0) goto ctl_error; #endif - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip)); + if (err < 0) goto ctl_error; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip)); + if (err < 0) goto ctl_error; #ifdef ECHOCARD_HAS_MONITOR snd_echo_monitor_mixer.count = num_busses_in(chip) * num_busses_out(chip); - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip)); + if (err < 0) goto ctl_error; #endif #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip)); + if (err < 0) goto ctl_error; #endif - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip)); + if (err < 0) goto ctl_error; #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH @@ -2116,7 +2151,8 @@ static int snd_echo_probe(struct pci_dev *pci, if (chip->digital_modes & (1 << i)) chip->digital_mode_list[chip->num_digital_modes++] = i; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip)); + if (err < 0) goto ctl_error; #endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */ @@ -2129,20 +2165,24 @@ static int snd_echo_probe(struct pci_dev *pci, if (chip->num_clock_sources > 1) { chip->clock_src_ctl = snd_ctl_new1(&snd_echo_clock_source_switch, chip); - if ((err = snd_ctl_add(chip->card, chip->clock_src_ctl)) < 0) + err = snd_ctl_add(chip->card, chip->clock_src_ctl); + if (err < 0) goto ctl_error; } #endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */ #ifdef ECHOCARD_HAS_DIGITAL_IO - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip)); + if (err < 0) goto ctl_error; #endif #ifdef ECHOCARD_HAS_PHANTOM_POWER - if (chip->has_phantom_power) - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip))) < 0) + if (chip->has_phantom_power) { + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip)); + if (err < 0) goto ctl_error; + } #endif err = snd_card_register(card); diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index d10d0e460f0b..2a40091d472c 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -349,7 +349,8 @@ static int load_dsp(struct echoaudio *chip, u16 *code) /* If this board requires a resident loader, install it. */ #ifdef DSP_56361 - if ((i = install_resident_loader(chip)) < 0) + i = install_resident_loader(chip); + if (i < 0) return i; #endif @@ -495,7 +496,8 @@ static int load_firmware(struct echoaudio *chip) /* See if the ASIC is present and working - only if the DSP is already loaded */ if (chip->dsp_code) { - if ((box_type = check_asic_status(chip)) >= 0) + box_type = check_asic_status(chip); + if (box_type >= 0) return box_type; /* ASIC check failed; force the DSP to reload */ chip->dsp_code = NULL; @@ -509,7 +511,8 @@ static int load_firmware(struct echoaudio *chip) if (err < 0) return err; - if ((box_type = load_asic(chip)) < 0) + box_type = load_asic(chip); + if (box_type < 0) return box_type; /* error */ return box_type; @@ -667,7 +670,8 @@ static int restore_dsp_rettings(struct echoaudio *chip) { int i, o, err; - if ((err = check_asic_status(chip)) < 0) + err = check_asic_status(chip); + if (err < 0) return err; /* Gina20/Darla20 only. Should be harmless for other cards. */ diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c index eea6fe530ab4..248983fa2959 100644 --- a/sound/pci/echoaudio/echoaudio_gml.c +++ b/sound/pci/echoaudio/echoaudio_gml.c @@ -194,7 +194,8 @@ static int set_professional_spdif(struct echoaudio *chip, char prof) } } - if ((err = write_control_reg(chip, control_reg, false))) + err = write_control_reg(chip, control_reg, false); + if (err) return err; chip->professional_spdif = prof; dev_dbg(chip->card->dev, "set_professional_spdif to %s\n", diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index b2377573de09..c93939850357 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c @@ -40,7 +40,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -58,7 +59,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 8eff2b4f5ceb..56e9d1b9b330 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c @@ -44,7 +44,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA24)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -74,7 +75,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_CDROM; } - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index c97dc83bbbdf..16eb082df56a 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c @@ -41,7 +41,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -56,7 +57,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->asic_loaded = true; chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index 2428b35f45d6..17a1d888d0b9 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c @@ -41,7 +41,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJ)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -56,7 +57,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->asic_loaded = true; chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 79b68ba70936..791787aa0744 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c @@ -41,7 +41,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IO)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -56,7 +57,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->asic_loaded = true; chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 5e5b6e288a2d..5fb5c4a4598b 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c @@ -43,7 +43,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -60,7 +61,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->output_clock_types = ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index c02bc1dcc170..ef27805d63f6 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -43,7 +43,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA24)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -62,11 +63,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; - if ((err = init_line_levels(chip)) < 0) + err = init_line_levels(chip); + if (err < 0) return err; return err; diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index 8f612a09c5d0..8a4dffc68889 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c @@ -44,7 +44,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -62,7 +63,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index 6045a115cffe..cb72d27e809e 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -308,8 +308,8 @@ static int snd_echo_midi_create(struct snd_card *card, { int err; - if ((err = snd_rawmidi_new(card, card->shortname, 0, 1, 1, - &chip->rmidi)) < 0) + err = snd_rawmidi_new(card, card->shortname, 0, 1, 1, &chip->rmidi); + if (err < 0) return err; strcpy(chip->rmidi->name, card->shortname); diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index f77db83dd73d..f8e7bb6ce040 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c @@ -44,7 +44,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if (snd_BUG_ON((subdevice_id & 0xfff0) != MONA)) return -ENODEV; - if ((err = init_dsp_comm_page(chip))) { + err = init_dsp_comm_page(chip); + if (err) { dev_err(chip->card->dev, "init_hw - could not initialize DSP comm page\n"); return err; @@ -67,7 +68,8 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) else chip->dsp_code_to_load = FW_MONA_301_DSP; - if ((err = load_firmware(chip)) < 0) + err = load_firmware(chip); + if (err < 0) return err; chip->bad_board = false; diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 45833bc2a7e7..887bfb3c1e17 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -107,18 +107,22 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, max_buffer_size[dev] = 32; else if (max_buffer_size[dev] > 1024) max_buffer_size[dev] = 1024; - if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev], - (long)max_buffer_size[dev] * 1024 * 1024, - enable_ir[dev], subsystem[dev], - &emu)) < 0) + err = snd_emu10k1_create(card, pci, extin[dev], extout[dev], + (long)max_buffer_size[dev] * 1024 * 1024, + enable_ir[dev], subsystem[dev], + &emu); + if (err < 0) goto error; card->private_data = emu; emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; - if ((err = snd_emu10k1_pcm(emu, 0)) < 0) + err = snd_emu10k1_pcm(emu, 0); + if (err < 0) goto error; - if ((err = snd_emu10k1_pcm_mic(emu, 1)) < 0) + err = snd_emu10k1_pcm_mic(emu, 1); + if (err < 0) goto error; - if ((err = snd_emu10k1_pcm_efx(emu, 2)) < 0) + err = snd_emu10k1_pcm_efx(emu, 2); + if (err < 0) goto error; /* This stores the periods table. */ if (emu->card_capabilities->ca0151_chip) { /* P16V */ @@ -128,26 +132,33 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, goto error; } - if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) + err = snd_emu10k1_mixer(emu, 0, 3); + if (err < 0) goto error; - if ((err = snd_emu10k1_timer(emu, 0)) < 0) + err = snd_emu10k1_timer(emu, 0); + if (err < 0) goto error; - if ((err = snd_emu10k1_pcm_multi(emu, 3)) < 0) + err = snd_emu10k1_pcm_multi(emu, 3); + if (err < 0) goto error; if (emu->card_capabilities->ca0151_chip) { /* P16V */ - if ((err = snd_p16v_pcm(emu, 4)) < 0) + err = snd_p16v_pcm(emu, 4); + if (err < 0) goto error; } if (emu->audigy) { - if ((err = snd_emu10k1_audigy_midi(emu)) < 0) + err = snd_emu10k1_audigy_midi(emu); + if (err < 0) goto error; } else { - if ((err = snd_emu10k1_midi(emu)) < 0) + err = snd_emu10k1_midi(emu); + if (err < 0) goto error; } - if ((err = snd_emu10k1_fx8010_new(emu, 0)) < 0) + err = snd_emu10k1_fx8010_new(emu, 0); + if (err < 0) goto error; #ifdef ENABLE_SYNTH if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, @@ -174,7 +185,8 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", card->shortname, emu->revision, emu->serial, emu->port, emu->irq); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto error; if (emu->card_capabilities->emu_model) diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 07471c3dcbed..dba1e9fc2eec 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -90,7 +90,8 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) if (best[i].voice >= 0) { int ch; vp = &emu->voices[best[i].voice]; - if ((ch = vp->ch) < 0) { + ch = vp->ch; + if (ch < 0) { /* dev_warn(emu->card->dev, "synth_get_voice: ch < 0 (%d) ??", i); diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index d9a12cd01647..89b0f3884067 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -349,7 +349,8 @@ static void snd_emu10k1x_pcm_interrupt(struct emu10k1x *emu, struct emu10k1x_voi { struct emu10k1x_pcm *epcm; - if ((epcm = voice->epcm) == NULL) + epcm = voice->epcm; + if (!epcm) return; if (epcm->substream == NULL) return; @@ -371,10 +372,11 @@ static int snd_emu10k1x_playback_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; - } - if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) + err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (err < 0) return err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); @@ -550,10 +552,12 @@ static int snd_emu10k1x_pcm_open_capture(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) - return err; - if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) - return err; + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + return err; + err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (err < 0) + return err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) @@ -722,7 +726,8 @@ static int snd_emu10k1x_ac97(struct emu10k1x *chip) .read = snd_emu10k1x_ac97_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; pbus->no_vra = 1; /* we don't need VRA */ @@ -838,7 +843,8 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device) if (device == 0) capture = 1; - if ((err = snd_pcm_new(emu->card, "emu10k1x", device, 1, capture, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1x", device, 1, capture, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -891,7 +897,8 @@ static int snd_emu10k1x_create(struct snd_card *card, *rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28)) < 0) { @@ -914,8 +921,8 @@ static int snd_emu10k1x_create(struct snd_card *card, spin_lock_init(&chip->voice_lock); chip->port = pci_resource_start(pci, 0); - if ((chip->res_port = request_region(chip->port, 8, - "EMU10K1X")) == NULL) { + chip->res_port = request_region(chip->port, 8, "EMU10K1X"); + if (!chip->res_port) { dev_err(card->dev, "cannot allocate the port 0x%lx\n", chip->port); snd_emu10k1x_free(chip); @@ -991,8 +998,8 @@ static int snd_emu10k1x_create(struct snd_card *card, outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_emu10k1x_free(chip); return err; } @@ -1171,17 +1178,23 @@ static int snd_emu10k1x_mixer(struct emu10k1x *emu) struct snd_kcontrol *kctl; struct snd_card *card = emu->card; - if ((kctl = snd_ctl_new1(&snd_emu10k1x_spdif_mask_control, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1x_spdif_mask_control, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = snd_ctl_new1(&snd_emu10k1x_shared_spdif, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1x_shared_spdif, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = snd_ctl_new1(&snd_emu10k1x_spdif_control, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1x_spdif_control, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; return 0; @@ -1488,7 +1501,8 @@ static int emu10k1x_midi_init(struct emu10k1x *emu, struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi); + if (err < 0) return err; midi->emu = emu; spin_lock_init(&midi->open_lock); @@ -1511,7 +1525,8 @@ static int snd_emu10k1x_midi(struct emu10k1x *emu) struct emu10k1x_midi *midi = &emu->midi; int err; - if ((err = emu10k1x_midi_init(emu, midi, 0, "EMU10K1X MPU-401 (UART)")) < 0) + err = emu10k1x_midi_init(emu, midi, 0, "EMU10K1X MPU-401 (UART)"); + if (err < 0) return err; midi->tx_enable = INTE_MIDITXENABLE; @@ -1543,35 +1558,42 @@ static int snd_emu10k1x_probe(struct pci_dev *pci, if (err < 0) return err; - if ((err = snd_emu10k1x_create(card, pci, &chip)) < 0) { + err = snd_emu10k1x_create(card, pci, &chip); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_pcm(chip, 0)) < 0) { + err = snd_emu10k1x_pcm(chip, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_pcm(chip, 1)) < 0) { + err = snd_emu10k1x_pcm(chip, 1); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_pcm(chip, 2)) < 0) { + err = snd_emu10k1x_pcm(chip, 2); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_ac97(chip)) < 0) { + err = snd_emu10k1x_ac97(chip); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_mixer(chip)) < 0) { + err = snd_emu10k1x_mixer(chip); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_emu10k1x_midi(chip)) < 0) { + err = snd_emu10k1x_midi(chip); + if (err < 0) { snd_card_free(card); return err; } @@ -1583,7 +1605,8 @@ static int snd_emu10k1x_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->port, chip->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 80ef62a4a7c0..6cf7c8b1de47 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -436,7 +436,8 @@ int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu, unsigned long flags; spin_lock_irqsave(&emu->fx8010.irq_lock, flags); - if ((tmp = emu->fx8010.irq_handlers) == irq) { + tmp = emu->fx8010.irq_handlers; + if (tmp == irq) { emu->fx8010.irq_handlers = tmp->next; if (emu->fx8010.irq_handlers == NULL) { snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); @@ -871,7 +872,9 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, } knew.private_value = (unsigned long)ctl; *ctl = *nctl; - if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { + kctl = snd_ctl_new1(&knew, emu); + err = snd_ctl_add(emu->card, kctl); + if (err < 0) { kfree(ctl); kfree(knew.tlv.p); goto __error; @@ -2403,7 +2406,8 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) while (ptr < 0x200) OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000); - if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0) + err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size); + if (err < 0) goto __err; icode->gpr_add_control_count = i; icode->gpr_add_controls = controls; @@ -2681,7 +2685,8 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device) struct snd_hwdep *hw; int err; - if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0) + err = snd_hwdep_new(emu->card, "FX8010", device, &hw); + if (err < 0) return err; strcpy(hw->name, "EMU10K1 (FX8010)"); hw->iface = SNDRV_HWDEP_IFACE_EMU10K1; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 8a6cbe67e29d..e9c0fe3b8446 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1119,7 +1119,8 @@ static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp = reg & ~A_SPDIF_RATE_MASK; tmp |= val; - if ((change = (tmp != reg))) + change = (tmp != reg); + if (change) snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); spin_unlock_irqrestore(&emu->reg_lock, flags); return change; @@ -1903,7 +1904,8 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, .read = snd_emu10k1_ac97_read, }; - if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; pbus->no_vra = 1; /* we don't need VRA */ @@ -1911,7 +1913,8 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, ac97.private_data = emu; ac97.private_free = snd_emu10k1_mixer_free_ac97; ac97.scaps = AC97_SCAP_NO_SPDIF; - if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) { + err = snd_ac97_mixer(pbus, &ac97, &emu->ac97); + if (err < 0) { if (emu->card_capabilities->ac97_chip == 1) return err; dev_info(emu->card->dev, @@ -1991,38 +1994,50 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); } - if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) + kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = pcm_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) + kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = pcm_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) + kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = pcm_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) + kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = multi_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) + kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = multi_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) + kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = multi_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; /* initialize the routing and volume table for each pcm playback stream */ @@ -2069,42 +2084,53 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ /* sb live! and audigy */ - if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu); + if (!kctl) return -ENOMEM; if (!emu->audigy) kctl->id.device = emu->pcm_efx->device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu); + if (!kctl) return -ENOMEM; if (!emu->audigy) kctl->id.device = emu->pcm_efx->device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; } if (emu->card_capabilities->emu_model) { ; /* Disable the snd_audigy_spdif_shared_spdif */ } else if (emu->audigy) { - if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) + kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; #if 0 - if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) + kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; #endif } else if (! emu->card_capabilities->ecard) { /* sb live! */ - if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; } if (emu->card_capabilities->ca0151_chip) { /* P16V */ - if ((err = snd_p16v_mixer(emu))) + err = snd_p16v_mixer(emu); + if (err) return err; } diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index b62c95150702..3ce9b2129ce6 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -319,7 +319,8 @@ static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *m struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi); + if (err < 0) return err; midi->emu = emu; spin_lock_init(&midi->open_lock); @@ -342,7 +343,8 @@ int snd_emu10k1_midi(struct snd_emu10k1 *emu) struct snd_emu10k1_midi *midi = &emu->midi; int err; - if ((err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)")) < 0) + err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)"); + if (err < 0) return err; midi->tx_enable = INTE_MIDITXENABLE; @@ -360,7 +362,8 @@ int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) int err; midi = &emu->midi; - if ((err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)")) < 0) + err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)"); + if (err < 0) return err; midi->tx_enable = INTE_MIDITXENABLE; @@ -371,7 +374,8 @@ int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) midi->interrupt = snd_emu10k1_midi_interrupt; midi = &emu->midi2; - if ((err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2")) < 0) + err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2"); + if (err < 0) return err; midi->tx_enable = INTE_A_MIDITXENABLE2; diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index b2ddabb99438..b2701a4452d8 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -25,7 +25,8 @@ static void snd_emu10k1_pcm_interrupt(struct snd_emu10k1 *emu, { struct snd_emu10k1_pcm *epcm; - if ((epcm = voice->epcm) == NULL) + epcm = voice->epcm; + if (!epcm) return; if (epcm->substream == NULL) return; @@ -399,7 +400,8 @@ static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream, size_t alloc_size; int err; - if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0) + err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params)); + if (err < 0) return err; alloc_size = params_buffer_bytes(hw_params); @@ -1124,11 +1126,13 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) runtime->private_data = epcm; runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_playback; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) { kfree(epcm); return err; } - if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0) { + err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); + if (err < 0) { kfree(epcm); return err; } @@ -1380,7 +1384,8 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -1412,7 +1417,8 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -1446,7 +1452,8 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -1774,7 +1781,8 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) struct snd_kcontrol *kctl; int err; - if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm); + if (err < 0) return err; pcm->private_data = emu; diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 288e0fd2e47d..9d26535f3fa3 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -169,16 +169,20 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) struct snd_emu10k1_memblk *q; /* calculate the expected size of empty region */ - if ((p = blk->mapped_link.prev) != &emu->mapped_link_head) { + p = blk->mapped_link.prev; + if (p != &emu->mapped_link_head) { q = get_emu10k1_memblk(p, mapped_link); start_page = q->mapped_page + q->pages; - } else + } else { start_page = 1; - if ((p = blk->mapped_link.next) != &emu->mapped_link_head) { + } + p = blk->mapped_link.next; + if (p != &emu->mapped_link_head) { q = get_emu10k1_memblk(p, mapped_link); end_page = q->mapped_page; - } else + } else { end_page = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0); + } /* remove links */ list_del(&blk->mapped_link); @@ -267,7 +271,8 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b spin_unlock_irqrestore(&emu->memblk_lock, flags); return 0; } - if ((err = map_memblk(emu, blk)) < 0) { + err = map_memblk(emu, blk); + if (err < 0) { /* no enough page - try to unmap some blocks */ /* starting from the oldest block */ p = emu->mapped_order_link_head.next; @@ -454,13 +459,15 @@ static void get_single_page_range(struct snd_util_memhdr *hdr, struct snd_emu10k1_memblk *q; int first_page, last_page; first_page = blk->first_page; - if ((p = blk->mem.list.prev) != &hdr->block) { + p = blk->mem.list.prev; + if (p != &hdr->block) { q = get_emu10k1_memblk(p, mem.list); if (q->last_page == first_page) first_page++; /* first page was already allocated */ } last_page = blk->last_page; - if ((p = blk->mem.list.next) != &hdr->block) { + p = blk->mem.list.next; + if (p != &hdr->block) { q = get_emu10k1_memblk(p, mem.list); if (q->first_page == last_page) last_page--; /* last page was already allocated */ diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 1099f102b365..ff2a3974c824 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -194,7 +194,8 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea #endif /* debug */ /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ channel->epcm = epcm; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; runtime->sync.id32[0] = substream->pcm->card->number; @@ -242,7 +243,8 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream #endif /* debug */ /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ channel->epcm = epcm; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; return 0; @@ -589,7 +591,8 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */ emu->p16v_device_offset = device; - if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) + err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -808,8 +811,8 @@ int snd_p16v_mixer(struct snd_emu10k1 *emu) struct snd_card *card = emu->card; for (i = 0; i < ARRAY_SIZE(p16v_mixer_controls); i++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&p16v_mixer_controls[i], - emu))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&p16v_mixer_controls[i], emu)); + if (err < 0) return err; } return 0; diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index c2803000aace..2435d3ba68f7 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -72,7 +72,8 @@ int snd_emu10k1_timer(struct snd_emu10k1 *emu, int device) tid.card = emu->card->number; tid.device = device; tid.subdevice = 0; - if ((err = snd_timer_new(emu->card, "EMU10K1", &tid, &timer)) >= 0) { + err = snd_timer_new(emu->card, "EMU10K1", &tid, &timer); + if (err >= 0) { strcpy(timer->name, "EMU10K1 timer"); timer->private_data = emu; timer->hw = snd_emu10k1_timer_hw; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 3ccccdbc0029..728b69dad21b 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -672,7 +672,8 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, } /* now wait for the stinkin' data (RDY) */ for (t = 0; t < POLL_COUNT; t++) { - if ((x = inl(ES_REG(ensoniq, 1371_CODEC))) & ES_1371_CODEC_RDY) { + x = inl(ES_REG(ensoniq, 1371_CODEC)); + if (x & ES_1371_CODEC_RDY) { if (is_ev1938(ensoniq)) { for (t = 0; t < 100; t++) inl(ES_REG(ensoniq, CONTROL)); @@ -1594,7 +1595,8 @@ static int snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, .wait = snd_es1371_codec_wait, }; - if ((err = snd_ac97_bus(card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(card, 0, &ops, NULL, &pbus); + if (err < 0) return err; memset(&ac97, 0, sizeof(ac97)); @@ -1602,7 +1604,8 @@ static int snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, ac97.private_free = snd_ensoniq_mixer_free_ac97; ac97.pci = ensoniq->pci; ac97.scaps = AC97_SCAP_AUDIO; - if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0) + err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97); + if (err < 0) return err; if (has_spdif > 0 || (!has_spdif && es1371_quirk_lookup(ensoniq, es1371_spdif_present))) { @@ -1722,7 +1725,8 @@ static int snd_ensoniq_1370_mixer(struct ensoniq *ensoniq) ak4531.write = snd_es1370_codec_write; ak4531.private_data = ensoniq; ak4531.private_free = snd_ensoniq_mixer_free_ak4531; - if ((err = snd_ak4531_mixer(card, &ak4531, &ensoniq->u.es1370.ak4531)) < 0) + err = snd_ak4531_mixer(card, &ak4531, &ensoniq->u.es1370.ak4531); + if (err < 0) return err; for (idx = 0; idx < ES1370_CONTROLS; idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_es1370_controls[idx], ensoniq)); @@ -2038,7 +2042,8 @@ static int snd_ensoniq_create(struct snd_card *card, }; *rensoniq = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; ensoniq = kzalloc(sizeof(*ensoniq), GFP_KERNEL); if (ensoniq == NULL) { @@ -2050,7 +2055,8 @@ static int snd_ensoniq_create(struct snd_card *card, ensoniq->card = card; ensoniq->pci = pci; ensoniq->irq = -1; - if ((err = pci_request_regions(pci, "Ensoniq AudioPCI")) < 0) { + err = pci_request_regions(pci, "Ensoniq AudioPCI"); + if (err < 0) { kfree(ensoniq); pci_disable_device(pci); return err; @@ -2095,7 +2101,8 @@ static int snd_ensoniq_create(struct snd_card *card, snd_ensoniq_chip_init(ensoniq); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ensoniq, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ensoniq, &ops); + if (err < 0) { snd_ensoniq_free(ensoniq); return err; } @@ -2286,7 +2293,8 @@ static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device) struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi); + if (err < 0) return err; strcpy(rmidi->name, CHIP_NAME); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ensoniq_midi_output); @@ -2357,33 +2365,39 @@ static int snd_audiopci_probe(struct pci_dev *pci, if (err < 0) return err; - if ((err = snd_ensoniq_create(card, pci, &ensoniq)) < 0) { + err = snd_ensoniq_create(card, pci, &ensoniq); + if (err < 0) { snd_card_free(card); return err; } card->private_data = ensoniq; #ifdef CHIP1370 - if ((err = snd_ensoniq_1370_mixer(ensoniq)) < 0) { + err = snd_ensoniq_1370_mixer(ensoniq); + if (err < 0) { snd_card_free(card); return err; } #endif #ifdef CHIP1371 - if ((err = snd_ensoniq_1371_mixer(ensoniq, spdif[dev], lineio[dev])) < 0) { + err = snd_ensoniq_1371_mixer(ensoniq, spdif[dev], lineio[dev]); + if (err < 0) { snd_card_free(card); return err; } #endif - if ((err = snd_ensoniq_pcm(ensoniq, 0)) < 0) { + err = snd_ensoniq_pcm(ensoniq, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_ensoniq_pcm2(ensoniq, 1)) < 0) { + err = snd_ensoniq_pcm2(ensoniq, 1); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_ensoniq_midi(ensoniq, 0)) < 0) { + err = snd_ensoniq_midi(ensoniq, 0); + if (err < 0) { snd_card_free(card); return err; } @@ -2399,7 +2413,8 @@ static int snd_audiopci_probe(struct pci_dev *pci, ensoniq->port, ensoniq->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index afc66347d162..33b1eb347a27 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -293,7 +293,8 @@ static void snd_es1938_write_cmd(struct es1938 *chip, unsigned char cmd) int i; unsigned char v; for (i = 0; i < WRITE_LOOP_TIMEOUT; i++) { - if (!(v = inb(SLSB_REG(chip, READSTATUS)) & 0x80)) { + v = inb(SLSB_REG(chip, READSTATUS)); + if (!(v & 0x80)) { outb(cmd, SLSB_REG(chip, WRITEDATA)); return; } @@ -309,9 +310,11 @@ static int snd_es1938_get_byte(struct es1938 *chip) { int i; unsigned char v; - for (i = GET_LOOP_TIMEOUT; i; i--) - if ((v = inb(SLSB_REG(chip, STATUS))) & 0x80) + for (i = GET_LOOP_TIMEOUT; i; i--) { + v = inb(SLSB_REG(chip, STATUS)); + if (v & 0x80) return inb(SLSB_REG(chip, READDATA)); + } dev_err(chip->card->dev, "get_byte timeout: status 0x02%x\n", v); return -ENODEV; } @@ -993,7 +996,8 @@ static int snd_es1938_new_pcm(struct es1938 *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "es-1938-1946", device, 2, 1, &pcm)) < 0) + err = snd_pcm_new(chip->card, "es-1938-1946", device, 2, 1, &pcm); + if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1938_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1938_capture_ops); @@ -1553,7 +1557,8 @@ static int snd_es1938_create(struct snd_card *card, *rchip = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; /* check, if we can restrict PCI DMA transfers to 24 bits */ if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) { @@ -1573,7 +1578,8 @@ static int snd_es1938_create(struct snd_card *card, chip->card = card; chip->pci = pci; chip->irq = -1; - if ((err = pci_request_regions(pci, "ESS Solo-1")) < 0) { + err = pci_request_regions(pci, "ESS Solo-1"); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -1599,7 +1605,8 @@ static int snd_es1938_create(struct snd_card *card, snd_es1938_chip_init(chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_es1938_free(chip); return err; } @@ -1731,7 +1738,8 @@ static int snd_es1938_mixer(struct es1938 *chip) kctl->private_free = snd_es1938_hwv_free; break; } - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) return err; } return 0; @@ -1765,7 +1773,8 @@ static int snd_es1938_probe(struct pci_dev *pci, return -ENODEV; } } - if ((err = snd_es1938_create(card, pci, &chip)) < 0) { + err = snd_es1938_create(card, pci, &chip); + if (err < 0) { snd_card_free(card); return err; } @@ -1778,11 +1787,13 @@ static int snd_es1938_probe(struct pci_dev *pci, chip->revision, chip->irq); - if ((err = snd_es1938_new_pcm(chip, 0)) < 0) { + err = snd_es1938_new_pcm(chip, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_es1938_mixer(chip)) < 0) { + err = snd_es1938_mixer(chip); + if (err < 0) { snd_card_free(card); return err; } @@ -1793,11 +1804,13 @@ static int snd_es1938_probe(struct pci_dev *pci, dev_err(card->dev, "OPL3 not detected at 0x%lx\n", SLSB_REG(chip, FMLOWADDR)); } else { - if ((err = snd_opl3_timer_new(opl3, 0, 1)) < 0) { + err = snd_opl3_timer_new(opl3, 0, 1); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) { snd_card_free(card); return err; } @@ -1815,7 +1828,8 @@ static int snd_es1938_probe(struct pci_dev *pci, snd_es1938_create_gameport(chip); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 5fa1861236f5..c038c1035c39 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1600,7 +1600,8 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream) es->mode = ESM_MODE_CAPTURE; /* get mixbuffer */ - if ((es->mixbuf = snd_es1968_new_memory(chip, ESM_MIXBUF_SIZE)) == NULL) { + es->mixbuf = snd_es1968_new_memory(chip, ESM_MIXBUF_SIZE); + if (!es->mixbuf) { snd_es1968_free_apu_pair(chip, apu1); snd_es1968_free_apu_pair(chip, apu2); kfree(es); @@ -1695,11 +1696,13 @@ static void es1968_measure_clock(struct es1968 *chip) chip->clock = 48000; /* default clock value */ /* search 2 APUs (although one apu is enough) */ - if ((apu = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY)) < 0) { + apu = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY); + if (apu < 0) { dev_err(chip->card->dev, "Hmm, cannot find empty APU pair!?\n"); return; } - if ((memory = snd_es1968_new_memory(chip, CLOCK_MEASURE_BUFSIZE)) == NULL) { + memory = snd_es1968_new_memory(chip, CLOCK_MEASURE_BUFSIZE); + if (!memory) { dev_warn(chip->card->dev, "cannot allocate dma buffer - using default clock %d\n", chip->clock); @@ -1791,7 +1794,8 @@ snd_es1968_pcm(struct es1968 *chip, int device) int err; /* get DMA buffer */ - if ((err = snd_es1968_init_dmabuf(chip)) < 0) + err = snd_es1968_init_dmabuf(chip); + if (err < 0) return err; /* set PCMBAR */ @@ -1800,9 +1804,10 @@ snd_es1968_pcm(struct es1968 *chip, int device) wave_set_register(chip, 0x01FE, chip->dma.addr >> 12); wave_set_register(chip, 0x01FF, chip->dma.addr >> 12); - if ((err = snd_pcm_new(chip->card, "ESS Maestro", device, - chip->playback_streams, - chip->capture_streams, &pcm)) < 0) + err = snd_pcm_new(chip->card, "ESS Maestro", device, + chip->playback_streams, + chip->capture_streams, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -1953,7 +1958,8 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) struct es1968 *chip = dev_id; u32 event; - if (!(event = inb(chip->io_port + 0x1A))) + event = inb(chip->io_port + 0x1A); + if (!event) return IRQ_NONE; outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); @@ -2008,13 +2014,15 @@ snd_es1968_mixer(struct es1968 *chip) .read = snd_es1968_ac97_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; pbus->no_vra = 1; /* ES1968 doesn't need VRA */ memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; - if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) + err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); + if (err < 0) return err; #ifndef CONFIG_SND_ES1968_INPUT @@ -2661,7 +2669,8 @@ static int snd_es1968_create(struct snd_card *card, *chip_ret = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; /* check, if we can restrict PCI DMA transfers to 28 bits */ if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28))) { @@ -2692,7 +2701,8 @@ static int snd_es1968_create(struct snd_card *card, chip->playback_streams = play_streams; chip->capture_streams = capt_streams; - if ((err = pci_request_regions(pci, "ESS Maestro")) < 0) { + err = pci_request_regions(pci, "ESS Maestro"); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -2739,7 +2749,8 @@ static int snd_es1968_create(struct snd_card *card, snd_es1968_chip_init(chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_es1968_free(chip); return err; } @@ -2804,14 +2815,15 @@ static int snd_es1968_probe(struct pci_dev *pci, total_bufsize[dev] = 128; if (total_bufsize[dev] > 4096) total_bufsize[dev] = 4096; - if ((err = snd_es1968_create(card, pci, - total_bufsize[dev] * 1024, /* in bytes */ - pcm_substreams_p[dev], - pcm_substreams_c[dev], - pci_id->driver_data, - use_pm[dev], - radio_nr[dev], - &chip)) < 0) { + err = snd_es1968_create(card, pci, + total_bufsize[dev] * 1024, /* in bytes */ + pcm_substreams_p[dev], + pcm_substreams_c[dev], + pci_id->driver_data, + use_pm[dev], + radio_nr[dev], + &chip); + if (err < 0) { snd_card_free(card); return err; } @@ -2832,12 +2844,14 @@ static int snd_es1968_probe(struct pci_dev *pci, break; } - if ((err = snd_es1968_pcm(chip, 0)) < 0) { + err = snd_es1968_pcm(chip, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_es1968_mixer(chip)) < 0) { + err = snd_es1968_mixer(chip); + if (err < 0) { snd_card_free(card); return err; } @@ -2855,13 +2869,13 @@ static int snd_es1968_probe(struct pci_dev *pci, } } if (enable_mpu[dev]) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - chip->io_port + ESM_MPU401_PORT, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi)) < 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + chip->io_port + ESM_MPU401_PORT, + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi); + if (err < 0) dev_warn(card->dev, "skipping MPU-401 MIDI support..\n"); - } } snd_es1968_create_gameport(chip, dev); @@ -2882,7 +2896,8 @@ static int snd_es1968_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->io_port, chip->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 6279eb156e36..ed9dae87145b 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -659,7 +659,8 @@ static int snd_fm801_playback_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels); } - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; return 0; } @@ -674,7 +675,8 @@ static int snd_fm801_capture_open(struct snd_pcm_substream *substream) runtime->hw = snd_fm801_capture; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; return 0; } @@ -717,7 +719,8 @@ static int snd_fm801_pcm(struct fm801 *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm)) < 0) + err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm); + if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_fm801_playback_ops); @@ -985,7 +988,8 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol, struct fm801 *chip = snd_kcontrol_chip(kcontrol); unsigned short val; - if ((val = ucontrol->value.enumerated.item[0]) > 4) + val = ucontrol->value.enumerated.item[0]; + if (val > 4) return -EINVAL; return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); } @@ -1050,19 +1054,22 @@ static int snd_fm801_mixer(struct fm801 *chip) .read = snd_fm801_codec_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus); + if (err < 0) return err; chip->ac97_bus->private_free = snd_fm801_mixer_free_ac97_bus; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_fm801_mixer_free_ac97; - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97); + if (err < 0) return err; if (chip->secondary) { ac97.num = 1; ac97.addr = chip->secondary_addr; - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_sec)) < 0) + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_sec); + if (err < 0) return err; } for (i = 0; i < FM801_CONTROLS; i++) { @@ -1213,7 +1220,8 @@ static int snd_fm801_create(struct snd_card *card, }; *rchip = NULL; - if ((err = pcim_enable_device(pci)) < 0) + err = pcim_enable_device(pci); + if (err < 0) return err; chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -1223,7 +1231,8 @@ static int snd_fm801_create(struct snd_card *card, chip->dev = &pci->dev; chip->irq = -1; chip->tea575x_tuner = tea575x_tuner; - if ((err = pci_request_regions(pci, "FM801")) < 0) + err = pci_request_regions(pci, "FM801"); + if (err < 0) return err; chip->port = pci_resource_start(pci, 0); @@ -1254,7 +1263,8 @@ static int snd_fm801_create(struct snd_card *card, snd_fm801_chip_init(chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_fm801_free(chip); return err; } @@ -1327,7 +1337,8 @@ static int snd_card_fm801_probe(struct pci_dev *pci, 0, &card); if (err < 0) return err; - if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip)) < 0) { + err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip); + if (err < 0) { snd_card_free(card); return err; } @@ -1342,35 +1353,41 @@ static int snd_card_fm801_probe(struct pci_dev *pci, if (chip->tea575x_tuner & TUNER_ONLY) goto __fm801_tuner_only; - if ((err = snd_fm801_pcm(chip, 0)) < 0) { + err = snd_fm801_pcm(chip, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_fm801_mixer(chip)) < 0) { + err = snd_fm801_mixer(chip); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, - chip->port + FM801_MPU401_DATA, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &chip->rmidi)) < 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, + chip->port + FM801_MPU401_DATA, + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3_create(card, chip->port + FM801_OPL3_BANK0, - chip->port + FM801_OPL3_BANK1, - OPL3_HW_OPL3_FM801, 1, &opl3)) < 0) { + err = snd_opl3_create(card, chip->port + FM801_OPL3_BANK0, + chip->port + FM801_OPL3_BANK1, + OPL3_HW_OPL3_FM801, 1, &opl3); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) { snd_card_free(card); return err; } __fm801_tuner_only: - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 17a25e453f60..e8dee24c309d 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -167,8 +167,11 @@ static void hda_codec_driver_shutdown(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); - if (!pm_runtime_suspended(dev) && codec->patch_ops.reboot_notify) - codec->patch_ops.reboot_notify(codec); + if (!pm_runtime_suspended(dev)) { + if (codec->patch_ops.reboot_notify) + codec->patch_ops.reboot_notify(codec); + snd_hda_codec_display_power(codec, false); + } } int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5462f771c2f9..7a717e151156 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -798,7 +798,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); /* enable/disable display power per codec */ -static void codec_display_power(struct hda_codec *codec, bool enable) +void snd_hda_codec_display_power(struct hda_codec *codec, bool enable) { if (codec->display_power_control) snd_hdac_display_power(&codec->bus->core, codec->addr, enable); @@ -810,7 +810,7 @@ void snd_hda_codec_register(struct hda_codec *codec) if (codec->registered) return; if (device_is_registered(hda_codec_dev(codec))) { - codec_display_power(codec, true); + snd_hda_codec_display_power(codec, true); pm_runtime_enable(hda_codec_dev(codec)); /* it was powered up in snd_hda_codec_new(), now all done */ snd_hda_power_down(codec); @@ -836,7 +836,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) */ if (codec->core.type == HDA_DEV_LEGACY) snd_hdac_device_unregister(&codec->core); - codec_display_power(codec, false); + snd_hda_codec_display_power(codec, false); /* * In the case of ASoC HD-audio bus, the device refcount is released in @@ -2893,7 +2893,7 @@ static int hda_codec_runtime_suspend(struct device *dev) (codec_has_clkstop(codec) && codec_has_epss(codec) && (state & AC_PWRST_CLK_STOP_OK))) snd_hdac_codec_link_down(&codec->core); - codec_display_power(codec, false); + snd_hda_codec_display_power(codec, false); return 0; } @@ -2905,7 +2905,7 @@ static int hda_codec_runtime_resume(struct device *dev) if (!codec->card) return 0; - codec_display_power(codec, true); + snd_hda_codec_display_power(codec, true); snd_hdac_codec_link_up(&codec->core); hda_call_codec_resume(codec); pm_runtime_mark_last_busy(dev); diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 1f8018f9ce57..e97d00585e8e 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1433,7 +1433,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs, path = snd_hda_add_new_path(codec, dac, pin, 0); } if (!path) { - dac = dacs[i] = 0; + dacs[i] = 0; badness += bad->no_dac; } else { /* print_nid_path(codec, "output", path); */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 470753b36c8a..0322b289505e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -883,6 +883,14 @@ static unsigned int azx_get_pos_skl(struct azx *chip, struct azx_dev *azx_dev) return azx_get_pos_posbuf(chip, azx_dev); } +static void azx_shutdown_chip(struct azx *chip) +{ + azx_stop_chip(chip); + azx_enter_link_reset(chip); + azx_clear_irq_pending(chip); + display_power(chip, false); +} + #ifdef CONFIG_PM static DEFINE_MUTEX(card_list_lock); static LIST_HEAD(card_list); @@ -942,14 +950,6 @@ static bool azx_is_pm_ready(struct snd_card *card) return true; } -static void __azx_runtime_suspend(struct azx *chip) -{ - azx_stop_chip(chip); - azx_enter_link_reset(chip); - azx_clear_irq_pending(chip); - display_power(chip, false); -} - static void __azx_runtime_resume(struct azx *chip) { struct hda_intel *hda = container_of(chip, struct hda_intel, chip); @@ -1028,7 +1028,7 @@ static int azx_suspend(struct device *dev) chip = card->private_data; bus = azx_bus(chip); - __azx_runtime_suspend(chip); + azx_shutdown_chip(chip); if (bus->irq >= 0) { free_irq(bus->irq, chip); bus->irq = -1; @@ -1107,7 +1107,7 @@ static int azx_runtime_suspend(struct device *dev) /* enable controller wake up event */ azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | STATESTS_INT_MASK); - __azx_runtime_suspend(chip); + azx_shutdown_chip(chip); trace_azx_runtime_suspend(chip); return 0; } @@ -2385,7 +2385,7 @@ static void azx_shutdown(struct pci_dev *pci) return; chip = card->private_data; if (chip && chip->running) - azx_stop_chip(chip); + azx_shutdown_chip(chip); } /* PCI IDs */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 4c5589c10f1d..8d2503e8dad8 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -709,6 +709,8 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld, #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); +void snd_hda_codec_display_power(struct hda_codec *codec, bool enable); + /* */ #define codec_err(codec, fmt, args...) \ diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 6f2b743b9d75..ea700395bef4 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -235,11 +235,9 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) { struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); struct hdac_bus *bus = azx_bus(chip); - struct device *dev = hda->dev; struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hda->regs = devm_ioremap_resource(dev, res); + hda->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(hda->regs)) return PTR_ERR(hda->regs); @@ -262,6 +260,9 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) const char *sname, *drv_name = "tegra-hda"; struct device_node *np = pdev->dev.of_node; + if (irq_id < 0) + return irq_id; + err = hda_tegra_init_chip(chip, pdev); if (err) return err; diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 49b4fdd2feab..b66e7bdbf483 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7598,7 +7598,7 @@ static void ca0132_alt_free_active_dma_channels(struct hda_codec *codec) */ static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec) { - const unsigned int dsp_dma_stream_ids[] = { 0x0c, 0x03, 0x04 }; + static const unsigned int dsp_dma_stream_ids[] = { 0x0c, 0x03, 0x04 }; struct ca0132_spec *spec = codec->spec; unsigned int i, tmp; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ab5113cccffa..493d8ee2642a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -385,6 +385,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); fallthrough; case 0x10ec0215: + case 0x10ec0230: case 0x10ec0233: case 0x10ec0235: case 0x10ec0236: @@ -3054,6 +3055,7 @@ enum { ALC269_TYPE_ALC257, ALC269_TYPE_ALC215, ALC269_TYPE_ALC225, + ALC269_TYPE_ALC287, ALC269_TYPE_ALC294, ALC269_TYPE_ALC300, ALC269_TYPE_ALC623, @@ -3090,6 +3092,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC257: case ALC269_TYPE_ALC215: case ALC269_TYPE_ALC225: + case ALC269_TYPE_ALC287: case ALC269_TYPE_ALC294: case ALC269_TYPE_ALC300: case ALC269_TYPE_ALC623: @@ -3153,6 +3156,7 @@ static void alc_disable_headset_jack_key(struct hda_codec *codec) alc_update_coef_idx(codec, 0x49, 0x0045, 0x0); alc_update_coef_idx(codec, 0x44, 0x0045 << 8, 0x0); break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_write_coef_idx(codec, 0x48, 0x0); @@ -3180,6 +3184,7 @@ static void alc_enable_headset_jack_key(struct hda_codec *codec) alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045); alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8); break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_write_coef_idx(codec, 0x48, 0xd011); @@ -3558,12 +3563,70 @@ static void alc256_shutup(struct hda_codec *codec) } } +static void alc285_hp_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = alc_get_hp_pin(spec); + int i, val; + int coef38, coef0d, coef36; + + alc_update_coef_idx(codec, 0x4a, 1<<15, 1<<15); /* Reset HP JD */ + coef38 = alc_read_coef_idx(codec, 0x38); /* Amp control */ + coef0d = alc_read_coef_idx(codec, 0x0d); /* Digital Misc control */ + coef36 = alc_read_coef_idx(codec, 0x36); /* Passthrough Control */ + alc_update_coef_idx(codec, 0x38, 1<<4, 0x0); + alc_update_coef_idx(codec, 0x0d, 0x110, 0x0); + + alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); + + if (hp_pin) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + msleep(130); + alc_update_coef_idx(codec, 0x36, 1<<14, 1<<14); + alc_update_coef_idx(codec, 0x36, 1<<13, 0x0); + + if (hp_pin) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + msleep(10); + alc_write_coef_idx(codec, 0x67, 0x0); /* Set HP depop to manual mode */ + alc_write_coefex_idx(codec, 0x58, 0x00, 0x7880); + alc_write_coefex_idx(codec, 0x58, 0x0f, 0xf049); + alc_update_coefex_idx(codec, 0x58, 0x03, 0x00f0, 0x00c0); + + alc_write_coefex_idx(codec, 0x58, 0x00, 0xf888); /* HP depop procedure start */ + val = alc_read_coefex_idx(codec, 0x58, 0x00); + for (i = 0; i < 20 && val & 0x8000; i++) { + msleep(50); + val = alc_read_coefex_idx(codec, 0x58, 0x00); + } /* Wait for depop procedure finish */ + + alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */ + alc_update_coef_idx(codec, 0x38, 1<<4, coef38); + alc_update_coef_idx(codec, 0x0d, 0x110, coef0d); + alc_update_coef_idx(codec, 0x36, 3<<13, coef36); + + msleep(50); + alc_update_coef_idx(codec, 0x4a, 1<<15, 0); +} + static void alc225_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; hda_nid_t hp_pin = alc_get_hp_pin(spec); bool hp1_pin_sense, hp2_pin_sense; + if (spec->codec_variant != ALC269_TYPE_ALC287) + /* required only at boot or S3 and S4 resume time */ + if (!spec->done_hp_init || + is_s3_resume(codec) || + is_s4_resume(codec)) { + alc285_hp_init(codec); + spec->done_hp_init = true; + } + if (!hp_pin) hp_pin = 0x21; msleep(30); @@ -4744,6 +4807,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0255: alc_process_coef_fw(codec, coef0255); break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_process_coef_fw(codec, coef0256); @@ -4858,6 +4922,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_process_coef_fw(codec, coef0255); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_write_coef_idx(codec, 0x45, 0xc489); @@ -5007,6 +5072,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) case 0x10ec0255: alc_process_coef_fw(codec, coef0255); break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_write_coef_idx(codec, 0x1b, 0x0e4b); @@ -5105,6 +5171,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) case 0x10ec0255: alc_process_coef_fw(codec, coef0255); break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_process_coef_fw(codec, coef0256); @@ -5218,6 +5285,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0255: alc_process_coef_fw(codec, coef0255); break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_process_coef_fw(codec, coef0256); @@ -5318,6 +5386,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_write_coef_idx(codec, 0x1b, 0x0e4b); @@ -5611,6 +5680,7 @@ static void alc255_set_default_jack_type(struct hda_codec *codec) case 0x10ec0255: alc_process_coef_fw(codec, alc255fw); break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: alc_process_coef_fw(codec, alc256fw); @@ -6211,6 +6281,7 @@ static void alc_combo_jack_hp_jd_restart(struct hda_codec *codec) alc_update_coef_idx(codec, 0x4a, 0x8000, 1 << 15); /* Reset HP JD */ alc_update_coef_idx(codec, 0x4a, 0x8000, 0 << 15); break; + case 0x10ec0230: case 0x10ec0235: case 0x10ec0236: case 0x10ec0255: @@ -6343,6 +6414,24 @@ static void alc_fixup_no_int_mic(struct hda_codec *codec, } } +static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const hda_nid_t conn[] = { 0x02 }; + static const struct hda_pintbl pincfgs[] = { + { 0x14, 0x90170110 }, /* rear speaker */ + { } + }; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_apply_pincfgs(codec, pincfgs); + /* force front speaker to DAC1 */ + snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); + break; + } +} + /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" @@ -7810,6 +7899,8 @@ static const struct hda_fixup alc269_fixups[] = { { 0x20, AC_VERB_SET_PROC_COEF, 0x4e4b }, { } }, + .chained = true, + .chain_id = ALC289_FIXUP_ASUS_GA401, }, [ALC285_FIXUP_HP_GPIO_LED] = { .type = HDA_FIXUP_FUNC, @@ -8127,13 +8218,8 @@ static const struct hda_fixup alc269_fixups[] = { .chain_id = ALC269_FIXUP_HP_LINE1_MIC1_LED, }, [ALC285_FIXUP_HP_SPECTRE_X360] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x90170110 }, /* enable top speaker */ - {} - }, - .chained = true, - .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1, + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_spectre_x360, }, [ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP] = { .type = HDA_FIXUP_FUNC, @@ -8319,6 +8405,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN), SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360), + SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), @@ -8336,13 +8423,19 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x87f1, "HP ProBook 630 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f2, "HP ProBook 640 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), + SND_PCI_QUIRK(0x103c, 0x880d, "HP EliteBook 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8862, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8863, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8870, "HP ZBook Fury 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8873, "HP ZBook Studio 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), @@ -8425,7 +8518,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x152d, 0x1082, "Quanta NL3", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x1558, 0x1323, "Clevo N130ZU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0x1325, "System76 Darter Pro (darp5)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x1325, "Clevo N15[01][CW]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x1401, "Clevo L140[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x1403, "Clevo N140CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -8460,11 +8553,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8535, "Clevo NH50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8536, "Clevo NH79D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0x8550, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0x8551, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0x8560, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1558, 0x8561, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[5|7][0-9]RZ[Q]", ALC269_FIXUP_DMIC), + SND_PCI_QUIRK(0x1558, 0x8550, "Clevo NH[57][0-9][ER][ACDH]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8551, "Clevo NH[57][0-9][ER][ACDH]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0x8560, "Clevo NH[57][0-9][ER][ACDH]Q", ALC269_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1558, 0x8561, "Clevo NH[57][0-9][ER][ACDH]Q", ALC269_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[57][0-9]RZ[Q]", ALC269_FIXUP_DMIC), SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -8475,8 +8568,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x9600, "Clevo N960K[PR]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x961d, "Clevo N960S[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x971d, "Clevo N970T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL53RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0xa600, "Clevo NL5XNU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL5[03]RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1558, 0xa600, "Clevo NL50NU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xb018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xb019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0xb022, "Clevo NH77D[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -9341,6 +9434,7 @@ static int patch_alc269(struct hda_codec *codec) spec->shutup = alc256_shutup; spec->init_hook = alc256_init; break; + case 0x10ec0230: case 0x10ec0236: case 0x10ec0256: spec->codec_variant = ALC269_TYPE_ALC256; @@ -9357,7 +9451,6 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0215: case 0x10ec0245: case 0x10ec0285: - case 0x10ec0287: case 0x10ec0289: spec->codec_variant = ALC269_TYPE_ALC215; spec->shutup = alc225_shutup; @@ -9372,6 +9465,12 @@ static int patch_alc269(struct hda_codec *codec) spec->init_hook = alc225_init; spec->gen.mixer_nid = 0; /* no loopback on ALC225, ALC295 and ALC299 */ break; + case 0x10ec0287: + spec->codec_variant = ALC269_TYPE_ALC287; + spec->shutup = alc225_shutup; + spec->init_hook = alc225_init; + spec->gen.mixer_nid = 0; /* no loopback on ALC287 */ + break; case 0x10ec0234: case 0x10ec0274: case 0x10ec0294: @@ -10632,6 +10731,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269), HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269), HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0230, "ALC236", patch_alc269), HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269), HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269), HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269), diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 1d2a0287284b..08adf4dd1303 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -676,13 +676,15 @@ static int snd_ice1712_delta_init(struct snd_ice1712 *ice) case ICE1712_SUBDEVICE_DELTA1010LT: case ICE1712_SUBDEVICE_VX442: case ICE1712_SUBDEVICE_DELTA66E: - if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { + err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c); + if (err < 0) { dev_err(ice->card->dev, "unable to create I2C bus\n"); return err; } ice->i2c->private_data = ice; ice->i2c->ops = &ap_cs8427_i2c_ops; - if ((err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR)) < 0) + err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR); + if (err < 0) return err; break; case ICE1712_SUBDEVICE_DELTA1010: diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 3794308313bf..8bb86b3c894e 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -442,7 +442,8 @@ static int snd_ice1712_ews_init(struct snd_ice1712 *ice) ice->spec = spec; /* create i2c */ - if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { + err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c); + if (err < 0) { dev_err(ice->card->dev, "unable to create I2C bus\n"); return err; } @@ -483,7 +484,8 @@ static int snd_ice1712_ews_init(struct snd_ice1712 *ice) if (err < 0) return err; /* Check if the front module is connected */ - if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0) + err = snd_ice1712_ews88mt_chip_select(ice, 0x0f); + if (err < 0) return err; break; case ICE1712_SUBDEVICE_EWS88D: @@ -498,12 +500,14 @@ static int snd_ice1712_ews_init(struct snd_ice1712 *ice) /* set up SPDIF interface */ switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_EWX2496: - if ((err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR)) < 0) + err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR); + if (err < 0) return err; snd_cs8427_reg_write(ice->cs8427, CS8427_REG_RECVERRMASK, CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR); break; case ICE1712_SUBDEVICE_DMX6FIRE: - if ((err = snd_ice1712_init_cs8427(ice, ICE1712_6FIRE_CS8427_ADDR)) < 0) + err = snd_ice1712_init_cs8427(ice, ICE1712_6FIRE_CS8427_ADDR); + if (err < 0) return err; snd_cs8427_reg_write(ice->cs8427, CS8427_REG_RECVERRMASK, CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR); break; @@ -853,7 +857,8 @@ static int snd_ice1712_6fire_control_get(struct snd_kcontrol *kcontrol, struct s int invert = (kcontrol->private_value >> 8) & 1; int data; - if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0) + data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT); + if (data < 0) return data; data = (data >> shift) & 1; if (invert) @@ -869,7 +874,8 @@ static int snd_ice1712_6fire_control_put(struct snd_kcontrol *kcontrol, struct s int invert = (kcontrol->private_value >> 8) & 1; int data, ndata; - if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0) + data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT); + if (data < 0) return data; ndata = data & ~(1 << shift); if (ucontrol->value.integer.value[0]) @@ -896,7 +902,8 @@ static int snd_ice1712_6fire_select_input_get(struct snd_kcontrol *kcontrol, str struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int data; - if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0) + data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT); + if (data < 0) return data; ucontrol->value.integer.value[0] = data & 3; return 0; @@ -907,7 +914,8 @@ static int snd_ice1712_6fire_select_input_put(struct snd_kcontrol *kcontrol, str struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int data, ndata; - if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0) + data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT); + if (data < 0) return data; ndata = data & ~3; ndata |= (ucontrol->value.integer.value[0] & 3); diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 5b124c4ad572..2d1bfbcba933 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -79,7 +79,7 @@ enum { \ ICH_REG_##name##_PICB = base + 0x08, /* word - position in current buffer */ \ ICH_REG_##name##_PIV = base + 0x0a, /* byte - prefetched index value */ \ ICH_REG_##name##_CR = base + 0x0b, /* byte - control register */ \ -}; +} /* busmaster blocks */ DEFINE_REGSET(OFF, 0); /* offset */ @@ -538,7 +538,8 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97, res = 0xffff; } else { res = iagetword(chip, reg + ac97->num * 0x80); - if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { + tmp = igetdword(chip, ICHREG(GLOB_STA)); + if (tmp & ICH_RCS) { /* reset RCS and preserve other R/WC bits */ iputdword(chip, ICHREG(GLOB_STA), tmp & ~(chip->codec_ready_bits | ICH_GSCI)); @@ -559,7 +560,8 @@ static void snd_intel8x0_codec_read_test(struct intel8x0 *chip, if (snd_intel8x0_codec_semaphore(chip, codec) >= 0) { iagetword(chip, codec * 0x80); - if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { + tmp = igetdword(chip, ICHREG(GLOB_STA)); + if (tmp & ICH_RCS) { /* reset RCS and preserve other R/WC bits */ iputdword(chip, ICHREG(GLOB_STA), tmp & ~(chip->codec_ready_bits | ICH_GSCI)); @@ -1105,7 +1107,8 @@ static int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ich runtime->hw.buffer_bytes_max = 64*1024; runtime->hw.period_bytes_max = 64*1024; } - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; runtime->private_data = ichdev; return 0; @@ -2190,7 +2193,8 @@ static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, udelay(1); } } - if ((err = snd_ac97_bus(chip->card, 0, ops, chip, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, ops, chip, &pbus); + if (err < 0) goto __err; pbus->private_free = snd_intel8x0_mixer_free_ac97_bus; if (ac97_clock >= 8000 && ac97_clock <= 48000) @@ -2206,7 +2210,8 @@ static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, ac97.pci = chip->pci; for (i = 0; i < codecs; i++) { ac97.num = i; - if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { + err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i]); + if (err < 0) { if (err != -EACCES) dev_err(chip->card->dev, "Unable to initialize codec #%d\n", i); @@ -2491,11 +2496,13 @@ static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing) int err; if (chip->device_type != DEVICE_ALI) { - if ((err = snd_intel8x0_ich_chip_init(chip, probing)) < 0) + err = snd_intel8x0_ich_chip_init(chip, probing); + if (err < 0) return err; iagetword(chip, 0); /* clear semaphore flag */ } else { - if ((err = snd_intel8x0_ali_chip_init(chip, probing)) < 0) + err = snd_intel8x0_ali_chip_init(chip, probing); + if (err < 0) return err; } @@ -2918,7 +2925,8 @@ static int snd_intel8x0_create(struct snd_card *card, *r_intel8x0 = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -2950,7 +2958,8 @@ static int snd_intel8x0_create(struct snd_card *card, pci->device == PCI_DEVICE_ID_INTEL_440MX) chip->fix_nocache = 1; /* enable workaround */ - if ((err = pci_request_regions(pci, card->shortname)) < 0) { + err = pci_request_regions(pci, card->shortname); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -3064,7 +3073,8 @@ static int snd_intel8x0_create(struct snd_card *card, for (i = 0; i < chip->max_codecs; i++) chip->codec_isr_bits |= chip->codec_bit[i]; - if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) { + err = snd_intel8x0_chip_init(chip, 1); + if (err < 0) { snd_intel8x0_free(chip); return err; } @@ -3079,7 +3089,8 @@ static int snd_intel8x0_create(struct snd_card *card, chip->irq = pci->irq; card->sync_irq = chip->irq; - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_intel8x0_free(chip); return err; } @@ -3186,18 +3197,20 @@ static int snd_intel8x0_probe(struct pci_dev *pci, buggy_irq = 0; } - if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, - &chip)) < 0) { + err = snd_intel8x0_create(card, pci, pci_id->driver_data, &chip); + if (err < 0) { snd_card_free(card); return err; } card->private_data = chip; - if ((err = snd_intel8x0_mixer(chip, ac97_clock, ac97_quirk)) < 0) { + err = snd_intel8x0_mixer(chip, ac97_clock, ac97_quirk); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_intel8x0_pcm(chip)) < 0) { + err = snd_intel8x0_pcm(chip); + if (err < 0) { snd_card_free(card); return err; } @@ -3217,7 +3230,8 @@ static int snd_intel8x0_probe(struct pci_dev *pci, } } - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 13ef838b26c1..b96fce6cbd83 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -57,7 +57,7 @@ enum { \ ICH_REG_##name##_PICB = base + 0x08, /* word - position in current buffer */ \ ICH_REG_##name##_PIV = base + 0x0a, /* byte - prefetched index value */ \ ICH_REG_##name##_CR = base + 0x0b, /* byte - control register */ \ -}; +} /* busmaster blocks */ DEFINE_REGSET(OFF, 0); /* offset */ @@ -342,7 +342,8 @@ static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97, res = 0xffff; } else { res = iagetword(chip, reg + ac97->num * 0x80); - if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { + tmp = igetdword(chip, ICHREG(GLOB_STA)); + if (tmp & ICH_RCS) { /* reset RCS and preserve other R/WC bits */ iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); @@ -800,7 +801,8 @@ static int snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock) glob_sta = igetdword(chip, ICHREG(GLOB_STA)); - if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus); + if (err < 0) goto __err; pbus->private_free = snd_intel8x0m_mixer_free_ac97_bus; if (ac97_clock >= 8000 && ac97_clock <= 48000) @@ -809,7 +811,8 @@ static int snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock) ac97.pci = chip->pci; ac97.num = glob_sta & ICH_SCR ? 1 : 0; - if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) { + err = snd_ac97_mixer(pbus, &ac97, &x97); + if (err < 0) { dev_err(chip->card->dev, "Unable to initialize codec #%d\n", ac97.num); if (ac97.num == 0) @@ -927,7 +930,8 @@ static int snd_intel8x0m_chip_init(struct intel8x0m *chip, int probing) unsigned int i; int err; - if ((err = snd_intel8x0m_ich_chip_init(chip, probing)) < 0) + err = snd_intel8x0m_ich_chip_init(chip, probing); + if (err < 0) return err; iagetword(chip, 0); /* clear semaphore flag */ @@ -1075,7 +1079,8 @@ static int snd_intel8x0m_create(struct snd_card *card, *r_intel8x0m = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -1089,7 +1094,8 @@ static int snd_intel8x0m_create(struct snd_card *card, chip->pci = pci; chip->irq = -1; - if ((err = pci_request_regions(pci, card->shortname)) < 0) { + err = pci_request_regions(pci, card->shortname); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -1167,7 +1173,8 @@ port_inited: pci_set_master(pci); - if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) { + err = snd_intel8x0m_chip_init(chip, 1); + if (err < 0) { snd_intel8x0m_free(chip); return err; } @@ -1181,7 +1188,8 @@ port_inited: chip->irq = pci->irq; card->sync_irq = chip->irq; - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_intel8x0m_free(chip); return err; } @@ -1238,17 +1246,20 @@ static int snd_intel8x0m_probe(struct pci_dev *pci, } strcat(card->shortname," Modem"); - if ((err = snd_intel8x0m_create(card, pci, pci_id->driver_data, &chip)) < 0) { + err = snd_intel8x0m_create(card, pci, pci_id->driver_data, &chip); + if (err < 0) { snd_card_free(card); return err; } card->private_data = chip; - if ((err = snd_intel8x0m_mixer(chip, ac97_clock)) < 0) { + err = snd_intel8x0m_mixer(chip, ac97_clock); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_intel8x0m_pcm(chip)) < 0) { + err = snd_intel8x0m_pcm(chip); + if (err < 0) { snd_card_free(card); return err; } @@ -1258,7 +1269,8 @@ static int snd_intel8x0m_probe(struct pci_dev *pci, sprintf(card->longname, "%s at irq %i", card->shortname, chip->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 80ac3c6152ad..030e01b062e4 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -1527,7 +1527,8 @@ static int snd_korg1212_hw_params(struct snd_pcm_substream *substream, return 0; } - if ((err = snd_korg1212_SetRate(korg1212, params_rate(params))) < 0) { + err = snd_korg1212_SetRate(korg1212, params_rate(params)); + if (err < 0) { spin_unlock_irqrestore(&korg1212->lock, flags); return err; } @@ -2159,7 +2160,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, }; * rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; korg1212 = kzalloc(sizeof(*korg1212), GFP_KERNEL); @@ -2196,7 +2198,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, for (i=0; i<kAudioChannels; i++) korg1212->volumePhase[i] = 0; - if ((err = pci_request_regions(pci, "korg1212")) < 0) { + err = pci_request_regions(pci, "korg1212"); + if (err < 0) { kfree(korg1212); pci_disable_device(pci); return err; @@ -2220,7 +2223,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, korg1212->iomem2, iomem2_size, stateName[korg1212->cardState]); - if ((korg1212->iobase = ioremap(korg1212->iomem, iomem_size)) == NULL) { + korg1212->iobase = ioremap(korg1212->iomem, iomem_size); + if (!korg1212->iobase) { snd_printk(KERN_ERR "korg1212: unable to remap memory region 0x%lx-0x%lx\n", korg1212->iomem, korg1212->iomem + iomem_size - 1); snd_korg1212_free(korg1212); @@ -2360,7 +2364,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: Reboot Card - RC = %d [%s]\n", rc, stateName[korg1212->cardState]); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, korg1212, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, korg1212, &ops); + if (err < 0) { snd_korg1212_free(korg1212); return err; } @@ -2385,7 +2390,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, korg1212->RoutingTablePhy, LowerWordSwap(korg1212->RoutingTablePhy), korg1212->AdatTimeCodePhy, LowerWordSwap(korg1212->AdatTimeCodePhy)); - if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm)) < 0) + err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm); + if (err < 0) return err; korg1212->pcm->private_data = korg1212; @@ -2436,7 +2442,8 @@ snd_korg1212_probe(struct pci_dev *pci, if (err < 0) return err; - if ((err = snd_korg1212_create(card, pci, &korg1212)) < 0) { + err = snd_korg1212_create(card, pci, &korg1212); + if (err < 0) { snd_card_free(card); return err; } @@ -2448,7 +2455,8 @@ snd_korg1212_probe(struct pci_dev *pci, K1212_DEBUG_PRINTK("K1212_DEBUG: %s\n", card->longname); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index f884f5a6a61c..d3f58a3d17fb 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -674,10 +674,6 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); u32 channels = runtime->channels; - if (runtime->channels != channels) - dev_err(chip->card->dev, "channel count mismatch: %d vs %d", - runtime->channels, channels); - mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index cdc4b6106252..77a484bc8c0d 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1765,7 +1765,8 @@ snd_m3_playback_open(struct snd_pcm_substream *subs) struct snd_pcm_runtime *runtime = subs->runtime; int err; - if ((err = snd_m3_substream_open(chip, subs)) < 0) + err = snd_m3_substream_open(chip, subs); + if (err < 0) return err; runtime->hw = snd_m3_playback; @@ -1789,7 +1790,8 @@ snd_m3_capture_open(struct snd_pcm_substream *subs) struct snd_pcm_runtime *runtime = subs->runtime; int err; - if ((err = snd_m3_substream_open(chip, subs)) < 0) + err = snd_m3_substream_open(chip, subs); + if (err < 0) return err; runtime->hw = snd_m3_capture; @@ -2036,12 +2038,14 @@ static int snd_m3_mixer(struct snd_m3 *chip) .read = snd_m3_ac97_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; - if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) + err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); + if (err < 0) return err; /* seems ac97 PCM needs initialization.. hack hack.. */ @@ -2642,16 +2646,19 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, if (err < 0) goto free_chip; - if ((err = snd_m3_mixer(chip)) < 0) + err = snd_m3_mixer(chip); + if (err < 0) return err; for (i = 0; i < chip->num_substreams; i++) { struct m3_dma *s = &chip->substreams[i]; - if ((err = snd_m3_assp_client_init(chip, s, i)) < 0) + err = snd_m3_assp_client_init(chip, s, i); + if (err < 0) return err; } - if ((err = snd_m3_pcm(chip, 0)) < 0) + err = snd_m3_pcm(chip, 0); + if (err < 0) return err; #ifdef CONFIG_SND_MAESTRO3_INPUT diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index a0bbb386dc25..1b078b789604 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -954,9 +954,10 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip) char name[32]; sprintf(name, "miXart analog %d", chip->chip_idx); - if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG, - MIXART_PLAYBACK_STREAMS, - MIXART_CAPTURE_STREAMS, &pcm)) < 0) { + err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG, + MIXART_PLAYBACK_STREAMS, + MIXART_CAPTURE_STREAMS, &pcm); + if (err < 0) { dev_err(chip->card->dev, "cannot create the analog pcm %d\n", chip->chip_idx); return err; @@ -987,9 +988,10 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip) char name[32]; sprintf(name, "miXart AES/EBU %d", chip->chip_idx); - if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL, - MIXART_PLAYBACK_STREAMS, - MIXART_CAPTURE_STREAMS, &pcm)) < 0) { + err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL, + MIXART_PLAYBACK_STREAMS, + MIXART_CAPTURE_STREAMS, &pcm); + if (err < 0) { dev_err(chip->card->dev, "cannot create the digital pcm %d\n", chip->chip_idx); return err; @@ -1042,7 +1044,8 @@ static int snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int chip->mgr = mgr; card->sync_irq = mgr->irq; - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_mixart_chip_free(chip); return err; } @@ -1243,7 +1246,8 @@ static int snd_mixart_probe(struct pci_dev *pci, } /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; pci_set_master(pci); @@ -1267,7 +1271,8 @@ static int snd_mixart_probe(struct pci_dev *pci, mgr->irq = -1; /* resource assignment */ - if ((err = pci_request_regions(pci, CARD_NAME)) < 0) { + err = pci_request_regions(pci, CARD_NAME); + if (err < 0) { kfree(mgr); pci_disable_device(pci); return err; @@ -1332,7 +1337,8 @@ static int snd_mixart_probe(struct pci_dev *pci, "Digigram miXart at 0x%lx & 0x%lx, irq %i [PCM #%d]", mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq, i); - if ((err = snd_mixart_create(mgr, card, i)) < 0) { + err = snd_mixart_create(mgr, card, i); + if (err < 0) { snd_card_free(card); snd_mixart_free(mgr); return err; @@ -1343,7 +1349,8 @@ static int snd_mixart_probe(struct pci_dev *pci, snd_mixart_proc_init(mgr->chip[i]); } - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_mixart_free(mgr); return err; } diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index f579f7698bba..689c0f995a9c 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -306,9 +306,13 @@ static int mixart_first_init(struct mixart_mgr *mgr) int err; struct mixart_msg request; - if((err = mixart_enum_connectors(mgr)) < 0) return err; + err = mixart_enum_connectors(mgr); + if (err < 0) + return err; - if((err = mixart_enum_physio(mgr)) < 0) return err; + err = mixart_enum_physio(mgr); + if (err < 0) + return err; /* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */ /* though why not here */ @@ -528,15 +532,18 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw for (card_index = 0; card_index < mgr->num_cards; card_index++) { struct snd_mixart *chip = mgr->chip[card_index]; - if ((err = snd_mixart_create_pcm(chip)) < 0) + err = snd_mixart_create_pcm(chip); + if (err < 0) return err; if (card_index == 0) { - if ((err = snd_mixart_create_mixer(chip->mgr)) < 0) + err = snd_mixart_create_mixer(chip->mgr); + if (err < 0) return err; } - if ((err = snd_card_register(chip->card)) < 0) + err = snd_card_register(chip->card); + if (err < 0) return err; } diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index d2e7c3381267..2727f3345795 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c @@ -1114,10 +1114,12 @@ int snd_mixart_create_mixer(struct mixart_mgr *mgr) temp = mixart_control_analog_level; temp.name = "Master Playback Volume"; temp.private_value = 0; /* playback */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; /* output mute controls */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_output_switch, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_output_switch, chip)); + if (err < 0) return err; /* analog input level control only on first two chips !*/ @@ -1125,7 +1127,8 @@ int snd_mixart_create_mixer(struct mixart_mgr *mgr) temp = mixart_control_analog_level; temp.name = "Master Capture Volume"; temp.private_value = 1; /* capture */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; } @@ -1133,45 +1136,53 @@ int snd_mixart_create_mixer(struct mixart_mgr *mgr) temp.name = "PCM Playback Volume"; temp.count = MIXART_PLAYBACK_STREAMS; temp.private_value = 0; /* playback analog */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; temp.name = "PCM Capture Volume"; temp.count = 1; temp.private_value = MIXART_VOL_REC_MASK; /* capture analog */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) { temp.name = "AES Playback Volume"; temp.count = MIXART_PLAYBACK_STREAMS; temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; temp.name = "AES Capture Volume"; temp.count = 0; temp.private_value = MIXART_VOL_REC_MASK | MIXART_VOL_AES_MASK; /* capture AES/EBU */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; } temp = mixart_control_pcm_switch; temp.name = "PCM Playback Switch"; temp.private_value = 0; /* playback analog */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) { temp.name = "AES Playback Switch"; temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip)); + if (err < 0) return err; } /* monitoring */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_vol, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_vol, chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_sw, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_sw, chip)); + if (err < 0) return err; /* init all mixer data and program the master volumes/switches */ diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 6cb689aa28c2..12d02d7d3b51 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1318,7 +1318,8 @@ snd_nm256_mixer(struct nm256 *chip) if (! chip->ac97_regs) return -ENOMEM; - if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; memset(&ac97, 0, sizeof(ac97)); @@ -1476,7 +1477,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, *chip_ret = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -1568,7 +1570,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, chip->buffer_end = buffer_top; else { /* get buffer end pointer from signature */ - if ((err = snd_nm256_peek_for_sig(chip)) < 0) + err = snd_nm256_peek_for_sig(chip); + if (err < 0) goto __error; } @@ -1618,7 +1621,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, // pci_set_master(pci); /* needed? */ - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) goto __error; *chip_ret = chip; @@ -1700,7 +1704,8 @@ static int snd_nm256_probe(struct pci_dev *pci, capture_bufsize = 4; if (capture_bufsize > 128) capture_bufsize = 128; - if ((err = snd_nm256_create(card, pci, &chip)) < 0) { + err = snd_nm256_create(card, pci, &chip); + if (err < 0) { snd_card_free(card); return err; } @@ -1716,8 +1721,13 @@ static int snd_nm256_probe(struct pci_dev *pci, chip->reset_workaround_2 = 1; } - if ((err = snd_nm256_pcm(chip, 0)) < 0 || - (err = snd_nm256_mixer(chip)) < 0) { + err = snd_nm256_pcm(chip, 0); + if (err < 0) { + snd_card_free(card); + return err; + } + err = snd_nm256_mixer(chip); + if (err < 0) { snd_card_free(card); return err; } @@ -1727,7 +1737,8 @@ static int snd_nm256_probe(struct pci_dev *pci, card->shortname, chip->buffer_addr, chip->cport_addr, chip->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 751f9744b089..96b9371c201a 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1134,9 +1134,10 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip) char name[32]; snprintf(name, sizeof(name), "pcxhr %d", chip->chip_idx); - if ((err = snd_pcm_new(chip->card, name, 0, - chip->nb_streams_play, - chip->nb_streams_capt, &pcm)) < 0) { + err = snd_pcm_new(chip->card, name, 0, + chip->nb_streams_play, + chip->nb_streams_capt, &pcm); + if (err < 0) { dev_err(chip->card->dev, "cannot create pcm %s\n", name); return err; } @@ -1202,7 +1203,8 @@ static int pcxhr_create(struct pcxhr_mgr *mgr, chip->nb_streams_capt = 1; /* or 1 stereo stream */ } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { pcxhr_chip_free(chip); return err; } @@ -1492,7 +1494,8 @@ static int pcxhr_probe(struct pci_dev *pci, } /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; pci_set_master(pci); @@ -1537,7 +1540,8 @@ static int pcxhr_probe(struct pci_dev *pci, mgr->granularity = PCXHR_GRANULARITY; /* resource assignment */ - if ((err = pci_request_regions(pci, card_name)) < 0) { + err = pci_request_regions(pci, card_name); + if (err < 0) { kfree(mgr); pci_disable_device(pci); return err; @@ -1608,7 +1612,8 @@ static int pcxhr_probe(struct pci_dev *pci, snprintf(card->longname, sizeof(card->longname), "%s [PCM #%d]", mgr->name, i); - if ((err = pcxhr_create(mgr, card, i)) < 0) { + err = pcxhr_create(mgr, card, i); + if (err < 0) { snd_card_free(card); pcxhr_free(mgr); return err; @@ -1618,7 +1623,8 @@ static int pcxhr_probe(struct pci_dev *pci, /* init proc interface only for chip0 */ pcxhr_proc_init(mgr->chip[i]); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { pcxhr_free(mgr); return err; } diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index 2258bd698844..249805065f61 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -322,14 +322,17 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, for (card_index = 0; card_index < mgr->num_cards; card_index++) { struct snd_pcxhr *chip = mgr->chip[card_index]; - if ((err = pcxhr_create_pcm(chip)) < 0) + err = pcxhr_create_pcm(chip); + if (err < 0) return err; if (card_index == 0) { - if ((err = pcxhr_create_mixer(chip->mgr)) < 0) + err = pcxhr_create_mixer(chip->mgr); + if (err < 0) return err; } - if ((err = snd_card_register(chip->card)) < 0) + err = snd_card_register(chip->card); + if (err < 0) return err; } err = pcxhr_start_pipes(mgr); diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 56827db97239..709a1a2cde20 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1087,9 +1087,15 @@ static irqreturn_t riptide_handleirq(int irq, void *dev_id) substream[i] = chip->playback_substream[i]; substream[i] = chip->capture_substream; for (i = 0; i < PLAYBACK_SUBSTREAMS + 1; i++) { - if (substream[i] && - (runtime = substream[i]->runtime) && - (data = runtime->private_data) && data->state != ST_STOP) { + if (!substream[i]) + continue; + runtime = substream[i]->runtime; + if (!runtime) + continue; + data = runtime->private_data; + if (!data) + continue; + if (data->state != ST_STOP) { pos = 0; for (j = 0; j < data->pages; j++) { c = &data->sgdbuf[j]; @@ -1549,10 +1555,10 @@ snd_riptide_hw_params(struct snd_pcm_substream *substream, (int)sgdlist->bytes); if (sgdlist->area) snd_dma_free_pages(sgdlist); - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - &chip->pci->dev, - sizeof(struct sgd) * (DESC_MAX_MASK + 1), - sgdlist)) < 0) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, + sizeof(struct sgd) * (DESC_MAX_MASK + 1), + sgdlist); + if (err < 0) { snd_printk(KERN_ERR "Riptide: failed to alloc %d dma bytes\n", (int)sizeof(struct sgd) * (DESC_MAX_MASK + 1)); return err; @@ -1677,9 +1683,9 @@ static int snd_riptide_pcm(struct snd_riptide *chip, int device) struct snd_pcm *pcm; int err; - if ((err = - snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1, - &pcm)) < 0) + err = snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1, + &pcm); + if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_riptide_playback_ops); @@ -1766,14 +1772,16 @@ static int snd_riptide_initialize(struct snd_riptide *chip) cif = chip->cif; if (!cif) { - if ((cif = kzalloc(sizeof(struct cmdif), GFP_KERNEL)) == NULL) + cif = kzalloc(sizeof(struct cmdif), GFP_KERNEL); + if (!cif) return -ENOMEM; cif->hwport = (struct riptideport *)chip->port; spin_lock_init(&cif->lock); chip->cif = cif; } cif->is_reset = 0; - if ((err = riptide_reset(cif, chip)) != 0) + err = riptide_reset(cif, chip); + if (err) return err; device_id = chip->device_id; switch (device_id) { @@ -1797,7 +1805,8 @@ static int snd_riptide_free(struct snd_riptide *chip) if (!chip) return 0; - if ((cif = chip->cif)) { + cif = chip->cif; + if (cif) { SET_GRESET(cif->hwport); udelay(100); UNSET_GRESET(cif->hwport); @@ -1830,9 +1839,11 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci, }; *rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; - if (!(chip = kzalloc(sizeof(struct snd_riptide), GFP_KERNEL))) + chip = kzalloc(sizeof(struct snd_riptide), GFP_KERNEL); + if (!chip) return -ENOMEM; spin_lock_init(&chip->lock); @@ -1845,8 +1856,8 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci, chip->handled_irqs = 0; chip->cif = NULL; - if ((chip->res_port = - request_region(chip->port, 64, "RIPTIDE")) == NULL) { + chip->res_port = request_region(chip->port, 64, "RIPTIDE"); + if (!chip->res_port) { snd_printk(KERN_ERR "Riptide: unable to grab region 0x%lx-0x%lx\n", chip->port, chip->port + 64 - 1); @@ -1868,12 +1879,14 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci, card->sync_irq = chip->irq; chip->device_id = pci->device; pci_set_master(pci); - if ((err = snd_riptide_initialize(chip)) < 0) { + err = snd_riptide_initialize(chip); + if (err < 0) { snd_riptide_free(chip); return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_riptide_free(chip); return err; } @@ -1903,7 +1916,8 @@ snd_riptide_proc_read(struct snd_info_entry *entry, for (i = 0; i < 64; i += 4) snd_iprintf(buffer, "%c%02x: %08x", (i % 16) ? ' ' : '\n', i, inl(chip->port + i)); - if ((cif = chip->cif)) { + cif = chip->cif; + if (cif) { snd_iprintf(buffer, "\nVersion: ASIC: %d CODEC: %d AUXDSP: %d PROG: %d", chip->firmware.firmware.ASIC, @@ -1922,10 +1936,11 @@ snd_riptide_proc_read(struct snd_info_entry *entry, } snd_iprintf(buffer, "\nOpen streams %d:\n", chip->openstreams); for (i = 0; i < PLAYBACK_SUBSTREAMS; i++) { - if (chip->playback_substream[i] - && chip->playback_substream[i]->runtime - && (data = - chip->playback_substream[i]->runtime->private_data)) { + if (!chip->playback_substream[i] || + !chip->playback_substream[i]->runtime) + continue; + data = chip->playback_substream[i]->runtime->private_data; + if (data) { snd_iprintf(buffer, "stream: %d mixer: %d source: %d (%d,%d)\n", data->id, data->mixer, data->source, @@ -1934,15 +1949,16 @@ snd_riptide_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "rate: %d\n", rate); } } - if (chip->capture_substream - && chip->capture_substream->runtime - && (data = chip->capture_substream->runtime->private_data)) { - snd_iprintf(buffer, - "stream: %d mixer: %d source: %d (%d,%d)\n", - data->id, data->mixer, - data->source, data->intdec[0], data->intdec[1]); - if (!(getsamplerate(cif, data->intdec, &rate))) - snd_iprintf(buffer, "rate: %d\n", rate); + if (chip->capture_substream && chip->capture_substream->runtime) { + data = chip->capture_substream->runtime->private_data; + if (data) { + snd_iprintf(buffer, + "stream: %d mixer: %d source: %d (%d,%d)\n", + data->id, data->mixer, + data->source, data->intdec[0], data->intdec[1]); + if (!(getsamplerate(cif, data->intdec, &rate))) + snd_iprintf(buffer, "rate: %d\n", rate); + } } snd_iprintf(buffer, "Paths:\n"); i = getpaths(cif, p); @@ -1973,12 +1989,14 @@ static int snd_riptide_mixer(struct snd_riptide *chip) ac97.private_data = chip; ac97.scaps = AC97_SCAP_SKIP_MODEM; - if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus); + if (err < 0) return err; chip->ac97_bus = pbus; ac97.pci = chip->pci; - if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) + err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); + if (err < 0) return err; return err; } diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 54f3e39f97f5..b5b357853c94 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -668,18 +668,24 @@ snd_rme32_playback_hw_params(struct snd_pcm_substream *substream, } spin_lock_irq(&rme32->lock); - if ((rme32->rcreg & RME32_RCR_KMODE) && - (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { + rate = 0; + if (rme32->rcreg & RME32_RCR_KMODE) + rate = snd_rme32_capture_getrate(rme32, &dummy); + if (rate > 0) { /* AutoSync */ if ((int)params_rate(params) != rate) { spin_unlock_irq(&rme32->lock); return -EIO; } - } else if ((err = snd_rme32_playback_setrate(rme32, params_rate(params))) < 0) { - spin_unlock_irq(&rme32->lock); - return err; + } else { + err = snd_rme32_playback_setrate(rme32, params_rate(params)); + if (err < 0) { + spin_unlock_irq(&rme32->lock); + return err; + } } - if ((err = snd_rme32_setformat(rme32, params_format(params))) < 0) { + err = snd_rme32_setformat(rme32, params_format(params)); + if (err < 0) { spin_unlock_irq(&rme32->lock); return err; } @@ -723,15 +729,18 @@ snd_rme32_capture_hw_params(struct snd_pcm_substream *substream, rme32->wcreg |= RME32_WCR_AUTOSYNC; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); - if ((err = snd_rme32_setformat(rme32, params_format(params))) < 0) { + err = snd_rme32_setformat(rme32, params_format(params)); + if (err < 0) { spin_unlock_irq(&rme32->lock); return err; } - if ((err = snd_rme32_playback_setrate(rme32, params_rate(params))) < 0) { + err = snd_rme32_playback_setrate(rme32, params_rate(params)); + if (err < 0) { spin_unlock_irq(&rme32->lock); return err; } - if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) { + rate = snd_rme32_capture_getrate(rme32, &isadat); + if (rate > 0) { if ((int)params_rate(params) != rate) { spin_unlock_irq(&rme32->lock); return -EIO; @@ -854,8 +863,10 @@ static int snd_rme32_playback_spdif_open(struct snd_pcm_substream *substream) runtime->hw.rates |= SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; } - if ((rme32->rcreg & RME32_RCR_KMODE) && - (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { + rate = 0; + if (rme32->rcreg & RME32_RCR_KMODE) + rate = snd_rme32_capture_getrate(rme32, &dummy); + if (rate > 0) { /* AutoSync */ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; @@ -895,7 +906,8 @@ static int snd_rme32_capture_spdif_open(struct snd_pcm_substream *substream) runtime->hw.rates |= SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; } - if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) { + rate = snd_rme32_capture_getrate(rme32, &isadat); + if (rate > 0) { if (isadat) { return -EIO; } @@ -932,8 +944,10 @@ snd_rme32_playback_adat_open(struct snd_pcm_substream *substream) runtime->hw = snd_rme32_adat_fd_info; else runtime->hw = snd_rme32_adat_info; - if ((rme32->rcreg & RME32_RCR_KMODE) && - (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { + rate = 0; + if (rme32->rcreg & RME32_RCR_KMODE) + rate = snd_rme32_capture_getrate(rme32, &dummy); + if (rate > 0) { /* AutoSync */ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; @@ -955,7 +969,8 @@ snd_rme32_capture_adat_open(struct snd_pcm_substream *substream) runtime->hw = snd_rme32_adat_fd_info; else runtime->hw = snd_rme32_adat_info; - if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) { + rate = snd_rme32_capture_getrate(rme32, &isadat); + if (rate > 0) { if (!isadat) { return -EIO; } @@ -1307,10 +1322,12 @@ static int snd_rme32_create(struct rme32 *rme32) rme32->irq = -1; spin_lock_init(&rme32->lock); - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; - if ((err = pci_request_regions(pci, "RME32")) < 0) + err = pci_request_regions(pci, "RME32"); + if (err < 0) return err; rme32->port = pci_resource_start(rme32->pci, 0); @@ -1334,9 +1351,9 @@ static int snd_rme32_create(struct rme32 *rme32) pci_read_config_byte(pci, 8, &rme32->rev); /* set up ALSA pcm device for S/PDIF */ - if ((err = snd_pcm_new(rme32->card, "Digi32 IEC958", 0, 1, 1, &rme32->spdif_pcm)) < 0) { + err = snd_pcm_new(rme32->card, "Digi32 IEC958", 0, 1, 1, &rme32->spdif_pcm); + if (err < 0) return err; - } rme32->spdif_pcm->private_data = rme32; rme32->spdif_pcm->private_free = snd_rme32_free_spdif_pcm; strcpy(rme32->spdif_pcm->name, "Digi32 IEC958"); @@ -1363,11 +1380,10 @@ static int snd_rme32_create(struct rme32 *rme32) rme32->adat_pcm = NULL; } else { - if ((err = snd_pcm_new(rme32->card, "Digi32 ADAT", 1, - 1, 1, &rme32->adat_pcm)) < 0) - { + err = snd_pcm_new(rme32->card, "Digi32 ADAT", 1, + 1, 1, &rme32->adat_pcm); + if (err < 0) return err; - } rme32->adat_pcm->private_data = rme32; rme32->adat_pcm->private_free = snd_rme32_free_adat_pcm; strcpy(rme32->adat_pcm->name, "Digi32 ADAT"); @@ -1410,9 +1426,9 @@ static int snd_rme32_create(struct rme32 *rme32) /* init switch interface */ - if ((err = snd_rme32_create_switches(rme32->card, rme32)) < 0) { + err = snd_rme32_create_switches(rme32->card, rme32); + if (err < 0) return err; - } /* init proc interface */ snd_rme32_proc_init(rme32); @@ -1855,7 +1871,9 @@ static int snd_rme32_create_switches(struct snd_card *card, struct rme32 * rme32 struct snd_kcontrol *kctl; for (idx = 0; idx < (int)ARRAY_SIZE(snd_rme32_controls); idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme32_controls[idx], rme32))) < 0) + kctl = snd_ctl_new1(&snd_rme32_controls[idx], rme32); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; if (idx == 1) /* IEC958 (S/PDIF) Stream */ rme32->spdif_ctl = kctl; @@ -1899,7 +1917,8 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) rme32->pci = pci; if (fullduplex[dev]) rme32->fullduplex_mode = 1; - if ((err = snd_rme32_create(rme32)) < 0) { + err = snd_rme32_create(rme32); + if (err < 0) { snd_card_free(card); return err; } @@ -1919,7 +1938,8 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) sprintf(card->longname, "%s (Rev. %d) at 0x%lx, irq %d", card->shortname, rme32->rev, rme32->port, rme32->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 66082e9f526d..fc7ac077559c 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -666,12 +666,14 @@ snd_rme96_playback_getrate(struct rme96 *rme96) int rate, dummy; if (!(rme96->wcreg & RME96_WCR_MASTER) && - snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && - (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) - { - /* slave clock */ - return rate; + snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG) { + rate = snd_rme96_capture_getrate(rme96, &dummy); + if (rate > 0) { + /* slave clock */ + return rate; + } } + rate = ((rme96->wcreg >> RME96_WCR_BITPOS_FREQ_0) & 1) + (((rme96->wcreg >> RME96_WCR_BITPOS_FREQ_1) & 1) << 1); switch (rate) { @@ -984,10 +986,11 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream, runtime->dma_bytes = RME96_BUFFER_SIZE; spin_lock_irq(&rme96->lock); + rate = 0; if (!(rme96->wcreg & RME96_WCR_MASTER) && - snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && - (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) - { + snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG) + rate = snd_rme96_capture_getrate(rme96, &dummy); + if (rate > 0) { /* slave clock */ if ((int)params_rate(params) != rate) { err = -EIO; @@ -1046,28 +1049,30 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream, runtime->dma_bytes = RME96_BUFFER_SIZE; spin_lock_irq(&rme96->lock); - if ((err = snd_rme96_capture_setformat(rme96, params_format(params))) < 0) { + err = snd_rme96_capture_setformat(rme96, params_format(params)); + if (err < 0) { spin_unlock_irq(&rme96->lock); return err; } if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { - if ((err = snd_rme96_capture_analog_setrate(rme96, - params_rate(params))) < 0) - { + err = snd_rme96_capture_analog_setrate(rme96, params_rate(params)); + if (err < 0) { spin_unlock_irq(&rme96->lock); return err; } - } else if ((rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) { - if ((int)params_rate(params) != rate) { - spin_unlock_irq(&rme96->lock); - return -EIO; - } - if ((isadat && runtime->hw.channels_min == 2) || - (!isadat && runtime->hw.channels_min == 8)) - { - spin_unlock_irq(&rme96->lock); - return -EIO; - } + } else { + rate = snd_rme96_capture_getrate(rme96, &isadat); + if (rate > 0) { + if ((int)params_rate(params) != rate) { + spin_unlock_irq(&rme96->lock); + return -EIO; + } + if ((isadat && runtime->hw.channels_min == 2) || + (!isadat && runtime->hw.channels_min == 8)) { + spin_unlock_irq(&rme96->lock); + return -EIO; + } + } } snd_rme96_setframelog(rme96, params_channels(params), 0); if (rme96->playback_periodsize != 0) { @@ -1160,8 +1165,10 @@ rme96_set_buffer_size_constraint(struct rme96 *rme96, snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE); - if ((size = rme96->playback_periodsize) != 0 || - (size = rme96->capture_periodsize) != 0) + size = rme96->playback_periodsize; + if (!size) + size = rme96->capture_periodsize; + if (size) snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, size); @@ -1191,13 +1198,14 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) runtime->hw = snd_rme96_playback_spdif_info; if (!(rme96->wcreg & RME96_WCR_MASTER) && - snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && - (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) - { - /* slave clock */ - runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); - runtime->hw.rate_min = rate; - runtime->hw.rate_max = rate; + snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG) { + rate = snd_rme96_capture_getrate(rme96, &dummy); + if (rate > 0) { + /* slave clock */ + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); + runtime->hw.rate_min = rate; + runtime->hw.rate_max = rate; + } } rme96_set_buffer_size_constraint(rme96, runtime); @@ -1217,16 +1225,16 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); runtime->hw = snd_rme96_capture_spdif_info; - if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && - (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) - { - if (isadat) { - return -EIO; - } - runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); - runtime->hw.rate_min = rate; - runtime->hw.rate_max = rate; - } + if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG) { + rate = snd_rme96_capture_getrate(rme96, &isadat); + if (rate > 0) { + if (isadat) + return -EIO; + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); + runtime->hw.rate_min = rate; + runtime->hw.rate_max = rate; + } + } spin_lock_irq(&rme96->lock); if (rme96->capture_substream) { @@ -1260,14 +1268,16 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream) runtime->hw = snd_rme96_playback_adat_info; if (!(rme96->wcreg & RME96_WCR_MASTER) && - snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && - (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) - { - /* slave clock */ - runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); - runtime->hw.rate_min = rate; - runtime->hw.rate_max = rate; - } + snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG) { + rate = snd_rme96_capture_getrate(rme96, &dummy); + if (rate > 0) { + /* slave clock */ + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); + runtime->hw.rate_min = rate; + runtime->hw.rate_max = rate; + } + } + rme96_set_buffer_size_constraint(rme96, runtime); return 0; } @@ -1286,7 +1296,8 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream) expension cards AEB4/8-I are RME96_INPUT_INTERNAL */ return -EIO; } - if ((rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) { + rate = snd_rme96_capture_getrate(rme96, &isadat); + if (rate > 0) { if (!isadat) { return -EIO; } @@ -1603,10 +1614,12 @@ snd_rme96_create(struct rme96 *rme96) rme96->irq = -1; spin_lock_init(&rme96->lock); - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; - if ((err = pci_request_regions(pci, "RME96")) < 0) + err = pci_request_regions(pci, "RME96"); + if (err < 0) return err; rme96->port = pci_resource_start(rme96->pci, 0); @@ -1630,11 +1643,11 @@ snd_rme96_create(struct rme96 *rme96) pci_read_config_byte(pci, 8, &rme96->rev); /* set up ALSA pcm device for S/PDIF */ - if ((err = snd_pcm_new(rme96->card, "Digi96 IEC958", 0, - 1, 1, &rme96->spdif_pcm)) < 0) - { + err = snd_pcm_new(rme96->card, "Digi96 IEC958", 0, + 1, 1, &rme96->spdif_pcm); + if (err < 0) return err; - } + rme96->spdif_pcm->private_data = rme96; rme96->spdif_pcm->private_free = snd_rme96_free_spdif_pcm; strcpy(rme96->spdif_pcm->name, "Digi96 IEC958"); @@ -1648,11 +1661,10 @@ snd_rme96_create(struct rme96 *rme96) /* ADAT is not available on the base model */ rme96->adat_pcm = NULL; } else { - if ((err = snd_pcm_new(rme96->card, "Digi96 ADAT", 1, - 1, 1, &rme96->adat_pcm)) < 0) - { + err = snd_pcm_new(rme96->card, "Digi96 ADAT", 1, + 1, 1, &rme96->adat_pcm); + if (err < 0) return err; - } rme96->adat_pcm->private_data = rme96; rme96->adat_pcm->private_free = snd_rme96_free_adat_pcm; strcpy(rme96->adat_pcm->name, "Digi96 ADAT"); @@ -1701,9 +1713,9 @@ snd_rme96_create(struct rme96 *rme96) } /* init switch interface */ - if ((err = snd_rme96_create_switches(rme96->card, rme96)) < 0) { + err = snd_rme96_create_switches(rme96->card, rme96); + if (err < 0) return err; - } /* init proc interface */ snd_rme96_proc_init(rme96); @@ -2336,16 +2348,20 @@ snd_rme96_create_switches(struct snd_card *card, struct snd_kcontrol *kctl; for (idx = 0; idx < 7; idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme96_controls[idx], rme96))) < 0) + kctl = snd_ctl_new1(&snd_rme96_controls[idx], rme96); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; if (idx == 1) /* IEC958 (S/PDIF) Stream */ rme96->spdif_ctl = kctl; } if (RME96_HAS_ANALOG_OUT(rme96)) { - for (idx = 7; idx < 10; idx++) - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_rme96_controls[idx], rme96))) < 0) + for (idx = 7; idx < 10; idx++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_rme96_controls[idx], rme96)); + if (err < 0) return err; + } } return 0; diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 720297cbdf87..8457a4bbc3df 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -289,7 +289,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); return 104857600000000 / rate; // 100 MHz return 110100480000000 / rate; // 105 MHz */ -#define DDS_NUMERATOR 104857600000000ULL; /* = 2^20 * 10^8 */ +#define DDS_NUMERATOR 104857600000000ULL /* = 2^20 * 10^8 */ #define hdsp_encode_latency(x) (((x)<<1) & HDSP_LatencyMask) #define hdsp_decode_latency(x) (((x) & HDSP_LatencyMask)>>1) @@ -1318,11 +1318,13 @@ static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi) spin_lock_irqsave (&hmidi->lock, flags); if (hmidi->output) { if (!snd_rawmidi_transmit_empty (hmidi->output)) { - if ((n_pending = snd_hdsp_midi_output_possible (hmidi->hdsp, hmidi->id)) > 0) { + n_pending = snd_hdsp_midi_output_possible(hmidi->hdsp, hmidi->id); + if (n_pending > 0) { if (n_pending > (int)sizeof (buf)) n_pending = sizeof (buf); - if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) { + to_write = snd_rawmidi_transmit(hmidi->output, buf, n_pending); + if (to_write > 0) { for (i = 0; i < to_write; ++i) snd_hdsp_midi_write_byte (hmidi->hdsp, hmidi->id, buf[i]); } @@ -1341,7 +1343,8 @@ static int snd_hdsp_midi_input_read (struct hdsp_midi *hmidi) int i; spin_lock_irqsave (&hmidi->lock, flags); - if ((n_pending = snd_hdsp_midi_input_available (hmidi->hdsp, hmidi->id)) > 0) { + n_pending = snd_hdsp_midi_input_available(hmidi->hdsp, hmidi->id); + if (n_pending > 0) { if (hmidi->input) { if (n_pending > (int)sizeof (buf)) n_pending = sizeof (buf); @@ -3322,7 +3325,9 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) } for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0) + kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; if (idx == 1) /* IEC958 (S/PDIF) Stream */ hdsp->spdif_ctl = kctl; @@ -3331,12 +3336,16 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) /* ADAT SyncCheck status */ snd_hdsp_adat_sync_check.name = "ADAT Lock Status"; snd_hdsp_adat_sync_check.index = 1; - if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) + kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; if (hdsp->io_type == Digiface || hdsp->io_type == H9652) { for (idx = 1; idx < 3; ++idx) { snd_hdsp_adat_sync_check.index = idx+1; - if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) + kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; } } @@ -3344,7 +3353,9 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) /* DA, AD and Phone gain and XLR breakout cable controls for H9632 cards */ if (hdsp->io_type == H9632) { for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_9632_controls); idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp))) < 0) + kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; } } @@ -3362,8 +3373,10 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) /* AEB control for H96xx card */ if (hdsp->io_type == H9632 || hdsp->io_type == H9652) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0) - return err; + kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp); + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; } return 0; @@ -3942,7 +3955,8 @@ static char *hdsp_channel_buffer_location(struct hdsp *hdsp, if (snd_BUG_ON(channel < 0 || channel >= hdsp->max_channels)) return NULL; - if ((mapped_channel = hdsp->channel_map[channel]) < 0) + mapped_channel = hdsp->channel_map[channel]; + if (mapped_channel < 0) return NULL; if (stream == SNDRV_PCM_STREAM_CAPTURE) @@ -4114,7 +4128,8 @@ static int snd_hdsp_hw_params(struct snd_pcm_substream *substream, spin_lock_irq(&hdsp->lock); if (! hdsp->clock_source_locked) { - if ((err = hdsp_set_rate(hdsp, params_rate(params), 0)) < 0) { + err = hdsp_set_rate(hdsp, params_rate(params), 0); + if (err < 0) { spin_unlock_irq(&hdsp->lock); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); return err; @@ -4122,7 +4137,8 @@ static int snd_hdsp_hw_params(struct snd_pcm_substream *substream, } spin_unlock_irq(&hdsp->lock); - if ((err = hdsp_set_interrupt_interval(hdsp, params_period_size(params))) < 0) { + err = hdsp_set_interrupt_interval(hdsp, params_period_size(params)); + if (err < 0) { _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return err; } @@ -4854,14 +4870,15 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL; if (hdsp->io_type == Undefined) { - if ((err = hdsp_get_iobox_version(hdsp)) < 0) + err = hdsp_get_iobox_version(hdsp); + if (err < 0) return err; } memset(&hdsp_version, 0, sizeof(hdsp_version)); hdsp_version.io_type = hdsp->io_type; hdsp_version.firmware_rev = hdsp->firmware_rev; - if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version)))) - return -EFAULT; + if (copy_to_user(argp, &hdsp_version, sizeof(hdsp_version))) + return -EFAULT; break; } case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: { @@ -4900,17 +4917,20 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne hdsp->state |= HDSP_FirmwareCached; - if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0) + err = snd_hdsp_load_firmware_from_cache(hdsp); + if (err < 0) return err; if (!(hdsp->state & HDSP_InitializationComplete)) { - if ((err = snd_hdsp_enable_io(hdsp)) < 0) + err = snd_hdsp_enable_io(hdsp); + if (err < 0) return err; snd_hdsp_initialize_channels(hdsp); snd_hdsp_initialize_midi_flush(hdsp); - if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) { + err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp); + if (err < 0) { dev_err(hdsp->card->dev, "error creating alsa devices\n"); return err; @@ -4960,7 +4980,8 @@ static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp) struct snd_hwdep *hw; int err; - if ((err = snd_hwdep_new(card, "HDSP hwdep", 0, &hw)) < 0) + err = snd_hwdep_new(card, "HDSP hwdep", 0, &hw); + if (err < 0) return err; hdsp->hwdep = hw; @@ -4978,7 +4999,8 @@ static int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(card, hdsp->card_name, 0, 1, 1, &pcm)) < 0) + err = snd_pcm_new(card, hdsp->card_name, 0, 1, 1, &pcm); + if (err < 0) return err; hdsp->pcm = pcm; @@ -5084,28 +5106,32 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp { int err; - if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) { + err = snd_hdsp_create_pcm(card, hdsp); + if (err < 0) { dev_err(card->dev, "Error creating pcm interface\n"); return err; } - if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) { + err = snd_hdsp_create_midi(card, hdsp, 0); + if (err < 0) { dev_err(card->dev, "Error creating first midi interface\n"); return err; } if (hdsp->io_type == Digiface || hdsp->io_type == H9652) { - if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) { + err = snd_hdsp_create_midi(card, hdsp, 1); + if (err < 0) { dev_err(card->dev, "Error creating second midi interface\n"); return err; } } - if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) { + err = snd_hdsp_create_controls(card, hdsp); + if (err < 0) { dev_err(card->dev, "Error creating ctl interface\n"); return err; @@ -5119,7 +5145,8 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp hdsp->capture_substream = NULL; hdsp->playback_substream = NULL; - if ((err = snd_hdsp_set_defaults(hdsp)) < 0) { + err = snd_hdsp_set_defaults(hdsp); + if (err < 0) { dev_err(card->dev, "Error setting default values\n"); return err; @@ -5130,7 +5157,8 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, hdsp->port, hdsp->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { dev_err(card->dev, "error registering card\n"); return err; @@ -5151,7 +5179,8 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; if (hdsp->io_type == Undefined) { - if ((err = hdsp_get_iobox_version(hdsp)) < 0) + err = hdsp_get_iobox_version(hdsp); + if (err < 0) return err; if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; @@ -5197,21 +5226,25 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) hdsp->state |= HDSP_FirmwareCached; - if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0) + err = snd_hdsp_load_firmware_from_cache(hdsp); + if (err < 0) return err; if (!(hdsp->state & HDSP_InitializationComplete)) { - if ((err = snd_hdsp_enable_io(hdsp)) < 0) + err = snd_hdsp_enable_io(hdsp); + if (err < 0) return err; - if ((err = snd_hdsp_create_hwdep(hdsp->card, hdsp)) < 0) { + err = snd_hdsp_create_hwdep(hdsp->card, hdsp); + if (err < 0) { dev_err(hdsp->card->dev, "error creating hwdep device\n"); return err; } snd_hdsp_initialize_channels(hdsp); snd_hdsp_initialize_midi_flush(hdsp); - if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) { + err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp); + if (err < 0) { dev_err(hdsp->card->dev, "error creating alsa devices\n"); return err; @@ -5280,15 +5313,18 @@ static int snd_hdsp_create(struct snd_card *card, is_9632 = 1; } - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; pci_set_master(hdsp->pci); - if ((err = pci_request_regions(pci, "hdsp")) < 0) + err = pci_request_regions(pci, "hdsp"); + if (err < 0) return err; hdsp->port = pci_resource_start(pci, 0); - if ((hdsp->iobase = ioremap(hdsp->port, HDSP_IO_EXTENT)) == NULL) { + hdsp->iobase = ioremap(hdsp->port, HDSP_IO_EXTENT); + if (!hdsp->iobase) { dev_err(hdsp->card->dev, "unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1); return -EBUSY; @@ -5306,7 +5342,8 @@ static int snd_hdsp_create(struct snd_card *card, hdsp->use_midi_work = 1; hdsp->dds_value = 0; - if ((err = snd_hdsp_initialize_memory(hdsp)) < 0) + err = snd_hdsp_initialize_memory(hdsp); + if (err < 0) return err; if (!is_9652 && !is_9632) { @@ -5318,7 +5355,8 @@ static int snd_hdsp_create(struct snd_card *card, return err; if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { - if ((err = hdsp_request_fw_loader(hdsp)) < 0) + err = hdsp_request_fw_loader(hdsp); + if (err < 0) /* we don't fail as this can happen if userspace is not ready for firmware upload @@ -5331,7 +5369,8 @@ static int snd_hdsp_create(struct snd_card *card, /* we defer initialization */ dev_info(hdsp->card->dev, "card initialization pending : waiting for firmware\n"); - if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) + err = snd_hdsp_create_hwdep(card, hdsp); + if (err < 0) return err; return 0; } else { @@ -5346,7 +5385,8 @@ static int snd_hdsp_create(struct snd_card *card, } } - if ((err = snd_hdsp_enable_io(hdsp)) != 0) + err = snd_hdsp_enable_io(hdsp); + if (err) return err; if (is_9652) @@ -5355,7 +5395,8 @@ static int snd_hdsp_create(struct snd_card *card, if (is_9632) hdsp->io_type = H9632; - if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) + err = snd_hdsp_create_hwdep(card, hdsp); + if (err < 0) return err; snd_hdsp_initialize_channels(hdsp); @@ -5363,7 +5404,8 @@ static int snd_hdsp_create(struct snd_card *card, hdsp->state |= HDSP_FirmwareLoaded; - if ((err = snd_hdsp_create_alsa_devices(card, hdsp)) < 0) + err = snd_hdsp_create_alsa_devices(card, hdsp); + if (err < 0) return err; return 0; diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 7a4d395abcee..f1aad38760d6 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -433,9 +433,9 @@ static int rme9652_set_interrupt_interval(struct snd_rme9652 *s, spin_lock_irq(&s->lock); - if ((restart = s->running)) { + restart = s->running; + if (restart) rme9652_stop(s); - } frames >>= 7; n = 0; @@ -518,16 +518,15 @@ static int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate) return -EBUSY; } - if ((restart = rme9652->running)) { + restart = rme9652->running; + if (restart) rme9652_stop(rme9652); - } rme9652->control_register &= ~(RME9652_freq | RME9652_DS); rme9652->control_register |= rate; rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); - if (restart) { + if (restart) rme9652_start(rme9652); - } if (rate & RME9652_DS) { if (rme9652->ss_channels == RME9652_NCHANNELS) { @@ -878,15 +877,14 @@ static int rme9652_set_adat1_input(struct snd_rme9652 *rme9652, int internal) /* XXX do we actually need to stop the card when we do this ? */ - if ((restart = rme9652->running)) { + restart = rme9652->running; + if (restart) rme9652_stop(rme9652); - } rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); - if (restart) { + if (restart) rme9652_start(rme9652); - } return 0; } @@ -943,15 +941,14 @@ static int rme9652_set_spdif_input(struct snd_rme9652 *rme9652, int in) rme9652->control_register &= ~RME9652_inp; rme9652->control_register |= rme9652_encode_spdif_in(in); - if ((restart = rme9652->running)) { + restart = rme9652->running; + if (restart) rme9652_stop(rme9652); - } rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); - if (restart) { + if (restart) rme9652_start(rme9652); - } return 0; } @@ -1010,15 +1007,14 @@ static int rme9652_set_spdif_output(struct snd_rme9652 *rme9652, int out) rme9652->control_register &= ~RME9652_opt_out; } - if ((restart = rme9652->running)) { + restart = rme9652->running; + if (restart) rme9652_stop(rme9652); - } rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); - if (restart) { + if (restart) rme9652_start(rme9652); - } return 0; } @@ -1086,15 +1082,14 @@ static int rme9652_set_sync_mode(struct snd_rme9652 *rme9652, int mode) break; } - if ((restart = rme9652->running)) { + restart = rme9652->running; + if (restart) rme9652_stop(rme9652); - } rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); - if (restart) { + if (restart) rme9652_start(rme9652); - } return 0; } @@ -1173,15 +1168,14 @@ static int rme9652_set_sync_pref(struct snd_rme9652 *rme9652, int pref) break; } - if ((restart = rme9652->running)) { + restart = rme9652->running; + if (restart) rme9652_stop(rme9652); - } rme9652_write(rme9652, RME9652_control_register, rme9652->control_register); - if (restart) { + if (restart) rme9652_start(rme9652); - } return 0; } @@ -1513,19 +1507,27 @@ static int snd_rme9652_create_controls(struct snd_card *card, struct snd_rme9652 struct snd_kcontrol *kctl; for (idx = 0; idx < ARRAY_SIZE(snd_rme9652_controls); idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_controls[idx], rme9652))) < 0) + kctl = snd_ctl_new1(&snd_rme9652_controls[idx], rme9652); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; if (idx == 1) /* IEC958 (S/PDIF) Stream */ rme9652->spdif_ctl = kctl; } - if (rme9652->ss_channels == RME9652_NCHANNELS) - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat3_check, rme9652))) < 0) + if (rme9652->ss_channels == RME9652_NCHANNELS) { + kctl = snd_ctl_new1(&snd_rme9652_adat3_check, rme9652); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; + } - if (rme9652->hw_rev >= 15) - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat1_input, rme9652))) < 0) + if (rme9652->hw_rev >= 15) { + kctl = snd_ctl_new1(&snd_rme9652_adat1_input, rme9652); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; + } return 0; } @@ -1842,9 +1844,9 @@ static char *rme9652_channel_buffer_location(struct snd_rme9652 *rme9652, if (snd_BUG_ON(channel < 0 || channel >= RME9652_NCHANNELS)) return NULL; - if ((mapped_channel = rme9652->channel_map[channel]) < 0) { + mapped_channel = rme9652->channel_map[channel]; + if (mapped_channel < 0) return NULL; - } if (stream == SNDRV_PCM_STREAM_CAPTURE) { return rme9652->capture_buffer + @@ -2021,12 +2023,14 @@ static int snd_rme9652_hw_params(struct snd_pcm_substream *substream, /* how to make sure that the rate matches an externally-set one ? */ - if ((err = rme9652_set_rate(rme9652, params_rate(params))) < 0) { + err = rme9652_set_rate(rme9652, params_rate(params)); + if (err < 0) { _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); return err; } - if ((err = rme9652_set_interrupt_interval(rme9652, params_period_size(params))) < 0) { + err = rme9652_set_interrupt_interval(rme9652, params_period_size(params)); + if (err < 0) { _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return err; } @@ -2406,11 +2410,9 @@ static int snd_rme9652_create_pcm(struct snd_card *card, struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(card, - rme9652->card_name, - 0, 1, 1, &pcm)) < 0) { + err = snd_pcm_new(card, rme9652->card_name, 0, 1, 1, &pcm); + if (err < 0) return err; - } rme9652->pcm = pcm; pcm->private_data = rme9652; @@ -2450,12 +2452,14 @@ static int snd_rme9652_create(struct snd_card *card, return -ENODEV; } - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; spin_lock_init(&rme9652->lock); - if ((err = pci_request_regions(pci, "rme9652")) < 0) + err = pci_request_regions(pci, "rme9652"); + if (err < 0) return err; rme9652->port = pci_resource_start(pci, 0); rme9652->iobase = ioremap(rme9652->port, RME9652_IO_EXTENT); @@ -2528,17 +2532,17 @@ static int snd_rme9652_create(struct snd_card *card, pci_set_master(rme9652->pci); - if ((err = snd_rme9652_initialize_memory(rme9652)) < 0) { + err = snd_rme9652_initialize_memory(rme9652); + if (err < 0) return err; - } - if ((err = snd_rme9652_create_pcm(card, rme9652)) < 0) { + err = snd_rme9652_create_pcm(card, rme9652); + if (err < 0) return err; - } - if ((err = snd_rme9652_create_controls(card, rme9652)) < 0) { + err = snd_rme9652_create_controls(card, rme9652); + if (err < 0) return err; - } snd_rme9652_proc_init(rme9652); diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 7de10997775f..03a48da897e3 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -852,7 +852,8 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(sonic->card, "s3_86c617", device, 1, 1, &pcm)) < 0) + err = snd_pcm_new(sonic->card, "s3_86c617", device, 1, 1, &pcm); + if (err < 0) return err; if (snd_BUG_ON(!pcm)) return -EINVAL; @@ -1093,7 +1094,9 @@ static int snd_sonicvibes_mixer(struct sonicvibes *sonic) strcpy(card->mixername, "S3 SonicVibes"); for (idx = 0; idx < ARRAY_SIZE(snd_sonicvibes_controls); idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_sonicvibes_controls[idx], sonic))) < 0) + kctl = snd_ctl_new1(&snd_sonicvibes_controls[idx], sonic); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; switch (idx) { case 0: @@ -1226,7 +1229,8 @@ static int snd_sonicvibes_create(struct snd_card *card, *rsonic = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; /* check, if we can restrict PCI DMA transfers to 24 bits */ if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(24))) { @@ -1246,7 +1250,8 @@ static int snd_sonicvibes_create(struct snd_card *card, sonic->pci = pci; sonic->irq = -1; - if ((err = pci_request_regions(pci, "S3 SonicVibes")) < 0) { + err = pci_request_regions(pci, "S3 SonicVibes"); + if (err < 0) { kfree(sonic); pci_disable_device(pci); return err; @@ -1289,14 +1294,16 @@ static int snd_sonicvibes_create(struct snd_card *card, pci_write_config_dword(pci, 0x40, dmaa); pci_write_config_dword(pci, 0x48, dmac); - if ((sonic->res_dmaa = request_region(dmaa, 0x10, "S3 SonicVibes DDMA-A")) == NULL) { + sonic->res_dmaa = request_region(dmaa, 0x10, "S3 SonicVibes DDMA-A"); + if (!sonic->res_dmaa) { snd_sonicvibes_free(sonic); dev_err(card->dev, "unable to grab DDMA-A port at 0x%x-0x%x\n", dmaa, dmaa + 0x10 - 1); return -EBUSY; } - if ((sonic->res_dmac = request_region(dmac, 0x10, "S3 SonicVibes DDMA-C")) == NULL) { + sonic->res_dmac = request_region(dmac, 0x10, "S3 SonicVibes DDMA-C"); + if (!sonic->res_dmac) { snd_sonicvibes_free(sonic); dev_err(card->dev, "unable to grab DDMA-C port at 0x%x-0x%x\n", @@ -1358,7 +1365,8 @@ static int snd_sonicvibes_create(struct snd_card *card, #endif sonic->revision = snd_sonicvibes_in(sonic, SV_IREG_REVISION); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sonic, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sonic, &ops); + if (err < 0) { snd_sonicvibes_free(sonic); return err; } @@ -1405,9 +1413,11 @@ static int snd_sonicvibes_midi(struct sonicvibes *sonic, mpu->private_data = sonic; mpu->open_input = snd_sonicvibes_midi_input_open; mpu->close_input = snd_sonicvibes_midi_input_close; - for (idx = 0; idx < ARRAY_SIZE(snd_sonicvibes_midi_controls); idx++) - if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_midi_controls[idx], sonic))) < 0) + for (idx = 0; idx < ARRAY_SIZE(snd_sonicvibes_midi_controls); idx++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_midi_controls[idx], sonic)); + if (err < 0) return err; + } return 0; } @@ -1439,10 +1449,11 @@ static int snd_sonic_probe(struct pci_dev *pci, return -ENODEV; } } - if ((err = snd_sonicvibes_create(card, pci, - reverb[dev] ? 1 : 0, - mge[dev] ? 1 : 0, - &sonic)) < 0) { + err = snd_sonicvibes_create(card, pci, + reverb[dev] ? 1 : 0, + mge[dev] ? 1 : 0, + &sonic); + if (err < 0) { snd_card_free(card); return err; } @@ -1455,30 +1466,35 @@ static int snd_sonic_probe(struct pci_dev *pci, (unsigned long long)pci_resource_start(pci, 1), sonic->irq); - if ((err = snd_sonicvibes_pcm(sonic, 0)) < 0) { + err = snd_sonicvibes_pcm(sonic, 0); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_sonicvibes_mixer(sonic)) < 0) { + err = snd_sonicvibes_mixer(sonic); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES, - sonic->midi_port, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &midi_uart)) < 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES, + sonic->midi_port, + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &midi_uart); + if (err < 0) { snd_card_free(card); return err; } snd_sonicvibes_midi(sonic, midi_uart); - if ((err = snd_opl3_create(card, sonic->synth_port, - sonic->synth_port + 2, - OPL3_HW_OPL3_SV, 1, &opl3)) < 0) { + err = snd_opl3_create(card, sonic->synth_port, + sonic->synth_port + 2, + OPL3_HW_OPL3_SV, 1, &opl3); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) { snd_card_free(card); return err; } @@ -1489,7 +1505,8 @@ static int snd_sonic_probe(struct pci_dev *pci, return err; } - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index a51041205f7c..60e4dca28c2b 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -67,11 +67,12 @@ static int snd_trident_probe(struct pci_dev *pci, if (err < 0) return err; - if ((err = snd_trident_create(card, pci, - pcm_channels[dev], - ((pci->vendor << 16) | pci->device) == TRIDENT_DEVICE_ID_SI7018 ? 1 : 2, - wavetable_size[dev], - &trident)) < 0) { + err = snd_trident_create(card, pci, + pcm_channels[dev], + ((pci->vendor << 16) | pci->device) == TRIDENT_DEVICE_ID_SI7018 ? 1 : 2, + wavetable_size[dev], + &trident); + if (err < 0) { snd_card_free(card); return err; } @@ -100,38 +101,44 @@ static int snd_trident_probe(struct pci_dev *pci, sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d", card->shortname, trident->port, trident->irq); - if ((err = snd_trident_pcm(trident, pcm_dev++)) < 0) { + err = snd_trident_pcm(trident, pcm_dev++); + if (err < 0) { snd_card_free(card); return err; } switch (trident->device) { case TRIDENT_DEVICE_ID_DX: case TRIDENT_DEVICE_ID_NX: - if ((err = snd_trident_foldback_pcm(trident, pcm_dev++)) < 0) { + err = snd_trident_foldback_pcm(trident, pcm_dev++); + if (err < 0) { snd_card_free(card); return err; } break; } if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) { - if ((err = snd_trident_spdif_pcm(trident, pcm_dev++)) < 0) { + err = snd_trident_spdif_pcm(trident, pcm_dev++); + if (err < 0) { snd_card_free(card); return err; } } - if (trident->device != TRIDENT_DEVICE_ID_SI7018 && - (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, - trident->midi_port, - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &trident->rmidi)) < 0) { - snd_card_free(card); - return err; + if (trident->device != TRIDENT_DEVICE_ID_SI7018) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, + trident->midi_port, + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &trident->rmidi); + if (err < 0) { + snd_card_free(card); + return err; + } } snd_trident_create_gameport(trident); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/trident/trident.h b/sound/pci/trident/trident.h index c7567edbe4c4..c579a44bb9ae 100644 --- a/sound/pci/trident/trident.h +++ b/sound/pci/trident/trident.h @@ -251,7 +251,6 @@ struct snd_trident_memblk_arg { struct snd_trident_tlb { __le32 *entries; /* 16k-aligned TLB table */ dma_addr_t entries_dmaaddr; /* 16k-aligned PCI address to TLB table */ - unsigned long * shadow_entries; /* shadow entries with virtual addresses */ struct snd_dma_buffer buffer; struct snd_util_memhdr * memhdr; /* page allocation list */ struct snd_dma_buffer silent_page; diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 20145143f6a6..cfbca3bd60ed 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2119,7 +2119,8 @@ int snd_trident_pcm(struct snd_trident *trident, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, trident->ChanPCM, 1, &pcm)) < 0) + err = snd_pcm_new(trident->card, "trident_dx_nx", device, trident->ChanPCM, 1, &pcm); + if (err < 0) return err; pcm->private_data = trident; @@ -2178,7 +2179,8 @@ int snd_trident_foldback_pcm(struct snd_trident *trident, int device) if (trident->device == TRIDENT_DEVICE_ID_NX) num_chan = 4; - if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, 0, num_chan, &foldback)) < 0) + err = snd_pcm_new(trident->card, "trident_dx_nx", device, 0, num_chan, &foldback); + if (err < 0) return err; foldback->private_data = trident; @@ -2228,7 +2230,8 @@ int snd_trident_spdif_pcm(struct snd_trident *trident, int device) struct snd_pcm *spdif; int err; - if ((err = snd_pcm_new(trident->card, "trident_dx_nx IEC958", device, 1, 0, &spdif)) < 0) + err = snd_pcm_new(trident->card, "trident_dx_nx IEC958", device, 1, 0, &spdif); + if (err < 0) return err; spdif->private_data = trident; @@ -2921,7 +2924,8 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) if (!uctl) return -ENOMEM; - if ((err = snd_ac97_bus(trident->card, 0, &ops, NULL, &trident->ac97_bus)) < 0) + err = snd_ac97_bus(trident->card, 0, &ops, NULL, &trident->ac97_bus); + if (err < 0) goto __out; memset(&_ac97, 0, sizeof(_ac97)); @@ -2929,9 +2933,11 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) trident->ac97_detect = 1; __again: - if ((err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97)) < 0) { + err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97); + if (err < 0) { if (trident->device == TRIDENT_DEVICE_ID_SI7018) { - if ((err = snd_trident_sis_reset(trident)) < 0) + err = snd_trident_sis_reset(trident); + if (err < 0) goto __out; if (retries-- > 0) goto __again; @@ -2962,10 +2968,14 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) trident->ac97_detect = 0; if (trident->device != TRIDENT_DEVICE_ID_SI7018) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_vol_wave_control, trident))) < 0) + kctl = snd_ctl_new1(&snd_trident_vol_wave_control, trident); + err = snd_ctl_add(card, kctl); + if (err < 0) goto __out; kctl->put(kctl, uctl); - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_vol_music_control, trident))) < 0) + kctl = snd_ctl_new1(&snd_trident_vol_music_control, trident); + err = snd_ctl_add(card, kctl); + if (err < 0) goto __out; kctl->put(kctl, uctl); outl(trident->musicvol_wavevol = 0x00000000, TRID_REG(trident, T4D_MUSICVOL_WAVEVOL)); @@ -2979,28 +2989,38 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) tmix = &trident->pcm_mixer[idx]; tmix->voice = NULL; } - if ((trident->ctl_vol = snd_ctl_new1(&snd_trident_pcm_vol_control, trident)) == NULL) + trident->ctl_vol = snd_ctl_new1(&snd_trident_pcm_vol_control, trident); + if (!trident->ctl_vol) goto __nomem; - if ((err = snd_ctl_add(card, trident->ctl_vol))) + err = snd_ctl_add(card, trident->ctl_vol); + if (err) goto __out; - if ((trident->ctl_pan = snd_ctl_new1(&snd_trident_pcm_pan_control, trident)) == NULL) + trident->ctl_pan = snd_ctl_new1(&snd_trident_pcm_pan_control, trident); + if (!trident->ctl_pan) goto __nomem; - if ((err = snd_ctl_add(card, trident->ctl_pan))) + err = snd_ctl_add(card, trident->ctl_pan); + if (err) goto __out; - if ((trident->ctl_rvol = snd_ctl_new1(&snd_trident_pcm_rvol_control, trident)) == NULL) + trident->ctl_rvol = snd_ctl_new1(&snd_trident_pcm_rvol_control, trident); + if (!trident->ctl_rvol) goto __nomem; - if ((err = snd_ctl_add(card, trident->ctl_rvol))) + err = snd_ctl_add(card, trident->ctl_rvol); + if (err) goto __out; - if ((trident->ctl_cvol = snd_ctl_new1(&snd_trident_pcm_cvol_control, trident)) == NULL) + trident->ctl_cvol = snd_ctl_new1(&snd_trident_pcm_cvol_control, trident); + if (!trident->ctl_cvol) goto __nomem; - if ((err = snd_ctl_add(card, trident->ctl_cvol))) + err = snd_ctl_add(card, trident->ctl_cvol); + if (err) goto __out; if (trident->device == TRIDENT_DEVICE_ID_NX) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_ac97_rear_control, trident))) < 0) + kctl = snd_ctl_new1(&snd_trident_ac97_rear_control, trident); + err = snd_ctl_add(card, kctl); + if (err < 0) goto __out; kctl->put(kctl, uctl); } @@ -3016,7 +3036,8 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) if (trident->ac97_sec && (trident->ac97_sec->ext_id & AC97_EI_SPDIF)) kctl->id.index++; idx = kctl->id.index; - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) goto __out; kctl->put(kctl, uctl); @@ -3027,7 +3048,8 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) } kctl->id.index = idx; kctl->id.device = pcm_spdif_device; - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) goto __out; kctl = snd_ctl_new1(&snd_trident_spdif_mask, trident); @@ -3037,7 +3059,8 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) } kctl->id.index = idx; kctl->id.device = pcm_spdif_device; - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) goto __out; kctl = snd_ctl_new1(&snd_trident_spdif_stream, trident); @@ -3047,7 +3070,8 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) } kctl->id.index = idx; kctl->id.device = pcm_spdif_device; - if ((err = snd_ctl_add(card, kctl)) < 0) + err = snd_ctl_add(card, kctl); + if (err < 0) goto __out; trident->spdif_pcm_ctl = kctl; } @@ -3307,12 +3331,6 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident) } trident->tlb.entries = (__le32 *)ALIGN((unsigned long)trident->tlb.buffer.area, SNDRV_TRIDENT_MAX_PAGES * 4); trident->tlb.entries_dmaaddr = ALIGN(trident->tlb.buffer.addr, SNDRV_TRIDENT_MAX_PAGES * 4); - /* allocate shadow TLB page table (virtual addresses) */ - trident->tlb.shadow_entries = - vmalloc(array_size(SNDRV_TRIDENT_MAX_PAGES, - sizeof(unsigned long))); - if (!trident->tlb.shadow_entries) - return -ENOMEM; /* allocate and setup silent page and initialise TLB entries */ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &trident->pci->dev, @@ -3321,10 +3339,8 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident) return -ENOMEM; } memset(trident->tlb.silent_page.area, 0, SNDRV_TRIDENT_PAGE_SIZE); - for (i = 0; i < SNDRV_TRIDENT_MAX_PAGES; i++) { + for (i = 0; i < SNDRV_TRIDENT_MAX_PAGES; i++) trident->tlb.entries[i] = cpu_to_le32(trident->tlb.silent_page.addr & ~(SNDRV_TRIDENT_PAGE_SIZE-1)); - trident->tlb.shadow_entries[i] = (unsigned long)trident->tlb.silent_page.area; - } /* use emu memory block manager code to manage tlb page allocation */ trident->tlb.memhdr = snd_util_memhdr_new(SNDRV_TRIDENT_PAGE_SIZE * SNDRV_TRIDENT_MAX_PAGES); @@ -3449,7 +3465,8 @@ static int snd_trident_sis_init(struct snd_trident *trident) { int err; - if ((err = snd_trident_sis_reset(trident)) < 0) + err = snd_trident_sis_reset(trident); + if (err < 0) return err; snd_trident_stop_all_voices(trident); @@ -3494,7 +3511,8 @@ int snd_trident_create(struct snd_card *card, *rtrident = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; /* check, if we can restrict PCI DMA transfers to 30 bits */ if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(30))) { @@ -3528,7 +3546,8 @@ int snd_trident_create(struct snd_card *card, trident->midi_port = TRID_REG(trident, T4D_MPU401_BASE); pci_set_master(pci); - if ((err = pci_request_regions(pci, "Trident Audio")) < 0) { + err = pci_request_regions(pci, "Trident Audio"); + if (err < 0) { kfree(trident); pci_disable_device(pci); return err; @@ -3548,7 +3567,8 @@ int snd_trident_create(struct snd_card *card, trident->tlb.entries = NULL; trident->tlb.buffer.area = NULL; if (trident->device == TRIDENT_DEVICE_ID_NX) { - if ((err = snd_trident_tlb_alloc(trident)) < 0) { + err = snd_trident_tlb_alloc(trident); + if (err < 0) { snd_trident_free(trident); return err; } @@ -3576,12 +3596,14 @@ int snd_trident_create(struct snd_card *card, return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, trident, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, trident, &ops); + if (err < 0) { snd_trident_free(trident); return err; } - if ((err = snd_trident_mixer(trident, pcm_spdif_device)) < 0) + err = snd_trident_mixer(trident, pcm_spdif_device); + if (err < 0) return err; /* initialise synth voices */ @@ -3635,7 +3657,6 @@ static int snd_trident_free(struct snd_trident *trident) snd_util_memhdr_free(trident->tlb.memhdr); if (trident->tlb.silent_page.area) snd_dma_free_pages(&trident->tlb.silent_page); - vfree(trident->tlb.shadow_entries); snd_dma_free_pages(&trident->tlb.buffer); } pci_release_regions(trident->pci); diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index bb24dbf0530d..4ad3855101c9 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -19,11 +19,8 @@ /* page arguments of these two macros are Trident page (4096 bytes), not like * aligned pages in others */ -#define __set_tlb_bus(trident,page,ptr,addr) \ - do { (trident)->tlb.entries[page] = cpu_to_le32((addr) & ~(SNDRV_TRIDENT_PAGE_SIZE-1)); \ - (trident)->tlb.shadow_entries[page] = (ptr); } while (0) -#define __tlb_to_ptr(trident,page) \ - (void*)((trident)->tlb.shadow_entries[page]) +#define __set_tlb_bus(trident,page,addr) \ + (trident)->tlb.entries[page] = cpu_to_le32((addr) & ~(SNDRV_TRIDENT_PAGE_SIZE-1)) #define __tlb_to_addr(trident,page) \ (dma_addr_t)le32_to_cpu((trident->tlb.entries[page]) & ~(SNDRV_TRIDENT_PAGE_SIZE - 1)) @@ -32,15 +29,13 @@ #define ALIGN_PAGE_SIZE PAGE_SIZE /* minimum page size for allocation */ #define MAX_ALIGN_PAGES SNDRV_TRIDENT_MAX_PAGES /* maxmium aligned pages */ /* fill TLB entrie(s) corresponding to page with ptr */ -#define set_tlb_bus(trident,page,ptr,addr) __set_tlb_bus(trident,page,ptr,addr) +#define set_tlb_bus(trident,page,addr) __set_tlb_bus(trident,page,addr) /* fill TLB entrie(s) corresponding to page with silence pointer */ -#define set_silent_tlb(trident,page) __set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr) +#define set_silent_tlb(trident,page) __set_tlb_bus(trident, page, trident->tlb.silent_page.addr) /* get aligned page from offset address */ #define get_aligned_page(offset) ((offset) >> 12) /* get offset address from aligned page */ #define aligned_page_offset(page) ((page) << 12) -/* get buffer address from aligned page */ -#define page_to_ptr(trident,page) __tlb_to_ptr(trident, page) /* get PCI physical address from aligned page */ #define page_to_addr(trident,page) __tlb_to_addr(trident, page) @@ -50,22 +45,21 @@ #define MAX_ALIGN_PAGES (SNDRV_TRIDENT_MAX_PAGES / 2) #define get_aligned_page(offset) ((offset) >> 13) #define aligned_page_offset(page) ((page) << 13) -#define page_to_ptr(trident,page) __tlb_to_ptr(trident, (page) << 1) #define page_to_addr(trident,page) __tlb_to_addr(trident, (page) << 1) /* fill TLB entries -- we need to fill two entries */ static inline void set_tlb_bus(struct snd_trident *trident, int page, - unsigned long ptr, dma_addr_t addr) + dma_addr_t addr) { page <<= 1; - __set_tlb_bus(trident, page, ptr, addr); - __set_tlb_bus(trident, page+1, ptr + SNDRV_TRIDENT_PAGE_SIZE, addr + SNDRV_TRIDENT_PAGE_SIZE); + __set_tlb_bus(trident, page, addr); + __set_tlb_bus(trident, page+1, addr + SNDRV_TRIDENT_PAGE_SIZE); } static inline void set_silent_tlb(struct snd_trident *trident, int page) { page <<= 1; - __set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr); - __set_tlb_bus(trident, page+1, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr); + __set_tlb_bus(trident, page, trident->tlb.silent_page.addr); + __set_tlb_bus(trident, page+1, trident->tlb.silent_page.addr); } #else @@ -80,18 +74,16 @@ static inline void set_silent_tlb(struct snd_trident *trident, int page) */ #define get_aligned_page(offset) ((offset) / ALIGN_PAGE_SIZE) #define aligned_page_offset(page) ((page) * ALIGN_PAGE_SIZE) -#define page_to_ptr(trident,page) __tlb_to_ptr(trident, (page) * UNIT_PAGES) #define page_to_addr(trident,page) __tlb_to_addr(trident, (page) * UNIT_PAGES) /* fill TLB entries -- UNIT_PAGES entries must be filled */ static inline void set_tlb_bus(struct snd_trident *trident, int page, - unsigned long ptr, dma_addr_t addr) + dma_addr_t addr) { int i; page *= UNIT_PAGES; for (i = 0; i < UNIT_PAGES; i++, page++) { - __set_tlb_bus(trident, page, ptr, addr); - ptr += SNDRV_TRIDENT_PAGE_SIZE; + __set_tlb_bus(trident, page, addr); addr += SNDRV_TRIDENT_PAGE_SIZE; } } @@ -100,20 +92,11 @@ static inline void set_silent_tlb(struct snd_trident *trident, int page) int i; page *= UNIT_PAGES; for (i = 0; i < UNIT_PAGES; i++, page++) - __set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr); + __set_tlb_bus(trident, page, trident->tlb.silent_page.addr); } #endif /* PAGE_SIZE */ -/* calculate buffer pointer from offset address */ -static inline void *offset_ptr(struct snd_trident *trident, int offset) -{ - char *ptr; - ptr = page_to_ptr(trident, get_aligned_page(offset)); - ptr += offset % ALIGN_PAGE_SIZE; - return (void*)ptr; -} - /* first and last (aligned) pages of memory block */ #define firstpg(blk) (((struct snd_trident_memblk_arg *)snd_util_memblk_argptr(blk))->first_page) #define lastpg(blk) (((struct snd_trident_memblk_arg *)snd_util_memblk_argptr(blk))->last_page) @@ -201,14 +184,12 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident, for (page = firstpg(blk); page <= lastpg(blk); page++, idx++) { unsigned long ofs = idx << PAGE_SHIFT; dma_addr_t addr = snd_pcm_sgbuf_get_addr(substream, ofs); - unsigned long ptr = (unsigned long) - snd_pcm_sgbuf_get_ptr(substream, ofs); if (! is_valid_page(addr)) { __snd_util_mem_free(hdr, blk); mutex_unlock(&hdr->block_mutex); return NULL; } - set_tlb_bus(trident, page, ptr, addr); + set_tlb_bus(trident, page, addr); } mutex_unlock(&hdr->block_mutex); return blk; @@ -226,7 +207,6 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident, int page; struct snd_pcm_runtime *runtime = substream->runtime; dma_addr_t addr; - unsigned long ptr; if (snd_BUG_ON(runtime->dma_bytes <= 0 || runtime->dma_bytes > SNDRV_TRIDENT_MAX_PAGES * @@ -245,15 +225,14 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident, /* set TLB entries */ addr = runtime->dma_addr; - ptr = (unsigned long)runtime->dma_area; for (page = firstpg(blk); page <= lastpg(blk); page++, - ptr += SNDRV_TRIDENT_PAGE_SIZE, addr += SNDRV_TRIDENT_PAGE_SIZE) { + addr += SNDRV_TRIDENT_PAGE_SIZE) { if (! is_valid_page(addr)) { __snd_util_mem_free(hdr, blk); mutex_unlock(&hdr->block_mutex); return NULL; } - set_tlb_bus(trident, page, ptr, addr); + set_tlb_bus(trident, page, addr); } mutex_unlock(&hdr->block_mutex); return blk; diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index fd1f2f9cfbc3..943813a06abc 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -515,7 +515,8 @@ static int snd_via82xx_codec_ready(struct via82xx *chip, int secondary) while (timeout-- > 0) { udelay(1); - if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)) + val = snd_via82xx_codec_xread(chip); + if (!(val & VIA_REG_AC97_BUSY)) return val & 0xffff; } dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]\n", @@ -1023,7 +1024,8 @@ static int snd_via8233_playback_prepare(struct snd_pcm_substream *substream) int rate_changed; u32 rbits; - if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0) + rate_changed = via_lock_rate(&chip->rates[0], ac97_rate); + if (rate_changed < 0) return rate_changed; if (rate_changed) snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, @@ -1197,7 +1199,8 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev, /* we may remove following constaint when we modify table entries in interrupt */ - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; if (use_src) { @@ -1222,7 +1225,8 @@ static int snd_via686_playback_open(struct snd_pcm_substream *substream) struct viadev *viadev = &chip->devs[chip->playback_devno + substream->number]; int err; - if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0) + err = snd_via82xx_pcm_open(chip, viadev, substream); + if (err < 0) return err; return 0; } @@ -1238,7 +1242,8 @@ static int snd_via8233_playback_open(struct snd_pcm_substream *substream) int err; viadev = &chip->devs[chip->playback_devno + substream->number]; - if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0) + err = snd_via82xx_pcm_open(chip, viadev, substream); + if (err < 0) return err; stream = viadev->reg_offset / 0x10; if (chip->dxs_controls[stream]) { @@ -1275,7 +1280,8 @@ static int snd_via8233_multi_open(struct snd_pcm_substream *substream) .mask = 0, }; - if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0) + err = snd_via82xx_pcm_open(chip, viadev, substream); + if (err < 0) return err; substream->runtime->hw.channels_max = 6; if (chip->revision == VIA_REV_8233A) @@ -1875,7 +1881,8 @@ static int snd_via82xx_mixer_new(struct via82xx *chip, const char *quirk_overrid .wait = snd_via82xx_codec_wait, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus); + if (err < 0) return err; chip->ac97_bus->private_free = snd_via82xx_mixer_free_ac97_bus; chip->ac97_bus->clock = chip->ac97_clock; @@ -1885,7 +1892,8 @@ static int snd_via82xx_mixer_new(struct via82xx *chip, const char *quirk_overrid ac97.private_free = snd_via82xx_mixer_free_ac97; ac97.pci = chip->pci; ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97); + if (err < 0) return err; snd_ac97_tune_hardware(chip->ac97, ac97_quirks, quirk_override); @@ -2054,9 +2062,9 @@ static int snd_via686_init_misc(struct via82xx *chip) break; } } - if (mpu_port >= 0x200 && - (chip->mpu_res = request_region(mpu_port, 2, "VIA82xx MPU401")) - != NULL) { + if (mpu_port >= 0x200) + chip->mpu_res = request_region(mpu_port, 2, "VIA82xx MPU401"); + if (chip->mpu_res) { if (rev_h) legacy |= VIA_FUNC_MIDI_PNP; /* enable PCI I/O 2 */ legacy |= VIA_FUNC_ENABLE_MIDI; @@ -2173,7 +2181,8 @@ static int snd_via82xx_chip_init(struct via82xx *chip) schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); - if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) + val = snd_via82xx_codec_xread(chip); + if (val & VIA_REG_AC97_BUSY) dev_err(chip->card->dev, "AC'97 codec is not ready [0x%x]\n", val); @@ -2186,7 +2195,8 @@ static int snd_via82xx_chip_init(struct via82xx *chip) VIA_REG_AC97_SECONDARY_VALID | (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT)); do { - if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) { + val = snd_via82xx_codec_xread(chip); + if (val & VIA_REG_AC97_SECONDARY_VALID) { chip->ac97_secondary = 1; goto __ac97_ok2; } @@ -2337,10 +2347,12 @@ static int snd_via82xx_create(struct snd_card *card, .dev_free = snd_via82xx_dev_free, }; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; - if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) { + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { pci_disable_device(pci); return -ENOMEM; } @@ -2360,7 +2372,8 @@ 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)); - if ((err = pci_request_regions(pci, card->driver)) < 0) { + err = pci_request_regions(pci, card->driver); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -2380,12 +2393,14 @@ static int snd_via82xx_create(struct snd_card *card, if (ac97_clock >= 8000 && ac97_clock <= 48000) chip->ac97_clock = ac97_clock; - if ((err = snd_via82xx_chip_init(chip)) < 0) { + err = snd_via82xx_chip_init(chip); + if (err < 0) { snd_via82xx_free(chip); return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_via82xx_free(chip); return err; } @@ -2541,24 +2556,31 @@ static int snd_via82xx_probe(struct pci_dev *pci, goto __error; } - if ((err = snd_via82xx_create(card, pci, chip_type, pci->revision, - ac97_clock, &chip)) < 0) + err = snd_via82xx_create(card, pci, chip_type, pci->revision, + ac97_clock, &chip); + if (err < 0) goto __error; card->private_data = chip; - if ((err = snd_via82xx_mixer_new(chip, ac97_quirk)) < 0) + err = snd_via82xx_mixer_new(chip, ac97_quirk); + if (err < 0) goto __error; if (chip_type == TYPE_VIA686) { - if ((err = snd_via686_pcm_new(chip)) < 0 || - (err = snd_via686_init_misc(chip)) < 0) + err = snd_via686_pcm_new(chip); + if (err < 0) + goto __error; + err = snd_via686_init_misc(chip); + if (err < 0) goto __error; } else { if (chip_type == TYPE_VIA8233A) { - if ((err = snd_via8233a_pcm_new(chip)) < 0) + err = snd_via8233a_pcm_new(chip); + if (err < 0) goto __error; // chip->dxs_fixed = 1; /* FIXME: use 48k for DXS #3? */ } else { - if ((err = snd_via8233_pcm_new(chip)) < 0) + err = snd_via8233_pcm_new(chip); + if (err < 0) goto __error; if (dxs_support == VIA_DXS_48K) chip->dxs_fixed = 1; @@ -2569,7 +2591,8 @@ static int snd_via82xx_probe(struct pci_dev *pci, chip->dxs_src = 1; } } - if ((err = snd_via8233_init_misc(chip)) < 0) + err = snd_via8233_init_misc(chip); + if (err < 0) goto __error; } @@ -2583,7 +2606,8 @@ static int snd_via82xx_probe(struct pci_dev *pci, snd_via82xx_proc_init(chip); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 30253306f67c..07278a3dc8c1 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -369,7 +369,8 @@ static int snd_via82xx_codec_ready(struct via82xx_modem *chip, int secondary) while (timeout-- > 0) { udelay(1); - if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)) + val = snd_via82xx_codec_xread(chip); + if (!(val & VIA_REG_AC97_BUSY)) return val & 0xffff; } dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]\n", @@ -738,13 +739,15 @@ static int snd_via82xx_modem_pcm_open(struct via82xx_modem *chip, struct viadev runtime->hw = snd_via82xx_hw; - if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &hw_constraints_rates)) < 0) + err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &hw_constraints_rates); + if (err < 0) return err; /* we may remove following constaint when we modify table entries in interrupt */ - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; runtime->private_data = viadev; @@ -878,7 +881,8 @@ static int snd_via82xx_mixer_new(struct via82xx_modem *chip) .wait = snd_via82xx_codec_wait, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus); + if (err < 0) return err; chip->ac97_bus->private_free = snd_via82xx_mixer_free_ac97_bus; chip->ac97_bus->clock = chip->ac97_clock; @@ -890,7 +894,8 @@ static int snd_via82xx_mixer_new(struct via82xx_modem *chip) ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; ac97.num = chip->ac97_secondary; - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97); + if (err < 0) return err; return 0; @@ -971,7 +976,8 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip) schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); - if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) + val = snd_via82xx_codec_xread(chip); + if (val & VIA_REG_AC97_BUSY) dev_err(chip->card->dev, "AC'97 codec is not ready [0x%x]\n", val); @@ -983,7 +989,8 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip) VIA_REG_AC97_SECONDARY_VALID | (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT)); do { - if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) { + val = snd_via82xx_codec_xread(chip); + if (val & VIA_REG_AC97_SECONDARY_VALID) { chip->ac97_secondary = 1; goto __ac97_ok2; } @@ -1079,10 +1086,12 @@ static int snd_via82xx_create(struct snd_card *card, .dev_free = snd_via82xx_dev_free, }; - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; - if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) { + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { pci_disable_device(pci); return -ENOMEM; } @@ -1092,7 +1101,8 @@ static int snd_via82xx_create(struct snd_card *card, chip->pci = pci; chip->irq = -1; - if ((err = pci_request_regions(pci, card->driver)) < 0) { + err = pci_request_regions(pci, card->driver); + if (err < 0) { kfree(chip); pci_disable_device(pci); return err; @@ -1109,12 +1119,14 @@ static int snd_via82xx_create(struct snd_card *card, if (ac97_clock >= 8000 && ac97_clock <= 48000) chip->ac97_clock = ac97_clock; - if ((err = snd_via82xx_chip_init(chip)) < 0) { + err = snd_via82xx_chip_init(chip); + if (err < 0) { snd_via82xx_free(chip); return err; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_via82xx_free(chip); return err; } @@ -1154,14 +1166,17 @@ static int snd_via82xx_probe(struct pci_dev *pci, goto __error; } - if ((err = snd_via82xx_create(card, pci, chip_type, pci->revision, - ac97_clock, &chip)) < 0) + err = snd_via82xx_create(card, pci, chip_type, pci->revision, + ac97_clock, &chip); + if (err < 0) goto __error; card->private_data = chip; - if ((err = snd_via82xx_mixer_new(chip)) < 0) + err = snd_via82xx_mixer_new(chip); + if (err < 0) goto __error; - if ((err = snd_via686_pcm_new(chip)) < 0 ) + err = snd_via686_pcm_new(chip); + if (err < 0) goto __error; /* disable interrupts */ @@ -1173,7 +1188,8 @@ static int snd_via82xx_probe(struct pci_dev *pci, snd_via82xx_proc_init(chip); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 2a9e1a77a81a..04c7204cb7bc 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -133,7 +133,8 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci, const struct snd_vx_ops *vx_ops; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; pci_set_master(pci); @@ -147,7 +148,8 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci, vx = to_vx222(chip); vx->pci = pci; - if ((err = pci_request_regions(pci, CARD_NAME)) < 0) { + err = pci_request_regions(pci, CARD_NAME); + if (err < 0) { snd_vx222_free(chip); return err; } @@ -164,7 +166,8 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci, chip->irq = pci->irq; card->sync_irq = chip->irq; - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_vx222_free(chip); return err; } @@ -207,7 +210,8 @@ static int snd_vx222_probe(struct pci_dev *pci, hw = &vx222_v2_hw; break; } - if ((err = snd_vx222_create(card, pci, hw, &vx)) < 0) { + err = snd_vx222_create(card, pci, hw, &vx); + if (err < 0) { snd_card_free(card); return err; } @@ -223,12 +227,14 @@ static int snd_vx222_probe(struct pci_dev *pci, vx->core.dev = &pci->dev; #endif - if ((err = snd_vx_setup_firmware(&vx->core)) < 0) { + err = snd_vx_setup_firmware(&vx->core); + if (err < 0) { snd_card_free(card); return err; } - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index a05537202738..3e7e928b24f8 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -408,9 +408,11 @@ static int vx2_load_dsp(struct vx_core *vx, int index, const struct firmware *ds switch (index) { case 1: /* xilinx image */ - if ((err = vx2_load_xilinx_binary(vx, dsp)) < 0) + err = vx2_load_xilinx_binary(vx, dsp); + if (err < 0) return err; - if ((err = vx2_test_xilinx(vx)) < 0) + err = vx2_test_xilinx(vx); + if (err < 0) return err; return 0; case 2: @@ -972,9 +974,11 @@ static int vx2_add_mic_controls(struct vx_core *_chip) vx2_set_input_level(chip); /* controls */ - if ((err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_input_level, chip))) < 0) + err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_input_level, chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_level, chip))) < 0) + err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_level, chip)); + if (err < 0) return err; return 0; diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 99be1490ef0e..7e32d57147ff 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -72,7 +72,8 @@ static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, if (io_port == 1) { /* auto-detect */ - if (!(io_port = pci_resource_start(chip->pci, 2))) + io_port = pci_resource_start(chip->pci, 2); + if (!io_port) return -ENODEV; } } else { @@ -81,7 +82,8 @@ static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, for (io_port = 0x201; io_port <= 0x205; io_port++) { if (io_port == 0x203) continue; - if ((r = request_region(io_port, 1, "YMFPCI gameport")) != NULL) + r = request_region(io_port, 1, "YMFPCI gameport"); + if (r) break; } if (!r) { @@ -102,10 +104,13 @@ static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, } } - if (!r && !(r = request_region(io_port, 1, "YMFPCI gameport"))) { - dev_err(chip->card->dev, - "joystick port %#x is in use.\n", io_port); - return -EBUSY; + if (!r) { + r = request_region(io_port, 1, "YMFPCI gameport"); + if (!r) { + dev_err(chip->card->dev, + "joystick port %#x is in use.\n", io_port); + return -EBUSY; + } } chip->gameport = gp = gameport_allocate_port(); @@ -193,8 +198,9 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, /* auto-detect */ fm_port[dev] = pci_resource_start(pci, 1); } - if (fm_port[dev] > 0 && - (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { + if (fm_port[dev] > 0) + fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3"); + if (fm_res) { legacy_ctrl |= YMFPCI_LEGACY_FMEN; pci_write_config_word(pci, PCIR_DSXG_FMBASE, fm_port[dev]); } @@ -202,8 +208,9 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, /* auto-detect */ mpu_port[dev] = pci_resource_start(pci, 1) + 0x20; } - if (mpu_port[dev] > 0 && - (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { + if (mpu_port[dev] > 0) + mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401"); + if (mpu_res) { legacy_ctrl |= YMFPCI_LEGACY_MEN; pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]); } @@ -215,8 +222,9 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, case 0x3a8: legacy_ctrl2 |= 3; break; default: fm_port[dev] = 0; break; } - if (fm_port[dev] > 0 && - (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { + if (fm_port[dev] > 0) + fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3"); + if (fm_res) { legacy_ctrl |= YMFPCI_LEGACY_FMEN; } else { legacy_ctrl2 &= ~YMFPCI_LEGACY2_FMIO; @@ -229,8 +237,9 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, case 0x334: legacy_ctrl2 |= 3 << 4; break; default: mpu_port[dev] = 0; break; } - if (mpu_port[dev] > 0 && - (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { + if (mpu_port[dev] > 0) + mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401"); + if (mpu_res) { legacy_ctrl |= YMFPCI_LEGACY_MEN; } else { legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO; @@ -244,9 +253,8 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, pci_read_config_word(pci, PCIR_DSXG_LEGACY, &old_legacy_ctrl); pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); pci_write_config_word(pci, PCIR_DSXG_ELEGACY, legacy_ctrl2); - if ((err = snd_ymfpci_create(card, pci, - old_legacy_ctrl, - &chip)) < 0) { + err = snd_ymfpci_create(card, pci, old_legacy_ctrl, &chip); + if (err < 0) { release_and_free_resource(mpu_res); release_and_free_resource(fm_res); goto free_card; @@ -287,11 +295,12 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, goto free_card; if (chip->mpu_res) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, - mpu_port[dev], - MPU401_INFO_INTEGRATED | - MPU401_INFO_IRQ_HOOK, - -1, &chip->rawmidi)) < 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, + mpu_port[dev], + MPU401_INFO_INTEGRATED | + MPU401_INFO_IRQ_HOOK, + -1, &chip->rawmidi); + if (err < 0) { dev_warn(card->dev, "cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]); @@ -300,18 +309,22 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci, } } if (chip->fm_res) { - if ((err = snd_opl3_create(card, - fm_port[dev], - fm_port[dev] + 2, - OPL3_HW_OPL3, 1, &opl3)) < 0) { + err = snd_opl3_create(card, + fm_port[dev], + fm_port[dev] + 2, + OPL3_HW_OPL3, 1, &opl3); + if (err < 0) { dev_warn(card->dev, "cannot initialize FM OPL3 at 0x%lx, skipping...\n", fm_port[dev]); legacy_ctrl &= ~YMFPCI_LEGACY_FMEN; pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); - } else if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - dev_err(card->dev, "cannot create opl3 hwdep\n"); - goto free_card; + } else { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) { + dev_err(card->dev, "cannot create opl3 hwdep\n"); + goto free_card; + } } } diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index cacc6a9d14c8..8fd060769882 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -292,7 +292,8 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_ struct snd_ymfpci_pcm *ypcm; u32 pos, delta; - if ((ypcm = voice->ypcm) == NULL) + ypcm = voice->ypcm; + if (!ypcm) return; if (ypcm->substream == NULL) return; @@ -628,7 +629,8 @@ static int snd_ymfpci_playback_hw_params(struct snd_pcm_substream *substream, struct snd_ymfpci_pcm *ypcm = runtime->private_data; int err; - if ((err = snd_ymfpci_pcm_voice_alloc(ypcm, params_channels(hw_params))) < 0) + err = snd_ymfpci_pcm_voice_alloc(ypcm, params_channels(hw_params)); + if (err < 0) return err; return 0; } @@ -932,7 +934,8 @@ static int snd_ymfpci_playback_open(struct snd_pcm_substream *substream) struct snd_ymfpci_pcm *ypcm; int err; - if ((err = snd_ymfpci_playback_open_1(substream)) < 0) + err = snd_ymfpci_playback_open_1(substream); + if (err < 0) return err; ypcm = runtime->private_data; ypcm->output_front = 1; @@ -954,7 +957,8 @@ static int snd_ymfpci_playback_spdif_open(struct snd_pcm_substream *substream) struct snd_ymfpci_pcm *ypcm; int err; - if ((err = snd_ymfpci_playback_open_1(substream)) < 0) + err = snd_ymfpci_playback_open_1(substream); + if (err < 0) return err; ypcm = runtime->private_data; ypcm->output_front = 0; @@ -982,7 +986,8 @@ static int snd_ymfpci_playback_4ch_open(struct snd_pcm_substream *substream) struct snd_ymfpci_pcm *ypcm; int err; - if ((err = snd_ymfpci_playback_open_1(substream)) < 0) + err = snd_ymfpci_playback_open_1(substream); + if (err < 0) return err; ypcm = runtime->private_data; ypcm->output_front = 0; @@ -1124,7 +1129,8 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm)) < 0) + err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -1157,7 +1163,8 @@ int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm)) < 0) + err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -1190,7 +1197,8 @@ int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm)) < 0) + err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -1230,7 +1238,8 @@ int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm)) < 0) + err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm); + if (err < 0) return err; pcm->private_data = chip; @@ -1785,7 +1794,8 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) .read = snd_ymfpci_codec_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus); + if (err < 0) return err; chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus; chip->ac97_bus->no_vra = 1; /* YMFPCI doesn't need VRA */ @@ -1793,7 +1803,8 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_ymfpci_mixer_free_ac97; - if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97); + if (err < 0) return err; /* to be sure */ @@ -1801,7 +1812,8 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) AC97_EA_VRA|AC97_EA_VRM, 0); for (idx = 0; idx < ARRAY_SIZE(snd_ymfpci_controls); idx++) { - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_controls[idx], chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_controls[idx], chip)); + if (err < 0) return err; } if (chip->ac97->ext_id & AC97_EI_SDAC) { @@ -1814,27 +1826,37 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) /* add S/PDIF control */ if (snd_BUG_ON(!chip->pcm_spdif)) return -ENXIO; - if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip))) < 0) + kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip); + err = snd_ctl_add(chip->card, kctl); + if (err < 0) return err; kctl->id.device = chip->pcm_spdif->device; - if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip))) < 0) + kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip); + err = snd_ctl_add(chip->card, kctl); + if (err < 0) return err; kctl->id.device = chip->pcm_spdif->device; - if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip))) < 0) + kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip); + err = snd_ctl_add(chip->card, kctl); + if (err < 0) return err; kctl->id.device = chip->pcm_spdif->device; chip->spdif_pcm_ctl = kctl; /* direct recording source */ - if (chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && - (err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_drec_source, chip))) < 0) - return err; + if (chip->device_id == PCI_DEVICE_ID_YAMAHA_754) { + kctl = snd_ctl_new1(&snd_ymfpci_drec_source, chip); + err = snd_ctl_add(chip->card, kctl); + if (err < 0) + return err; + } /* * shared rear/line-in */ if (rear_switch) { - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_rear_shared, chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_rear_shared, chip)); + if (err < 0) return err; } @@ -1847,7 +1869,8 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) kctl->id.device = chip->pcm->device; kctl->id.subdevice = idx; kctl->private_value = (unsigned long)substream; - if ((err = snd_ctl_add(chip->card, kctl)) < 0) + err = snd_ctl_add(chip->card, kctl); + if (err < 0) return err; chip->pcm_mixer[idx].left = 0x8000; chip->pcm_mixer[idx].right = 0x8000; @@ -1928,7 +1951,8 @@ int snd_ymfpci_timer(struct snd_ymfpci *chip, int device) tid.card = chip->card->number; tid.device = device; tid.subdevice = 0; - if ((err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer)) >= 0) { + err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer); + if (err >= 0) { strcpy(timer->name, "YMFPCI timer"); timer->private_data = chip; timer->hw = snd_ymfpci_timer_hw; @@ -2334,7 +2358,8 @@ int snd_ymfpci_create(struct snd_card *card, *rchip = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -2357,7 +2382,8 @@ int snd_ymfpci_create(struct snd_card *card, pci_set_master(pci); chip->src441_used = -1; - if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) { + chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI"); + if (!chip->res_reg_area) { dev_err(chip->card->dev, "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 144582350a05..8363ec08df5d 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -170,7 +170,8 @@ static int snd_pdacf_assign_resources(struct snd_pdacf *pdacf, int port, int irq if (err < 0) return err; - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) return err; return 0; diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index 0f59e4cca56d..bc2114475810 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c @@ -124,11 +124,13 @@ int vxp_add_mic_controls(struct vx_core *_chip) /* mic level */ switch (_chip->type) { case VX_TYPE_VXPOCKET: - if ((err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_level, chip))) < 0) + err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_level, chip)); + if (err < 0) return err; break; case VX_TYPE_VXP440: - if ((err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_boost, chip))) < 0) + err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_boost, chip)); + if (err < 0) return err; break; } diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 45eeb0f57d59..4176abd73799 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c @@ -237,9 +237,11 @@ static int vxp_load_dsp(struct vx_core *vx, int index, const struct firmware *fw switch (index) { case 0: /* xilinx boot */ - if ((err = vx_check_magic(vx)) < 0) + err = vx_check_magic(vx); + if (err < 0) return err; - if ((err = snd_vx_load_boot_image(vx, fw)) < 0) + err = snd_vx_load_boot_image(vx, fw); + if (err < 0) return err; return 0; case 1: diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 636320489805..0dfb6a943b60 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -183,7 +183,8 @@ static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq chip->irq = irq; card->sync_irq = chip->irq; - if ((err = snd_vx_setup_firmware(chip)) < 0) + err = snd_vx_setup_firmware(chip); + if (err < 0) return err; return 0; diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index 6bc586a5db0f..0f4bce1c0d4f 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -105,7 +105,10 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, } chip = input_get_drvdata(dev); - if (! chip || (beep = chip->beep) == NULL) + if (!chip) + return -1; + beep = chip->beep; + if (!beep) return -1; if (! hz) { diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index 1eb698dafd93..4da9278dd58a 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -84,7 +84,8 @@ static int daca_get_deemphasis(struct snd_kcontrol *kcontrol, { struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); struct pmac_daca *mix; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; ucontrol->value.integer.value[0] = mix->deemphasis ? 1 : 0; return 0; @@ -97,7 +98,8 @@ static int daca_put_deemphasis(struct snd_kcontrol *kcontrol, struct pmac_daca *mix; int change; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; change = mix->deemphasis != ucontrol->value.integer.value[0]; if (change) { @@ -123,7 +125,8 @@ static int daca_get_volume(struct snd_kcontrol *kcontrol, { struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); struct pmac_daca *mix; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; ucontrol->value.integer.value[0] = mix->left_vol; ucontrol->value.integer.value[1] = mix->right_vol; @@ -138,7 +141,8 @@ static int daca_put_volume(struct snd_kcontrol *kcontrol, unsigned int vol[2]; int change; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; vol[0] = ucontrol->value.integer.value[0]; vol[1] = ucontrol->value.integer.value[1]; @@ -162,7 +166,8 @@ static int daca_get_amp(struct snd_kcontrol *kcontrol, { struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); struct pmac_daca *mix; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; ucontrol->value.integer.value[0] = mix->amp_on ? 1 : 0; return 0; @@ -175,7 +180,8 @@ static int daca_put_amp(struct snd_kcontrol *kcontrol, struct pmac_daca *mix; int change; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; change = mix->amp_on != ucontrol->value.integer.value[0]; if (change) { @@ -248,7 +254,8 @@ int snd_pmac_daca_init(struct snd_pmac *chip) mix->i2c.addr = DACA_I2C_ADDR; mix->i2c.init_client = daca_init_client; mix->i2c.name = "DACA"; - if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0) + err = snd_pmac_keywest_init(&mix->i2c); + if (err < 0) return err; /* @@ -257,7 +264,8 @@ int snd_pmac_daca_init(struct snd_pmac *chip) strcpy(chip->card->mixername, "PowerMac DACA"); for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) { - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip)); + if (err < 0) return err; } diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index a8915100d6bb..6e5daae18f9d 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -114,7 +114,8 @@ int snd_pmac_tumbler_post_init(void) if (!keywest_ctx || !keywest_ctx->client) return -ENXIO; - if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) { + err = keywest_ctx->init_client(keywest_ctx); + if (err < 0) { snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err); return err; } @@ -136,7 +137,8 @@ int snd_pmac_keywest_init(struct pmac_keywest *i2c) keywest_ctx = i2c; - if ((err = i2c_add_driver(&keywest_driver))) { + err = i2c_add_driver(&keywest_driver); + if (err) { snd_printk(KERN_ERR "cannot register keywest i2c driver\n"); i2c_put_adapter(adap); return err; diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 2e750b317be1..84058bbf9d12 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -1160,7 +1160,8 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) chip->playback.stream = SNDRV_PCM_STREAM_PLAYBACK; chip->capture.stream = SNDRV_PCM_STREAM_CAPTURE; - if ((err = snd_pmac_detect(chip)) < 0) + err = snd_pmac_detect(chip); + if (err < 0) goto __error; if (snd_pmac_dbdma_alloc(chip, &chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 || @@ -1299,7 +1300,8 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) /* Reset dbdma channels */ snd_pmac_dbdma_reset(chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) goto __error; *chip_return = chip; diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index 9fb51ebafde1..db414b61157e 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c @@ -48,7 +48,8 @@ static int snd_pmac_probe(struct platform_device *devptr) if (err < 0) return err; - if ((err = snd_pmac_new(card, &chip)) < 0) + err = snd_pmac_new(card, &chip); + if (err < 0) goto __error; card->private_data = chip; @@ -58,7 +59,8 @@ static int snd_pmac_probe(struct platform_device *devptr) strcpy(card->shortname, "PowerMac Burgundy"); sprintf(card->longname, "%s (Dev %d) Sub-frame %d", card->shortname, chip->device_id, chip->subframe); - if ((err = snd_pmac_burgundy_init(chip)) < 0) + err = snd_pmac_burgundy_init(chip); + if (err < 0) goto __error; break; case PMAC_DACA: @@ -66,7 +68,8 @@ static int snd_pmac_probe(struct platform_device *devptr) strcpy(card->shortname, "PowerMac DACA"); sprintf(card->longname, "%s (Dev %d) Sub-frame %d", card->shortname, chip->device_id, chip->subframe); - if ((err = snd_pmac_daca_init(chip)) < 0) + err = snd_pmac_daca_init(chip); + if (err < 0) goto __error; break; case PMAC_TUMBLER: @@ -76,7 +79,11 @@ static int snd_pmac_probe(struct platform_device *devptr) sprintf(card->shortname, "PowerMac %s", name_ext); sprintf(card->longname, "%s (Dev %d) Sub-frame %d", card->shortname, chip->device_id, chip->subframe); - if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0) + err = snd_pmac_tumbler_init(chip); + if (err < 0) + goto __error; + err = snd_pmac_tumbler_post_init(); + if (err < 0) goto __error; break; case PMAC_AWACS: @@ -92,7 +99,8 @@ static int snd_pmac_probe(struct platform_device *devptr) name_ext = ""; sprintf(card->longname, "%s%s Rev %d", card->shortname, name_ext, chip->revision); - if ((err = snd_pmac_awacs_init(chip)) < 0) + err = snd_pmac_awacs_init(chip); + if (err < 0) goto __error; break; default: @@ -101,14 +109,16 @@ static int snd_pmac_probe(struct platform_device *devptr) goto __error; } - if ((err = snd_pmac_pcm_new(chip)) < 0) + err = snd_pmac_pcm_new(chip); + if (err < 0) goto __error; chip->initialized = 1; if (enable_beep) snd_pmac_attach_beep(chip); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto __error; platform_set_drvdata(devptr, card); @@ -162,7 +172,8 @@ static int __init alsa_card_pmac_init(void) { int err; - if ((err = platform_driver_register(&snd_pmac_driver)) < 0) + err = platform_driver_register(&snd_pmac_driver); + if (err < 0) return err; device = platform_device_register_simple(SND_PMAC_DRIVER, -1, NULL, 0); return 0; diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 6e5bdaa262b0..c65e74d7cd0a 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -402,7 +402,8 @@ static int tumbler_get_drc_value(struct snd_kcontrol *kcontrol, { struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); struct pmac_tumbler *mix; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; ucontrol->value.integer.value[0] = mix->drc_range; return 0; @@ -416,7 +417,8 @@ static int tumbler_put_drc_value(struct snd_kcontrol *kcontrol, unsigned int val; int change; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; val = ucontrol->value.integer.value[0]; if (chip->model == PMAC_TUMBLER) { @@ -442,7 +444,8 @@ static int tumbler_get_drc_switch(struct snd_kcontrol *kcontrol, { struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); struct pmac_tumbler *mix; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; ucontrol->value.integer.value[0] = mix->drc_enable; return 0; @@ -455,7 +458,8 @@ static int tumbler_put_drc_switch(struct snd_kcontrol *kcontrol, struct pmac_tumbler *mix; int change; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; change = mix->drc_enable != ucontrol->value.integer.value[0]; if (change) { @@ -524,7 +528,8 @@ static int tumbler_get_mono(struct snd_kcontrol *kcontrol, struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value; struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); struct pmac_tumbler *mix; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; ucontrol->value.integer.value[0] = mix->mono_vol[info->index]; return 0; @@ -539,7 +544,8 @@ static int tumbler_put_mono(struct snd_kcontrol *kcontrol, unsigned int vol; int change; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; vol = ucontrol->value.integer.value[0]; if (vol >= info->max) @@ -669,7 +675,8 @@ static int snapper_get_mix(struct snd_kcontrol *kcontrol, int idx = (int)kcontrol->private_value; struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); struct pmac_tumbler *mix; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; ucontrol->value.integer.value[0] = mix->mix_vol[idx][0]; ucontrol->value.integer.value[1] = mix->mix_vol[idx][1]; @@ -685,7 +692,8 @@ static int snapper_put_mix(struct snd_kcontrol *kcontrol, unsigned int vol[2]; int change; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; vol[0] = ucontrol->value.integer.value[0]; vol[1] = ucontrol->value.integer.value[1]; @@ -716,7 +724,8 @@ static int tumbler_get_mute_switch(struct snd_kcontrol *kcontrol, struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); struct pmac_tumbler *mix; struct pmac_gpio *gp; - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; switch(kcontrol->private_value) { case TUMBLER_MUTE_HP: @@ -745,7 +754,8 @@ static int tumbler_put_mute_switch(struct snd_kcontrol *kcontrol, if (chip->update_automute && chip->auto_mute) return 0; /* don't touch in the auto-mute mode */ #endif - if (! (mix = chip->mixer_data)) + mix = chip->mixer_data; + if (!mix) return -ENODEV; switch(kcontrol->private_value) { case TUMBLER_MUTE_HP: @@ -1361,7 +1371,8 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip) break; } } - if ((err = tumbler_init(chip)) < 0) + err = tumbler_init(chip); + if (err < 0) return err; /* set up TAS */ @@ -1392,7 +1403,8 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip) chipname = "Snapper"; } - if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0) + err = snd_pmac_keywest_init(&mix->i2c); + if (err < 0) return err; /* @@ -1402,28 +1414,34 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip) if (chip->model == PMAC_TUMBLER) { for (i = 0; i < ARRAY_SIZE(tumbler_mixers); i++) { - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&tumbler_mixers[i], chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&tumbler_mixers[i], chip)); + if (err < 0) return err; } } else { for (i = 0; i < ARRAY_SIZE(snapper_mixers); i++) { - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snapper_mixers[i], chip))) < 0) + err = snd_ctl_add(chip->card, snd_ctl_new1(&snapper_mixers[i], chip)); + if (err < 0) return err; } } chip->master_sw_ctl = snd_ctl_new1(&tumbler_hp_sw, chip); - if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0) + err = snd_ctl_add(chip->card, chip->master_sw_ctl); + if (err < 0) return err; chip->speaker_sw_ctl = snd_ctl_new1(&tumbler_speaker_sw, chip); - if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0) + err = snd_ctl_add(chip->card, chip->speaker_sw_ctl); + if (err < 0) return err; if (mix->line_mute.addr != 0) { chip->lineout_sw_ctl = snd_ctl_new1(&tumbler_lineout_sw, chip); - if ((err = snd_ctl_add(chip->card, chip->lineout_sw_ctl)) < 0) + err = snd_ctl_add(chip->card, chip->lineout_sw_ctl); + if (err < 0) return err; } chip->drc_sw_ctl = snd_ctl_new1(&tumbler_drc_sw, chip); - if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0) + err = snd_ctl_add(chip->card, chip->drc_sw_ctl); + if (err < 0) return err; /* set initial DRC range to 60% */ @@ -1446,9 +1464,11 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip) device_change_chip = chip; #ifdef PMAC_SUPPORT_AUTOMUTE - if ((mix->headphone_irq >=0 || mix->lineout_irq >= 0) - && (err = snd_pmac_add_automute(chip)) < 0) - return err; + if (mix->headphone_irq >= 0 || mix->lineout_irq >= 0) { + err = snd_pmac_add_automute(chip); + if (err < 0) + return err; + } chip->detect_headphone = tumbler_detect_headphone; chip->update_automute = tumbler_update_automute; tumbler_update_automute(chip, 0); /* update the status only */ @@ -1456,8 +1476,9 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip) /* activate headphone status interrupts */ if (mix->headphone_irq >= 0) { unsigned char val; - if ((err = request_irq(mix->headphone_irq, headphone_intr, 0, - "Sound Headphone Detection", chip)) < 0) + err = request_irq(mix->headphone_irq, headphone_intr, 0, + "Sound Headphone Detection", chip); + if (err < 0) return 0; /* activate headphone status interrupts */ val = do_gpio_read(&mix->hp_detect); @@ -1465,8 +1486,9 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip) } if (mix->lineout_irq >= 0) { unsigned char val; - if ((err = request_irq(mix->lineout_irq, headphone_intr, 0, - "Sound Lineout Detection", chip)) < 0) + err = request_irq(mix->lineout_irq, headphone_intr, 0, + "Sound Lineout Detection", chip); + if (err < 0) return 0; /* activate headphone status interrupts */ val = do_gpio_read(&mix->line_detect); diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c index aa082131fb90..1289cb4e2988 100644 --- a/sound/soc/adi/axi-i2s.c +++ b/sound/soc/adi/axi-i2s.c @@ -198,8 +198,7 @@ static int axi_i2s_probe(struct platform_device *pdev) axi_i2s_parse_of(i2s, pdev->dev.of_node); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c index 9b3d81c41c8c..8d4a6cb4e5c5 100644 --- a/sound/soc/adi/axi-spdif.c +++ b/sound/soc/adi/axi-spdif.c @@ -189,8 +189,7 @@ static int axi_spdif_probe(struct platform_device *pdev) platform_set_drvdata(pdev, spdif); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 4c2810e58dce..bd20622b0933 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -77,7 +77,6 @@ static void enable_pdm_clock(void __iomem *acp_base) u32 pdm_clk_enable, pdm_ctrl; pdm_clk_enable = ACP_PDM_CLK_FREQ_MASK; - pdm_ctrl = 0x00; rn_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL); pdm_ctrl = rn_readl(acp_base + ACP_WOV_MISC_CTRL); @@ -144,9 +143,6 @@ static int stop_pdm_dma(void __iomem *acp_base) u32 pdm_enable, pdm_dma_enable; int timeout; - pdm_enable = 0x00; - pdm_dma_enable = 0x00; - pdm_enable = rn_readl(acp_base + ACP_WOV_PDM_ENABLE); pdm_dma_enable = rn_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); if (pdm_dma_enable & 0x01) { diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 6023369e0f1a..a9f9f449c48c 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -558,8 +558,7 @@ static int atmel_classd_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(dev, res); + io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(io_base)) return PTR_ERR(io_base); diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 584656cc7d3c..6b3d9c05eaf2 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -200,6 +200,7 @@ struct atmel_i2s_dev { unsigned int fmt; const struct atmel_i2s_gck_param *gck_param; const struct atmel_i2s_caps *caps; + int clk_use_no; }; static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id) @@ -321,9 +322,16 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, { struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - unsigned int mr = 0; + unsigned int mr = 0, mr_mask; int ret; + mr_mask = ATMEL_I2SC_MR_FORMAT_MASK | ATMEL_I2SC_MR_MODE_MASK | + ATMEL_I2SC_MR_DATALENGTH_MASK; + if (is_playback) + mr_mask |= ATMEL_I2SC_MR_TXMONO; + else + mr_mask |= ATMEL_I2SC_MR_RXMONO; + switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: mr |= ATMEL_I2SC_MR_FORMAT_I2S; @@ -402,7 +410,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - return regmap_write(dev->regmap, ATMEL_I2SC_MR, mr); + return regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr); } static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev, @@ -495,18 +503,28 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd, is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER; /* If master starts, enable the audio clock. */ - if (is_master && mck_enabled) - err = atmel_i2s_switch_mck_generator(dev, true); - if (err) - return err; + if (is_master && mck_enabled) { + if (!dev->clk_use_no) { + err = atmel_i2s_switch_mck_generator(dev, true); + if (err) + return err; + } + dev->clk_use_no++; + } err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr); if (err) return err; /* If master stops, disable the audio clock. */ - if (is_master && !mck_enabled) - err = atmel_i2s_switch_mck_generator(dev, false); + if (is_master && !mck_enabled) { + if (dev->clk_use_no == 1) { + err = atmel_i2s_switch_mck_generator(dev, false); + if (err) + return err; + } + dev->clk_use_no--; + } return err; } @@ -542,6 +560,7 @@ static struct snd_soc_dai_driver atmel_i2s_dai = { }, .ops = &atmel_i2s_dai_ops, .symmetric_rate = 1, + .symmetric_sample_bits = 1, }; static const struct snd_soc_component_driver atmel_i2s_component = { @@ -610,8 +629,7 @@ static int atmel_i2s_probe(struct platform_device *pdev) dev->caps = match->data; /* Map I/O registers. */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index 8e1d8230b180..42117de299e7 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c @@ -620,8 +620,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(dev, res); + io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(io_base)) return PTR_ERR(io_base); diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 673bc16cb46a..8988f024a732 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -1008,8 +1008,7 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c index f9a85fd01b79..0be7b4221c14 100644 --- a/sound/soc/atmel/mikroe-proto.c +++ b/sound/soc/atmel/mikroe-proto.c @@ -120,19 +120,22 @@ static int snd_proto_probe(struct platform_device *pdev) dai->cpus->of_node = cpu_np; dai->platforms->of_node = cpu_np; - dai_fmt = snd_soc_of_parse_daifmt(np, NULL, - &bitclkmaster, &framemaster); + dai_fmt = snd_soc_daifmt_parse_format(np, NULL); + snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, + &bitclkmaster, &framemaster); if (bitclkmaster != framemaster) { dev_err(&pdev->dev, "Must be the same bitclock and frame master\n"); return -EINVAL; } if (bitclkmaster) { - dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK; if (codec_np == bitclkmaster) dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; else dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } else { + dai_fmt |= snd_soc_daifmt_parse_clock_provider_as_flag(np, NULL); } + of_node_put(bitclkmaster); of_node_put(framemaster); dai->dai_fmt = dai_fmt; diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c index 9fbc3c1113cc..7745250fd743 100644 --- a/sound/soc/atmel/sam9x5_wm8731.c +++ b/sound/soc/atmel/sam9x5_wm8731.c @@ -159,7 +159,7 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) of_node_put(codec_np); of_node_put(cpu_np); - ret = snd_soc_register_card(card); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(&pdev->dev, "Platform device allocation failed\n"); goto out_put_audio; @@ -180,7 +180,6 @@ static int sam9x5_wm8731_driver_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct sam9x5_drvdata *priv = card->drvdata; - snd_soc_unregister_card(card); atmel_ssc_put_audio(priv->ssc_id); return 0; diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index ba03bb62ba96..fca5a3f2eec5 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1308,7 +1308,6 @@ static int cygnus_ssp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *child_node; - struct resource *res; struct cygnus_audio *cygaud; int err; int node_count; @@ -1320,13 +1319,11 @@ static int cygnus_ssp_probe(struct platform_device *pdev) dev_set_drvdata(dev, cygaud); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud"); - cygaud->audio = devm_ioremap_resource(dev, res); + cygaud->audio = devm_platform_ioremap_resource_byname(pdev, "aud"); if (IS_ERR(cygaud->audio)) return PTR_ERR(cygaud->audio); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "i2s_in"); - cygaud->i2s_in = devm_ioremap_resource(dev, res); + cygaud->i2s_in = devm_platform_ioremap_resource_byname(pdev, "i2s_in"); if (IS_ERR(cygaud->i2s_in)) return PTR_ERR(cygaud->i2s_in); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 2a7b3e363069..3abdda48dc8e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -155,6 +155,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_PCM512x_I2C imply SND_SOC_PCM512x_SPI imply SND_SOC_RK3328 + imply SND_SOC_RK817 imply SND_SOC_RT274 imply SND_SOC_RT286 imply SND_SOC_RT298 @@ -211,6 +212,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TAS6424 imply SND_SOC_TDA7419 imply SND_SOC_TFA9879 + imply SND_SOC_TFA989X imply SND_SOC_TLV320ADCX140 imply SND_SOC_TLV320AIC23_I2C imply SND_SOC_TLV320AIC23_SPI @@ -232,6 +234,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X + imply SND_SOC_WCD937X + imply SND_SOC_WCD938X imply SND_SOC_LPASS_RX_MACRO imply SND_SOC_LPASS_TX_MACRO imply SND_SOC_WL1273 @@ -1063,6 +1067,11 @@ config SND_SOC_RK3328 tristate "Rockchip RK3328 audio CODEC" select REGMAP_MMIO +config SND_SOC_RK817 + tristate "Rockchip RK817 audio CODEC" + depends on MFD_RK808 + select REGMAP_I2C + config SND_SOC_RL6231 tristate default y if SND_SOC_RT5514=y @@ -1180,7 +1189,7 @@ config SND_SOC_RT5631 depends on I2C config SND_SOC_RT5640 - tristate + tristate "Realtek RT5640/RT5639 Codec" depends on I2C config SND_SOC_RT5645 @@ -1408,6 +1417,16 @@ config SND_SOC_TFA9879 tristate "NXP Semiconductors TFA9879 amplifier" depends on I2C +config SND_SOC_TFA989X + tristate "NXP/Goodix TFA989X (TFA1) amplifiers" + depends on I2C + select REGMAP_I2C + help + Enable support for NXP (now Goodix) TFA989X (TFA1 family) speaker + amplifiers, e.g. TFA9895. + Note that the driver currently bypasses the built-in "CoolFlux DSP" + and does not support (hardware) volume control. + config SND_SOC_TLV320AIC23 tristate @@ -1525,14 +1544,30 @@ config SND_SOC_WCD9335 Qualcomm Technologies, Inc. (QTI) multimedia solutions, including the MSM8996, MSM8976, and MSM8956 chipsets. +config SND_SOC_WCD_MBHC + tristate + config SND_SOC_WCD934X tristate "WCD9340/WCD9341 Codec" depends on COMMON_CLK + select SND_SOC_WCD_MBHC depends on MFD_WCD934X help The WCD9340/9341 is a audio codec IC Integrated in Qualcomm SoCs like SDM845. +config SND_SOC_WCD938X + tristate + +config SND_SOC_WCD938X_SDW + tristate "WCD9380/WCD9385 Codec - SDW" + select SND_SOC_WCD938X + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + help + The WCD9380/9385 is a audio codec IC Integrated in + Qualcomm SoCs like SM8250. + config SND_SOC_WL1273 tristate @@ -1871,18 +1906,22 @@ config SND_SOC_TPA6130A2 config SND_SOC_LPASS_WSA_MACRO depends on COMMON_CLK + select REGMAP_MMIO tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_VA_MACRO depends on COMMON_CLK + select REGMAP_MMIO tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_RX_MACRO depends on COMMON_CLK + select REGMAP_MMIO tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_TX_MACRO depends on COMMON_CLK + select REGMAP_MMIO tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0efdba609048..de8b83dd2c76 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -166,6 +166,7 @@ snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-rk3328-objs := rk3328_codec.o +snd-soc-rk817-objs := rk817_codec.o snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt1011-objs := rt1011.o @@ -229,6 +230,7 @@ snd-soc-tas6424-objs := tas6424.o snd-soc-tda7419-objs := tda7419.o snd-soc-tas2770-objs := tas2770.o snd-soc-tfa9879-objs := tfa9879.o +snd-soc-tfa989x-objs := tfa989x.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o @@ -250,8 +252,11 @@ snd-soc-twl6040-objs := twl6040.o snd-soc-uda1334-objs := uda1334.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o +snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o +snd-soc-wcd938x-objs := wcd938x.o wcd-clsh-v2.o +snd-soc-wcd938x-sdw-objs := wcd938x-sdw.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o @@ -487,6 +492,7 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o +obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o @@ -551,6 +557,7 @@ obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o +obj-$(CONFIG_SND_SOC_TFA989X) += snd-soc-tfa989x.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o @@ -572,8 +579,11 @@ obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o +obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o +obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x.o +obj-$(CONFIG_SND_SOC_WCD938X_SDW) += snd-soc-wcd938x-sdw.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index fe208cfdd3ba..4d2e78101f28 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -539,6 +539,15 @@ static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } +/* + * Select below from Sound Card, not Auto + * SND_SOC_DAIFMT_CBC_CFC + * SND_SOC_DAIFMT_CBP_CFP + */ +static u64 ak4613_dai_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J; + static const struct snd_soc_dai_ops ak4613_dai_ops = { .startup = ak4613_dai_startup, .shutdown = ak4613_dai_shutdown, @@ -546,6 +555,8 @@ static const struct snd_soc_dai_ops ak4613_dai_ops = { .set_fmt = ak4613_dai_set_fmt, .trigger = ak4613_dai_trigger, .hw_params = ak4613_dai_hw_params, + .auto_selectable_formats = &ak4613_dai_formats, + .num_auto_selectable_formats = 1, }; #define AK4613_PCM_RATE (SNDRV_PCM_RATE_32000 |\ diff --git a/sound/soc/codecs/cirrus_legacy.h b/sound/soc/codecs/cirrus_legacy.h new file mode 100644 index 000000000000..87c6fd79290d --- /dev/null +++ b/sound/soc/codecs/cirrus_legacy.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Some small helpers for older Cirrus Logic parts. + * + * Copyright (C) 2021 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +static inline int cirrus_read_device_id(struct regmap *regmap, unsigned int reg) +{ + u8 devid[3]; + int ret; + + ret = regmap_bulk_read(regmap, reg, devid, ARRAY_SIZE(devid)); + if (ret < 0) + return ret; + + return ((devid[0] & 0xFF) << 12) | + ((devid[1] & 0xFF) << 4) | + ((devid[2] & 0xF0) >> 4); +} diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 88e79b9f52ed..933e3d627e5f 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -30,6 +30,7 @@ #include <dt-bindings/sound/cs35l32.h> #include "cs35l32.h" +#include "cirrus_legacy.h" #define CS35L32_NUM_SUPPLIES 2 static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = { @@ -351,8 +352,7 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, struct cs35l32_private *cs35l32; struct cs35l32_platform_data *pdata = dev_get_platdata(&i2c_client->dev); - int ret, i; - unsigned int devid = 0; + int ret, i, devid; unsigned int reg; cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l32), GFP_KERNEL); @@ -407,40 +407,40 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, /* Reset the Device */ cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(cs35l32->reset_gpio)) - return PTR_ERR(cs35l32->reset_gpio); + if (IS_ERR(cs35l32->reset_gpio)) { + ret = PTR_ERR(cs35l32->reset_gpio); + goto err_supplies; + } gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); /* initialize codec */ - ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); - devid = (reg & 0xFF) << 12; - - ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, ®); - devid |= (reg & 0xFF) << 4; - - ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, ®); - devid |= (reg & 0xF0) >> 4; + devid = cirrus_read_device_id(cs35l32->regmap, CS35L32_DEVID_AB); + if (devid < 0) { + ret = devid; + dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + goto err_disable; + } if (devid != CS35L32_CHIP_ID) { ret = -ENODEV; dev_err(&i2c_client->dev, "CS35L32 Device ID (%X). Expected %X\n", devid, CS35L32_CHIP_ID); - return ret; + goto err_disable; } ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, ®); if (ret < 0) { dev_err(&i2c_client->dev, "Get Revision ID failed\n"); - return ret; + goto err_disable; } ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch, ARRAY_SIZE(cs35l32_monitor_patch)); if (ret < 0) { dev_err(&i2c_client->dev, "Failed to apply errata patch\n"); - return ret; + goto err_disable; } dev_info(&i2c_client->dev, @@ -481,7 +481,7 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, CS35L32_PDN_AMP); /* Clear MCLK Error Bit since we don't have the clock yet */ - ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, ®); + regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, ®); ret = devm_snd_soc_register_component(&i2c_client->dev, &soc_component_dev_cs35l32, cs35l32_dai, @@ -492,6 +492,8 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, return 0; err_disable: + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); +err_supplies: regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), cs35l32->supplies); return ret; diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index e8f3dcfd144d..2a6f5e46d031 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -34,6 +34,7 @@ #include <linux/of_irq.h> #include "cs35l33.h" +#include "cirrus_legacy.h" #define CS35L33_BOOT_DELAY 50 @@ -1190,12 +1191,12 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client, regcache_cache_only(cs35l33->regmap, false); /* initialize codec */ - ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_AB, ®); - devid = (reg & 0xFF) << 12; - ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_CD, ®); - devid |= (reg & 0xFF) << 4; - ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_E, ®); - devid |= (reg & 0xF0) >> 4; + devid = cirrus_read_device_id(cs35l33->regmap, CS35L33_DEVID_AB); + if (devid < 0) { + ret = devid; + dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + goto err_enable; + } if (devid != CS35L33_CHIP_ID) { dev_err(&i2c_client->dev, @@ -1243,6 +1244,8 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client, return 0; err_enable: + gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); + regulator_bulk_disable(cs35l33->num_core_supplies, cs35l33->core_supplies); diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 3d3c3c34dfe2..ed678241c22b 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -34,6 +34,7 @@ #include <sound/cs35l34.h> #include "cs35l34.h" +#include "cirrus_legacy.h" #define PDN_DONE_ATTEMPTS 10 #define CS35L34_START_DELAY 50 @@ -999,9 +1000,8 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client, struct cs35l34_private *cs35l34; struct cs35l34_platform_data *pdata = dev_get_platdata(&i2c_client->dev); - int i; + int i, devid; int ret; - unsigned int devid = 0; unsigned int reg; cs35l34 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l34), GFP_KERNEL); @@ -1042,13 +1042,15 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client, } else { pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; + if (!pdata) { + ret = -ENOMEM; + goto err_regulator; + } if (i2c_client->dev.of_node) { ret = cs35l34_handle_of_data(i2c_client, pdata); if (ret != 0) - return ret; + goto err_regulator; } cs35l34->pdata = *pdata; @@ -1062,33 +1064,34 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client, cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset-gpios", GPIOD_OUT_LOW); - if (IS_ERR(cs35l34->reset_gpio)) - return PTR_ERR(cs35l34->reset_gpio); + if (IS_ERR(cs35l34->reset_gpio)) { + ret = PTR_ERR(cs35l34->reset_gpio); + goto err_regulator; + } gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); msleep(CS35L34_START_DELAY); - ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_AB, ®); - - devid = (reg & 0xFF) << 12; - ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_CD, ®); - devid |= (reg & 0xFF) << 4; - ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_E, ®); - devid |= (reg & 0xF0) >> 4; + devid = cirrus_read_device_id(cs35l34->regmap, CS35L34_DEVID_AB); + if (devid < 0) { + ret = devid; + dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + goto err_reset; + } if (devid != CS35L34_CHIP_ID) { dev_err(&i2c_client->dev, "CS35l34 Device ID (%X). Expected ID %X\n", devid, CS35L34_CHIP_ID); ret = -ENODEV; - goto err_regulator; + goto err_reset; } ret = regmap_read(cs35l34->regmap, CS35L34_REV_ID, ®); if (ret < 0) { dev_err(&i2c_client->dev, "Get Revision ID failed\n"); - goto err_regulator; + goto err_reset; } dev_info(&i2c_client->dev, @@ -1113,11 +1116,13 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client, if (ret < 0) { dev_err(&i2c_client->dev, "%s: Register component failed\n", __func__); - goto err_regulator; + goto err_reset; } return 0; +err_reset: + gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); err_regulator: regulator_bulk_disable(cs35l34->num_core_supplies, cs35l34->core_supplies); diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index f20ed838b958..7a5588f1df01 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -33,6 +33,7 @@ #include <linux/completion.h> #include "cs35l35.h" +#include "cirrus_legacy.h" /* * Some fields take zero as a valid value so use a high bit flag that won't @@ -367,16 +368,16 @@ static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct snd_soc_component *component = codec_dai->component; struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT); - cs35l35->slave_mode = false; + cs35l35->clock_consumer = false; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT); - cs35l35->slave_mode = true; + cs35l35->clock_consumer = true; break; default: return -EINVAL; @@ -495,10 +496,10 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream, * the Class H algorithm does not enable weak-drive operation for * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10 */ - errata_chk = clk_ctl & CS35L35_SP_RATE_MASK; + errata_chk = (clk_ctl & CS35L35_SP_RATE_MASK) >> CS35L35_SP_RATE_SHIFT; if (classh->classh_wk_fet_disable == 0x00 && - (errata_chk == 0x01 || errata_chk == 0x03)) { + (errata_chk == 0x01 || errata_chk == 0x02)) { ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_FET_DRIVE_CTL, CS35L35_CH_WKFET_DEL_MASK, @@ -555,8 +556,8 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream, } sp_sclks = ((cs35l35->sclk / srate) / 4) - 1; - /* Only certain ratios are supported in I2S Slave Mode */ - if (cs35l35->slave_mode) { + /* Only certain ratios supported when device is a clock consumer */ + if (cs35l35->clock_consumer) { switch (sp_sclks) { case CS35L35_SP_SCLKS_32FS: case CS35L35_SP_SCLKS_48FS: @@ -567,7 +568,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } } else { - /* Only certain ratios supported in I2S MASTER Mode */ + /* Only certain ratios supported when device is a clock provider */ switch (sp_sclks) { case CS35L35_SP_SCLKS_32FS: case CS35L35_SP_SCLKS_64FS: @@ -1471,9 +1472,8 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, struct cs35l35_private *cs35l35; struct device *dev = &i2c_client->dev; struct cs35l35_platform_data *pdata = dev_get_platdata(dev); - int i; + int i, devid; int ret; - unsigned int devid = 0; unsigned int reg; cs35l35 = devm_kzalloc(dev, sizeof(struct cs35l35_private), GFP_KERNEL); @@ -1552,13 +1552,12 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, goto err; } /* initialize codec */ - ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_AB, ®); - - devid = (reg & 0xFF) << 12; - ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_CD, ®); - devid |= (reg & 0xFF) << 4; - ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_E, ®); - devid |= (reg & 0xF0) >> 4; + devid = cirrus_read_device_id(cs35l35->regmap, CS35L35_DEVID_AB); + if (devid < 0) { + ret = devid; + dev_err(dev, "Failed to read device ID: %d\n", ret); + goto err; + } if (devid != CS35L35_CHIP_ID) { dev_err(dev, "CS35L35 Device ID (%X). Expected ID %X\n", diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h index ffb154cd962c..5e4509f41b32 100644 --- a/sound/soc/codecs/cs35l35.h +++ b/sound/soc/codecs/cs35l35.h @@ -168,6 +168,7 @@ #define CS35L35_SP_SCLKS_48FS 0x0B #define CS35L35_SP_SCLKS_64FS 0x0F #define CS35L35_SP_RATE_MASK 0xC0 +#define CS35L35_SP_RATE_SHIFT 6 #define CS35L35_PDN_BST_MASK 0x06 #define CS35L35_PDN_BST_FETON_SHIFT 1 @@ -282,7 +283,7 @@ struct cs35l35_private { int sclk; bool pdm_mode; bool i2s_mode; - bool slave_mode; + bool clock_consumer; /* GPIO for /RST */ struct gpio_desc *reset_gpio; struct completion pdn_done; diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index a038bcec2d17..d83c1b318c1c 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -756,14 +756,14 @@ static int cs35l36_set_dai_fmt(struct snd_soc_dai *component_dai, { struct cs35l36_private *cs35l36 = snd_soc_component_get_drvdata(component_dai->component); - unsigned int asp_fmt, lrclk_fmt, sclk_fmt, slave_mode, clk_frc; + unsigned int asp_fmt, lrclk_fmt, sclk_fmt, clock_provider, clk_frc; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - slave_mode = 1; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + clock_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: - slave_mode = 0; + case SND_SOC_DAIFMT_CBC_CFC: + clock_provider = 0; break; default: return -EINVAL; @@ -771,10 +771,10 @@ static int cs35l36_set_dai_fmt(struct snd_soc_dai *component_dai, regmap_update_bits(cs35l36->regmap, CS35L36_ASP_TX_PIN_CTRL, CS35L36_SCLK_MSTR_MASK, - slave_mode << CS35L36_SCLK_MSTR_SHIFT); + clock_provider << CS35L36_SCLK_MSTR_SHIFT); regmap_update_bits(cs35l36->regmap, CS35L36_ASP_RATE_CTRL, CS35L36_LRCLK_MSTR_MASK, - slave_mode << CS35L36_LRCLK_MSTR_SHIFT); + clock_provider << CS35L36_LRCLK_MSTR_SHIFT); switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { case SND_SOC_DAIFMT_CONT: @@ -1156,7 +1156,7 @@ static int cs35l36_component_probe(struct snd_soc_component *component) { struct cs35l36_private *cs35l36 = snd_soc_component_get_drvdata(component); - int ret = 0; + int ret; if ((cs35l36->rev_id == CS35L36_REV_A0) && cs35l36->pdata.dcm_mode) { regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_DCM_CTRL, diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index d76be44f46b4..cffd6111afac 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -573,7 +573,7 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs4265_private *cs4265; - int ret = 0; + int ret; unsigned int devid = 0; unsigned int reg; @@ -602,6 +602,11 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, i2c_set_clientdata(i2c_client, cs4265); ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, ®); + if (ret) { + dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret); + return ret; + } + devid = reg & CS4265_CHIP_ID_MASK; if (devid != CS4265_CHIP_ID_VAL) { ret = -ENODEV; @@ -616,10 +621,9 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F); - ret = devm_snd_soc_register_component(&i2c_client->dev, + return devm_snd_soc_register_component(&i2c_client->dev, &soc_component_cs4265, cs4265_dai, ARRAY_SIZE(cs4265_dai)); - return ret; } static const struct of_device_id cs4265_of_match[] = { diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 77473c226f9e..eff013f295be 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -19,11 +19,11 @@ #include <linux/gpio.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/acpi.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/gpio/consumer.h> -#include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> #include <sound/core.h> @@ -36,6 +36,7 @@ #include <dt-bindings/sound/cs42l42.h> #include "cs42l42.h" +#include "cirrus_legacy.h" static const struct reg_default cs42l42_reg_defaults[] = { { CS42L42_FRZ_CTL, 0x00 }, @@ -521,26 +522,33 @@ static const struct snd_soc_dapm_route cs42l42_audio_map[] = { { "SDOUT2", NULL, "ASP TX EN" }, }; +static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jk, void *d) +{ + struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); + + cs42l42->jack = jk; + + regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_RS_PLUG_MASK | CS42L42_RS_UNPLUG_MASK | + CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK, + (1 << CS42L42_RS_PLUG_SHIFT) | (1 << CS42L42_RS_UNPLUG_SHIFT) | + (0 << CS42L42_TS_PLUG_SHIFT) | (0 << CS42L42_TS_UNPLUG_SHIFT)); + + return 0; +} + static int cs42l42_component_probe(struct snd_soc_component *component) { - struct cs42l42_private *cs42l42 = - (struct cs42l42_private *)snd_soc_component_get_drvdata(component); - struct snd_soc_card *crd = component->card; - int ret = 0; + struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); cs42l42->component = component; - ret = snd_soc_card_jack_new(crd, "CS42L42 Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &cs42l42->jack, NULL, 0); - if (ret < 0) - dev_err(component->dev, "Cannot create CS42L42 Headset: %d\n", ret); - - return ret; + return 0; } static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { .probe = cs42l42_component_probe, + .set_jack = cs42l42_set_jack, .dapm_widgets = cs42l42_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), .dapm_routes = cs42l42_audio_map, @@ -581,6 +589,7 @@ struct cs42l42_pll_params { u8 pll_divout; u32 mclk_int; u8 pll_cal_ratio; + u8 n; }; /* @@ -588,21 +597,23 @@ struct cs42l42_pll_params { * Table 4-5 from the Datasheet */ static const struct cs42l42_pll_params pll_ratio_table[] = { - { 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125 }, - { 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, - { 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, - { 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, - { 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96 }, - { 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94 }, - { 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, - { 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, - { 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, - { 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0 }, - { 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0 }, - { 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0 }, - { 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0 }, - { 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0 }, - { 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 } + { 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125, 2}, + { 2304000, 0, 1, 0x00, 0x55, 0xC00000, 0x02, 0x10, 12288000, 85, 2}, + { 2400000, 0, 1, 0x00, 0x50, 0x000000, 0x03, 0x10, 12000000, 80, 2}, + { 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, + { 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, + { 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1}, + { 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96, 1}, + { 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94, 1}, + { 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128, 1}, + { 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128, 1}, + { 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125, 1}, + { 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0, 1}, + { 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0, 1}, + { 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0, 1}, + { 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0, 1}, + { 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0, 1}, + { 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0, 1} }; static int cs42l42_pll_config(struct snd_soc_component *component) @@ -738,8 +749,12 @@ static int cs42l42_pll_config(struct snd_soc_component *component) snd_soc_component_update_bits(component, CS42L42_PLL_CTL3, CS42L42_PLL_DIVOUT_MASK, - pll_ratio_table[i].pll_divout + (pll_ratio_table[i].pll_divout * pll_ratio_table[i].n) << CS42L42_PLL_DIVOUT_SHIFT); + if (pll_ratio_table[i].n != 1) + cs42l42->pll_divout = pll_ratio_table[i].pll_divout; + else + cs42l42->pll_divout = 0; snd_soc_component_update_bits(component, CS42L42_PLL_CAL_RATIO, CS42L42_PLL_CAL_RATIO_MASK, @@ -894,6 +909,16 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) if ((cs42l42->bclk < 11289600) && (cs42l42->sclk < 11289600)) { snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, CS42L42_PLL_START_MASK, 1); + + if (cs42l42->pll_divout) { + usleep_range(CS42L42_PLL_DIVOUT_TIME_US, + CS42L42_PLL_DIVOUT_TIME_US * 2); + snd_soc_component_update_bits(component, CS42L42_PLL_CTL3, + CS42L42_PLL_DIVOUT_MASK, + cs42l42->pll_divout << + CS42L42_PLL_DIVOUT_SHIFT); + } + ret = regmap_read_poll_timeout(cs42l42->regmap, CS42L42_PLL_LOCK_STATUS, regval, @@ -1028,7 +1053,7 @@ static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) CS42L42_AUTO_HSBIAS_HIZ_MASK | CS42L42_TIP_SENSE_EN_MASK | CS42L42_HSBIAS_SENSE_TRIP_MASK, - (1 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (cs42l42->hs_bias_sense_en << CS42L42_HSBIAS_SENSE_EN_SHIFT) | (1 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | (0 << CS42L42_TIP_SENSE_EN_SHIFT) | (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); @@ -1413,11 +1438,11 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) switch(cs42l42->hs_type){ case CS42L42_PLUG_CTIA: case CS42L42_PLUG_OMTP: - snd_soc_jack_report(&cs42l42->jack, SND_JACK_HEADSET, + snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADSET, SND_JACK_HEADSET); break; case CS42L42_PLUG_HEADPHONE: - snd_soc_jack_report(&cs42l42->jack, SND_JACK_HEADPHONE, + snd_soc_jack_report(cs42l42->jack, SND_JACK_HEADPHONE, SND_JACK_HEADPHONE); break; default: @@ -1445,14 +1470,18 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) switch(cs42l42->hs_type){ case CS42L42_PLUG_CTIA: case CS42L42_PLUG_OMTP: - snd_soc_jack_report(&cs42l42->jack, 0, SND_JACK_HEADSET); + snd_soc_jack_report(cs42l42->jack, 0, SND_JACK_HEADSET); break; case CS42L42_PLUG_HEADPHONE: - snd_soc_jack_report(&cs42l42->jack, 0, SND_JACK_HEADPHONE); + snd_soc_jack_report(cs42l42->jack, 0, SND_JACK_HEADPHONE); break; default: break; } + snd_soc_jack_report(cs42l42->jack, 0, + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + dev_dbg(component->dev, "Unplug event\n"); } break; @@ -1464,7 +1493,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) } /* Check button detect status */ - if ((~masks[7]) & irq_params_table[7].mask) { + if (cs42l42->plug_state == CS42L42_TS_PLUG && ((~masks[7]) & irq_params_table[7].mask)) { if (!(current_button_status & CS42L42_M_HSBIAS_HIZ_MASK)) { @@ -1475,7 +1504,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) report = cs42l42_handle_button_press(cs42l42); } - snd_soc_jack_report(&cs42l42->jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 | + snd_soc_jack_report(cs42l42->jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3); } } @@ -1582,8 +1611,8 @@ static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42) CS42L42_TS_UNPLUG_MASK, (1 << CS42L42_RS_PLUG_SHIFT) | (1 << CS42L42_RS_UNPLUG_SHIFT) | - (0 << CS42L42_TS_PLUG_SHIFT) | - (0 << CS42L42_TS_UNPLUG_SHIFT)); + (1 << CS42L42_TS_PLUG_SHIFT) | + (1 << CS42L42_TS_UNPLUG_SHIFT)); } static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42) @@ -1633,17 +1662,15 @@ static const unsigned int threshold_defaults[] = { CS42L42_HS_DET_LEVEL_1 }; -static int cs42l42_handle_device_data(struct i2c_client *i2c_client, +static int cs42l42_handle_device_data(struct device *dev, struct cs42l42_private *cs42l42) { - struct device_node *np = i2c_client->dev.of_node; unsigned int val; - unsigned int thresholds[CS42L42_NUM_BIASES]; + u32 thresholds[CS42L42_NUM_BIASES]; int ret; int i; - ret = of_property_read_u32(np, "cirrus,ts-inv", &val); - + ret = device_property_read_u32(dev, "cirrus,ts-inv", &val); if (!ret) { switch (val) { case CS42L42_TS_INV_EN: @@ -1651,7 +1678,7 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, cs42l42->ts_inv = val; break; default: - dev_err(&i2c_client->dev, + dev_err(dev, "Wrong cirrus,ts-inv DT value %d\n", val); cs42l42->ts_inv = CS42L42_TS_INV_DIS; @@ -1664,8 +1691,7 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, CS42L42_TS_INV_MASK, (cs42l42->ts_inv << CS42L42_TS_INV_SHIFT)); - ret = of_property_read_u32(np, "cirrus,ts-dbnc-rise", &val); - + ret = device_property_read_u32(dev, "cirrus,ts-dbnc-rise", &val); if (!ret) { switch (val) { case CS42L42_TS_DBNCE_0: @@ -1679,7 +1705,7 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, cs42l42->ts_dbnc_rise = val; break; default: - dev_err(&i2c_client->dev, + dev_err(dev, "Wrong cirrus,ts-dbnc-rise DT value %d\n", val); cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; @@ -1693,8 +1719,7 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, (cs42l42->ts_dbnc_rise << CS42L42_TS_RISE_DBNCE_TIME_SHIFT)); - ret = of_property_read_u32(np, "cirrus,ts-dbnc-fall", &val); - + ret = device_property_read_u32(dev, "cirrus,ts-dbnc-fall", &val); if (!ret) { switch (val) { case CS42L42_TS_DBNCE_0: @@ -1708,7 +1733,7 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, cs42l42->ts_dbnc_fall = val; break; default: - dev_err(&i2c_client->dev, + dev_err(dev, "Wrong cirrus,ts-dbnc-fall DT value %d\n", val); cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; @@ -1722,13 +1747,12 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, (cs42l42->ts_dbnc_fall << CS42L42_TS_FALL_DBNCE_TIME_SHIFT)); - ret = of_property_read_u32(np, "cirrus,btn-det-init-dbnce", &val); - + ret = device_property_read_u32(dev, "cirrus,btn-det-init-dbnce", &val); if (!ret) { if (val <= CS42L42_BTN_DET_INIT_DBNCE_MAX) cs42l42->btn_det_init_dbnce = val; else { - dev_err(&i2c_client->dev, + dev_err(dev, "Wrong cirrus,btn-det-init-dbnce DT value %d\n", val); cs42l42->btn_det_init_dbnce = @@ -1739,14 +1763,13 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; } - ret = of_property_read_u32(np, "cirrus,btn-det-event-dbnce", &val); - + ret = device_property_read_u32(dev, "cirrus,btn-det-event-dbnce", &val); if (!ret) { if (val <= CS42L42_BTN_DET_EVENT_DBNCE_MAX) cs42l42->btn_det_event_dbnce = val; else { - dev_err(&i2c_client->dev, - "Wrong cirrus,btn-det-event-dbnce DT value %d\n", val); + dev_err(dev, + "Wrong cirrus,btn-det-event-dbnce DT value %d\n", val); cs42l42->btn_det_event_dbnce = CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; } @@ -1755,19 +1778,17 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; } - ret = of_property_read_u32_array(np, "cirrus,bias-lvls", - (u32 *)thresholds, CS42L42_NUM_BIASES); - + ret = device_property_read_u32_array(dev, "cirrus,bias-lvls", + thresholds, ARRAY_SIZE(thresholds)); if (!ret) { for (i = 0; i < CS42L42_NUM_BIASES; i++) { if (thresholds[i] <= CS42L42_HS_DET_LEVEL_MAX) cs42l42->bias_thresholds[i] = thresholds[i]; else { - dev_err(&i2c_client->dev, - "Wrong cirrus,bias-lvls[%d] DT value %d\n", i, + dev_err(dev, + "Wrong cirrus,bias-lvls[%d] DT value %d\n", i, thresholds[i]); - cs42l42->bias_thresholds[i] = - threshold_defaults[i]; + cs42l42->bias_thresholds[i] = threshold_defaults[i]; } } } else { @@ -1775,8 +1796,7 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, cs42l42->bias_thresholds[i] = threshold_defaults[i]; } - ret = of_property_read_u32(np, "cirrus,hs-bias-ramp-rate", &val); - + ret = device_property_read_u32(dev, "cirrus,hs-bias-ramp-rate", &val); if (!ret) { switch (val) { case CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL: @@ -1796,7 +1816,7 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME3; break; default: - dev_err(&i2c_client->dev, + dev_err(dev, "Wrong cirrus,hs-bias-ramp-rate DT value %d\n", val); cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; @@ -1812,6 +1832,11 @@ static int cs42l42_handle_device_data(struct i2c_client *i2c_client, (cs42l42->hs_bias_ramp_rate << CS42L42_HSBIAS_RAMP_SHIFT)); + if (device_property_read_bool(dev, "cirrus,hs-bias-sense-disable")) + cs42l42->hs_bias_sense_en = 0; + else + cs42l42->hs_bias_sense_en = 1; + return 0; } @@ -1819,8 +1844,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs42l42_private *cs42l42; - int ret, i; - unsigned int devid = 0; + int ret, i, devid; unsigned int reg; cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private), @@ -1883,14 +1907,12 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, "Failed to request IRQ: %d\n", ret); /* initialize codec */ - ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_AB, ®); - devid = (reg & 0xFF) << 12; - - ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_CD, ®); - devid |= (reg & 0xFF) << 4; - - ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_E, ®); - devid |= (reg & 0xF0) >> 4; + devid = cirrus_read_device_id(cs42l42->regmap, CS42L42_DEVID_AB); + if (devid < 0) { + ret = devid; + dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + goto err_disable; + } if (devid != CS42L42_CHIP_ID) { ret = -ENODEV; @@ -1926,11 +1948,9 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, (1 << CS42L42_ADC_PDN_SHIFT) | (0 << CS42L42_PDN_ALL_SHIFT)); - if (i2c_client->dev.of_node) { - ret = cs42l42_handle_device_data(i2c_client, cs42l42); - if (ret != 0) - goto err_disable; - } + ret = cs42l42_handle_device_data(&i2c_client->dev, cs42l42); + if (ret != 0) + goto err_disable; /* Setup headset detection */ cs42l42_setup_hs_type_detect(cs42l42); @@ -2009,12 +2029,21 @@ static const struct dev_pm_ops cs42l42_runtime_pm = { NULL) }; +#ifdef CONFIG_OF static const struct of_device_id cs42l42_of_match[] = { { .compatible = "cirrus,cs42l42", }, - {}, + {} }; MODULE_DEVICE_TABLE(of, cs42l42_of_match); +#endif +#ifdef CONFIG_ACPI +static const struct acpi_device_id cs42l42_acpi_match[] = { + {"10134242", 0,}, + {} +}; +MODULE_DEVICE_TABLE(acpi, cs42l42_acpi_match); +#endif static const struct i2c_device_id cs42l42_id[] = { {"cs42l42", 0}, @@ -2027,7 +2056,8 @@ static struct i2c_driver cs42l42_i2c_driver = { .driver = { .name = "cs42l42", .pm = &cs42l42_runtime_pm, - .of_match_table = cs42l42_of_match, + .of_match_table = of_match_ptr(cs42l42_of_match), + .acpi_match_table = ACPI_PTR(cs42l42_acpi_match), }, .id_table = cs42l42_id, .probe = cs42l42_i2c_probe, diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 36b763f0d1a0..206b3c81d3e0 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -79,7 +79,7 @@ #define CS42L42_HP_PDN_SHIFT 3 #define CS42L42_HP_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT) #define CS42L42_ADC_PDN_SHIFT 2 -#define CS42L42_ADC_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT) +#define CS42L42_ADC_PDN_MASK (1 << CS42L42_ADC_PDN_SHIFT) #define CS42L42_PDN_ALL_SHIFT 0 #define CS42L42_PDN_ALL_MASK (1 << CS42L42_PDN_ALL_SHIFT) @@ -755,6 +755,7 @@ #define CS42L42_NUM_SUPPLIES 5 #define CS42L42_BOOT_TIME_US 3000 +#define CS42L42_PLL_DIVOUT_TIME_US 800 #define CS42L42_CLOCK_SWITCH_DELAY_US 150 #define CS42L42_PLL_LOCK_POLL_US 250 #define CS42L42_PLL_LOCK_TIMEOUT_US 1250 @@ -773,10 +774,11 @@ struct cs42l42_private { struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES]; struct gpio_desc *reset_gpio; struct completion pdn_done; - struct snd_soc_jack jack; + struct snd_soc_jack *jack; int bclk; u32 sclk; u32 srate; + u8 pll_divout; u8 plug_state; u8 hs_type; u8 ts_inv; @@ -787,6 +789,7 @@ struct cs42l42_private { u8 bias_thresholds[CS42L42_NUM_BIASES]; u8 hs_bias_ramp_rate; u8 hs_bias_ramp_time; + u8 hs_bias_sense_en; u8 stream_use; }; diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 796b894c390f..80161151b3f2 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -957,9 +957,8 @@ static int cs42l52_beep_event(struct input_dev *dev, unsigned int type, return 0; } -static ssize_t cs42l52_beep_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t beep_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct cs42l52_private *cs42l52 = dev_get_drvdata(dev); long int time; @@ -974,7 +973,7 @@ static ssize_t cs42l52_beep_set(struct device *dev, return count; } -static DEVICE_ATTR(beep, 0200, NULL, cs42l52_beep_set); +static DEVICE_ATTR_WO(beep); static void cs42l52_init_beep(struct snd_soc_component *component) { @@ -1093,7 +1092,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, struct cs42l52_private *cs42l52; struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev); int ret; - unsigned int devid = 0; + unsigned int devid; unsigned int reg; u32 val32; @@ -1163,6 +1162,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, ret); ret = regmap_read(cs42l52->regmap, CS42L52_CHIP, ®); + if (ret) { + dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret); + return ret; + } + devid = reg & CS42L52_CHIP_ID_MASK; if (devid != CS42L52_CHIP_ID) { ret = -ENODEV; @@ -1199,11 +1203,8 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, CS42L52_IFACE_CTL2_BIAS_LVL, cs42l52->pdata.micbias_lvl); - ret = devm_snd_soc_register_component(&i2c_client->dev, + return devm_snd_soc_register_component(&i2c_client->dev, &soc_component_dev_cs42l52, &cs42l52_dai, 1); - if (ret < 0) - return ret; - return 0; } static const struct of_device_id cs42l52_of_match[] = { diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 7cdffdf6b8cf..3cf8a0b4478c 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1021,9 +1021,8 @@ static int cs42l56_beep_event(struct input_dev *dev, unsigned int type, return 0; } -static ssize_t cs42l56_beep_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t beep_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct cs42l56_private *cs42l56 = dev_get_drvdata(dev); long int time; @@ -1038,7 +1037,7 @@ static ssize_t cs42l56_beep_set(struct device *dev, return count; } -static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set); +static DEVICE_ATTR_WO(beep); static void cs42l56_init_beep(struct snd_soc_component *component) { diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index e92bacaab53f..018463f34e12 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -27,6 +27,7 @@ #include <sound/tlv.h> #include <sound/cs42l73.h> #include "cs42l73.h" +#include "cirrus_legacy.h" struct sp_config { u8 spc, mmcc, spfs; @@ -1278,8 +1279,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, { struct cs42l73_private *cs42l73; struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev); - int ret; - unsigned int devid = 0; + int ret, devid; unsigned int reg; u32 val32; @@ -1329,27 +1329,25 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, } /* initialize codec */ - ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); - devid = (reg & 0xFF) << 12; - - ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_CD, ®); - devid |= (reg & 0xFF) << 4; - - ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, ®); - devid |= (reg & 0xF0) >> 4; + devid = cirrus_read_device_id(cs42l73->regmap, CS42L73_DEVID_AB); + if (devid < 0) { + ret = devid; + dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + goto err_reset; + } if (devid != CS42L73_DEVID) { ret = -ENODEV; dev_err(&i2c_client->dev, "CS42L73 Device ID (%X). Expected %X\n", devid, CS42L73_DEVID); - return ret; + goto err_reset; } ret = regmap_read(cs42l73->regmap, CS42L73_REVID, ®); if (ret < 0) { dev_err(&i2c_client->dev, "Get Revision ID failed\n"); - return ret; + goto err_reset; } dev_info(&i2c_client->dev, @@ -1359,8 +1357,14 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, &soc_component_dev_cs42l73, cs42l73_dai, ARRAY_SIZE(cs42l73_dai)); if (ret < 0) - return ret; + goto err_reset; + return 0; + +err_reset: + gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0); + + return ret; } static const struct of_device_id cs42l73_of_match[] = { diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 80cd3ea0c157..44b20c1ef851 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -36,6 +36,7 @@ #include <sound/jack.h> #include "cs43130.h" +#include "cirrus_legacy.h" static const struct reg_default cs43130_reg_defaults[] = { {CS43130_SYS_CLK_CTL_1, 0x06}, @@ -1671,14 +1672,14 @@ static int cs43130_show_dc(struct device *dev, char *buf, u8 ch) cs43130->hpload_dc[ch]); } -static ssize_t cs43130_show_dc_l(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hpload_dc_l_show(struct device *dev, + struct device_attribute *attr, char *buf) { return cs43130_show_dc(dev, buf, HP_LEFT); } -static ssize_t cs43130_show_dc_r(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hpload_dc_r_show(struct device *dev, + struct device_attribute *attr, char *buf) { return cs43130_show_dc(dev, buf, HP_RIGHT); } @@ -1718,22 +1719,22 @@ static int cs43130_show_ac(struct device *dev, char *buf, u8 ch) } } -static ssize_t cs43130_show_ac_l(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hpload_ac_l_show(struct device *dev, + struct device_attribute *attr, char *buf) { return cs43130_show_ac(dev, buf, HP_LEFT); } -static ssize_t cs43130_show_ac_r(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hpload_ac_r_show(struct device *dev, + struct device_attribute *attr, char *buf) { return cs43130_show_ac(dev, buf, HP_RIGHT); } -static DEVICE_ATTR(hpload_dc_l, 0444, cs43130_show_dc_l, NULL); -static DEVICE_ATTR(hpload_dc_r, 0444, cs43130_show_dc_r, NULL); -static DEVICE_ATTR(hpload_ac_l, 0444, cs43130_show_ac_l, NULL); -static DEVICE_ATTR(hpload_ac_r, 0444, cs43130_show_ac_r, NULL); +static DEVICE_ATTR_RO(hpload_dc_l); +static DEVICE_ATTR_RO(hpload_dc_r); +static DEVICE_ATTR_RO(hpload_ac_l); +static DEVICE_ATTR_RO(hpload_ac_r); static struct attribute *hpload_attrs[] = { &dev_attr_hpload_dc_l.attr, @@ -2422,9 +2423,8 @@ static int cs43130_i2c_probe(struct i2c_client *client, { struct cs43130_private *cs43130; int ret; - unsigned int devid = 0; unsigned int reg; - int i; + int i, devid; cs43130 = devm_kzalloc(&client->dev, sizeof(*cs43130), GFP_KERNEL); if (!cs43130) @@ -2462,20 +2462,21 @@ static int cs43130_i2c_probe(struct i2c_client *client, cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(cs43130->reset_gpio)) - return PTR_ERR(cs43130->reset_gpio); + if (IS_ERR(cs43130->reset_gpio)) { + ret = PTR_ERR(cs43130->reset_gpio); + goto err_supplies; + } gpiod_set_value_cansleep(cs43130->reset_gpio, 1); usleep_range(2000, 2050); - ret = regmap_read(cs43130->regmap, CS43130_DEVID_AB, ®); - - devid = (reg & 0xFF) << 12; - ret = regmap_read(cs43130->regmap, CS43130_DEVID_CD, ®); - devid |= (reg & 0xFF) << 4; - ret = regmap_read(cs43130->regmap, CS43130_DEVID_E, ®); - devid |= (reg & 0xF0) >> 4; + devid = cirrus_read_device_id(cs43130->regmap, CS43130_DEVID_AB); + if (devid < 0) { + ret = devid; + dev_err(&client->dev, "Failed to read device ID: %d\n", ret); + goto err; + } switch (devid) { case CS43130_CHIP_ID: @@ -2515,7 +2516,7 @@ static int cs43130_i2c_probe(struct i2c_client *client, "cs43130", cs43130); if (ret != 0) { dev_err(&client->dev, "Failed to request IRQ: %d\n", ret); - return ret; + goto err; } cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; @@ -2574,7 +2575,13 @@ static int cs43130_i2c_probe(struct i2c_client *client, CS43130_XSP_3ST_MASK, 0); return 0; + err: + gpiod_set_value_cansleep(cs43130->reset_gpio, 0); +err_supplies: + regulator_bulk_disable(ARRAY_SIZE(cs43130->supplies), + cs43130->supplies); + return ret; } diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index eaabbb56a173..6b6d08816024 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1178,7 +1178,7 @@ static unsigned int cs47l24_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_4L, }; -static struct snd_compress_ops cs47l24_compress_ops = { +static const struct snd_compress_ops cs47l24_compress_ops = { .open = cs47l24_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index abe0cc0bc03a..f2087bd38dbc 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -20,6 +20,7 @@ #include <sound/tlv.h> #include "cs53l30.h" +#include "cirrus_legacy.h" #define CS53L30_NUM_SUPPLIES 2 static const char *const cs53l30_supply_names[CS53L30_NUM_SUPPLIES] = { @@ -923,9 +924,8 @@ static int cs53l30_i2c_probe(struct i2c_client *client, const struct device_node *np = client->dev.of_node; struct device *dev = &client->dev; struct cs53l30_private *cs53l30; - unsigned int devid = 0; unsigned int reg; - int ret = 0, i; + int ret = 0, i, devid; u8 val; cs53l30 = devm_kzalloc(dev, sizeof(*cs53l30), GFP_KERNEL); @@ -954,7 +954,7 @@ static int cs53l30_i2c_probe(struct i2c_client *client, GPIOD_OUT_LOW); if (IS_ERR(cs53l30->reset_gpio)) { ret = PTR_ERR(cs53l30->reset_gpio); - goto error; + goto error_supplies; } gpiod_set_value_cansleep(cs53l30->reset_gpio, 1); @@ -971,14 +971,12 @@ static int cs53l30_i2c_probe(struct i2c_client *client, } /* Initialize codec */ - ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_AB, ®); - devid = reg << 12; - - ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_CD, ®); - devid |= reg << 4; - - ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_E, ®); - devid |= (reg & 0xF0) >> 4; + devid = cirrus_read_device_id(cs53l30->regmap, CS53L30_DEVID_AB); + if (devid < 0) { + ret = devid; + dev_err(dev, "Failed to read device ID: %d\n", ret); + goto error; + } if (devid != CS53L30_DEVID) { ret = -ENODEV; @@ -1040,6 +1038,8 @@ static int cs53l30_i2c_probe(struct i2c_client *client, return 0; error: + gpiod_set_value_cansleep(cs53l30->reset_gpio, 0); +error_supplies: regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), cs53l30->supplies); return ret; diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 1567ba196ab9..b61f980cabdc 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -277,6 +277,7 @@ struct hdmi_codec_priv { bool busy; struct snd_soc_jack *jack; unsigned int jack_status; + u8 iec_status[5]; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -385,6 +386,47 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } +static int hdmi_codec_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int hdmi_codec_iec958_default_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + + memcpy(ucontrol->value.iec958.status, hcp->iec_status, + sizeof(hcp->iec_status)); + + return 0; +} + +static int hdmi_codec_iec958_default_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + + memcpy(hcp->iec_status, ucontrol->value.iec958.status, + sizeof(hcp->iec_status)); + + return 0; +} + +static int hdmi_codec_iec958_mask_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memset(ucontrol->value.iec958.status, 0xff, + sizeof_field(struct hdmi_codec_priv, iec_status)); + + return 0; +} + static int hdmi_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -439,6 +481,42 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, mutex_unlock(&hcp->lock); } +static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai, + unsigned int sample_width, + unsigned int sample_rate, + unsigned int channels, + struct hdmi_codec_params *hp) +{ + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + int idx; + + /* Select a channel allocation that matches with ELD and pcm channels */ + idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels); + if (idx < 0) { + dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", + idx); + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + return idx; + } + + memset(hp, 0, sizeof(*hp)); + + hdmi_audio_infoframe_init(&hp->cea); + hp->cea.channels = channels; + hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; + hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; + hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; + hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; + + hp->sample_width = sample_width; + hp->sample_rate = sample_rate; + hp->channels = channels; + + hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; + + return 0; +} + static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -453,46 +531,73 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, .dig_subframe = { 0 }, } }; - int ret, idx; + int ret; + + if (!hcp->hcd.ops->hw_params) + return 0; dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, params_width(params), params_rate(params), params_channels(params)); - ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status, - sizeof(hp.iec.status)); + ret = hdmi_codec_fill_codec_params(dai, + params_width(params), + params_rate(params), + params_channels(params), + &hp); + if (ret < 0) + return ret; + + memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status)); + ret = snd_pcm_fill_iec958_consumer_hw_params(params, hp.iec.status, + sizeof(hp.iec.status)); if (ret < 0) { dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", ret); return ret; } - hdmi_audio_infoframe_init(&hp.cea); - hp.cea.channels = params_channels(params); - hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; - hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; - hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; - - /* Select a channel allocation that matches with ELD and pcm channels */ - idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels); - if (idx < 0) { - dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", - idx); - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - return idx; - } - hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; - hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; - - hp.sample_width = params_width(params); - hp.sample_rate = params_rate(params); - hp.channels = params_channels(params); - cf->bit_fmt = params_format(params); return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, cf, &hp); } +static int hdmi_codec_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int channels = runtime->channels; + unsigned int width = snd_pcm_format_width(runtime->format); + unsigned int rate = runtime->rate; + struct hdmi_codec_params hp; + int ret; + + if (!hcp->hcd.ops->prepare) + return 0; + + dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, + width, rate, channels); + + ret = hdmi_codec_fill_codec_params(dai, width, rate, channels, &hp); + if (ret < 0) + return ret; + + memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status)); + ret = snd_pcm_fill_iec958_consumer(runtime, hp.iec.status, + sizeof(hp.iec.status)); + if (ret < 0) { + dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", + ret); + return ret; + } + + cf->bit_fmt = runtime->format; + return hcp->hcd.ops->prepare(dai->dev->parent, hcp->hcd.data, + cf, &hp); +} + static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { @@ -580,12 +685,34 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction) return -ENOTSUPP; } +/* + * This driver can select all SND_SOC_DAIFMT_CBx_CFx, + * but need to be selected from Sound Card, not be auto selected. + * Because it might be used from other driver. + * For example, + * ${LINUX}/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c + */ +static u64 hdmi_codec_formats = + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF | + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_AC97; + static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { .startup = hdmi_codec_startup, .shutdown = hdmi_codec_shutdown, .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, .set_fmt = hdmi_codec_i2s_set_fmt, .mute_stream = hdmi_codec_mute, + .auto_selectable_formats = &hdmi_codec_formats, + .num_auto_selectable_formats = 1, }; static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { @@ -620,21 +747,37 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) +static struct snd_kcontrol_new hdmi_codec_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = hdmi_codec_iec958_info, + .get = hdmi_codec_iec958_mask_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = hdmi_codec_iec958_info, + .get = hdmi_codec_iec958_default_get, + .put = hdmi_codec_iec958_default_put, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "ELD", + .info = hdmi_eld_ctl_info, + .get = hdmi_eld_ctl_get, + }, +}; + static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_dai_driver *drv = dai->driver; struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - struct snd_kcontrol *kctl; - struct snd_kcontrol_new hdmi_eld_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READ | - SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "ELD", - .info = hdmi_eld_ctl_info, - .get = hdmi_eld_ctl_get, - .device = rtd->pcm->device, - }; + unsigned int i; int ret; ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -651,12 +794,21 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - /* add ELD ctl with the device number corresponding to the PCM stream */ - kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); - if (!kctl) - return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(hdmi_codec_controls); i++) { + struct snd_kcontrol *kctl; + + /* add ELD ctl with the device number corresponding to the PCM stream */ + kctl = snd_ctl_new1(&hdmi_codec_controls[i], dai->component); + if (!kctl) + return -ENOMEM; - return snd_ctl_add(rtd->card->snd_card, kctl); + kctl->id.device = rtd->pcm->device; + ret = snd_ctl_add(rtd->card->snd_card, kctl); + if (ret < 0) + return ret; + } + + return 0; } static int hdmi_dai_probe(struct snd_soc_dai *dai) @@ -849,7 +1001,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) } dai_count = hcd->i2s + hcd->spdif; - if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params || + if (dai_count < 1 || !hcd->ops || + (!hcd->ops->hw_params && !hcd->ops->prepare) || !hcd->ops->audio_shutdown) { dev_err(dev, "%s: Invalid parameters\n", __func__); return -EINVAL; @@ -862,6 +1015,11 @@ static int hdmi_codec_probe(struct platform_device *pdev) hcp->hcd = *hcd; mutex_init(&hcp->lock); + ret = snd_pcm_create_iec958_consumer_default(hcp->iec_status, + sizeof(hcp->iec_status)); + if (ret < 0) + return ret; + daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); if (!daidrv) return -ENOMEM; diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 171ab7f519c0..3622961f7c2c 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -2628,7 +2628,7 @@ static int rx_macro_enable_rx_path_clk(struct snd_soc_dapm_widget *w, break; default: break; - }; + } return 0; } diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 1a7fa5492f28..d3ac318fd6b6 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -1727,6 +1727,10 @@ static int wsa_macro_enable_echo(struct snd_soc_dapm_widget *w, val = val & CDC_WSA_RX_MIX_TX1_SEL_MASK; ec_tx = (val >> CDC_WSA_RX_MIX_TX1_SEL_SHFT) - 1; break; + default: + dev_err(component->dev, "%s: Invalid shift %u\n", + __func__, w->shift); + return -EINVAL; } if (wsa->ec_hq[ec_tx]) { diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index f3a12205cd48..dc520effc61c 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -271,7 +271,7 @@ static __maybe_unused int max98373_resume(struct device *dev) struct max98373_priv *max98373 = dev_get_drvdata(dev); unsigned long time; - if (!max98373->hw_init) + if (!max98373->first_hw_init) return 0; if (!slave->unattach_request) @@ -362,7 +362,7 @@ static int max98373_io_init(struct sdw_slave *slave) struct device *dev = &slave->dev; struct max98373_priv *max98373 = dev_get_drvdata(dev); - if (max98373->pm_init_once) { + if (max98373->first_hw_init) { regcache_cache_only(max98373->regmap, false); regcache_cache_bypass(max98373->regmap, true); } @@ -370,7 +370,7 @@ static int max98373_io_init(struct sdw_slave *slave) /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!max98373->pm_init_once) { + if (!max98373->first_hw_init) { /* set autosuspend parameters */ pm_runtime_set_autosuspend_delay(dev, 3000); pm_runtime_use_autosuspend(dev); @@ -462,12 +462,12 @@ static int max98373_io_init(struct sdw_slave *slave) regmap_write(max98373->regmap, MAX98373_R20B5_BDE_EN, 1); regmap_write(max98373->regmap, MAX98373_R20E2_LIMITER_EN, 1); - if (max98373->pm_init_once) { + if (max98373->first_hw_init) { regcache_cache_bypass(max98373->regmap, false); regcache_mark_dirty(max98373->regmap); } - max98373->pm_init_once = true; + max98373->first_hw_init = true; max98373->hw_init = true; pm_runtime_mark_last_busy(dev); @@ -787,6 +787,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap) max98373->cache = devm_kcalloc(dev, max98373->cache_num, sizeof(*max98373->cache), GFP_KERNEL); + if (!max98373->cache) + return -ENOMEM; for (i = 0; i < max98373->cache_num; i++) max98373->cache[i].reg = max98373_sdw_cache_reg[i]; @@ -795,7 +797,7 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap) max98373_slot_config(dev, max98373); max98373->hw_init = false; - max98373->pm_init_once = false; + max98373->first_hw_init = false; /* codec registration */ ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw, diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h index 73a2cf69d84a..e1810b3b1620 100644 --- a/sound/soc/codecs/max98373.h +++ b/sound/soc/codecs/max98373.h @@ -226,7 +226,7 @@ struct max98373_priv { /* variables to support soundwire */ struct sdw_slave *slave; bool hw_init; - bool pm_init_once; + bool first_hw_init; int slot; unsigned int rx_mask; }; diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c index 4222aed013f1..78314187d37e 100644 --- a/sound/soc/codecs/mt6359-accdet.c +++ b/sound/soc/codecs/mt6359-accdet.c @@ -414,7 +414,7 @@ static void mt6359_accdet_work(struct work_struct *work) static void mt6359_accdet_jd_work(struct work_struct *work) { - int ret = 0; + int ret; unsigned int value = 0; struct mt6359_accdet *priv = diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index b909b36582b7..2d6a4a29b850 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -271,7 +271,7 @@ static void hp_aux_feedback_loop_gain_ramp(struct mt6359_priv *priv, bool up) static void hp_in_pair_current(struct mt6359_priv *priv, bool increase) { - int i = 0, stage = 0; + int i, stage; int target = 0x3; /* Set input diff pair bias select (Hi-Fi mode) */ diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 821e7395f90f..b6fd412441a1 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -573,6 +573,30 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return 0; } +static u64 pcm3168a_dai_formats[] = { + /* + * Select below from Sound Card, not here + * SND_SOC_DAIFMT_CBC_CFC + * SND_SOC_DAIFMT_CBP_CFP + */ + + /* + * First Priority + */ + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J, + /* + * Second Priority + * + * These have picky limitation. + * see + * pcm3168a_hw_params() + */ + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B, +}; + static const struct snd_soc_dai_ops pcm3168a_dai_ops = { .set_fmt = pcm3168a_set_dai_fmt, .set_sysclk = pcm3168a_set_dai_sysclk, @@ -580,6 +604,8 @@ static const struct snd_soc_dai_ops pcm3168a_dai_ops = { .mute_stream = pcm3168a_mute, .set_tdm_slot = pcm3168a_set_tdm_slot, .no_capture_mute = 1, + .auto_selectable_formats = pcm3168a_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(pcm3168a_dai_formats), }; static struct snd_soc_dai_driver pcm3168a_dais[] = { diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index bfefefcc76d8..758d439e8c7a 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -474,7 +474,8 @@ static int rk3328_platform_probe(struct platform_device *pdev) rk3328->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(rk3328->pclk)) { dev_err(&pdev->dev, "can't get acodec pclk\n"); - return PTR_ERR(rk3328->pclk); + ret = PTR_ERR(rk3328->pclk); + goto err_unprepare_mclk; } ret = clk_prepare_enable(rk3328->pclk); @@ -484,19 +485,34 @@ static int rk3328_platform_probe(struct platform_device *pdev) } base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto err_unprepare_pclk; + } rk3328->regmap = devm_regmap_init_mmio(&pdev->dev, base, &rk3328_codec_regmap_config); - if (IS_ERR(rk3328->regmap)) - return PTR_ERR(rk3328->regmap); + if (IS_ERR(rk3328->regmap)) { + ret = PTR_ERR(rk3328->regmap); + goto err_unprepare_pclk; + } platform_set_drvdata(pdev, rk3328); - return devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328, + ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328, rk3328_dai, ARRAY_SIZE(rk3328_dai)); + if (ret) + goto err_unprepare_pclk; + + return 0; + +err_unprepare_pclk: + clk_disable_unprepare(rk3328->pclk); + +err_unprepare_mclk: + clk_disable_unprepare(rk3328->mclk); + return ret; } static const struct of_device_id rk3328_codec_of_match[] __maybe_unused = { diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c new file mode 100644 index 000000000000..943d7d933e81 --- /dev/null +++ b/sound/soc/codecs/rk817_codec.c @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// rk817 ALSA SoC Audio driver +// +// Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/mfd/rk808.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +struct rk817_codec_priv { + struct snd_soc_component *component; + struct rk808 *rk808; + struct clk *mclk; + unsigned int stereo_sysclk; + bool mic_in_differential; +}; + +/* + * This sets the codec up with the values defined in the default implementation including the APLL + * from the Rockchip vendor kernel. I do not know if these values are universal despite differing + * from the default values defined above and taken from the datasheet, or implementation specific. + * I don't have another implementation to compare from the Rockchip sources. Hard-coding for now. + * Additionally, I do not know according to the documentation the units accepted for the clock + * values, so for the moment those are left unvalidated. + */ + +static int rk817_init(struct snd_soc_component *component) +{ + struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); + + snd_soc_component_write(component, RK817_CODEC_DDAC_POPD_DACST, 0x02); + snd_soc_component_write(component, RK817_CODEC_DDAC_SR_LMT0, 0x02); + snd_soc_component_write(component, RK817_CODEC_DADC_SR_ACL0, 0x02); + snd_soc_component_write(component, RK817_CODEC_DTOP_VUCTIME, 0xf4); + if (rk817->mic_in_differential) { + snd_soc_component_update_bits(component, RK817_CODEC_AMIC_CFG0, MIC_DIFF_MASK, + MIC_DIFF_EN); + } + + return 0; +} + +static int rk817_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, unsigned int freq_in, + unsigned int freq_out) +{ + /* Set resistor value and charge pump current for PLL. */ + snd_soc_component_write(component, RK817_CODEC_APLL_CFG1, 0x58); + /* Set the PLL feedback clock divide value (values not documented). */ + snd_soc_component_write(component, RK817_CODEC_APLL_CFG2, 0x2d); + /* Set the PLL pre-divide value (values not documented). */ + snd_soc_component_write(component, RK817_CODEC_APLL_CFG3, 0x0c); + /* Set the PLL VCO output clock divide and PLL divided ratio of PLL High Clk (values not + * documented). + */ + snd_soc_component_write(component, RK817_CODEC_APLL_CFG4, 0xa5); + + return 0; +} + +/* + * DDAC/DADC L/R volume setting + * 0db~-95db, 0.375db/step, for example: + * 0x00: 0dB + * 0xff: -95dB + */ + +static const DECLARE_TLV_DB_MINMAX(rk817_vol_tlv, -9500, 0); + +/* + * PGA GAIN L/R volume setting + * 27db~-18db, 3db/step, for example: + * 0x0: -18dB + * 0xf: 27dB + */ + +static const DECLARE_TLV_DB_MINMAX(rk817_gain_tlv, -1800, 2700); + +static const struct snd_kcontrol_new rk817_volume_controls[] = { + SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume", RK817_CODEC_DDAC_VOLL, + RK817_CODEC_DDAC_VOLR, 0, 0x00, 0xff, 1, rk817_vol_tlv), + SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume", RK817_CODEC_DADC_VOLL, + RK817_CODEC_DADC_VOLR, 0, 0x00, 0xff, 1, rk817_vol_tlv), + SOC_DOUBLE_TLV("Mic Capture Gain", RK817_CODEC_DMIC_PGA_GAIN, 4, 0, 0xf, 0, + rk817_gain_tlv), +}; + +/* Since the speaker output and L headphone pin are internally the same, make audio path mutually + * exclusive with a mux. + */ + +static const char *dac_mux_text[] = { + "HP", + "SPK", +}; + +static SOC_ENUM_SINGLE_VIRT_DECL(dac_enum, dac_mux_text); + +static const struct snd_kcontrol_new dac_mux = + SOC_DAPM_ENUM("Playback Mux", dac_enum); + +static const struct snd_soc_dapm_widget rk817_dapm_widgets[] = { + + /* capture/playback common */ + SND_SOC_DAPM_SUPPLY("LDO Regulator", RK817_CODEC_AREF_RTCFG1, 6, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("IBIAS Block", RK817_CODEC_AREF_RTCFG1, 2, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("VAvg Buffer", RK817_CODEC_AREF_RTCFG1, 1, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL Power", RK817_CODEC_APLL_CFG5, 0, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S TX1 Transfer Start", RK817_CODEC_DI2S_RXCMD_TSD, 5, 0, NULL, 0), + + /* capture path common */ + SND_SOC_DAPM_SUPPLY("ADC Clock", RK817_CODEC_DTOP_DIGEN_CLKE, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S TX Clock", RK817_CODEC_DTOP_DIGEN_CLKE, 6, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Channel Enable", RK817_CODEC_DTOP_DIGEN_CLKE, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S TX Channel Enable", RK817_CODEC_DTOP_DIGEN_CLKE, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MIC Power On", RK817_CODEC_AMIC_CFG0, 6, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S TX3 Transfer Start", RK817_CODEC_DI2S_TXCR3_TXCMD, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S TX3 Right Justified", RK817_CODEC_DI2S_TXCR3_TXCMD, 3, 0, NULL, 0), + + /* capture path L */ + SND_SOC_DAPM_ADC("ADC L", "Capture", RK817_CODEC_AADC_CFG0, 7, 1), + SND_SOC_DAPM_SUPPLY("PGA L Power On", RK817_CODEC_AMIC_CFG0, 5, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Boost L1", RK817_CODEC_AMIC_CFG0, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Boost L2", RK817_CODEC_AMIC_CFG0, 2, 0, NULL, 0), + + /* capture path R */ + SND_SOC_DAPM_ADC("ADC R", "Capture", RK817_CODEC_AADC_CFG0, 6, 1), + SND_SOC_DAPM_SUPPLY("PGA R Power On", RK817_CODEC_AMIC_CFG0, 4, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Boost R1", RK817_CODEC_AMIC_CFG0, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Boost R2", RK817_CODEC_AMIC_CFG0, 3, 0, NULL, 0), + + /* playback path common */ + SND_SOC_DAPM_SUPPLY("DAC Clock", RK817_CODEC_DTOP_DIGEN_CLKE, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S RX Clock", RK817_CODEC_DTOP_DIGEN_CLKE, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Channel Enable", RK817_CODEC_DTOP_DIGEN_CLKE, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S RX Channel Enable", RK817_CODEC_DTOP_DIGEN_CLKE, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Bias", RK817_CODEC_ADAC_CFG1, 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mute Off", RK817_CODEC_DDAC_MUTE_MIXCTL, 0, 1, NULL, 0), + + /* playback path speaker */ + SND_SOC_DAPM_SUPPLY("Class D Mode", RK817_CODEC_DDAC_MUTE_MIXCTL, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("High Pass Filter", RK817_CODEC_DDAC_MUTE_MIXCTL, 7, 0, NULL, 0), + SND_SOC_DAPM_DAC("SPK DAC", "Playback", RK817_CODEC_ADAC_CFG1, 2, 1), + SND_SOC_DAPM_SUPPLY("Enable Class D", RK817_CODEC_ACLASSD_CFG1, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Disable Class D Mute Ramp", RK817_CODEC_ACLASSD_CFG1, 6, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Class D Mute Rate 1", RK817_CODEC_ACLASSD_CFG1, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Class D Mute Rate 2", RK817_CODEC_ACLASSD_CFG1, 2, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Class D OCPP 2", RK817_CODEC_ACLASSD_CFG2, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Class D OCPP 3", RK817_CODEC_ACLASSD_CFG2, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Class D OCPN 2", RK817_CODEC_ACLASSD_CFG2, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Class D OCPN 3", RK817_CODEC_ACLASSD_CFG2, 0, 0, NULL, 0), + + /* playback path headphones */ + SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", RK817_CODEC_AHP_CP, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone CP Discharge LDO", RK817_CODEC_AHP_CP, 3, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone OStage", RK817_CODEC_AHP_CFG0, 6, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Headphone Pre Amp", RK817_CODEC_AHP_CFG0, 5, 1, NULL, 0), + SND_SOC_DAPM_DAC("DAC L", "Playback", RK817_CODEC_ADAC_CFG1, 1, 1), + SND_SOC_DAPM_DAC("DAC R", "Playback", RK817_CODEC_ADAC_CFG1, 0, 1), + + /* Mux for input/output path selection */ + SND_SOC_DAPM_MUX("Playback Mux", SND_SOC_NOPM, 1, 0, &dac_mux), + + /* Pins for Simple Card Bindings */ + SND_SOC_DAPM_INPUT("MICL"), + SND_SOC_DAPM_INPUT("MICR"), + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("SPKO"), +}; + +static const struct snd_soc_dapm_route rk817_dapm_routes[] = { + + /* capture path */ + /* left mic */ + {"ADC L", NULL, "LDO Regulator"}, + {"ADC L", NULL, "IBIAS Block"}, + {"ADC L", NULL, "VAvg Buffer"}, + {"ADC L", NULL, "PLL Power"}, + {"ADC L", NULL, "ADC Clock"}, + {"ADC L", NULL, "I2S TX Clock"}, + {"ADC L", NULL, "ADC Channel Enable"}, + {"ADC L", NULL, "I2S TX Channel Enable"}, + {"ADC L", NULL, "I2S TX1 Transfer Start"}, + {"MICL", NULL, "MIC Power On"}, + {"MICL", NULL, "PGA L Power On"}, + {"MICL", NULL, "Mic Boost L1"}, + {"MICL", NULL, "Mic Boost L2"}, + {"MICL", NULL, "I2S TX3 Transfer Start"}, + {"MICL", NULL, "I2S TX3 Right Justified"}, + {"ADC L", NULL, "MICL"}, + + /* right mic */ + {"ADC R", NULL, "LDO Regulator"}, + {"ADC R", NULL, "IBIAS Block"}, + {"ADC R", NULL, "VAvg Buffer"}, + {"ADC R", NULL, "PLL Power"}, + {"ADC R", NULL, "ADC Clock"}, + {"ADC R", NULL, "I2S TX Clock"}, + {"ADC R", NULL, "ADC Channel Enable"}, + {"ADC R", NULL, "I2S TX Channel Enable"}, + {"ADC R", NULL, "I2S TX1 Transfer Start"}, + {"MICR", NULL, "MIC Power On"}, + {"MICR", NULL, "PGA R Power On"}, + {"MICR", NULL, "Mic Boost R1"}, + {"MICR", NULL, "Mic Boost R2"}, + {"MICR", NULL, "I2S TX3 Transfer Start"}, + {"MICR", NULL, "I2S TX3 Right Justified"}, + {"ADC R", NULL, "MICR"}, + + /* playback path */ + /* speaker path */ + {"SPK DAC", NULL, "LDO Regulator"}, + {"SPK DAC", NULL, "IBIAS Block"}, + {"SPK DAC", NULL, "VAvg Buffer"}, + {"SPK DAC", NULL, "PLL Power"}, + {"SPK DAC", NULL, "I2S TX1 Transfer Start"}, + {"SPK DAC", NULL, "DAC Clock"}, + {"SPK DAC", NULL, "I2S RX Clock"}, + {"SPK DAC", NULL, "DAC Channel Enable"}, + {"SPK DAC", NULL, "I2S RX Channel Enable"}, + {"SPK DAC", NULL, "Class D Mode"}, + {"SPK DAC", NULL, "DAC Bias"}, + {"SPK DAC", NULL, "DAC Mute Off"}, + {"SPK DAC", NULL, "Enable Class D"}, + {"SPK DAC", NULL, "Disable Class D Mute Ramp"}, + {"SPK DAC", NULL, "Class D Mute Rate 1"}, + {"SPK DAC", NULL, "Class D Mute Rate 2"}, + {"SPK DAC", NULL, "Class D OCPP 2"}, + {"SPK DAC", NULL, "Class D OCPP 3"}, + {"SPK DAC", NULL, "Class D OCPN 2"}, + {"SPK DAC", NULL, "Class D OCPN 3"}, + {"SPK DAC", NULL, "High Pass Filter"}, + + /* headphone path L */ + {"DAC L", NULL, "LDO Regulator"}, + {"DAC L", NULL, "IBIAS Block"}, + {"DAC L", NULL, "VAvg Buffer"}, + {"DAC L", NULL, "PLL Power"}, + {"DAC L", NULL, "I2S TX1 Transfer Start"}, + {"DAC L", NULL, "DAC Clock"}, + {"DAC L", NULL, "I2S RX Clock"}, + {"DAC L", NULL, "DAC Channel Enable"}, + {"DAC L", NULL, "I2S RX Channel Enable"}, + {"DAC L", NULL, "DAC Bias"}, + {"DAC L", NULL, "DAC Mute Off"}, + {"DAC L", NULL, "Headphone Charge Pump"}, + {"DAC L", NULL, "Headphone CP Discharge LDO"}, + {"DAC L", NULL, "Headphone OStage"}, + {"DAC L", NULL, "Headphone Pre Amp"}, + + /* headphone path R */ + {"DAC R", NULL, "LDO Regulator"}, + {"DAC R", NULL, "IBIAS Block"}, + {"DAC R", NULL, "VAvg Buffer"}, + {"DAC R", NULL, "PLL Power"}, + {"DAC R", NULL, "I2S TX1 Transfer Start"}, + {"DAC R", NULL, "DAC Clock"}, + {"DAC R", NULL, "I2S RX Clock"}, + {"DAC R", NULL, "DAC Channel Enable"}, + {"DAC R", NULL, "I2S RX Channel Enable"}, + {"DAC R", NULL, "DAC Bias"}, + {"DAC R", NULL, "DAC Mute Off"}, + {"DAC R", NULL, "Headphone Charge Pump"}, + {"DAC R", NULL, "Headphone CP Discharge LDO"}, + {"DAC R", NULL, "Headphone OStage"}, + {"DAC R", NULL, "Headphone Pre Amp"}, + + /* mux path for output selection */ + {"Playback Mux", "HP", "DAC L"}, + {"Playback Mux", "HP", "DAC R"}, + {"Playback Mux", "SPK", "SPK DAC"}, + {"SPKO", NULL, "Playback Mux"}, + {"HPOL", NULL, "Playback Mux"}, + {"HPOR", NULL, "Playback Mux"}, +}; + +static int rk817_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); + + rk817->stereo_sysclk = freq; + + return 0; +} + +static int rk817_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + unsigned int i2s_mst = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + i2s_mst |= RK817_I2S_MODE_SLV; + break; + case SND_SOC_DAIFMT_CBM_CFM: + i2s_mst |= RK817_I2S_MODE_MST; + break; + default: + dev_err(component->dev, "%s : set master mask failed!\n", __func__); + return -EINVAL; + } + + snd_soc_component_update_bits(component, RK817_CODEC_DI2S_CKM, + RK817_I2S_MODE_MASK, i2s_mst); + + return 0; +} + +static int rk817_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_component_write(component, RK817_CODEC_DI2S_RXCR2, + VDW_RX_16BITS); + snd_soc_component_write(component, RK817_CODEC_DI2S_TXCR2, + VDW_TX_16BITS); + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + snd_soc_component_write(component, RK817_CODEC_DI2S_RXCR2, + VDW_RX_24BITS); + snd_soc_component_write(component, RK817_CODEC_DI2S_TXCR2, + VDW_TX_24BITS); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + + if (mute) + snd_soc_component_update_bits(component, + RK817_CODEC_DDAC_MUTE_MIXCTL, + DACMT_MASK, DACMT_ENABLE); + else + snd_soc_component_update_bits(component, + RK817_CODEC_DDAC_MUTE_MIXCTL, + DACMT_MASK, DACMT_DISABLE); + + return 0; +} + +#define RK817_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000) + +#define RK817_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000) + +#define RK817_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops rk817_dai_ops = { + .hw_params = rk817_hw_params, + .set_fmt = rk817_set_dai_fmt, + .set_sysclk = rk817_set_dai_sysclk, + .mute_stream = rk817_digital_mute, + .no_capture_mute = 1, +}; + +static struct snd_soc_dai_driver rk817_dai[] = { + { + .name = "rk817-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 8, + .rates = RK817_PLAYBACK_RATES, + .formats = RK817_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RK817_CAPTURE_RATES, + .formats = RK817_FORMATS, + }, + .ops = &rk817_dai_ops, + }, +}; + +static int rk817_probe(struct snd_soc_component *component) +{ + struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component); + struct rk808 *rk808 = dev_get_drvdata(component->dev->parent); + + snd_soc_component_init_regmap(component, rk808->regmap); + rk817->component = component; + + snd_soc_component_write(component, RK817_CODEC_DTOP_LPT_SRST, 0x40); + + rk817_init(component); + + /* setting initial pll values so that we can continue to leverage simple-audio-card. + * The values aren't important since no parameters are used. + */ + + snd_soc_component_set_pll(component, 0, 0, 0, 0); + + return 0; +} + +static void rk817_remove(struct snd_soc_component *component) +{ + snd_soc_component_exit_regmap(component); +} + +static const struct snd_soc_component_driver soc_codec_dev_rk817 = { + .probe = rk817_probe, + .remove = rk817_remove, + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, + .controls = rk817_volume_controls, + .num_controls = ARRAY_SIZE(rk817_volume_controls), + .dapm_routes = rk817_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rk817_dapm_routes), + .dapm_widgets = rk817_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk817_dapm_widgets), + .set_pll = rk817_set_component_pll, +}; + +static void rk817_codec_parse_dt_property(struct device *dev, + struct rk817_codec_priv *rk817) +{ + struct device_node *node; + + node = of_get_child_by_name(dev->parent->of_node, "codec"); + if (!node) { + dev_dbg(dev, "%s() Can not get child: codec\n", + __func__); + } + + rk817->mic_in_differential = + of_property_read_bool(node, "rockchip,mic-in-differential"); + + of_node_put(node); +} + +static int rk817_platform_probe(struct platform_device *pdev) +{ + struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); + struct rk817_codec_priv *rk817_codec_data; + int ret; + + rk817_codec_data = devm_kzalloc(&pdev->dev, + sizeof(struct rk817_codec_priv), + GFP_KERNEL); + if (!rk817_codec_data) + return -ENOMEM; + + platform_set_drvdata(pdev, rk817_codec_data); + + rk817_codec_data->rk808 = rk808; + + rk817_codec_parse_dt_property(&pdev->dev, rk817_codec_data); + + rk817_codec_data->mclk = clk_get(pdev->dev.parent, "mclk"); + if (IS_ERR(rk817_codec_data->mclk)) { + dev_dbg(&pdev->dev, "Unable to get mclk\n"); + ret = -ENXIO; + goto err_; + } + + ret = clk_prepare_enable(rk817_codec_data->mclk); + if (ret < 0) { + dev_err(&pdev->dev, "%s() clock prepare error %d\n", + __func__, ret); + goto err_; + } + + ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rk817, + rk817_dai, ARRAY_SIZE(rk817_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "%s() register codec error %d\n", + __func__, ret); + goto err_; + } + + return 0; +err_: + + return ret; +} + +static int rk817_platform_remove(struct platform_device *pdev) +{ + struct rk817_codec_priv *rk817 = platform_get_drvdata(pdev); + + clk_disable_unprepare(rk817->mclk); + + return 0; +} + +static struct platform_driver rk817_codec_driver = { + .driver = { + .name = "rk817-codec", + }, + .probe = rk817_platform_probe, + .remove = rk817_platform_remove, +}; + +module_platform_driver(rk817_codec_driver); + +MODULE_DESCRIPTION("ASoC RK817 codec driver"); +MODULE_AUTHOR("binyuan <kevan.lan@rock-chips.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index 10656a5927f1..8c0b00242bb8 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -372,8 +372,8 @@ static int rt1019_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, RT1019_AUTO_BITS_SEL_MANU | RT1019_AUTO_CLK_SEL_MANU); snd_soc_component_update_bits(component, RT1019_PLL_1, RT1019_PLL_M_MASK | RT1019_PLL_M_BP_MASK | RT1019_PLL_Q_8_8_MASK, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT1019_PLL_M_SFT | - pll_code.m_bp << RT1019_PLL_M_BP_SFT | + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1019_PLL_M_SFT) | + (pll_code.m_bp << RT1019_PLL_M_BP_SFT) | ((pll_code.n_code >> 8) & RT1019_PLL_Q_8_8_MASK)); snd_soc_component_update_bits(component, RT1019_PLL_2, RT1019_PLL_Q_7_0_MASK, pll_code.n_code & RT1019_PLL_Q_7_0_MASK); @@ -522,6 +522,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt1019 = { .num_dapm_widgets = ARRAY_SIZE(rt1019_dapm_widgets), .dapm_routes = rt1019_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt1019_dapm_routes), + .non_legacy_dai_naming = 1, }; static const struct regmap_config rt1019_regmap = { diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 1c226994aebd..f716668de640 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -709,7 +709,7 @@ static int __maybe_unused rt1308_dev_resume(struct device *dev) struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); unsigned long time; - if (!rt1308->hw_init) + if (!rt1308->first_hw_init) return 0; if (!slave->unattach_request) diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 3b029c56467d..09b4914bba1b 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -701,7 +701,7 @@ static int __maybe_unused rt1316_dev_resume(struct device *dev) struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev); unsigned long time; - if (!rt1316->hw_init) + if (!rt1316->first_hw_init) return 0; if (!slave->unattach_request) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 802f4851c3df..caa720884e3e 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -725,7 +725,6 @@ static int rt286_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - d_len_code = 0; switch (params_width(params)) { /* bit 6:4 Bits per Sample */ case 16: diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 8ea9f1d9fec0..4a56a52adab5 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -273,12 +273,23 @@ static void rt5682_i2c_shutdown(struct i2c_client *client) { struct rt5682_priv *rt5682 = i2c_get_clientdata(client); + disable_irq(client->irq); cancel_delayed_work_sync(&rt5682->jack_detect_work); cancel_delayed_work_sync(&rt5682->jd_check_work); rt5682_reset(rt5682); } +static int rt5682_i2c_remove(struct i2c_client *client) +{ + struct rt5682_priv *rt5682 = i2c_get_clientdata(client); + + rt5682_i2c_shutdown(client); + regulator_bulk_disable(ARRAY_SIZE(rt5682->supplies), rt5682->supplies); + + return 0; +} + static const struct of_device_id rt5682_of_match[] = { {.compatible = "realtek,rt5682i"}, {}, @@ -305,6 +316,7 @@ static struct i2c_driver rt5682_i2c_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = rt5682_i2c_probe, + .remove = rt5682_i2c_remove, .shutdown = rt5682_i2c_shutdown, .id_table = rt5682_i2c_id, }; diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index e78ba3b064c4..31a4f286043e 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -344,6 +344,8 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap, rt5682->sdw_regmap = regmap; rt5682->is_sdw = true; + mutex_init(&rt5682->disable_irq_lock); + rt5682->regmap = devm_regmap_init(dev, NULL, dev, &rt5682_sdw_indirect_regmap); if (IS_ERR(rt5682->regmap)) { @@ -378,6 +380,8 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) int ret = 0, loop = 10; unsigned int val; + rt5682->disable_irq = false; + if (rt5682->hw_init) return 0; @@ -400,6 +404,11 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_get_noresume(&slave->dev); + if (rt5682->first_hw_init) { + regcache_cache_only(rt5682->regmap, false); + regcache_cache_bypass(rt5682->regmap, true); + } + while (loop > 0) { regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val); if (val == DEVICE_ID) @@ -408,14 +417,11 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) usleep_range(30000, 30005); loop--; } + if (val != DEVICE_ID) { dev_err(dev, "Device with ID register %x is not rt5682\n", val); - return -ENODEV; - } - - if (rt5682->first_hw_init) { - regcache_cache_only(rt5682->regmap, false); - regcache_cache_bypass(rt5682->regmap, true); + ret = -ENODEV; + goto err_nodev; } rt5682_calibrate(rt5682); @@ -486,10 +492,11 @@ reinit: rt5682->hw_init = true; rt5682->first_hw_init = true; +err_nodev: pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); - dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret); return ret; } @@ -676,10 +683,12 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - if (status->control_port & 0x4) { + mutex_lock(&rt5682->disable_irq_lock); + if (status->control_port & 0x4 && !rt5682->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time)); } + mutex_unlock(&rt5682->disable_irq_lock); return 0; } @@ -737,13 +746,41 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev) return 0; } +static int __maybe_unused rt5682_dev_system_suspend(struct device *dev) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(dev); + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret; + + if (!rt5682->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt5682->disable_irq_lock); + rt5682->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + mutex_unlock(&rt5682->disable_irq_lock); + + if (ret < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable imp-def interrupts\n:", __func__); + } + + return rt5682_dev_suspend(dev); +} + static int __maybe_unused rt5682_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt5682_priv *rt5682 = dev_get_drvdata(dev); unsigned long time; - if (!rt5682->hw_init) + if (!rt5682->first_hw_init) return 0; if (!slave->unattach_request) @@ -765,7 +802,7 @@ regmap_sync: } static const struct dev_pm_ops rt5682_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume) + SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_system_suspend, rt5682_dev_resume) SET_RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL) }; diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 74ff66767016..b59221048ebf 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1415,6 +1415,8 @@ struct rt5682_priv { struct regulator_bulk_data supplies[RT5682_NUM_SUPPLIES]; struct delayed_work jack_detect_work; struct delayed_work jd_check_work; + struct mutex disable_irq_lock; /* imp-def irq lock protection */ + bool disable_irq; struct mutex calibrate_mutex; struct sdw_slave *slave; enum sdw_slave_status status; diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index ff9c081fd52a..bda594899664 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -418,10 +418,12 @@ static int rt700_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - if (status->control_port & 0x4) { + mutex_lock(&rt700->disable_irq_lock); + if (status->control_port & 0x4 && !rt700->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt700->jack_detect_work, msecs_to_jiffies(250)); } + mutex_unlock(&rt700->disable_irq_lock); return 0; } @@ -490,6 +492,34 @@ static int __maybe_unused rt700_dev_suspend(struct device *dev) return 0; } +static int __maybe_unused rt700_dev_system_suspend(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt700_priv *rt700 = dev_get_drvdata(dev); + int ret; + + if (!rt700->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt700->disable_irq_lock); + rt700->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + mutex_unlock(&rt700->disable_irq_lock); + + if (ret < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable imp-def interrupts\n:", __func__); + } + + return rt700_dev_suspend(dev); +} + #define RT700_PROBE_TIMEOUT 5000 static int __maybe_unused rt700_dev_resume(struct device *dev) @@ -498,7 +528,7 @@ static int __maybe_unused rt700_dev_resume(struct device *dev) struct rt700_priv *rt700 = dev_get_drvdata(dev); unsigned long time; - if (!rt700->hw_init) + if (!rt700->first_hw_init) return 0; if (!slave->unattach_request) @@ -521,7 +551,7 @@ regmap_sync: } static const struct dev_pm_ops rt700_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_suspend, rt700_dev_resume) + SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_system_suspend, rt700_dev_resume) SET_RUNTIME_PM_OPS(rt700_dev_suspend, rt700_dev_resume, NULL) }; diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 01af9d9dd3ca..921382724f9c 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -1112,6 +1112,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, rt700->sdw_regmap = sdw_regmap; rt700->regmap = regmap; + mutex_init(&rt700->disable_irq_lock); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1133,6 +1135,8 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) { struct rt700_priv *rt700 = dev_get_drvdata(dev); + rt700->disable_irq = false; + if (rt700->hw_init) return 0; diff --git a/sound/soc/codecs/rt700.h b/sound/soc/codecs/rt700.h index 794ee2e29051..bed9d1de6d5b 100644 --- a/sound/soc/codecs/rt700.h +++ b/sound/soc/codecs/rt700.h @@ -23,6 +23,8 @@ struct rt700_priv { struct delayed_work jack_detect_work; struct delayed_work jack_btn_check_work; int jack_type; + struct mutex disable_irq_lock; /* imp-def irq lock protection */ + bool disable_irq; }; struct sdw_stream_data { diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 9685c8905468..aaf5af153d3f 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -75,6 +75,16 @@ static bool rt711_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x5b00000 ... 0x5b000ff: case 0x5f00000 ... 0x5f000ff: case 0x6100000 ... 0x61000ff: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R): return true; default: return false; @@ -246,6 +256,15 @@ static int rt711_sdca_interrupt_callback(struct sdw_slave *slave, scp_sdca_stat2 = rt711->scp_sdca_stat2; } + /* + * The critical section below intentionally protects a rather large piece of code. + * We don't want to allow the system suspend to disable an interrupt while we are + * processing it, which could be problematic given the quirky SoundWire interrupt + * scheme. We do want however to prevent new workqueues from being scheduled if + * the disable_irq flag was set during system suspend. + */ + mutex_lock(&rt711->disable_irq_lock); + ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT1); if (ret < 0) goto io_error; @@ -304,13 +323,16 @@ static int rt711_sdca_interrupt_callback(struct sdw_slave *slave, "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, rt711->scp_sdca_stat1, rt711->scp_sdca_stat2); - if (status->sdca_cascade) + if (status->sdca_cascade && !rt711->disable_irq) mod_delayed_work(system_power_efficient_wq, &rt711->jack_detect_work, msecs_to_jiffies(30)); + mutex_unlock(&rt711->disable_irq_lock); + return 0; io_error: + mutex_unlock(&rt711->disable_irq_lock); pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); return ret; } @@ -372,6 +394,36 @@ static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev) return 0; } +static int __maybe_unused rt711_sdca_dev_system_suspend(struct device *dev) +{ + struct rt711_sdca_priv *rt711_sdca = dev_get_drvdata(dev); + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret1, ret2; + + if (!rt711_sdca->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt711_sdca->disable_irq_lock); + rt711_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + mutex_unlock(&rt711_sdca->disable_irq_lock); + + if (ret1 < 0 || ret2 < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__); + } + + return rt711_sdca_dev_suspend(dev); +} + #define RT711_PROBE_TIMEOUT 5000 static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) @@ -380,7 +432,7 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev); unsigned long time; - if (!rt711->hw_init) + if (!rt711->first_hw_init) return 0; if (!slave->unattach_request) @@ -403,7 +455,7 @@ regmap_sync: } static const struct dev_pm_ops rt711_sdca_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume) + SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_system_suspend, rt711_sdca_dev_resume) SET_RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL) }; diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 24a084e0b48a..2e992589f1e4 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -1411,6 +1411,8 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, rt711->regmap = regmap; rt711->mbq_regmap = mbq_regmap; + mutex_init(&rt711->disable_irq_lock); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1494,12 +1496,16 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) int ret = 0; unsigned int val; + rt711->disable_irq = false; + if (rt711->hw_init) return 0; if (rt711->first_hw_init) { regcache_cache_only(rt711->regmap, false); regcache_cache_bypass(rt711->regmap, true); + regcache_cache_only(rt711->mbq_regmap, false); + regcache_cache_bypass(rt711->mbq_regmap, true); } else { /* * PM runtime is only enabled when a Slave reports as Attached @@ -1565,6 +1571,8 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->first_hw_init) { regcache_cache_bypass(rt711->regmap, false); regcache_mark_dirty(rt711->regmap); + regcache_cache_bypass(rt711->mbq_regmap, false); + regcache_mark_dirty(rt711->mbq_regmap); } else rt711->first_hw_init = true; diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h index 43ae82b7fdb3..498ca687c47b 100644 --- a/sound/soc/codecs/rt711-sdca.h +++ b/sound/soc/codecs/rt711-sdca.h @@ -27,6 +27,8 @@ struct rt711_sdca_priv { struct delayed_work jack_detect_work; struct delayed_work jack_btn_check_work; struct mutex calibrate_mutex; /* for headset calibration */ + struct mutex disable_irq_lock; /* SDCA irq lock protection */ + bool disable_irq; int jack_type, jd_src; unsigned int scp_sdca_stat1, scp_sdca_stat2; int hw_ver; diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 8f5ebe92d407..bda2cc9439c9 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -423,10 +423,12 @@ static int rt711_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - if (status->control_port & 0x4) { + mutex_lock(&rt711->disable_irq_lock); + if (status->control_port & 0x4 && !rt711->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt711->jack_detect_work, msecs_to_jiffies(250)); } + mutex_unlock(&rt711->disable_irq_lock); return 0; } @@ -493,6 +495,34 @@ static int __maybe_unused rt711_dev_suspend(struct device *dev) return 0; } +static int __maybe_unused rt711_dev_system_suspend(struct device *dev) +{ + struct rt711_priv *rt711 = dev_get_drvdata(dev); + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret; + + if (!rt711->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt711->disable_irq_lock); + rt711->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + mutex_unlock(&rt711->disable_irq_lock); + + if (ret < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable imp-def interrupts\n:", __func__); + } + + return rt711_dev_suspend(dev); +} + #define RT711_PROBE_TIMEOUT 5000 static int __maybe_unused rt711_dev_resume(struct device *dev) @@ -501,7 +531,7 @@ static int __maybe_unused rt711_dev_resume(struct device *dev) struct rt711_priv *rt711 = dev_get_drvdata(dev); unsigned long time; - if (!rt711->hw_init) + if (!rt711->first_hw_init) return 0; if (!slave->unattach_request) @@ -524,7 +554,7 @@ regmap_sync: } static const struct dev_pm_ops rt711_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt711_dev_suspend, rt711_dev_resume) + SET_SYSTEM_SLEEP_PM_OPS(rt711_dev_system_suspend, rt711_dev_resume) SET_RUNTIME_PM_OPS(rt711_dev_suspend, rt711_dev_resume, NULL) }; diff --git a/sound/soc/codecs/rt711-sdw.h b/sound/soc/codecs/rt711-sdw.h index 43b2b984b29c..6acf9858330d 100644 --- a/sound/soc/codecs/rt711-sdw.h +++ b/sound/soc/codecs/rt711-sdw.h @@ -267,7 +267,9 @@ static const struct reg_default rt711_reg_defaults[] = { { 0x8393, 0x00 }, { 0x7319, 0x00 }, { 0x8399, 0x00 }, + { 0x752008, 0xa807 }, { 0x752009, 0x1029 }, + { 0x75200b, 0x7770 }, { 0x752011, 0x007a }, { 0x75201a, 0x8003 }, { 0x752045, 0x5289 }, diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 9f5b2dc16c54..a7c5608a0ef8 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -389,6 +389,36 @@ static void rt711_jack_init(struct rt711_priv *rt711) RT711_HP_JD_FINAL_RESULT_CTL_JD12, RT711_HP_JD_FINAL_RESULT_CTL_JD12); break; + case RT711_JD2_100K: + rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, + RT711_JD_CTL2, RT711_JD2_2PORT_100K_DECODE | RT711_JD2_1PORT_TYPE_DECODE | + RT711_HP_JD_SEL_JD2 | RT711_JD1_2PORT_TYPE_100K_DECODE, + RT711_JD2_2PORT_100K_DECODE_HP | RT711_JD2_1PORT_JD_HP | + RT711_HP_JD_SEL_JD2 | RT711_JD1_2PORT_JD_RESERVED); + rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, + RT711_CC_DET1, + RT711_HP_JD_FINAL_RESULT_CTL_JD12, + RT711_HP_JD_FINAL_RESULT_CTL_JD12); + break; + case RT711_JD2_1P8V_1PORT: + rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, + RT711_JD_CTL1, RT711_JD2_DIGITAL_JD_MODE_SEL, + RT711_JD2_1_JD_MODE); + rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, + RT711_JD_CTL2, RT711_JD2_1PORT_TYPE_DECODE | + RT711_HP_JD_SEL_JD2, + RT711_JD2_1PORT_JD_HP | + RT711_HP_JD_SEL_JD2); + rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, + RT711_JD_CTL4, RT711_JD2_PAD_PULL_UP_MASK | + RT711_JD2_MODE_SEL_MASK, + RT711_JD2_PAD_PULL_UP | + RT711_JD2_MODE2_1P8V_1PORT); + rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, + RT711_CC_DET1, + RT711_HP_JD_FINAL_RESULT_CTL_JD12, + RT711_HP_JD_FINAL_RESULT_CTL_JD12); + break; default: dev_warn(rt711->component->dev, "Wrong JD source\n"); break; @@ -1166,6 +1196,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, rt711->sdw_regmap = sdw_regmap; rt711->regmap = regmap; + mutex_init(&rt711->disable_irq_lock); + /* * Mark hw_init to false * HW init will be performed when device reports present @@ -1190,6 +1222,8 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) { struct rt711_priv *rt711 = dev_get_drvdata(dev); + rt711->disable_irq = false; + if (rt711->hw_init) return 0; diff --git a/sound/soc/codecs/rt711.h b/sound/soc/codecs/rt711.h index ca0f581feec7..f50f8c8d0934 100644 --- a/sound/soc/codecs/rt711.h +++ b/sound/soc/codecs/rt711.h @@ -25,6 +25,8 @@ struct rt711_priv { struct work_struct calibration_work; struct mutex calibrate_mutex; /* for headset calibration */ int jack_type, jd_src; + struct mutex disable_irq_lock; /* imp-def irq lock protection */ + bool disable_irq; }; struct sdw_stream_data { @@ -52,7 +54,9 @@ struct sdw_stream_data { /* Index (NID:20h) */ #define RT711_DAC_DC_CALI_CTL1 0x00 +#define RT711_JD_CTL1 0x08 #define RT711_JD_CTL2 0x09 +#define RT711_JD_CTL4 0x0b #define RT711_CC_DET1 0x11 #define RT711_PARA_VERB_CTL 0x1a #define RT711_COMBO_JACK_AUTO_CTL1 0x45 @@ -171,10 +175,33 @@ struct sdw_stream_data { /* DAC DC offset calibration control-1 (0x00)(NID:20h) */ #define RT711_DAC_DC_CALI_TRIGGER (0x1 << 15) +/* jack detect control 1 (0x08)(NID:20h) */ +#define RT711_JD2_DIGITAL_JD_MODE_SEL (0x1 << 1) +#define RT711_JD2_1_JD_MODE (0x0 << 1) +#define RT711_JD2_2_JD_MODE (0x1 << 1) + /* jack detect control 2 (0x09)(NID:20h) */ #define RT711_JD2_2PORT_200K_DECODE_HP (0x1 << 13) +#define RT711_JD2_2PORT_100K_DECODE (0x1 << 12) +#define RT711_JD2_2PORT_100K_DECODE_HP (0x0 << 12) #define RT711_HP_JD_SEL_JD1 (0x0 << 1) #define RT711_HP_JD_SEL_JD2 (0x1 << 1) +#define RT711_JD2_1PORT_TYPE_DECODE (0x3 << 10) +#define RT711_JD2_1PORT_JD_LINE2 (0x0 << 10) +#define RT711_JD2_1PORT_JD_HP (0x1 << 10) +#define RT711_JD2_1PORT_JD_LINE1 (0x2 << 10) +#define RT711_JD1_2PORT_TYPE_100K_DECODE (0x1 << 0) +#define RT711_JD1_2PORT_JD_RESERVED (0x0 << 0) +#define RT711_JD1_2PORT_JD_LINE1 (0x1 << 0) + +/* jack detect control 4 (0x0b)(NID:20h) */ +#define RT711_JD2_PAD_PULL_UP_MASK (0x1 << 3) +#define RT711_JD2_PAD_NOT_PULL_UP (0x0 << 3) +#define RT711_JD2_PAD_PULL_UP (0x1 << 3) +#define RT711_JD2_MODE_SEL_MASK (0x3 << 0) +#define RT711_JD2_MODE0_2PORT (0x0 << 0) +#define RT711_JD2_MODE1_3P3V_1PORT (0x1 << 0) +#define RT711_JD2_MODE2_1P8V_1PORT (0x2 << 0) /* CC DET1 (0x11)(NID:20h) */ #define RT711_HP_JD_FINAL_RESULT_CTL_JD12 (0x1 << 10) @@ -215,7 +242,9 @@ enum { enum rt711_jd_src { RT711_JD_NULL, RT711_JD1, - RT711_JD2 + RT711_JD2, + RT711_JD2_100K, + RT711_JD2_1P8V_1PORT }; int rt711_io_init(struct device *dev, struct sdw_slave *slave); diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index 1350798406f0..a5c673f43d82 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -70,6 +70,7 @@ static bool rt715_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x2000036: case 0x2000037: case 0x2000039: + case 0x2000044: case 0x6100000: return true; default: @@ -224,7 +225,7 @@ static int __maybe_unused rt715_dev_resume(struct device *dev) struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); unsigned long time; - if (!rt715->hw_init) + if (!rt715->first_hw_init) return 0; if (!slave->unattach_request) diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h index cd365bb60747..0cbc14844f8c 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.h +++ b/sound/soc/codecs/rt715-sdca-sdw.h @@ -113,6 +113,7 @@ static const struct reg_default rt715_mbq_reg_defaults_sdca[] = { { 0x2000036, 0x0000 }, { 0x2000037, 0x0000 }, { 0x2000039, 0xaa81 }, + { 0x2000044, 0x0202 }, { 0x6100000, 0x0100 }, { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 }, diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 7db76c19e048..66e166568c50 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -997,7 +997,7 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, * HW init will be performed when device reports present */ rt715->hw_init = false; - rt715->first_init = false; + rt715->first_hw_init = false; ret = devm_snd_soc_register_component(dev, &soc_codec_dev_rt715_sdca, @@ -1018,7 +1018,7 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!rt715->first_init) { + if (!rt715->first_hw_init) { /* set autosuspend parameters */ pm_runtime_set_autosuspend_delay(&slave->dev, 3000); pm_runtime_use_autosuspend(&slave->dev); @@ -1031,7 +1031,7 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_enable(&slave->dev); - rt715->first_init = true; + rt715->first_hw_init = true; } pm_runtime_get_noresume(&slave->dev); @@ -1054,6 +1054,9 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, RT715_REV_1, 0x40, 0x40); } + /* DFLL Calibration trigger */ + rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, + RT715_DFLL_VAD, 0x1, 0x1); /* trigger mode = VAD enable */ regmap_write(rt715->regmap, SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, diff --git a/sound/soc/codecs/rt715-sdca.h b/sound/soc/codecs/rt715-sdca.h index 85ce4d95e5eb..90881b455ece 100644 --- a/sound/soc/codecs/rt715-sdca.h +++ b/sound/soc/codecs/rt715-sdca.h @@ -27,7 +27,7 @@ struct rt715_sdca_priv { enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; - bool first_init; + bool first_hw_init; int l_is_unmute; int r_is_unmute; int hw_sdw_ver; @@ -81,6 +81,7 @@ struct rt715_sdca_kcontrol_private { #define RT715_AD_FUNC_EN 0x36 #define RT715_REV_1 0x37 #define RT715_SDW_INPUT_SEL 0x39 +#define RT715_DFLL_VAD 0x44 #define RT715_EXT_DMIC_CLK_CTRL2 0x54 /* Index (NID:61h) */ diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 81a1dd77b6f6..a7b21b03c08b 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -541,7 +541,7 @@ static int __maybe_unused rt715_dev_resume(struct device *dev) struct rt715_priv *rt715 = dev_get_drvdata(dev); unsigned long time; - if (!rt715->hw_init) + if (!rt715->first_hw_init) return 0; if (!slave->unattach_request) diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index d63b8c366efb..2783eff633a1 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h @@ -44,7 +44,6 @@ struct sigmadsp { struct sigmadsp *devm_sigmadsp_init(struct device *dev, const struct sigmadsp_ops *ops, const char *firmware_name); -void sigmadsp_reset(struct sigmadsp *sigmadsp); int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, struct snd_pcm_substream *substream); diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c new file mode 100644 index 000000000000..643b45188b6f --- /dev/null +++ b/sound/soc/codecs/tfa989x.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Stephan Gerhold + * + * Register definitions/sequences taken from various tfa98xx kernel drivers: + * Copyright (C) 2014-2020 NXP Semiconductors, All Rights Reserved. + * Copyright (C) 2013 Sony Mobile Communications Inc. + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <sound/soc.h> + +#define TFA989X_STATUSREG 0x00 +#define TFA989X_BATTERYVOLTAGE 0x01 +#define TFA989X_TEMPERATURE 0x02 +#define TFA989X_REVISIONNUMBER 0x03 +#define TFA989X_REVISIONNUMBER_REV_MSK GENMASK(7, 0) /* device revision */ +#define TFA989X_I2SREG 0x04 +#define TFA989X_I2SREG_CHSA 6 /* amplifier input select */ +#define TFA989X_I2SREG_CHSA_MSK GENMASK(7, 6) +#define TFA989X_I2SREG_I2SSR 12 /* sample rate */ +#define TFA989X_I2SREG_I2SSR_MSK GENMASK(15, 12) +#define TFA989X_BAT_PROT 0x05 +#define TFA989X_AUDIO_CTR 0x06 +#define TFA989X_DCDCBOOST 0x07 +#define TFA989X_SPKR_CALIBRATION 0x08 +#define TFA989X_SYS_CTRL 0x09 +#define TFA989X_SYS_CTRL_PWDN 0 /* power down */ +#define TFA989X_SYS_CTRL_I2CR 1 /* I2C reset */ +#define TFA989X_SYS_CTRL_CFE 2 /* enable CoolFlux DSP */ +#define TFA989X_SYS_CTRL_AMPE 3 /* enable amplifier */ +#define TFA989X_SYS_CTRL_DCA 4 /* enable boost */ +#define TFA989X_SYS_CTRL_SBSL 5 /* DSP configured */ +#define TFA989X_SYS_CTRL_AMPC 6 /* amplifier enabled by DSP */ +#define TFA989X_I2S_SEL_REG 0x0a +#define TFA989X_I2S_SEL_REG_SPKR_MSK GENMASK(10, 9) /* speaker impedance */ +#define TFA989X_I2S_SEL_REG_DCFG_MSK GENMASK(14, 11) /* DCDC compensation */ +#define TFA989X_PWM_CONTROL 0x41 +#define TFA989X_CURRENTSENSE1 0x46 +#define TFA989X_CURRENTSENSE2 0x47 +#define TFA989X_CURRENTSENSE3 0x48 +#define TFA989X_CURRENTSENSE4 0x49 + +#define TFA9895_REVISION 0x12 +#define TFA9897_REVISION 0x97 + +struct tfa989x_rev { + unsigned int rev; + int (*init)(struct regmap *regmap); +}; + +struct tfa989x { + struct regulator *vddd_supply; +}; + +static bool tfa989x_writeable_reg(struct device *dev, unsigned int reg) +{ + return reg > TFA989X_REVISIONNUMBER; +} + +static bool tfa989x_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg < TFA989X_REVISIONNUMBER; +} + +static const struct regmap_config tfa989x_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .writeable_reg = tfa989x_writeable_reg, + .volatile_reg = tfa989x_volatile_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const char * const chsa_text[] = { "Left", "Right", /* "DSP" */ }; +static SOC_ENUM_SINGLE_DECL(chsa_enum, TFA989X_I2SREG, TFA989X_I2SREG_CHSA, chsa_text); +static const struct snd_kcontrol_new chsa_mux = SOC_DAPM_ENUM("Amp Input", chsa_enum); + +static const struct snd_soc_dapm_widget tfa989x_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("OUT"), + SND_SOC_DAPM_SUPPLY("POWER", TFA989X_SYS_CTRL, TFA989X_SYS_CTRL_PWDN, 1, NULL, 0), + SND_SOC_DAPM_OUT_DRV("AMPE", TFA989X_SYS_CTRL, TFA989X_SYS_CTRL_AMPE, 0, NULL, 0), + + SND_SOC_DAPM_MUX("Amp Input", SND_SOC_NOPM, 0, 0, &chsa_mux), + SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Playback", 1, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route tfa989x_dapm_routes[] = { + {"OUT", NULL, "AMPE"}, + {"AMPE", NULL, "POWER"}, + {"AMPE", NULL, "Amp Input"}, + {"Amp Input", "Left", "AIFINL"}, + {"Amp Input", "Right", "AIFINR"}, +}; + +static const struct snd_soc_component_driver tfa989x_component = { + .dapm_widgets = tfa989x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tfa989x_dapm_widgets), + .dapm_routes = tfa989x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(tfa989x_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const unsigned int tfa989x_rates[] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +}; + +static int tfa989x_find_sample_rate(unsigned int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tfa989x_rates); ++i) + if (tfa989x_rates[i] == rate) + return i; + + return -EINVAL; +} + +static int tfa989x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int sr; + + sr = tfa989x_find_sample_rate(params_rate(params)); + if (sr < 0) + return sr; + + return snd_soc_component_update_bits(component, TFA989X_I2SREG, + TFA989X_I2SREG_I2SSR_MSK, + sr << TFA989X_I2SREG_I2SSR); +} + +static const struct snd_soc_dai_ops tfa989x_dai_ops = { + .hw_params = tfa989x_hw_params, +}; + +static struct snd_soc_dai_driver tfa989x_dai = { + .name = "tfa989x-hifi", + .playback = { + .stream_name = "HiFi Playback", + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tfa989x_dai_ops, +}; + +static const struct reg_sequence tfa9895_reg_init[] = { + /* some other registers must be set for optimal amplifier behaviour */ + { TFA989X_BAT_PROT, 0x13ab }, + { TFA989X_AUDIO_CTR, 0x001f }, + + /* peak voltage protection is always on, but may be written */ + { TFA989X_SPKR_CALIBRATION, 0x3c4e }, + + /* TFA989X_SYSCTRL_DCA = 0 */ + { TFA989X_SYS_CTRL, 0x024d }, + { TFA989X_PWM_CONTROL, 0x0308 }, + { TFA989X_CURRENTSENSE4, 0x0e82 }, +}; + +static int tfa9895_init(struct regmap *regmap) +{ + return regmap_multi_reg_write(regmap, tfa9895_reg_init, + ARRAY_SIZE(tfa9895_reg_init)); +} + +static const struct tfa989x_rev tfa9895_rev = { + .rev = TFA9895_REVISION, + .init = tfa9895_init, +}; + +static int tfa9897_init(struct regmap *regmap) +{ + int ret; + + /* Reduce slewrate by clearing iddqtestbst to avoid booster damage */ + ret = regmap_write(regmap, TFA989X_CURRENTSENSE3, 0x0300); + if (ret) + return ret; + + /* Enable clipping */ + ret = regmap_clear_bits(regmap, TFA989X_CURRENTSENSE4, 0x1); + if (ret) + return ret; + + /* Set required TDM configuration */ + return regmap_write(regmap, 0x14, 0x0); +} + +static const struct tfa989x_rev tfa9897_rev = { + .rev = TFA9897_REVISION, + .init = tfa9897_init, +}; + +/* + * Note: At the moment this driver bypasses the "CoolFlux DSP" built into the + * TFA989X amplifiers. Unfortunately, there seems to be absolutely + * no documentation for it - the public "short datasheets" do not provide + * any information about the DSP or available registers. + * + * Usually the TFA989X amplifiers are configured through proprietary userspace + * libraries. There are also some (rather complex) kernel drivers but even those + * rely on obscure firmware blobs for configuration (so-called "containers"). + * They seem to contain different "profiles" with tuned speaker settings, sample + * rates and volume steps (which would be better exposed as separate ALSA mixers). + * + * Bypassing the DSP disables volume control (and perhaps some speaker + * optimization?), but at least allows using the speaker without obscure + * kernel drivers and firmware. + * + * Ideally NXP (or now Goodix) should release proper documentation for these + * amplifiers so that support for the "CoolFlux DSP" can be implemented properly. + */ +static int tfa989x_dsp_bypass(struct regmap *regmap) +{ + int ret; + + /* Clear CHSA to bypass DSP and take input from I2S 1 left channel */ + ret = regmap_clear_bits(regmap, TFA989X_I2SREG, TFA989X_I2SREG_CHSA_MSK); + if (ret) + return ret; + + /* Set DCDC compensation to off and speaker impedance to 8 ohm */ + ret = regmap_update_bits(regmap, TFA989X_I2S_SEL_REG, + TFA989X_I2S_SEL_REG_DCFG_MSK | + TFA989X_I2S_SEL_REG_SPKR_MSK, + TFA989X_I2S_SEL_REG_SPKR_MSK); + if (ret) + return ret; + + /* Set DCDC to follower mode and disable CoolFlux DSP */ + return regmap_clear_bits(regmap, TFA989X_SYS_CTRL, + BIT(TFA989X_SYS_CTRL_DCA) | + BIT(TFA989X_SYS_CTRL_CFE) | + BIT(TFA989X_SYS_CTRL_AMPC)); +} + +static void tfa989x_regulator_disable(void *data) +{ + struct tfa989x *tfa989x = data; + + regulator_disable(tfa989x->vddd_supply); +} + +static int tfa989x_i2c_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + const struct tfa989x_rev *rev; + struct tfa989x *tfa989x; + struct regmap *regmap; + unsigned int val; + int ret; + + rev = device_get_match_data(dev); + if (!rev) { + dev_err(dev, "unknown device revision\n"); + return -ENODEV; + } + + tfa989x = devm_kzalloc(dev, sizeof(*tfa989x), GFP_KERNEL); + if (!tfa989x) + return -ENOMEM; + + i2c_set_clientdata(i2c, tfa989x); + + tfa989x->vddd_supply = devm_regulator_get(dev, "vddd"); + if (IS_ERR(tfa989x->vddd_supply)) + return dev_err_probe(dev, PTR_ERR(tfa989x->vddd_supply), + "Failed to get vddd regulator\n"); + + regmap = devm_regmap_init_i2c(i2c, &tfa989x_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = regulator_enable(tfa989x->vddd_supply); + if (ret) { + dev_err(dev, "Failed to enable vddd regulator: %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(dev, tfa989x_regulator_disable, tfa989x); + if (ret) + return ret; + + /* Bypass regcache for reset and init sequence */ + regcache_cache_bypass(regmap, true); + + /* Dummy read to generate i2c clocks, required on some devices */ + regmap_read(regmap, TFA989X_REVISIONNUMBER, &val); + + ret = regmap_read(regmap, TFA989X_REVISIONNUMBER, &val); + if (ret) { + dev_err(dev, "failed to read revision number: %d\n", ret); + return ret; + } + + val &= TFA989X_REVISIONNUMBER_REV_MSK; + if (val != rev->rev) { + dev_err(dev, "invalid revision number, expected %#x, got %#x\n", + rev->rev, val); + return -ENODEV; + } + + ret = regmap_write(regmap, TFA989X_SYS_CTRL, BIT(TFA989X_SYS_CTRL_I2CR)); + if (ret) { + dev_err(dev, "failed to reset I2C registers: %d\n", ret); + return ret; + } + + ret = rev->init(regmap); + if (ret) { + dev_err(dev, "failed to initialize registers: %d\n", ret); + return ret; + } + + ret = tfa989x_dsp_bypass(regmap); + if (ret) { + dev_err(dev, "failed to enable DSP bypass: %d\n", ret); + return ret; + } + regcache_cache_bypass(regmap, false); + + return devm_snd_soc_register_component(dev, &tfa989x_component, + &tfa989x_dai, 1); +} + +static const struct of_device_id tfa989x_of_match[] = { + { .compatible = "nxp,tfa9895", .data = &tfa9895_rev }, + { .compatible = "nxp,tfa9897", .data = &tfa9897_rev }, + { } +}; +MODULE_DEVICE_TABLE(of, tfa989x_of_match); + +static struct i2c_driver tfa989x_i2c_driver = { + .driver = { + .name = "tfa989x", + .of_match_table = tfa989x_of_match, + }, + .probe_new = tfa989x_i2c_probe, +}; +module_i2c_driver(tfa989x_i2c_driver); + +MODULE_DESCRIPTION("ASoC NXP/Goodix TFA989X (TFA1) driver"); +MODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index c7baef8948d4..077415a57225 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -261,8 +261,8 @@ static const struct snd_kcontrol_new aic26_snd_controls[] = { * SPI device portion of driver: sysfs files for debugging */ -static ssize_t aic26_keyclick_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t keyclick_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct aic26 *aic26 = dev_get_drvdata(dev); int val, amp, freq, len; @@ -276,9 +276,9 @@ static ssize_t aic26_keyclick_show(struct device *dev, } /* Any write to the keyclick attribute will trigger the keyclick event */ -static ssize_t aic26_keyclick_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t keyclick_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct aic26 *aic26 = dev_get_drvdata(dev); @@ -288,7 +288,7 @@ static ssize_t aic26_keyclick_set(struct device *dev, return count; } -static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); +static DEVICE_ATTR_RW(keyclick); /* --------------------------------------------------------------------- * SoC CODEC portion of driver: probe and release routines diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index 6d54cbf70a0b..04ad38311360 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -16,6 +16,8 @@ #include "tlv320aic32x4.h" +static const struct of_device_id aic32x4_of_id[]; + static int aic32x4_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -27,6 +29,16 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, config.val_bits = 8; regmap = devm_regmap_init_i2c(i2c, &config); + + if (i2c->dev.of_node) { + const struct of_device_id *oid; + + oid = of_match_node(aic32x4_of_id, i2c->dev.of_node); + dev_set_drvdata(&i2c->dev, (void *)oid->data); + } else if (id) { + dev_set_drvdata(&i2c->dev, (void *)id->driver_data); + } + return aic32x4_probe(&i2c->dev, regmap); } @@ -36,15 +48,17 @@ static int aic32x4_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id aic32x4_i2c_id[] = { - { "tlv320aic32x4", 0 }, - { "tlv320aic32x6", 1 }, + { "tlv320aic32x4", (kernel_ulong_t)AIC32X4_TYPE_AIC32X4 }, + { "tlv320aic32x6", (kernel_ulong_t)AIC32X4_TYPE_AIC32X6 }, + { "tas2505", (kernel_ulong_t)AIC32X4_TYPE_TAS2505 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); static const struct of_device_id aic32x4_of_id[] = { - { .compatible = "ti,tlv320aic32x4", }, - { .compatible = "ti,tlv320aic32x6", }, + { .compatible = "ti,tlv320aic32x4", .data = (void *)AIC32X4_TYPE_AIC32X4 }, + { .compatible = "ti,tlv320aic32x6", .data = (void *)AIC32X4_TYPE_AIC32X6 }, + { .compatible = "ti,tas2505", .data = (void *)AIC32X4_TYPE_TAS2505 }, { /* senitel */ } }; MODULE_DEVICE_TABLE(of, aic32x4_of_id); diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index a22e7700bfc8..e81c72958a82 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -16,6 +16,8 @@ #include "tlv320aic32x4.h" +static const struct of_device_id aic32x4_of_id[]; + static int aic32x4_spi_probe(struct spi_device *spi) { struct regmap *regmap; @@ -28,6 +30,19 @@ static int aic32x4_spi_probe(struct spi_device *spi) config.read_flag_mask = 0x01; regmap = devm_regmap_init_spi(spi, &config); + + if (spi->dev.of_node) { + const struct of_device_id *oid; + + oid = of_match_node(aic32x4_of_id, spi->dev.of_node); + dev_set_drvdata(&spi->dev, (void *)oid->data); + } else { + const struct spi_device_id *id_entry; + + id_entry = spi_get_device_id(spi); + dev_set_drvdata(&spi->dev, (void *)id_entry->driver_data); + } + return aic32x4_probe(&spi->dev, regmap); } @@ -37,15 +52,15 @@ static int aic32x4_spi_remove(struct spi_device *spi) } static const struct spi_device_id aic32x4_spi_id[] = { - { "tlv320aic32x4", 0 }, - { "tlv320aic32x6", 1 }, + { "tlv320aic32x4", (kernel_ulong_t)AIC32X4_TYPE_AIC32X4 }, + { "tlv320aic32x6", (kernel_ulong_t)AIC32X4_TYPE_AIC32X6 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(spi, aic32x4_spi_id); static const struct of_device_id aic32x4_of_id[] = { - { .compatible = "ti,tlv320aic32x4", }, - { .compatible = "ti,tlv320aic32x6", }, + { .compatible = "ti,tlv320aic32x4", .data = (void *)AIC32X4_TYPE_AIC32X4 }, + { .compatible = "ti,tlv320aic32x6", .data = (void *)AIC32X4_TYPE_AIC32X6 }, { /* senitel */ } }; MODULE_DEVICE_TABLE(of, aic32x4_of_id); diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index b689f26fc4be..c63b717040ed 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -48,6 +48,7 @@ struct aic32x4_priv { struct aic32x4_setup_data *setup; struct device *dev; + enum aic32x4_type type; }; static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w, @@ -250,6 +251,9 @@ static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0); /* -12dB min, 0.5dB steps */ static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0); +static DECLARE_TLV_DB_LINEAR(tlv_spk_vol, TLV_DB_GAIN_MUTE, 0); +static DECLARE_TLV_DB_SCALE(tlv_amp_vol, 0, 600, 1); + static const char * const lo_cm_text[] = { "Full Chip", "1.65V", }; @@ -1058,6 +1062,129 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4 = { .non_legacy_dai_naming = 1, }; +static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = { + SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL, + AIC32X4_LDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), + SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum), + SOC_DOUBLE_R_S_TLV("HP Driver Playback Volume", AIC32X4_HPLGAIN, + AIC32X4_HPLGAIN, 0, -0x6, 0x1d, 5, 0, + tlv_driver_gain), + SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN, + AIC32X4_HPLGAIN, 6, 0x01, 1), + + SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0), + + SOC_SINGLE_RANGE_TLV("Speaker Driver Playback Volume", TAS2505_SPKVOL1, + 0, 0, 117, 1, tlv_spk_vol), + SOC_SINGLE_TLV("Speaker Amplifier Playback Volume", TAS2505_SPKVOL2, + 4, 5, 0, tlv_amp_vol), +}; + +static const struct snd_kcontrol_new hp_output_mixer_controls[] = { + SOC_DAPM_SINGLE("DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0), +}; + +static const struct snd_soc_dapm_widget aic32x4_tas2505_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC", "Playback", AIC32X4_DACSETUP, 7, 0), + SND_SOC_DAPM_MIXER("HP Output Mixer", SND_SOC_NOPM, 0, 0, + &hp_output_mixer_controls[0], + ARRAY_SIZE(hp_output_mixer_controls)), + SND_SOC_DAPM_PGA("HP Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Speaker Driver", TAS2505_SPK, 1, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_OUTPUT("Speaker"), +}; + +static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = { + /* Left Output */ + {"HP Output Mixer", "DAC Switch", "DAC"}, + + {"HP Power", NULL, "HP Output Mixer"}, + {"HP", NULL, "HP Power"}, + + {"Speaker Driver", NULL, "DAC"}, + {"Speaker", NULL, "Speaker Driver"}, +}; + +static struct snd_soc_dai_driver aic32x4_tas2505_dai = { + .name = "tas2505-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = AIC32X4_FORMATS,}, + .ops = &aic32x4_ops, + .symmetric_rate = 1, +}; + +static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) +{ + struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); + u32 tmp_reg; + int ret; + + struct clk_bulk_data clocks[] = { + { .id = "codec_clkin" }, + { .id = "pll" }, + { .id = "bdiv" }, + { .id = "mdac" }, + }; + + ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks); + if (ret) + return ret; + + if (aic32x4->setup) + aic32x4_setup_gpios(component); + + clk_set_parent(clocks[0].clk, clocks[1].clk); + clk_set_parent(clocks[2].clk, clocks[3].clk); + + /* Power platform configuration */ + if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE) + snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE); + + tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ? + AIC32X4_LDOCTLEN : 0; + snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg); + + tmp_reg = snd_soc_component_read(component, AIC32X4_CMMODE); + if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36) + tmp_reg |= AIC32X4_LDOIN_18_36; + if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED) + tmp_reg |= AIC32X4_LDOIN2HP; + snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg); + + /* + * Enable the fast charging feature and ensure the needed 40ms ellapsed + * before using the analog circuits. + */ + snd_soc_component_write(component, TAS2505_REFPOWERUP, + AIC32X4_REFPOWERUP_40MS); + msleep(40); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = { + .probe = aic32x4_tas2505_component_probe, + .set_bias_level = aic32x4_set_bias_level, + .controls = aic32x4_tas2505_snd_controls, + .num_controls = ARRAY_SIZE(aic32x4_tas2505_snd_controls), + .dapm_widgets = aic32x4_tas2505_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aic32x4_tas2505_dapm_widgets), + .dapm_routes = aic32x4_tas2505_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(aic32x4_tas2505_dapm_routes), + .suspend_bias_off = 1, + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, struct device_node *np) { @@ -1198,6 +1325,8 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) return -ENOMEM; aic32x4->dev = dev; + aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev); + dev_set_drvdata(dev, aic32x4); if (pdata) { @@ -1247,8 +1376,16 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) if (ret) goto err_disable_regulators; - ret = devm_snd_soc_register_component(dev, + switch (aic32x4->type) { + case AIC32X4_TYPE_TAS2505: + ret = devm_snd_soc_register_component(dev, + &soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1); + break; + default: + ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic32x4, &aic32x4_dai, 1); + } + if (ret) { dev_err(dev, "Failed to register component\n"); goto err_disable_regulators; diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 7550122e9f8a..e9fd2e55d6c3 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -10,6 +10,12 @@ struct device; struct regmap_config; +enum aic32x4_type { + AIC32X4_TYPE_AIC32X4 = 0, + AIC32X4_TYPE_AIC32X6, + AIC32X4_TYPE_TAS2505, +}; + extern const struct regmap_config aic32x4_regmap_config; int aic32x4_probe(struct device *dev, struct regmap *regmap); int aic32x4_remove(struct device *dev); @@ -88,6 +94,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); #define AIC32X4_LOLGAIN AIC32X4_REG(1, 18) #define AIC32X4_LORGAIN AIC32X4_REG(1, 19) #define AIC32X4_HEADSTART AIC32X4_REG(1, 20) +#define TAS2505_SPK AIC32X4_REG(1, 45) +#define TAS2505_SPKVOL1 AIC32X4_REG(1, 46) +#define TAS2505_SPKVOL2 AIC32X4_REG(1, 48) #define AIC32X4_MICBIAS AIC32X4_REG(1, 51) #define AIC32X4_LMICPGAPIN AIC32X4_REG(1, 52) #define AIC32X4_LMICPGANIN AIC32X4_REG(1, 54) @@ -96,6 +105,7 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); #define AIC32X4_FLOATINGINPUT AIC32X4_REG(1, 58) #define AIC32X4_LMICPGAVOL AIC32X4_REG(1, 59) #define AIC32X4_RMICPGAVOL AIC32X4_REG(1, 60) +#define TAS2505_REFPOWERUP AIC32X4_REG(1, 122) #define AIC32X4_REFPOWERUP AIC32X4_REG(1, 123) /* Bits, masks, and shifts */ diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index 817d8259758c..4c7ebc7fb400 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -88,6 +88,19 @@ struct wcd_clsh_ctrl { #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30 +#define WCD9XXX_BASE_ADDRESS 0x3000 +#define WCD9XXX_ANA_RX_SUPPLIES (WCD9XXX_BASE_ADDRESS+0x008) +#define WCD9XXX_ANA_HPH (WCD9XXX_BASE_ADDRESS+0x009) +#define WCD9XXX_CLASSH_MODE_2 (WCD9XXX_BASE_ADDRESS+0x098) +#define WCD9XXX_CLASSH_MODE_3 (WCD9XXX_BASE_ADDRESS+0x099) +#define WCD9XXX_FLYBACK_VNEG_CTRL_1 (WCD9XXX_BASE_ADDRESS+0x0A5) +#define WCD9XXX_FLYBACK_VNEG_CTRL_4 (WCD9XXX_BASE_ADDRESS+0x0A8) +#define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 (WCD9XXX_BASE_ADDRESS+0x0AF) +#define WCD9XXX_RX_BIAS_HPH_LOWPOWER (WCD9XXX_BASE_ADDRESS+0x0BF) +#define WCD9XXX_V3_RX_BIAS_FLYB_BUFF (WCD9XXX_BASE_ADDRESS+0x0C7) +#define WCD9XXX_HPH_PA_CTL1 (WCD9XXX_BASE_ADDRESS+0x0D1) +#define WCD9XXX_HPH_NEW_INT_PA_MISC2 (WCD9XXX_BASE_ADDRESS+0x138) + #define CLSH_REQ_ENABLE true #define CLSH_REQ_DISABLE false #define WCD_USLEEP_RANGE 50 @@ -137,6 +150,20 @@ static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT); } +static void wcd_clsh_v3_set_buck_mode(struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x08, 0x08); /* set to HIFI */ + else + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x08, 0x00); /* set to default */ +} + static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp, int mode) { @@ -170,6 +197,36 @@ static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl, usleep_range(500, 500 + WCD_USLEEP_RANGE); } +static void wcd_clsh_v3_buck_ctrl(struct snd_soc_component *component, + struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + /* enable/disable buck */ + if ((enable && (++ctrl->buck_users == 1)) || + (!enable && (--ctrl->buck_users == 0))) { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + (1 << 7), (enable << 7)); + /* + * 500us sleep is required after buck enable/disable + * as per HW requirement + */ + usleep_range(500, 510); + if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP || + mode == CLS_H_HIFI || mode == CLS_H_LP) + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_3, + 0x02, 0x00); + + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_2, + 0xFF, 0x3A); + /* 500usec delay is needed as per HW requirement */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); + } +} + static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl, int mode, bool enable) @@ -219,8 +276,7 @@ static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) val); } -static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, - int mode) +static void wcd_clsh_v2_set_hph_mode(struct snd_soc_component *comp, int mode) { int val = 0, gain = 0, res_val; int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; @@ -264,6 +320,48 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, ipeak); } +static void wcd_clsh_v3_set_hph_mode(struct snd_soc_component *component, + int mode) +{ + u8 val; + + switch (mode) { + case CLS_H_NORMAL: + val = 0x00; + break; + case CLS_AB: + case CLS_H_ULP: + val = 0x0C; + break; + case CLS_AB_HIFI: + case CLS_H_HIFI: + val = 0x08; + break; + case CLS_H_LP: + case CLS_H_LOHIFI: + case CLS_AB_LP: + case CLS_AB_LOHIFI: + val = 0x04; + break; + default: + dev_err(component->dev, "%s:Invalid mode %d\n", __func__, mode); + return; + } + + snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, val); +} + +void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_set_hph_mode(comp, mode); + else + wcd_clsh_v2_set_hph_mode(comp, mode); + +} + static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, int mode) { @@ -289,6 +387,130 @@ static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); } +static void wcd_clsh_v3_set_buck_regulator_mode(struct snd_soc_component *component, + int mode) +{ + snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES, + 0x02, 0x00); +} + +static void wcd_clsh_v3_set_flyback_mode(struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x80); + } else { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x04, 0x00); /* set to Default */ + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x70); + } +} + +static void wcd_clsh_v3_force_iq_ctl(struct snd_soc_component *component, + int mode, bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, 0xA0); + /* 100usec delay is needed as per HW requirement */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_3, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_2, + 0xFF, 0x1C); + if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) { + snd_soc_component_update_bits(component, + WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0xC0); + snd_soc_component_update_bits(component, + WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x02); + } + } else { + snd_soc_component_update_bits(component, + WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x00); + snd_soc_component_update_bits(component, + WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0x80); + snd_soc_component_update_bits(component, + WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x06); + } +} + +static void wcd_clsh_v3_flyback_ctrl(struct snd_soc_component *component, + struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + /* enable/disable flyback */ + if ((enable && (++ctrl->flyback_users == 1)) || + (!enable && (--ctrl->flyback_users == 0))) { + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_1, + 0xE0, 0xE0); + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + (1 << 6), (enable << 6)); + /* + * 100us sleep is required after flyback enable/disable + * as per HW requirement + */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, 0xE0); + /* 500usec delay is needed as per HW requirement */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); + } +} + +static void wcd_clsh_v3_set_flyback_current(struct snd_soc_component *component, + int mode) +{ + snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, + 0x0F, 0x0A); + snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, + 0xF0, 0xA0); + /* Sleep needed to avoid click and pop as per HW requirement */ + usleep_range(100, 110); +} + +static void wcd_clsh_v3_state_aux(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *component = ctrl->comp; + + if (is_enable) { + wcd_clsh_v3_set_buck_mode(component, mode); + wcd_clsh_v3_set_flyback_mode(component, mode); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_flyback_current(component, mode); + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); + } else { + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, false); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, false); + wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); + } +} + static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, bool is_enable, int mode) { @@ -316,6 +538,38 @@ static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, } } +static void wcd_clsh_v3_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *component = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n", + __func__); + return; + } + + if (is_enable) { + wcd_clsh_v3_set_buck_regulator_mode(component, mode); + wcd_clsh_v3_set_flyback_mode(component, mode); + wcd_clsh_v3_force_iq_ctl(component, mode, true); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_flyback_current(component, mode); + wcd_clsh_v3_set_buck_mode(component, mode); + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_hph_mode(component, mode); + } else { + wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); + + /* buck and flyback set to default mode and disable */ + wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); + } +} + static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, bool is_enable, int mode) { @@ -353,10 +607,10 @@ static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, wcd_clsh_set_flyback_current(comp, mode); wcd_clsh_set_buck_mode(comp, mode); wcd_clsh_buck_ctrl(ctrl, mode, true); - wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_v2_set_hph_mode(comp, mode); wcd_clsh_set_gain_path(ctrl, mode); } else { - wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL); if (mode != CLS_AB) { snd_soc_component_update_bits(comp, @@ -374,6 +628,38 @@ static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, } } +static void wcd_clsh_v3_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *component = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n", + __func__); + return; + } + + if (is_enable) { + wcd_clsh_v3_set_buck_regulator_mode(component, mode); + wcd_clsh_v3_set_flyback_mode(component, mode); + wcd_clsh_v3_force_iq_ctl(component, mode, true); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_flyback_current(component, mode); + wcd_clsh_v3_set_buck_mode(component, mode); + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_hph_mode(component, mode); + } else { + wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); + + /* set buck and flyback to Default Mode */ + wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); + } +} + static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, bool is_enable, int mode) { @@ -411,10 +697,10 @@ static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, wcd_clsh_set_flyback_current(comp, mode); wcd_clsh_set_buck_mode(comp, mode); wcd_clsh_buck_ctrl(ctrl, mode, true); - wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_v2_set_hph_mode(comp, mode); wcd_clsh_set_gain_path(ctrl, mode); } else { - wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL); if (mode != CLS_AB) { snd_soc_component_update_bits(comp, @@ -432,6 +718,32 @@ static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, } } +static void wcd_clsh_v3_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *component = ctrl->comp; + + if (is_enable) { + wcd_clsh_v3_set_buck_regulator_mode(component, mode); + wcd_clsh_v3_set_flyback_mode(component, mode); + wcd_clsh_v3_force_iq_ctl(component, mode, true); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_flyback_current(component, mode); + wcd_clsh_v3_set_buck_mode(component, mode); + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_hph_mode(component, mode); + } else { + wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); + + /* set buck and flyback to Default Mode */ + wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); + } +} + static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, bool is_enable, int mode) { @@ -472,16 +784,30 @@ static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, { switch (req_state) { case WCD_CLSH_STATE_EAR: - wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_state_ear(ctrl, req_state, is_enable, mode); + else + wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); break; case WCD_CLSH_STATE_HPHL: - wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_state_hph_l(ctrl, req_state, is_enable, mode); + else + wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); break; case WCD_CLSH_STATE_HPHR: - wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_state_hph_r(ctrl, req_state, is_enable, mode); + else + wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); break; case WCD_CLSH_STATE_LO: - wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); + if (ctrl->codec_version < WCD937X) + wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_AUX: + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_state_aux(ctrl, req_state, is_enable, mode); break; default: break; @@ -504,6 +830,7 @@ static bool wcd_clsh_is_state_valid(int state) case WCD_CLSH_STATE_HPHL: case WCD_CLSH_STATE_HPHR: case WCD_CLSH_STATE_LO: + case WCD_CLSH_STATE_AUX: return true; default: return false; @@ -565,6 +892,7 @@ struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, ctrl->state = WCD_CLSH_STATE_IDLE; ctrl->comp = comp; + ctrl->codec_version = version; return ctrl; } diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h index a6d0f2d0e9e3..4e3653058275 100644 --- a/sound/soc/codecs/wcd-clsh-v2.h +++ b/sound/soc/codecs/wcd-clsh-v2.h @@ -22,8 +22,11 @@ enum wcd_clsh_event { #define WCD_CLSH_STATE_HPHL BIT(1) #define WCD_CLSH_STATE_HPHR BIT(2) #define WCD_CLSH_STATE_LO BIT(3) +#define WCD_CLSH_STATE_AUX BIT(4) #define WCD_CLSH_STATE_MAX 4 +#define WCD_CLSH_V3_STATE_MAX 5 #define NUM_CLSH_STATES_V2 BIT(WCD_CLSH_STATE_MAX) +#define NUM_CLSH_STATES_V3 BIT(WCD_CLSH_V3_STATE_MAX) enum wcd_clsh_mode { CLS_H_NORMAL = 0, /* Class-H Default */ @@ -31,9 +34,20 @@ enum wcd_clsh_mode { CLS_H_LP, /* Class-H Low Power */ CLS_AB, /* Class-AB */ CLS_H_LOHIFI, /* LoHIFI */ + CLS_H_ULP, /* Ultra Low power */ + CLS_AB_HIFI, /* Class-AB */ + CLS_AB_LP, /* Class-AB Low Power */ + CLS_AB_LOHIFI, /* Class-AB Low HIFI */ CLS_NONE, /* None of the above modes */ }; +enum wcd_codec_version { + WCD9335 = 0, + WCD934X = 1, + /* New CLSH after this */ + WCD937X = 2, + WCD938X = 3, +}; struct wcd_clsh_ctrl; extern struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc( @@ -45,5 +59,7 @@ extern int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, enum wcd_clsh_event clsh_event, int nstate, enum wcd_clsh_mode mode); +extern void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, + int mode); #endif /* _WCD_CLSH_V2_H_ */ diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c new file mode 100644 index 000000000000..405128ccb4b0 --- /dev/null +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -0,0 +1,1475 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/printk.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include "wcd-mbhc-v2.h" + +#define HS_DETECT_PLUG_TIME_MS (3 * 1000) +#define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250 +#define GND_MIC_SWAP_THRESHOLD 4 +#define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100 +#define HPHL_CROSS_CONN_THRESHOLD 100 +#define HS_VREF_MIN_VAL 1400 +#define FAKE_REM_RETRY_ATTEMPTS 3 +#define WCD_MBHC_ADC_HS_THRESHOLD_MV 1700 +#define WCD_MBHC_ADC_HPH_THRESHOLD_MV 75 +#define WCD_MBHC_ADC_MICBIAS_MV 1800 +#define WCD_MBHC_FAKE_INS_RETRY 4 + +#define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | \ + SND_JACK_MECHANICAL) + +#define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \ + SND_JACK_BTN_2 | SND_JACK_BTN_3 | \ + SND_JACK_BTN_4 | SND_JACK_BTN_5) + +enum wcd_mbhc_adc_mux_ctl { + MUX_CTL_AUTO = 0, + MUX_CTL_IN2P, + MUX_CTL_IN3P, + MUX_CTL_IN4P, + MUX_CTL_HPH_L, + MUX_CTL_HPH_R, + MUX_CTL_NONE, +}; + +struct wcd_mbhc { + struct device *dev; + struct snd_soc_component *component; + struct snd_soc_jack *jack; + struct wcd_mbhc_config *cfg; + const struct wcd_mbhc_cb *mbhc_cb; + const struct wcd_mbhc_intr *intr_ids; + struct wcd_mbhc_field *fields; + /* Delayed work to report long button press */ + struct delayed_work mbhc_btn_dwork; + /* Work to correct accessory type */ + struct work_struct correct_plug_swch; + struct mutex lock; + int buttons_pressed; + u32 hph_status; /* track headhpone status */ + u8 current_plug; + bool is_btn_press; + bool in_swch_irq_handler; + bool hs_detect_work_stop; + bool is_hs_recording; + bool extn_cable_hph_rem; + bool force_linein; + bool impedance_detect; + unsigned long event_state; + unsigned long jiffies_atreport; + /* impedance of hphl and hphr */ + uint32_t zl, zr; + /* Holds type of Headset - Mono/Stereo */ + enum wcd_mbhc_hph_type hph_type; + /* Holds mbhc detection method - ADC/Legacy */ + int mbhc_detection_logic; +}; + +static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc, + int field, int val) +{ + if (!mbhc->fields[field].reg) + return 0; + + return snd_soc_component_write_field(mbhc->component, + mbhc->fields[field].reg, + mbhc->fields[field].mask, val); +} + +static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field) +{ + if (!mbhc->fields[field].reg) + return 0; + + return snd_soc_component_read_field(mbhc->component, + mbhc->fields[field].reg, + mbhc->fields[field].mask); +} + +static void wcd_program_hs_vref(struct wcd_mbhc *mbhc) +{ + u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100); + + wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val); +} + +static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias) +{ + struct snd_soc_component *component = mbhc->component; + + mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low, + mbhc->cfg->btn_high, + mbhc->cfg->num_btn, micbias); +} + +static void wcd_mbhc_curr_micbias_control(const struct wcd_mbhc *mbhc, + const enum wcd_mbhc_cs_mb_en_flag cs_mb_en) +{ + + /* + * Some codecs handle micbias/pullup enablement in codec + * drivers itself and micbias is not needed for regular + * plug type detection. So if micbias_control callback function + * is defined, just return. + */ + if (mbhc->mbhc_cb->mbhc_micbias_control) + return; + + switch (cs_mb_en) { + case WCD_MBHC_EN_CS: + wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); + /* Program Button threshold registers as per CS */ + wcd_program_btn_threshold(mbhc, false); + break; + case WCD_MBHC_EN_MB: + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); + /* Disable PULL_UP_EN & enable MICBIAS */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 2); + /* Program Button threshold registers as per MICBIAS */ + wcd_program_btn_threshold(mbhc, true); + break; + case WCD_MBHC_EN_PULLUP: + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); + wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 1); + /* Program Button threshold registers as per MICBIAS */ + wcd_program_btn_threshold(mbhc, true); + break; + case WCD_MBHC_EN_NONE: + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); + wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); + break; + default: + dev_err(mbhc->dev, "%s: Invalid parameter", __func__); + break; + } +} + +int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event) +{ + + struct snd_soc_component *component; + bool micbias2 = false; + + if (!mbhc) + return 0; + + component = mbhc->component; + + if (mbhc->mbhc_cb->micbias_enable_status) + micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2); + + switch (event) { + /* MICBIAS usage change */ + case WCD_EVENT_POST_DAPM_MICBIAS_2_ON: + mbhc->is_hs_recording = true; + break; + case WCD_EVENT_POST_MICBIAS_2_ON: + /* Disable current source if micbias2 enabled */ + if (mbhc->mbhc_cb->mbhc_micbias_control) { + if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN)) + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); + } else { + mbhc->is_hs_recording = true; + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); + } + break; + case WCD_EVENT_PRE_MICBIAS_2_OFF: + /* + * Before MICBIAS_2 is turned off, if FSM is enabled, + * make sure current source is enabled so as to detect + * button press/release events + */ + if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) { + if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN)) + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); + } + break; + /* MICBIAS usage change */ + case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: + mbhc->is_hs_recording = false; + break; + case WCD_EVENT_POST_MICBIAS_2_OFF: + if (!mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->is_hs_recording = false; + + /* Enable PULL UP if PA's are enabled */ + if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) || + (test_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state))) + /* enable pullup and cs, disable mb */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); + else + /* enable current source and disable mb, pullup*/ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); + + break; + case WCD_EVENT_POST_HPHL_PA_OFF: + clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state); + + /* check if micbias is enabled */ + if (micbias2) + /* Disable cs, pullup & enable micbias */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); + else + /* Disable micbias, pullup & enable cs */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); + break; + case WCD_EVENT_POST_HPHR_PA_OFF: + clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state); + /* check if micbias is enabled */ + if (micbias2) + /* Disable cs, pullup & enable micbias */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); + else + /* Disable micbias, pullup & enable cs */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); + break; + case WCD_EVENT_PRE_HPHL_PA_ON: + set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state); + /* check if micbias is enabled */ + if (micbias2) + /* Disable cs, pullup & enable micbias */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); + else + /* Disable micbias, enable pullup & cs */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); + break; + case WCD_EVENT_PRE_HPHR_PA_ON: + set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state); + /* check if micbias is enabled */ + if (micbias2) + /* Disable cs, pullup & enable micbias */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); + else + /* Disable micbias, enable pullup & cs */ + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); + break; + default: + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(wcd_mbhc_event_notify); + +static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc) +{ + return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork); +} + +static void wcd_micbias_disable(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE); + + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false); + + if (mbhc->mbhc_cb->set_micbias_value) { + mbhc->mbhc_cb->set_micbias_value(component); + wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); + } +} + +static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc, + enum snd_jack_types jack_type) +{ + mbhc->hph_status &= ~jack_type; + /* + * cancel possibly scheduled btn work and + * report release if we reported button press + */ + if (!wcd_cancel_btn_work(mbhc) && mbhc->buttons_pressed) { + snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); + mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK; + } + + wcd_micbias_disable(mbhc); + mbhc->hph_type = WCD_MBHC_HPH_NONE; + mbhc->zl = mbhc->zr = 0; + snd_soc_jack_report(mbhc->jack, mbhc->hph_status, WCD_MBHC_JACK_MASK); + mbhc->current_plug = MBHC_PLUG_TYPE_NONE; + mbhc->force_linein = false; +} + +static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc) +{ + + if (!mbhc->impedance_detect) + return; + + if (mbhc->cfg->linein_th != 0) { + u8 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN); + /* Set MUX_CTL to AUTO for Z-det */ + + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO); + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); + mbhc->mbhc_cb->compute_impedance(mbhc->component, &mbhc->zl, &mbhc->zr); + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en); + } +} + +static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc, + enum snd_jack_types jack_type) +{ + bool is_pa_on; + /* + * Report removal of current jack type. + * Headphone to headset shouldn't report headphone + * removal. + */ + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET && + jack_type == SND_JACK_HEADPHONE) + mbhc->hph_status &= ~SND_JACK_HEADSET; + + /* Report insertion */ + switch (jack_type) { + case SND_JACK_HEADPHONE: + mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE; + break; + case SND_JACK_HEADSET: + mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET; + mbhc->jiffies_atreport = jiffies; + break; + case SND_JACK_LINEOUT: + mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; + break; + default: + break; + } + + + is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); + + if (!is_pa_on) { + wcd_mbhc_compute_impedance(mbhc); + if ((mbhc->zl > mbhc->cfg->linein_th) && + (mbhc->zr > mbhc->cfg->linein_th) && + (jack_type == SND_JACK_HEADPHONE)) { + jack_type = SND_JACK_LINEOUT; + mbhc->force_linein = true; + mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; + if (mbhc->hph_status) { + mbhc->hph_status &= ~(SND_JACK_HEADSET | + SND_JACK_LINEOUT); + snd_soc_jack_report(mbhc->jack, mbhc->hph_status, + WCD_MBHC_JACK_MASK); + } + } + } + + /* Do not calculate impedance again for lineout + * as during playback pa is on and impedance values + * will not be correct resulting in lineout detected + * as headphone. + */ + if (is_pa_on && mbhc->force_linein) { + jack_type = SND_JACK_LINEOUT; + mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; + if (mbhc->hph_status) { + mbhc->hph_status &= ~(SND_JACK_HEADSET | + SND_JACK_LINEOUT); + snd_soc_jack_report(mbhc->jack, mbhc->hph_status, + WCD_MBHC_JACK_MASK); + } + } + + mbhc->hph_status |= jack_type; + + if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control) + mbhc->mbhc_cb->mbhc_micb_ramp_control(mbhc->component, false); + + snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL), + WCD_MBHC_JACK_MASK); +} + +static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, + enum snd_jack_types jack_type) +{ + + WARN_ON(!mutex_is_locked(&mbhc->lock)); + + if (!insertion) /* Report removal */ + wcd_mbhc_report_plug_removal(mbhc, jack_type); + else + wcd_mbhc_report_plug_insertion(mbhc, jack_type); + +} + +static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc, + struct work_struct *work) +{ + mbhc->hs_detect_work_stop = true; + mutex_unlock(&mbhc->lock); + cancel_work_sync(work); + mutex_lock(&mbhc->lock); +} + +static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc) +{ + /* cancel pending button press */ + wcd_cancel_btn_work(mbhc); + /* cancel correct work function */ + wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); +} + +static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc) +{ + wcd_mbhc_cancel_pending_work(mbhc); + /* Report extension cable */ + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); + /* + * Disable HPHL trigger and MIC Schmitt triggers. + * Setup for insertion detection. + */ + disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); + wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE); + /* Disable HW FSM */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3); + + /* Set the detection type appropriately */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1); + enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr); +} + +static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc, + enum wcd_mbhc_plug_type plug_type) +{ + if (mbhc->current_plug == plug_type) + return; + + mutex_lock(&mbhc->lock); + + switch (plug_type) { + case MBHC_PLUG_TYPE_HEADPHONE: + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE); + break; + case MBHC_PLUG_TYPE_HEADSET: + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET); + break; + case MBHC_PLUG_TYPE_HIGH_HPH: + wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); + break; + case MBHC_PLUG_TYPE_GND_MIC_SWAP: + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET); + break; + default: + WARN(1, "Unexpected current plug_type %d, plug_type %d\n", + mbhc->current_plug, plug_type); + break; + } + mutex_unlock(&mbhc->lock); +} + +static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc, + struct work_struct *work) +{ + WARN_ON(!mutex_is_locked(&mbhc->lock)); + mbhc->hs_detect_work_stop = false; + schedule_work(work); +} + +static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + + WARN_ON(!mutex_is_locked(&mbhc->lock)); + + if (mbhc->mbhc_cb->hph_pull_down_ctrl) + mbhc->mbhc_cb->hph_pull_down_ctrl(component, false); + + wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); + + if (mbhc->mbhc_cb->mbhc_micbias_control) { + mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, + MICB_ENABLE); + wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); + } +} + +static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data) +{ + struct snd_soc_component *component; + enum snd_jack_types jack_type; + struct wcd_mbhc *mbhc = data; + bool detection_type; + + component = mbhc->component; + mutex_lock(&mbhc->lock); + + mbhc->in_swch_irq_handler = true; + + wcd_mbhc_cancel_pending_work(mbhc); + + detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE); + + /* Set the detection type appropriately */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type); + + /* Enable micbias ramp */ + if (mbhc->mbhc_cb->mbhc_micb_ramp_control) + mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true); + + if (detection_type) { + if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) + goto exit; + /* Make sure MASTER_BIAS_CTL is enabled */ + mbhc->mbhc_cb->mbhc_bias(component, true); + mbhc->is_btn_press = false; + wcd_mbhc_adc_detect_plug_type(mbhc); + } else { + /* Disable HW FSM */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->extn_cable_hph_rem = false; + + if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE) + goto exit; + + mbhc->is_btn_press = false; + switch (mbhc->current_plug) { + case MBHC_PLUG_TYPE_HEADPHONE: + jack_type = SND_JACK_HEADPHONE; + break; + case MBHC_PLUG_TYPE_HEADSET: + jack_type = SND_JACK_HEADSET; + break; + case MBHC_PLUG_TYPE_HIGH_HPH: + if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC) + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 0); + jack_type = SND_JACK_LINEOUT; + break; + case MBHC_PLUG_TYPE_GND_MIC_SWAP: + dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n"); + goto exit; + default: + dev_err(mbhc->dev, "Invalid current plug: %d\n", + mbhc->current_plug); + goto exit; + } + disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); + disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0); + wcd_mbhc_report_plug(mbhc, 0, jack_type); + } + +exit: + mbhc->in_swch_irq_handler = false; + mutex_unlock(&mbhc->lock); + return IRQ_HANDLED; +} + +static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc) +{ + int mask = 0; + int btn; + + btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT); + + switch (btn) { + case 0: + mask = SND_JACK_BTN_0; + break; + case 1: + mask = SND_JACK_BTN_1; + break; + case 2: + mask = SND_JACK_BTN_2; + break; + case 3: + mask = SND_JACK_BTN_3; + break; + case 4: + mask = SND_JACK_BTN_4; + break; + case 5: + mask = SND_JACK_BTN_5; + break; + default: + break; + } + + return mask; +} + +static void wcd_btn_long_press_fn(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork); + + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) + snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed, + mbhc->buttons_pressed); +} + +static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + int mask; + unsigned long msec_val; + + mutex_lock(&mbhc->lock); + wcd_cancel_btn_work(mbhc); + mbhc->is_btn_press = true; + msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport); + + /* Too short, ignore button press */ + if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN) + goto done; + + /* If switch interrupt already kicked in, ignore button press */ + if (mbhc->in_swch_irq_handler) + goto done; + + /* Plug isn't headset, ignore button press */ + if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) + goto done; + + mask = wcd_mbhc_get_button_mask(mbhc); + mbhc->buttons_pressed |= mask; + if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)) == 0) + WARN(1, "Button pressed twice without release event\n"); +done: + mutex_unlock(&mbhc->lock); + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_btn_release_handler(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + int ret; + + mutex_lock(&mbhc->lock); + if (mbhc->is_btn_press) + mbhc->is_btn_press = false; + else /* fake btn press */ + goto exit; + + if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK)) + goto exit; + + ret = wcd_cancel_btn_work(mbhc); + if (ret == 0) { /* Reporting long button release event */ + snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); + } else { + if (!mbhc->in_swch_irq_handler) { + /* Reporting btn press n Release */ + snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed, + mbhc->buttons_pressed); + snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); + } + } + mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK; +exit: + mutex_unlock(&mbhc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr) +{ + + /* TODO Find a better way to report this to Userspace */ + dev_err(mbhc->dev, "MBHC Over Current on %s detected\n", + hphr ? "HPHR" : "HPHL"); + + wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1); + + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data) +{ + return wcd_mbhc_hph_ocp_irq(data, false); +} + +static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data) +{ + return wcd_mbhc_hph_ocp_irq(data, true); +} + +static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) +{ + struct snd_soc_component *component = mbhc->component; + + mutex_lock(&mbhc->lock); + + /* enable HS detection */ + if (mbhc->mbhc_cb->hph_pull_up_control_v2) + mbhc->mbhc_cb->hph_pull_up_control_v2(component, + HS_PULLUP_I_DEFAULT); + else if (mbhc->mbhc_cb->hph_pull_up_control) + mbhc->mbhc_cb->hph_pull_up_control(component, I_DEFAULT); + else + wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3); + + wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh); + wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh); + wcd_mbhc_write_field(mbhc, WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1); + if (mbhc->cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl) + mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true); + wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1); + + wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1); + + /* Insertion debounce set to 96ms */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6); + + /* Button Debounce set to 16ms */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2); + + /* enable bias */ + mbhc->mbhc_cb->mbhc_bias(component, true); + /* enable MBHC clock */ + if (mbhc->mbhc_cb->clk_setup) + mbhc->mbhc_cb->clk_setup(component, true); + + /* program HS_VREF value */ + wcd_program_hs_vref(mbhc); + + wcd_program_btn_threshold(mbhc, false); + + mutex_unlock(&mbhc->lock); + + return 0; +} + +static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc) +{ + int micbias = 0; + + if (mbhc->mbhc_cb->get_micbias_val) { + mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias); + } else { + u8 vout_ctl = 0; + /* Read MBHC Micbias (Mic Bias2) voltage */ + vout_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_MICB2_VOUT); + /* Formula for getting micbias from vout + * micbias = 1.0V + VOUT_CTL * 50mV + */ + micbias = 1000 + (vout_ctl * 50); + } + return micbias; +} + +static int wcd_get_voltage_from_adc(u8 val, int micbias) +{ + /* Formula for calculating voltage from ADC + * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8 + */ + return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10)); +} + +static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc) +{ + u8 adc_result; + int output_mv; + int retry = 3; + u8 adc_en; + + /* Pre-requisites for ADC continuous measurement */ + /* Read legacy electircal detection and disable */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00); + /* Set ADC to continuous measurement */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1); + /* Read ADC Enable bit to restore after adc measurement */ + adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); + /* Disable ADC_ENABLE bit */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); + /* Disable MBHC FSM */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); + /* Set the MUX selection to IN2P */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_IN2P); + /* Enable MBHC FSM */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); + /* Enable ADC_ENABLE bit */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1); + + while (retry--) { + /* wait for 3 msec before reading ADC result */ + usleep_range(3000, 3100); + adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT); + } + + /* Restore ADC Enable */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); + /* Get voltage from ADC result */ + output_mv = wcd_get_voltage_from_adc(adc_result, wcd_mbhc_get_micbias(mbhc)); + + return output_mv; +} + +static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl) +{ + struct device *dev = mbhc->dev; + u8 adc_timeout = 0; + u8 adc_complete = 0; + u8 adc_result; + int retry = 6; + int ret; + int output_mv = 0; + u8 adc_en; + + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); + /* Read ADC Enable bit to restore after adc measurement */ + adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); + /* Trigger ADC one time measurement */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); + /* Set the appropriate MUX selection */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, mux_ctl); + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1); + + while (retry--) { + /* wait for 600usec to get adc results */ + usleep_range(600, 610); + + /* check for ADC Timeout */ + adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT); + if (adc_timeout) + continue; + + /* Read ADC complete bit */ + adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE); + if (!adc_complete) + continue; + + /* Read ADC result */ + adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT); + + /* Get voltage from ADC result */ + output_mv = wcd_get_voltage_from_adc(adc_result, + wcd_mbhc_get_micbias(mbhc)); + break; + } + + /* Restore ADC Enable */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); + + if (retry <= 0) { + dev_err(dev, "%s: adc complete: %d, adc timeout: %d\n", + __func__, adc_complete, adc_timeout); + ret = -EINVAL; + } else { + ret = output_mv; + } + + return ret; +} + +/* To determine if cross connection occurred */ +static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) +{ + u8 adc_mode, elect_ctl, adc_en, fsm_en; + int hphl_adc_res, hphr_adc_res; + bool is_cross_conn = false; + + /* If PA is enabled, dont check for cross-connection */ + if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN)) + return -EINVAL; + + /* Read legacy electircal detection and disable */ + elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0); + + /* Read and set ADC to single measurement */ + adc_mode = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_MODE); + /* Read ADC Enable bit to restore after adc measurement */ + adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); + /* Read FSM status */ + fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN); + + /* Get adc result for HPH L */ + hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L); + if (hphl_adc_res < 0) + return hphl_adc_res; + + /* Get adc result for HPH R in mV */ + hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R); + if (hphr_adc_res < 0) + return hphr_adc_res; + + if (hphl_adc_res > HPHL_CROSS_CONN_THRESHOLD || + hphr_adc_res > HPHL_CROSS_CONN_THRESHOLD) + is_cross_conn = true; + + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); + /* Set the MUX selection to Auto */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO); + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); + /* Restore ADC Enable */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); + /* Restore ADC mode */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, adc_mode); + /* Restore FSM state */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en); + /* Restore electrical detection */ + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); + + return is_cross_conn; +} + +static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc) +{ + int hs_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->cfg->hs_thr) { + if (mbhc->cfg->micb_mv == micbias_mv) + hs_threshold = mbhc->cfg->hs_thr; + else + hs_threshold = (mbhc->cfg->hs_thr * + micbias_mv) / mbhc->cfg->micb_mv; + } else { + hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * + micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); + } + return hs_threshold; +} + +static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc) +{ + int hph_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->cfg->hph_thr) { + if (mbhc->cfg->micb_mv == micbias_mv) + hph_threshold = mbhc->cfg->hph_thr; + else + hph_threshold = (mbhc->cfg->hph_thr * + micbias_mv) / mbhc->cfg->micb_mv; + } else { + hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV * + micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); + } + return hph_threshold; +} + +static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc, + enum wcd_mbhc_plug_type plug_type) +{ + bool micbias2 = false; + + switch (plug_type) { + case MBHC_PLUG_TYPE_HEADPHONE: + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); + break; + case MBHC_PLUG_TYPE_HEADSET: + if (mbhc->mbhc_cb->micbias_enable_status) + micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component, + MIC_BIAS_2); + + if (!mbhc->is_hs_recording && !micbias2) + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); + break; + default: + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); + break; + + } +} + +static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable) +{ + switch (plug_type) { + case MBHC_PLUG_TYPE_HEADSET: + case MBHC_PLUG_TYPE_HEADPHONE: + if (mbhc->mbhc_cb->bcs_enable) + mbhc->mbhc_cb->bcs_enable(mbhc->component, enable); + break; + default: + break; + } +} + +static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result) + +{ + enum wcd_mbhc_plug_type plug_type; + u32 hph_thr, hs_thr; + + hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc); + hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc); + + if (adc_result < hph_thr) + plug_type = MBHC_PLUG_TYPE_HEADPHONE; + else if (adc_result > hs_thr) + plug_type = MBHC_PLUG_TYPE_HIGH_HPH; + else + plug_type = MBHC_PLUG_TYPE_HEADSET; + + return plug_type; +} + +static void wcd_correct_swch_plug(struct work_struct *work) +{ + struct wcd_mbhc *mbhc; + struct snd_soc_component *component; + enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID; + unsigned long timeout; + int pt_gnd_mic_swap_cnt = 0; + int output_mv, cross_conn, hs_threshold, try = 0; + bool is_pa_on; + + mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); + component = mbhc->component; + + hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); + + /* Mask ADC COMPLETE interrupt */ + disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); + + /* Check for cross connection */ + do { + cross_conn = wcd_check_cross_conn(mbhc); + try++; + } while (try < GND_MIC_SWAP_THRESHOLD); + + if (cross_conn > 0) { + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + dev_err(mbhc->dev, "cross connection found, Plug type %d\n", + plug_type); + goto correct_plug_type; + } + + /* Find plug type */ + output_mv = wcd_measure_adc_continuous(mbhc); + plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); + + /* + * Report plug type if it is either headset or headphone + * else start the 3 sec loop + */ + switch (plug_type) { + case MBHC_PLUG_TYPE_HEADPHONE: + wcd_mbhc_find_plug_and_report(mbhc, plug_type); + break; + case MBHC_PLUG_TYPE_HEADSET: + wcd_mbhc_find_plug_and_report(mbhc, plug_type); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); + break; + default: + break; + } + +correct_plug_type: + + /* Disable BCS slow insertion detection */ + wcd_mbhc_bcs_enable(mbhc, plug_type, false); + + timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS); + + while (!time_after(jiffies, timeout)) { + if (mbhc->hs_detect_work_stop) { + wcd_micbias_disable(mbhc); + goto exit; + } + + msleep(180); + /* + * Use ADC single mode to minimize the chance of missing out + * btn press/release for HEADSET type during correct work. + */ + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); + is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); + + if ((output_mv <= hs_threshold) && !is_pa_on) { + /* Check for cross connection*/ + cross_conn = wcd_check_cross_conn(mbhc); + if (cross_conn > 0) { /* cross-connection */ + pt_gnd_mic_swap_cnt++; + if (pt_gnd_mic_swap_cnt < GND_MIC_SWAP_THRESHOLD) + continue; + else + plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; + } else if (!cross_conn) { /* no cross connection */ + pt_gnd_mic_swap_cnt = 0; + plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); + continue; + } else if (cross_conn < 0) /* Error */ + continue; + + if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) { + /* US_EU gpio present, flip switch */ + if (mbhc->cfg->swap_gnd_mic) { + if (mbhc->cfg->swap_gnd_mic(component, true)) + continue; + } + } + } + + if (output_mv > hs_threshold) /* cable is extension cable */ + plug_type = MBHC_PLUG_TYPE_HIGH_HPH; + } + + wcd_mbhc_bcs_enable(mbhc, plug_type, true); + + if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) + wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1); + + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); + wcd_mbhc_find_plug_and_report(mbhc, plug_type); + + /* + * Set DETECTION_DONE bit for HEADSET + * so that btn press/release interrupt can be generated. + * For other plug type, clear the bit. + */ + if (plug_type == MBHC_PLUG_TYPE_HEADSET) + wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); + else + wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); + + if (mbhc->mbhc_cb->mbhc_micbias_control) + wcd_mbhc_adc_update_fsm_source(mbhc, plug_type); + +exit: + if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) + mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE); + + /* + * If plug type is corrected from special headset to headphone, + * clear the micbias enable flag, set micbias back to 1.8V and + * disable micbias. + */ + if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) { + wcd_micbias_disable(mbhc); + /* + * Enable ADC COMPLETE interrupt for HEADPHONE. + * Btn release may happen after the correct work, ADC COMPLETE + * interrupt needs to be captured to correct plug type. + */ + enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr); + } + + if (mbhc->mbhc_cb->hph_pull_down_ctrl) + mbhc->mbhc_cb->hph_pull_down_ctrl(component, true); +} + +static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + unsigned long timeout; + int adc_threshold, output_mv, retry = 0; + bool hphpa_on = false; + + mutex_lock(&mbhc->lock); + timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS); + adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); + + do { + retry++; + /* + * read output_mv every 10ms to look for + * any change in IN2_P + */ + usleep_range(10000, 10100); + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); + + /* Check for fake removal */ + if ((output_mv <= adc_threshold) && retry > FAKE_REM_RETRY_ATTEMPTS) + goto exit; + } while (!time_after(jiffies, timeout)); + + /* + * ADC COMPLETE and ELEC_REM interrupts are both enabled for + * HEADPHONE, need to reject the ADC COMPLETE interrupt which + * follows ELEC_REM one when HEADPHONE is removed. + */ + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) + mbhc->extn_cable_hph_rem = true; + + wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); + wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); + wcd_mbhc_elec_hs_report_unplug(mbhc); + wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); + + if (hphpa_on) { + hphpa_on = false; + wcd_mbhc_write_field(mbhc, WCD_MBHC_HPH_PA_EN, 3); + } +exit: + mutex_unlock(&mbhc->lock); + return IRQ_HANDLED; +} + +static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data) +{ + struct wcd_mbhc *mbhc = data; + u8 clamp_state = 0; + u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY; + + /* + * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE, + * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one + * when HEADPHONE is removed. + */ + if (mbhc->extn_cable_hph_rem == true) { + mbhc->extn_cable_hph_rem = false; + return IRQ_HANDLED; + } + + do { + clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE); + if (clamp_state) + return IRQ_HANDLED; + /* + * check clamp for 120ms but at 30ms chunks to leave + * room for other interrupts to be processed + */ + usleep_range(30000, 30100); + } while (--clamp_retry); + + /* + * If current plug is headphone then there is no chance to + * get ADC complete interrupt, so connected cable should be + * headset not headphone. + */ + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { + disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); + wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); + wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET); + return IRQ_HANDLED; + } + + return IRQ_HANDLED; +} + +int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr) +{ + *zl = mbhc->zl; + *zr = mbhc->zr; + + if (*zl && *zr) + return 0; + else + return -EINVAL; +} +EXPORT_SYMBOL(wcd_mbhc_get_impedance); + +void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type) +{ + mbhc->hph_type = hph_type; +} +EXPORT_SYMBOL(wcd_mbhc_set_hph_type); + +int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc) +{ + return mbhc->hph_type; +} +EXPORT_SYMBOL(wcd_mbhc_get_hph_type); + +int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg, + struct snd_soc_jack *jack) +{ + if (!mbhc || !cfg || !jack) + return -EINVAL; + + mbhc->cfg = cfg; + mbhc->jack = jack; + + return wcd_mbhc_initialise(mbhc); +} +EXPORT_SYMBOL(wcd_mbhc_start); + +void wcd_mbhc_stop(struct wcd_mbhc *mbhc) +{ + mbhc->current_plug = MBHC_PLUG_TYPE_NONE; + mbhc->hph_status = 0; + disable_irq_nosync(mbhc->intr_ids->hph_left_ocp); + disable_irq_nosync(mbhc->intr_ids->hph_right_ocp); +} +EXPORT_SYMBOL(wcd_mbhc_stop); + +int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg) +{ + struct device_node *np = dev->of_node; + int ret, i, microvolt; + + if (of_property_read_bool(np, "qcom,hphl-jack-type-normally-closed")) + cfg->hphl_swh = false; + else + cfg->hphl_swh = true; + + if (of_property_read_bool(np, "qcom,ground-jack-type-normally-closed")) + cfg->gnd_swh = false; + else + cfg->gnd_swh = true; + + ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt", + µvolt); + if (ret) + dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n"); + else + cfg->hs_thr = microvolt/1000; + + ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt", + µvolt); + if (ret) + dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt entry\n"); + else + cfg->hph_thr = microvolt/1000; + + ret = of_property_read_u32_array(np, + "qcom,mbhc-buttons-vthreshold-microvolt", + &cfg->btn_high[0], + WCD_MBHC_DEF_BUTTONS); + if (ret) + dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n"); + + for (i = 0; i < WCD_MBHC_DEF_BUTTONS; i++) { + if (ret) /* default voltage */ + cfg->btn_high[i] = 500000; + else + /* Micro to Milli Volts */ + cfg->btn_high[i] = cfg->btn_high[i]/1000; + } + + return 0; +} +EXPORT_SYMBOL(wcd_dt_parse_mbhc_data); + +struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, + const struct wcd_mbhc_cb *mbhc_cb, + const struct wcd_mbhc_intr *intr_ids, + struct wcd_mbhc_field *fields, + bool impedance_det_en) +{ + struct device *dev = component->dev; + struct wcd_mbhc *mbhc; + int ret; + + if (!intr_ids || !fields || !mbhc_cb || !mbhc_cb->mbhc_bias || !mbhc_cb->set_btn_thr) { + dev_err(dev, "%s: Insufficient mbhc configuration\n", __func__); + return ERR_PTR(-EINVAL); + } + + mbhc = devm_kzalloc(dev, sizeof(*mbhc), GFP_KERNEL); + if (!mbhc) + return ERR_PTR(-ENOMEM); + + mbhc->component = component; + mbhc->dev = dev; + mbhc->intr_ids = intr_ids; + mbhc->mbhc_cb = mbhc_cb; + mbhc->fields = fields; + mbhc->mbhc_detection_logic = WCD_DETECTION_ADC; + + if (mbhc_cb->compute_impedance) + mbhc->impedance_detect = impedance_det_en; + + INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn); + + mutex_init(&mbhc->lock); + + INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug); + + ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_sw_intr, NULL, + wcd_mbhc_mech_plug_detect_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "mbhc sw intr", mbhc); + if (ret) + goto err; + + ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_press_intr, NULL, + wcd_mbhc_btn_press_handler, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "Button Press detect", mbhc); + if (ret) + goto err; + + ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_release_intr, NULL, + wcd_mbhc_btn_release_handler, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "Button Release detect", mbhc); + if (ret) + goto err; + + ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_ins_intr, NULL, + wcd_mbhc_adc_hs_ins_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "Elect Insert", mbhc); + if (ret) + goto err; + + disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); + + ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_rem_intr, NULL, + wcd_mbhc_adc_hs_rem_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "Elect Remove", mbhc); + if (ret) + goto err; + + disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); + + ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_left_ocp, NULL, + wcd_mbhc_hphl_ocp_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPH_L OCP detect", mbhc); + if (ret) + goto err; + + ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_right_ocp, NULL, + wcd_mbhc_hphr_ocp_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPH_R OCP detect", mbhc); + if (ret) + goto err; + + return mbhc; +err: + dev_err(dev, "Failed to request mbhc interrupts %d\n", ret); + + return ERR_PTR(ret); +} +EXPORT_SYMBOL(wcd_mbhc_init); + +void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) +{ + mutex_lock(&mbhc->lock); + wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); + mutex_unlock(&mbhc->lock); +} +EXPORT_SYMBOL(wcd_mbhc_deinit); + +static int __init mbhc_init(void) +{ + return 0; +} + +static void __exit mbhc_exit(void) +{ +} + +module_init(mbhc_init); +module_exit(mbhc_exit); + +MODULE_DESCRIPTION("wcd MBHC v2 module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h new file mode 100644 index 000000000000..006118f3e81f --- /dev/null +++ b/sound/soc/codecs/wcd-mbhc-v2.h @@ -0,0 +1,340 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __WCD_MBHC_V2_H__ +#define __WCD_MBHC_V2_H__ + +#include <sound/jack.h> + +#define WCD_MBHC_FIELD(id, rreg, rmask) \ + [id] = { .reg = rreg, .mask = rmask } + +enum wcd_mbhc_field_function { + WCD_MBHC_L_DET_EN, + WCD_MBHC_GND_DET_EN, + WCD_MBHC_MECH_DETECTION_TYPE, + WCD_MBHC_MIC_CLAMP_CTL, + WCD_MBHC_ELECT_DETECTION_TYPE, + WCD_MBHC_HS_L_DET_PULL_UP_CTRL, + WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, + WCD_MBHC_HPHL_PLUG_TYPE, + WCD_MBHC_GND_PLUG_TYPE, + WCD_MBHC_SW_HPH_LP_100K_TO_GND, + WCD_MBHC_ELECT_SCHMT_ISRC, + WCD_MBHC_FSM_EN, + WCD_MBHC_INSREM_DBNC, + WCD_MBHC_BTN_DBNC, + WCD_MBHC_HS_VREF, + WCD_MBHC_HS_COMP_RESULT, + WCD_MBHC_IN2P_CLAMP_STATE, + WCD_MBHC_MIC_SCHMT_RESULT, + WCD_MBHC_HPHL_SCHMT_RESULT, + WCD_MBHC_HPHR_SCHMT_RESULT, + WCD_MBHC_OCP_FSM_EN, + WCD_MBHC_BTN_RESULT, + WCD_MBHC_BTN_ISRC_CTL, + WCD_MBHC_ELECT_RESULT, + WCD_MBHC_MICB_CTRL, /* Pull-up and micb control */ + WCD_MBHC_HPH_CNP_WG_TIME, + WCD_MBHC_HPHR_PA_EN, + WCD_MBHC_HPHL_PA_EN, + WCD_MBHC_HPH_PA_EN, + WCD_MBHC_SWCH_LEVEL_REMOVE, + WCD_MBHC_PULLDOWN_CTRL, + WCD_MBHC_ANC_DET_EN, + WCD_MBHC_FSM_STATUS, + WCD_MBHC_MUX_CTL, + WCD_MBHC_MOISTURE_STATUS, + WCD_MBHC_HPHR_GND, + WCD_MBHC_HPHL_GND, + WCD_MBHC_HPHL_OCP_DET_EN, + WCD_MBHC_HPHR_OCP_DET_EN, + WCD_MBHC_HPHL_OCP_STATUS, + WCD_MBHC_HPHR_OCP_STATUS, + WCD_MBHC_ADC_EN, + WCD_MBHC_ADC_COMPLETE, + WCD_MBHC_ADC_TIMEOUT, + WCD_MBHC_ADC_RESULT, + WCD_MBHC_MICB2_VOUT, + WCD_MBHC_ADC_MODE, + WCD_MBHC_DETECTION_DONE, + WCD_MBHC_ELECT_ISRC_EN, + WCD_MBHC_REG_FUNC_MAX, +}; + +#define WCD_MBHC_DEF_BUTTONS 8 +#define WCD_MBHC_KEYCODE_NUM 8 +#define WCD_MBHC_USLEEP_RANGE_MARGIN_US 100 +#define WCD_MBHC_THR_HS_MICB_MV 2700 +#define WCD_MONO_HS_MIN_THR 2 + +enum wcd_mbhc_detect_logic { + WCD_DETECTION_LEGACY, + WCD_DETECTION_ADC, +}; + +enum wcd_mbhc_cs_mb_en_flag { + WCD_MBHC_EN_CS = 0, + WCD_MBHC_EN_MB, + WCD_MBHC_EN_PULLUP, + WCD_MBHC_EN_NONE, +}; + +enum { + WCD_MBHC_ELEC_HS_INS, + WCD_MBHC_ELEC_HS_REM, +}; + +enum wcd_mbhc_plug_type { + MBHC_PLUG_TYPE_INVALID = -1, + MBHC_PLUG_TYPE_NONE, + MBHC_PLUG_TYPE_HEADSET, + MBHC_PLUG_TYPE_HEADPHONE, + MBHC_PLUG_TYPE_HIGH_HPH, + MBHC_PLUG_TYPE_GND_MIC_SWAP, +}; + +enum pa_dac_ack_flags { + WCD_MBHC_HPHL_PA_OFF_ACK = 0, + WCD_MBHC_HPHR_PA_OFF_ACK, +}; + +enum wcd_mbhc_btn_det_mem { + WCD_MBHC_BTN_DET_V_BTN_LOW, + WCD_MBHC_BTN_DET_V_BTN_HIGH +}; + +enum { + MIC_BIAS_1 = 1, + MIC_BIAS_2, + MIC_BIAS_3, + MIC_BIAS_4 +}; + +enum { + MICB_PULLUP_ENABLE, + MICB_PULLUP_DISABLE, + MICB_ENABLE, + MICB_DISABLE, +}; + +enum wcd_notify_event { + WCD_EVENT_INVALID, + /* events for micbias ON and OFF */ + WCD_EVENT_PRE_MICBIAS_2_OFF, + WCD_EVENT_POST_MICBIAS_2_OFF, + WCD_EVENT_PRE_MICBIAS_2_ON, + WCD_EVENT_POST_MICBIAS_2_ON, + WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF, + WCD_EVENT_POST_DAPM_MICBIAS_2_OFF, + WCD_EVENT_PRE_DAPM_MICBIAS_2_ON, + WCD_EVENT_POST_DAPM_MICBIAS_2_ON, + /* events for PA ON and OFF */ + WCD_EVENT_PRE_HPHL_PA_ON, + WCD_EVENT_POST_HPHL_PA_OFF, + WCD_EVENT_PRE_HPHR_PA_ON, + WCD_EVENT_POST_HPHR_PA_OFF, + WCD_EVENT_PRE_HPHL_PA_OFF, + WCD_EVENT_PRE_HPHR_PA_OFF, + WCD_EVENT_OCP_OFF, + WCD_EVENT_OCP_ON, + WCD_EVENT_LAST, +}; + +enum wcd_mbhc_event_state { + WCD_MBHC_EVENT_PA_HPHL, + WCD_MBHC_EVENT_PA_HPHR, +}; + +enum wcd_mbhc_hph_type { + WCD_MBHC_HPH_NONE = 0, + WCD_MBHC_HPH_MONO, + WCD_MBHC_HPH_STEREO, +}; + +/* + * These enum definitions are directly mapped to the register + * definitions + */ + +enum mbhc_hs_pullup_iref { + I_DEFAULT = -1, + I_OFF = 0, + I_1P0_UA, + I_2P0_UA, + I_3P0_UA, +}; + +enum mbhc_hs_pullup_iref_v2 { + HS_PULLUP_I_DEFAULT = -1, + HS_PULLUP_I_3P0_UA = 0, + HS_PULLUP_I_2P25_UA, + HS_PULLUP_I_1P5_UA, + HS_PULLUP_I_0P75_UA, + HS_PULLUP_I_1P125_UA = 0x05, + HS_PULLUP_I_0P375_UA = 0x07, + HS_PULLUP_I_2P0_UA, + HS_PULLUP_I_1P0_UA = 0x0A, + HS_PULLUP_I_0P5_UA, + HS_PULLUP_I_0P25_UA = 0x0F, + HS_PULLUP_I_0P125_UA = 0x17, + HS_PULLUP_I_OFF, +}; + +enum mbhc_moisture_rref { + R_OFF, + R_24_KOHM, + R_84_KOHM, + R_184_KOHM, +}; + +struct wcd_mbhc_config { + int btn_high[WCD_MBHC_DEF_BUTTONS]; + int btn_low[WCD_MBHC_DEF_BUTTONS]; + int v_hs_max; + int num_btn; + bool mono_stero_detection; + bool (*swap_gnd_mic)(struct snd_soc_component *component, bool active); + bool hs_ext_micbias; + bool gnd_det_en; + uint32_t linein_th; + bool moisture_en; + int mbhc_micbias; + int anc_micbias; + bool moisture_duty_cycle_en; + bool hphl_swh; /*track HPHL switch NC / NO */ + bool gnd_swh; /*track GND switch NC / NO */ + u32 hs_thr; + u32 hph_thr; + u32 micb_mv; + u32 moist_vref; + u32 moist_iref; + u32 moist_rref; +}; + +struct wcd_mbhc_intr { + int mbhc_sw_intr; + int mbhc_btn_press_intr; + int mbhc_btn_release_intr; + int mbhc_hs_ins_intr; + int mbhc_hs_rem_intr; + int hph_left_ocp; + int hph_right_ocp; +}; + +struct wcd_mbhc_field { + u16 reg; + u8 mask; +}; + +struct wcd_mbhc; + +struct wcd_mbhc_cb { + void (*update_cross_conn_thr)(struct snd_soc_component *component); + void (*get_micbias_val)(struct snd_soc_component *component, int *mb); + void (*bcs_enable)(struct snd_soc_component *component, bool bcs_enable); + void (*compute_impedance)(struct snd_soc_component *component, + uint32_t *zl, uint32_t *zr); + void (*set_micbias_value)(struct snd_soc_component *component); + void (*set_auto_zeroing)(struct snd_soc_component *component, + bool enable); + void (*clk_setup)(struct snd_soc_component *component, bool enable); + bool (*micbias_enable_status)(struct snd_soc_component *component, int micb_num); + void (*mbhc_bias)(struct snd_soc_component *component, bool enable); + void (*set_btn_thr)(struct snd_soc_component *component, + int *btn_low, int *btn_high, + int num_btn, bool is_micbias); + void (*hph_pull_up_control)(struct snd_soc_component *component, + enum mbhc_hs_pullup_iref); + int (*mbhc_micbias_control)(struct snd_soc_component *component, + int micb_num, int req); + void (*mbhc_micb_ramp_control)(struct snd_soc_component *component, + bool enable); + bool (*extn_use_mb)(struct snd_soc_component *component); + int (*mbhc_micb_ctrl_thr_mic)(struct snd_soc_component *component, + int micb_num, bool req_en); + void (*mbhc_gnd_det_ctrl)(struct snd_soc_component *component, + bool enable); + void (*hph_pull_down_ctrl)(struct snd_soc_component *component, + bool enable); + void (*mbhc_moisture_config)(struct snd_soc_component *component); + void (*update_anc_state)(struct snd_soc_component *component, + bool enable, int anc_num); + void (*hph_pull_up_control_v2)(struct snd_soc_component *component, + int pull_up_cur); + bool (*mbhc_get_moisture_status)(struct snd_soc_component *component); + void (*mbhc_moisture_polling_ctrl)(struct snd_soc_component *component, bool enable); + void (*mbhc_moisture_detect_en)(struct snd_soc_component *component, bool enable); +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD_MBHC) +int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg); +int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg, + struct snd_soc_jack *jack); +void wcd_mbhc_stop(struct wcd_mbhc *mbhc); +void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type); +int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc); +struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, + const struct wcd_mbhc_cb *mbhc_cb, + const struct wcd_mbhc_intr *mbhc_cdc_intr_ids, + struct wcd_mbhc_field *fields, + bool impedance_det_en); +int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr); +void wcd_mbhc_deinit(struct wcd_mbhc *mbhc); +int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event); + +#else +static inline int wcd_dt_parse_mbhc_data(struct device *dev, + struct wcd_mbhc_config *cfg) +{ + return -ENOTSUPP; +} + +static inline void wcd_mbhc_stop(struct wcd_mbhc *mbhc) +{ +} + +static inline struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, + const struct wcd_mbhc_cb *mbhc_cb, + const struct wcd_mbhc_intr *mbhc_cdc_intr_ids, + struct wcd_mbhc_field *fields, + bool impedance_det_en) +{ + return ERR_PTR(-ENOTSUPP); +} + +static inline void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type) +{ +} + +static inline int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc) +{ + return -ENOTSUPP; +} + +static inline int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event) +{ + return -ENOTSUPP; +} + +static inline int wcd_mbhc_start(struct wcd_mbhc *mbhc, + struct wcd_mbhc_config *mbhc_cfg, + struct snd_soc_jack *jack) +{ + return 0; +} + +static inline int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, + uint32_t *zl, + uint32_t *zr) +{ + *zl = 0; + *zr = 0; + return -EINVAL; +} +static inline void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) +{ +} +#endif + +#endif /* __WCD_MBHC_V2_H__ */ diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 046874ef490e..c496b359f2f4 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -21,6 +21,7 @@ #include <sound/soc-dapm.h> #include <sound/tlv.h> #include "wcd-clsh-v2.h" +#include "wcd-mbhc-v2.h" #define WCD934X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ @@ -131,6 +132,24 @@ } \ } +/* Z value defined in milliohm */ +#define WCD934X_ZDET_VAL_32 32000 +#define WCD934X_ZDET_VAL_400 400000 +#define WCD934X_ZDET_VAL_1200 1200000 +#define WCD934X_ZDET_VAL_100K 100000000 +/* Z floating defined in ohms */ +#define WCD934X_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE + +#define WCD934X_ZDET_NUM_MEASUREMENTS 900 +#define WCD934X_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define WCD934X_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define WCD934X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define WCD934X_MBHC_ZDET_CONST (86 * 16384) +#define WCD934X_MBHC_MOISTURE_RREF R_24_KOHM +#define WCD934X_MBHC_MAX_BUTTONS (8) +#define WCD_MBHC_HS_V_MAX 1600 + #define WCD934X_INTERPOLATOR_PATH(id) \ {"RX INT" #id "_1 MIX1 INP0", "RX0", "SLIM RX0"}, \ {"RX INT" #id "_1 MIX1 INP0", "RX1", "SLIM RX1"}, \ @@ -287,12 +306,7 @@ {"AIF3_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id }, \ {"SLIM TX" #id, NULL, "CDC_IF TX" #id " MUX"} -enum { - MIC_BIAS_1 = 1, - MIC_BIAS_2, - MIC_BIAS_3, - MIC_BIAS_4 -}; +#define WCD934X_MAX_MICBIAS MIC_BIAS_4 enum { SIDO_SOURCE_INTERNAL, @@ -486,6 +500,15 @@ static struct interp_sample_rate sr_val_tbl[] = { {352800, 0xC}, }; +struct wcd934x_mbhc_zdet_param { + u16 ldo_ctl; + u16 noff; + u16 nshift; + u16 btn5; + u16 btn6; + u16 btn7; +}; + struct wcd_slim_codec_dai_data { struct list_head slim_ch_list; struct slim_stream_config sconfig; @@ -541,6 +564,18 @@ struct wcd934x_codec { int comp_enabled[COMPANDER_MAX]; int sysclk_users; struct mutex sysclk_mutex; + /* mbhc module */ + struct wcd_mbhc *mbhc; + struct wcd_mbhc_config mbhc_cfg; + struct wcd_mbhc_intr intr_ids; + bool mbhc_started; + struct mutex micb_lock; + u32 micb_ref[WCD934X_MAX_MICBIAS]; + u32 pullup_ref[WCD934X_MAX_MICBIAS]; + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; + u32 micb4_mv; }; #define to_wcd934x_codec(_hw) container_of(_hw, struct wcd934x_codec, hw) @@ -1183,6 +1218,57 @@ static const struct soc_enum cdc_if_tx13_mux_enum = SOC_ENUM_SINGLE(WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0, ARRAY_SIZE(cdc_if_tx13_mux_text), cdc_if_tx13_mux_text); +static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { + WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD934X_ANA_MBHC_MECH, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD934X_ANA_MBHC_MECH, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD934X_ANA_MBHC_MECH, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0x30), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD934X_ANA_MBHC_ELECT, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0xC0), + WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD934X_ANA_MBHC_MECH, 0x04), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD934X_ANA_MBHC_MECH, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD934X_ANA_MBHC_MECH, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD934X_ANA_MBHC_MECH, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD934X_ANA_MBHC_ELECT, 0x06), + WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD934X_ANA_MBHC_ELECT, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F), + WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD934X_MBHC_NEW_CTL_1, 0x03), + WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD934X_MBHC_NEW_CTL_2, 0x03), + WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD934X_ANA_MBHC_RESULT_3, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD934X_ANA_MBHC_RESULT_3, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD934X_ANA_MBHC_RESULT_3, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD934X_ANA_MBHC_RESULT_3, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD934X_ANA_MBHC_RESULT_3, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD934X_HPH_OCP_CTL, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD934X_ANA_MBHC_RESULT_3, 0x07), + WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD934X_ANA_MBHC_ELECT, 0x70), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD934X_ANA_MBHC_RESULT_3, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD934X_ANA_MICB2, 0xC0), + WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD934X_HPH_CNP_WG_TIME, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD934X_ANA_HPH, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD934X_ANA_HPH, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD934X_ANA_HPH, 0xC0), + WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD934X_ANA_MBHC_RESULT_3, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD934X_MBHC_CTL_BCS, 0x02), + WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD934X_MBHC_STATUS_SPARE_1, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD934X_MBHC_NEW_CTL_2, 0x70), + WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD934X_MBHC_NEW_FSM_STATUS, 0x20), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD934X_HPH_PA_CTL2, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD934X_HPH_PA_CTL2, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD934X_HPH_L_TEST, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD934X_HPH_R_TEST, 0x01), + WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD934X_INTR_PIN1_STATUS0, 0x04), + WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD934X_INTR_PIN1_STATUS0, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD934X_MBHC_NEW_CTL_1, 0x08), + WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD934X_MBHC_NEW_FSM_STATUS, 0x40), + WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD934X_MBHC_NEW_FSM_STATUS, 0x80), + WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD934X_MBHC_NEW_ADC_RESULT, 0xFF), + WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD934X_ANA_MICB2, 0x3F), + WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD934X_MBHC_NEW_CTL_1, 0x10), + WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD934X_MBHC_NEW_CTL_1, 0x04), + WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD934X_ANA_MBHC_ZDET, 0x02), +}; + static int wcd934x_set_sido_input_src(struct wcd934x_codec *wcd, int sido_src) { if (sido_src == wcd->sido_input_src) @@ -2127,7 +2213,8 @@ static struct clk *wcd934x_register_mclk_output(struct wcd934x_codec *wcd) return NULL; } -static int wcd934x_get_micbias_val(struct device *dev, const char *micbias) +static int wcd934x_get_micbias_val(struct device *dev, const char *micbias, + u32 *micb_mv) { int mv; @@ -2145,6 +2232,8 @@ static int wcd934x_get_micbias_val(struct device *dev, const char *micbias) mv = WCD934X_DEF_MICBIAS_MV; } + *micb_mv = mv; + return (mv - 1000) / 50; } @@ -2155,13 +2244,17 @@ static int wcd934x_init_dmic(struct snd_soc_component *comp) u32 def_dmic_rate, dmic_clk_drv; vout_ctl_1 = wcd934x_get_micbias_val(comp->dev, - "qcom,micbias1-microvolt"); + "qcom,micbias1-microvolt", + &wcd->micb1_mv); vout_ctl_2 = wcd934x_get_micbias_val(comp->dev, - "qcom,micbias2-microvolt"); + "qcom,micbias2-microvolt", + &wcd->micb2_mv); vout_ctl_3 = wcd934x_get_micbias_val(comp->dev, - "qcom,micbias3-microvolt"); + "qcom,micbias3-microvolt", + &wcd->micb3_mv); vout_ctl_4 = wcd934x_get_micbias_val(comp->dev, - "qcom,micbias4-microvolt"); + "qcom,micbias4-microvolt", + &wcd->micb4_mv); snd_soc_component_update_bits(comp, WCD934X_ANA_MICB1, WCD934X_MICB_VAL_MASK, vout_ctl_1); @@ -2287,6 +2380,695 @@ static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data) return ret; } +static void wcd934x_mbhc_clk_setup(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD934X_MBHC_NEW_CTL_1, + WCD934X_MBHC_CTL_RCO_EN_MASK, enable); +} + +static void wcd934x_mbhc_mbhc_bias_control(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD934X_ANA_MBHC_ELECT, + WCD934X_ANA_MBHC_BIAS_EN, enable); +} + +static void wcd934x_mbhc_program_btn_thr(struct snd_soc_component *component, + int *btn_low, int *btn_high, + int num_btn, bool is_micbias) +{ + int i, vth; + + if (num_btn > WCD_MBHC_DEF_BUTTONS) { + dev_err(component->dev, "%s: invalid number of buttons: %d\n", + __func__, num_btn); + return; + } + + for (i = 0; i < num_btn; i++) { + vth = ((btn_high[i] * 2) / 25) & 0x3F; + snd_soc_component_write_field(component, WCD934X_ANA_MBHC_BTN0 + i, + WCD934X_MBHC_BTN_VTH_MASK, vth); + } +} + +static bool wcd934x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num) +{ + u8 val; + + if (micb_num == MIC_BIAS_2) { + val = snd_soc_component_read_field(component, WCD934X_ANA_MICB2, + WCD934X_ANA_MICB2_ENABLE_MASK); + if (val == WCD934X_MICB_ENABLE) + return true; + } + return false; +} + +static void wcd934x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component, + enum mbhc_hs_pullup_iref pull_up_cur) +{ + /* Default pull up current to 2uA */ + if (pull_up_cur < I_OFF || pull_up_cur > I_3P0_UA || + pull_up_cur == I_DEFAULT) + pull_up_cur = I_2P0_UA; + + + snd_soc_component_write_field(component, WCD934X_MBHC_NEW_PLUG_DETECT_CTL, + WCD934X_HSDET_PULLUP_C_MASK, pull_up_cur); +} + +static int wcd934x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd934x_codec *wcd934x = snd_soc_component_get_drvdata(component); + int micb_index = micb_num - 1; + u16 micb_reg; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD934X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD934X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD934X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD934X_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + mutex_lock(&wcd934x->micb_lock); + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd934x->pullup_ref[micb_index]++; + if ((wcd934x->pullup_ref[micb_index] == 1) && + (wcd934x->micb_ref[micb_index] == 0)) + snd_soc_component_write_field(component, micb_reg, + WCD934X_ANA_MICB_EN_MASK, + WCD934X_MICB_PULL_UP); + break; + case MICB_PULLUP_DISABLE: + if (wcd934x->pullup_ref[micb_index] > 0) + wcd934x->pullup_ref[micb_index]--; + + if ((wcd934x->pullup_ref[micb_index] == 0) && + (wcd934x->micb_ref[micb_index] == 0)) + snd_soc_component_write_field(component, micb_reg, + WCD934X_ANA_MICB_EN_MASK, 0); + break; + case MICB_ENABLE: + wcd934x->micb_ref[micb_index]++; + if (wcd934x->micb_ref[micb_index] == 1) { + snd_soc_component_write_field(component, micb_reg, + WCD934X_ANA_MICB_EN_MASK, + WCD934X_MICB_ENABLE); + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd934x->mbhc, + WCD_EVENT_POST_MICBIAS_2_ON); + } + + if (micb_num == MIC_BIAS_2 && is_dapm) + wcd_mbhc_event_notify(wcd934x->mbhc, + WCD_EVENT_POST_DAPM_MICBIAS_2_ON); + break; + case MICB_DISABLE: + if (wcd934x->micb_ref[micb_index] > 0) + wcd934x->micb_ref[micb_index]--; + + if ((wcd934x->micb_ref[micb_index] == 0) && + (wcd934x->pullup_ref[micb_index] > 0)) + snd_soc_component_write_field(component, micb_reg, + WCD934X_ANA_MICB_EN_MASK, + WCD934X_MICB_PULL_UP); + else if ((wcd934x->micb_ref[micb_index] == 0) && + (wcd934x->pullup_ref[micb_index] == 0)) { + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd934x->mbhc, + WCD_EVENT_PRE_MICBIAS_2_OFF); + + snd_soc_component_write_field(component, micb_reg, + WCD934X_ANA_MICB_EN_MASK, 0); + if (micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd934x->mbhc, + WCD_EVENT_POST_MICBIAS_2_OFF); + } + if (is_dapm && micb_num == MIC_BIAS_2) + wcd_mbhc_event_notify(wcd934x->mbhc, + WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); + break; + } + + mutex_unlock(&wcd934x->micb_lock); + + return 0; +} + +static int wcd934x_mbhc_request_micbias(struct snd_soc_component *component, + int micb_num, int req) +{ + struct wcd934x_codec *wcd = dev_get_drvdata(component->dev); + int ret; + + if (req == MICB_ENABLE) + __wcd934x_cdc_mclk_enable(wcd, true); + + ret = wcd934x_micbias_control(component, micb_num, req, false); + + if (req == MICB_DISABLE) + __wcd934x_cdc_mclk_enable(wcd, false); + + return ret; +} + +static void wcd934x_mbhc_micb_ramp_control(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_write_field(component, WCD934X_ANA_MICB2_RAMP, + WCD934X_RAMP_SHIFT_CTRL_MASK, 0x3); + snd_soc_component_write_field(component, WCD934X_ANA_MICB2_RAMP, + WCD934X_RAMP_EN_MASK, 1); + } else { + snd_soc_component_write_field(component, WCD934X_ANA_MICB2_RAMP, + WCD934X_RAMP_EN_MASK, 0); + snd_soc_component_write_field(component, WCD934X_ANA_MICB2_RAMP, + WCD934X_RAMP_SHIFT_CTRL_MASK, 0); + } +} + +static int wcd934x_get_micb_vout_ctl_val(u32 micb_mv) +{ + /* min micbias voltage is 1V and maximum is 2.85V */ + if (micb_mv < 1000 || micb_mv > 2850) + return -EINVAL; + + return (micb_mv - 1000) / 50; +} + +static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, + int req_volt, int micb_num) +{ + struct wcd934x_codec *wcd934x = snd_soc_component_get_drvdata(component); + int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD934X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD934X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD934X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD934X_ANA_MICB4; + break; + default: + return -EINVAL; + } + mutex_lock(&wcd934x->micb_lock); + /* + * If requested micbias voltage is same as current micbias + * voltage, then just return. Otherwise, adjust voltage as + * per requested value. If micbias is already enabled, then + * to avoid slow micbias ramp-up or down enable pull-up + * momentarily, change the micbias value and then re-enable + * micbias. + */ + micb_en = snd_soc_component_read_field(component, micb_reg, + WCD934X_ANA_MICB_EN_MASK); + cur_vout_ctl = snd_soc_component_read_field(component, micb_reg, + WCD934X_MICB_VAL_MASK); + + req_vout_ctl = wcd934x_get_micb_vout_ctl_val(req_volt); + if (req_vout_ctl < 0) { + ret = -EINVAL; + goto exit; + } + + if (cur_vout_ctl == req_vout_ctl) { + ret = 0; + goto exit; + } + + if (micb_en == WCD934X_MICB_ENABLE) + snd_soc_component_write_field(component, micb_reg, + WCD934X_ANA_MICB_EN_MASK, + WCD934X_MICB_PULL_UP); + + snd_soc_component_write_field(component, micb_reg, + WCD934X_MICB_VAL_MASK, + req_vout_ctl); + + if (micb_en == WCD934X_MICB_ENABLE) { + snd_soc_component_write_field(component, micb_reg, + WCD934X_ANA_MICB_EN_MASK, + WCD934X_MICB_ENABLE); + /* + * Add 2ms delay as per HW requirement after enabling + * micbias + */ + usleep_range(2000, 2100); + } +exit: + mutex_unlock(&wcd934x->micb_lock); + return ret; +} + +static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, + int micb_num, bool req_en) +{ + struct wcd934x_codec *wcd934x = snd_soc_component_get_drvdata(component); + int rc, micb_mv; + + if (micb_num != MIC_BIAS_2) + return -EINVAL; + /* + * If device tree micbias level is already above the minimum + * voltage needed to detect threshold microphone, then do + * not change the micbias, just return. + */ + if (wcd934x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) + return 0; + + micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd934x->micb2_mv; + + rc = wcd934x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); + + return rc; +} + +static inline void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x, + s16 *d1_a, u16 noff, + int32_t *zdet) +{ + int i; + int val, val1; + s16 c1; + s32 x1, d1; + int32_t denom; + int minCode_param[] = { + 3277, 1639, 820, 410, 205, 103, 52, 26 + }; + + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ZDET, 0x20, 0x20); + for (i = 0; i < WCD934X_ZDET_NUM_MEASUREMENTS; i++) { + regmap_read(wcd934x->regmap, WCD934X_ANA_MBHC_RESULT_2, &val); + if (val & 0x80) + break; + } + val = val << 0x8; + regmap_read(wcd934x->regmap, WCD934X_ANA_MBHC_RESULT_1, &val1); + val |= val1; + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ZDET, 0x20, 0x00); + x1 = WCD934X_MBHC_GET_X1(val); + c1 = WCD934X_MBHC_GET_C1(val); + /* If ramp is not complete, give additional 5ms */ + if ((c1 < 2) && x1) + usleep_range(5000, 5050); + + if (!c1 || !x1) { + dev_err(wcd934x->dev, "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", + __func__, c1, x1); + goto ramp_down; + } + d1 = d1_a[c1]; + denom = (x1 * d1) - (1 << (14 - noff)); + if (denom > 0) + *zdet = (WCD934X_MBHC_ZDET_CONST * 1000) / denom; + else if (x1 < minCode_param[noff]) + *zdet = WCD934X_ZDET_FLOATING_IMPEDANCE; + + dev_info(wcd934x->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", + __func__, d1, c1, x1, *zdet); +ramp_down: + i = 0; + + while (x1) { + regmap_read(wcd934x->regmap, WCD934X_ANA_MBHC_RESULT_1, &val); + regmap_read(wcd934x->regmap, WCD934X_ANA_MBHC_RESULT_2, &val1); + val = val << 0x08; + val |= val1; + x1 = WCD934X_MBHC_GET_X1(val); + i++; + if (i == WCD934X_ZDET_NUM_MEASUREMENTS) + break; + } +} + +static void wcd934x_mbhc_zdet_ramp(struct snd_soc_component *component, + struct wcd934x_mbhc_zdet_param *zdet_param, + int32_t *zl, int32_t *zr, s16 *d1_a) +{ + struct wcd934x_codec *wcd934x = dev_get_drvdata(component->dev); + int32_t zdet = 0; + + snd_soc_component_write_field(component, WCD934X_MBHC_NEW_ZDET_ANA_CTL, + WCD934X_ZDET_MAXV_CTL_MASK, zdet_param->ldo_ctl); + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_BTN5, + WCD934X_VTH_MASK, zdet_param->btn5); + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_BTN6, + WCD934X_VTH_MASK, zdet_param->btn6); + snd_soc_component_update_bits(component, WCD934X_ANA_MBHC_BTN7, + WCD934X_VTH_MASK, zdet_param->btn7); + snd_soc_component_write_field(component, WCD934X_MBHC_NEW_ZDET_ANA_CTL, + WCD934X_ZDET_RANGE_CTL_MASK, zdet_param->noff); + snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_ZDET_RAMP_CTL, + 0x0F, zdet_param->nshift); + + if (!zl) + goto z_right; + /* Start impedance measurement for HPH_L */ + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ZDET, 0x80, 0x80); + wcd934x_mbhc_get_result_params(wcd934x, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ZDET, 0x80, 0x00); + + *zl = zdet; + +z_right: + if (!zr) + return; + /* Start impedance measurement for HPH_R */ + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ZDET, 0x40, 0x40); + wcd934x_mbhc_get_result_params(wcd934x, d1_a, zdet_param->noff, &zdet); + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ZDET, 0x40, 0x00); + + *zr = zdet; +} + +static inline void wcd934x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, + int32_t *z_val, int flag_l_r) +{ + s16 q1; + int q1_cal; + + if (*z_val < (WCD934X_ZDET_VAL_400/1000)) + q1 = snd_soc_component_read(component, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 + (2 * flag_l_r)); + else + q1 = snd_soc_component_read(component, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 + (2 * flag_l_r)); + if (q1 & 0x80) + q1_cal = (10000 - ((q1 & 0x7F) * 25)); + else + q1_cal = (10000 + (q1 * 25)); + if (q1_cal > 0) + *z_val = ((*z_val) * 10000) / q1_cal; +} + +static void wcd934x_wcd_mbhc_calc_impedance(struct snd_soc_component *component, + uint32_t *zl, uint32_t *zr) +{ + struct wcd934x_codec *wcd934x = dev_get_drvdata(component->dev); + s16 reg0, reg1, reg2, reg3, reg4; + int32_t z1L, z1R, z1Ls; + int zMono, z_diff1, z_diff2; + bool is_fsm_disable = false; + struct wcd934x_mbhc_zdet_param zdet_param[] = { + {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */ + {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */ + {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */ + {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */ + }; + struct wcd934x_mbhc_zdet_param *zdet_param_ptr = NULL; + s16 d1_a[][4] = { + {0, 30, 90, 30}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + {0, 30, 30, 5}, + }; + s16 *d1 = NULL; + + reg0 = snd_soc_component_read(component, WCD934X_ANA_MBHC_BTN5); + reg1 = snd_soc_component_read(component, WCD934X_ANA_MBHC_BTN6); + reg2 = snd_soc_component_read(component, WCD934X_ANA_MBHC_BTN7); + reg3 = snd_soc_component_read(component, WCD934X_MBHC_CTL_CLK); + reg4 = snd_soc_component_read(component, WCD934X_MBHC_NEW_ZDET_ANA_CTL); + + if (snd_soc_component_read(component, WCD934X_ANA_MBHC_ELECT) & 0x80) { + is_fsm_disable = true; + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ELECT, 0x80, 0x00); + } + + /* For NO-jack, disable L_DET_EN before Z-det measurements */ + if (wcd934x->mbhc_cfg.hphl_swh) + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_MECH, 0x80, 0x00); + + /* Turn off 100k pull down on HPHL */ + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_MECH, 0x01, 0x00); + + /* First get impedance on Left */ + d1 = d1_a[1]; + zdet_param_ptr = &zdet_param[1]; + wcd934x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + + if (!WCD934X_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) + goto left_ch_impedance; + + /* Second ramp for left ch */ + if (z1L < WCD934X_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1L > WCD934X_ZDET_VAL_400) && + (z1L <= WCD934X_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1L > WCD934X_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd934x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); + +left_ch_impedance: + if ((z1L == WCD934X_ZDET_FLOATING_IMPEDANCE) || + (z1L > WCD934X_ZDET_VAL_100K)) { + *zl = WCD934X_ZDET_FLOATING_IMPEDANCE; + zdet_param_ptr = &zdet_param[1]; + d1 = d1_a[1]; + } else { + *zl = z1L/1000; + wcd934x_wcd_mbhc_qfuse_cal(component, zl, 0); + } + dev_info(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", + __func__, *zl); + + /* Start of right impedance ramp and calculation */ + wcd934x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + if (WCD934X_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { + if (((z1R > WCD934X_ZDET_VAL_1200) && + (zdet_param_ptr->noff == 0x6)) || + ((*zl) != WCD934X_ZDET_FLOATING_IMPEDANCE)) + goto right_ch_impedance; + /* Second ramp for right ch */ + if (z1R < WCD934X_ZDET_VAL_32) { + zdet_param_ptr = &zdet_param[0]; + d1 = d1_a[0]; + } else if ((z1R > WCD934X_ZDET_VAL_400) && + (z1R <= WCD934X_ZDET_VAL_1200)) { + zdet_param_ptr = &zdet_param[2]; + d1 = d1_a[2]; + } else if (z1R > WCD934X_ZDET_VAL_1200) { + zdet_param_ptr = &zdet_param[3]; + d1 = d1_a[3]; + } + wcd934x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); + } +right_ch_impedance: + if ((z1R == WCD934X_ZDET_FLOATING_IMPEDANCE) || + (z1R > WCD934X_ZDET_VAL_100K)) { + *zr = WCD934X_ZDET_FLOATING_IMPEDANCE; + } else { + *zr = z1R/1000; + wcd934x_wcd_mbhc_qfuse_cal(component, zr, 1); + } + dev_err(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", + __func__, *zr); + + /* Mono/stereo detection */ + if ((*zl == WCD934X_ZDET_FLOATING_IMPEDANCE) && + (*zr == WCD934X_ZDET_FLOATING_IMPEDANCE)) { + dev_dbg(component->dev, + "%s: plug type is invalid or extension cable\n", + __func__); + goto zdet_complete; + } + if ((*zl == WCD934X_ZDET_FLOATING_IMPEDANCE) || + (*zr == WCD934X_ZDET_FLOATING_IMPEDANCE) || + ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) || + ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) { + dev_dbg(component->dev, + "%s: Mono plug type with one ch floating or shorted to GND\n", + __func__); + wcd_mbhc_set_hph_type(wcd934x->mbhc, WCD_MBHC_HPH_MONO); + goto zdet_complete; + } + snd_soc_component_write_field(component, WCD934X_HPH_R_ATEST, + WCD934X_HPHPA_GND_OVR_MASK, 1); + snd_soc_component_write_field(component, WCD934X_HPH_PA_CTL2, + WCD934X_HPHPA_GND_R_MASK, 1); + if (*zl < (WCD934X_ZDET_VAL_32/1000)) + wcd934x_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls, NULL, d1); + else + wcd934x_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls, NULL, d1); + snd_soc_component_write_field(component, WCD934X_HPH_PA_CTL2, + WCD934X_HPHPA_GND_R_MASK, 0); + snd_soc_component_write_field(component, WCD934X_HPH_R_ATEST, + WCD934X_HPHPA_GND_OVR_MASK, 0); + z1Ls /= 1000; + wcd934x_wcd_mbhc_qfuse_cal(component, &z1Ls, 0); + /* Parallel of left Z and 9 ohm pull down resistor */ + zMono = ((*zl) * 9) / ((*zl) + 9); + z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls); + z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl)); + if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) { + dev_err(component->dev, "%s: stereo plug type detected\n", + __func__); + wcd_mbhc_set_hph_type(wcd934x->mbhc, WCD_MBHC_HPH_STEREO); + } else { + dev_err(component->dev, "%s: MONO plug type detected\n", + __func__); + wcd_mbhc_set_hph_type(wcd934x->mbhc, WCD_MBHC_HPH_MONO); + } + +zdet_complete: + snd_soc_component_write(component, WCD934X_ANA_MBHC_BTN5, reg0); + snd_soc_component_write(component, WCD934X_ANA_MBHC_BTN6, reg1); + snd_soc_component_write(component, WCD934X_ANA_MBHC_BTN7, reg2); + /* Turn on 100k pull down on HPHL */ + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_MECH, 0x01, 0x01); + + /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ + if (wcd934x->mbhc_cfg.hphl_swh) + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_MECH, 0x80, 0x80); + + snd_soc_component_write(component, WCD934X_MBHC_NEW_ZDET_ANA_CTL, reg4); + snd_soc_component_write(component, WCD934X_MBHC_CTL_CLK, reg3); + if (is_fsm_disable) + regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ELECT, 0x80, 0x80); +} + +static void wcd934x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, + bool enable) +{ + if (enable) { + snd_soc_component_write_field(component, WCD934X_ANA_MBHC_MECH, + WCD934X_MBHC_HSG_PULLUP_COMP_EN, 1); + snd_soc_component_write_field(component, WCD934X_ANA_MBHC_MECH, + WCD934X_MBHC_GND_DET_EN_MASK, 1); + } else { + snd_soc_component_write_field(component, WCD934X_ANA_MBHC_MECH, + WCD934X_MBHC_GND_DET_EN_MASK, 0); + snd_soc_component_write_field(component, WCD934X_ANA_MBHC_MECH, + WCD934X_MBHC_HSG_PULLUP_COMP_EN, 0); + } +} + +static void wcd934x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, + bool enable) +{ + snd_soc_component_write_field(component, WCD934X_HPH_PA_CTL2, + WCD934X_HPHPA_GND_R_MASK, enable); + snd_soc_component_write_field(component, WCD934X_HPH_PA_CTL2, + WCD934X_HPHPA_GND_L_MASK, enable); +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .clk_setup = wcd934x_mbhc_clk_setup, + .mbhc_bias = wcd934x_mbhc_mbhc_bias_control, + .set_btn_thr = wcd934x_mbhc_program_btn_thr, + .micbias_enable_status = wcd934x_mbhc_micb_en_status, + .hph_pull_up_control = wcd934x_mbhc_hph_l_pull_up_control, + .mbhc_micbias_control = wcd934x_mbhc_request_micbias, + .mbhc_micb_ramp_control = wcd934x_mbhc_micb_ramp_control, + .mbhc_micb_ctrl_thr_mic = wcd934x_mbhc_micb_ctrl_threshold_mic, + .compute_impedance = wcd934x_wcd_mbhc_calc_impedance, + .mbhc_gnd_det_ctrl = wcd934x_mbhc_gnd_det_ctrl, + .hph_pull_down_ctrl = wcd934x_mbhc_hph_pull_down_ctrl, +}; + +static int wcd934x_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd->mbhc); + + return 0; +} + +static int wcd934x_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t zl, zr; + bool hphr; + struct soc_mixer_control *mc; + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(component); + + mc = (struct soc_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + wcd_mbhc_get_impedance(wcd->mbhc, &zl, &zr); + dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr); + ucontrol->value.integer.value[0] = hphr ? zr : zl; + + return 0; +} +static const struct snd_kcontrol_new hph_type_detect_controls[] = { + SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, + wcd934x_get_hph_type, NULL), +}; + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + wcd934x_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + wcd934x_hph_impedance_get, NULL), +}; + +static int wcd934x_mbhc_init(struct snd_soc_component *component) +{ + struct wcd934x_ddata *data = dev_get_drvdata(component->dev->parent); + struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(component); + struct wcd_mbhc_intr *intr_ids = &wcd->intr_ids; + + intr_ids->mbhc_sw_intr = regmap_irq_get_virq(data->irq_data, + WCD934X_IRQ_MBHC_SW_DET); + intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(data->irq_data, + WCD934X_IRQ_MBHC_BUTTON_PRESS_DET); + intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(data->irq_data, + WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET); + intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(data->irq_data, + WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET); + intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(data->irq_data, + WCD934X_IRQ_MBHC_ELECT_INS_REM_DET); + intr_ids->hph_left_ocp = regmap_irq_get_virq(data->irq_data, + WCD934X_IRQ_HPH_PA_OCPL_FAULT); + intr_ids->hph_right_ocp = regmap_irq_get_virq(data->irq_data, + WCD934X_IRQ_HPH_PA_OCPR_FAULT); + + wcd->mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true); + if (IS_ERR(wcd->mbhc)) { + wcd->mbhc = NULL; + return -EINVAL; + } + + snd_soc_add_component_controls(component, impedance_detect_controls, + ARRAY_SIZE(impedance_detect_controls)); + snd_soc_add_component_controls(component, hph_type_detect_controls, + ARRAY_SIZE(hph_type_detect_controls)); + + return 0; +} static int wcd934x_comp_probe(struct snd_soc_component *component) { struct wcd934x_codec *wcd = dev_get_drvdata(component->dev); @@ -2309,6 +3091,10 @@ static int wcd934x_comp_probe(struct snd_soc_component *component) INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list); wcd934x_init_dmic(component); + + if (wcd934x_mbhc_init(component)) + dev_err(component->dev, "Failed to Initialize MBHC\n"); + return 0; } @@ -3756,6 +4542,7 @@ static int wcd934x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(comp); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -3788,6 +4575,7 @@ static int wcd934x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, WCD934X_CDC_RX_PGA_MUTE_EN_MASK, 0x00); break; case SND_SOC_DAPM_PRE_PMD: + wcd_mbhc_event_notify(wcd->mbhc, WCD_EVENT_POST_HPHL_PA_OFF); /* Enable DSD Mute before PA disable */ snd_soc_component_update_bits(comp, WCD934X_HPH_L_TEST, WCD934X_HPH_OCP_DET_MASK, @@ -3806,6 +4594,7 @@ static int wcd934x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, * disabled, then 20ms delay is needed after PA disable. */ usleep_range(20000, 20100); + wcd_mbhc_event_notify(wcd->mbhc, WCD_EVENT_POST_HPHL_PA_OFF); break; } @@ -3817,6 +4606,7 @@ static int wcd934x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(comp); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -3851,6 +4641,7 @@ static int wcd934x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, WCD934X_CDC_RX_PGA_MUTE_DISABLE); break; case SND_SOC_DAPM_PRE_PMD: + wcd_mbhc_event_notify(wcd->mbhc, WCD_EVENT_PRE_HPHR_PA_OFF); snd_soc_component_update_bits(comp, WCD934X_HPH_R_TEST, WCD934X_HPH_OCP_DET_MASK, WCD934X_HPH_OCP_DET_DISABLE); @@ -3868,6 +4659,7 @@ static int wcd934x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, * disabled, then 20ms delay is needed after PA disable. */ usleep_range(20000, 20100); + wcd_mbhc_event_notify(wcd->mbhc, WCD_EVENT_POST_HPHR_PA_OFF); break; } @@ -4323,6 +5115,29 @@ static int wcd934x_codec_enable_adc(struct snd_soc_dapm_widget *w, return 0; } +static int wcd934x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num = w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd934x_micbias_control(component, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd934x_micbias_control(component, micb_num, MICB_DISABLE, true); + break; + } + + return 0; +} + static const struct snd_soc_dapm_widget wcd934x_dapm_widgets[] = { /* Analog Outputs */ SND_SOC_DAPM_OUTPUT("EAR"), @@ -4778,13 +5593,17 @@ static const struct snd_soc_dapm_widget wcd934x_dapm_widgets[] = { wcd934x_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD934X_ANA_AMIC4, 7, 0, wcd934x_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), - SND_SOC_DAPM_SUPPLY("MIC BIAS1", WCD934X_ANA_MICB1, 6, 0, NULL, + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, + wcd934x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("MIC BIAS2", WCD934X_ANA_MICB2, 6, 0, NULL, + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, + wcd934x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("MIC BIAS3", WCD934X_ANA_MICB3, 6, 0, NULL, + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, + wcd934x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("MIC BIAS4", WCD934X_ANA_MICB4, 6, 0, NULL, + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, + wcd934x_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("AMIC4_5 SEL", SND_SOC_NOPM, 0, 0, &tx_amic4_5), @@ -4961,6 +5780,26 @@ static const struct snd_soc_dapm_route wcd934x_audio_map[] = { {"SRC1", NULL, "IIR1"}, }; +static int wcd934x_codec_set_jack(struct snd_soc_component *comp, + struct snd_soc_jack *jack, void *data) +{ + struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev); + int ret = 0; + + if (!wcd->mbhc) + return -ENOTSUPP; + + if (jack && !wcd->mbhc_started) { + ret = wcd_mbhc_start(wcd->mbhc, &wcd->mbhc_cfg, jack); + wcd->mbhc_started = true; + } else if (wcd->mbhc_started) { + wcd_mbhc_stop(wcd->mbhc); + wcd->mbhc_started = false; + } + + return ret; +} + static const struct snd_soc_component_driver wcd934x_component_drv = { .probe = wcd934x_comp_probe, .remove = wcd934x_comp_remove, @@ -4971,11 +5810,13 @@ static const struct snd_soc_component_driver wcd934x_component_drv = { .num_dapm_widgets = ARRAY_SIZE(wcd934x_dapm_widgets), .dapm_routes = wcd934x_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd934x_audio_map), + .set_jack = wcd934x_codec_set_jack, }; static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd) { struct device *dev = &wcd->sdev->dev; + struct wcd_mbhc_config *cfg = &wcd->mbhc_cfg; struct device_node *ifc_dev_np; ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0); @@ -5001,6 +5842,18 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd) of_property_read_u32(dev->parent->of_node, "qcom,dmic-sample-rate", &wcd->dmic_sample_rate); + cfg->mbhc_micbias = MIC_BIAS_2; + cfg->anc_micbias = MIC_BIAS_2; + cfg->v_hs_max = WCD_MBHC_HS_V_MAX; + cfg->num_btn = WCD934X_MBHC_MAX_BUTTONS; + cfg->micb_mv = wcd->micb2_mv; + cfg->linein_th = 5000; + cfg->hs_thr = 1700; + cfg->hph_thr = 50; + + wcd_dt_parse_mbhc_data(dev, cfg); + + return 0; } @@ -5020,6 +5873,7 @@ static int wcd934x_codec_probe(struct platform_device *pdev) wcd->extclk = data->extclk; wcd->sdev = to_slim_device(data->dev); mutex_init(&wcd->sysclk_mutex); + mutex_init(&wcd->micb_lock); ret = wcd934x_codec_parse_data(wcd); if (ret) { diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c new file mode 100644 index 000000000000..1fa05ec7459a --- /dev/null +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2021, Linaro Limited + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/component.h> +#include <linux/pm_runtime.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/of.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include "wcd938x.h" + +#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m)) + +static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = { + WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_COMP_L, WCD938X_COMP_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_COMP_R, WCD938X_COMP_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_LO, WCD938X_LO_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_DSD_L, WCD938X_DSD_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)), +}; + +static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = { + WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_ADC4, WCD938X_ADC_3_4_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_DMIC0, WCD938X_DMIC_0_3_MBHC_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_DMIC1, WCD938X_DMIC_0_3_MBHC_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_MBHC, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)), + WCD_SDW_CH(WCD938X_DMIC2, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)), + WCD_SDW_CH(WCD938X_DMIC3, WCD938X_DMIC_0_3_MBHC_PORT, BIT(3)), + WCD_SDW_CH(WCD938X_DMIC4, WCD938X_DMIC_4_7_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_DMIC5, WCD938X_DMIC_4_7_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_DMIC6, WCD938X_DMIC_4_7_PORT, BIT(2)), + WCD_SDW_CH(WCD938X_DMIC7, WCD938X_DMIC_4_7_PORT, BIT(3)), +}; + +static struct sdw_dpn_prop wcd938x_dpn_prop[WCD938X_MAX_SWR_PORTS] = { + { + .num = 1, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 8, + .simple_ch_prep_sm = true, + }, { + .num = 2, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 3, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 4, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 5, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + } +}; + +struct device *wcd938x_sdw_device_get(struct device_node *np) +{ + return bus_find_device_by_of_node(&sdw_bus_type, np); + +} +EXPORT_SYMBOL_GPL(wcd938x_sdw_device_get); + +int wcd938x_swr_get_current_bank(struct sdw_slave *sdev) +{ + int bank; + + bank = sdw_read(sdev, SDW_SCP_CTRL); + + return ((bank & 0x40) ? 1 : 0); +} +EXPORT_SYMBOL_GPL(wcd938x_swr_get_current_bank); + +int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS]; + unsigned long ch_mask; + int i, j; + + wcd->sconfig.ch_count = 1; + wcd->active_ports = 0; + for (i = 0; i < WCD938X_MAX_SWR_PORTS; i++) { + ch_mask = wcd->port_config[i].ch_mask; + + if (!ch_mask) + continue; + + for_each_set_bit(j, &ch_mask, 4) + wcd->sconfig.ch_count++; + + port_config[wcd->active_ports] = wcd->port_config[i]; + wcd->active_ports++; + } + + wcd->sconfig.bps = 1; + wcd->sconfig.frame_rate = params_rate(params); + if (wcd->is_tx) + wcd->sconfig.direction = SDW_DATA_DIR_TX; + else + wcd->sconfig.direction = SDW_DATA_DIR_RX; + + wcd->sconfig.type = SDW_STREAM_PCM; + + return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig, + &port_config[0], wcd->active_ports, + wcd->sruntime); +} +EXPORT_SYMBOL_GPL(wcd938x_sdw_hw_params); + +int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + sdw_stream_remove_slave(wcd->sdev, wcd->sruntime); + + return 0; +} +EXPORT_SYMBOL_GPL(wcd938x_sdw_free); + +int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction) +{ + wcd->sruntime = stream; + + return 0; +} +EXPORT_SYMBOL_GPL(wcd938x_sdw_set_sdw_stream); + +static int wcd9380_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + return 0; +} + +static int wcd9380_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), 0x01); + + return 0; +} + +static int wcd9380_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct wcd938x_sdw_priv *wcd = dev_get_drvdata(&slave->dev); + struct irq_domain *slave_irq = wcd->slave_irq; + struct regmap *regmap = dev_get_regmap(&slave->dev, NULL); + u32 sts1, sts2, sts3; + + do { + handle_nested_irq(irq_find_mapping(slave_irq, 0)); + regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_0, &sts1); + regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_1, &sts2); + regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_2, &sts3); + + } while (sts1 || sts2 || sts3); + + return IRQ_HANDLED; +} + +static struct sdw_slave_ops wcd9380_slave_ops = { + .update_status = wcd9380_update_status, + .interrupt_callback = wcd9380_interrupt_callback, + .bus_config = wcd9380_bus_config, +}; + +static int wcd938x_sdw_component_bind(struct device *dev, + struct device *master, void *data) +{ + return 0; +} + +static void wcd938x_sdw_component_unbind(struct device *dev, + struct device *master, void *data) +{ +} + +static const struct component_ops wcd938x_sdw_component_ops = { + .bind = wcd938x_sdw_component_bind, + .unbind = wcd938x_sdw_component_unbind, +}; + +static int wcd9380_probe(struct sdw_slave *pdev, + const struct sdw_device_id *id) +{ + struct device *dev = &pdev->dev; + struct wcd938x_sdw_priv *wcd; + int ret; + + wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); + if (!wcd) + return -ENOMEM; + + /** + * Port map index starts with 0, however the data port for this codec + * are from index 1 + */ + if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) { + wcd->is_tx = true; + ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", + &pdev->m_port_map[1], + WCD938X_MAX_TX_SWR_PORTS); + } else { + ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping", + &pdev->m_port_map[1], + WCD938X_MAX_SWR_PORTS); + } + + if (ret < 0) + dev_info(dev, "Static Port mapping not specified\n"); + + wcd->sdev = pdev; + dev_set_drvdata(dev, wcd); + + pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | + SDW_SCP_INT1_BUS_CLASH | + SDW_SCP_INT1_PARITY; + pdev->prop.lane_control_support = true; + if (wcd->is_tx) { + pdev->prop.source_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0); + pdev->prop.src_dpn_prop = wcd938x_dpn_prop; + wcd->ch_info = &wcd938x_sdw_tx_ch_info[0]; + pdev->prop.wake_capable = true; + } else { + pdev->prop.sink_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0); + pdev->prop.sink_dpn_prop = wcd938x_dpn_prop; + wcd->ch_info = &wcd938x_sdw_rx_ch_info[0]; + } + + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return component_add(dev, &wcd938x_sdw_component_ops); +} + +static const struct sdw_device_id wcd9380_slave_id[] = { + SDW_SLAVE_ENTRY(0x0217, 0x10d, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, wcd9380_slave_id); + +static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev) +{ + struct regmap *regmap = dev_get_regmap(dev, NULL); + + if (regmap) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + } + return 0; +} + +static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev) +{ + struct regmap *regmap = dev_get_regmap(dev, NULL); + + if (regmap) { + regcache_cache_only(regmap, false); + regcache_sync(regmap); + } + + pm_runtime_mark_last_busy(dev); + + return 0; +} + +static const struct dev_pm_ops wcd938x_sdw_pm_ops = { + SET_RUNTIME_PM_OPS(wcd938x_sdw_runtime_suspend, wcd938x_sdw_runtime_resume, NULL) +}; + + +static struct sdw_driver wcd9380_codec_driver = { + .probe = wcd9380_probe, + .ops = &wcd9380_slave_ops, + .id_table = wcd9380_slave_id, + .driver = { + .name = "wcd9380-codec", + .pm = &wcd938x_sdw_pm_ops, + } +}; +module_sdw_driver(wcd9380_codec_driver); + +MODULE_DESCRIPTION("WCD938X SDW codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c new file mode 100644 index 000000000000..78b76eceff8f --- /dev/null +++ b/sound/soc/codecs/wcd938x.c @@ -0,0 +1,3737 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/pm_runtime.h> +#include <linux/component.h> +#include <sound/tlv.h> +#include <linux/of_gpio.h> +#include <linux/of.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/regulator/consumer.h> + +#include "wcd-clsh-v2.h" +#include "wcd938x.h" + +#define WCD938X_MAX_MICBIAS (4) +#define WCD938X_MAX_SUPPLY (4) +#define WCD938X_MBHC_MAX_BUTTONS (8) +#define TX_ADC_MAX (4) +#define WCD938X_TX_MAX_SWR_PORTS (5) + +#define WCD938X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +/* Fractional Rates */ +#define WCD938X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400) +#define WCD938X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) +#define SWR_CLK_RATE_0P6MHZ (600000) +#define SWR_CLK_RATE_1P2MHZ (1200000) +#define SWR_CLK_RATE_2P4MHZ (2400000) +#define SWR_CLK_RATE_4P8MHZ (4800000) +#define SWR_CLK_RATE_9P6MHZ (9600000) +#define SWR_CLK_RATE_11P2896MHZ (1128960) + +#define WCD938X_DRV_NAME "wcd938x_codec" +#define WCD938X_VERSION_1_0 (1) +#define EAR_RX_PATH_AUX (1) + +#define ADC_MODE_VAL_HIFI 0x01 +#define ADC_MODE_VAL_LO_HIF 0x02 +#define ADC_MODE_VAL_NORMAL 0x03 +#define ADC_MODE_VAL_LP 0x05 +#define ADC_MODE_VAL_ULP1 0x09 +#define ADC_MODE_VAL_ULP2 0x0B + +/* Z value defined in milliohm */ +#define WCD938X_ZDET_VAL_32 (32000) +#define WCD938X_ZDET_VAL_400 (400000) +#define WCD938X_ZDET_VAL_1200 (1200000) +#define WCD938X_ZDET_VAL_100K (100000000) +/* Z floating defined in ohms */ +#define WCD938X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE) +#define WCD938X_ZDET_NUM_MEASUREMENTS (900) +#define WCD938X_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define WCD938X_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define WCD938X_MBHC_ZDET_CONST (86 * 16384) +#define WCD938X_MBHC_MOISTURE_RREF R_24_KOHM +#define WCD_MBHC_HS_V_MAX 1600 + +#define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ + .put = wcd938x_ear_pa_put_gain, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + +enum { + WCD9380 = 0, + WCD9385 = 5, +}; + +enum { + TX_HDR12 = 0, + TX_HDR34, + TX_HDR_MAX, +}; + +enum { + WCD_RX1, + WCD_RX2, + WCD_RX3 +}; + +enum { + /* INTR_CTRL_INT_MASK_0 */ + WCD938X_IRQ_MBHC_BUTTON_PRESS_DET = 0, + WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD938X_IRQ_MBHC_SW_DET, + WCD938X_IRQ_HPHR_OCP_INT, + WCD938X_IRQ_HPHR_CNP_INT, + WCD938X_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + WCD938X_IRQ_HPHL_CNP_INT, + WCD938X_IRQ_EAR_CNP_INT, + WCD938X_IRQ_EAR_SCD_INT, + WCD938X_IRQ_AUX_CNP_INT, + WCD938X_IRQ_AUX_SCD_INT, + WCD938X_IRQ_HPHL_PDM_WD_INT, + WCD938X_IRQ_HPHR_PDM_WD_INT, + WCD938X_IRQ_AUX_PDM_WD_INT, + + /* INTR_CTRL_INT_MASK_2 */ + WCD938X_IRQ_LDORT_SCD_INT, + WCD938X_IRQ_MBHC_MOISTURE_INT, + WCD938X_IRQ_HPHL_SURGE_DET_INT, + WCD938X_IRQ_HPHR_SURGE_DET_INT, + WCD938X_NUM_IRQS, +}; + +enum { + WCD_ADC1 = 0, + WCD_ADC2, + WCD_ADC3, + WCD_ADC4, + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, + AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, +}; + +enum { + ADC_MODE_INVALID = 0, + ADC_MODE_HIFI, + ADC_MODE_LO_HIF, + ADC_MODE_NORMAL, + ADC_MODE_LP, + ADC_MODE_ULP1, + ADC_MODE_ULP2, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + NUM_CODEC_DAIS, +}; + +static u8 tx_mode_bit[] = { + [ADC_MODE_INVALID] = 0x00, + [ADC_MODE_HIFI] = 0x01, + [ADC_MODE_LO_HIF] = 0x02, + [ADC_MODE_NORMAL] = 0x04, + [ADC_MODE_LP] = 0x08, + [ADC_MODE_ULP1] = 0x10, + [ADC_MODE_ULP2] = 0x20, +}; + +struct wcd938x_priv { + struct sdw_slave *tx_sdw_dev; + struct wcd938x_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; + struct device *txdev; + struct device *rxdev; + struct device_node *rxnode, *txnode; + struct regmap *regmap; + struct wcd_clsh_ctrl *clsh_info; + struct irq_domain *virq; + struct regmap_irq_chip *wcd_regmap_irq_chip; + struct regmap_irq_chip_data *irq_chip; + struct regulator_bulk_data supplies[WCD938X_MAX_SUPPLY]; + struct snd_soc_jack *jack; + unsigned long status_mask; + s32 micb_ref[WCD938X_MAX_MICBIAS]; + s32 pullup_ref[WCD938X_MAX_MICBIAS]; + u32 hph_mode; + u32 tx_mode[TX_ADC_MAX]; + int flyback_cur_det_disable; + int ear_rx_path; + int variant; + int reset_gpio; + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; + u32 micb4_mv; + int hphr_pdm_wd_int; + int hphl_pdm_wd_int; + int aux_pdm_wd_int; + bool comp1_enable; + bool comp2_enable; + bool ldoh; + bool bcs_dis; +}; + +enum { + MIC_BIAS_1 = 1, + MIC_BIAS_2, + MIC_BIAS_3, + MIC_BIAS_4 +}; + +enum { + MICB_PULLUP_ENABLE, + MICB_PULLUP_DISABLE, + MICB_ENABLE, + MICB_DISABLE, +}; + +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(line_gain, 600, -3000); +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000); + +static const struct reg_default wcd938x_defaults[] = { + {WCD938X_ANA_PAGE_REGISTER, 0x00}, + {WCD938X_ANA_BIAS, 0x00}, + {WCD938X_ANA_RX_SUPPLIES, 0x00}, + {WCD938X_ANA_HPH, 0x0C}, + {WCD938X_ANA_EAR, 0x00}, + {WCD938X_ANA_EAR_COMPANDER_CTL, 0x02}, + {WCD938X_ANA_TX_CH1, 0x20}, + {WCD938X_ANA_TX_CH2, 0x00}, + {WCD938X_ANA_TX_CH3, 0x20}, + {WCD938X_ANA_TX_CH4, 0x00}, + {WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00}, + {WCD938X_ANA_MICB3_DSP_EN_LOGIC, 0x00}, + {WCD938X_ANA_MBHC_MECH, 0x39}, + {WCD938X_ANA_MBHC_ELECT, 0x08}, + {WCD938X_ANA_MBHC_ZDET, 0x00}, + {WCD938X_ANA_MBHC_RESULT_1, 0x00}, + {WCD938X_ANA_MBHC_RESULT_2, 0x00}, + {WCD938X_ANA_MBHC_RESULT_3, 0x00}, + {WCD938X_ANA_MBHC_BTN0, 0x00}, + {WCD938X_ANA_MBHC_BTN1, 0x10}, + {WCD938X_ANA_MBHC_BTN2, 0x20}, + {WCD938X_ANA_MBHC_BTN3, 0x30}, + {WCD938X_ANA_MBHC_BTN4, 0x40}, + {WCD938X_ANA_MBHC_BTN5, 0x50}, + {WCD938X_ANA_MBHC_BTN6, 0x60}, + {WCD938X_ANA_MBHC_BTN7, 0x70}, + {WCD938X_ANA_MICB1, 0x10}, + {WCD938X_ANA_MICB2, 0x10}, + {WCD938X_ANA_MICB2_RAMP, 0x00}, + {WCD938X_ANA_MICB3, 0x10}, + {WCD938X_ANA_MICB4, 0x10}, + {WCD938X_BIAS_CTL, 0x2A}, + {WCD938X_BIAS_VBG_FINE_ADJ, 0x55}, + {WCD938X_LDOL_VDDCX_ADJUST, 0x01}, + {WCD938X_LDOL_DISABLE_LDOL, 0x00}, + {WCD938X_MBHC_CTL_CLK, 0x00}, + {WCD938X_MBHC_CTL_ANA, 0x00}, + {WCD938X_MBHC_CTL_SPARE_1, 0x00}, + {WCD938X_MBHC_CTL_SPARE_2, 0x00}, + {WCD938X_MBHC_CTL_BCS, 0x00}, + {WCD938X_MBHC_MOISTURE_DET_FSM_STATUS, 0x00}, + {WCD938X_MBHC_TEST_CTL, 0x00}, + {WCD938X_LDOH_MODE, 0x2B}, + {WCD938X_LDOH_BIAS, 0x68}, + {WCD938X_LDOH_STB_LOADS, 0x00}, + {WCD938X_LDOH_SLOWRAMP, 0x50}, + {WCD938X_MICB1_TEST_CTL_1, 0x1A}, + {WCD938X_MICB1_TEST_CTL_2, 0x00}, + {WCD938X_MICB1_TEST_CTL_3, 0xA4}, + {WCD938X_MICB2_TEST_CTL_1, 0x1A}, + {WCD938X_MICB2_TEST_CTL_2, 0x00}, + {WCD938X_MICB2_TEST_CTL_3, 0x24}, + {WCD938X_MICB3_TEST_CTL_1, 0x1A}, + {WCD938X_MICB3_TEST_CTL_2, 0x00}, + {WCD938X_MICB3_TEST_CTL_3, 0xA4}, + {WCD938X_MICB4_TEST_CTL_1, 0x1A}, + {WCD938X_MICB4_TEST_CTL_2, 0x00}, + {WCD938X_MICB4_TEST_CTL_3, 0xA4}, + {WCD938X_TX_COM_ADC_VCM, 0x39}, + {WCD938X_TX_COM_BIAS_ATEST, 0xE0}, + {WCD938X_TX_COM_SPARE1, 0x00}, + {WCD938X_TX_COM_SPARE2, 0x00}, + {WCD938X_TX_COM_TXFE_DIV_CTL, 0x22}, + {WCD938X_TX_COM_TXFE_DIV_START, 0x00}, + {WCD938X_TX_COM_SPARE3, 0x00}, + {WCD938X_TX_COM_SPARE4, 0x00}, + {WCD938X_TX_1_2_TEST_EN, 0xCC}, + {WCD938X_TX_1_2_ADC_IB, 0xE9}, + {WCD938X_TX_1_2_ATEST_REFCTL, 0x0A}, + {WCD938X_TX_1_2_TEST_CTL, 0x38}, + {WCD938X_TX_1_2_TEST_BLK_EN1, 0xFF}, + {WCD938X_TX_1_2_TXFE1_CLKDIV, 0x00}, + {WCD938X_TX_1_2_SAR2_ERR, 0x00}, + {WCD938X_TX_1_2_SAR1_ERR, 0x00}, + {WCD938X_TX_3_4_TEST_EN, 0xCC}, + {WCD938X_TX_3_4_ADC_IB, 0xE9}, + {WCD938X_TX_3_4_ATEST_REFCTL, 0x0A}, + {WCD938X_TX_3_4_TEST_CTL, 0x38}, + {WCD938X_TX_3_4_TEST_BLK_EN3, 0xFF}, + {WCD938X_TX_3_4_TXFE3_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SAR4_ERR, 0x00}, + {WCD938X_TX_3_4_SAR3_ERR, 0x00}, + {WCD938X_TX_3_4_TEST_BLK_EN2, 0xFB}, + {WCD938X_TX_3_4_TXFE2_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SPARE1, 0x00}, + {WCD938X_TX_3_4_TEST_BLK_EN4, 0xFB}, + {WCD938X_TX_3_4_TXFE4_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SPARE2, 0x00}, + {WCD938X_CLASSH_MODE_1, 0x40}, + {WCD938X_CLASSH_MODE_2, 0x3A}, + {WCD938X_CLASSH_MODE_3, 0x00}, + {WCD938X_CLASSH_CTRL_VCL_1, 0x70}, + {WCD938X_CLASSH_CTRL_VCL_2, 0x82}, + {WCD938X_CLASSH_CTRL_CCL_1, 0x31}, + {WCD938X_CLASSH_CTRL_CCL_2, 0x80}, + {WCD938X_CLASSH_CTRL_CCL_3, 0x80}, + {WCD938X_CLASSH_CTRL_CCL_4, 0x51}, + {WCD938X_CLASSH_CTRL_CCL_5, 0x00}, + {WCD938X_CLASSH_BUCK_TMUX_A_D, 0x00}, + {WCD938X_CLASSH_BUCK_SW_DRV_CNTL, 0x77}, + {WCD938X_CLASSH_SPARE, 0x00}, + {WCD938X_FLYBACK_EN, 0x4E}, + {WCD938X_FLYBACK_VNEG_CTRL_1, 0x0B}, + {WCD938X_FLYBACK_VNEG_CTRL_2, 0x45}, + {WCD938X_FLYBACK_VNEG_CTRL_3, 0x74}, + {WCD938X_FLYBACK_VNEG_CTRL_4, 0x7F}, + {WCD938X_FLYBACK_VNEG_CTRL_5, 0x83}, + {WCD938X_FLYBACK_VNEG_CTRL_6, 0x98}, + {WCD938X_FLYBACK_VNEG_CTRL_7, 0xA9}, + {WCD938X_FLYBACK_VNEG_CTRL_8, 0x68}, + {WCD938X_FLYBACK_VNEG_CTRL_9, 0x64}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_1, 0xED}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_2, 0xF0}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_3, 0xA6}, + {WCD938X_FLYBACK_CTRL_1, 0x65}, + {WCD938X_FLYBACK_TEST_CTL, 0x00}, + {WCD938X_RX_AUX_SW_CTL, 0x00}, + {WCD938X_RX_PA_AUX_IN_CONN, 0x01}, + {WCD938X_RX_TIMER_DIV, 0x32}, + {WCD938X_RX_OCP_CTL, 0x1F}, + {WCD938X_RX_OCP_COUNT, 0x77}, + {WCD938X_RX_BIAS_EAR_DAC, 0xA0}, + {WCD938X_RX_BIAS_EAR_AMP, 0xAA}, + {WCD938X_RX_BIAS_HPH_LDO, 0xA9}, + {WCD938X_RX_BIAS_HPH_PA, 0xAA}, + {WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A}, + {WCD938X_RX_BIAS_HPH_RDAC_LDO, 0x88}, + {WCD938X_RX_BIAS_HPH_CNP1, 0x82}, + {WCD938X_RX_BIAS_HPH_LOWPOWER, 0x82}, + {WCD938X_RX_BIAS_AUX_DAC, 0xA0}, + {WCD938X_RX_BIAS_AUX_AMP, 0xAA}, + {WCD938X_RX_BIAS_VNEGDAC_BLEEDER, 0x50}, + {WCD938X_RX_BIAS_MISC, 0x00}, + {WCD938X_RX_BIAS_BUCK_RST, 0x08}, + {WCD938X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44}, + {WCD938X_RX_BIAS_FLYB_ERRAMP, 0x40}, + {WCD938X_RX_BIAS_FLYB_BUFF, 0xAA}, + {WCD938X_RX_BIAS_FLYB_MID_RST, 0x14}, + {WCD938X_HPH_L_STATUS, 0x04}, + {WCD938X_HPH_R_STATUS, 0x04}, + {WCD938X_HPH_CNP_EN, 0x80}, + {WCD938X_HPH_CNP_WG_CTL, 0x9A}, + {WCD938X_HPH_CNP_WG_TIME, 0x14}, + {WCD938X_HPH_OCP_CTL, 0x28}, + {WCD938X_HPH_AUTO_CHOP, 0x16}, + {WCD938X_HPH_CHOP_CTL, 0x83}, + {WCD938X_HPH_PA_CTL1, 0x46}, + {WCD938X_HPH_PA_CTL2, 0x50}, + {WCD938X_HPH_L_EN, 0x80}, + {WCD938X_HPH_L_TEST, 0xE0}, + {WCD938X_HPH_L_ATEST, 0x50}, + {WCD938X_HPH_R_EN, 0x80}, + {WCD938X_HPH_R_TEST, 0xE0}, + {WCD938X_HPH_R_ATEST, 0x54}, + {WCD938X_HPH_RDAC_CLK_CTL1, 0x99}, + {WCD938X_HPH_RDAC_CLK_CTL2, 0x9B}, + {WCD938X_HPH_RDAC_LDO_CTL, 0x33}, + {WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00}, + {WCD938X_HPH_REFBUFF_UHQA_CTL, 0x68}, + {WCD938X_HPH_REFBUFF_LP_CTL, 0x0E}, + {WCD938X_HPH_L_DAC_CTL, 0x20}, + {WCD938X_HPH_R_DAC_CTL, 0x20}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0x19}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xA0}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS, 0x00}, + {WCD938X_EAR_EAR_EN_REG, 0x22}, + {WCD938X_EAR_EAR_PA_CON, 0x44}, + {WCD938X_EAR_EAR_SP_CON, 0xDB}, + {WCD938X_EAR_EAR_DAC_CON, 0x80}, + {WCD938X_EAR_EAR_CNP_FSM_CON, 0xB2}, + {WCD938X_EAR_TEST_CTL, 0x00}, + {WCD938X_EAR_STATUS_REG_1, 0x00}, + {WCD938X_EAR_STATUS_REG_2, 0x08}, + {WCD938X_ANA_NEW_PAGE_REGISTER, 0x00}, + {WCD938X_HPH_NEW_ANA_HPH2, 0x00}, + {WCD938X_HPH_NEW_ANA_HPH3, 0x00}, + {WCD938X_SLEEP_CTL, 0x16}, + {WCD938X_SLEEP_WATCHDOG_CTL, 0x00}, + {WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00}, + {WCD938X_MBHC_NEW_CTL_1, 0x02}, + {WCD938X_MBHC_NEW_CTL_2, 0x05}, + {WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0xE9}, + {WCD938X_MBHC_NEW_ZDET_ANA_CTL, 0x0F}, + {WCD938X_MBHC_NEW_ZDET_RAMP_CTL, 0x00}, + {WCD938X_MBHC_NEW_FSM_STATUS, 0x00}, + {WCD938X_MBHC_NEW_ADC_RESULT, 0x00}, + {WCD938X_TX_NEW_AMIC_MUX_CFG, 0x00}, + {WCD938X_AUX_AUXPA, 0x00}, + {WCD938X_LDORXTX_MODE, 0x0C}, + {WCD938X_LDORXTX_CONFIG, 0x10}, + {WCD938X_DIE_CRACK_DIE_CRK_DET_EN, 0x00}, + {WCD938X_DIE_CRACK_DIE_CRK_DET_OUT, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81}, + {WCD938X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10}, + {WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81}, + {WCD938X_HPH_NEW_INT_PA_MISC1, 0x22}, + {WCD938X_HPH_NEW_INT_PA_MISC2, 0x00}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC, 0x00}, + {WCD938X_HPH_NEW_INT_HPH_TIMER1, 0xFE}, + {WCD938X_HPH_NEW_INT_HPH_TIMER2, 0x02}, + {WCD938X_HPH_NEW_INT_HPH_TIMER3, 0x4E}, + {WCD938X_HPH_NEW_INT_HPH_TIMER4, 0x54}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, 0x90}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, 0x90}, + {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62}, + {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01}, + {WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11}, + {WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57}, + {WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01}, + {WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00}, + {WCD938X_MBHC_NEW_INT_SPARE_2, 0x00}, + {WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xA8}, + {WCD938X_EAR_INT_NEW_CNP_VCM_CON1, 0x42}, + {WCD938X_EAR_INT_NEW_CNP_VCM_CON2, 0x22}, + {WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00}, + {WCD938X_AUX_INT_EN_REG, 0x00}, + {WCD938X_AUX_INT_PA_CTRL, 0x06}, + {WCD938X_AUX_INT_SP_CTRL, 0xD2}, + {WCD938X_AUX_INT_DAC_CTRL, 0x80}, + {WCD938X_AUX_INT_CLK_CTRL, 0x50}, + {WCD938X_AUX_INT_TEST_CTRL, 0x00}, + {WCD938X_AUX_INT_STATUS_REG, 0x00}, + {WCD938X_AUX_INT_MISC, 0x00}, + {WCD938X_LDORXTX_INT_BIAS, 0x6E}, + {WCD938X_LDORXTX_INT_STB_LOADS_DTEST, 0x50}, + {WCD938X_LDORXTX_INT_TEST0, 0x1C}, + {WCD938X_LDORXTX_INT_STARTUP_TIMER, 0xFF}, + {WCD938X_LDORXTX_INT_TEST1, 0x1F}, + {WCD938X_LDORXTX_INT_STATUS, 0x00}, + {WCD938X_SLEEP_INT_WATCHDOG_CTL_1, 0x0A}, + {WCD938X_SLEEP_INT_WATCHDOG_CTL_2, 0x0A}, + {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02}, + {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2, 0xFF}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1, 0x7F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0, 0x3F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M, 0x1F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M, 0x0F}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1, 0xD7}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0, 0xC8}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP, 0xC6}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1, 0xD5}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0, 0xCA}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, 0x05}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0, 0xA5}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, 0x13}, + {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1, 0x88}, + {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP, 0x42}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L2, 0xFF}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L1, 0x64}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L0, 0x64}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP, 0x77}, + {WCD938X_DIGITAL_PAGE_REGISTER, 0x00}, + {WCD938X_DIGITAL_CHIP_ID0, 0x00}, + {WCD938X_DIGITAL_CHIP_ID1, 0x00}, + {WCD938X_DIGITAL_CHIP_ID2, 0x0D}, + {WCD938X_DIGITAL_CHIP_ID3, 0x01}, + {WCD938X_DIGITAL_SWR_TX_CLK_RATE, 0x00}, + {WCD938X_DIGITAL_CDC_RST_CTL, 0x03}, + {WCD938X_DIGITAL_TOP_CLK_CFG, 0x00}, + {WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0xF0}, + {WCD938X_DIGITAL_SWR_RST_EN, 0x00}, + {WCD938X_DIGITAL_CDC_PATH_MODE, 0x55}, + {WCD938X_DIGITAL_CDC_RX_RST, 0x00}, + {WCD938X_DIGITAL_CDC_RX0_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_RX1_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_RX2_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x00}, + {WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x00}, + {WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x00}, + {WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x1E}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A3_0, 0xAC}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1A}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A5_0, 0xBC}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A6_0, 0xC7}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A7_0, 0xF8}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_0, 0x47}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_1, 0x43}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_2, 0xB1}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_3, 0x17}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R1, 0x4D}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R2, 0x29}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R3, 0x34}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R4, 0x59}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R5, 0x66}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R6, 0x87}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R7, 0x64}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A3_0, 0xAB}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1C}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A6_0, 0xAA}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A7_0, 0xE3}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_0, 0x69}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_1, 0x54}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_2, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_3, 0x15}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R1, 0xA4}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R2, 0xB5}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R3, 0x86}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R4, 0x85}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R5, 0xAA}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R6, 0xE2}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R7, 0x62}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xA9}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3D}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2E}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xFC}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_SWR_CLH, 0x00}, + {WCD938X_DIGITAL_SWR_CLH_BYP, 0x00}, + {WCD938X_DIGITAL_CDC_TX0_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX1_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX2_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX_RST, 0x00}, + {WCD938X_DIGITAL_CDC_REQ_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_RST, 0x00}, + {WCD938X_DIGITAL_CDC_AMIC_CTL, 0x0F}, + {WCD938X_DIGITAL_CDC_DMIC_CTL, 0x04}, + {WCD938X_DIGITAL_CDC_DMIC1_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC2_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC3_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC4_CTL, 0x01}, + {WCD938X_DIGITAL_EFUSE_PRG_CTL, 0x00}, + {WCD938X_DIGITAL_EFUSE_CTL, 0x2B}, + {WCD938X_DIGITAL_CDC_DMIC_RATE_1_2, 0x11}, + {WCD938X_DIGITAL_CDC_DMIC_RATE_3_4, 0x11}, + {WCD938X_DIGITAL_PDM_WD_CTL0, 0x00}, + {WCD938X_DIGITAL_PDM_WD_CTL1, 0x00}, + {WCD938X_DIGITAL_PDM_WD_CTL2, 0x00}, + {WCD938X_DIGITAL_INTR_MODE, 0x00}, + {WCD938X_DIGITAL_INTR_MASK_0, 0xFF}, + {WCD938X_DIGITAL_INTR_MASK_1, 0xFF}, + {WCD938X_DIGITAL_INTR_MASK_2, 0x3F}, + {WCD938X_DIGITAL_INTR_STATUS_0, 0x00}, + {WCD938X_DIGITAL_INTR_STATUS_1, 0x00}, + {WCD938X_DIGITAL_INTR_STATUS_2, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_0, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_1, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_2, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_0, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_1, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_2, 0x00}, + {WCD938X_DIGITAL_INTR_SET_0, 0x00}, + {WCD938X_DIGITAL_INTR_SET_1, 0x00}, + {WCD938X_DIGITAL_INTR_SET_2, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_0, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_1, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_2, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_EN, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_0_1, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_2_3, 0x00}, + {WCD938X_DIGITAL_LB_IN_SEL_CTL, 0x00}, + {WCD938X_DIGITAL_LOOP_BACK_MODE, 0x00}, + {WCD938X_DIGITAL_SWR_DAC_TEST, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_RX_0, 0x40}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_0, 0x40}, + {WCD938X_DIGITAL_SWR_HM_TEST_RX_1, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_1, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_2, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_0, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_1, 0x00}, + {WCD938X_DIGITAL_PAD_CTL_SWR_0, 0x8F}, + {WCD938X_DIGITAL_PAD_CTL_SWR_1, 0x06}, + {WCD938X_DIGITAL_I2C_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE, 0x00}, + {WCD938X_DIGITAL_EFUSE_TEST_CTL_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_TEST_CTL_1, 0x00}, + {WCD938X_DIGITAL_EFUSE_T_DATA_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_T_DATA_1, 0x00}, + {WCD938X_DIGITAL_PAD_CTL_PDM_RX0, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_RX1, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX0, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX1, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX2, 0xF1}, + {WCD938X_DIGITAL_PAD_INP_DIS_0, 0x00}, + {WCD938X_DIGITAL_PAD_INP_DIS_1, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_0, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_1, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_2, 0x00}, + {WCD938X_DIGITAL_RX_DATA_EDGE_CTL, 0x1F}, + {WCD938X_DIGITAL_TX_DATA_EDGE_CTL, 0x80}, + {WCD938X_DIGITAL_GPIO_MODE, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_OE, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_DATA_0, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_DATA_1, 0x00}, + {WCD938X_DIGITAL_PIN_STATUS_0, 0x00}, + {WCD938X_DIGITAL_PIN_STATUS_1, 0x00}, + {WCD938X_DIGITAL_DIG_DEBUG_CTL, 0x00}, + {WCD938X_DIGITAL_DIG_DEBUG_EN, 0x00}, + {WCD938X_DIGITAL_ANA_CSR_DBG_ADD, 0x00}, + {WCD938X_DIGITAL_ANA_CSR_DBG_CTL, 0x48}, + {WCD938X_DIGITAL_SSP_DBG, 0x00}, + {WCD938X_DIGITAL_MODE_STATUS_0, 0x00}, + {WCD938X_DIGITAL_MODE_STATUS_1, 0x00}, + {WCD938X_DIGITAL_SPARE_0, 0x00}, + {WCD938X_DIGITAL_SPARE_1, 0x00}, + {WCD938X_DIGITAL_SPARE_2, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_1, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_2, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_3, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_4, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_5, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_6, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_7, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_8, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_9, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_10, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_11, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_12, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_13, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_14, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_15, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_16, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_17, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_18, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_19, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_20, 0x0E}, + {WCD938X_DIGITAL_EFUSE_REG_21, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_22, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_23, 0xF8}, + {WCD938X_DIGITAL_EFUSE_REG_24, 0x16}, + {WCD938X_DIGITAL_EFUSE_REG_25, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_26, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_27, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_28, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_29, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_30, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_31, 0x00}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0x88}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA0, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA1, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA2, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA3, 0x01}, +}; + +static bool wcd938x_rdwr_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD938X_ANA_PAGE_REGISTER: + case WCD938X_ANA_BIAS: + case WCD938X_ANA_RX_SUPPLIES: + case WCD938X_ANA_HPH: + case WCD938X_ANA_EAR: + case WCD938X_ANA_EAR_COMPANDER_CTL: + case WCD938X_ANA_TX_CH1: + case WCD938X_ANA_TX_CH2: + case WCD938X_ANA_TX_CH3: + case WCD938X_ANA_TX_CH4: + case WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC: + case WCD938X_ANA_MICB3_DSP_EN_LOGIC: + case WCD938X_ANA_MBHC_MECH: + case WCD938X_ANA_MBHC_ELECT: + case WCD938X_ANA_MBHC_ZDET: + case WCD938X_ANA_MBHC_BTN0: + case WCD938X_ANA_MBHC_BTN1: + case WCD938X_ANA_MBHC_BTN2: + case WCD938X_ANA_MBHC_BTN3: + case WCD938X_ANA_MBHC_BTN4: + case WCD938X_ANA_MBHC_BTN5: + case WCD938X_ANA_MBHC_BTN6: + case WCD938X_ANA_MBHC_BTN7: + case WCD938X_ANA_MICB1: + case WCD938X_ANA_MICB2: + case WCD938X_ANA_MICB2_RAMP: + case WCD938X_ANA_MICB3: + case WCD938X_ANA_MICB4: + case WCD938X_BIAS_CTL: + case WCD938X_BIAS_VBG_FINE_ADJ: + case WCD938X_LDOL_VDDCX_ADJUST: + case WCD938X_LDOL_DISABLE_LDOL: + case WCD938X_MBHC_CTL_CLK: + case WCD938X_MBHC_CTL_ANA: + case WCD938X_MBHC_CTL_SPARE_1: + case WCD938X_MBHC_CTL_SPARE_2: + case WCD938X_MBHC_CTL_BCS: + case WCD938X_MBHC_TEST_CTL: + case WCD938X_LDOH_MODE: + case WCD938X_LDOH_BIAS: + case WCD938X_LDOH_STB_LOADS: + case WCD938X_LDOH_SLOWRAMP: + case WCD938X_MICB1_TEST_CTL_1: + case WCD938X_MICB1_TEST_CTL_2: + case WCD938X_MICB1_TEST_CTL_3: + case WCD938X_MICB2_TEST_CTL_1: + case WCD938X_MICB2_TEST_CTL_2: + case WCD938X_MICB2_TEST_CTL_3: + case WCD938X_MICB3_TEST_CTL_1: + case WCD938X_MICB3_TEST_CTL_2: + case WCD938X_MICB3_TEST_CTL_3: + case WCD938X_MICB4_TEST_CTL_1: + case WCD938X_MICB4_TEST_CTL_2: + case WCD938X_MICB4_TEST_CTL_3: + case WCD938X_TX_COM_ADC_VCM: + case WCD938X_TX_COM_BIAS_ATEST: + case WCD938X_TX_COM_SPARE1: + case WCD938X_TX_COM_SPARE2: + case WCD938X_TX_COM_TXFE_DIV_CTL: + case WCD938X_TX_COM_TXFE_DIV_START: + case WCD938X_TX_COM_SPARE3: + case WCD938X_TX_COM_SPARE4: + case WCD938X_TX_1_2_TEST_EN: + case WCD938X_TX_1_2_ADC_IB: + case WCD938X_TX_1_2_ATEST_REFCTL: + case WCD938X_TX_1_2_TEST_CTL: + case WCD938X_TX_1_2_TEST_BLK_EN1: + case WCD938X_TX_1_2_TXFE1_CLKDIV: + case WCD938X_TX_3_4_TEST_EN: + case WCD938X_TX_3_4_ADC_IB: + case WCD938X_TX_3_4_ATEST_REFCTL: + case WCD938X_TX_3_4_TEST_CTL: + case WCD938X_TX_3_4_TEST_BLK_EN3: + case WCD938X_TX_3_4_TXFE3_CLKDIV: + case WCD938X_TX_3_4_TEST_BLK_EN2: + case WCD938X_TX_3_4_TXFE2_CLKDIV: + case WCD938X_TX_3_4_SPARE1: + case WCD938X_TX_3_4_TEST_BLK_EN4: + case WCD938X_TX_3_4_TXFE4_CLKDIV: + case WCD938X_TX_3_4_SPARE2: + case WCD938X_CLASSH_MODE_1: + case WCD938X_CLASSH_MODE_2: + case WCD938X_CLASSH_MODE_3: + case WCD938X_CLASSH_CTRL_VCL_1: + case WCD938X_CLASSH_CTRL_VCL_2: + case WCD938X_CLASSH_CTRL_CCL_1: + case WCD938X_CLASSH_CTRL_CCL_2: + case WCD938X_CLASSH_CTRL_CCL_3: + case WCD938X_CLASSH_CTRL_CCL_4: + case WCD938X_CLASSH_CTRL_CCL_5: + case WCD938X_CLASSH_BUCK_TMUX_A_D: + case WCD938X_CLASSH_BUCK_SW_DRV_CNTL: + case WCD938X_CLASSH_SPARE: + case WCD938X_FLYBACK_EN: + case WCD938X_FLYBACK_VNEG_CTRL_1: + case WCD938X_FLYBACK_VNEG_CTRL_2: + case WCD938X_FLYBACK_VNEG_CTRL_3: + case WCD938X_FLYBACK_VNEG_CTRL_4: + case WCD938X_FLYBACK_VNEG_CTRL_5: + case WCD938X_FLYBACK_VNEG_CTRL_6: + case WCD938X_FLYBACK_VNEG_CTRL_7: + case WCD938X_FLYBACK_VNEG_CTRL_8: + case WCD938X_FLYBACK_VNEG_CTRL_9: + case WCD938X_FLYBACK_VNEGDAC_CTRL_1: + case WCD938X_FLYBACK_VNEGDAC_CTRL_2: + case WCD938X_FLYBACK_VNEGDAC_CTRL_3: + case WCD938X_FLYBACK_CTRL_1: + case WCD938X_FLYBACK_TEST_CTL: + case WCD938X_RX_AUX_SW_CTL: + case WCD938X_RX_PA_AUX_IN_CONN: + case WCD938X_RX_TIMER_DIV: + case WCD938X_RX_OCP_CTL: + case WCD938X_RX_OCP_COUNT: + case WCD938X_RX_BIAS_EAR_DAC: + case WCD938X_RX_BIAS_EAR_AMP: + case WCD938X_RX_BIAS_HPH_LDO: + case WCD938X_RX_BIAS_HPH_PA: + case WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2: + case WCD938X_RX_BIAS_HPH_RDAC_LDO: + case WCD938X_RX_BIAS_HPH_CNP1: + case WCD938X_RX_BIAS_HPH_LOWPOWER: + case WCD938X_RX_BIAS_AUX_DAC: + case WCD938X_RX_BIAS_AUX_AMP: + case WCD938X_RX_BIAS_VNEGDAC_BLEEDER: + case WCD938X_RX_BIAS_MISC: + case WCD938X_RX_BIAS_BUCK_RST: + case WCD938X_RX_BIAS_BUCK_VREF_ERRAMP: + case WCD938X_RX_BIAS_FLYB_ERRAMP: + case WCD938X_RX_BIAS_FLYB_BUFF: + case WCD938X_RX_BIAS_FLYB_MID_RST: + case WCD938X_HPH_CNP_EN: + case WCD938X_HPH_CNP_WG_CTL: + case WCD938X_HPH_CNP_WG_TIME: + case WCD938X_HPH_OCP_CTL: + case WCD938X_HPH_AUTO_CHOP: + case WCD938X_HPH_CHOP_CTL: + case WCD938X_HPH_PA_CTL1: + case WCD938X_HPH_PA_CTL2: + case WCD938X_HPH_L_EN: + case WCD938X_HPH_L_TEST: + case WCD938X_HPH_L_ATEST: + case WCD938X_HPH_R_EN: + case WCD938X_HPH_R_TEST: + case WCD938X_HPH_R_ATEST: + case WCD938X_HPH_RDAC_CLK_CTL1: + case WCD938X_HPH_RDAC_CLK_CTL2: + case WCD938X_HPH_RDAC_LDO_CTL: + case WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL: + case WCD938X_HPH_REFBUFF_UHQA_CTL: + case WCD938X_HPH_REFBUFF_LP_CTL: + case WCD938X_HPH_L_DAC_CTL: + case WCD938X_HPH_R_DAC_CTL: + case WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL: + case WCD938X_HPH_SURGE_HPHLR_SURGE_EN: + case WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1: + case WCD938X_EAR_EAR_EN_REG: + case WCD938X_EAR_EAR_PA_CON: + case WCD938X_EAR_EAR_SP_CON: + case WCD938X_EAR_EAR_DAC_CON: + case WCD938X_EAR_EAR_CNP_FSM_CON: + case WCD938X_EAR_TEST_CTL: + case WCD938X_ANA_NEW_PAGE_REGISTER: + case WCD938X_HPH_NEW_ANA_HPH2: + case WCD938X_HPH_NEW_ANA_HPH3: + case WCD938X_SLEEP_CTL: + case WCD938X_SLEEP_WATCHDOG_CTL: + case WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL: + case WCD938X_MBHC_NEW_CTL_1: + case WCD938X_MBHC_NEW_CTL_2: + case WCD938X_MBHC_NEW_PLUG_DETECT_CTL: + case WCD938X_MBHC_NEW_ZDET_ANA_CTL: + case WCD938X_MBHC_NEW_ZDET_RAMP_CTL: + case WCD938X_TX_NEW_AMIC_MUX_CFG: + case WCD938X_AUX_AUXPA: + case WCD938X_LDORXTX_MODE: + case WCD938X_LDORXTX_CONFIG: + case WCD938X_DIE_CRACK_DIE_CRK_DET_EN: + case WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL: + case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L: + case WCD938X_HPH_NEW_INT_RDAC_VREF_CTL: + case WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL: + case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R: + case WCD938X_HPH_NEW_INT_PA_MISC1: + case WCD938X_HPH_NEW_INT_PA_MISC2: + case WCD938X_HPH_NEW_INT_PA_RDAC_MISC: + case WCD938X_HPH_NEW_INT_HPH_TIMER1: + case WCD938X_HPH_NEW_INT_HPH_TIMER2: + case WCD938X_HPH_NEW_INT_HPH_TIMER3: + case WCD938X_HPH_NEW_INT_HPH_TIMER4: + case WCD938X_HPH_NEW_INT_PA_RDAC_MISC2: + case WCD938X_HPH_NEW_INT_PA_RDAC_MISC3: + case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW: + case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW: + case WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI: + case WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP: + case WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP: + case WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL: + case WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL: + case WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT: + case WCD938X_MBHC_NEW_INT_SPARE_2: + case WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON: + case WCD938X_EAR_INT_NEW_CNP_VCM_CON1: + case WCD938X_EAR_INT_NEW_CNP_VCM_CON2: + case WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS: + case WCD938X_AUX_INT_EN_REG: + case WCD938X_AUX_INT_PA_CTRL: + case WCD938X_AUX_INT_SP_CTRL: + case WCD938X_AUX_INT_DAC_CTRL: + case WCD938X_AUX_INT_CLK_CTRL: + case WCD938X_AUX_INT_TEST_CTRL: + case WCD938X_AUX_INT_MISC: + case WCD938X_LDORXTX_INT_BIAS: + case WCD938X_LDORXTX_INT_STB_LOADS_DTEST: + case WCD938X_LDORXTX_INT_TEST0: + case WCD938X_LDORXTX_INT_STARTUP_TIMER: + case WCD938X_LDORXTX_INT_TEST1: + case WCD938X_SLEEP_INT_WATCHDOG_CTL_1: + case WCD938X_SLEEP_INT_WATCHDOG_CTL_2: + case WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1: + case WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP: + case WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1: + case WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP: + case WCD938X_TX_COM_NEW_INT_TXADC_INT_L2: + case WCD938X_TX_COM_NEW_INT_TXADC_INT_L1: + case WCD938X_TX_COM_NEW_INT_TXADC_INT_L0: + case WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP: + case WCD938X_DIGITAL_PAGE_REGISTER: + case WCD938X_DIGITAL_SWR_TX_CLK_RATE: + case WCD938X_DIGITAL_CDC_RST_CTL: + case WCD938X_DIGITAL_TOP_CLK_CFG: + case WCD938X_DIGITAL_CDC_ANA_CLK_CTL: + case WCD938X_DIGITAL_CDC_DIG_CLK_CTL: + case WCD938X_DIGITAL_SWR_RST_EN: + case WCD938X_DIGITAL_CDC_PATH_MODE: + case WCD938X_DIGITAL_CDC_RX_RST: + case WCD938X_DIGITAL_CDC_RX0_CTL: + case WCD938X_DIGITAL_CDC_RX1_CTL: + case WCD938X_DIGITAL_CDC_RX2_CTL: + case WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1: + case WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3: + case WCD938X_DIGITAL_CDC_COMP_CTL_0: + case WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL: + case WCD938X_DIGITAL_CDC_HPH_DSM_A1_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A1_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A2_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A2_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A3_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A3_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A4_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A4_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A5_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A5_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A6_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A7_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_C_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_C_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_C_2: + case WCD938X_DIGITAL_CDC_HPH_DSM_C_3: + case WCD938X_DIGITAL_CDC_HPH_DSM_R1: + case WCD938X_DIGITAL_CDC_HPH_DSM_R2: + case WCD938X_DIGITAL_CDC_HPH_DSM_R3: + case WCD938X_DIGITAL_CDC_HPH_DSM_R4: + case WCD938X_DIGITAL_CDC_HPH_DSM_R5: + case WCD938X_DIGITAL_CDC_HPH_DSM_R6: + case WCD938X_DIGITAL_CDC_HPH_DSM_R7: + case WCD938X_DIGITAL_CDC_AUX_DSM_A1_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A1_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A2_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A2_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A3_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A3_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A4_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A4_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A5_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A5_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A6_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A7_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_C_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_C_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_C_2: + case WCD938X_DIGITAL_CDC_AUX_DSM_C_3: + case WCD938X_DIGITAL_CDC_AUX_DSM_R1: + case WCD938X_DIGITAL_CDC_AUX_DSM_R2: + case WCD938X_DIGITAL_CDC_AUX_DSM_R3: + case WCD938X_DIGITAL_CDC_AUX_DSM_R4: + case WCD938X_DIGITAL_CDC_AUX_DSM_R5: + case WCD938X_DIGITAL_CDC_AUX_DSM_R6: + case WCD938X_DIGITAL_CDC_AUX_DSM_R7: + case WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0: + case WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1: + case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0: + case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1: + case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2: + case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0: + case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1: + case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2: + case WCD938X_DIGITAL_CDC_HPH_GAIN_CTL: + case WCD938X_DIGITAL_CDC_AUX_GAIN_CTL: + case WCD938X_DIGITAL_CDC_EAR_PATH_CTL: + case WCD938X_DIGITAL_CDC_SWR_CLH: + case WCD938X_DIGITAL_SWR_CLH_BYP: + case WCD938X_DIGITAL_CDC_TX0_CTL: + case WCD938X_DIGITAL_CDC_TX1_CTL: + case WCD938X_DIGITAL_CDC_TX2_CTL: + case WCD938X_DIGITAL_CDC_TX_RST: + case WCD938X_DIGITAL_CDC_REQ_CTL: + case WCD938X_DIGITAL_CDC_RST: + case WCD938X_DIGITAL_CDC_AMIC_CTL: + case WCD938X_DIGITAL_CDC_DMIC_CTL: + case WCD938X_DIGITAL_CDC_DMIC1_CTL: + case WCD938X_DIGITAL_CDC_DMIC2_CTL: + case WCD938X_DIGITAL_CDC_DMIC3_CTL: + case WCD938X_DIGITAL_CDC_DMIC4_CTL: + case WCD938X_DIGITAL_EFUSE_PRG_CTL: + case WCD938X_DIGITAL_EFUSE_CTL: + case WCD938X_DIGITAL_CDC_DMIC_RATE_1_2: + case WCD938X_DIGITAL_CDC_DMIC_RATE_3_4: + case WCD938X_DIGITAL_PDM_WD_CTL0: + case WCD938X_DIGITAL_PDM_WD_CTL1: + case WCD938X_DIGITAL_PDM_WD_CTL2: + case WCD938X_DIGITAL_INTR_MODE: + case WCD938X_DIGITAL_INTR_MASK_0: + case WCD938X_DIGITAL_INTR_MASK_1: + case WCD938X_DIGITAL_INTR_MASK_2: + case WCD938X_DIGITAL_INTR_CLEAR_0: + case WCD938X_DIGITAL_INTR_CLEAR_1: + case WCD938X_DIGITAL_INTR_CLEAR_2: + case WCD938X_DIGITAL_INTR_LEVEL_0: + case WCD938X_DIGITAL_INTR_LEVEL_1: + case WCD938X_DIGITAL_INTR_LEVEL_2: + case WCD938X_DIGITAL_INTR_SET_0: + case WCD938X_DIGITAL_INTR_SET_1: + case WCD938X_DIGITAL_INTR_SET_2: + case WCD938X_DIGITAL_INTR_TEST_0: + case WCD938X_DIGITAL_INTR_TEST_1: + case WCD938X_DIGITAL_INTR_TEST_2: + case WCD938X_DIGITAL_TX_MODE_DBG_EN: + case WCD938X_DIGITAL_TX_MODE_DBG_0_1: + case WCD938X_DIGITAL_TX_MODE_DBG_2_3: + case WCD938X_DIGITAL_LB_IN_SEL_CTL: + case WCD938X_DIGITAL_LOOP_BACK_MODE: + case WCD938X_DIGITAL_SWR_DAC_TEST: + case WCD938X_DIGITAL_SWR_HM_TEST_RX_0: + case WCD938X_DIGITAL_SWR_HM_TEST_TX_0: + case WCD938X_DIGITAL_SWR_HM_TEST_RX_1: + case WCD938X_DIGITAL_SWR_HM_TEST_TX_1: + case WCD938X_DIGITAL_SWR_HM_TEST_TX_2: + case WCD938X_DIGITAL_PAD_CTL_SWR_0: + case WCD938X_DIGITAL_PAD_CTL_SWR_1: + case WCD938X_DIGITAL_I2C_CTL: + case WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE: + case WCD938X_DIGITAL_EFUSE_TEST_CTL_0: + case WCD938X_DIGITAL_EFUSE_TEST_CTL_1: + case WCD938X_DIGITAL_PAD_CTL_PDM_RX0: + case WCD938X_DIGITAL_PAD_CTL_PDM_RX1: + case WCD938X_DIGITAL_PAD_CTL_PDM_TX0: + case WCD938X_DIGITAL_PAD_CTL_PDM_TX1: + case WCD938X_DIGITAL_PAD_CTL_PDM_TX2: + case WCD938X_DIGITAL_PAD_INP_DIS_0: + case WCD938X_DIGITAL_PAD_INP_DIS_1: + case WCD938X_DIGITAL_DRIVE_STRENGTH_0: + case WCD938X_DIGITAL_DRIVE_STRENGTH_1: + case WCD938X_DIGITAL_DRIVE_STRENGTH_2: + case WCD938X_DIGITAL_RX_DATA_EDGE_CTL: + case WCD938X_DIGITAL_TX_DATA_EDGE_CTL: + case WCD938X_DIGITAL_GPIO_MODE: + case WCD938X_DIGITAL_PIN_CTL_OE: + case WCD938X_DIGITAL_PIN_CTL_DATA_0: + case WCD938X_DIGITAL_PIN_CTL_DATA_1: + case WCD938X_DIGITAL_DIG_DEBUG_CTL: + case WCD938X_DIGITAL_DIG_DEBUG_EN: + case WCD938X_DIGITAL_ANA_CSR_DBG_ADD: + case WCD938X_DIGITAL_ANA_CSR_DBG_CTL: + case WCD938X_DIGITAL_SSP_DBG: + case WCD938X_DIGITAL_SPARE_0: + case WCD938X_DIGITAL_SPARE_1: + case WCD938X_DIGITAL_SPARE_2: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_0: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_1: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_2: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_3: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_4: + case WCD938X_DIGITAL_DEM_BYPASS_DATA0: + case WCD938X_DIGITAL_DEM_BYPASS_DATA1: + case WCD938X_DIGITAL_DEM_BYPASS_DATA2: + case WCD938X_DIGITAL_DEM_BYPASS_DATA3: + return true; + } + + return false; +} + +static bool wcd938x_readonly_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD938X_ANA_MBHC_RESULT_1: + case WCD938X_ANA_MBHC_RESULT_2: + case WCD938X_ANA_MBHC_RESULT_3: + case WCD938X_MBHC_MOISTURE_DET_FSM_STATUS: + case WCD938X_TX_1_2_SAR2_ERR: + case WCD938X_TX_1_2_SAR1_ERR: + case WCD938X_TX_3_4_SAR4_ERR: + case WCD938X_TX_3_4_SAR3_ERR: + case WCD938X_HPH_L_STATUS: + case WCD938X_HPH_R_STATUS: + case WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS: + case WCD938X_EAR_STATUS_REG_1: + case WCD938X_EAR_STATUS_REG_2: + case WCD938X_MBHC_NEW_FSM_STATUS: + case WCD938X_MBHC_NEW_ADC_RESULT: + case WCD938X_DIE_CRACK_DIE_CRK_DET_OUT: + case WCD938X_AUX_INT_STATUS_REG: + case WCD938X_LDORXTX_INT_STATUS: + case WCD938X_DIGITAL_CHIP_ID0: + case WCD938X_DIGITAL_CHIP_ID1: + case WCD938X_DIGITAL_CHIP_ID2: + case WCD938X_DIGITAL_CHIP_ID3: + case WCD938X_DIGITAL_INTR_STATUS_0: + case WCD938X_DIGITAL_INTR_STATUS_1: + case WCD938X_DIGITAL_INTR_STATUS_2: + case WCD938X_DIGITAL_SWR_HM_TEST_0: + case WCD938X_DIGITAL_SWR_HM_TEST_1: + case WCD938X_DIGITAL_EFUSE_T_DATA_0: + case WCD938X_DIGITAL_EFUSE_T_DATA_1: + case WCD938X_DIGITAL_PIN_STATUS_0: + case WCD938X_DIGITAL_PIN_STATUS_1: + case WCD938X_DIGITAL_MODE_STATUS_0: + case WCD938X_DIGITAL_MODE_STATUS_1: + case WCD938X_DIGITAL_EFUSE_REG_0: + case WCD938X_DIGITAL_EFUSE_REG_1: + case WCD938X_DIGITAL_EFUSE_REG_2: + case WCD938X_DIGITAL_EFUSE_REG_3: + case WCD938X_DIGITAL_EFUSE_REG_4: + case WCD938X_DIGITAL_EFUSE_REG_5: + case WCD938X_DIGITAL_EFUSE_REG_6: + case WCD938X_DIGITAL_EFUSE_REG_7: + case WCD938X_DIGITAL_EFUSE_REG_8: + case WCD938X_DIGITAL_EFUSE_REG_9: + case WCD938X_DIGITAL_EFUSE_REG_10: + case WCD938X_DIGITAL_EFUSE_REG_11: + case WCD938X_DIGITAL_EFUSE_REG_12: + case WCD938X_DIGITAL_EFUSE_REG_13: + case WCD938X_DIGITAL_EFUSE_REG_14: + case WCD938X_DIGITAL_EFUSE_REG_15: + case WCD938X_DIGITAL_EFUSE_REG_16: + case WCD938X_DIGITAL_EFUSE_REG_17: + case WCD938X_DIGITAL_EFUSE_REG_18: + case WCD938X_DIGITAL_EFUSE_REG_19: + case WCD938X_DIGITAL_EFUSE_REG_20: + case WCD938X_DIGITAL_EFUSE_REG_21: + case WCD938X_DIGITAL_EFUSE_REG_22: + case WCD938X_DIGITAL_EFUSE_REG_23: + case WCD938X_DIGITAL_EFUSE_REG_24: + case WCD938X_DIGITAL_EFUSE_REG_25: + case WCD938X_DIGITAL_EFUSE_REG_26: + case WCD938X_DIGITAL_EFUSE_REG_27: + case WCD938X_DIGITAL_EFUSE_REG_28: + case WCD938X_DIGITAL_EFUSE_REG_29: + case WCD938X_DIGITAL_EFUSE_REG_30: + case WCD938X_DIGITAL_EFUSE_REG_31: + return true; + } + return false; +} + +static bool wcd938x_readable_register(struct device *dev, unsigned int reg) +{ + bool ret; + + ret = wcd938x_readonly_register(dev, reg); + if (!ret) + return wcd938x_rdwr_register(dev, reg); + + return ret; +} + +static bool wcd938x_writeable_register(struct device *dev, unsigned int reg) +{ + return wcd938x_rdwr_register(dev, reg); +} + +static bool wcd938x_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg <= WCD938X_BASE_ADDRESS) + return false; + + if (reg == WCD938X_DIGITAL_SWR_TX_CLK_RATE) + return true; + + if (wcd938x_readonly_register(dev, reg)) + return true; + + return false; +} + +static struct regmap_config wcd938x_regmap_config = { + .name = "wcd938x_csr", + .reg_bits = 32, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd938x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd938x_defaults), + .max_register = WCD938X_MAX_REGISTER, + .readable_reg = wcd938x_readable_register, + .writeable_reg = wcd938x_writeable_register, + .volatile_reg = wcd938x_volatile_register, + .can_multi_write = true, +}; + +static const struct regmap_irq wcd938x_irqs[WCD938X_NUM_IRQS] = { + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_OCP_INT, 0, 0x20), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_CNP_INT, 0, 0x40), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_OCP_INT, 0, 0x80), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_CNP_INT, 1, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_EAR_CNP_INT, 1, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_EAR_SCD_INT, 1, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_CNP_INT, 1, 0x08), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_SCD_INT, 1, 0x10), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_PDM_WD_INT, 1, 0x80), + REGMAP_IRQ_REG(WCD938X_IRQ_LDORT_SCD_INT, 2, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), +}; + +static struct regmap_irq_chip wcd938x_regmap_irq_chip = { + .name = "wcd938x", + .irqs = wcd938x_irqs, + .num_irqs = ARRAY_SIZE(wcd938x_irqs), + .num_regs = 3, + .status_base = WCD938X_DIGITAL_INTR_STATUS_0, + .mask_base = WCD938X_DIGITAL_INTR_MASK_0, + .type_base = WCD938X_DIGITAL_INTR_LEVEL_0, + .ack_base = WCD938X_DIGITAL_INTR_CLEAR_0, + .use_ack = 1, + .runtime_pm = true, + .irq_drv_data = NULL, +}; + +static int wcd938x_get_clk_rate(int mode) +{ + int rate; + + switch (mode) { + case ADC_MODE_ULP2: + rate = SWR_CLK_RATE_0P6MHZ; + break; + case ADC_MODE_ULP1: + rate = SWR_CLK_RATE_1P2MHZ; + break; + case ADC_MODE_LP: + rate = SWR_CLK_RATE_4P8MHZ; + break; + case ADC_MODE_NORMAL: + case ADC_MODE_LO_HIF: + case ADC_MODE_HIFI: + case ADC_MODE_INVALID: + default: + rate = SWR_CLK_RATE_9P6MHZ; + break; + } + + return rate; +} + +static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component, int rate, int bank) +{ + u8 mask = (bank ? 0xF0 : 0x0F); + u8 val = 0; + + switch (rate) { + case SWR_CLK_RATE_0P6MHZ: + val = (bank ? 0x60 : 0x06); + break; + case SWR_CLK_RATE_1P2MHZ: + val = (bank ? 0x50 : 0x05); + break; + case SWR_CLK_RATE_2P4MHZ: + val = (bank ? 0x30 : 0x03); + break; + case SWR_CLK_RATE_4P8MHZ: + val = (bank ? 0x10 : 0x01); + break; + case SWR_CLK_RATE_9P6MHZ: + default: + val = 0x00; + break; + } + snd_soc_component_update_bits(component, WCD938X_DIGITAL_SWR_TX_CLK_RATE, + mask, val); + + return 0; +} + +static int wcd938x_io_init(struct wcd938x_priv *wcd938x) +{ + struct regmap *rm = wcd938x->regmap; + + regmap_update_bits(rm, WCD938X_SLEEP_CTL, 0x0E, 0x0E); + regmap_update_bits(rm, WCD938X_SLEEP_CTL, 0x80, 0x80); + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + regmap_update_bits(rm, WCD938X_SLEEP_CTL, 0x40, 0x40); + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + regmap_update_bits(rm, WCD938X_LDORXTX_CONFIG, 0x10, 0x00); + regmap_update_bits(rm, WCD938X_BIAS_VBG_FINE_ADJ, + 0xF0, 0x80); + regmap_update_bits(rm, WCD938X_ANA_BIAS, 0x80, 0x80); + regmap_update_bits(rm, WCD938X_ANA_BIAS, 0x40, 0x40); + /* 10 msec delay as per HW requirement */ + usleep_range(10000, 10010); + + regmap_update_bits(rm, WCD938X_ANA_BIAS, 0x40, 0x00); + regmap_update_bits(rm, WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x00); + regmap_update_bits(rm, WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, + 0x1F, 0x15); + regmap_update_bits(rm, WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, + 0x1F, 0x15); + regmap_update_bits(rm, WCD938X_HPH_REFBUFF_UHQA_CTL, + 0xC0, 0x80); + regmap_update_bits(rm, WCD938X_DIGITAL_CDC_DMIC_CTL, + 0x02, 0x02); + + regmap_update_bits(rm, WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, + 0xFF, 0x14); + regmap_update_bits(rm, WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, + 0x1F, 0x08); + + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0xFF, 0x55); + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0xFF, 0x44); + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0xFF, 0x11); + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0xFF, 0x00); + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0xFF, 0x00); + + /* Set Noise Filter Resistor value */ + regmap_update_bits(rm, WCD938X_MICB1_TEST_CTL_1, 0xE0, 0xE0); + regmap_update_bits(rm, WCD938X_MICB2_TEST_CTL_1, 0xE0, 0xE0); + regmap_update_bits(rm, WCD938X_MICB3_TEST_CTL_1, 0xE0, 0xE0); + regmap_update_bits(rm, WCD938X_MICB4_TEST_CTL_1, 0xE0, 0xE0); + + regmap_update_bits(rm, WCD938X_TX_3_4_TEST_BLK_EN2, 0x01, 0x00); + regmap_update_bits(rm, WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); + + return 0; + +} + +static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info, + struct sdw_port_config *port_config, + u32 mstr_port_num, + u8 enable) +{ + u8 ch_mask, port_num; + + port_num = ch_info->port_num; + ch_mask = ch_info->ch_mask; + + port_config->num = port_num; + + if (enable) + port_config->ch_mask |= ch_mask; + else + port_config->ch_mask &= ~ch_mask; + + return 0; +} + +static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enable) +{ + u8 port_num, mstr_port_num; + + port_num = wcd->ch_info[ch_id].port_num; + mstr_port_num = wcd->port_map[port_num - 1]; + + return wcd938x_sdw_connect_port(&wcd->ch_info[ch_id], + &wcd->port_config[port_num], + mstr_port_num, + enable); +} + +static int wcd938x_codec_enable_rxclk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_RX_BIAS_EN_MASK, 1); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX0_CTL, + WCD938X_DEM_DITHER_ENABLE_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX1_CTL, + WCD938X_DEM_DITHER_ENABLE_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX2_CTL, + WCD938X_DEM_DITHER_ENABLE_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, WCD938X_AUX_AUXPA, + WCD938X_AUXPA_CLK_EN_MASK, 1); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_VNEG_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_VPOS_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_RX_BIAS_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_CLK_EN_MASK, 0); + break; + } + return 0; +} + +static int wcd938x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD0_CLK_EN_MASK, 0x01); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD938X_HPHL_RX_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_HPH_RDAC_CLK_CTL1, + WCD938X_CHOP_CLK_EN_MASK, 0); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write_field(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, + WCD938X_HPH_RES_DIV_MASK, 0x02); + if (wcd938x->comp1_enable) { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHL_COMP_EN_MASK, 1); + /* 5msec compander delay as per HW requirement */ + if (!wcd938x->comp2_enable || (snd_soc_component_read(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x01)) + usleep_range(5000, 5010); + snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, + WCD938X_AUTOCHOP_TIMER_EN, 0); + } else { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHL_COMP_EN_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_HPH_L_EN, + WCD938X_GAIN_SRC_SEL_MASK, + WCD938X_GAIN_SRC_SEL_REGISTER); + + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD938X_HPH_RES_DIV_MASK, 0x1); + break; + } + + return 0; +} + +static int wcd938x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD1_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD938X_HPHR_RX_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_HPH_RDAC_CLK_CTL1, + WCD938X_CHOP_CLK_EN_MASK, 0); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write_field(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD938X_HPH_RES_DIV_MASK, 0x02); + if (wcd938x->comp2_enable) { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHR_COMP_EN_MASK, 1); + /* 5msec compander delay as per HW requirement */ + if (!wcd938x->comp1_enable || + (snd_soc_component_read(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x02)) + usleep_range(5000, 5010); + snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, + WCD938X_AUTOCHOP_TIMER_EN, 0); + } else { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHR_COMP_EN_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_HPH_R_EN, + WCD938X_GAIN_SRC_SEL_MASK, + WCD938X_GAIN_SRC_SEL_REGISTER); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD938X_HPH_RES_DIV_MASK, 0x01); + break; + } + + return 0; +} + +static int wcd938x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x->ear_rx_path = + snd_soc_component_read( + component, WCD938X_DIGITAL_CDC_EAR_PATH_CTL); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { + snd_soc_component_write_field(component, + WCD938X_EAR_EAR_DAC_CON, + WCD938X_DAC_SAMPLE_EDGE_SEL_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, + WCD938X_AUX_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD2_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_GAIN_OVRD_REG_MASK, 1); + } else { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD938X_HPHL_RX_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD0_CLK_EN_MASK, 1); + if (wcd938x->comp1_enable) + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHL_COMP_EN_MASK, 1); + } + /* 5 msec delay as per HW requirement */ + usleep_range(5000, 5010); + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, + WCD938X_EN_CUR_DET_MASK, 0); + wcd938x->flyback_cur_det_disable++; + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + wcd938x->hph_mode); + break; + case SND_SOC_DAPM_POST_PMD: + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, + WCD938X_AUX_EN_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD2_CLK_EN_MASK, 0); + } else { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD938X_HPHL_RX_EN_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD0_CLK_EN_MASK, 0); + if (wcd938x->comp1_enable) + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHL_COMP_EN_MASK, 0); + } + snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_GAIN_OVRD_REG_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_EAR_EAR_DAC_CON, + WCD938X_DAC_SAMPLE_EDGE_SEL_MASK, 1); + break; + } + return 0; + +} + +static int wcd938x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_DIV4_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD2_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, + WCD938X_AUX_EN_MASK, 1); + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, + WCD938X_EN_CUR_DET_MASK, 0); + wcd938x->flyback_cur_det_disable++; + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_AUX, + wcd938x->hph_mode); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_DIV4_CLK_EN_MASK, 0); + break; + } + return ret; + +} + +static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd938x->ldoh) + snd_soc_component_write_field(component, WCD938X_LDOH_MODE, + WCD938X_LDOH_EN_MASK, 1); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, hph_mode); + wcd_clsh_set_hph_mode(wcd938x->clsh_info, CLS_H_HIFI); + + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) { + snd_soc_component_write_field(component, + WCD938X_HPH_REFBUFF_LP_CTL, + WCD938X_PREREF_FLIT_BYPASS_MASK, 1); + } + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHR_REF_EN_MASK, 1); + wcd_clsh_set_hph_mode(wcd938x->clsh_info, hph_mode); + /* 100 usec delay as per HW requirement */ + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_PDM_WD_CTL1, + WCD938X_PDM_WD_EN_MASK, 0x3); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + snd_soc_component_write_field(component, + WCD938X_HPH_REFBUFF_LP_CTL, + WCD938X_PREREF_FLIT_BYPASS_MASK, 0); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, + WCD938X_AUTOCHOP_TIMER_EN, 1); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_REGULATOR_MODE_MASK, + WCD938X_REGULATOR_MODE_CLASS_AB); + enable_irq(wcd938x->hphr_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd938x->hphr_pdm_wd_int); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHR_EN_MASK, 0); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHR_REF_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL1, + WCD938X_PDM_WD_EN_MASK, 0); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, hph_mode); + if (wcd938x->ldoh) + snd_soc_component_write_field(component, WCD938X_LDOH_MODE, + WCD938X_LDOH_EN_MASK, 0); + break; + } + + return 0; +} + +static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd938x->ldoh) + snd_soc_component_write_field(component, WCD938X_LDOH_MODE, + WCD938X_LDOH_EN_MASK, 1); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, hph_mode); + wcd_clsh_set_hph_mode(wcd938x->clsh_info, CLS_H_HIFI); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) { + snd_soc_component_write_field(component, + WCD938X_HPH_REFBUFF_LP_CTL, + WCD938X_PREREF_FLIT_BYPASS_MASK, 1); + } + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHL_REF_EN_MASK, 1); + wcd_clsh_set_hph_mode(wcd938x->clsh_info, hph_mode); + /* 100 usec delay as per HW requirement */ + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_PDM_WD_CTL0, + WCD938X_PDM_WD_EN_MASK, 0x3); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + snd_soc_component_write_field(component, + WCD938X_HPH_REFBUFF_LP_CTL, + WCD938X_PREREF_FLIT_BYPASS_MASK, 0); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + + snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, + WCD938X_AUTOCHOP_TIMER_EN, 1); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_REGULATOR_MODE_MASK, + WCD938X_REGULATOR_MODE_CLASS_AB); + enable_irq(wcd938x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd938x->hphl_pdm_wd_int); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd938x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHL_EN_MASK, 0); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp1_enable) + usleep_range(21000, 21100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHL_REF_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL0, + WCD938X_PDM_WD_EN_MASK, 0); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, hph_mode); + if (wcd938x->ldoh) + snd_soc_component_write_field(component, WCD938X_LDOH_MODE, + WCD938X_LDOH_EN_MASK, 0); + break; + } + + return 0; +} + +static int wcd938x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, + WCD938X_AUX_PDM_WD_EN_MASK, 1); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_REGULATOR_MODE_MASK, + WCD938X_REGULATOR_MODE_CLASS_AB); + enable_irq(wcd938x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd938x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_POST_PMD: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, + WCD938X_AUX_PDM_WD_EN_MASK, 0); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_AUX, + hph_mode); + + wcd938x->flyback_cur_det_disable--; + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, + WCD938X_EN_CUR_DET_MASK, 1); + break; + } + return ret; +} + +static int wcd938x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* + * Enable watchdog interrupt for HPHL or AUX + * depending on mux value + */ + wcd938x->ear_rx_path = snd_soc_component_read(component, + WCD938X_DIGITAL_CDC_EAR_PATH_CTL); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, + WCD938X_AUX_PDM_WD_EN_MASK, 1); + else + snd_soc_component_write_field(component, + WCD938X_DIGITAL_PDM_WD_CTL0, + WCD938X_PDM_WD_EN_MASK, 0x3); + if (!wcd938x->comp1_enable) + snd_soc_component_write_field(component, + WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_GAIN_OVRD_REG_MASK, 1); + + break; + case SND_SOC_DAPM_POST_PMU: + /* 6 msec delay as per HW requirement */ + usleep_range(6000, 6010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_REGULATOR_MODE_MASK, + WCD938X_REGULATOR_MODE_CLASS_AB); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + enable_irq(wcd938x->aux_pdm_wd_int); + else + enable_irq(wcd938x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + disable_irq_nosync(wcd938x->aux_pdm_wd_int); + else + disable_irq_nosync(wcd938x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_POST_PMD: + if (!wcd938x->comp1_enable) + snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_GAIN_OVRD_REG_MASK, 0); + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7010); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, + WCD938X_AUX_PDM_WD_EN_MASK, 0); + else + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL0, + WCD938X_PDM_WD_EN_MASK, 0); + + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, hph_mode); + + wcd938x->flyback_cur_det_disable--; + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, + WCD938X_EN_CUR_DET_MASK, 1); + break; + } + + return 0; +} + +static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u16 dmic_clk_reg, dmic_clk_en_reg; + u8 dmic_sel_mask, dmic_clk_mask; + + switch (w->shift) { + case 0: + case 1: + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC1_CTL; + dmic_clk_mask = WCD938X_DMIC1_RATE_MASK; + dmic_sel_mask = WCD938X_AMIC1_IN_SEL_MASK; + break; + case 2: + case 3: + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC2_CTL; + dmic_clk_mask = WCD938X_DMIC2_RATE_MASK; + dmic_sel_mask = WCD938X_AMIC3_IN_SEL_MASK; + break; + case 4: + case 5: + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC3_CTL; + dmic_clk_mask = WCD938X_DMIC3_RATE_MASK; + dmic_sel_mask = WCD938X_AMIC4_IN_SEL_MASK; + break; + case 6: + case 7: + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC4_CTL; + dmic_clk_mask = WCD938X_DMIC4_RATE_MASK; + dmic_sel_mask = WCD938X_AMIC5_IN_SEL_MASK; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AMIC_CTL, + dmic_sel_mask, + WCD938X_AMIC1_IN_SEL_DMIC); + /* 250us sleep as per HW requirement */ + usleep_range(250, 260); + /* Setting DMIC clock rate to 2.4MHz */ + snd_soc_component_write_field(component, dmic_clk_reg, + dmic_clk_mask, + WCD938X_DMIC4_RATE_2P4MHZ); + snd_soc_component_write_field(component, dmic_clk_en_reg, + WCD938X_DMIC_CLK_EN_MASK, 1); + /* enable clock scaling */ + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_DMIC_CTL, + WCD938X_DMIC_CLK_SCALING_EN_MASK, 0x3); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AMIC_CTL, + dmic_sel_mask, WCD938X_AMIC1_IN_SEL_AMIC); + snd_soc_component_write_field(component, dmic_clk_en_reg, + WCD938X_DMIC_CLK_EN_MASK, 0); + break; + } + return 0; +} + +static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int bank; + int rate; + + bank = (wcd938x_swr_get_current_bank(wcd938x->sdw_priv[AIF1_CAP]->sdev)) ? 0 : 1; + bank = bank ? 0 : 1; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + int i = 0, mode = 0; + + if (test_bit(WCD_ADC1, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]]; + + if (mode != 0) { + for (i = 0; i < ADC_MODE_ULP2; i++) { + if (mode & (1 << i)) { + i++; + break; + } + } + } + rate = wcd938x_get_clk_rate(i); + wcd938x_set_swr_clk_rate(component, rate, bank); + /* Copy clk settings to active bank */ + wcd938x_set_swr_clk_rate(component, rate, !bank); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + rate = wcd938x_get_clk_rate(ADC_MODE_INVALID); + wcd938x_set_swr_clk_rate(component, rate, !bank); + wcd938x_set_swr_clk_rate(component, rate, bank); + } + break; + } + + return 0; +} + +static int wcd938x_get_adc_mode(int val) +{ + int ret = 0; + + switch (val) { + case ADC_MODE_INVALID: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_HIFI: + ret = ADC_MODE_VAL_HIFI; + break; + case ADC_MODE_LO_HIF: + ret = ADC_MODE_VAL_LO_HIF; + break; + case ADC_MODE_NORMAL: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_LP: + ret = ADC_MODE_VAL_LP; + break; + case ADC_MODE_ULP1: + ret = ADC_MODE_VAL_ULP1; + break; + case ADC_MODE_ULP2: + ret = ADC_MODE_VAL_ULP2; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_DIV2_CLK_EN_MASK, 1); + set_bit(w->shift, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_CLK_EN_MASK, 0); + clear_bit(w->shift, &wcd938x->status_mask); + break; + } + + return 0; +} + +static void wcd938x_tx_channel_config(struct snd_soc_component *component, + int channel, int mode) +{ + int reg, mask; + + switch (channel) { + case 0: + reg = WCD938X_ANA_TX_CH2; + mask = WCD938X_HPF1_INIT_MASK; + break; + case 1: + reg = WCD938X_ANA_TX_CH2; + mask = WCD938X_HPF2_INIT_MASK; + break; + case 2: + reg = WCD938X_ANA_TX_CH4; + mask = WCD938X_HPF3_INIT_MASK; + break; + case 3: + reg = WCD938X_ANA_TX_CH4; + mask = WCD938X_HPF4_INIT_MASK; + break; + default: + return; + } + + snd_soc_component_write_field(component, reg, mask, mode); +} + +static int wcd938x_adc_enable_req(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_REQ_CTL, + WCD938X_FS_RATE_4P8_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_REQ_CTL, + WCD938X_NO_NOTCH_MASK, 0); + wcd938x_tx_channel_config(component, w->shift, 1); + mode = wcd938x_get_adc_mode(wcd938x->tx_mode[w->shift]); + if (mode < 0) { + dev_info(component->dev, "Invalid ADC mode\n"); + return -EINVAL; + } + switch (w->shift) { + case 0: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD938X_TXD0_MODE_MASK, mode); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD0_CLK_EN_MASK, 1); + break; + case 1: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD938X_TXD1_MODE_MASK, mode); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD1_CLK_EN_MASK, 1); + break; + case 2: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD938X_TXD2_MODE_MASK, mode); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD2_CLK_EN_MASK, 1); + break; + case 3: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD938X_TXD3_MODE_MASK, mode); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD3_CLK_EN_MASK, 1); + break; + default: + break; + } + + wcd938x_tx_channel_config(component, w->shift, 0); + break; + case SND_SOC_DAPM_POST_PMD: + switch (w->shift) { + case 0: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD938X_TXD0_MODE_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD0_CLK_EN_MASK, 0); + break; + case 1: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD938X_TXD1_MODE_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD1_CLK_EN_MASK, 0); + break; + case 2: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD938X_TXD2_MODE_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD2_CLK_EN_MASK, 0); + break; + case 3: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD938X_TXD3_MODE_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD3_CLK_EN_MASK, 0); + break; + default: + break; + } + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_DIV2_CLK_EN_MASK, 0); + break; + } + + return 0; +} + +static int wcd938x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int micb_index = micb_num - 1; + u16 micb_reg; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD938X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD938X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD938X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD938X_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd938x->pullup_ref[micb_index]++; + if ((wcd938x->pullup_ref[micb_index] == 1) && + (wcd938x->micb_ref[micb_index] == 0)) + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, + WCD938X_MICB_PULL_UP); + break; + case MICB_PULLUP_DISABLE: + if (wcd938x->pullup_ref[micb_index] > 0) + wcd938x->pullup_ref[micb_index]--; + + if ((wcd938x->pullup_ref[micb_index] == 0) && + (wcd938x->micb_ref[micb_index] == 0)) + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, 0); + break; + case MICB_ENABLE: + wcd938x->micb_ref[micb_index]++; + if (wcd938x->micb_ref[micb_index] == 1) { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TX_CLK_EN_MASK, 0xF); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_DIV2_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, + WCD938X_TX_SC_CLK_EN_MASK, 1); + + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, + WCD938X_MICB_ENABLE); + } + + break; + case MICB_DISABLE: + if (wcd938x->micb_ref[micb_index] > 0) + wcd938x->micb_ref[micb_index]--; + + if ((wcd938x->micb_ref[micb_index] == 0) && + (wcd938x->pullup_ref[micb_index] > 0)) + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, + WCD938X_MICB_PULL_UP); + else if ((wcd938x->micb_ref[micb_index] == 0) && + (wcd938x->pullup_ref[micb_index] == 0)) { + + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, 0); + } + break; + } + + return 0; +} + +static int wcd938x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num = w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_micbias_control(component, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_micbias_control(component, micb_num, MICB_DISABLE, true); + break; + } + + return 0; +} + +static int wcd938x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num = w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_micbias_control(component, micb_num, + MICB_PULLUP_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_micbias_control(component, micb_num, + MICB_PULLUP_DISABLE, true); + break; + } + + return 0; +} + +static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int path = e->shift_l; + + ucontrol->value.integer.value[0] = wcd938x->tx_mode[path]; + + return 0; +} + +static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int path = e->shift_l; + + wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0]; + + return 1; +} + +static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd938x->hph_mode; + + return 0; +} + +static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd938x->hph_mode = ucontrol->value.enumerated.item[0]; + + return 1; +} + +static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (wcd938x->comp1_enable) { + dev_err(component->dev, "Can not set EAR PA Gain, compander1 is enabled\n"); + return -EINVAL; + } + + snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_EAR_GAIN_MASK, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int wcd938x_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc; + bool hphr; + + mc = (struct soc_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + + if (hphr) + ucontrol->value.integer.value[0] = wcd938x->comp2_enable; + else + ucontrol->value.integer.value[0] = wcd938x->comp1_enable; + + return 0; +} + +static int wcd938x_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct wcd938x_sdw_priv *wcd; + int value = ucontrol->value.integer.value[0]; + struct soc_mixer_control *mc; + bool hphr; + + mc = (struct soc_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + + wcd = wcd938x->sdw_priv[AIF1_PB]; + + if (hphr) + wcd938x->comp2_enable = value; + else + wcd938x->comp1_enable = value; + + if (value) + wcd938x_connect_port(wcd, mc->reg, true); + else + wcd938x_connect_port(wcd, mc->reg, false); + + return 0; +} + +static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd938x->ldoh; + + return 0; +} + +static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd938x->ldoh = ucontrol->value.integer.value[0]; + + return 1; +} + +static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd938x->bcs_dis; + + return 0; +} + +static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd938x->bcs_dis = ucontrol->value.integer.value[0]; + + return 1; +} + +static const char * const tx_mode_mux_text_wcd9380[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", +}; + +static const char * const tx_mode_mux_text[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", + "ADC_ULP1", "ADC_ULP2", +}; + +static const char * const rx_hph_mode_mux_text_wcd9380[] = { + "CLS_H_INVALID", "CLS_H_INVALID_1", "CLS_H_LP", "CLS_AB", + "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_H_INVALID_2", "CLS_AB_LP", + "CLS_AB_LOHIFI", +}; + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", + "CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI", +}; + +static const char * const adc2_mux_text[] = { + "INP2", "INP3" +}; + +static const char * const adc3_mux_text[] = { + "INP4", "INP6" +}; + +static const char * const adc4_mux_text[] = { + "INP5", "INP7" +}; + +static const char * const rdac3_mux_text[] = { + "RX1", "RX3" +}; + +static const char * const hdr12_mux_text[] = { + "NO_HDR12", "HDR12" +}; + +static const char * const hdr34_mux_text[] = { + "NO_HDR34", "HDR34" +}; + +static const struct soc_enum tx0_mode_enum_wcd9380 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380); + +static const struct soc_enum tx1_mode_enum_wcd9380 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380); + +static const struct soc_enum tx2_mode_enum_wcd9380 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380); + +static const struct soc_enum tx3_mode_enum_wcd9380 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380); + +static const struct soc_enum tx0_mode_enum_wcd9385 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const struct soc_enum tx1_mode_enum_wcd9385 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const struct soc_enum tx2_mode_enum_wcd9385 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const struct soc_enum tx3_mode_enum_wcd9385 = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text); + +static const struct soc_enum rx_hph_mode_mux_enum_wcd9380 = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9380), + rx_hph_mode_mux_text_wcd9380); + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + +static const struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 7, + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +static const struct soc_enum adc3_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 6, + ARRAY_SIZE(adc3_mux_text), adc3_mux_text); + +static const struct soc_enum adc4_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 5, + ARRAY_SIZE(adc4_mux_text), adc4_mux_text); + +static const struct soc_enum hdr12_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 4, + ARRAY_SIZE(hdr12_mux_text), hdr12_mux_text); + +static const struct soc_enum hdr34_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 3, + ARRAY_SIZE(hdr34_mux_text), hdr34_mux_text); + +static const struct soc_enum rdac3_enum = + SOC_ENUM_SINGLE(WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0, + ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); + +static const struct snd_kcontrol_new adc1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic6_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic7_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic8_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new ear_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new aux_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphl_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphr_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new tx_adc2_mux = + SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); + +static const struct snd_kcontrol_new tx_adc3_mux = + SOC_DAPM_ENUM("ADC3 MUX Mux", adc3_enum); + +static const struct snd_kcontrol_new tx_adc4_mux = + SOC_DAPM_ENUM("ADC4 MUX Mux", adc4_enum); + +static const struct snd_kcontrol_new tx_hdr12_mux = + SOC_DAPM_ENUM("HDR12 MUX Mux", hdr12_enum); + +static const struct snd_kcontrol_new tx_hdr34_mux = + SOC_DAPM_ENUM("HDR34 MUX Mux", hdr34_enum); + +static const struct snd_kcontrol_new rx_rdac3_mux = + SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); + +static const struct snd_kcontrol_new wcd9380_snd_controls[] = { + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9380, + wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), + SOC_ENUM_EXT("TX0 MODE", tx0_mode_enum_wcd9380, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx1_mode_enum_wcd9380, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx2_mode_enum_wcd9380, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx3_mode_enum_wcd9380, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), +}; + +static const struct snd_kcontrol_new wcd9385_snd_controls[] = { + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), + SOC_ENUM_EXT("TX0 MODE", tx0_mode_enum_wcd9385, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx1_mode_enum_wcd9385, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx2_mode_enum_wcd9385, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx3_mode_enum_wcd9385, + wcd938x_tx_mode_get, wcd938x_tx_mode_put), +}; + +static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(comp); + struct wcd938x_sdw_priv *wcd; + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + int dai_id = mixer->shift; + int portidx = mixer->reg; + + wcd = wcd938x->sdw_priv[dai_id]; + + ucontrol->value.integer.value[0] = wcd->port_enable[portidx]; + + return 0; +} + +static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(comp); + struct wcd938x_sdw_priv *wcd; + struct soc_mixer_control *mixer = + (struct soc_mixer_control *)kcontrol->private_value; + int portidx = mixer->reg; + int dai_id = mixer->shift; + bool enable; + + wcd = wcd938x->sdw_priv[dai_id]; + + if (ucontrol->value.integer.value[0]) + enable = true; + else + enable = false; + + wcd->port_enable[portidx] = enable; + + wcd938x_connect_port(wcd, portidx, enable); + + return 0; + +} + +static const struct snd_kcontrol_new wcd938x_snd_controls[] = { + SOC_SINGLE_EXT("HPHL_COMP Switch", WCD938X_COMP_L, 0, 1, 0, + wcd938x_get_compander, wcd938x_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", WCD938X_COMP_R, 1, 1, 0, + wcd938x_get_compander, wcd938x_set_compander), + SOC_SINGLE_EXT("HPHL Switch", WCD938X_HPH_L, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("HPHR Switch", WCD938X_HPH_R, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("CLSH Switch", WCD938X_CLSH, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("LO Switch", WCD938X_LO, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DSD_L Switch", WCD938X_DSD_L, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DSD_R Switch", WCD938X_DSD_R, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 0x18, 0, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 0x18, 0, line_gain), + WCD938X_EAR_PA_GAIN_TLV("EAR_PA Volume", WCD938X_ANA_EAR_COMPANDER_CTL, + 2, 0x10, 0, ear_pa_gain), + SOC_SINGLE_EXT("ADC1 Switch", WCD938X_ADC1, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("ADC2 Switch", WCD938X_ADC2, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("ADC3 Switch", WCD938X_ADC3, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("ADC4 Switch", WCD938X_ADC4, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC0 Switch", WCD938X_DMIC0, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC1 Switch", WCD938X_DMIC1, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("MBHC Switch", WCD938X_MBHC, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC2 Switch", WCD938X_DMIC2, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC3 Switch", WCD938X_DMIC3, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC4 Switch", WCD938X_DMIC4, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC5 Switch", WCD938X_DMIC5, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC6 Switch", WCD938X_DMIC6, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC7 Switch", WCD938X_DMIC7, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0, + wcd938x_ldoh_get, wcd938x_ldoh_put), + SOC_SINGLE_EXT("ADC2_BCS Disable Switch", SND_SOC_NOPM, 0, 1, 0, + wcd938x_bcs_get, wcd938x_bcs_put), + + SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD938X_ANA_TX_CH2, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD938X_ANA_TX_CH3, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD938X_ANA_TX_CH4, 0, 20, 0, analog_gain), +}; + +static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { + + /*input widgets*/ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + SND_SOC_DAPM_INPUT("AMIC6"), + SND_SOC_DAPM_INPUT("AMIC7"), + SND_SOC_DAPM_MIC("Analog Mic1", NULL), + SND_SOC_DAPM_MIC("Analog Mic2", NULL), + SND_SOC_DAPM_MIC("Analog Mic3", NULL), + SND_SOC_DAPM_MIC("Analog Mic4", NULL), + SND_SOC_DAPM_MIC("Analog Mic5", NULL), + + /*tx widgets*/ + SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 3, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 6, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC8", NULL, SND_SOC_NOPM, 7, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd938x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 1, 0, + NULL, 0, wcd938x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 2, 0, + NULL, 0, wcd938x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4 REQ", SND_SOC_NOPM, 3, 0, NULL, 0, + wcd938x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), + SND_SOC_DAPM_MUX("ADC3 MUX", SND_SOC_NOPM, 0, 0, &tx_adc3_mux), + SND_SOC_DAPM_MUX("ADC4 MUX", SND_SOC_NOPM, 0, 0, &tx_adc4_mux), + SND_SOC_DAPM_MUX("HDR12 MUX", SND_SOC_NOPM, 0, 0, &tx_hdr12_mux), + SND_SOC_DAPM_MUX("HDR34 MUX", SND_SOC_NOPM, 0, 0, &tx_hdr34_mux), + + /*tx mixers*/ + SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, adc1_switch, + ARRAY_SIZE(adc1_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0, adc2_switch, + ARRAY_SIZE(adc2_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 0, 0, adc3_switch, + ARRAY_SIZE(adc3_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, 0, 0, adc4_switch, + ARRAY_SIZE(adc4_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, 0, dmic1_switch, + ARRAY_SIZE(dmic1_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0, 0, dmic2_switch, + ARRAY_SIZE(dmic2_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 0, 0, dmic3_switch, + ARRAY_SIZE(dmic3_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 0, 0, dmic4_switch, + ARRAY_SIZE(dmic4_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 0, 0, dmic5_switch, + ARRAY_SIZE(dmic5_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 0, 0, dmic6_switch, + ARRAY_SIZE(dmic6_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, 0, 0, dmic7_switch, + ARRAY_SIZE(dmic7_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, 0, 0, dmic8_switch, + ARRAY_SIZE(dmic8_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* micbias widgets*/ + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /* micbias pull up widgets*/ + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /*output widgets tx*/ + SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC4_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC7_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC8_OUTPUT"), + + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + SND_SOC_DAPM_INPUT("IN3_AUX"), + + /*rx widgets*/ + SND_SOC_DAPM_PGA_E("EAR PGA", WCD938X_ANA_EAR, 7, 0, NULL, 0, + wcd938x_codec_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AUX PGA", WCD938X_AUX_AUXPA, 7, 0, NULL, 0, + wcd938x_codec_enable_aux_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PGA", WCD938X_ANA_HPH, 7, 0, NULL, 0, + wcd938x_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PGA", WCD938X_ANA_HPH, 6, 0, NULL, 0, + wcd938x_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC4", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_aux_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), + + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXCLK", SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_rxclk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + + /* rx mixer widgets*/ + SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0, + ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)), + SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0, + aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, + hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, + hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), + + /*output widgets rx*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("AUX"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + +}; + +static const struct snd_soc_dapm_route wcd938x_audio_map[] = { + {"ADC1_OUTPUT", NULL, "ADC1_MIXER"}, + {"ADC1_MIXER", "Switch", "ADC1 REQ"}, + {"ADC1 REQ", NULL, "ADC1"}, + {"ADC1", NULL, "AMIC1"}, + + {"ADC2_OUTPUT", NULL, "ADC2_MIXER"}, + {"ADC2_MIXER", "Switch", "ADC2 REQ"}, + {"ADC2 REQ", NULL, "ADC2"}, + {"ADC2", NULL, "HDR12 MUX"}, + {"HDR12 MUX", "NO_HDR12", "ADC2 MUX"}, + {"HDR12 MUX", "HDR12", "AMIC1"}, + {"ADC2 MUX", "INP3", "AMIC3"}, + {"ADC2 MUX", "INP2", "AMIC2"}, + + {"ADC3_OUTPUT", NULL, "ADC3_MIXER"}, + {"ADC3_MIXER", "Switch", "ADC3 REQ"}, + {"ADC3 REQ", NULL, "ADC3"}, + {"ADC3", NULL, "HDR34 MUX"}, + {"HDR34 MUX", "NO_HDR34", "ADC3 MUX"}, + {"HDR34 MUX", "HDR34", "AMIC5"}, + {"ADC3 MUX", "INP4", "AMIC4"}, + {"ADC3 MUX", "INP6", "AMIC6"}, + + {"ADC4_OUTPUT", NULL, "ADC4_MIXER"}, + {"ADC4_MIXER", "Switch", "ADC4 REQ"}, + {"ADC4 REQ", NULL, "ADC4"}, + {"ADC4", NULL, "ADC4 MUX"}, + {"ADC4 MUX", "INP5", "AMIC5"}, + {"ADC4 MUX", "INP7", "AMIC7"}, + + {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_MIXER", "Switch", "DMIC1"}, + + {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_MIXER", "Switch", "DMIC2"}, + + {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"}, + {"DMIC3_MIXER", "Switch", "DMIC3"}, + + {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"}, + {"DMIC4_MIXER", "Switch", "DMIC4"}, + + {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"}, + {"DMIC5_MIXER", "Switch", "DMIC5"}, + + {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"}, + {"DMIC6_MIXER", "Switch", "DMIC6"}, + + {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"}, + {"DMIC7_MIXER", "Switch", "DMIC7"}, + + {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"}, + {"DMIC8_MIXER", "Switch", "DMIC8"}, + + {"IN1_HPHL", NULL, "VDD_BUCK"}, + {"IN1_HPHL", NULL, "CLS_H_PORT"}, + + {"RX1", NULL, "IN1_HPHL"}, + {"RX1", NULL, "RXCLK"}, + {"RDAC1", NULL, "RX1"}, + {"HPHL_RDAC", "Switch", "RDAC1"}, + {"HPHL PGA", NULL, "HPHL_RDAC"}, + {"HPHL", NULL, "HPHL PGA"}, + + {"IN2_HPHR", NULL, "VDD_BUCK"}, + {"IN2_HPHR", NULL, "CLS_H_PORT"}, + {"RX2", NULL, "IN2_HPHR"}, + {"RDAC2", NULL, "RX2"}, + {"RX2", NULL, "RXCLK"}, + {"HPHR_RDAC", "Switch", "RDAC2"}, + {"HPHR PGA", NULL, "HPHR_RDAC"}, + {"HPHR", NULL, "HPHR PGA"}, + + {"IN3_AUX", NULL, "VDD_BUCK"}, + {"IN3_AUX", NULL, "CLS_H_PORT"}, + {"RX3", NULL, "IN3_AUX"}, + {"RDAC4", NULL, "RX3"}, + {"RX3", NULL, "RXCLK"}, + {"AUX_RDAC", "Switch", "RDAC4"}, + {"AUX PGA", NULL, "AUX_RDAC"}, + {"AUX", NULL, "AUX PGA"}, + + {"RDAC3_MUX", "RX3", "RX3"}, + {"RDAC3_MUX", "RX1", "RX1"}, + {"RDAC3", NULL, "RDAC3_MUX"}, + {"EAR_RDAC", "Switch", "RDAC3"}, + {"EAR PGA", NULL, "EAR_RDAC"}, + {"EAR", NULL, "EAR PGA"}, +}; + +static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv) +{ + /* min micbias voltage is 1V and maximum is 2.85V */ + if (micb_mv < 1000 || micb_mv > 2850) + return -EINVAL; + + return (micb_mv - 1000) / 50; +} + +static int wcd938x_set_micbias_data(struct wcd938x_priv *wcd938x) +{ + int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; + + /* set micbias voltage */ + vout_ctl_1 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb1_mv); + vout_ctl_2 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb2_mv); + vout_ctl_3 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb3_mv); + vout_ctl_4 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb4_mv); + if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || vout_ctl_4 < 0) + return -EINVAL; + + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB1, + WCD938X_MICB_VOUT_MASK, vout_ctl_1); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB2, + WCD938X_MICB_VOUT_MASK, vout_ctl_2); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB3, + WCD938X_MICB_VOUT_MASK, vout_ctl_3); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB4, + WCD938X_MICB_VOUT_MASK, vout_ctl_4); + + return 0; +} + +static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data) +{ + return IRQ_HANDLED; +} + +static struct irq_chip wcd_irq_chip = { + .name = "WCD938x", +}; + +static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq); + irq_set_nested_thread(virq, 1); + irq_set_noprobe(virq); + + return 0; +} + +static const struct irq_domain_ops wcd_domain_ops = { + .map = wcd_irq_chip_map, +}; + +static int wcd938x_irq_init(struct wcd938x_priv *wcd, struct device *dev) +{ + + wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); + if (!(wcd->virq)) { + dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); + return -EINVAL; + } + + return devm_regmap_add_irq_chip(dev, wcd->regmap, + irq_create_mapping(wcd->virq, 0), + IRQF_ONESHOT, 0, &wcd938x_regmap_irq_chip, + &wcd->irq_chip); +} + +static int wcd938x_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct device *dev = component->dev; + int ret, i; + + snd_soc_component_init_regmap(component, wcd938x->regmap); + + wcd938x->variant = snd_soc_component_read_field(component, + WCD938X_DIGITAL_EFUSE_REG_0, + WCD938X_ID_MASK); + + wcd938x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD938X); + + wcd938x_io_init(wcd938x); + /* Set all interrupts as edge triggered */ + for (i = 0; i < wcd938x_regmap_irq_chip.num_regs; i++) { + regmap_write(wcd938x->regmap, + (WCD938X_DIGITAL_INTR_LEVEL_0 + i), 0); + } + + ret = wcd938x_irq_init(wcd938x, component->dev); + if (ret) { + dev_err(component->dev, "%s: IRQ init failed: %d\n", + __func__, ret); + return ret; + } + + wcd938x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip, + WCD938X_IRQ_HPHR_PDM_WD_INT); + wcd938x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip, + WCD938X_IRQ_HPHL_PDM_WD_INT); + wcd938x->aux_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip, + WCD938X_IRQ_AUX_PDM_WD_INT); + + /* Request for watchdog interrupt */ + ret = request_threaded_irq(wcd938x->hphr_pdm_wd_int, NULL, wcd938x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPHR PDM WD INT", wcd938x); + if (ret) + dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n", ret); + + ret = request_threaded_irq(wcd938x->hphl_pdm_wd_int, NULL, wcd938x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPHL PDM WD INT", wcd938x); + if (ret) + dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n", ret); + + ret = request_threaded_irq(wcd938x->aux_pdm_wd_int, NULL, wcd938x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "AUX PDM WD INT", wcd938x); + if (ret) + dev_err(dev, "Failed to request Aux WD interrupt (%d)\n", ret); + + /* Disable watchdog interrupt for HPH and AUX */ + disable_irq_nosync(wcd938x->hphr_pdm_wd_int); + disable_irq_nosync(wcd938x->hphl_pdm_wd_int); + disable_irq_nosync(wcd938x->aux_pdm_wd_int); + + switch (wcd938x->variant) { + case WCD9380: + ret = snd_soc_add_component_controls(component, wcd9380_snd_controls, + ARRAY_SIZE(wcd9380_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd938x->variant); + goto err; + } + break; + case WCD9385: + ret = snd_soc_add_component_controls(component, wcd9385_snd_controls, + ARRAY_SIZE(wcd9385_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd938x->variant); + goto err; + } + break; + default: + break; + } +err: + return ret; +} + +static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { + .name = "wcd938x_codec", + .probe = wcd938x_soc_codec_probe, + .controls = wcd938x_snd_controls, + .num_controls = ARRAY_SIZE(wcd938x_snd_controls), + .dapm_widgets = wcd938x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets), + .dapm_routes = wcd938x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map), +}; + +static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd) +{ + struct device_node *np = dev->of_node; + u32 prop_val = 0; + int rc = 0; + + rc = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val); + if (!rc) + wcd->micb1_mv = prop_val/1000; + else + dev_info(dev, "%s: Micbias1 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val); + if (!rc) + wcd->micb2_mv = prop_val/1000; + else + dev_info(dev, "%s: Micbias2 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val); + if (!rc) + wcd->micb3_mv = prop_val/1000; + else + dev_info(dev, "%s: Micbias3 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias4-microvolt", &prop_val); + if (!rc) + wcd->micb4_mv = prop_val/1000; + else + dev_info(dev, "%s: Micbias4 DT property not found\n", __func__); +} + +static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device *dev) +{ + int ret; + + wcd938x->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0); + if (wcd938x->reset_gpio < 0) { + dev_err(dev, "Failed to get reset gpio: err = %d\n", + wcd938x->reset_gpio); + return wcd938x->reset_gpio; + } + + wcd938x->supplies[0].supply = "vdd-rxtx"; + wcd938x->supplies[1].supply = "vdd-io"; + wcd938x->supplies[2].supply = "vdd-buck"; + wcd938x->supplies[3].supply = "vdd-mic-bias"; + + ret = regulator_bulk_get(dev, WCD938X_MAX_SUPPLY, wcd938x->supplies); + if (ret) { + dev_err(dev, "Failed to get supplies: err = %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, wcd938x->supplies); + if (ret) { + dev_err(dev, "Failed to enable supplies: err = %d\n", ret); + return ret; + } + + wcd938x_dt_parse_micbias_info(dev, wcd938x); + + return 0; +} + +static int wcd938x_reset(struct wcd938x_priv *wcd938x) +{ + gpio_direction_output(wcd938x->reset_gpio, 0); + /* 20us sleep required after pulling the reset gpio to LOW */ + usleep_range(20, 30); + gpio_set_value(wcd938x->reset_gpio, 1); + /* 20us sleep required after pulling the reset gpio to HIGH */ + usleep_range(20, 30); + + return 0; +} + +static int wcd938x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dai->dev); + struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; + + return wcd938x_sdw_hw_params(wcd, substream, params, dai); +} + +static int wcd938x_codec_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dai->dev); + struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; + + return wcd938x_sdw_free(wcd, substream, dai); +} + +static int wcd938x_codec_set_sdw_stream(struct snd_soc_dai *dai, + void *stream, int direction) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dai->dev); + struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; + + return wcd938x_sdw_set_sdw_stream(wcd, dai, stream, direction); + +} + +static const struct snd_soc_dai_ops wcd938x_sdw_dai_ops = { + .hw_params = wcd938x_codec_hw_params, + .hw_free = wcd938x_codec_free, + .set_sdw_stream = wcd938x_codec_set_sdw_stream, +}; + +static struct snd_soc_dai_driver wcd938x_dais[] = { + [0] = { + .name = "wcd938x-sdw-rx", + .playback = { + .stream_name = "WCD AIF1 Playback", + .rates = WCD938X_RATES_MASK | WCD938X_FRAC_RATES_MASK, + .formats = WCD938X_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd938x_sdw_dai_ops, + }, + [1] = { + .name = "wcd938x-sdw-tx", + .capture = { + .stream_name = "WCD AIF1 Capture", + .rates = WCD938X_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd938x_sdw_dai_ops, + }, +}; + +static int wcd938x_bind(struct device *dev) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); + int ret; + + ret = component_bind_all(dev, wcd938x); + if (ret) { + dev_err(dev, "%s: Slave bind failed, ret = %d\n", + __func__, ret); + return ret; + } + + wcd938x->rxdev = wcd938x_sdw_device_get(wcd938x->rxnode); + if (!wcd938x->rxdev) { + dev_err(dev, "could not find slave with matching of node\n"); + return -EINVAL; + } + wcd938x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd938x->rxdev); + wcd938x->sdw_priv[AIF1_PB]->wcd938x = wcd938x; + wcd938x->sdw_priv[AIF1_PB]->slave_irq = wcd938x->virq; + + wcd938x->txdev = wcd938x_sdw_device_get(wcd938x->txnode); + if (!wcd938x->txdev) { + dev_err(dev, "could not find txslave with matching of node\n"); + return -EINVAL; + } + wcd938x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd938x->txdev); + wcd938x->sdw_priv[AIF1_CAP]->wcd938x = wcd938x; + wcd938x->sdw_priv[AIF1_CAP]->slave_irq = wcd938x->virq; + wcd938x->tx_sdw_dev = dev_to_sdw_dev(wcd938x->txdev); + if (!wcd938x->tx_sdw_dev) { + dev_err(dev, "could not get txslave with matching of dev\n"); + return -EINVAL; + } + + /* As TX is main CSR reg interface, which should not be suspended first. + * expicilty add the dependency link */ + if (!device_link_add(wcd938x->rxdev, wcd938x->txdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink tx and rx\n"); + return -EINVAL; + } + + if (!device_link_add(dev, wcd938x->txdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink wcd and tx\n"); + return -EINVAL; + } + + if (!device_link_add(dev, wcd938x->rxdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink wcd and rx\n"); + return -EINVAL; + } + + wcd938x->regmap = devm_regmap_init_sdw(wcd938x->tx_sdw_dev, &wcd938x_regmap_config); + if (IS_ERR(wcd938x->regmap)) { + dev_err(dev, "%s: tx csr regmap not found\n", __func__); + return PTR_ERR(wcd938x->regmap); + } + + ret = wcd938x_set_micbias_data(wcd938x); + if (ret < 0) { + dev_err(dev, "%s: bad micbias pdata\n", __func__); + return ret; + } + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd938x, + wcd938x_dais, ARRAY_SIZE(wcd938x_dais)); + if (ret) + dev_err(dev, "%s: Codec registration failed\n", + __func__); + + return ret; + +} + +static void wcd938x_unbind(struct device *dev) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); + + device_link_remove(dev, wcd938x->txdev); + device_link_remove(dev, wcd938x->rxdev); + device_link_remove(wcd938x->rxdev, wcd938x->txdev); + snd_soc_unregister_component(dev); + component_unbind_all(dev, wcd938x); +} + +static const struct component_master_ops wcd938x_comp_ops = { + .bind = wcd938x_bind, + .unbind = wcd938x_unbind, +}; + +static int wcd938x_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void wcd938x_release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + +static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x, + struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np; + + np = dev->of_node; + + wcd938x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0); + if (!wcd938x->rxnode) { + dev_err(dev, "%s: Rx-device node not defined\n", __func__); + return -ENODEV; + } + + of_node_get(wcd938x->rxnode); + component_match_add_release(dev, matchptr, wcd938x_release_of, + wcd938x_compare_of, wcd938x->rxnode); + + wcd938x->txnode = of_parse_phandle(np, "qcom,tx-device", 0); + if (!wcd938x->txnode) { + dev_err(dev, "%s: Tx-device node not defined\n", __func__); + return -ENODEV; + } + of_node_get(wcd938x->txnode); + component_match_add_release(dev, matchptr, wcd938x_release_of, + wcd938x_compare_of, wcd938x->txnode); + return 0; +} + +static int wcd938x_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct wcd938x_priv *wcd938x = NULL; + struct device *dev = &pdev->dev; + int ret; + + wcd938x = devm_kzalloc(dev, sizeof(struct wcd938x_priv), + GFP_KERNEL); + if (!wcd938x) + return -ENOMEM; + + dev_set_drvdata(dev, wcd938x); + + ret = wcd938x_populate_dt_data(wcd938x, dev); + if (ret) { + dev_err(dev, "%s: Fail to obtain platform data\n", __func__); + return -EINVAL; + } + + ret = wcd938x_add_slave_components(wcd938x, dev, &match); + if (ret) + return ret; + + wcd938x_reset(wcd938x); + + ret = component_master_add_with_match(dev, &wcd938x_comp_ops, match); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return ret; +} + +static int wcd938x_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &wcd938x_comp_ops); + + return 0; +} + +#if defined(CONFIG_OF) +static const struct of_device_id wcd938x_dt_match[] = { + { .compatible = "qcom,wcd9380-codec" }, + { .compatible = "qcom,wcd9385-codec" }, + {} +}; +MODULE_DEVICE_TABLE(of, wcd938x_dt_match); +#endif + +static struct platform_driver wcd938x_codec_driver = { + .probe = wcd938x_probe, + .remove = wcd938x_remove, + .driver = { + .name = "wcd938x_codec", + .of_match_table = of_match_ptr(wcd938x_dt_match), + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(wcd938x_codec_driver); +MODULE_DESCRIPTION("WCD938X Codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h new file mode 100644 index 000000000000..07b08de4cebf --- /dev/null +++ b/sound/soc/codecs/wcd938x.h @@ -0,0 +1,718 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __WCD938X_H__ +#define __WCD938X_H__ +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> + +#define WCD938X_BASE_ADDRESS (0x3000) +#define WCD938X_ANA_PAGE_REGISTER (0x3000) +#define WCD938X_ANA_BIAS (0x3001) +#define WCD938X_ANA_RX_SUPPLIES (0x3008) +#define WCD938X_RX_BIAS_EN_MASK BIT(0) +#define WCD938X_REGULATOR_MODE_MASK BIT(1) +#define WCD938X_REGULATOR_MODE_CLASS_AB 1 +#define WCD938X_VNEG_EN_MASK BIT(6) +#define WCD938X_VPOS_EN_MASK BIT(7) +#define WCD938X_ANA_HPH (0x3009) +#define WCD938X_HPHR_REF_EN_MASK BIT(4) +#define WCD938X_HPHL_REF_EN_MASK BIT(5) +#define WCD938X_HPHR_EN_MASK BIT(6) +#define WCD938X_HPHL_EN_MASK BIT(7) +#define WCD938X_ANA_EAR (0x300A) +#define WCD938X_ANA_EAR_COMPANDER_CTL (0x300B) +#define WCD938X_GAIN_OVRD_REG_MASK BIT(7) +#define WCD938X_EAR_GAIN_MASK GENMASK(6, 2) +#define WCD938X_ANA_TX_CH1 (0x300E) +#define WCD938X_ANA_TX_CH2 (0x300F) +#define WCD938X_HPF1_INIT_MASK BIT(6) +#define WCD938X_HPF2_INIT_MASK BIT(5) +#define WCD938X_ANA_TX_CH3 (0x3010) +#define WCD938X_ANA_TX_CH4 (0x3011) +#define WCD938X_HPF3_INIT_MASK BIT(6) +#define WCD938X_HPF4_INIT_MASK BIT(5) +#define WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC (0x3012) +#define WCD938X_ANA_MICB3_DSP_EN_LOGIC (0x3013) +#define WCD938X_ANA_MBHC_MECH (0x3014) +#define WCD938X_MBHC_L_DET_EN_MASK BIT(7) +#define WCD938X_MBHC_L_DET_EN BIT(7) +#define WCD938X_MBHC_GND_DET_EN_MASK BIT(6) +#define WCD938X_MBHC_MECH_DETECT_TYPE_MASK BIT(5) +#define WCD938X_MBHC_MECH_DETECT_TYPE_INS 1 +#define WCD938X_MBHC_HPHL_PLUG_TYPE_MASK BIT(4) +#define WCD938X_MBHC_HPHL_PLUG_TYPE_NO 1 +#define WCD938X_MBHC_GND_PLUG_TYPE_MASK BIT(3) +#define WCD938X_MBHC_GND_PLUG_TYPE_NO 1 +#define WCD938X_MBHC_HSL_PULLUP_COMP_EN BIT(2) +#define WCD938X_MBHC_HSG_PULLUP_COMP_EN BIT(1) +#define WCD938X_MBHC_HPHL_100K_TO_GND_EN BIT(0) + +#define WCD938X_ANA_MBHC_ELECT (0x3015) +#define WCD938X_ANA_MBHC_BD_ISRC_CTL_MASK GENMASK(6, 4) +#define WCD938X_ANA_MBHC_BD_ISRC_100UA GENMASK(5, 4) +#define WCD938X_ANA_MBHC_BD_ISRC_OFF 0 +#define WCD938X_ANA_MBHC_BIAS_EN_MASK BIT(0) +#define WCD938X_ANA_MBHC_BIAS_EN BIT(0) +#define WCD938X_ANA_MBHC_ZDET (0x3016) +#define WCD938X_ANA_MBHC_RESULT_1 (0x3017) +#define WCD938X_ANA_MBHC_RESULT_2 (0x3018) +#define WCD938X_ANA_MBHC_RESULT_3 (0x3019) +#define WCD938X_MBHC_BTN_RESULT_MASK GENMASK(2, 0) +#define WCD938X_ANA_MBHC_BTN0 (0x301A) +#define WCD938X_MBHC_BTN_VTH_MASK GENMASK(7, 2) +#define WCD938X_ANA_MBHC_BTN1 (0x301B) +#define WCD938X_ANA_MBHC_BTN2 (0x301C) +#define WCD938X_ANA_MBHC_BTN3 (0x301D) +#define WCD938X_ANA_MBHC_BTN4 (0x301E) +#define WCD938X_ANA_MBHC_BTN5 (0x301F) +#define WCD938X_VTH_MASK GENMASK(7, 2) +#define WCD938X_ANA_MBHC_BTN6 (0x3020) +#define WCD938X_ANA_MBHC_BTN7 (0x3021) +#define WCD938X_ANA_MICB1 (0x3022) +#define WCD938X_MICB_VOUT_MASK GENMASK(5, 0) +#define WCD938X_MICB_EN_MASK GENMASK(7, 6) +#define WCD938X_MICB_DISABLE 0 +#define WCD938X_MICB_ENABLE 1 +#define WCD938X_MICB_PULL_UP 2 +#define WCD938X_MICB_PULL_DOWN 3 +#define WCD938X_ANA_MICB2 (0x3023) +#define WCD938X_ANA_MICB2_ENABLE BIT(6) +#define WCD938X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6) +#define WCD938X_ANA_MICB2_VOUT_MASK GENMASK(5, 0) +#define WCD938X_ANA_MICB2_RAMP (0x3024) +#define WCD938X_RAMP_EN_MASK BIT(7) +#define WCD938X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2) +#define WCD938X_ANA_MICB3 (0x3025) +#define WCD938X_ANA_MICB4 (0x3026) +#define WCD938X_BIAS_CTL (0x3028) +#define WCD938X_BIAS_VBG_FINE_ADJ (0x3029) +#define WCD938X_LDOL_VDDCX_ADJUST (0x3040) +#define WCD938X_LDOL_DISABLE_LDOL (0x3041) +#define WCD938X_MBHC_CTL_CLK (0x3056) +#define WCD938X_MBHC_CTL_ANA (0x3057) +#define WCD938X_MBHC_CTL_SPARE_1 (0x3058) +#define WCD938X_MBHC_CTL_SPARE_2 (0x3059) +#define WCD938X_MBHC_CTL_BCS (0x305A) +#define WCD938X_MBHC_MOISTURE_DET_FSM_STATUS (0x305B) +#define WCD938X_MBHC_TEST_CTL (0x305C) +#define WCD938X_LDOH_MODE (0x3067) +#define WCD938X_LDOH_EN_MASK BIT(7) +#define WCD938X_LDOH_BIAS (0x3068) +#define WCD938X_LDOH_STB_LOADS (0x3069) +#define WCD938X_LDOH_SLOWRAMP (0x306A) +#define WCD938X_MICB1_TEST_CTL_1 (0x306B) +#define WCD938X_MICB1_TEST_CTL_2 (0x306C) +#define WCD938X_MICB1_TEST_CTL_3 (0x306D) +#define WCD938X_MICB2_TEST_CTL_1 (0x306E) +#define WCD938X_MICB2_TEST_CTL_2 (0x306F) +#define WCD938X_MICB2_TEST_CTL_3 (0x3070) +#define WCD938X_MICB3_TEST_CTL_1 (0x3071) +#define WCD938X_MICB3_TEST_CTL_2 (0x3072) +#define WCD938X_MICB3_TEST_CTL_3 (0x3073) +#define WCD938X_MICB4_TEST_CTL_1 (0x3074) +#define WCD938X_MICB4_TEST_CTL_2 (0x3075) +#define WCD938X_MICB4_TEST_CTL_3 (0x3076) +#define WCD938X_TX_COM_ADC_VCM (0x3077) +#define WCD938X_TX_COM_BIAS_ATEST (0x3078) +#define WCD938X_TX_COM_SPARE1 (0x3079) +#define WCD938X_TX_COM_SPARE2 (0x307A) +#define WCD938X_TX_COM_TXFE_DIV_CTL (0x307B) +#define WCD938X_TX_COM_TXFE_DIV_START (0x307C) +#define WCD938X_TX_COM_SPARE3 (0x307D) +#define WCD938X_TX_COM_SPARE4 (0x307E) +#define WCD938X_TX_1_2_TEST_EN (0x307F) +#define WCD938X_TX_1_2_ADC_IB (0x3080) +#define WCD938X_TX_1_2_ATEST_REFCTL (0x3081) +#define WCD938X_TX_1_2_TEST_CTL (0x3082) +#define WCD938X_TX_1_2_TEST_BLK_EN1 (0x3083) +#define WCD938X_TX_1_2_TXFE1_CLKDIV (0x3084) +#define WCD938X_TX_1_2_SAR2_ERR (0x3085) +#define WCD938X_TX_1_2_SAR1_ERR (0x3086) +#define WCD938X_TX_3_4_TEST_EN (0x3087) +#define WCD938X_TX_3_4_ADC_IB (0x3088) +#define WCD938X_TX_3_4_ATEST_REFCTL (0x3089) +#define WCD938X_TX_3_4_TEST_CTL (0x308A) +#define WCD938X_TX_3_4_TEST_BLK_EN3 (0x308B) +#define WCD938X_TX_3_4_TXFE3_CLKDIV (0x308C) +#define WCD938X_TX_3_4_SAR4_ERR (0x308D) +#define WCD938X_TX_3_4_SAR3_ERR (0x308E) +#define WCD938X_TX_3_4_TEST_BLK_EN2 (0x308F) +#define WCD938X_TX_3_4_TXFE2_CLKDIV (0x3090) +#define WCD938X_TX_3_4_SPARE1 (0x3091) +#define WCD938X_TX_3_4_TEST_BLK_EN4 (0x3092) +#define WCD938X_TX_3_4_TXFE4_CLKDIV (0x3093) +#define WCD938X_TX_3_4_SPARE2 (0x3094) +#define WCD938X_CLASSH_MODE_1 (0x3097) +#define WCD938X_CLASSH_MODE_2 (0x3098) +#define WCD938X_CLASSH_MODE_3 (0x3099) +#define WCD938X_CLASSH_CTRL_VCL_1 (0x309A) +#define WCD938X_CLASSH_CTRL_VCL_2 (0x309B) +#define WCD938X_CLASSH_CTRL_CCL_1 (0x309C) +#define WCD938X_CLASSH_CTRL_CCL_2 (0x309D) +#define WCD938X_CLASSH_CTRL_CCL_3 (0x309E) +#define WCD938X_CLASSH_CTRL_CCL_4 (0x309F) +#define WCD938X_CLASSH_CTRL_CCL_5 (0x30A0) +#define WCD938X_CLASSH_BUCK_TMUX_A_D (0x30A1) +#define WCD938X_CLASSH_BUCK_SW_DRV_CNTL (0x30A2) +#define WCD938X_CLASSH_SPARE (0x30A3) +#define WCD938X_FLYBACK_EN (0x30A4) +#define WCD938X_EN_CUR_DET_MASK BIT(2) +#define WCD938X_FLYBACK_VNEG_CTRL_1 (0x30A5) +#define WCD938X_FLYBACK_VNEG_CTRL_2 (0x30A6) +#define WCD938X_FLYBACK_VNEG_CTRL_3 (0x30A7) +#define WCD938X_FLYBACK_VNEG_CTRL_4 (0x30A8) +#define WCD938X_FLYBACK_VNEG_CTRL_5 (0x30A9) +#define WCD938X_FLYBACK_VNEG_CTRL_6 (0x30AA) +#define WCD938X_FLYBACK_VNEG_CTRL_7 (0x30AB) +#define WCD938X_FLYBACK_VNEG_CTRL_8 (0x30AC) +#define WCD938X_FLYBACK_VNEG_CTRL_9 (0x30AD) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_1 (0x30AE) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_2 (0x30AF) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_3 (0x30B0) +#define WCD938X_FLYBACK_CTRL_1 (0x30B1) +#define WCD938X_FLYBACK_TEST_CTL (0x30B2) +#define WCD938X_RX_AUX_SW_CTL (0x30B3) +#define WCD938X_RX_PA_AUX_IN_CONN (0x30B4) +#define WCD938X_RX_TIMER_DIV (0x30B5) +#define WCD938X_RX_OCP_CTL (0x30B6) +#define WCD938X_RX_OCP_COUNT (0x30B7) +#define WCD938X_RX_BIAS_EAR_DAC (0x30B8) +#define WCD938X_RX_BIAS_EAR_AMP (0x30B9) +#define WCD938X_RX_BIAS_HPH_LDO (0x30BA) +#define WCD938X_RX_BIAS_HPH_PA (0x30BB) +#define WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2 (0x30BC) +#define WCD938X_RX_BIAS_HPH_RDAC_LDO (0x30BD) +#define WCD938X_RX_BIAS_HPH_CNP1 (0x30BE) +#define WCD938X_RX_BIAS_HPH_LOWPOWER (0x30BF) +#define WCD938X_RX_BIAS_AUX_DAC (0x30C0) +#define WCD938X_RX_BIAS_AUX_AMP (0x30C1) +#define WCD938X_RX_BIAS_VNEGDAC_BLEEDER (0x30C2) +#define WCD938X_RX_BIAS_MISC (0x30C3) +#define WCD938X_RX_BIAS_BUCK_RST (0x30C4) +#define WCD938X_RX_BIAS_BUCK_VREF_ERRAMP (0x30C5) +#define WCD938X_RX_BIAS_FLYB_ERRAMP (0x30C6) +#define WCD938X_RX_BIAS_FLYB_BUFF (0x30C7) +#define WCD938X_RX_BIAS_FLYB_MID_RST (0x30C8) +#define WCD938X_HPH_L_STATUS (0x30C9) +#define WCD938X_HPH_R_STATUS (0x30CA) +#define WCD938X_HPH_CNP_EN (0x30CB) +#define WCD938X_HPH_CNP_WG_CTL (0x30CC) +#define WCD938X_HPH_CNP_WG_TIME (0x30CD) +#define WCD938X_HPH_OCP_CTL (0x30CE) +#define WCD938X_HPH_AUTO_CHOP (0x30CF) +#define WCD938X_HPH_CHOP_CTL (0x30D0) +#define WCD938X_HPH_PA_CTL1 (0x30D1) +#define WCD938X_HPH_PA_CTL2 (0x30D2) +#define WCD938X_HPHPA_GND_R_MASK BIT(6) +#define WCD938X_HPHPA_GND_L_MASK BIT(4) +#define WCD938X_HPH_L_EN (0x30D3) +#define WCD938X_HPH_L_TEST (0x30D4) +#define WCD938X_HPH_L_ATEST (0x30D5) +#define WCD938X_HPH_R_EN (0x30D6) +#define WCD938X_GAIN_SRC_SEL_MASK BIT(5) +#define WCD938X_GAIN_SRC_SEL_REGISTER 1 +#define WCD938X_HPH_R_TEST (0x30D7) +#define WCD938X_HPH_R_ATEST (0x30D8) +#define WCD938X_HPHPA_GND_OVR_MASK BIT(1) +#define WCD938X_HPH_RDAC_CLK_CTL1 (0x30D9) +#define WCD938X_CHOP_CLK_EN_MASK BIT(7) +#define WCD938X_HPH_RDAC_CLK_CTL2 (0x30DA) +#define WCD938X_HPH_RDAC_LDO_CTL (0x30DB) +#define WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL (0x30DC) +#define WCD938X_HPH_REFBUFF_UHQA_CTL (0x30DD) +#define WCD938X_HPH_REFBUFF_LP_CTL (0x30DE) +#define WCD938X_PREREF_FLIT_BYPASS_MASK BIT(0) +#define WCD938X_HPH_L_DAC_CTL (0x30DF) +#define WCD938X_HPH_R_DAC_CTL (0x30E0) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL (0x30E1) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_EN (0x30E2) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1 (0x30E3) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS (0x30E4) +#define WCD938X_EAR_EAR_EN_REG (0x30E9) +#define WCD938X_EAR_EAR_PA_CON (0x30EA) +#define WCD938X_EAR_EAR_SP_CON (0x30EB) +#define WCD938X_EAR_EAR_DAC_CON (0x30EC) +#define WCD938X_DAC_SAMPLE_EDGE_SEL_MASK BIT(7) +#define WCD938X_EAR_EAR_CNP_FSM_CON (0x30ED) +#define WCD938X_EAR_TEST_CTL (0x30EE) +#define WCD938X_EAR_STATUS_REG_1 (0x30EF) +#define WCD938X_EAR_STATUS_REG_2 (0x30F0) +#define WCD938X_ANA_NEW_PAGE_REGISTER (0x3100) +#define WCD938X_HPH_NEW_ANA_HPH2 (0x3101) +#define WCD938X_HPH_NEW_ANA_HPH3 (0x3102) +#define WCD938X_SLEEP_CTL (0x3103) +#define WCD938X_SLEEP_WATCHDOG_CTL (0x3104) +#define WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL (0x311F) +#define WCD938X_MBHC_NEW_CTL_1 (0x3120) +#define WCD938X_MBHC_CTL_RCO_EN_MASK BIT(7) +#define WCD938X_MBHC_CTL_RCO_EN BIT(7) +#define WCD938X_MBHC_BTN_DBNC_MASK GENMASK(1, 0) +#define WCD938X_MBHC_BTN_DBNC_T_16_MS 0x2 +#define WCD938X_MBHC_NEW_CTL_2 (0x3121) +#define WCD938X_M_RTH_CTL_MASK GENMASK(3, 2) +#define WCD938X_MBHC_HS_VREF_CTL_MASK GENMASK(1, 0) +#define WCD938X_MBHC_HS_VREF_1P5_V 0x1 +#define WCD938X_MBHC_NEW_PLUG_DETECT_CTL (0x3122) +#define WCD938X_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS 0x6 + +#define WCD938X_MBHC_NEW_ZDET_ANA_CTL (0x3123) +#define WCD938X_ZDET_RANGE_CTL_MASK GENMASK(3, 0) +#define WCD938X_ZDET_MAXV_CTL_MASK GENMASK(6, 4) +#define WCD938X_MBHC_NEW_ZDET_RAMP_CTL (0x3124) +#define WCD938X_MBHC_NEW_FSM_STATUS (0x3125) +#define WCD938X_MBHC_NEW_ADC_RESULT (0x3126) +#define WCD938X_TX_NEW_AMIC_MUX_CFG (0x3127) +#define WCD938X_AUX_AUXPA (0x3128) +#define WCD938X_AUXPA_CLK_EN_MASK BIT(4) +#define WCD938X_LDORXTX_MODE (0x3129) +#define WCD938X_LDORXTX_CONFIG (0x312A) +#define WCD938X_DIE_CRACK_DIE_CRK_DET_EN (0x312C) +#define WCD938X_DIE_CRACK_DIE_CRK_DET_OUT (0x312D) +#define WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL (0x3132) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L (0x3133) +#define WCD938X_HPH_NEW_INT_RDAC_VREF_CTL (0x3134) +#define WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL (0x3135) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R (0x3136) +#define WCD938X_HPH_RES_DIV_MASK GENMASK(4, 0) +#define WCD938X_HPH_NEW_INT_PA_MISC1 (0x3137) +#define WCD938X_HPH_NEW_INT_PA_MISC2 (0x3138) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC (0x3139) +#define WCD938X_HPH_NEW_INT_HPH_TIMER1 (0x313A) +#define WCD938X_AUTOCHOP_TIMER_EN BIT(1) +#define WCD938X_HPH_NEW_INT_HPH_TIMER2 (0x313B) +#define WCD938X_HPH_NEW_INT_HPH_TIMER3 (0x313C) +#define WCD938X_HPH_NEW_INT_HPH_TIMER4 (0x313D) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC2 (0x313E) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC3 (0x313F) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW (0x3140) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW (0x3141) +#define WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI (0x3145) +#define WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP (0x3146) +#define WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP (0x3147) +#define WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL (0x31AF) +#define WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL (0x31B0) +#define WCD938X_MOISTURE_EN_POLLING_MASK BIT(2) +#define WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT (0x31B1) +#define WCD938X_HSDET_PULLUP_C_MASK GENMASK(4, 0) +#define WCD938X_MBHC_NEW_INT_SPARE_2 (0x31B2) +#define WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON (0x31B7) +#define WCD938X_EAR_INT_NEW_CNP_VCM_CON1 (0x31B8) +#define WCD938X_EAR_INT_NEW_CNP_VCM_CON2 (0x31B9) +#define WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS (0x31BA) +#define WCD938X_AUX_INT_EN_REG (0x31BD) +#define WCD938X_AUX_INT_PA_CTRL (0x31BE) +#define WCD938X_AUX_INT_SP_CTRL (0x31BF) +#define WCD938X_AUX_INT_DAC_CTRL (0x31C0) +#define WCD938X_AUX_INT_CLK_CTRL (0x31C1) +#define WCD938X_AUX_INT_TEST_CTRL (0x31C2) +#define WCD938X_AUX_INT_STATUS_REG (0x31C3) +#define WCD938X_AUX_INT_MISC (0x31C4) +#define WCD938X_LDORXTX_INT_BIAS (0x31C5) +#define WCD938X_LDORXTX_INT_STB_LOADS_DTEST (0x31C6) +#define WCD938X_LDORXTX_INT_TEST0 (0x31C7) +#define WCD938X_LDORXTX_INT_STARTUP_TIMER (0x31C8) +#define WCD938X_LDORXTX_INT_TEST1 (0x31C9) +#define WCD938X_LDORXTX_INT_STATUS (0x31CA) +#define WCD938X_SLEEP_INT_WATCHDOG_CTL_1 (0x31D0) +#define WCD938X_SLEEP_INT_WATCHDOG_CTL_2 (0x31D1) +#define WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1 (0x31D3) +#define WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2 (0x31D4) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2 (0x31D5) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1 (0x31D6) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0 (0x31D7) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M (0x31D8) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M (0x31D9) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1 (0x31DA) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0 (0x31DB) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP (0x31DC) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1 (0x31DD) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0 (0x31DE) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP (0x31DF) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0 (0x31E0) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP (0x31E1) +#define WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1 (0x31E2) +#define WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP (0x31E3) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L2 (0x31E4) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L1 (0x31E5) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L0 (0x31E6) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP (0x31E7) +#define WCD938X_DIGITAL_PAGE_REGISTER (0x3400) +#define WCD938X_DIGITAL_CHIP_ID0 (0x3401) +#define WCD938X_DIGITAL_CHIP_ID1 (0x3402) +#define WCD938X_DIGITAL_CHIP_ID2 (0x3403) +#define WCD938X_DIGITAL_CHIP_ID3 (0x3404) +#define WCD938X_DIGITAL_SWR_TX_CLK_RATE (0x3405) +#define WCD938X_DIGITAL_CDC_RST_CTL (0x3406) +#define WCD938X_DIGITAL_TOP_CLK_CFG (0x3407) +#define WCD938X_DIGITAL_CDC_ANA_CLK_CTL (0x3408) +#define WCD938X_ANA_RX_CLK_EN_MASK BIT(0) +#define WCD938X_ANA_RX_DIV2_CLK_EN_MASK BIT(1) +#define WCD938X_ANA_RX_DIV4_CLK_EN_MASK BIT(2) +#define WCD938X_ANA_TX_CLK_EN_MASK BIT(3) +#define WCD938X_ANA_TX_DIV2_CLK_EN_MASK BIT(4) +#define WCD938X_ANA_TX_DIV4_CLK_EN_MASK BIT(5) +#define WCD938X_DIGITAL_CDC_DIG_CLK_CTL (0x3409) +#define WCD938X_TXD3_CLK_EN_MASK BIT(7) +#define WCD938X_TXD2_CLK_EN_MASK BIT(6) +#define WCD938X_TXD1_CLK_EN_MASK BIT(5) +#define WCD938X_TXD0_CLK_EN_MASK BIT(4) +#define WCD938X_TX_CLK_EN_MASK GENMASK(7, 4) +#define WCD938X_RXD2_CLK_EN_MASK BIT(2) +#define WCD938X_RXD1_CLK_EN_MASK BIT(1) +#define WCD938X_RXD0_CLK_EN_MASK BIT(0) +#define WCD938X_DIGITAL_SWR_RST_EN (0x340A) +#define WCD938X_DIGITAL_CDC_PATH_MODE (0x340B) +#define WCD938X_DIGITAL_CDC_RX_RST (0x340C) +#define WCD938X_DIGITAL_CDC_RX0_CTL (0x340D) +#define WCD938X_DEM_DITHER_ENABLE_MASK BIT(6) +#define WCD938X_DIGITAL_CDC_RX1_CTL (0x340E) +#define WCD938X_DIGITAL_CDC_RX2_CTL (0x340F) +#define WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1 (0x3410) +#define WCD938X_TXD0_MODE_MASK GENMASK(3, 0) +#define WCD938X_TXD1_MODE_MASK GENMASK(7, 4) +#define WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3 (0x3411) +#define WCD938X_TXD2_MODE_MASK GENMASK(3, 0) +#define WCD938X_TXD3_MODE_MASK GENMASK(7, 4) +#define WCD938X_DIGITAL_CDC_COMP_CTL_0 (0x3414) +#define WCD938X_HPHR_COMP_EN_MASK BIT(0) +#define WCD938X_HPHL_COMP_EN_MASK BIT(1) +#define WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL (0x3417) +#define WCD938X_TX_SC_CLK_EN_MASK BIT(0) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A1_0 (0x3418) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A1_1 (0x3419) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A2_0 (0x341A) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A2_1 (0x341B) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A3_0 (0x341C) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A3_1 (0x341D) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A4_0 (0x341E) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A4_1 (0x341F) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A5_0 (0x3420) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A5_1 (0x3421) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A6_0 (0x3422) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A7_0 (0x3423) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_0 (0x3424) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_1 (0x3425) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_2 (0x3426) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_3 (0x3427) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R1 (0x3428) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R2 (0x3429) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R3 (0x342A) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R4 (0x342B) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R5 (0x342C) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R6 (0x342D) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R7 (0x342E) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A1_0 (0x342F) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A1_1 (0x3430) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A2_0 (0x3431) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A2_1 (0x3432) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A3_0 (0x3433) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A3_1 (0x3434) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A4_0 (0x3435) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A4_1 (0x3436) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A5_0 (0x3437) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A5_1 (0x3438) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A6_0 (0x3439) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A7_0 (0x343A) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_0 (0x343B) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_1 (0x343C) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_2 (0x343D) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_3 (0x343E) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R1 (0x343F) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R2 (0x3440) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R3 (0x3441) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R4 (0x3442) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R5 (0x3443) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R6 (0x3444) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R7 (0x3445) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0 (0x3446) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1 (0x3447) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0 (0x3448) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1 (0x3449) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2 (0x344A) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0 (0x344B) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1 (0x344C) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2 (0x344D) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_CTL (0x344E) +#define WCD938X_HPHL_RX_EN_MASK BIT(2) +#define WCD938X_HPHR_RX_EN_MASK BIT(3) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_CTL (0x344F) +#define WCD938X_AUX_EN_MASK BIT(0) +#define WCD938X_DIGITAL_CDC_EAR_PATH_CTL (0x3450) +#define WCD938X_DIGITAL_CDC_SWR_CLH (0x3451) +#define WCD938X_DIGITAL_SWR_CLH_BYP (0x3452) +#define WCD938X_DIGITAL_CDC_TX0_CTL (0x3453) +#define WCD938X_DIGITAL_CDC_TX1_CTL (0x3454) +#define WCD938X_DIGITAL_CDC_TX2_CTL (0x3455) +#define WCD938X_DIGITAL_CDC_TX_RST (0x3456) +#define WCD938X_DIGITAL_CDC_REQ_CTL (0x3457) +#define WCD938X_FS_RATE_4P8_MASK BIT(1) +#define WCD938X_NO_NOTCH_MASK BIT(0) +#define WCD938X_DIGITAL_CDC_RST (0x3458) +#define WCD938X_DIGITAL_CDC_AMIC_CTL (0x345A) +#define WCD938X_AMIC1_IN_SEL_DMIC 0 +#define WCD938X_AMIC1_IN_SEL_AMIC 0 +#define WCD938X_AMIC1_IN_SEL_MASK BIT(0) +#define WCD938X_AMIC3_IN_SEL_MASK BIT(1) +#define WCD938X_AMIC4_IN_SEL_MASK BIT(2) +#define WCD938X_AMIC5_IN_SEL_MASK BIT(3) +#define WCD938X_DIGITAL_CDC_DMIC_CTL (0x345B) +#define WCD938X_DMIC_CLK_SCALING_EN_MASK GENMASK(2, 1) +#define WCD938X_DIGITAL_CDC_DMIC1_CTL (0x345C) +#define WCD938X_DMIC_CLK_EN_MASK BIT(3) +#define WCD938X_DIGITAL_CDC_DMIC2_CTL (0x345D) +#define WCD938X_DIGITAL_CDC_DMIC3_CTL (0x345E) +#define WCD938X_DIGITAL_CDC_DMIC4_CTL (0x345F) +#define WCD938X_DIGITAL_EFUSE_PRG_CTL (0x3460) +#define WCD938X_DIGITAL_EFUSE_CTL (0x3461) +#define WCD938X_DIGITAL_CDC_DMIC_RATE_1_2 (0x3462) +#define WCD938X_DIGITAL_CDC_DMIC_RATE_3_4 (0x3463) +#define WCD938X_DMIC1_RATE_MASK GENMASK(3, 0) +#define WCD938X_DMIC2_RATE_MASK GENMASK(7, 4) +#define WCD938X_DMIC3_RATE_MASK GENMASK(3, 0) +#define WCD938X_DMIC4_RATE_MASK GENMASK(7, 4) +#define WCD938X_DMIC4_RATE_2P4MHZ 3 + +#define WCD938X_DIGITAL_PDM_WD_CTL0 (0x3465) +#define WCD938X_PDM_WD_EN_MASK GENMASK(2, 0) +#define WCD938X_DIGITAL_PDM_WD_CTL1 (0x3466) +#define WCD938X_DIGITAL_PDM_WD_CTL2 (0x3467) +#define WCD938X_AUX_PDM_WD_EN_MASK GENMASK(2, 0) +#define WCD938X_DIGITAL_INTR_MODE (0x346A) +#define WCD938X_DIGITAL_INTR_MASK_0 (0x346B) +#define WCD938X_DIGITAL_INTR_MASK_1 (0x346C) +#define WCD938X_DIGITAL_INTR_MASK_2 (0x346D) +#define WCD938X_DIGITAL_INTR_STATUS_0 (0x346E) +#define WCD938X_DIGITAL_INTR_STATUS_1 (0x346F) +#define WCD938X_DIGITAL_INTR_STATUS_2 (0x3470) +#define WCD938X_DIGITAL_INTR_CLEAR_0 (0x3471) +#define WCD938X_DIGITAL_INTR_CLEAR_1 (0x3472) +#define WCD938X_DIGITAL_INTR_CLEAR_2 (0x3473) +#define WCD938X_DIGITAL_INTR_LEVEL_0 (0x3474) +#define WCD938X_DIGITAL_INTR_LEVEL_1 (0x3475) +#define WCD938X_DIGITAL_INTR_LEVEL_2 (0x3476) +#define WCD938X_DIGITAL_INTR_SET_0 (0x3477) +#define WCD938X_DIGITAL_INTR_SET_1 (0x3478) +#define WCD938X_DIGITAL_INTR_SET_2 (0x3479) +#define WCD938X_DIGITAL_INTR_TEST_0 (0x347A) +#define WCD938X_DIGITAL_INTR_TEST_1 (0x347B) +#define WCD938X_DIGITAL_INTR_TEST_2 (0x347C) +#define WCD938X_DIGITAL_TX_MODE_DBG_EN (0x347F) +#define WCD938X_DIGITAL_TX_MODE_DBG_0_1 (0x3480) +#define WCD938X_DIGITAL_TX_MODE_DBG_2_3 (0x3481) +#define WCD938X_DIGITAL_LB_IN_SEL_CTL (0x3482) +#define WCD938X_DIGITAL_LOOP_BACK_MODE (0x3483) +#define WCD938X_DIGITAL_SWR_DAC_TEST (0x3484) +#define WCD938X_DIGITAL_SWR_HM_TEST_RX_0 (0x3485) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_0 (0x3486) +#define WCD938X_DIGITAL_SWR_HM_TEST_RX_1 (0x3487) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_1 (0x3488) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_2 (0x3489) +#define WCD938X_DIGITAL_SWR_HM_TEST_0 (0x348A) +#define WCD938X_DIGITAL_SWR_HM_TEST_1 (0x348B) +#define WCD938X_DIGITAL_PAD_CTL_SWR_0 (0x348C) +#define WCD938X_DIGITAL_PAD_CTL_SWR_1 (0x348D) +#define WCD938X_DIGITAL_I2C_CTL (0x348E) +#define WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE (0x348F) +#define WCD938X_DIGITAL_EFUSE_TEST_CTL_0 (0x3490) +#define WCD938X_DIGITAL_EFUSE_TEST_CTL_1 (0x3491) +#define WCD938X_DIGITAL_EFUSE_T_DATA_0 (0x3492) +#define WCD938X_DIGITAL_EFUSE_T_DATA_1 (0x3493) +#define WCD938X_DIGITAL_PAD_CTL_PDM_RX0 (0x3494) +#define WCD938X_DIGITAL_PAD_CTL_PDM_RX1 (0x3495) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX0 (0x3496) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX1 (0x3497) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX2 (0x3498) +#define WCD938X_DIGITAL_PAD_INP_DIS_0 (0x3499) +#define WCD938X_DIGITAL_PAD_INP_DIS_1 (0x349A) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_0 (0x349B) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_1 (0x349C) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_2 (0x349D) +#define WCD938X_DIGITAL_RX_DATA_EDGE_CTL (0x349E) +#define WCD938X_DIGITAL_TX_DATA_EDGE_CTL (0x349F) +#define WCD938X_DIGITAL_GPIO_MODE (0x34A0) +#define WCD938X_DIGITAL_PIN_CTL_OE (0x34A1) +#define WCD938X_DIGITAL_PIN_CTL_DATA_0 (0x34A2) +#define WCD938X_DIGITAL_PIN_CTL_DATA_1 (0x34A3) +#define WCD938X_DIGITAL_PIN_STATUS_0 (0x34A4) +#define WCD938X_DIGITAL_PIN_STATUS_1 (0x34A5) +#define WCD938X_DIGITAL_DIG_DEBUG_CTL (0x34A6) +#define WCD938X_DIGITAL_DIG_DEBUG_EN (0x34A7) +#define WCD938X_DIGITAL_ANA_CSR_DBG_ADD (0x34A8) +#define WCD938X_DIGITAL_ANA_CSR_DBG_CTL (0x34A9) +#define WCD938X_DIGITAL_SSP_DBG (0x34AA) +#define WCD938X_DIGITAL_MODE_STATUS_0 (0x34AB) +#define WCD938X_DIGITAL_MODE_STATUS_1 (0x34AC) +#define WCD938X_DIGITAL_SPARE_0 (0x34AD) +#define WCD938X_DIGITAL_SPARE_1 (0x34AE) +#define WCD938X_DIGITAL_SPARE_2 (0x34AF) +#define WCD938X_DIGITAL_EFUSE_REG_0 (0x34B0) +#define WCD938X_ID_MASK GENMASK(4, 1) +#define WCD938X_DIGITAL_EFUSE_REG_1 (0x34B1) +#define WCD938X_DIGITAL_EFUSE_REG_2 (0x34B2) +#define WCD938X_DIGITAL_EFUSE_REG_3 (0x34B3) +#define WCD938X_DIGITAL_EFUSE_REG_4 (0x34B4) +#define WCD938X_DIGITAL_EFUSE_REG_5 (0x34B5) +#define WCD938X_DIGITAL_EFUSE_REG_6 (0x34B6) +#define WCD938X_DIGITAL_EFUSE_REG_7 (0x34B7) +#define WCD938X_DIGITAL_EFUSE_REG_8 (0x34B8) +#define WCD938X_DIGITAL_EFUSE_REG_9 (0x34B9) +#define WCD938X_DIGITAL_EFUSE_REG_10 (0x34BA) +#define WCD938X_DIGITAL_EFUSE_REG_11 (0x34BB) +#define WCD938X_DIGITAL_EFUSE_REG_12 (0x34BC) +#define WCD938X_DIGITAL_EFUSE_REG_13 (0x34BD) +#define WCD938X_DIGITAL_EFUSE_REG_14 (0x34BE) +#define WCD938X_DIGITAL_EFUSE_REG_15 (0x34BF) +#define WCD938X_DIGITAL_EFUSE_REG_16 (0x34C0) +#define WCD938X_DIGITAL_EFUSE_REG_17 (0x34C1) +#define WCD938X_DIGITAL_EFUSE_REG_18 (0x34C2) +#define WCD938X_DIGITAL_EFUSE_REG_19 (0x34C3) +#define WCD938X_DIGITAL_EFUSE_REG_20 (0x34C4) +#define WCD938X_DIGITAL_EFUSE_REG_21 (0x34C5) +#define WCD938X_DIGITAL_EFUSE_REG_22 (0x34C6) +#define WCD938X_DIGITAL_EFUSE_REG_23 (0x34C7) +#define WCD938X_DIGITAL_EFUSE_REG_24 (0x34C8) +#define WCD938X_DIGITAL_EFUSE_REG_25 (0x34C9) +#define WCD938X_DIGITAL_EFUSE_REG_26 (0x34CA) +#define WCD938X_DIGITAL_EFUSE_REG_27 (0x34CB) +#define WCD938X_DIGITAL_EFUSE_REG_28 (0x34CC) +#define WCD938X_DIGITAL_EFUSE_REG_29 (0x34CD) +#define WCD938X_DIGITAL_EFUSE_REG_30 (0x34CE) +#define WCD938X_DIGITAL_EFUSE_REG_31 (0x34CF) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_0 (0x34D0) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_1 (0x34D1) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_2 (0x34D2) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_3 (0x34D3) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_4 (0x34D4) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA0 (0x34D5) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA1 (0x34D6) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA2 (0x34D7) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA3 (0x34D8) +#define WCD938X_MAX_REGISTER (WCD938X_DIGITAL_DEM_BYPASS_DATA3) + +#define WCD938X_MAX_SWR_PORTS 5 +#define WCD938X_MAX_TX_SWR_PORTS 4 +#define WCD938X_MAX_SWR_CH_IDS 15 + +struct wcd938x_sdw_ch_info { + int port_num; + unsigned int ch_mask; +}; + +#define WCD_SDW_CH(id, pn, cmask) \ + [id] = { \ + .port_num = pn, \ + .ch_mask = cmask, \ + } + +enum wcd938x_tx_sdw_ports { + WCD938X_ADC_1_2_PORT = 1, + WCD938X_ADC_3_4_PORT, + /* DMIC0_0, DMIC0_1, DMIC1_0, DMIC1_1 */ + WCD938X_DMIC_0_3_MBHC_PORT, + WCD938X_DMIC_4_7_PORT, +}; + +enum wcd938x_tx_sdw_channels { + WCD938X_ADC1, + WCD938X_ADC2, + WCD938X_ADC3, + WCD938X_ADC4, + WCD938X_DMIC0, + WCD938X_DMIC1, + WCD938X_MBHC, + WCD938X_DMIC2, + WCD938X_DMIC3, + WCD938X_DMIC4, + WCD938X_DMIC5, + WCD938X_DMIC6, + WCD938X_DMIC7, +}; + +enum wcd938x_rx_sdw_ports { + WCD938X_HPH_PORT = 1, + WCD938X_CLSH_PORT, + WCD938X_COMP_PORT, + WCD938X_LO_PORT, + WCD938X_DSD_PORT, +}; + +enum wcd938x_rx_sdw_channels { + WCD938X_HPH_L, + WCD938X_HPH_R, + WCD938X_CLSH, + WCD938X_COMP_L, + WCD938X_COMP_R, + WCD938X_LO, + WCD938X_DSD_R, + WCD938X_DSD_L, +}; +enum { + WCD938X_SDW_DIR_RX, + WCD938X_SDW_DIR_TX, +}; + +struct wcd938x_priv; +struct wcd938x_sdw_priv { + struct sdw_slave *sdev; + struct sdw_stream_config sconfig; + struct sdw_stream_runtime *sruntime; + struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS]; + struct wcd938x_sdw_ch_info *ch_info; + bool port_enable[WCD938X_MAX_SWR_CH_IDS]; + int port_map[WCD938X_MAX_SWR_PORTS]; + int active_ports; + int num_ports; + bool is_tx; + struct wcd938x_priv *wcd938x; + struct irq_domain *slave_irq; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_WCD938X_SDW) +int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction); +int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + +struct device *wcd938x_sdw_device_get(struct device_node *np); +int wcd938x_swr_get_current_bank(struct sdw_slave *sdev); + +#else + +static inline int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return -EOPNOTSUPP; +} + +static inline int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction) +{ + return -EOPNOTSUPP; +} + +static inline int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return -EOPNOTSUPP; +} + +static inline struct device *wcd938x_sdw_device_get(struct device_node *np) +{ + return NULL; +} + +static inline int wcd938x_swr_get_current_bank(struct sdw_slave *sdev) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_WCD938X_SDW */ +#endif /* __WCD938X_H__ */ diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index b0a6d31299bb..c35673e7f420 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -30,7 +30,6 @@ #include <sound/wm2200.h> #include "wm2200.h" -#include "wmfw.h" #include "wm_adsp.h" #define WM2200_DSP_CONTROL_1 0x00 diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 34b665895bdf..621598608bf0 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1989,7 +1989,7 @@ static unsigned int wm5102_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; -static struct snd_compress_ops wm5102_compress_ops = { +static const struct snd_compress_ops wm5102_compress_ops = { .open = wm5102_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 76efca0fe515..5c2d45d05c97 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2355,7 +2355,7 @@ static unsigned int wm5110_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_6R, }; -static struct snd_compress_ops wm5110_compress_ops = { +static const struct snd_compress_ops wm5110_compress_ops = { .open = wm5110_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 34080f497584..ba16bdf9e478 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3219,9 +3219,8 @@ static int wm8962_beep_event(struct input_dev *dev, unsigned int type, return 0; } -static ssize_t wm8962_beep_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t beep_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); long int time; @@ -3236,7 +3235,7 @@ static ssize_t wm8962_beep_set(struct device *dev, return count; } -static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set); +static DEVICE_ATTR_WO(beep); static void wm8962_init_beep(struct snd_soc_component *component) { diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 3dc119daf2f6..37aa020f23f6 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -303,9 +303,9 @@ #define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff #define HALO_MPU_VIO_ERR_SRC_SHIFT 0 -static struct wm_adsp_ops wm_adsp1_ops; -static struct wm_adsp_ops wm_adsp2_ops[]; -static struct wm_adsp_ops wm_halo_ops; +static const struct wm_adsp_ops wm_adsp1_ops; +static const struct wm_adsp_ops wm_adsp2_ops[]; +static const struct wm_adsp_ops wm_halo_ops; struct wm_adsp_buf { struct list_head list; @@ -824,7 +824,7 @@ const struct soc_enum wm_adsp_fw_enum[] = { }; EXPORT_SYMBOL_GPL(wm_adsp_fw_enum); -static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, +static const struct wm_adsp_region *wm_adsp_find_region(struct wm_adsp *dsp, int type) { int i; @@ -2240,7 +2240,7 @@ static void wmfw_v3_parse_id_header(struct wm_adsp *dsp, } static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions, - int *type, __be32 *base) + const int *type, __be32 *base) { struct wm_adsp_alg_region *alg_region; int i; @@ -2487,7 +2487,7 @@ out: static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id, __be32 xm_base, __be32 ym_base) { - int types[] = { + static const int types[] = { WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED, WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED }; @@ -4500,13 +4500,13 @@ irqreturn_t wm_halo_wdt_expire(int irq, void *data) } EXPORT_SYMBOL_GPL(wm_halo_wdt_expire); -static struct wm_adsp_ops wm_adsp1_ops = { +static const struct wm_adsp_ops wm_adsp1_ops = { .validate_version = wm_adsp_validate_version, .parse_sizes = wm_adsp1_parse_sizes, .region_to_reg = wm_adsp_region_to_reg, }; -static struct wm_adsp_ops wm_adsp2_ops[] = { +static const struct wm_adsp_ops wm_adsp2_ops[] = { { .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr), .parse_sizes = wm_adsp2_parse_sizes, @@ -4567,7 +4567,7 @@ static struct wm_adsp_ops wm_adsp2_ops[] = { }, }; -static struct wm_adsp_ops wm_halo_ops = { +static const struct wm_adsp_ops wm_halo_ops = { .sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr), .parse_sizes = wm_adsp2_parse_sizes, .validate_version = wm_halo_validate_version, diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 1996350b817e..f22131d9cc29 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -64,7 +64,7 @@ struct wm_adsp { struct regmap *regmap; struct snd_soc_component *component; - struct wm_adsp_ops *ops; + const struct wm_adsp_ops *ops; unsigned int base; unsigned int base_sysinfo; diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index fd4160289fac..8ebf76e04702 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -636,8 +636,7 @@ static int dw_i2s_probe(struct platform_device *pdev) dw_i2s_dai->ops = &dw_i2s_dai_ops; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->i2s_base = devm_ioremap_resource(&pdev->dev, res); + dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dev->i2s_base)) return PTR_ERR(dev->i2s_base); diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 556c284f49dd..8e05d092790e 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -351,6 +351,19 @@ config SND_SOC_IMX_RPMSG Say Y if you want to add support for SoC audio on an i.MX board with a rpmsg devices. +config SND_SOC_IMX_CARD + tristate "SoC Audio Graph Sound Card support for i.MX boards" + depends on OF && I2C + select SND_SOC_AK4458 + select SND_SOC_AK5558 + select SND_SOC_IMX_PCM_DMA + select SND_SOC_FSL_SAI + select SND_SIMPLE_CARD_UTILS + help + This option enables audio sound card support for i.MX boards + with OF-graph DT bindings. + It also support DPCM of single CPU multi Codec ststem. + endif # SND_IMX_SOC endmenu diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index f146ce464acd..b54beb1a66fa 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -71,6 +71,7 @@ snd-soc-imx-spdif-objs := imx-spdif.o snd-soc-imx-audmix-objs := imx-audmix.o snd-soc-imx-hdmi-objs := imx-hdmi.o snd-soc-imx-rpmsg-objs := imx-rpmsg.o +snd-soc-imx-card-objs := imx-card.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o @@ -79,3 +80,4 @@ obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o obj-$(CONFIG_SND_SOC_IMX_RPMSG) += snd-soc-imx-rpmsg.o +obj-$(CONFIG_SND_SOC_IMX_CARD) += snd-soc-imx-card.o diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 4f55b316cf0f..06107ae46e20 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -540,7 +540,6 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) struct device *codec_dev = NULL; const char *codec_dai_name; const char *codec_dev_name; - unsigned int daifmt; u32 width; int ret; @@ -684,10 +683,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } /* Format info from DT is optional. */ - daifmt = snd_soc_of_parse_daifmt(np, NULL, - &bitclkmaster, &framemaster); - daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; + snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkmaster, &framemaster); if (bitclkmaster || framemaster) { + unsigned int daifmt = snd_soc_daifmt_parse_format(np, NULL); + if (codec_np == bitclkmaster) daifmt |= (codec_np == framemaster) ? SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; @@ -709,7 +708,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) of_node_put(framemaster); if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) { - dev_err(&pdev->dev, "failed to find codec device\n"); + dev_dbg(&pdev->dev, "failed to find codec device\n"); ret = -EPROBE_DEFER; goto asrc_fail; } diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 0e1ad8efebd3..24b41881a68f 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1035,8 +1035,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) asrc->private = asrc_priv; /* Get the addresses and IRQ */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index a328697511f7..99ab7f0241cf 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -196,8 +196,7 @@ static int fsl_aud2htx_probe(struct platform_device *pdev) aud2htx->pdev = pdev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index b1765c7d3bcd..be14f84796cb 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1887,8 +1887,7 @@ static int fsl_easrc_probe(struct platform_device *pdev) easrc->private = easrc_priv; np = dev->of_node; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); @@ -1901,10 +1900,8 @@ static int fsl_easrc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "no irq for node %pOF\n", np); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, fsl_easrc_isr, 0, dev_name(dev), easrc); diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index f356ae5925af..a961f837cd09 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -969,8 +969,7 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->soc = of_device_get_match_data(&pdev->dev); /* Get the addresses and IRQ */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 3cf789ed6cbe..8c0c75ce9490 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -669,8 +669,7 @@ static int fsl_micfil_probe(struct platform_device *pdev) } /* init regmap */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 407a45e48eee..223fcd15bfcc 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1017,8 +1017,7 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index c631de325a6e..8ffb1a6048d6 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -49,6 +49,7 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; * @imx: for imx platform * @shared_root_clock: flag of sharing a clock source with others; * so the driver shouldn't set root clock rate + * @raw_capture_mode: if raw capture mode support * @interrupts: interrupt number * @tx_burst: tx maxburst size * @rx_burst: rx maxburst size @@ -57,6 +58,7 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; struct fsl_spdif_soc_data { bool imx; bool shared_root_clock; + bool raw_capture_mode; u32 interrupts; u32 tx_burst; u32 rx_burst; @@ -136,6 +138,7 @@ struct fsl_spdif_priv { static struct fsl_spdif_soc_data fsl_spdif_vf610 = { .imx = false, .shared_root_clock = false, + .raw_capture_mode = false, .interrupts = 1, .tx_burst = FSL_SPDIF_TXFIFO_WML, .rx_burst = FSL_SPDIF_RXFIFO_WML, @@ -145,6 +148,7 @@ static struct fsl_spdif_soc_data fsl_spdif_vf610 = { static struct fsl_spdif_soc_data fsl_spdif_imx35 = { .imx = true, .shared_root_clock = false, + .raw_capture_mode = false, .interrupts = 1, .tx_burst = FSL_SPDIF_TXFIFO_WML, .rx_burst = FSL_SPDIF_RXFIFO_WML, @@ -154,6 +158,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx35 = { static struct fsl_spdif_soc_data fsl_spdif_imx6sx = { .imx = true, .shared_root_clock = true, + .raw_capture_mode = false, .interrupts = 1, .tx_burst = FSL_SPDIF_TXFIFO_WML, .rx_burst = FSL_SPDIF_RXFIFO_WML, @@ -164,12 +169,23 @@ static struct fsl_spdif_soc_data fsl_spdif_imx6sx = { static struct fsl_spdif_soc_data fsl_spdif_imx8qm = { .imx = true, .shared_root_clock = true, + .raw_capture_mode = false, .interrupts = 2, .tx_burst = 2, /* Applied for EDMA */ .rx_burst = 2, /* Applied for EDMA */ .tx_formats = SNDRV_PCM_FMTBIT_S24_LE, /* Applied for EDMA */ }; +static struct fsl_spdif_soc_data fsl_spdif_imx8mm = { + .imx = true, + .shared_root_clock = false, + .raw_capture_mode = true, + .interrupts = 1, + .tx_burst = FSL_SPDIF_TXFIFO_WML, + .rx_burst = FSL_SPDIF_RXFIFO_WML, + .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK, +}; + /* Check if clk is a root clock that does not share clock source with others */ static inline bool fsl_spdif_can_set_clk_rate(struct fsl_spdif_priv *spdif, int clk) { @@ -846,6 +862,39 @@ static int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol, return 0; } +static int fsl_spdif_rx_rcm_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regmap = spdif_priv->regmap; + u32 val; + + regmap_read(regmap, REG_SPDIF_SCR, &val); + val = (val & SCR_RAW_CAPTURE_MODE) ? 1 : 0; + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static int fsl_spdif_rx_rcm_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regmap = spdif_priv->regmap; + u32 val = (ucontrol->value.integer.value[0] ? SCR_RAW_CAPTURE_MODE : 0); + + if (val) + cpu_dai->driver->capture.formats |= SNDRV_PCM_FMTBIT_S32_LE; + else + cpu_dai->driver->capture.formats &= ~SNDRV_PCM_FMTBIT_S32_LE; + + regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_RAW_CAPTURE_MODE, val); + + return 0; +} + /* DPLL lock information */ static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1029,6 +1078,19 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { }, }; +static struct snd_kcontrol_new fsl_spdif_ctrls_rcm[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Raw Capture Mode", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_WRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ctl_boolean_mono_info, + .get = fsl_spdif_rx_rcm_get, + .put = fsl_spdif_rx_rcm_put, + }, +}; + static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) { struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); @@ -1038,6 +1100,10 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); + if (spdif_private->soc->raw_capture_mode) + snd_soc_add_dai_controls(dai, fsl_spdif_ctrls_rcm, + ARRAY_SIZE(fsl_spdif_ctrls_rcm)); + /*Clear the val bit for Tx*/ regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR, SCR_VAL_MASK, SCR_VAL_CLEAR); @@ -1289,8 +1355,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) spdif_priv->soc->tx_formats; /* Get the addresses and IRQ */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); @@ -1302,10 +1367,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) for (i = 0; i < spdif_priv->soc->interrupts; i++) { irq = platform_get_irq(pdev, i); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, dev_name(&pdev->dev), spdif_priv); @@ -1375,22 +1438,38 @@ static int fsl_spdif_probe(struct platform_device *pdev) &spdif_priv->cpu_dai_drv, 1); if (ret) { dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); - return ret; + goto err_pm_disable; } ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); + if (ret) { + dev_err_probe(&pdev->dev, ret, "imx_pcm_dma_init failed\n"); + goto err_pm_disable; + } + + return ret; +err_pm_disable: + pm_runtime_disable(&pdev->dev); return ret; } +static int fsl_spdif_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + #ifdef CONFIG_PM static int fsl_spdif_runtime_suspend(struct device *dev) { struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); int i; + /* Disable all the interrupts */ + regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SIE, 0xffffff, 0); + regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, &spdif_priv->regcache_srpc); regcache_cache_only(spdif_priv->regmap, true); @@ -1476,6 +1555,7 @@ static const struct of_device_id fsl_spdif_dt_ids[] = { { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, }, { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, }, { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, }, + { .compatible = "fsl,imx8mm-spdif", .data = &fsl_spdif_imx8mm, }, {} }; MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); @@ -1487,6 +1567,7 @@ static struct platform_driver fsl_spdif_driver = { .pm = &fsl_spdif_pm, }, .probe = fsl_spdif_probe, + .remove = fsl_spdif_remove, }; module_platform_driver(fsl_spdif_driver); diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h index d5f1dfd58740..bff8290e71f2 100644 --- a/sound/soc/fsl/fsl_spdif.h +++ b/sound/soc/fsl/fsl_spdif.h @@ -63,6 +63,7 @@ #define SCR_TXFIFO_FSEL_IF4 (0x1 << SCR_TXFIFO_FSEL_OFFSET) #define SCR_TXFIFO_FSEL_IF8 (0x2 << SCR_TXFIFO_FSEL_OFFSET) #define SCR_TXFIFO_FSEL_IF12 (0x3 << SCR_TXFIFO_FSEL_OFFSET) +#define SCR_RAW_CAPTURE_MODE BIT(14) #define SCR_LOW_POWER (1 << 13) #define SCR_SOFT_RESET (1 << 12) #define SCR_TXFIFO_CTRL_OFFSET 10 diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2b57b60431bb..ecbc1c365d5b 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1503,8 +1503,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) } ssi->cpu_dai_drv.name = dev_name(dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iomem = devm_ioremap_resource(dev, res); + iomem = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(iomem)) return PTR_ERR(iomem); ssi->ssi_phys = res->start; diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 6cb558165848..fb7c29fc39d7 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -736,7 +736,7 @@ static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) /* clean current page, including data memory */ memset_io(xcvr->ram_addr, 0, size); } - }; + } err_firmware: release_firmware(fw); @@ -1202,6 +1202,10 @@ static int fsl_xcvr_probe(struct platform_device *pdev) rx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rxfifo"); tx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "txfifo"); + if (!rx_res || !tx_res) { + dev_err(dev, "could not find rxfifo or txfifo resource\n"); + return -EINVAL; + } xcvr->dma_prms_rx.chan_name = "rx"; xcvr->dma_prms_tx.chan_name = "tx"; xcvr->dma_prms_rx.addr = rx_res->start; @@ -1233,6 +1237,16 @@ static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) struct fsl_xcvr *xcvr = dev_get_drvdata(dev); int ret; + /* + * Clear interrupts, when streams starts or resumes after + * suspend, interrupts are enabled in prepare(), so no need + * to enable interrupts in resume(). + */ + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, + FSL_XCVR_IRQ_EARC_ALL, 0); + if (ret < 0) + dev_err(dev, "Failed to clear IER0: %d\n", ret); + /* Assert M0+ reset */ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, FSL_XCVR_EXT_CTRL_CORE_RESET, diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c index 50099bcaa9cd..905c3a071300 100644 --- a/sound/soc/fsl/imx-audio-rpmsg.c +++ b/sound/soc/fsl/imx-audio-rpmsg.c @@ -122,17 +122,7 @@ static struct rpmsg_driver imx_audio_rpmsg_driver = { .remove = imx_audio_rpmsg_remove, }; -static int __init imx_audio_rpmsg_init(void) -{ - return register_rpmsg_driver(&imx_audio_rpmsg_driver); -} - -static void __exit imx_audio_rpmsg_exit(void) -{ - unregister_rpmsg_driver(&imx_audio_rpmsg_driver); -} -module_init(imx_audio_rpmsg_init); -module_exit(imx_audio_rpmsg_exit); +module_rpmsg_driver(imx_audio_rpmsg_driver); MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface"); MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>"); diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index cbdc0a2c09c5..a364e2415de0 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -209,10 +209,8 @@ static int imx_audmix_probe(struct platform_device *pdev) /* for CPU/Codec/Platform x 2 */ dlc = devm_kcalloc(&pdev->dev, 6, sizeof(*dlc), GFP_KERNEL); - if (!dlc) { - dev_err(&pdev->dev, "failed to allocate dai_link\n"); + if (!dlc) return -ENOMEM; - } ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i, &args); diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c new file mode 100644 index 000000000000..58fd0639a069 --- /dev/null +++ b/sound/soc/fsl/imx-card.c @@ -0,0 +1,844 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017-2021 NXP + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/gpio/consumer.h> +#include <linux/of_device.h> +#include <linux/i2c.h> +#include <linux/of_gpio.h> +#include <linux/clk.h> +#include <sound/soc.h> +#include <sound/pcm_params.h> +#include <sound/pcm.h> +#include <sound/soc-dapm.h> +#include <sound/simple_card_utils.h> + +#include "fsl_sai.h" + +enum codec_type { + CODEC_DUMMY = 0, + CODEC_AK5558 = 1, + CODEC_AK4458, + CODEC_AK4497, + CODEC_AK5552, +}; + +/* + * Mapping LRCK fs and frame width, table 3 & 4 in datasheet + * @rmin: min rate + * @rmax: max rate + * @wmin: min frame ratio + * @wmax: max frame ratio + */ +struct imx_akcodec_fs_mul { + unsigned int rmin; + unsigned int rmax; + unsigned int wmin; + unsigned int wmax; +}; + +/* + * Mapping TDM mode and frame width + */ +struct imx_akcodec_tdm_fs_mul { + unsigned int min; + unsigned int max; + unsigned int mul; +}; + +/* + * struct imx_card_plat_data - specific info for codecs + * + * @fs_mul: ratio of mclk/fs for normal mode + * @tdm_fs_mul: ratio of mclk/fs for tdm mode + * @support_rates: supported sample rate + * @support_tdm_rates: supported sample rate for tdm mode + * @support_channels: supported channels + * @support_tdm_channels: supported channels for tdm mode + * @num_fs_mul: ARRAY_SIZE of fs_mul + * @num_tdm_fs_mul: ARRAY_SIZE of tdm_fs_mul + * @num_rates: ARRAY_SIZE of support_rates + * @num_tdm_rates: ARRAY_SIZE of support_tdm_rates + * @num_channels: ARRAY_SIZE of support_channels + * @num_tdm_channels: ARRAY_SIZE of support_tdm_channels + * @type: codec type + */ +struct imx_card_plat_data { + struct imx_akcodec_fs_mul *fs_mul; + struct imx_akcodec_tdm_fs_mul *tdm_fs_mul; + const u32 *support_rates; + const u32 *support_tdm_rates; + const u32 *support_channels; + const u32 *support_tdm_channels; + unsigned int num_fs_mul; + unsigned int num_tdm_fs_mul; + unsigned int num_rates; + unsigned int num_tdm_rates; + unsigned int num_channels; + unsigned int num_tdm_channels; + unsigned int num_codecs; + enum codec_type type; +}; + +/* + * struct dai_link_data - specific info for dai link + * + * @slots: slot number + * @slot_width: slot width value + * @cpu_sysclk_id: sysclk id for cpu dai + * @one2one_ratio: true if mclk equal to bclk + */ +struct dai_link_data { + unsigned int slots; + unsigned int slot_width; + unsigned int cpu_sysclk_id; + bool one2one_ratio; +}; + +/* + * struct imx_card_data - platform device data + * + * @plat_data: pointer of imx_card_plat_data + * @dapm_routes: pointer of dapm_routes + * @link_data: private data for dai link + * @card: card instance + * @num_dapm_routes: number of dapm_routes + * @asrc_rate: asrc rates + * @asrc_format: asrc format + */ +struct imx_card_data { + struct imx_card_plat_data *plat_data; + struct snd_soc_dapm_route *dapm_routes; + struct dai_link_data *link_data; + struct snd_soc_card card; + int num_dapm_routes; + u32 asrc_rate; + u32 asrc_format; +}; + +static struct imx_akcodec_fs_mul ak4458_fs_mul[] = { + /* Normal, < 32kHz */ + { .rmin = 8000, .rmax = 24000, .wmin = 1024, .wmax = 1024, }, + /* Normal, 32kHz */ + { .rmin = 32000, .rmax = 32000, .wmin = 256, .wmax = 1024, }, + /* Normal */ + { .rmin = 44100, .rmax = 48000, .wmin = 256, .wmax = 768, }, + /* Double */ + { .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 512, }, + /* Quad */ + { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 256, }, + /* Oct */ + { .rmin = 352800, .rmax = 384000, .wmin = 32, .wmax = 128, }, + /* Hex */ + { .rmin = 705600, .rmax = 768000, .wmin = 16, .wmax = 64, }, +}; + +static struct imx_akcodec_tdm_fs_mul ak4458_tdm_fs_mul[] = { + /* + * Table 13 - Audio Interface Format + * For TDM mode, MCLK should is set to + * obtained from 2 * slots * slot_width + */ + { .min = 128, .max = 128, .mul = 256 }, /* TDM128 */ + { .min = 256, .max = 256, .mul = 512 }, /* TDM256 */ + { .min = 512, .max = 512, .mul = 1024 }, /* TDM512 */ +}; + +static struct imx_akcodec_fs_mul ak4497_fs_mul[] = { + /** + * Table 7 - mapping multiplier and speed mode + * Tables 8 & 9 - mapping speed mode and LRCK fs + */ + { .rmin = 8000, .rmax = 32000, .wmin = 1024, .wmax = 1024, }, /* Normal, <= 32kHz */ + { .rmin = 44100, .rmax = 48000, .wmin = 512, .wmax = 512, }, /* Normal */ + { .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 256, }, /* Double */ + { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 128, }, /* Quad */ + { .rmin = 352800, .rmax = 384000, .wmin = 128, .wmax = 128, }, /* Oct */ + { .rmin = 705600, .rmax = 768000, .wmin = 64, .wmax = 64, }, /* Hex */ +}; + +/* + * Auto MCLK selection based on LRCK for Normal Mode + * (Table 4 from datasheet) + */ +static struct imx_akcodec_fs_mul ak5558_fs_mul[] = { + { .rmin = 8000, .rmax = 32000, .wmin = 1024, .wmax = 1024, }, + { .rmin = 44100, .rmax = 48000, .wmin = 512, .wmax = 512, }, + { .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 256, }, + { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 128, }, + { .rmin = 352800, .rmax = 384000, .wmin = 64, .wmax = 64, }, + { .rmin = 705600, .rmax = 768000, .wmin = 32, .wmax = 32, }, +}; + +/* + * MCLK and BCLK selection based on TDM mode + * because of SAI we also add the restriction: MCLK >= 2 * BCLK + * (Table 9 from datasheet) + */ +static struct imx_akcodec_tdm_fs_mul ak5558_tdm_fs_mul[] = { + { .min = 128, .max = 128, .mul = 256 }, + { .min = 256, .max = 256, .mul = 512 }, + { .min = 512, .max = 512, .mul = 1024 }, +}; + +static const u32 akcodec_rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, + 96000, 176400, 192000, 352800, 384000, 705600, 768000, +}; + +static const u32 akcodec_tdm_rates[] = { + 8000, 16000, 32000, 48000, 96000, +}; + +static const u32 ak4458_channels[] = { + 1, 2, 4, 6, 8, 10, 12, 14, 16, +}; + +static const u32 ak4458_tdm_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 16, +}; + +static const u32 ak5558_channels[] = { + 1, 2, 4, 6, 8, +}; + +static const u32 ak5558_tdm_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, +}; + +static bool format_is_dsd(struct snd_pcm_hw_params *params) +{ + snd_pcm_format_t format = params_format(params); + + switch (format) { + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_U16_BE: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + case SNDRV_PCM_FORMAT_DSD_U32_BE: + return true; + default: + return false; + } +} + +static bool format_is_tdm(struct dai_link_data *link_data) +{ + if (link_data->slots > 2) + return true; + else + return false; +} + +static bool codec_is_akcodec(unsigned int type) +{ + switch (type) { + case CODEC_AK4458: + case CODEC_AK4497: + case CODEC_AK5558: + case CODEC_AK5552: + return true; + default: + break; + } + return false; +} + +static unsigned long akcodec_get_mclk_rate(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct imx_card_data *data = snd_soc_card_get_drvdata(rtd->card); + const struct imx_card_plat_data *plat_data = data->plat_data; + struct dai_link_data *link_data = &data->link_data[rtd->num]; + unsigned int width = link_data->slots * link_data->slot_width; + unsigned int rate = params_rate(params); + int i; + + if (format_is_tdm(link_data)) { + for (i = 0; i < plat_data->num_tdm_fs_mul; i++) { + /* min = max = slots * slots_width */ + if (width != plat_data->tdm_fs_mul[i].min) + continue; + return rate * plat_data->tdm_fs_mul[i].mul; + } + } else { + for (i = 0; i < plat_data->num_fs_mul; i++) { + if (rate >= plat_data->fs_mul[i].rmin && + rate <= plat_data->fs_mul[i].rmax) { + width = max(width, plat_data->fs_mul[i].wmin); + width = min(width, plat_data->fs_mul[i].wmax); + + /* Adjust SAI bclk:mclk ratio */ + width *= link_data->one2one_ratio ? 1 : 2; + + return rate * width; + } + } + } + + /* Let DAI manage clk frequency by default */ + return 0; +} + +static int imx_aif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_card *card = rtd->card; + struct imx_card_data *data = snd_soc_card_get_drvdata(card); + struct dai_link_data *link_data = &data->link_data[rtd->num]; + struct imx_card_plat_data *plat_data = data->plat_data; + struct device *dev = card->dev; + struct snd_soc_dai *codec_dai; + unsigned long mclk_freq; + unsigned int fmt = rtd->dai_link->dai_fmt; + unsigned int slots, slot_width; + int ret, i; + + slots = link_data->slots; + slot_width = link_data->slot_width; + + if (!format_is_tdm(link_data)) { + if (format_is_dsd(params)) { + slots = 1; + slot_width = params_width(params); + fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | + SND_SOC_DAIFMT_PDM; + } else { + slots = 2; + slot_width = params_physical_width(params); + fmt = (rtd->dai_link->dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | + SND_SOC_DAIFMT_I2S; + } + } + + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set cpu dai fmt: %d\n", ret); + return ret; + } + ret = snd_soc_dai_set_tdm_slot(cpu_dai, + BIT(slots) - 1, + BIT(slots) - 1, + slots, slot_width); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret); + return ret; + } + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set codec dai[%d] fmt: %d\n", i, ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(codec_dai, + BIT(slots) - 1, + BIT(slots) - 1, + slots, slot_width); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); + return ret; + } + } + + /* Set MCLK freq */ + if (codec_is_akcodec(plat_data->type)) + mclk_freq = akcodec_get_mclk_rate(substream, params); + else + mclk_freq = params_rate(params) * slots * slot_width; + /* Use the maximum freq from DSD512 (512*44100 = 22579200) */ + if (format_is_dsd(params)) + mclk_freq = 22579200; + + ret = snd_soc_dai_set_sysclk(cpu_dai, link_data->cpu_sysclk_id, mclk_freq, + SND_SOC_CLOCK_OUT); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n", mclk_freq, ret); + return ret; + } + + return 0; +} + +static int ak5558_hw_rule_rate(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *r) +{ + struct dai_link_data *link_data = r->private; + struct snd_interval t = { .min = 8000, .max = 8000, }; + unsigned long mclk_freq; + unsigned int fs; + int i; + + fs = hw_param_interval(p, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; + fs *= link_data->slots; + + /* Identify maximum supported rate */ + for (i = 0; i < ARRAY_SIZE(akcodec_rates); i++) { + mclk_freq = fs * akcodec_rates[i]; + /* Adjust SAI bclk:mclk ratio */ + mclk_freq *= link_data->one2one_ratio ? 1 : 2; + + /* Skip rates for which MCLK is beyond supported value */ + if (mclk_freq > 36864000) + continue; + + if (t.max < akcodec_rates[i]) + t.max = akcodec_rates[i]; + } + + return snd_interval_refine(hw_param_interval(p, r->var), &t); +} + +static int imx_aif_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct imx_card_data *data = snd_soc_card_get_drvdata(card); + struct dai_link_data *link_data = &data->link_data[rtd->num]; + static struct snd_pcm_hw_constraint_list constraint_rates; + static struct snd_pcm_hw_constraint_list constraint_channels; + int ret = 0; + + if (format_is_tdm(link_data)) { + constraint_channels.list = data->plat_data->support_tdm_channels; + constraint_channels.count = data->plat_data->num_tdm_channels; + constraint_rates.list = data->plat_data->support_tdm_rates; + constraint_rates.count = data->plat_data->num_tdm_rates; + } else { + constraint_channels.list = data->plat_data->support_channels; + constraint_channels.count = data->plat_data->num_channels; + constraint_rates.list = data->plat_data->support_rates; + constraint_rates.count = data->plat_data->num_rates; + } + + if (constraint_channels.count) { + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraint_channels); + if (ret) + return ret; + } + + if (constraint_rates.count) { + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraint_rates); + if (ret) + return ret; + } + + if (data->plat_data->type == CODEC_AK5558) + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + ak5558_hw_rule_rate, link_data, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); + + return ret; +} + +static struct snd_soc_ops imx_aif_ops = { + .hw_params = imx_aif_hw_params, + .startup = imx_aif_startup, +}; + +static struct snd_soc_ops imx_aif_ops_be = { + .hw_params = imx_aif_hw_params, +}; + +static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_card *card = rtd->card; + struct imx_card_data *data = snd_soc_card_get_drvdata(card); + struct snd_interval *rate; + struct snd_mask *mask; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + rate->max = data->asrc_rate; + rate->min = data->asrc_rate; + + mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_none(mask); + snd_mask_set(mask, data->asrc_format); + + return 0; +} + +static int imx_card_parse_of(struct imx_card_data *data) +{ + struct imx_card_plat_data *plat_data = data->plat_data; + struct snd_soc_card *card = &data->card; + struct snd_soc_dai_link_component *dlc; + struct device_node *platform = NULL; + struct device_node *codec = NULL; + struct device_node *cpu = NULL; + struct device_node *np; + struct device *dev = card->dev; + struct snd_soc_dai_link *link; + struct dai_link_data *link_data; + struct of_phandle_args args; + int ret, num_links; + u32 width; + + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret) { + dev_err(dev, "Error parsing card name: %d\n", ret); + return ret; + } + + /* DAPM routes */ + if (of_property_read_bool(dev->of_node, "audio-routing")) { + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) + return ret; + } + + /* Populate links */ + num_links = of_get_child_count(dev->of_node); + + /* Allocate the DAI link array */ + card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); + if (!card->dai_link) + return -ENOMEM; + + data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); + if (!data->link_data) + return -ENOMEM; + + card->num_links = num_links; + link = card->dai_link; + link_data = data->link_data; + + for_each_child_of_node(dev->of_node, np) { + dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL); + if (!dlc) { + ret = -ENOMEM; + goto err_put_np; + } + + link->cpus = &dlc[0]; + link->platforms = &dlc[1]; + + link->num_cpus = 1; + link->num_platforms = 1; + + ret = of_property_read_string(np, "link-name", &link->name); + if (ret) { + dev_err(card->dev, "error getting codec dai_link name\n"); + goto err_put_np; + } + + cpu = of_get_child_by_name(np, "cpu"); + if (!cpu) { + dev_err(dev, "%s: Can't find cpu DT node\n", link->name); + ret = -EINVAL; + goto err; + } + + ret = of_parse_phandle_with_args(cpu, "sound-dai", + "#sound-dai-cells", 0, &args); + if (ret) { + dev_err(card->dev, "%s: error getting cpu phandle\n", link->name); + goto err; + } + + if (of_node_name_eq(args.np, "sai")) { + /* sai sysclk id */ + link_data->cpu_sysclk_id = FSL_SAI_CLK_MAST1; + + /* sai may support mclk/bclk = 1 */ + if (of_find_property(np, "fsl,mclk-equal-bclk", NULL)) + link_data->one2one_ratio = true; + } + + link->cpus->of_node = args.np; + link->platforms->of_node = link->cpus->of_node; + link->id = args.args[0]; + + ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(card->dev, "%s: error getting cpu dai name: %d\n", + link->name, ret); + goto err; + } + + codec = of_get_child_by_name(np, "codec"); + if (codec) { + ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "%s: codec dai not found: %d\n", + link->name, ret); + goto err; + } + + plat_data->num_codecs = link->num_codecs; + + /* Check the akcodec type */ + if (!strcmp(link->codecs->dai_name, "ak4458-aif")) + plat_data->type = CODEC_AK4458; + else if (!strcmp(link->codecs->dai_name, "ak4497-aif")) + plat_data->type = CODEC_AK4497; + else if (!strcmp(link->codecs->dai_name, "ak5558-aif")) + plat_data->type = CODEC_AK5558; + else if (!strcmp(link->codecs->dai_name, "ak5552-aif")) + plat_data->type = CODEC_AK5552; + + } else { + dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL); + if (!dlc) { + ret = -ENOMEM; + goto err; + } + + link->codecs = dlc; + link->num_codecs = 1; + + link->codecs->dai_name = "snd-soc-dummy-dai"; + link->codecs->name = "snd-soc-dummy"; + } + + if (!strncmp(link->name, "HiFi-ASRC-FE", 12)) { + /* DPCM frontend */ + link->dynamic = 1; + link->dpcm_merged_chan = 1; + + ret = of_property_read_u32(args.np, "fsl,asrc-rate", &data->asrc_rate); + if (ret) { + dev_err(dev, "failed to get output rate\n"); + ret = -EINVAL; + goto err; + } + + ret = of_property_read_u32(args.np, "fsl,asrc-format", &data->asrc_format); + if (ret) { + /* Fallback to old binding; translate to asrc_format */ + ret = of_property_read_u32(args.np, "fsl,asrc-width", &width); + if (ret) { + dev_err(dev, + "failed to decide output format\n"); + goto err; + } + + if (width == 24) + data->asrc_format = SNDRV_PCM_FORMAT_S24_LE; + else + data->asrc_format = SNDRV_PCM_FORMAT_S16_LE; + } + } else if (!strncmp(link->name, "HiFi-ASRC-BE", 12)) { + /* DPCM backend */ + link->no_pcm = 1; + link->platforms->of_node = NULL; + link->platforms->name = "snd-soc-dummy"; + + link->be_hw_params_fixup = be_hw_params_fixup; + link->ops = &imx_aif_ops_be; + } else { + link->ops = &imx_aif_ops; + } + + if (link->no_pcm || link->dynamic) + snd_soc_dai_link_set_capabilities(link); + + /* Get dai fmt */ + ret = asoc_simple_parse_daifmt(dev, np, codec, + NULL, &link->dai_fmt); + if (ret) + link->dai_fmt = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_I2S; + + /* Get tdm slot */ + snd_soc_of_parse_tdm_slot(np, NULL, NULL, + &link_data->slots, + &link_data->slot_width); + /* default value */ + if (!link_data->slots) + link_data->slots = 2; + + if (!link_data->slot_width) + link_data->slot_width = 32; + + link->ignore_pmdown_time = 1; + link->stream_name = link->name; + link++; + link_data++; + + of_node_put(cpu); + of_node_put(codec); + of_node_put(platform); + } + + return 0; +err: + of_node_put(cpu); + of_node_put(codec); + of_node_put(platform); +err_put_np: + of_node_put(np); + return ret; +} + +static int imx_card_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *link_be = NULL, *link; + struct imx_card_plat_data *plat_data; + struct imx_card_data *data; + int ret, i; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + plat_data = devm_kzalloc(&pdev->dev, sizeof(*plat_data), GFP_KERNEL); + if (!plat_data) + return -ENOMEM; + + data->plat_data = plat_data; + data->card.dev = &pdev->dev; + + dev_set_drvdata(&pdev->dev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = imx_card_parse_of(data); + if (ret) + return ret; + + data->num_dapm_routes = plat_data->num_codecs + 1; + data->dapm_routes = devm_kcalloc(&pdev->dev, data->num_dapm_routes, + sizeof(struct snd_soc_dapm_route), + GFP_KERNEL); + if (!data->dapm_routes) + return -ENOMEM; + + /* configure the dapm routes */ + switch (plat_data->type) { + case CODEC_AK4458: + case CODEC_AK4497: + if (plat_data->num_codecs == 1) { + data->dapm_routes[0].sink = "Playback"; + data->dapm_routes[0].source = "CPU-Playback"; + i = 1; + } else { + for (i = 0; i < plat_data->num_codecs; i++) { + data->dapm_routes[i].sink = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s", + i + 1, "Playback"); + data->dapm_routes[i].source = "CPU-Playback"; + } + } + data->dapm_routes[i].sink = "CPU-Playback"; + data->dapm_routes[i].source = "ASRC-Playback"; + break; + case CODEC_AK5558: + case CODEC_AK5552: + if (plat_data->num_codecs == 1) { + data->dapm_routes[0].sink = "CPU-Capture"; + data->dapm_routes[0].source = "Capture"; + i = 1; + } else { + for (i = 0; i < plat_data->num_codecs; i++) { + data->dapm_routes[i].source = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s", + i + 1, "Capture"); + data->dapm_routes[i].sink = "CPU-Capture"; + } + } + data->dapm_routes[i].sink = "ASRC-Capture"; + data->dapm_routes[i].source = "CPU-Capture"; + break; + default: + break; + } + + /* default platform data for akcodecs */ + if (codec_is_akcodec(plat_data->type)) { + plat_data->support_rates = akcodec_rates; + plat_data->num_rates = ARRAY_SIZE(akcodec_rates); + plat_data->support_tdm_rates = akcodec_tdm_rates; + plat_data->num_tdm_rates = ARRAY_SIZE(akcodec_tdm_rates); + + switch (plat_data->type) { + case CODEC_AK4458: + plat_data->fs_mul = ak4458_fs_mul; + plat_data->num_fs_mul = ARRAY_SIZE(ak4458_fs_mul); + plat_data->tdm_fs_mul = ak4458_tdm_fs_mul; + plat_data->num_tdm_fs_mul = ARRAY_SIZE(ak4458_tdm_fs_mul); + plat_data->support_channels = ak4458_channels; + plat_data->num_channels = ARRAY_SIZE(ak4458_channels); + plat_data->support_tdm_channels = ak4458_tdm_channels; + plat_data->num_tdm_channels = ARRAY_SIZE(ak4458_tdm_channels); + break; + case CODEC_AK4497: + plat_data->fs_mul = ak4497_fs_mul; + plat_data->num_fs_mul = ARRAY_SIZE(ak4497_fs_mul); + plat_data->support_channels = ak4458_channels; + plat_data->num_channels = ARRAY_SIZE(ak4458_channels); + break; + case CODEC_AK5558: + case CODEC_AK5552: + plat_data->fs_mul = ak5558_fs_mul; + plat_data->num_fs_mul = ARRAY_SIZE(ak5558_fs_mul); + plat_data->tdm_fs_mul = ak5558_tdm_fs_mul; + plat_data->num_tdm_fs_mul = ARRAY_SIZE(ak5558_tdm_fs_mul); + plat_data->support_channels = ak5558_channels; + plat_data->num_channels = ARRAY_SIZE(ak5558_channels); + plat_data->support_tdm_channels = ak5558_tdm_channels; + plat_data->num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels); + break; + default: + break; + } + } + + /* with asrc as front end */ + if (data->card.num_links == 3) { + data->card.dapm_routes = data->dapm_routes; + data->card.num_dapm_routes = data->num_dapm_routes; + for_each_card_prelinks(&data->card, i, link) { + if (link->no_pcm == 1) + link_be = link; + } + for_each_card_prelinks(&data->card, i, link) { + if (link->dynamic == 1 && link_be) { + link->dpcm_playback = link_be->dpcm_playback; + link->dpcm_capture = link_be->dpcm_capture; + } + } + } + + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id imx_card_dt_ids[] = { + { .compatible = "fsl,imx-audio-card", }, + { }, +}; +MODULE_DEVICE_TABLE(of, imx_card_dt_ids); + +static struct platform_driver imx_card_driver = { + .driver = { + .name = "imx-card", + .pm = &snd_soc_pm_ops, + .of_match_table = imx_card_dt_ids, + }, + .probe = imx_card_probe, +}; +module_platform_driver(imx_card_driver); + +MODULE_DESCRIPTION("Freescale i.MX ASoC Machine Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx-card"); diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index fad1eb6253d5..1981dcd7e930 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -193,7 +193,7 @@ static int imx_es8328_probe(struct platform_device *pdev) data->card.owner = THIS_MODULE; data->card.dai_link = &data->dai; - ret = snd_soc_register_card(&data->card); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(dev, "Unable to register: %d\n", ret); goto put_device; @@ -209,15 +209,6 @@ fail: return ret; } -static int imx_es8328_remove(struct platform_device *pdev) -{ - struct imx_es8328_data *data = platform_get_drvdata(pdev); - - snd_soc_unregister_card(&data->card); - - return 0; -} - static const struct of_device_id imx_es8328_dt_ids[] = { { .compatible = "fsl,imx-audio-es8328", }, { /* sentinel */ } @@ -230,7 +221,6 @@ static struct platform_driver imx_es8328_driver = { .of_match_table = imx_es8328_dt_ids, }, .probe = imx_es8328_probe, - .remove = imx_es8328_remove, }; module_platform_driver(imx_es8328_driver); diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index 875c0d6df339..6d6c44cf3451 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -161,10 +161,10 @@ static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component, msg->s_msg.param.format = RPMSG_S24_LE; break; case SNDRV_PCM_FORMAT_DSD_U16_LE: - msg->s_msg.param.format = SNDRV_PCM_FORMAT_DSD_U16_LE; + msg->s_msg.param.format = RPMSG_DSD_U16_LE; break; case SNDRV_PCM_FORMAT_DSD_U32_LE: - msg->s_msg.param.format = SNDRV_PCM_FORMAT_DSD_U32_LE; + msg->s_msg.param.format = RPMSG_DSD_U32_LE; break; default: msg->s_msg.param.format = RPMSG_S32_LE; @@ -544,7 +544,7 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component, struct rpmsg_msg *msg; unsigned long flags; int buffer_tail = 0; - int written_num = 0; + int written_num; if (!rpmsg->force_lpa) return 0; diff --git a/sound/soc/fsl/imx-pcm-rpmsg.h b/sound/soc/fsl/imx-pcm-rpmsg.h index 308d153920a3..8286b55f00ae 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.h +++ b/sound/soc/fsl/imx-pcm-rpmsg.h @@ -328,9 +328,9 @@ #define RPMSG_S16_LE 0x0 #define RPMSG_S24_LE 0x1 #define RPMSG_S32_LE 0x2 -#define RPMSG_DSD_U16_LE 0x3 +#define RPMSG_DSD_U16_LE 49 /* SNDRV_PCM_FORMAT_DSD_U16_LE */ #define RPMSG_DSD_U24_LE 0x4 -#define RPMSG_DSD_U32_LE 0x5 +#define RPMSG_DSD_U32_LE 50 /* SNDRV_PCM_FORMAT_DSD_U32_LE */ #define RPMSG_CH_LEFT 0x0 #define RPMSG_CH_RIGHT 0x1 diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index 5a9a470d203f..f0cae8c59d54 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -137,7 +137,6 @@ fail: static struct platform_driver imx_rpmsg_driver = { .driver = { .name = "imx-audio-rpmsg", - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, }, .probe = imx_rpmsg_probe, diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index fa1247f0dda1..677f7da93b4b 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -61,10 +61,9 @@ int asoc_simple_parse_daifmt(struct device *dev, struct device_node *framemaster = NULL; unsigned int daifmt; - daifmt = snd_soc_of_parse_daifmt(node, prefix, - &bitclkmaster, &framemaster); - daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; + daifmt = snd_soc_daifmt_parse_format(node, prefix); + snd_soc_daifmt_parse_clock_provider_as_phandle(node, prefix, &bitclkmaster, &framemaster); if (!bitclkmaster && !framemaster) { /* * No dai-link level and master setting was not found from @@ -73,15 +72,10 @@ int asoc_simple_parse_daifmt(struct device *dev, */ dev_dbg(dev, "Revert to legacy daifmt parsing\n"); - daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | - (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); + daifmt |= snd_soc_daifmt_parse_clock_provider_as_flag(codec, NULL); } else { - if (codec == bitclkmaster) - daifmt |= (codec == framemaster) ? - SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; - else - daifmt |= (codec == framemaster) ? - SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; + daifmt |= snd_soc_daifmt_clock_provider_from_bitmap( + ((codec == bitclkmaster) << 4) | (codec == framemaster)); } of_node_put(bitclkmaster); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 0015f534d42d..a3a7990b5cb6 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -621,6 +621,7 @@ static int asoc_simple_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dev = dev; card->probe = simple_soc_probe; + card->driver_name = "simple-card"; li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); if (!li) diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 907f5f1f7b44..a297d4af5099 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -102,18 +102,15 @@ static int hi6210_i2s_startup(struct snd_pcm_substream *substream, for (n = 0; n < i2s->clocks; n++) { ret = clk_prepare_enable(i2s->clk[n]); - if (ret) { - while (n--) - clk_disable_unprepare(i2s->clk[n]); - return ret; - } + if (ret) + goto err_unprepare_clk; } ret = clk_set_rate(i2s->clk[CLK_I2S_BASE], 49152000); if (ret) { dev_err(i2s->dev, "%s: setting 49.152MHz base rate failed %d\n", __func__, ret); - return ret; + goto err_unprepare_clk; } /* enable clock before frequency division */ @@ -165,6 +162,11 @@ static int hi6210_i2s_startup(struct snd_pcm_substream *substream, hi6210_write_reg(i2s, HII2S_SW_RST_N, val); return 0; + +err_unprepare_clk: + while (n--) + clk_disable_unprepare(i2s->clk[n]); + return ret; } static void hi6210_i2s_shutdown(struct snd_pcm_substream *substream, @@ -554,8 +556,7 @@ static int hi6210_i2s_probe(struct platform_device *pdev) i2s->dev = dev; spin_lock_init(&i2s->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2s->base = devm_ioremap_resource(dev, res); + i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2s->base)) return PTR_ERR(i2s->base); diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index 0843235d73c9..1bf5d6edbd32 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -434,8 +434,7 @@ static int img_i2s_in_probe(struct platform_device *pdev) i2s->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); @@ -464,7 +463,7 @@ static int img_i2s_in_probe(struct platform_device *pdev) if (ret) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) goto err_suspend; diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index b56a18e7f3ac..4f90d36dc7df 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -440,8 +440,7 @@ static int img_i2s_out_probe(struct platform_device *pdev) i2s->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index 4da49a42e854..ce0f08d3777c 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -222,8 +222,7 @@ static int img_prl_out_probe(struct platform_device *pdev) prl->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 46ff8a3621d5..6364eb742f6d 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -732,8 +732,7 @@ static int img_spdif_in_probe(struct platform_device *pdev) spdif->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index b1d8e4535726..858e1b853820 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -335,8 +335,7 @@ static int img_spdif_out_probe(struct platform_device *pdev) spdif->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 58379393b8e4..7e29b0d911e2 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -26,6 +26,12 @@ config SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES interface. If unsure select N. +config SND_SOC_INTEL_HDA_DSP_COMMON + tristate + +config SND_SOC_INTEL_SOF_MAXIM_COMMON + tristate + if SND_SOC_INTEL_CATPT config SND_SOC_INTEL_HASWELL_MACH @@ -278,6 +284,7 @@ config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_SOC_MAX98390 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON tristate @@ -304,6 +311,7 @@ config SND_SOC_INTEL_BXT_RT298_MACH select SND_SOC_RT298 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON help This adds support for ASoC machine driver for Broxton platforms with RT286 I2S audio codec. @@ -422,6 +430,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH select SND_SOC_MAX98357A select SND_SOC_DMIC select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON help This adds support for ASoC machine driver for Geminilake platforms with RT5682 + MAX98357A I2S audio codec. @@ -433,15 +442,17 @@ endif ## SND_SOC_SOF_GEMINILAKE if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH - tristate "SKL/KBL/BXT/APL with HDA Codecs" + tristate "Skylake+ with HDA Codecs" depends on SND_HDA_CODEC_HDMI depends on GPIOLIB select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected help - This adds support for ASoC machine driver for Intel platforms - SKL/KBL/BXT/APL with iDisp, HDA audio codecs. + This adds support for ASoC machine driver for Intel Skylake+ + platforms with display (HDMI/DP) and HDA audio codecs, and + Smart Sound Technology (SST) integrated audio DSP. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". @@ -461,18 +472,38 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_RT5682_I2C select SND_SOC_DMIC select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_MAXIM_COMMON help This adds support for ASoC machine driver for SOF platforms with rt5682 codec. Say Y if you have such a device. If unsure select "N". +config SND_SOC_INTEL_SOF_CS42L42_MACH + tristate "SOF with cs42l42 codec in I2S Mode" + depends on I2C && ACPI + depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\ + (MFD_INTEL_LPSS || COMPILE_TEST)) + select SND_SOC_CS42L42 + select SND_SOC_MAX98357A + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_MAXIM_COMMON + help + This adds support for ASoC machine driver for SOF platforms + with cs42l42 codec. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_INTEL_SOF_PCM512x_MACH tristate "SOF with TI PCM512x codec" depends on I2C && ACPI depends on (SND_SOC_SOF_HDA_AUDIO_CODEC && (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) depends on SND_HDA_CODEC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_PCM512x_I2C help This adds support for ASoC machine driver for SOF platforms @@ -504,6 +535,7 @@ config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH select SND_SOC_RT5682_I2C select SND_SOC_DMIC select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_HDA_DSP_COMMON help This adds support for ASoC machine driver for SOF platform with RT1011 + RT5682 I2S codec. @@ -519,6 +551,7 @@ config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH depends on I2C && ACPI && GPIOLIB depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC + select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_DA7219 select SND_SOC_MAX98373_I2C select SND_SOC_DMIC @@ -539,6 +572,7 @@ config SND_SOC_INTEL_EHL_RT5660_MACH depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_RT5660 select SND_SOC_DMIC + select SND_SOC_INTEL_HDA_DSP_COMMON help This adds support for ASoC machine driver for Elkhart Lake platform with RT5660 I2S audio codec. @@ -566,6 +600,8 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT5682_SDW select SND_SOC_DMIC + select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_MAXIM_COMMON help Add support for Intel SoundWire-based platforms connected to MAX98373, RT700, RT711, RT1308 and RT715 @@ -573,5 +609,4 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH endif - endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 616c5fbab7d5..ed21b82a4cf6 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -3,11 +3,11 @@ snd-soc-sst-haswell-objs := haswell.o snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o snd-soc-sst-broadwell-objs := broadwell.o -snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o hda_dsp_common.o -snd-soc-sst-bxt-rt298-objs := bxt_rt298.o hda_dsp_common.o -snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o hda_dsp_common.o +snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o +snd-soc-sst-bxt-rt298-objs := bxt_rt298.o +snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o snd-soc-sst-sof-wm8804-objs := sof_wm8804.o -snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o +snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o snd-soc-sst-bytcr-wm5102-objs := bytcr_wm5102.o @@ -19,28 +19,29 @@ snd-soc-sst-byt-cht-cx2072x-objs := bytcht_cx2072x.o snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o -snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o sof_maxim_common.o sof_realtek_common.o -snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o hda_dsp_common.o +snd-soc-sof_rt5682-objs := sof_rt5682.o sof_realtek_common.o +snd-soc-sof_cs42l42-objs := sof_cs42l42.o +snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-kbl_rt5660-objs := kbl_rt5660.o snd-soc-skl_rt286-objs := skl_rt286.o -snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_common.o +snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o -snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o -snd-soc-ehl-rt5660-objs := ehl_rt5660.o hda_dsp_common.o +snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o +snd-soc-ehl-rt5660-objs := ehl_rt5660.o snd-soc-sof-sdw-objs += sof_sdw.o \ sof_sdw_max98373.o \ sof_sdw_rt1308.o sof_sdw_rt1316.o \ sof_sdw_rt5682.o sof_sdw_rt700.o \ sof_sdw_rt711.o sof_sdw_rt711_sdca.o \ sof_sdw_rt715.o sof_sdw_rt715_sdca.o \ - sof_maxim_common.o \ - sof_sdw_dmic.o sof_sdw_hdmi.o hda_dsp_common.o + sof_sdw_dmic.o sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o @@ -74,3 +75,10 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o obj-$(CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH) += snd-soc-ehl-rt5660.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH) += snd-soc-sof-sdw.o + +# common modules +snd-soc-intel-hda-dsp-common-objs := hda_dsp_common.o +obj-$(CONFIG_SND_SOC_INTEL_HDA_DSP_COMMON) += snd-soc-intel-hda-dsp-common.o + +snd-soc-intel-sof-maxim-common-objs += sof_maxim_common.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_MAXIM_COMMON) += snd-soc-intel-sof-maxim-common.o diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 021bc59aac80..e01b7a90ca6c 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -423,10 +423,8 @@ static int bdw_rt5677_probe(struct platform_device *pdev) /* Allocate driver private struct */ bdw_rt5677 = devm_kzalloc(&pdev->dev, sizeof(struct bdw_rt5677_priv), GFP_KERNEL); - if (!bdw_rt5677) { - dev_err(&pdev->dev, "Can't allocate bdw_rt5677\n"); + if (!bdw_rt5677) return -ENOMEM; - } /* override plaform name, if required */ mach = pdev->dev.platform_data; diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 9ffef396f8f2..e67ddfb8e469 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -840,11 +840,12 @@ static int broxton_audio_probe(struct platform_device *pdev) } static const struct platform_device_id bxt_board_ids[] = { - { .name = "bxt_da7219_max98357a" }, - { .name = "glk_da7219_max98357a" }, - { .name = "cml_da7219_max98357a" }, + { .name = "bxt_da7219_mx98357a" }, + { .name = "glk_da7219_mx98357a" }, + { .name = "cml_da7219_mx98357a" }, { } }; +MODULE_DEVICE_TABLE(platform, bxt_board_ids); static struct platform_driver broxton_audio = { .probe = broxton_audio_probe, @@ -866,6 +867,4 @@ MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bxt_da7219_max98357a"); -MODULE_ALIAS("platform:glk_da7219_max98357a"); -MODULE_ALIAS("platform:cml_da7219_max98357a"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 0f3157dfa838..47f6b1523ae6 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -649,6 +649,7 @@ static const struct platform_device_id bxt_board_ids[] = { (unsigned long)&geminilake_rt298 }, {} }; +MODULE_DEVICE_TABLE(platform, bxt_board_ids); static struct platform_driver broxton_audio = { .probe = broxton_audio_probe, @@ -665,5 +666,4 @@ MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>"); MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>"); MODULE_DESCRIPTION("Intel SST Audio for Broxton"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bxt_alc298s_i2s"); -MODULE_ALIAS("platform:glk_alc298s_i2s"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 2bfe3e4c696f..a9e51bbf018c 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -198,7 +198,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { | SND_SOC_DAIFMT_CBS_CFS, .init = byt_cht_cx2072x_init, .be_hw_params_fixup = byt_cht_cx2072x_fixup, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2, cx2072x, platform), diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index cfeba27252ba..a28773fb7892 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -197,7 +197,6 @@ static struct snd_soc_dai_link dailink[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = codec_fixup, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .ops = &ssp2_ops, diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 06df2d46d910..a0af91580184 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -337,7 +337,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = byt_cht_es8316_codec_fixup, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .init = byt_cht_es8316_init, diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 8c0dab1f4030..9b48fe701a2c 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -144,7 +144,6 @@ static struct snd_soc_dai_link dais[] = { | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = codec_fixup, .ignore_suspend = 1, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2_port, dummy, platform), diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 22dbd9d93c1e..91a6d712eb58 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1205,7 +1205,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = byt_rt5640_codec_fixup, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .init = byt_rt5640_init, diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 148b7b1bd3e8..e13c0c63a949 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -786,7 +786,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = byt_rt5651_codec_fixup, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .init = byt_rt5651_init, diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index 8d8ab9be256f..580d5fddae5a 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -351,7 +351,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = byt_wm5102_codec_fixup, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .init = byt_wm5102_init, diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 6fea554cfed5..804dbc7911d5 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -471,7 +471,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e358632f50d7..9509b6e161b8 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -375,7 +375,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .name = "SSP2-Codec", .id = 0, .no_pcm = 1, - .nonatomic = true, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, .dpcm_playback = 1, diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c index 14813beb33d1..27615acddacd 100644 --- a/sound/soc/intel/boards/cml_rt1011_rt5682.c +++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c @@ -594,3 +594,4 @@ MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:cml_rt1011_rt5682"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index 7c0d4e915406..d5235c294c4c 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -181,7 +181,6 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .dpcm_playback = 1, .dpcm_capture = 1, .ops = &rt5660_ops, - .nonatomic = true, SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform), }, { @@ -305,6 +304,7 @@ static const struct platform_device_id ehl_board_ids[] = { { .name = "ehl_rt5660" }, { } }; +MODULE_DEVICE_TABLE(platform, ehl_board_ids); static struct platform_driver snd_ehl_rt5660_driver = { .driver = { @@ -320,4 +320,4 @@ module_platform_driver(snd_ehl_rt5660_driver); MODULE_DESCRIPTION("ASoC Intel(R) Elkhartlake + rt5660 Machine driver"); MODULE_AUTHOR("libin.yang@intel.com"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:ehl_rt5660"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index 62cca511522e..71fe26a1b701 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -619,12 +619,13 @@ static int geminilake_audio_probe(struct platform_device *pdev) static const struct platform_device_id glk_board_ids[] = { { - .name = "glk_rt5682_max98357a", + .name = "glk_rt5682_mx98357a", .driver_data = (kernel_ulong_t)&glk_audio_card_rt5682_m98357a, }, { } }; +MODULE_DEVICE_TABLE(platform, glk_board_ids); static struct platform_driver geminilake_audio = { .probe = geminilake_audio_probe, @@ -641,4 +642,4 @@ MODULE_DESCRIPTION("Geminilake Audio Machine driver-RT5682 & MAX98357A in I2S mo MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:glk_rt5682_max98357a"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index 91ad2a0ad1ce..efdc4bc4bb1f 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -2,6 +2,7 @@ // // Copyright(c) 2019 Intel Corporation. All rights reserved. +#include <linux/module.h> #include <sound/pcm.h> #include <sound/soc.h> #include <sound/hda_codec.h> @@ -82,5 +83,9 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, return err; } +EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, SND_SOC_INTEL_HDA_DSP_COMMON); #endif + +MODULE_DESCRIPTION("ASoC Intel HDMI helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index c0d8a73c6d21..14b625e947f5 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -644,12 +644,13 @@ static int kabylake_audio_probe(struct platform_device *pdev) static const struct platform_device_id kbl_board_ids[] = { { - .name = "kbl_da7219_max98357a", + .name = "kbl_da7219_mx98357a", .driver_data = (kernel_ulong_t)&kabylake_audio_card_da7219_m98357a, }, { } }; +MODULE_DEVICE_TABLE(platform, kbl_board_ids); static struct platform_driver kabylake_audio = { .probe = kabylake_audio_probe, @@ -666,4 +667,3 @@ module_platform_driver(kabylake_audio) MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode"); MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_da7219_max98357a"); diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 4b7b4a044f81..a31a7a7bbf66 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -1175,6 +1175,7 @@ static const struct platform_device_id kbl_board_ids[] = { }, { } }; +MODULE_DEVICE_TABLE(platform, kbl_board_ids); static struct platform_driver kabylake_audio = { .probe = kabylake_audio_probe, @@ -1191,7 +1192,3 @@ module_platform_driver(kabylake_audio) MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927/MAX98373 & DA7219"); MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_da7219_max98927"); -MODULE_ALIAS("platform:kbl_max98927"); -MODULE_ALIAS("platform:kbl_da7219_max98373"); -MODULE_ALIAS("platform:kbl_max98373"); diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c index 3a9f91b58e11..289ca39b8206 100644 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ b/sound/soc/intel/boards/kbl_rt5660.c @@ -548,6 +548,7 @@ static const struct platform_device_id kbl_board_ids[] = { }, { } }; +MODULE_DEVICE_TABLE(platform, kbl_board_ids); static struct platform_driver kabylake_audio = { .probe = kabylake_audio_probe, @@ -564,4 +565,3 @@ module_platform_driver(kabylake_audio) MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode"); MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_rt5660"); diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index a3de55a3b58d..a3e040a249f6 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -1039,6 +1039,7 @@ static const struct platform_device_id kbl_board_ids[] = { }, { } }; +MODULE_DEVICE_TABLE(platform, kbl_board_ids); static struct platform_driver kabylake_audio = { .probe = kabylake_audio_probe, @@ -1056,5 +1057,3 @@ MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode"); MODULE_AUTHOR("Naveen M <naveen.m@intel.com>"); MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_rt5663"); -MODULE_ALIAS("platform:kbl_rt5663_m98927"); diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index f95546c184aa..dd38fdaf2ff5 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -837,6 +837,7 @@ static const struct platform_device_id kbl_board_ids[] = { { .name = "kbl_r5514_5663_max" }, { } }; +MODULE_DEVICE_TABLE(platform, kbl_board_ids); static struct platform_driver kabylake_audio = { .probe = kabylake_audio_probe, @@ -853,4 +854,3 @@ module_platform_driver(kabylake_audio) MODULE_DESCRIPTION("Audio Machine driver-RT5663 RT5514 & MAX98927"); MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:kbl_r5514_5663_max"); diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index bc50eda297ab..f4b4eeca3e03 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -258,3 +258,4 @@ MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); MODULE_AUTHOR("Rakesh Ughreja <rakesh.a.ughreja@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:skl_hda_dsp_generic"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 55802900069a..e3a1f04a8b53 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -673,6 +673,7 @@ static const struct platform_device_id skl_board_ids[] = { { .name = "kbl_n88l25_m98357a" }, { } }; +MODULE_DEVICE_TABLE(platform, skl_board_ids); static struct platform_driver skylake_audio = { .probe = skylake_audio_probe, @@ -689,5 +690,3 @@ module_platform_driver(skylake_audio) MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:skl_n88l25_m98357a"); -MODULE_ALIAS("platform:kbl_n88l25_m98357a"); diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 0c734f3a9364..adf5992a9ec5 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -717,6 +717,7 @@ static const struct platform_device_id skl_board_ids[] = { { .name = "kbl_n88l25_s4567" }, { } }; +MODULE_DEVICE_TABLE(platform, skl_board_ids); static struct platform_driver skylake_audio = { .probe = skylake_audio_probe, @@ -737,5 +738,3 @@ MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:skl_n88l25_s4567"); -MODULE_ALIAS("platform:kbl_n88l25_s4567"); diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 5a0c64a83146..75dab5405380 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -548,6 +548,7 @@ static const struct platform_device_id skl_board_ids[] = { { .name = "kbl_alc286s_i2s" }, { } }; +MODULE_DEVICE_TABLE(platform, skl_board_ids); static struct platform_driver skylake_audio = { .probe = skylake_audio_probe, @@ -565,5 +566,3 @@ module_platform_driver(skylake_audio) MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>"); MODULE_DESCRIPTION("Intel SST Audio for Skylake"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:skl_alc286s_i2s"); -MODULE_ALIAS("platform:kbl_alc286s_i2s"); diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c new file mode 100644 index 000000000000..42aadf801f72 --- /dev/null +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -0,0 +1,508 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2021 Intel Corporation. + +/* + * Intel SOF Machine Driver with Cirrus Logic CS42L42 Codec + * and speaker codec MAX98357A + */ +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/dmi.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include <dt-bindings/sound/cs42l42.h> +#include "../../codecs/hdac_hdmi.h" +#include "../common/soc-intel-quirks.h" +#include "hda_dsp_common.h" +#include "sof_maxim_common.h" + +#define NAME_SIZE 32 + +#define SOF_CS42L42_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) +#define SOF_CS42L42_SSP_CODEC_MASK (GENMASK(2, 0)) +#define SOF_SPEAKER_AMP_PRESENT BIT(3) +#define SOF_CS42L42_SSP_AMP_SHIFT 4 +#define SOF_CS42L42_SSP_AMP_MASK (GENMASK(6, 4)) +#define SOF_CS42L42_SSP_AMP(quirk) \ + (((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK) +#define SOF_CS42L42_NUM_HDMIDEV_SHIFT 7 +#define SOF_CS42L42_NUM_HDMIDEV_MASK (GENMASK(9, 7)) +#define SOF_CS42L42_NUM_HDMIDEV(quirk) \ + (((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK) +#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(10) + +/* Default: SSP2 */ +static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2); + +struct sof_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + struct snd_soc_jack hdmi_jack; + int device; +}; + +struct sof_card_private { + struct snd_soc_jack headset_jack; + struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; +}; + +static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); + struct sof_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_jack *jack = &ctx->headset_jack; + int ret; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return ret; +}; + +static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int clk_freq, ret; + + clk_freq = 3072000; /* BCLK freq */ + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, + clk_freq, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops sof_cs42l42_ops = { + .hw_params = sof_cs42l42_hw_params, +}; + +static struct snd_soc_dai_link_component platform_component[] = { + { + /* name might be overridden during probe */ + .name = "0000:00:1f.3" + } +}; + +static int sof_card_late_probe(struct snd_soc_card *card) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = NULL; + char jack_name[NAME_SIZE]; + struct sof_hdmi_pcm *pcm; + int err; + + if (list_empty(&ctx->hdmi_pcm_list)) + return -EINVAL; + + if (ctx->common_hdmi_codec_drv) { + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, + head); + component = pcm->codec_dai->component; + return hda_dsp_hdmi_build_controls(card, component); + } + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &pcm->hdmi_jack, + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &pcm->hdmi_jack); + if (err < 0) + return err; + } + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} + +static const struct snd_kcontrol_new sof_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget sof_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_widget dmic_widgets[] = { + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_soc_dapm_route sof_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + {"Headphone Jack", NULL, "HP"}, + + /* other jacks */ + {"HS", NULL, "Headset Mic"}, +}; + +static const struct snd_soc_dapm_route dmic_map[] = { + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, +}; + +static int dmic_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ARRAY_SIZE(dmic_widgets)); + if (ret) { + dev_err(card->dev, "DMic widget addition failed: %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, + ARRAY_SIZE(dmic_map)); + + if (ret) + dev_err(card->dev, "DMic map addition failed: %d\n", ret); + + return ret; +} + +/* sof audio machine driver for cs42l42 codec */ +static struct snd_soc_card sof_audio_card_cs42l42 = { + .name = "cs42l42", /* the sof- prefix is added by the core */ + .owner = THIS_MODULE, + .controls = sof_controls, + .num_controls = ARRAY_SIZE(sof_controls), + .dapm_widgets = sof_widgets, + .num_dapm_widgets = ARRAY_SIZE(sof_widgets), + .dapm_routes = sof_map, + .num_dapm_routes = ARRAY_SIZE(sof_map), + .fully_routed = true, + .late_probe = sof_card_late_probe, +}; + +static struct snd_soc_dai_link_component cs42l42_component[] = { + { + .name = "i2c-10134242:00", + .dai_name = "cs42l42", + } +}; + +static struct snd_soc_dai_link_component dmic_component[] = { + { + .name = "dmic-codec", + .dai_name = "dmic-hifi", + } +}; + +static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, + int ssp_codec, + int ssp_amp, + int dmic_be_num, + int hdmi_num) +{ + struct snd_soc_dai_link_component *idisp_components; + struct snd_soc_dai_link_component *cpus; + struct snd_soc_dai_link *links; + int i, id = 0; + + links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * + sof_audio_card_cs42l42.num_links, GFP_KERNEL); + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * + sof_audio_card_cs42l42.num_links, GFP_KERNEL); + if (!links || !cpus) + goto devm_err; + + /* speaker amp */ + if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT) { + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d-Codec", ssp_amp); + if (!links[id].name) + goto devm_err; + + links[id].id = id; + + if (sof_cs42l42_quirk & SOF_MAX98357A_SPEAKER_AMP_PRESENT) { + max_98357a_dai_link(&links[id]); + } else { + dev_err(dev, "no amp defined\n"); + goto devm_err; + } + + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_playback = 1; + links[id].no_pcm = 1; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_amp); + if (!links[id].cpus->dai_name) + goto devm_err; + + id++; + } + + /* codec SSP */ + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d-Codec", ssp_codec); + if (!links[id].name) + goto devm_err; + + links[id].id = id; + links[id].codecs = cs42l42_component; + links[id].num_codecs = ARRAY_SIZE(cs42l42_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = sof_cs42l42_init; + links[id].exit = sof_cs42l42_exit; + links[id].ops = &sof_cs42l42_ops; + links[id].dpcm_playback = 1; + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_codec); + if (!links[id].cpus->dai_name) + goto devm_err; + + id++; + + /* dmic */ + if (dmic_be_num > 0) { + /* at least we have dmic01 */ + links[id].name = "dmic01"; + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = "DMIC01 Pin"; + links[id].init = dmic_init; + if (dmic_be_num > 1) { + /* set up 2 BE links at most */ + links[id + 1].name = "dmic16k"; + links[id + 1].cpus = &cpus[id + 1]; + links[id + 1].cpus->dai_name = "DMIC16k Pin"; + dmic_be_num = 2; + } + } + + for (i = 0; i < dmic_be_num; i++) { + links[id].id = id; + links[id].num_cpus = 1; + links[id].codecs = dmic_component; + links[id].num_codecs = ARRAY_SIZE(dmic_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].ignore_suspend = 1; + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + id++; + } + + /* HDMI */ + if (hdmi_num > 0) { + idisp_components = devm_kzalloc(dev, + sizeof(struct snd_soc_dai_link_component) * + hdmi_num, GFP_KERNEL); + if (!idisp_components) + goto devm_err; + } + for (i = 1; i <= hdmi_num; i++) { + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d", i); + if (!links[id].name) + goto devm_err; + + links[id].id = id; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d Pin", i); + if (!links[id].cpus->dai_name) + goto devm_err; + + idisp_components[i - 1].name = "ehdaudio0D2"; + idisp_components[i - 1].dai_name = devm_kasprintf(dev, + GFP_KERNEL, + "intel-hdmi-hifi%d", + i); + if (!idisp_components[i - 1].dai_name) + goto devm_err; + + links[id].codecs = &idisp_components[i - 1]; + links[id].num_codecs = 1; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = sof_hdmi_init; + links[id].dpcm_playback = 1; + links[id].no_pcm = 1; + id++; + } + + return links; +devm_err: + return NULL; +} + +static int sof_audio_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_links; + struct snd_soc_acpi_mach *mach; + struct sof_card_private *ctx; + int dmic_be_num, hdmi_num; + int ret, ssp_amp, ssp_codec; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (pdev->id_entry && pdev->id_entry->driver_data) + sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data; + + mach = pdev->dev.platform_data; + + if (soc_intel_is_glk()) { + dmic_be_num = 1; + hdmi_num = 3; + } else { + dmic_be_num = 2; + hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >> + SOF_CS42L42_NUM_HDMIDEV_SHIFT; + /* default number of HDMI DAI's */ + if (!hdmi_num) + hdmi_num = 3; + } + + dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); + + ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> + SOF_CS42L42_SSP_AMP_SHIFT; + + ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; + + /* compute number of dai links */ + sof_audio_card_cs42l42.num_links = 1 + dmic_be_num + hdmi_num; + + if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT) + sof_audio_card_cs42l42.num_links++; + + dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, + dmic_be_num, hdmi_num); + if (!dai_links) + return -ENOMEM; + + sof_audio_card_cs42l42.dai_link = dai_links; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + sof_audio_card_cs42l42.dev = &pdev->dev; + + /* set platform name for each dailink */ + ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42, + mach->mach_params.platform); + if (ret) + return ret; + + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + + snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx); + + return devm_snd_soc_register_card(&pdev->dev, + &sof_audio_card_cs42l42); +} + +static const struct platform_device_id board_ids[] = { + { + .name = "glk_cs4242_mx98357a", + .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98357A_SPEAKER_AMP_PRESENT | + SOF_CS42L42_SSP_AMP(1)), + }, + { } +}; +MODULE_DEVICE_TABLE(platform, board_ids); + +static struct platform_driver sof_audio = { + .probe = sof_audio_probe, + .driver = { + .name = "sof_cs42l42", + .pm = &snd_soc_pm_ops, + }, + .id_table = board_ids, +}; +module_platform_driver(sof_audio) + +/* Module information */ +MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c index f3cb0773e70e..896251d742fe 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -431,15 +431,16 @@ static int audio_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { - .name = "sof_da7219_max98373", + .name = "sof_da7219_mx98373", .driver_data = (kernel_ulong_t)&card_da7219_m98373, }, { - .name = "sof_da7219_max98360a", + .name = "sof_da7219_mx98360a", .driver_data = (kernel_ulong_t)&card_da7219_m98360a, }, { } }; +MODULE_DEVICE_TABLE(platform, board_ids); static struct platform_driver audio = { .probe = audio_probe, @@ -455,5 +456,4 @@ module_platform_driver(audio) MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver"); MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sof_da7219_max98360a"); -MODULE_ALIAS("platform:sof_da7219_max98373"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 437d20562753..e9c52f8b6428 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only // // Copyright(c) 2020 Intel Corporation. All rights reserved. +#include <linux/module.h> #include <linux/string.h> #include <sound/pcm.h> #include <sound/soc.h> @@ -16,6 +17,7 @@ const struct snd_soc_dapm_route max_98373_dapm_routes[] = { { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, }; +EXPORT_SYMBOL_NS(max_98373_dapm_routes, SND_SOC_INTEL_SOF_MAXIM_COMMON); static struct snd_soc_codec_conf max_98373_codec_conf[] = { { @@ -38,9 +40,10 @@ struct snd_soc_dai_link_component max_98373_components[] = { .dai_name = MAX_98373_CODEC_DAI, }, }; +EXPORT_SYMBOL_NS(max_98373_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); -static int max98373_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int max_98373_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; @@ -59,7 +62,7 @@ static int max98373_hw_params(struct snd_pcm_substream *substream, return 0; } -int max98373_trigger(struct snd_pcm_substream *substream, int cmd) +int max_98373_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; @@ -102,13 +105,15 @@ int max98373_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } +EXPORT_SYMBOL_NS(max_98373_trigger, SND_SOC_INTEL_SOF_MAXIM_COMMON); struct snd_soc_ops max_98373_ops = { - .hw_params = max98373_hw_params, - .trigger = max98373_trigger, + .hw_params = max_98373_hw_params, + .trigger = max_98373_trigger, }; +EXPORT_SYMBOL_NS(max_98373_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); -int max98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) +int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; int ret; @@ -119,9 +124,74 @@ int max98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); return ret; } +EXPORT_SYMBOL_NS(max_98373_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); -void sof_max98373_codec_conf(struct snd_soc_card *card) +void max_98373_set_codec_conf(struct snd_soc_card *card) { card->codec_conf = max_98373_codec_conf; card->num_configs = ARRAY_SIZE(max_98373_codec_conf); } +EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +/* + * Maxim MAX98357A + */ +static const struct snd_kcontrol_new max_98357a_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget max_98357a_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + +static const struct snd_soc_dapm_route max_98357a_dapm_routes[] = { + /* speaker */ + {"Spk", NULL, "Speaker"}, +}; + +static struct snd_soc_dai_link_component max_98357a_components[] = { + { + .name = MAX_98357A_DEV0_NAME, + .dai_name = MAX_98357A_CODEC_DAI, + } +}; + +static int max_98357a_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, max_98357a_dapm_widgets, + ARRAY_SIZE(max_98357a_dapm_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_add_card_controls(card, max_98357a_kcontrols, + ARRAY_SIZE(max_98357a_kcontrols)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, max_98357a_dapm_routes, + ARRAY_SIZE(max_98357a_dapm_routes)); + + if (ret) + dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret); + + return ret; +} + +void max_98357a_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = max_98357a_components; + link->num_codecs = ARRAY_SIZE(max_98357a_components); + link->init = max_98357a_init; +} +EXPORT_SYMBOL_NS(max_98357a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index 5240b1c9d379..2674f1e373ef 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -20,8 +20,16 @@ extern struct snd_soc_dai_link_component max_98373_components[2]; extern struct snd_soc_ops max_98373_ops; extern const struct snd_soc_dapm_route max_98373_dapm_routes[]; -int max98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd); -void sof_max98373_codec_conf(struct snd_soc_card *card); -int max98373_trigger(struct snd_pcm_substream *substream, int cmd); +int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd); +void max_98373_set_codec_conf(struct snd_soc_card *card); +int max_98373_trigger(struct snd_pcm_substream *substream, int cmd); + +/* + * Maxim MAX98357A + */ +#define MAX_98357A_CODEC_DAI "HiFi" +#define MAX_98357A_DEV0_NAME "MX98357A:00" + +void max_98357a_dai_link(struct snd_soc_dai_link *link); #endif /* __SOF_MAXIM_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index d2b0456236c7..2ec9c62366e2 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -241,7 +241,6 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_pcm512x_codec_init; links[id].ops = &sof_pcm512x_ops; - links[id].nonatomic = true; links[id].dpcm_playback = 1; /* * capture only supported with specific versions of the Hifiberry DAC+ @@ -437,3 +436,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF + PCM512x Machine driver"); MODULE_AUTHOR("Pierre-Louis Bossart"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sof_pcm512x"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 58548ea0d915..39217223d50c 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -50,6 +50,13 @@ #define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(17) #define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(18) +/* BT audio offload: reserve 3 bits for future */ +#define SOF_BT_OFFLOAD_SSP_SHIFT 19 +#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(21, 19)) +#define SOF_BT_OFFLOAD_SSP(quirk) \ + (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) +#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22) + /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | SOF_RT5682_SSP_CODEC(0); @@ -444,20 +451,26 @@ static int sof_card_late_probe(struct snd_soc_card *card) static const struct snd_kcontrol_new sof_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), }; +static const struct snd_kcontrol_new speaker_controls[] = { + SOC_DAPM_PIN_SWITCH("Spk"), +}; + static const struct snd_soc_dapm_widget sof_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), }; +static const struct snd_soc_dapm_widget speaker_widgets[] = { + SND_SOC_DAPM_SPK("Spk", NULL), +}; + static const struct snd_soc_dapm_widget dmic_widgets[] = { SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; @@ -497,6 +510,21 @@ static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; int ret; + ret = snd_soc_dapm_new_controls(&card->dapm, speaker_widgets, + ARRAY_SIZE(speaker_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_add_card_controls(card, speaker_controls, + ARRAY_SIZE(speaker_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map, ARRAY_SIZE(speaker_map)); @@ -566,13 +594,6 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; -static struct snd_soc_dai_link_component max98357a_component[] = { - { - .name = "MX98357A:00", - .dai_name = "HiFi", - } -}; - static struct snd_soc_dai_link_component max98360a_component[] = { { .name = "MX98360A:00", @@ -591,6 +612,13 @@ static struct snd_soc_dai_link_component rt1015_components[] = { }, }; +static struct snd_soc_dai_link_component dummy_component[] = { + { + .name = "snd-soc-dummy", + .dai_name = "snd-soc-dummy-dai", + } +}; + static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, int ssp_codec, int ssp_amp, @@ -623,7 +651,6 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].init = sof_rt5682_codec_init; links[id].exit = sof_rt5682_codec_exit; links[id].ops = &sof_rt5682_ops; - links[id].nonatomic = true; links[id].dpcm_playback = 1; links[id].dpcm_capture = 1; links[id].no_pcm = 1; @@ -742,7 +769,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, SOF_MAX98373_SPEAKER_AMP_PRESENT) { links[id].codecs = max_98373_components; links[id].num_codecs = ARRAY_SIZE(max_98373_components); - links[id].init = max98373_spk_codec_init; + links[id].init = max_98373_spk_codec_init; links[id].ops = &max_98373_ops; /* feedback stream */ links[id].dpcm_capture = 1; @@ -755,13 +782,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, SOF_RT1011_SPEAKER_AMP_PRESENT) { sof_rt1011_dai_link(&links[id]); } else { - links[id].codecs = max98357a_component; - links[id].num_codecs = ARRAY_SIZE(max98357a_component); - links[id].init = speaker_codec_init; + max_98357a_dai_link(&links[id]); } links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].nonatomic = true; links[id].dpcm_playback = 1; links[id].no_pcm = 1; links[id].cpus = &cpus[id]; @@ -780,6 +804,31 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (!links[id].cpus->dai_name) goto devm_err; } + id++; + } + + /* BT audio offload */ + if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + int port = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + + links[id].id = id; + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", port); + if (!links[id].cpus->dai_name) + goto devm_err; + links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); + if (!links[id].name) + goto devm_err; + links[id].codecs = dummy_component; + links[id].num_codecs = ARRAY_SIZE(dummy_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].dpcm_playback = 1; + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + links[id].num_cpus = 1; } return links; @@ -863,12 +912,15 @@ static int sof_audio_probe(struct platform_device *pdev) sof_audio_card_rt5682.num_links++; if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) - sof_max98373_codec_conf(&sof_audio_card_rt5682); + max_98373_set_codec_conf(&sof_audio_card_rt5682); else if (sof_rt5682_quirk & SOF_RT1011_SPEAKER_AMP_PRESENT) sof_rt1011_codec_conf(&sof_audio_card_rt5682); else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) sof_rt1015p_codec_conf(&sof_audio_card_rt5682); + if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + sof_audio_card_rt5682.num_links++; + dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, dmic_be_num, hdmi_num); if (!dai_links) @@ -904,12 +956,14 @@ static const struct platform_device_id board_ids[] = { .name = "sof_rt5682", }, { - .name = "tgl_max98357a_rt5682", + .name = "tgl_mx98357a_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | SOF_RT5682_SSP_CODEC(0) | SOF_SPEAKER_AMP_PRESENT | SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_RT5682_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, { .name = "jsl_rt5682_rt1015", @@ -921,16 +975,18 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(1)), }, { - .name = "tgl_max98373_rt5682", + .name = "tgl_mx98373_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | SOF_RT5682_SSP_CODEC(0) | SOF_SPEAKER_AMP_PRESENT | SOF_MAX98373_SPEAKER_AMP_PRESENT | SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_RT5682_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, { - .name = "jsl_rt5682_max98360a", + .name = "jsl_rt5682_mx98360a", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | SOF_RT5682_MCLK_24MHZ | SOF_RT5682_SSP_CODEC(0) | @@ -955,7 +1011,9 @@ static const struct platform_device_id board_ids[] = { SOF_SPEAKER_AMP_PRESENT | SOF_RT1011_SPEAKER_AMP_PRESENT | SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_RT5682_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, { .name = "jsl_rt5682_rt1015p", @@ -966,8 +1024,28 @@ static const struct platform_device_id board_ids[] = { SOF_RT1015P_SPEAKER_AMP_PRESENT | SOF_RT5682_SSP_AMP(1)), }, + { + .name = "adl_mx98373_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_MAX98373_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1) | + SOF_RT5682_NUM_HDMIDEV(4) | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + { + .name = "adl_mx98357a_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(2) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, { } }; +MODULE_DEVICE_TABLE(platform, board_ids); static struct platform_driver sof_audio = { .probe = sof_audio_probe, @@ -985,11 +1063,5 @@ MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>"); MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sof_rt5682"); -MODULE_ALIAS("platform:tgl_max98357a_rt5682"); -MODULE_ALIAS("platform:jsl_rt5682_rt1015"); -MODULE_ALIAS("platform:tgl_max98373_rt5682"); -MODULE_ALIAS("platform:jsl_rt5682_max98360a"); -MODULE_ALIAS("platform:cml_rt1015_rt5682"); -MODULE_ALIAS("platform:tgl_rt1011_rt5682"); -MODULE_ALIAS("platform:jsl_rt5682_rt1015p"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index ecd3f90f4bbe..e9118234b30e 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -147,7 +147,9 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | - SOF_SDW_FOUR_SPK), + SOF_SDW_FOUR_SPK | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, { .callback = sof_sdw_quirk_cb, @@ -196,7 +198,21 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_RT711_JD_SRC_JD1 | SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC), + SOF_RT715_DAI_ID_FIX | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Brya"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOF_SDW_PCH_DMIC | + SOF_SDW_FOUR_SPK | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), }, {} }; @@ -353,6 +369,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .part_id = 0x714, .version_id = 3, .direction = {false, true}, + .ignore_pch_dmic = true, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_sdca_init, }, @@ -360,6 +377,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .part_id = 0x715, .version_id = 3, .direction = {false, true}, + .ignore_pch_dmic = true, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_sdca_init, }, @@ -367,6 +385,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .part_id = 0x714, .version_id = 2, .direction = {false, true}, + .ignore_pch_dmic = true, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_init, }, @@ -374,6 +393,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .part_id = 0x715, .version_id = 2, .direction = {false, true}, + .ignore_pch_dmic = true, .dai_name = "rt715-aif2", .init = sof_sdw_rt715_init, }, @@ -499,7 +519,6 @@ static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links dai_links->name = name; dai_links->platforms = platform_component; dai_links->num_platforms = ARRAY_SIZE(platform_component); - dai_links->nonatomic = true; dai_links->no_pcm = 1; dai_links->cpus = cpus; dai_links->num_cpus = cpus_num; @@ -663,7 +682,7 @@ static int set_codec_init_func(const struct snd_soc_acpi_link_adr *link, */ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, struct device *dev, int *cpu_dai_id, int *cpu_dai_num, - int *codec_num, int *group_id, + int *codec_num, unsigned int *group_id, bool *group_generated) { const struct snd_soc_acpi_adr_device *adr_d; @@ -729,7 +748,8 @@ static int create_sdw_dailink(struct device *dev, int *be_index, int *cpu_id, bool *group_generated, struct snd_soc_codec_conf *codec_conf, int codec_count, - int *codec_conf_index) + int *codec_conf_index, + bool *ignore_pch_dmic) { const struct snd_soc_acpi_link_adr *link_next; struct snd_soc_dai_link_component *codecs; @@ -782,6 +802,9 @@ static int create_sdw_dailink(struct device *dev, int *be_index, if (codec_index < 0) return codec_index; + if (codec_info_list[codec_index].ignore_pch_dmic) + *ignore_pch_dmic = true; + cpu_dai_index = *cpu_id; for_each_pcm_streams(stream) { char *name, *cpu_name; @@ -913,6 +936,7 @@ static int sof_card_dai_links_create(struct device *dev, const struct snd_soc_acpi_link_adr *adr_link; struct snd_soc_dai_link_component *cpus; struct snd_soc_codec_conf *codec_conf; + bool ignore_pch_dmic = false; int codec_conf_count; int codec_conf_index = 0; bool group_generated[SDW_MAX_GROUPS]; @@ -968,6 +992,9 @@ static int sof_card_dai_links_create(struct device *dev, dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0; comp_num += dmic_num; + if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + comp_num++; + dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num, dmic_num, ctx->idisp_codec ? hdmi_num : 0); @@ -1019,7 +1046,8 @@ static int sof_card_dai_links_create(struct device *dev, sdw_cpu_dai_num, cpus, adr_link, &cpu_id, group_generated, codec_conf, codec_conf_count, - &codec_conf_index); + &codec_conf_index, + &ignore_pch_dmic); if (ret < 0) { dev_err(dev, "failed to create dai link %d", be_id); return -ENOMEM; @@ -1087,6 +1115,10 @@ SSP: DMIC: /* dmic */ if (dmic_num > 0) { + if (ignore_pch_dmic) { + dev_warn(dev, "Ignoring PCH DMIC\n"); + goto HDMI; + } cpus[cpu_id].dai_name = "DMIC01 Pin"; init_dai_link(dev, links + link_id, be_id, "dmic01", 0, 1, // DMIC only supports capture @@ -1105,6 +1137,7 @@ DMIC: INC_ID(be_id, cpu_id, link_id); } +HDMI: /* HDMI */ if (hdmi_num > 0) { idisp_components = devm_kcalloc(dev, hdmi_num, @@ -1147,6 +1180,31 @@ DMIC: INC_ID(be_id, cpu_id, link_id); } + if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + + name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); + if (!name) + return -ENOMEM; + + ssp_components = devm_kzalloc(dev, sizeof(*ssp_components), + GFP_KERNEL); + if (!ssp_components) + return -ENOMEM; + + ssp_components->name = "snd-soc-dummy"; + ssp_components->dai_name = "snd-soc-dummy-dai"; + + cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); + if (!cpu_name) + return -ENOMEM; + + cpus[cpu_id].dai_name = cpu_name; + init_dai_link(dev, links + link_id, be_id, name, 1, 1, + cpus + cpu_id, 1, ssp_components, 1, NULL, NULL); + } + card->dai_link = links; card->num_links = num_links; @@ -1215,8 +1273,6 @@ static int mc_probe(struct platform_device *pdev) if (ret < 0) return ret; - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - /* * the default amp_num is zero for each codec and * amp_num will only be increased for active amp @@ -1302,3 +1358,5 @@ MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>"); MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sof_sdw"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index f3cb6796363e..ec5740486b75 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -50,12 +50,20 @@ enum { #define SOF_RT715_DAI_ID_FIX BIT(11) #define SOF_SDW_NO_AGGREGATION BIT(12) +/* BT audio offload: reserve 3 bits for future */ +#define SOF_BT_OFFLOAD_SSP_SHIFT 13 +#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(15, 13)) +#define SOF_BT_OFFLOAD_SSP(quirk) \ + (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) +#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(16) + struct sof_sdw_codec_info { const int part_id; const int version_id; int amp_num; const u8 acpi_id[ACPI_ID_LEN]; const bool direction[2]; // playback & capture support + const bool ignore_pch_dmic; const char *dai_name; const struct snd_soc_ops *ops; @@ -71,7 +79,6 @@ struct sof_sdw_codec_info { struct mc_private { struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; bool idisp_codec; struct snd_soc_jack sdw_headset; }; diff --git a/sound/soc/intel/boards/sof_sdw_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c index 99b04bb2f3a0..d47d8bf528c1 100644 --- a/sound/soc/intel/boards/sof_sdw_hdmi.c +++ b/sound/soc/intel/boards/sof_sdw_hdmi.c @@ -13,11 +13,8 @@ #include <sound/soc-acpi.h> #include <sound/jack.h> #include "sof_sdw_common.h" -#include "../../codecs/hdac_hdmi.h" #include "hda_dsp_common.h" -static struct snd_soc_jack hdmi[MAX_HDMI_NUM]; - struct hdmi_pcm { struct list_head head; struct snd_soc_dai *codec_dai; @@ -49,8 +46,6 @@ int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card) struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct hdmi_pcm *pcm; struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; if (!ctx->idisp_codec) return 0; @@ -62,35 +57,5 @@ int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card) head); component = pcm->codec_dai->component; - if (ctx->common_hdmi_codec_drv) - return hda_dsp_hdmi_build_controls(card, component); - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &hdmi[i], - NULL, 0); - - if (err) - return err; - - err = snd_jack_add_new_kctl(hdmi[i].jack, - jack_name, SND_JACK_AVOUT); - if (err) - dev_warn(component->dev, "failed creating Jack kctl\n"); - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); + return hda_dsp_hdmi_build_controls(card, component); } diff --git a/sound/soc/intel/boards/sof_sdw_max98373.c b/sound/soc/intel/boards/sof_sdw_max98373.c index cfdf970c5800..0e7ed906b341 100644 --- a/sound/soc/intel/boards/sof_sdw_max98373.c +++ b/sound/soc/intel/boards/sof_sdw_max98373.c @@ -64,7 +64,7 @@ static int max98373_sdw_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* enable max98373 first */ - ret = max98373_trigger(substream, cmd); + ret = max_98373_trigger(substream, cmd); if (ret < 0) break; @@ -77,7 +77,7 @@ static int max98373_sdw_trigger(struct snd_pcm_substream *substream, int cmd) if (ret < 0) break; - ret = max98373_trigger(substream, cmd); + ret = max_98373_trigger(substream, cmd); break; default: ret = -EINVAL; diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index 6a181e45143d..54395e2ededc 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -167,7 +167,6 @@ static struct snd_soc_dai_link dailink[] = { .name = "SSP5-Codec", .id = 0, .no_pcm = 1, - .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .ops = &sof_wm8804_ops, diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index 692c4c479ed8..a0f6a69c7038 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -31,7 +31,7 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { - .adr = 0x000020025D071100, + .adr = 0x000020025D071100ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt711" @@ -40,7 +40,7 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { { - .adr = 0x000120025D130800, + .adr = 0x000120025D130800ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "rt1308-1" @@ -49,7 +49,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { { - .adr = 0x000220025D130800, + .adr = 0x000220025D130800ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1308-2" @@ -58,7 +58,7 @@ static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { { - .adr = 0x000320025D071500, + .adr = 0x000320025D071500ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt715" @@ -67,7 +67,7 @@ static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { { - .adr = 0x000030025D071101, + .adr = 0x000030025D071101ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt711" @@ -76,7 +76,7 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { { - .adr = 0x000131025D131601, /* unique ID is set for some reason */ + .adr = 0x000131025D131601ull, /* unique ID is set for some reason */ .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "rt1316-1" @@ -85,7 +85,7 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { { - .adr = 0x000230025D131601, + .adr = 0x000230025D131601ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1316-2" @@ -94,7 +94,7 @@ static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { { - .adr = 0x000330025D131601, + .adr = 0x000330025D131601ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1316-2" @@ -103,7 +103,7 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = { { - .adr = 0x000230025D131601, + .adr = 0x000230025D131601ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt1316-1" @@ -112,7 +112,7 @@ static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = { static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { { - .adr = 0x000030025D071401, + .adr = 0x000030025D071401ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt714" @@ -121,7 +121,7 @@ static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { static const struct snd_soc_acpi_adr_device rt714_2_adr[] = { { - .adr = 0x000230025D071401, + .adr = 0x000230025D071401ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt714" @@ -130,7 +130,7 @@ static const struct snd_soc_acpi_adr_device rt714_2_adr[] = { static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { { - .adr = 0x000330025D071401, + .adr = 0x000330025D071401ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt714" @@ -223,6 +223,30 @@ static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link0[] = { {} }; +static const struct snd_soc_acpi_adr_device mx8373_2_adr[] = { + { + .adr = 0x000223019F837300ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "Left" + }, + { + .adr = 0x000227019F837300ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "Right" + } +}; + +static const struct snd_soc_acpi_adr_device rt5682_0_adr[] = { + { + .adr = 0x000021025D568200ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt5682" + } +}; + static const struct snd_soc_acpi_link_adr adl_rvp[] = { { .mask = BIT(0), @@ -232,7 +256,47 @@ static const struct snd_soc_acpi_link_adr adl_rvp[] = { {} }; +static const struct snd_soc_acpi_link_adr adl_chromebook_base[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt5682_0_adr), + .adr_d = rt5682_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(mx8373_2_adr), + .adr_d = mx8373_2_adr, + }, + {} +}; + +static const struct snd_soc_acpi_codecs adl_max98373_amp = { + .num_codecs = 1, + .codecs = {"MX98373"} +}; + +static const struct snd_soc_acpi_codecs adl_max98357a_amp = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { + { + .id = "10EC5682", + .drv_name = "adl_mx98373_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_max98373_amp, + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-max98373-rt5682.tplg", + }, + { + .id = "10EC5682", + .drv_name = "adl_mx98357a_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &adl_max98357a_amp, + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-max98357a-rt5682.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); @@ -269,6 +333,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-adl-rt711.tplg", }, + { + .link_mask = 0x5, /* rt5682 on link0 & 2xmax98373 on link 2 */ + .links = adl_chromebook_base, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-sdw-max98373-rt5682.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index 398cc771c835..576407b5daf2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -56,7 +56,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { }, { .id = "DLGS7219", - .drv_name = "bxt_da7219_max98357a", + .drv_name = "bxt_da7219_mx98357a", .fw_filename = "intel/dsp_fw_bxtn.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &bxt_codecs, diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index 7f6ef8229969..42ef51c3fb4f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -67,7 +67,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { }, { .id = "DLGS7219", - .drv_name = "cml_da7219_max98357a", + .drv_name = "cml_da7219_mx98357a", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &max98357a_spk_codecs, .sof_fw_filename = "sof-cml.ri", @@ -108,7 +108,7 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { static const struct snd_soc_acpi_adr_device rt700_1_adr[] = { { - .adr = 0x000110025D070000, + .adr = 0x000110025D070000ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt700" @@ -126,7 +126,7 @@ static const struct snd_soc_acpi_link_adr cml_rvp[] = { static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { - .adr = 0x000020025D071100, + .adr = 0x000020025D071100ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt711" @@ -135,7 +135,7 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_single_adr[] = { { - .adr = 0x000120025D130800, + .adr = 0x000120025D130800ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt1308-1" @@ -144,7 +144,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_single_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { { - .adr = 0x000120025D130800, + .adr = 0x000120025D130800ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "rt1308-1" @@ -153,7 +153,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { { - .adr = 0x000220025D130800, + .adr = 0x000220025D130800ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1308-2" @@ -162,7 +162,7 @@ static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { { - .adr = 0x000320025D071500, + .adr = 0x000320025D071500ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt715" @@ -171,7 +171,7 @@ static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { { - .adr = 0x000030025D071101, + .adr = 0x000030025D071101ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt711" @@ -180,7 +180,7 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { { - .adr = 0x000131025D131601, /* unique ID is set for some reason */ + .adr = 0x000131025D131601ull, /* unique ID is set for some reason */ .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "rt1316-1" @@ -189,7 +189,7 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { { - .adr = 0x000230025D131601, + .adr = 0x000230025D131601ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1316-2" @@ -198,7 +198,7 @@ static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { { - .adr = 0x000330025D071401, + .adr = 0x000330025D071401ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt714" diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index ec77a57a07ba..39dad32564e6 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -36,7 +36,7 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { static const struct snd_soc_acpi_adr_device rt5682_2_adr[] = { { - .adr = 0x000220025D568200, + .adr = 0x000220025D568200ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt5682" diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 6ceaab19ccb6..da1e151190b4 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -24,7 +24,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { }, { .id = "DLGS7219", - .drv_name = "glk_da7219_max98357a", + .drv_name = "glk_da7219_mx98357a", .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, @@ -33,13 +33,23 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { }, { .id = "10EC5682", - .drv_name = "glk_rt5682_max98357a", + .drv_name = "glk_rt5682_mx98357a", .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-rt5682.tplg", }, + { + .id = "10134242", + .drv_name = "glk_cs4242_mx98357a", + .fw_filename = "intel/dsp_fw_glk.bin", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &glk_codecs, + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-cs42l42.tplg", + }, + {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_glk_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index d38ff7d187c4..768ed538c4ea 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -56,7 +56,7 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { static const struct snd_soc_acpi_adr_device rt700_0_adr[] = { { - .adr = 0x000010025D070000, + .adr = 0x000010025D070000ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt700" @@ -74,7 +74,7 @@ static const struct snd_soc_acpi_link_adr icl_rvp[] = { static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { - .adr = 0x000020025D071100, + .adr = 0x000020025D071100ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt711" @@ -83,7 +83,7 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { { - .adr = 0x000120025D130800, + .adr = 0x000120025D130800ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt1308-1" @@ -92,7 +92,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { { - .adr = 0x000120025D130800, + .adr = 0x000120025D130800ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "rt1308-1" @@ -101,7 +101,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { { - .adr = 0x000220025D130800, + .adr = 0x000220025D130800ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1308-2" @@ -110,7 +110,7 @@ static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { { - .adr = 0x000320025D071500, + .adr = 0x000320025D071500ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt715" diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c index 73fe4f89a82d..3586ce72c42c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -37,7 +37,7 @@ static struct snd_soc_acpi_codecs mx98360a_spk = { struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { { .id = "DLGS7219", - .drv_name = "sof_da7219_max98373", + .drv_name = "sof_da7219_mx98373", .sof_fw_filename = "sof-jsl.ri", .sof_tplg_filename = "sof-jsl-da7219.tplg", .machine_quirk = snd_soc_acpi_codec_list, @@ -45,7 +45,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { }, { .id = "DLGS7219", - .drv_name = "sof_da7219_max98360a", + .drv_name = "sof_da7219_mx98360a", .sof_fw_filename = "sof-jsl.ri", .sof_tplg_filename = "sof-jsl-da7219-mx98360a.tplg", }, @@ -67,7 +67,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { }, { .id = "10EC5682", - .drv_name = "jsl_rt5682_max98360a", + .drv_name = "jsl_rt5682_mx98360a", .sof_fw_filename = "sof-jsl.ri", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &mx98360a_spk, diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index 47dadc9d5d2a..ba5ff468c265 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -113,7 +113,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { }, { .id = "DLGS7219", - .drv_name = "kbl_da7219_max98373", + .drv_name = "kbl_da7219_mx98373", .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_7219_98373_codecs, diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index b5f05b81a584..66595e3ab13f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -37,7 +37,7 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { - .adr = 0x000020025D071100, + .adr = 0x000020025D071100ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt711" @@ -46,7 +46,7 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { static const struct snd_soc_acpi_adr_device rt711_1_adr[] = { { - .adr = 0x000120025D071100, + .adr = 0x000120025D071100ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt711" @@ -55,13 +55,13 @@ static const struct snd_soc_acpi_adr_device rt711_1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_dual_adr[] = { { - .adr = 0x000120025D130800, + .adr = 0x000120025D130800ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "rt1308-1" }, { - .adr = 0x000122025D130800, + .adr = 0x000122025D130800ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1308-2" @@ -70,7 +70,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_dual_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_single_adr[] = { { - .adr = 0x000120025D130800, + .adr = 0x000120025D130800ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt1308-1" @@ -79,7 +79,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_single_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_2_single_adr[] = { { - .adr = 0x000220025D130800, + .adr = 0x000220025D130800ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt1308-1" @@ -88,7 +88,7 @@ static const struct snd_soc_acpi_adr_device rt1308_2_single_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { { - .adr = 0x000120025D130800, + .adr = 0x000120025D130800ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "rt1308-1" @@ -97,7 +97,7 @@ static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { { - .adr = 0x000220025D130800, + .adr = 0x000220025D130800ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1308-2" @@ -106,7 +106,7 @@ static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt715_0_adr[] = { { - .adr = 0x000021025D071500, + .adr = 0x000021025D071500ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt715" @@ -115,7 +115,7 @@ static const struct snd_soc_acpi_adr_device rt715_0_adr[] = { static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { { - .adr = 0x000320025D071500, + .adr = 0x000320025D071500ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt715" @@ -124,13 +124,13 @@ static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { static const struct snd_soc_acpi_adr_device mx8373_1_adr[] = { { - .adr = 0x000123019F837300, + .adr = 0x000123019F837300ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "Right" }, { - .adr = 0x000127019F837300, + .adr = 0x000127019F837300ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "Left" @@ -139,7 +139,7 @@ static const struct snd_soc_acpi_adr_device mx8373_1_adr[] = { static const struct snd_soc_acpi_adr_device rt5682_0_adr[] = { { - .adr = 0x000021025D568200, + .adr = 0x000021025D568200ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt5682" @@ -148,7 +148,7 @@ static const struct snd_soc_acpi_adr_device rt5682_0_adr[] = { static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { { - .adr = 0x000030025D071101, + .adr = 0x000030025D071101ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt711" @@ -157,7 +157,7 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { { - .adr = 0x000131025D131601, /* unique ID is set for some reason */ + .adr = 0x000131025D131601ull, /* unique ID is set for some reason */ .num_endpoints = 1, .endpoints = &spk_l_endpoint, .name_prefix = "rt1316-1" @@ -166,7 +166,7 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { { - .adr = 0x000230025D131601, + .adr = 0x000230025D131601ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, .name_prefix = "rt1316-2" @@ -175,7 +175,7 @@ static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { { - .adr = 0x000330025D071401, + .adr = 0x000330025D071401ull, .num_endpoints = 1, .endpoints = &single_endpoint, .name_prefix = "rt714" @@ -323,7 +323,7 @@ static const struct snd_soc_acpi_codecs tgl_rt1011_amp = { struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { .id = "10EC5682", - .drv_name = "tgl_max98357a_rt5682", + .drv_name = "tgl_mx98357a_rt5682", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &tgl_codecs, .sof_fw_filename = "sof-tgl.ri", @@ -331,7 +331,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { }, { .id = "10EC5682", - .drv_name = "tgl_max98373_rt5682", + .drv_name = "tgl_mx98373_rt5682", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &tgl_max98373_amp, .sof_fw_filename = "sof-tgl.ri", diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 87c891c46291..64226072f0ee 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -149,8 +149,8 @@ int skl_nhlt_update_topology_bin(struct skl_dev *skl) return 0; } -static ssize_t skl_nhlt_platform_id_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t platform_id_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); @@ -166,7 +166,7 @@ static ssize_t skl_nhlt_platform_id_show(struct device *dev, return sprintf(buf, "%s\n", platform_id); } -static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); +static DEVICE_ATTR_RO(platform_id); int skl_nhlt_create_sysfs(struct skl_dev *skl) { diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 52ba0e3a9e95..7ad5d9a924d8 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -371,7 +371,7 @@ static int jz4740_i2s_resume(struct snd_soc_component *component) return 0; } -static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s) +static void jz4740_i2s_init_pcm_config(struct jz4740_i2s *i2s) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -396,7 +396,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) if (ret) return ret; - jz4740_i2c_init_pcm_config(i2s); + jz4740_i2s_init_pcm_config(i2s); snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, &i2s->capture_dma_data); @@ -525,8 +525,7 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) i2s->soc_info = device_get_match_data(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2s->base = devm_ioremap_resource(dev, mem); + i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(i2s->base)) return PTR_ERR(i2s->base); diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h index 44f12016064d..4da14eac1145 100644 --- a/sound/soc/jz4740/jz4740-i2s.h +++ b/sound/soc/jz4740/jz4740-i2s.h @@ -7,6 +7,4 @@ #define JZ4740_I2S_CLKSRC_EXT 0 #define JZ4740_I2S_CLKSRC_PLL 1 -#define JZ4740_I2S_BIT_CLK 0 - #endif diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index f85b5ea180ec..d884bb7c0fc7 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -1281,7 +1281,7 @@ static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = { static int mtk_btcvsd_snd_probe(struct platform_device *pdev) { - int ret = 0; + int ret; int irq_id; u32 offset[5] = {0, 0, 0, 0, 0}; struct mtk_btcvsd_snd *btcvsd; @@ -1337,7 +1337,8 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) btcvsd->bt_sram_bank2_base = of_iomap(dev->of_node, 1); if (!btcvsd->bt_sram_bank2_base) { dev_err(dev, "iomap bt_sram_bank2_base fail\n"); - return -EIO; + ret = -EIO; + goto unmap_pkv_err; } btcvsd->infra = syscon_regmap_lookup_by_phandle(dev->of_node, @@ -1345,7 +1346,8 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) if (IS_ERR(btcvsd->infra)) { dev_err(dev, "cannot find infra controller: %ld\n", PTR_ERR(btcvsd->infra)); - return PTR_ERR(btcvsd->infra); + ret = PTR_ERR(btcvsd->infra); + goto unmap_bank2_err; } /* get offset */ @@ -1354,7 +1356,7 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) ARRAY_SIZE(offset)); if (ret) { dev_warn(dev, "%s(), get offset fail, ret %d\n", __func__, ret); - return ret; + goto unmap_bank2_err; } btcvsd->infra_misc_offset = offset[0]; btcvsd->conn_bt_cvsd_mask = offset[1]; @@ -1373,8 +1375,18 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) mtk_btcvsd_snd_set_state(btcvsd, btcvsd->tx, BT_SCO_STATE_IDLE); mtk_btcvsd_snd_set_state(btcvsd, btcvsd->rx, BT_SCO_STATE_IDLE); - return devm_snd_soc_register_component(dev, &mtk_btcvsd_snd_platform, - NULL, 0); + ret = devm_snd_soc_register_component(dev, &mtk_btcvsd_snd_platform, + NULL, 0); + if (ret) + goto unmap_bank2_err; + + return 0; + +unmap_bank2_err: + iounmap(btcvsd->bt_sram_bank2_base); +unmap_pkv_err: + iounmap(btcvsd->bt_pkv_base); + return ret; } static int mtk_btcvsd_snd_remove(struct platform_device *pdev) diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c index f040dce85da5..f8c73e8624df 100644 --- a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c +++ b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c @@ -413,8 +413,6 @@ static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMU: if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x38); - else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) - regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30); else regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30); break; diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index 9339fabccb79..1dfee1396843 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -21,17 +21,41 @@ #define TOACODEC_CTRL0 0x0 #define CTRL0_ENABLE_SHIFT 31 -#define CTRL0_DAT_SEL_SHIFT 14 -#define CTRL0_DAT_SEL (0x3 << CTRL0_DAT_SEL_SHIFT) +#define CTRL0_DAT_SEL_SM1_MSB 19 +#define CTRL0_DAT_SEL_SM1_LSB 18 +#define CTRL0_DAT_SEL_MSB 15 +#define CTRL0_DAT_SEL_LSB 14 +#define CTRL0_LANE_SEL_SM1 16 #define CTRL0_LANE_SEL 12 -#define CTRL0_LRCLK_SEL GENMASK(9, 8) +#define CTRL0_LRCLK_SEL_SM1_MSB 14 +#define CTRL0_LRCLK_SEL_SM1_LSB 12 +#define CTRL0_LRCLK_SEL_MSB 9 +#define CTRL0_LRCLK_SEL_LSB 8 +#define CTRL0_LRCLK_INV_SM1 BIT(10) +#define CTRL0_BLK_CAP_INV_SM1 BIT(9) #define CTRL0_BLK_CAP_INV BIT(7) +#define CTRL0_BCLK_O_INV_SM1 BIT(8) #define CTRL0_BCLK_O_INV BIT(6) -#define CTRL0_BCLK_SEL GENMASK(5, 4) +#define CTRL0_BCLK_SEL_SM1_MSB 6 +#define CTRL0_BCLK_SEL_MSB 5 +#define CTRL0_BCLK_SEL_LSB 4 #define CTRL0_MCLK_SEL GENMASK(2, 0) #define TOACODEC_OUT_CHMAX 2 +struct g12a_toacodec { + struct regmap_field *field_dat_sel; + struct regmap_field *field_lrclk_sel; + struct regmap_field *field_bclk_sel; +}; + +struct g12a_toacodec_match_data { + const struct snd_soc_component_driver *component_drv; + struct reg_field field_dat_sel; + struct reg_field field_lrclk_sel; + struct reg_field field_bclk_sel; +}; + static const char * const g12a_toacodec_mux_texts[] = { "I2S A", "I2S B", "I2S C", }; @@ -41,29 +65,24 @@ static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); + struct g12a_toacodec *priv = snd_soc_component_get_drvdata(component); struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int mux, changed; + unsigned int mux, reg; mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); - changed = snd_soc_component_test_bits(component, e->reg, - CTRL0_DAT_SEL, - FIELD_PREP(CTRL0_DAT_SEL, mux)); + regmap_field_read(priv->field_dat_sel, ®); - if (!changed) + if (mux == reg) return 0; /* Force disconnect of the mux while updating */ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); - snd_soc_component_update_bits(component, e->reg, - CTRL0_DAT_SEL | - CTRL0_LRCLK_SEL | - CTRL0_BCLK_SEL, - FIELD_PREP(CTRL0_DAT_SEL, mux) | - FIELD_PREP(CTRL0_LRCLK_SEL, mux) | - FIELD_PREP(CTRL0_BCLK_SEL, mux)); + regmap_field_write(priv->field_dat_sel, mux); + regmap_field_write(priv->field_lrclk_sel, mux); + regmap_field_write(priv->field_bclk_sel, mux); /* * FIXME: @@ -86,7 +105,11 @@ static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol, } static SOC_ENUM_SINGLE_DECL(g12a_toacodec_mux_enum, TOACODEC_CTRL0, - CTRL0_DAT_SEL_SHIFT, + CTRL0_DAT_SEL_LSB, + g12a_toacodec_mux_texts); + +static SOC_ENUM_SINGLE_DECL(sm1_toacodec_mux_enum, TOACODEC_CTRL0, + CTRL0_DAT_SEL_SM1_LSB, g12a_toacodec_mux_texts); static const struct snd_kcontrol_new g12a_toacodec_mux = @@ -94,6 +117,11 @@ static const struct snd_kcontrol_new g12a_toacodec_mux = snd_soc_dapm_get_enum_double, g12a_toacodec_mux_put_enum); +static const struct snd_kcontrol_new sm1_toacodec_mux = + SOC_DAPM_ENUM_EXT("Source", sm1_toacodec_mux_enum, + snd_soc_dapm_get_enum_double, + g12a_toacodec_mux_put_enum); + static const struct snd_kcontrol_new g12a_toacodec_out_enable = SOC_DAPM_SINGLE_AUTODISABLE("Switch", TOACODEC_CTRL0, CTRL0_ENABLE_SHIFT, 1, 0); @@ -105,6 +133,13 @@ static const struct snd_soc_dapm_widget g12a_toacodec_widgets[] = { &g12a_toacodec_out_enable), }; +static const struct snd_soc_dapm_widget sm1_toacodec_widgets[] = { + SND_SOC_DAPM_MUX("SRC", SND_SOC_NOPM, 0, 0, + &sm1_toacodec_mux), + SND_SOC_DAPM_SWITCH("OUT EN", SND_SOC_NOPM, 0, 0, + &g12a_toacodec_out_enable), +}; + static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -175,6 +210,13 @@ static int g12a_toacodec_component_probe(struct snd_soc_component *c) CTRL0_BLK_CAP_INV); } +static int sm1_toacodec_component_probe(struct snd_soc_component *c) +{ + /* Initialize the static clock parameters */ + return snd_soc_component_write(c, TOACODEC_CTRL0, + CTRL0_BLK_CAP_INV_SM1); +} + static const struct snd_soc_dapm_route g12a_toacodec_routes[] = { { "SRC", "I2S A", "IN A Playback" }, { "SRC", "I2S B", "IN B Playback" }, @@ -187,6 +229,10 @@ static const struct snd_kcontrol_new g12a_toacodec_controls[] = { SOC_SINGLE("Lane Select", TOACODEC_CTRL0, CTRL0_LANE_SEL, 3, 0), }; +static const struct snd_kcontrol_new sm1_toacodec_controls[] = { + SOC_SINGLE("Lane Select", TOACODEC_CTRL0, CTRL0_LANE_SEL_SM1, 3, 0), +}; + static const struct snd_soc_component_driver g12a_toacodec_component_drv = { .probe = g12a_toacodec_component_probe, .controls = g12a_toacodec_controls, @@ -199,25 +245,72 @@ static const struct snd_soc_component_driver g12a_toacodec_component_drv = { .non_legacy_dai_naming = 1, }; +static const struct snd_soc_component_driver sm1_toacodec_component_drv = { + .probe = sm1_toacodec_component_probe, + .controls = sm1_toacodec_controls, + .num_controls = ARRAY_SIZE(sm1_toacodec_controls), + .dapm_widgets = sm1_toacodec_widgets, + .num_dapm_widgets = ARRAY_SIZE(sm1_toacodec_widgets), + .dapm_routes = g12a_toacodec_routes, + .num_dapm_routes = ARRAY_SIZE(g12a_toacodec_routes), + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + static const struct regmap_config g12a_toacodec_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, }; +static const struct g12a_toacodec_match_data g12a_toacodec_match_data = { + .component_drv = &g12a_toacodec_component_drv, + .field_dat_sel = REG_FIELD(TOACODEC_CTRL0, 14, 15), + .field_lrclk_sel = REG_FIELD(TOACODEC_CTRL0, 8, 9), + .field_bclk_sel = REG_FIELD(TOACODEC_CTRL0, 4, 5), +}; + +static const struct g12a_toacodec_match_data sm1_toacodec_match_data = { + .component_drv = &sm1_toacodec_component_drv, + .field_dat_sel = REG_FIELD(TOACODEC_CTRL0, 18, 19), + .field_lrclk_sel = REG_FIELD(TOACODEC_CTRL0, 12, 14), + .field_bclk_sel = REG_FIELD(TOACODEC_CTRL0, 4, 6), +}; + static const struct of_device_id g12a_toacodec_of_match[] = { - { .compatible = "amlogic,g12a-toacodec", }, + { + .compatible = "amlogic,g12a-toacodec", + .data = &g12a_toacodec_match_data, + }, + { + .compatible = "amlogic,sm1-toacodec", + .data = &sm1_toacodec_match_data, + }, {} }; MODULE_DEVICE_TABLE(of, g12a_toacodec_of_match); static int g12a_toacodec_probe(struct platform_device *pdev) { + const struct g12a_toacodec_match_data *data; struct device *dev = &pdev->dev; + struct g12a_toacodec *priv; void __iomem *regs; struct regmap *map; int ret; + data = device_get_match_data(dev); + if (!data) { + dev_err(dev, "failed to match device\n"); + return -ENODEV; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + ret = device_reset(dev); if (ret) return ret; @@ -233,8 +326,20 @@ static int g12a_toacodec_probe(struct platform_device *pdev) return PTR_ERR(map); } + priv->field_dat_sel = devm_regmap_field_alloc(dev, map, data->field_dat_sel); + if (IS_ERR(priv->field_dat_sel)) + return PTR_ERR(priv->field_dat_sel); + + priv->field_lrclk_sel = devm_regmap_field_alloc(dev, map, data->field_lrclk_sel); + if (IS_ERR(priv->field_lrclk_sel)) + return PTR_ERR(priv->field_lrclk_sel); + + priv->field_bclk_sel = devm_regmap_field_alloc(dev, map, data->field_bclk_sel); + if (IS_ERR(priv->field_bclk_sel)) + return PTR_ERR(priv->field_bclk_sel); + return devm_snd_soc_register_component(dev, - &g12a_toacodec_component_drv, g12a_toacodec_dai_drv, + data->component_drv, g12a_toacodec_dai_drv, ARRAY_SIZE(g12a_toacodec_dai_drv)); } diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 300ac8be46ef..415cc0046e4b 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -119,9 +119,9 @@ unsigned int meson_card_parse_daifmt(struct device_node *node, struct device_node *framemaster = NULL; unsigned int daifmt; - daifmt = snd_soc_of_parse_daifmt(node, "", - &bitclkmaster, &framemaster); - daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; + daifmt = snd_soc_daifmt_parse_format(node, NULL); + + snd_soc_daifmt_parse_clock_provider_as_phandle(node, NULL, &bitclkmaster, &framemaster); /* If no master is provided, default to cpu master */ if (!bitclkmaster || bitclkmaster == cpu_node) { diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 270986b2f102..08a05f0ecad7 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -134,7 +134,6 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct snd_soc_card *card; struct apq8016_sbc_data *data; - struct resource *res; int ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); @@ -151,13 +150,11 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) if (ret) return ret; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mic-iomux"); - data->mic_iomux = devm_ioremap_resource(dev, res); + data->mic_iomux = devm_platform_ioremap_resource_byname(pdev, "mic-iomux"); if (IS_ERR(data->mic_iomux)) return PTR_ERR(data->mic_iomux); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spkr-iomux"); - data->spkr_iomux = devm_ioremap_resource(dev, res); + data->spkr_iomux = devm_platform_ioremap_resource_byname(pdev, "spkr-iomux"); if (IS_ERR(data->spkr_iomux)) return PTR_ERR(data->spkr_iomux); diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index a6e95db6b3fb..3bd9eb3cc688 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -29,6 +29,15 @@ #define LPASS_CPU_I2S_SD0_1_2_MASK GENMASK(2, 0) #define LPASS_CPU_I2S_SD0_1_2_3_MASK GENMASK(3, 0) +/* + * Channel maps for Quad channel playbacks on MI2S Secondary + */ +static struct snd_pcm_chmap_elem lpass_quad_chmaps[] = { + { .channels = 4, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_RL, + SNDRV_CHMAP_FR, SNDRV_CHMAP_RR } }, + { } +}; static int lpass_cpu_init_i2sctl_bitfields(struct device *dev, struct lpaif_i2sctl *i2sctl, struct regmap *map) { @@ -403,6 +412,25 @@ const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { }; EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops); +int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai) +{ + int ret; + struct snd_soc_dai_driver *drv = dai->driver; + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + + if (drvdata->mi2s_playback_sd_mode[dai->id] == LPAIF_I2SCTL_MODE_QUAD01) { + ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, + lpass_quad_chmaps, drv->playback.channels_max, 0, + NULL); + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new); + int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); @@ -497,6 +525,8 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) return true; for (i = 0; i < v->irq_ports; ++i) { + if (reg == LPAIF_IRQCLEAR_REG(v, i)) + return true; if (reg == LPAIF_IRQEN_REG(v, i)) return true; if (reg == LPAIF_IRQSTAT_REG(v, i)) @@ -538,9 +568,12 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) struct lpass_variant *v = drvdata->variant; int i; - for (i = 0; i < v->irq_ports; ++i) + for (i = 0; i < v->irq_ports; ++i) { + if (reg == LPAIF_IRQCLEAR_REG(v, i)) + return true; if (reg == LPAIF_IRQSTAT_REG(v, i)) return true; + } for (i = 0; i < v->rdma_channels; ++i) if (reg == LPAIF_RDMACURR_REG(v, i)) @@ -839,7 +872,6 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) { struct lpass_data *drvdata; struct device_node *dsp_of_node; - struct resource *res; struct lpass_variant *variant; struct device *dev = &pdev->dev; const struct of_device_id *match; @@ -865,9 +897,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) of_lpass_cpu_parse_dai_data(dev, drvdata); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif"); - - drvdata->lpaif = devm_ioremap_resource(dev, res); + drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif"); if (IS_ERR(drvdata->lpaif)) return PTR_ERR(drvdata->lpaif); @@ -884,9 +914,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) } if (drvdata->hdmi_port_enable) { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-hdmiif"); - - drvdata->hdmiif = devm_ioremap_resource(dev, res); + drvdata->hdmiif = devm_platform_ioremap_resource_byname(pdev, "lpass-hdmiif"); if (IS_ERR(drvdata->hdmiif)) return PTR_ERR(drvdata->hdmiif); @@ -925,6 +953,11 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) PTR_ERR(drvdata->mi2s_bit_clk[dai_id])); return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]); } + if (drvdata->mi2s_playback_sd_mode[dai_id] == + LPAIF_I2SCTL_MODE_QUAD01) { + variant->dai_driver[dai_id].playback.channels_min = 4; + variant->dai_driver[dai_id].playback.channels_max = 4; + } } /* Allocation for i2sctl regmap fields */ diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 0df9481ea4c6..f9df76d37858 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -526,7 +526,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, return -EINVAL; } - ret = regmap_write(map, reg_irqclr, val_irqclr); + ret = regmap_update_bits(map, reg_irqclr, val_irqclr, val_irqclr); if (ret) { dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret); return ret; @@ -650,10 +650,11 @@ static irqreturn_t lpass_dma_interrupt_handler( struct lpass_variant *v = drvdata->variant; irqreturn_t ret = IRQ_NONE; int rv; - unsigned int reg = 0, val = 0; + unsigned int reg, val, mask; struct regmap *map; unsigned int dai_id = cpu_dai->driver->id; + mask = LPAIF_IRQ_ALL(chan); switch (dai_id) { case LPASS_DP_RX: map = drvdata->hdmiif_map; @@ -676,8 +677,7 @@ static irqreturn_t lpass_dma_interrupt_handler( return -EINVAL; } if (interrupts & LPAIF_IRQ_PER(chan)) { - - rv = regmap_write(map, reg, LPAIF_IRQ_PER(chan) | val); + rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val)); if (rv) { dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", rv); @@ -688,7 +688,7 @@ static irqreturn_t lpass_dma_interrupt_handler( } if (interrupts & LPAIF_IRQ_XRUN(chan)) { - rv = regmap_write(map, reg, LPAIF_IRQ_XRUN(chan) | val); + rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val)); if (rv) { dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", rv); @@ -700,7 +700,7 @@ static irqreturn_t lpass_dma_interrupt_handler( } if (interrupts & LPAIF_IRQ_ERR(chan)) { - rv = regmap_write(map, reg, LPAIF_IRQ_ERR(chan) | val); + rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val)); if (rv) { dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", rv); diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 8c168d3c589e..77a556b27cf0 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -58,6 +58,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { }, .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, + .pcm_new = lpass_cpu_pcm_new, }, { .id = LPASS_DP_RX, .name = "Hdmi", diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 7f72214404ba..67ef497166af 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -263,5 +263,7 @@ void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; +int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai); #endif /* __LPASS_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index b539af86e8f7..ac8f7324e94b 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -475,6 +475,7 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, q6afe_slim_port_prepare(dai_data->port[dai->id], &dai_data->port_config[dai->id].slim); break; + case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: rc = q6afe_i2s_port_prepare(dai_data->port[dai->id], &dai_data->port_config[dai->id].i2s_cfg); @@ -598,6 +599,7 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"Secondary MI2S Playback", NULL, "SEC_MI2S_RX"}, {"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"}, {"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"}, + {"Quinary MI2S Playback", NULL, "QUIN_MI2S_RX"}, {"Primary TDM0 Playback", NULL, "PRIMARY_TDM_RX_0"}, {"Primary TDM1 Playback", NULL, "PRIMARY_TDM_RX_1"}, @@ -693,6 +695,7 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"PRI_MI2S_TX", NULL, "Primary MI2S Capture"}, {"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"}, {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"}, + {"QUIN_MI2S_TX", NULL, "Quinary MI2S Capture"}, {"WSA_CODEC_DMA_RX_0 Playback", NULL, "WSA_CODEC_DMA_RX_0"}, {"WSA_CODEC_DMA_TX_0", NULL, "WSA_CODEC_DMA_TX_0 Capture"}, @@ -1190,6 +1193,39 @@ static struct snd_soc_dai_driver q6afe_dais[] = { .ops = &q6i2s_ops, .probe = msm_dai_q6_dai_probe, .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Quinary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 192000, + }, + .id = QUINARY_MI2S_RX, + .name = "QUIN_MI2S_RX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Quinary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = QUINARY_MI2S_TX, + .name = "QUIN_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, }, Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0), Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1), @@ -1349,6 +1385,10 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_TX", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_TX", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_TX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("QUIN_MI2S_RX", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("QUIN_MI2S_TX", NULL, + 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("QUAT_MI2S_RX", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_TX", NULL, @@ -1610,6 +1650,7 @@ static void of_q6afe_parse_dai_data(struct device *dev, switch (id) { /* MI2S specific properties */ + case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: priv = &data->priv[id]; ret = of_property_read_variable_u32_array(node, diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 729d27da0447..625724852a7f 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -120,6 +120,8 @@ #define AFE_PORT_ID_TERTIARY_MI2S_TX 0x1005 #define AFE_PORT_ID_QUATERNARY_MI2S_RX 0x1006 #define AFE_PORT_ID_QUATERNARY_MI2S_TX 0x1007 +#define AFE_PORT_ID_QUINARY_MI2S_RX 0x1016 +#define AFE_PORT_ID_QUINARY_MI2S_TX 0x1017 /* Start of the range of port IDs for TDM devices. */ #define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000 @@ -620,6 +622,10 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = { QUATERNARY_MI2S_RX, 1, 1}, [QUATERNARY_MI2S_TX] = { AFE_PORT_ID_QUATERNARY_MI2S_TX, QUATERNARY_MI2S_TX, 0, 1}, + [QUINARY_MI2S_RX] = { AFE_PORT_ID_QUINARY_MI2S_RX, + QUINARY_MI2S_RX, 1, 1}, + [QUINARY_MI2S_TX] = { AFE_PORT_ID_QUINARY_MI2S_TX, + QUINARY_MI2S_TX, 0, 1}, [PRIMARY_TDM_RX_0] = { AFE_PORT_ID_PRIMARY_TDM_RX, PRIMARY_TDM_RX_0, 1, 1}, [PRIMARY_TDM_TX_0] = { AFE_PORT_ID_PRIMARY_TDM_TX, @@ -1596,6 +1602,8 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) case AFE_PORT_ID_TERTIARY_MI2S_TX: case AFE_PORT_ID_QUATERNARY_MI2S_RX: case AFE_PORT_ID_QUATERNARY_MI2S_TX: + case AFE_PORT_ID_QUINARY_MI2S_RX: + case AFE_PORT_ID_QUINARY_MI2S_TX: cfg_type = AFE_PARAM_ID_I2S_CONFIG; break; case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7: diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index f9a1c04e38c2..30fd77e2f458 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -5,7 +5,7 @@ #include <dt-bindings/sound/qcom,q6afe.h> -#define AFE_PORT_MAX 127 +#define AFE_PORT_MAX 129 #define MSM_AFE_PORT_TYPE_RX 0 #define MSM_AFE_PORT_TYPE_TX 1 diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 9766725c2916..5ff56a735419 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -1169,7 +1169,7 @@ static int q6asm_dai_compr_get_codec_caps(struct snd_soc_component *component, return 0; } -static struct snd_compress_ops q6asm_dai_compress_ops = { +static const struct snd_compress_ops q6asm_dai_compress_ops = { .open = q6asm_dai_compr_open, .free = q6asm_dai_compr_free, .set_params = q6asm_dai_compr_set_params, diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index 0a6b9433f6ac..3390ebef9549 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -66,6 +66,7 @@ { mix_name, "PRI_MI2S_TX", "PRI_MI2S_TX" }, \ { mix_name, "SEC_MI2S_TX", "SEC_MI2S_TX" }, \ { mix_name, "QUAT_MI2S_TX", "QUAT_MI2S_TX" }, \ + { mix_name, "QUIN_MI2S_TX", "QUIN_MI2S_TX" }, \ { mix_name, "TERT_MI2S_TX", "TERT_MI2S_TX" }, \ { mix_name, "SLIMBUS_0_TX", "SLIMBUS_0_TX" }, \ { mix_name, "SLIMBUS_1_TX", "SLIMBUS_1_TX" }, \ @@ -140,6 +141,9 @@ SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, \ id, 1, 0, msm_routing_get_audio_mixer, \ msm_routing_put_audio_mixer), \ + SOC_SINGLE_EXT("QUIN_MI2S_TX", QUINARY_MI2S_TX, \ + id, 1, 0, msm_routing_get_audio_mixer, \ + msm_routing_put_audio_mixer), \ SOC_SINGLE_EXT("SLIMBUS_0_TX", SLIMBUS_0_TX, \ id, 1, 0, msm_routing_get_audio_mixer, \ msm_routing_put_audio_mixer), \ @@ -513,6 +517,9 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { Q6ROUTING_RX_MIXERS(QUATERNARY_MI2S_RX) }; +static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(QUINARY_MI2S_RX) }; + static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { Q6ROUTING_RX_MIXERS(TERTIARY_MI2S_RX) }; @@ -752,6 +759,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, quaternary_mi2s_rx_mixer_controls, ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("QUIN_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, + quinary_mi2s_rx_mixer_controls, + ARRAY_SIZE(quinary_mi2s_rx_mixer_controls)), SND_SOC_DAPM_MIXER("TERT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, tertiary_mi2s_rx_mixer_controls, ARRAY_SIZE(tertiary_mi2s_rx_mixer_controls)), @@ -941,6 +951,7 @@ static const struct snd_soc_dapm_route intercon[] = { Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_5_RX Audio Mixer", "SLIMBUS_5_RX"), Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_6_RX Audio Mixer", "SLIMBUS_6_RX"), Q6ROUTING_RX_DAPM_ROUTE("QUAT_MI2S_RX Audio Mixer", "QUAT_MI2S_RX"), + Q6ROUTING_RX_DAPM_ROUTE("QUIN_MI2S_RX Audio Mixer", "QUIN_MI2S_RX"), Q6ROUTING_RX_DAPM_ROUTE("TERT_MI2S_RX Audio Mixer", "TERT_MI2S_RX"), Q6ROUTING_RX_DAPM_ROUTE("SEC_MI2S_RX Audio Mixer", "SEC_MI2S_RX"), Q6ROUTING_RX_DAPM_ROUTE("PRI_MI2S_RX Audio Mixer", "PRI_MI2S_RX"), diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 153e9b2de0b5..0adfc5708949 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -288,6 +288,14 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dai_set_sysclk(codec_dai, 0, WCD934X_DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + + rval = snd_soc_component_set_jack(codec_dai->component, + &pdata->jack, NULL); + if (rval != 0 && rval != -ENOTSUPP) { + dev_warn(card->dev, "Failed to set jack: %d\n", rval); + return rval; + } + } break; default: diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 0740764e7f71..c7dc3509bceb 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -618,8 +618,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev) return PTR_ERR(i2s->mclk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 9295d648624e..38bd603eeb45 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -495,8 +495,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev) return PTR_ERR(pdm->reset); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index ffb4ec306441..73226a46d489 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -313,8 +313,7 @@ static int rk_spdif_probe(struct platform_device *pdev) if (IS_ERR(spdif->mclk)) return PTR_ERR(spdif->mclk); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index c632842d42eb..309badc97290 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1441,8 +1441,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) } } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->addr = devm_ioremap_resource(&pdev->dev, res); + priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(priv->addr)) return PTR_ERR(priv->addr); diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index bfd76e9cc0ca..4c4dfde0568f 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -512,8 +512,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) /* Default is 128fs */ pcm->sclk_per_fs = 128; - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pcm->regs = devm_ioremap_resource(&pdev->dev, mem_res); + pcm->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res); if (IS_ERR(pcm->regs)) return PTR_ERR(pcm->regs); diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 81f416ac457e..ec1c6f9d76ac 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -208,8 +208,7 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) return -ENXIO; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - s3c2412_i2s.regs = devm_ioremap_resource(&pdev->dev, res); + s3c2412_i2s.regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(s3c2412_i2s.regs)) return PTR_ERR(s3c2412_i2s.regs); diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 50c08008aacb..0f46304eaa4f 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -425,8 +425,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) struct resource *res; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res); + s3c24xx_i2s.regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(s3c24xx_i2s.regs)) return PTR_ERR(s3c24xx_i2s.regs); diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 3c574792231b..cdf3b7f69ba7 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -219,7 +219,7 @@ struct fsi_stream { u32 bus_option; /* - * thse are initialized by fsi_handler_init() + * these are initialized by fsi_handler_init() */ struct fsi_stream_handler *handler; struct fsi_priv *priv; @@ -1694,12 +1694,27 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, return 0; } +/* + * Select below from Sound Card, not auto + * SND_SOC_DAIFMT_CBC_CFC + * SND_SOC_DAIFMT_CBP_CFP + */ +static u64 fsi_dai_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + static const struct snd_soc_dai_ops fsi_dai_ops = { .startup = fsi_dai_startup, .shutdown = fsi_dai_shutdown, .trigger = fsi_dai_trigger, .set_fmt = fsi_dai_set_fmt, .hw_params = fsi_dai_hw_params, + .auto_selectable_formats = &fsi_dai_formats, + .num_auto_selectable_formats = 1, }; /* diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 5d1ff8ef26f9..d07eccfa3ac2 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 0b8ae3eee148..0ebee1ed06a9 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -3,8 +3,8 @@ // Helper routines for R-Car sound ADG. // // Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - #include <linux/clk-provider.h> +#include <linux/clkdev.h> #include "rsnd.h" #define CLKA 0 @@ -28,6 +28,7 @@ static struct rsnd_mod_ops adg_ops = { struct rsnd_adg { struct clk *clk[CLKMAX]; struct clk *clkout[CLKOUTMAX]; + struct clk *null_clk; struct clk_onecell_data onecell; struct rsnd_mod mod; int clk_rate[CLKMAX]; @@ -290,7 +291,6 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct clk *clk; int i; int sel_table[] = { [CLKA] = 0x1, @@ -303,10 +303,9 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) * find suitable clock from * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. */ - for_each_rsnd_clk(clk, adg, i) { + for (i = 0; i < CLKMAX; i++) if (rate == adg->clk_rate[i]) return sel_table[i]; - } /* * find divided clock from BRGA/BRGB @@ -365,48 +364,103 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct device *dev = rsnd_priv_to_dev(priv); struct clk *clk; int i; for_each_rsnd_clk(clk, adg, i) { if (enable) { - int ret = clk_prepare_enable(clk); + clk_prepare_enable(clk); /* * We shouldn't use clk_get_rate() under * atomic context. Let's keep it when * rsnd_adg_clk_enable() was called */ - adg->clk_rate[i] = 0; - if (ret < 0) - dev_warn(dev, "can't use clk %d\n", i); - else - adg->clk_rate[i] = clk_get_rate(clk); + adg->clk_rate[i] = clk_get_rate(clk); } else { - if (adg->clk_rate[i]) - clk_disable_unprepare(clk); - adg->clk_rate[i] = 0; + clk_disable_unprepare(clk); } } } -static void rsnd_adg_get_clkin(struct rsnd_priv *priv, - struct rsnd_adg *adg) +static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv, + const char * const name, + const char *parent) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct clk *clk; + + clk = clk_register_fixed_rate(dev, name, parent, 0, 0); + if (IS_ERR(clk)) { + dev_err(dev, "create null clk error\n"); + return NULL; + } + + return clk; +} + +static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = priv->adg; + + if (!adg->null_clk) { + static const char * const name = "rsnd_adg_null"; + + adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL); + } + + return adg->null_clk; +} + +static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv) { + struct rsnd_adg *adg = priv->adg; + + if (adg->null_clk) + clk_unregister_fixed_rate(adg->null_clk); +} + +static int rsnd_adg_get_clkin(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = priv->adg; struct device *dev = rsnd_priv_to_dev(priv); + struct clk *clk; int i; for (i = 0; i < CLKMAX; i++) { - struct clk *clk = devm_clk_get(dev, clk_name[i]); + clk = devm_clk_get(dev, clk_name[i]); + + if (IS_ERR(clk)) + clk = rsnd_adg_null_clk_get(priv); + if (IS_ERR(clk)) + goto err; - adg->clk[i] = IS_ERR(clk) ? NULL : clk; + adg->clk[i] = clk; } + + return 0; + +err: + dev_err(dev, "adg clock IN get failed\n"); + + rsnd_adg_null_clk_clean(priv); + + return -EIO; } -static void rsnd_adg_get_clkout(struct rsnd_priv *priv, - struct rsnd_adg *adg) +static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv) { + struct rsnd_adg *adg = priv->adg; + struct clk *clk; + int i; + + for_each_rsnd_clkout(clk, adg, i) + clk_unregister_fixed_rate(clk); +} + +static int rsnd_adg_get_clkout(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = priv->adg; struct clk *clk; struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; @@ -446,9 +500,8 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, req_size = prop->length / sizeof(u32); if (req_size > REQ_SIZE) { - dev_err(dev, - "too many clock-frequency, use top %d\n", REQ_SIZE); - req_size = REQ_SIZE; + dev_err(dev, "too many clock-frequency\n"); + return -EINVAL; } of_property_read_u32_array(np, "clock-frequency", req_rate, req_size); @@ -529,10 +582,11 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, if (!count) { clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], parent_clk_name, 0, req_rate[0]); - if (!IS_ERR(clk)) { - adg->clkout[CLKOUT] = clk; - of_clk_add_provider(np, of_clk_src_simple_get, clk); - } + if (IS_ERR(clk)) + goto err; + + adg->clkout[CLKOUT] = clk; + of_clk_add_provider(np, of_clk_src_simple_get, clk); } /* * for clkout0/1/2/3 @@ -542,8 +596,10 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, clk = clk_register_fixed_rate(dev, clkout_name[i], parent_clk_name, 0, req_rate[0]); - if (!IS_ERR(clk)) - adg->clkout[i] = clk; + if (IS_ERR(clk)) + goto err; + + adg->clkout[i] = clk; } adg->onecell.clks = adg->clkout; adg->onecell.clk_num = CLKOUTMAX; @@ -555,34 +611,61 @@ rsnd_adg_get_clkout_end: adg->ckr = ckr; adg->rbga = rbga; adg->rbgb = rbgb; + + return 0; + +err: + dev_err(dev, "adg clock OUT get failed\n"); + + rsnd_adg_unregister_clkout(priv); + + return -EIO; } -#ifdef DEBUG -static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg) +#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) +__printf(3, 4) +static void dbg_msg(struct device *dev, struct seq_file *m, + const char *fmt, ...) { + char msg[128]; + va_list args; + + va_start(args, fmt); + vsnprintf(msg, sizeof(msg), fmt, args); + va_end(args); + + if (m) + seq_puts(m, msg); + else + dev_dbg(dev, "%s", msg); +} + +void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); struct clk *clk; int i; for_each_rsnd_clk(clk, adg, i) - dev_dbg(dev, "%s : %pa : %ld\n", + dbg_msg(dev, m, "%s : %pa : %ld\n", clk_name[i], clk, clk_get_rate(clk)); - dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", + dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", adg->ckr, adg->rbga, adg->rbgb); - dev_dbg(dev, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz); - dev_dbg(dev, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz); + dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz); + dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz); /* * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start() * by BRGCKR::BRGCKR_31 */ for_each_rsnd_clkout(clk, adg, i) - dev_dbg(dev, "clkout %d : %pa : %ld\n", i, + dbg_msg(dev, m, "clkout %d : %pa : %ld\n", i, clk, clk_get_rate(clk)); } #else -#define rsnd_adg_clk_dbg_info(priv, adg) +#define rsnd_adg_clk_dbg_info(priv, m) #endif int rsnd_adg_probe(struct rsnd_priv *priv) @@ -600,13 +683,18 @@ int rsnd_adg_probe(struct rsnd_priv *priv) if (ret) return ret; - rsnd_adg_get_clkin(priv, adg); - rsnd_adg_get_clkout(priv, adg); - rsnd_adg_clk_dbg_info(priv, adg); - priv->adg = adg; + ret = rsnd_adg_get_clkin(priv); + if (ret) + return ret; + + ret = rsnd_adg_get_clkout(priv); + if (ret) + return ret; + rsnd_adg_clk_enable(priv); + rsnd_adg_clk_dbg_info(priv, NULL); return 0; } @@ -615,15 +703,13 @@ void rsnd_adg_remove(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; - struct rsnd_adg *adg = priv->adg; - struct clk *clk; - int i; - for_each_rsnd_clkout(clk, adg, i) - if (adg->clkout[i]) - clk_unregister_fixed_rate(adg->clkout[i]); + rsnd_adg_unregister_clkout(priv); of_clk_del_provider(np); rsnd_adg_clk_disable(priv); + + /* It should be called after rsnd_adg_clk_disable() */ + rsnd_adg_null_clk_clean(priv); } diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 9fdb37c2cbc2..329e6ab1b222 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -114,12 +114,26 @@ static int rsnd_cmd_stop(struct rsnd_mod *mod, return 0; } +#ifdef CONFIG_DEBUG_FS +static void rsnd_cmd_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, + 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30); +} +#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info +#else +#define DEBUG_INFO +#endif + static struct rsnd_mod_ops rsnd_cmd_ops = { .name = CMD_NAME, .init = rsnd_cmd_init, .start = rsnd_cmd_start, .stop = rsnd_cmd_stop, .get_status = rsnd_mod_get_status, + DEBUG_INFO }; static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8696a993c478..5e382b5c9d45 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -90,14 +90,6 @@ * */ -/* - * you can enable below define if you don't need - * DAI status debug message when debugging - * see rsnd_dbg_dai_call() - * - * #define RSND_DEBUG_NO_DAI_CALL 1 - */ - #include <linux/pm_runtime.h> #include "rsnd.h" @@ -267,8 +259,9 @@ int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, */ if (params) return params_channels(params); - else + else if (runtime) return runtime->channels; + return 0; } int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, @@ -533,16 +526,22 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { }, }; -static int rsnd_status_update(u32 *status, +static int rsnd_status_update(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, enum rsnd_mod_type type, int shift, int add, int timing) { + u32 *status = mod->ops->get_status(mod, io, type); u32 mask = 0xF << shift; u8 val = (*status >> shift) & 0xF; u8 next_val = (val + add) & 0xF; int func_call = (val == timing); + /* no status update */ + if (add == 0 || shift == 28) + return 1; + if (next_val == 0xF) /* underflow case */ - func_call = 0; + func_call = -1; else *status = (*status & ~mask) + (next_val << shift); @@ -558,19 +557,16 @@ static int rsnd_status_update(u32 *status, enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ int tmp = 0; \ - u32 *status = mod->ops->get_status(mod, io, types[i]); \ - int func_call = rsnd_status_update(status, \ + int func_call = rsnd_status_update(io, mod, types[i], \ __rsnd_mod_shift_##fn, \ __rsnd_mod_add_##fn, \ __rsnd_mod_call_##fn); \ - rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n", \ - rsnd_mod_name(mod), *status, \ - (func_call && (mod)->ops->fn) ? #fn : ""); \ - if (func_call && (mod)->ops->fn) \ + if (func_call > 0 && (mod)->ops->fn) \ tmp = (mod)->ops->fn(mod, io, param); \ - if (tmp && (tmp != -EPROBE_DEFER)) \ - dev_err(dev, "%s : %s error %d\n", \ - rsnd_mod_name(mod), #fn, tmp); \ + if (unlikely(func_call < 0) || \ + unlikely(tmp && (tmp != -EPROBE_DEFER))) \ + dev_err(dev, "%s : %s error (%d, %d)\n", \ + rsnd_mod_name(mod), #fn, tmp, func_call);\ ret |= tmp; \ } \ ret; \ @@ -760,10 +756,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* set clock master for audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rdai->clk_master = 0; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: rdai->clk_master = 1; /* cpu is master */ break; default: @@ -1043,6 +1039,31 @@ static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream, return rsnd_dai_call(prepare, io, priv); } +static u64 rsnd_soc_dai_formats[] = { + /* + * 1st Priority + * + * Well tested formats. + * Select below from Sound Card, not auto + * SND_SOC_DAIFMT_CBC_CFC + * SND_SOC_DAIFMT_CBP_CFP + */ + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF, + /* + * 2nd Priority + * + * Supported, but not well tested + */ + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B, +}; + static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .startup = rsnd_soc_dai_startup, .shutdown = rsnd_soc_dai_shutdown, @@ -1050,6 +1071,8 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .set_fmt = rsnd_soc_dai_set_fmt, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, .prepare = rsnd_soc_dai_prepare, + .auto_selectable_formats = rsnd_soc_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), }; static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, @@ -1129,7 +1152,7 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv, of_node_put(remote_node); } -void rsnd_parse_connect_common(struct rsnd_dai *rdai, +void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), struct device_node *node, struct device_node *playback, @@ -1144,7 +1167,11 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, i = 0; for_each_child_of_node(node, np) { - struct rsnd_mod *mod = mod_get(priv, i); + struct rsnd_mod *mod; + + i = rsnd_node_fixed_index(np, name, i); + + mod = mod_get(priv, i); if (np == playback) rsnd_dai_connect(mod, &rdai->playback, mod->type); @@ -1156,6 +1183,56 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, of_node_put(node); } +int rsnd_node_fixed_index(struct device_node *node, char *name, int idx) +{ + char node_name[16]; + + /* + * rsnd is assuming each device nodes are sequential numbering, + * but some of them are not. + * This function adjusts index for it. + * + * ex) + * Normal case, special case + * ssi-0 + * ssi-1 + * ssi-2 + * ssi-3 ssi-3 + * ssi-4 ssi-4 + * ... + * + * assume Max 64 node + */ + for (; idx < 64; idx++) { + snprintf(node_name, sizeof(node_name), "%s-%d", name, idx); + + if (strncmp(node_name, of_node_full_name(node), sizeof(node_name)) == 0) + return idx; + } + + return -EINVAL; +} + +int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np; + int i; + + i = 0; + for_each_child_of_node(node, np) { + i = rsnd_node_fixed_index(np, name, i); + if (i < 0) { + dev_err(dev, "strange node numbering (%s)", + of_node_full_name(node)); + return 0; + } + i++; + } + + return i; +} + static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) { @@ -1388,6 +1465,26 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) /* * pcm ops */ +static int rsnd_hw_update(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + if (hw_params) + ret = rsnd_dai_call(hw_params, io, substream, hw_params); + else + ret = rsnd_dai_call(hw_free, io, substream); + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + static int rsnd_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) @@ -1495,17 +1592,13 @@ static int rsnd_hw_params(struct snd_soc_component *component, } } - return rsnd_dai_call(hw_params, io, substream, hw_params); + return rsnd_hw_update(substream, hw_params); } static int rsnd_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - - return rsnd_dai_call(hw_free, io, substream); + return rsnd_hw_update(substream, NULL); } static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component, @@ -1715,6 +1808,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, */ static const struct snd_soc_component_driver rsnd_soc_component = { .name = "rsnd", + .probe = rsnd_debugfs_probe, .hw_params = rsnd_hw_params, .hw_free = rsnd_hw_free, .pointer = rsnd_pointer, diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 20eecd088d13..6156445bcb69 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -275,6 +275,19 @@ static int rsnd_ctu_id_sub(struct rsnd_mod *mod) return mod->id % 4; } +#ifdef CONFIG_DEBUG_FS +static void rsnd_ctu_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, + 0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100); +} +#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info +#else +#define DEBUG_INFO +#endif + static struct rsnd_mod_ops rsnd_ctu_ops = { .name = CTU_NAME, .probe = rsnd_ctu_probe_, @@ -285,6 +298,7 @@ static struct rsnd_mod_ops rsnd_ctu_ops = { .id = rsnd_ctu_id, .id_sub = rsnd_ctu_id_sub, .id_cmd = rsnd_mod_id_raw, + DEBUG_INFO }; struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) diff --git a/sound/soc/sh/rcar/debugfs.c b/sound/soc/sh/rcar/debugfs.c new file mode 100644 index 000000000000..26d3b310b9db --- /dev/null +++ b/sound/soc/sh/rcar/debugfs.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// // Renesas R-Car debugfs support +// +// Copyright (c) 2021 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +// +// > mount -t debugfs none /sys/kernel/debug +// > cd /sys/kernel/debug/asoc/rcar-sound/ec500000.sound/rdai{N}/ +// > cat playback/xxx +// > cat capture/xxx +// +#ifdef CONFIG_DEBUG_FS + +#include <linux/debugfs.h> +#include "rsnd.h" + +static int rsnd_debugfs_show(struct seq_file *m, void *v) +{ + struct rsnd_dai_stream *io = m->private; + struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + int i; + + /* adg is out of mods */ + rsnd_adg_clk_dbg_info(priv, m); + + for_each_rsnd_mod(i, mod, io) { + u32 *status = mod->ops->get_status(mod, io, mod->type); + + seq_printf(m, "name: %s\n", rsnd_mod_name(mod)); + seq_printf(m, "status: %08x\n", *status); + + if (mod->ops->debug_info) + mod->ops->debug_info(m, io, mod); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rsnd_debugfs); + +void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr, + void __iomem *base, int offset, int size) +{ + int i, j; + + for (i = 0; i < size; i += 0x10) { + phys_addr_t addr = _addr + offset + i; + + seq_printf(m, "%pa:", &addr); + for (j = 0; j < 0x10; j += 0x4) + seq_printf(m, " %08x", __raw_readl(base + offset + i + j)); + seq_puts(m, "\n"); + } +} + +void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod, + int reg_id, int offset, int size) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + + rsnd_debugfs_reg_show(m, + rsnd_gen_get_phy_addr(priv, reg_id), + rsnd_gen_get_base_addr(priv, reg_id), + offset, size); +} + +int rsnd_debugfs_probe(struct snd_soc_component *component) +{ + struct rsnd_priv *priv = dev_get_drvdata(component->dev); + struct rsnd_dai *rdai; + struct dentry *dir; + char name[64]; + int i; + + /* Gen1 is not supported */ + if (rsnd_is_gen1(priv)) + return 0; + + for_each_rsnd_dai(rdai, priv, i) { + /* + * created debugfs will be automatically + * removed, nothing to do for _remove. + * see + * soc_cleanup_component_debugfs() + */ + snprintf(name, sizeof(name), "rdai%d", i); + dir = debugfs_create_dir(name, component->debugfs_root); + + debugfs_create_file("playback", 0444, dir, &rdai->playback, &rsnd_debugfs_fops); + debugfs_create_file("capture", 0444, dir, &rdai->capture, &rsnd_debugfs_fops); + } + + return 0; +} + +#endif /* CONFIG_DEBUG_FS */ diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 95aa26d62e4f..82d16e037d9a 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -44,7 +44,8 @@ struct rsnd_dma { }; struct rsnd_dma_ctrl { - void __iomem *base; + void __iomem *ppbase; + phys_addr_t ppres; int dmaen_num; int dmapp_num; }; @@ -236,16 +237,18 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, return 0; } -struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, - struct rsnd_mod *mod, char *name) +struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, + struct rsnd_mod *mod, char *x) { struct dma_chan *chan = NULL; struct device_node *np; int i = 0; for_each_child_of_node(of_node, np) { + i = rsnd_node_fixed_index(np, name, i); + if (i == rsnd_mod_id_raw(mod) && (!chan)) - chan = of_dma_request_slave_channel(np, name); + chan = of_dma_request_slave_channel(np, x); i++; } @@ -415,7 +418,7 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, } #define rsnd_dmapp_addr(dmac, dma, reg) \ - (dmac->base + 0x20 + reg + \ + (dmac->ppbase + 0x20 + reg + \ (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) { @@ -504,12 +507,31 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, return 0; } +#ifdef CONFIG_DEBUG_FS +static void rsnd_dmapp_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); + + rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase, + 0x20 + 0x10 * dmapp->dmapp_id, 0x10); +} +#define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info +#else +#define DEBUG_INFO +#endif + static struct rsnd_mod_ops rsnd_dmapp_ops = { .name = "audmac-pp", .start = rsnd_dmapp_start, .stop = rsnd_dmapp_stop, .quit = rsnd_dmapp_stop, .get_status = rsnd_mod_get_status, + DEBUG_INFO }; /* @@ -864,9 +886,10 @@ int rsnd_dma_probe(struct rsnd_priv *priv) } dmac->dmapp_num = 0; - dmac->base = devm_ioremap_resource(dev, res); - if (IS_ERR(dmac->base)) - return PTR_ERR(dmac->base); + dmac->ppres = res->start; + dmac->ppbase = devm_ioremap_resource(dev, res); + if (IS_ERR(dmac->ppbase)) + return PTR_ERR(dmac->ppbase); priv->dma = dmac; diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 8d91c0eb0880..5137e03a9d7c 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -282,9 +282,22 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); return rsnd_dma_request_channel(rsnd_dvc_of_node(priv), - mod, "tx"); + DVC_NAME, mod, "tx"); } +#ifdef CONFIG_DEBUG_FS +static void rsnd_dvc_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, + 0xe00 + rsnd_mod_id(mod) * 0x100, 0x60); +} +#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info +#else +#define DEBUG_INFO +#endif + static struct rsnd_mod_ops rsnd_dvc_ops = { .name = DVC_NAME, .dma_req = rsnd_dvc_dma_req, @@ -293,6 +306,7 @@ static struct rsnd_mod_ops rsnd_dvc_ops = { .quit = rsnd_dvc_quit, .pcm_new = rsnd_dvc_pcm_new, .get_status = rsnd_mod_get_status, + DEBUG_INFO }; struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 8bd49c8a9517..925565baaa41 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -141,6 +141,15 @@ phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) return gen->res[reg_id]; } +#ifdef CONFIG_DEBUG_FS +void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id) +{ + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + return gen->base[reg_id]; +} +#endif + #define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \ _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf)) static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index a3e0370f5704..3572c2c5686c 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -250,6 +250,19 @@ static int rsnd_mix_pcm_new(struct rsnd_mod *mod, return ret; } +#ifdef CONFIG_DEBUG_FS +static void rsnd_mix_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, + 0xd00 + rsnd_mod_id(mod) * 0x40, 0x30); +} +#define DEBUG_INFO .debug_info = rsnd_mix_debug_info +#else +#define DEBUG_INFO +#endif + static struct rsnd_mod_ops rsnd_mix_ops = { .name = MIX_NAME, .probe = rsnd_mix_probe_, @@ -257,6 +270,7 @@ static struct rsnd_mod_ops rsnd_mix_ops = { .quit = rsnd_mix_quit, .pcm_new = rsnd_mix_pcm_new, .get_status = rsnd_mod_get_status, + DEBUG_INFO }; struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 1255a85151db..6580bab0e229 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -269,8 +269,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod); int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); -struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, - struct rsnd_mod *mod, char *name); +struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, + struct rsnd_mod *mod, char *x); /* * R-Car sound mod @@ -345,6 +345,11 @@ struct rsnd_mod_ops { int (*id)(struct rsnd_mod *mod); int (*id_sub)(struct rsnd_mod *mod); int (*id_cmd)(struct rsnd_mod *mod); + +#ifdef CONFIG_DEBUG_FS + void (*debug_info)(struct seq_file *m, + struct rsnd_dai_stream *io, struct rsnd_mod *mod); +#endif }; struct rsnd_dai_stream; @@ -359,19 +364,13 @@ struct rsnd_mod { /* * status * - * 0xH0000CB0 + * 0xH000DCB0 * * B 0: init 1: quit * C 0: start 1: stop * D 0: hw_params 1: hw_free * * H is always called (see __rsnd_mod_call) - * H 0: probe 1: remove - * H 0: pcm_new - * H 0: fallback - * H 0: pointer - * H 0: prepare - * H 0: cleanup */ #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 @@ -392,12 +391,12 @@ struct rsnd_mod { #define __rsnd_mod_add_remove 0 #define __rsnd_mod_add_prepare 0 #define __rsnd_mod_add_cleanup 0 -#define __rsnd_mod_add_init 1 -#define __rsnd_mod_add_quit -1 -#define __rsnd_mod_add_start 1 -#define __rsnd_mod_add_stop -1 -#define __rsnd_mod_add_hw_params 1 -#define __rsnd_mod_add_hw_free -1 +#define __rsnd_mod_add_init 1 /* needs protect */ +#define __rsnd_mod_add_quit -1 /* needs protect */ +#define __rsnd_mod_add_start 1 /* needs protect */ +#define __rsnd_mod_add_stop -1 /* needs protect */ +#define __rsnd_mod_add_hw_params 1 /* needs protect */ +#define __rsnd_mod_add_hw_free -1 /* needs protect */ #define __rsnd_mod_add_irq 0 #define __rsnd_mod_add_pcm_new 0 #define __rsnd_mod_add_fallback 0 @@ -407,16 +406,16 @@ struct rsnd_mod { #define __rsnd_mod_call_remove 0 #define __rsnd_mod_call_prepare 0 #define __rsnd_mod_call_cleanup 0 -#define __rsnd_mod_call_init 0 -#define __rsnd_mod_call_quit 1 -#define __rsnd_mod_call_start 0 -#define __rsnd_mod_call_stop 1 +#define __rsnd_mod_call_init 0 /* needs protect */ +#define __rsnd_mod_call_quit 1 /* needs protect */ +#define __rsnd_mod_call_start 0 /* needs protect */ +#define __rsnd_mod_call_stop 1 /* needs protect */ +#define __rsnd_mod_call_hw_params 0 /* needs protect */ +#define __rsnd_mod_call_hw_free 1 /* needs protect */ #define __rsnd_mod_call_irq 0 #define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_fallback 0 -#define __rsnd_mod_call_hw_params 0 #define __rsnd_mod_call_pointer 0 -#define __rsnd_mod_call_hw_free 1 #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) @@ -455,11 +454,13 @@ struct rsnd_mod *rsnd_mod_next(int *iterator, #define for_each_rsnd_mod_array(iterator, pos, io, array) \ for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array)) -void rsnd_parse_connect_common(struct rsnd_dai *rdai, +void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), struct device_node *node, struct device_node *playback, struct device_node *capture); +int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name); +int rsnd_node_fixed_index(struct device_node *node, char *name, int idx); int rsnd_channel_normalization(int chan); #define rsnd_runtime_channel_original(io) \ @@ -592,6 +593,9 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); +#ifdef CONFIG_DEBUG_FS +void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id); +#endif /* * R-Car ADG @@ -610,6 +614,7 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, #define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) #define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable); +void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m); /* * R-Car sound priv @@ -776,6 +781,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io); +int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); #define rsnd_ssi_is_pin_sharing(io) \ __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) @@ -799,6 +805,7 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); #define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU) +bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod); /* * R-Car SRC @@ -815,7 +822,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, #define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC) #define rsnd_parse_connect_src(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \ + rsnd_parse_connect_common(rdai, "src", rsnd_src_mod_get, \ rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ playback, capture) @@ -827,7 +834,7 @@ void rsnd_ctu_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); #define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) #define rsnd_parse_connect_ctu(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \ + rsnd_parse_connect_common(rdai, "ctu", rsnd_ctu_mod_get, \ rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ playback, capture) @@ -839,7 +846,7 @@ void rsnd_mix_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); #define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX) #define rsnd_parse_connect_mix(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \ + rsnd_parse_connect_common(rdai, "mix", rsnd_mix_mod_get, \ rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ playback, capture) @@ -851,7 +858,7 @@ void rsnd_dvc_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); #define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC) #define rsnd_parse_connect_dvc(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \ + rsnd_parse_connect_common(rdai, "dvc", rsnd_dvc_mod_get, \ rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ playback, capture) @@ -879,9 +886,10 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); * * #define RSND_DEBUG_NO_IRQ_STATUS 1 */ -#define rsnd_dbg_irq_status(dev, param...) \ +#define rsnd_print_irq_status(dev, param...) do { \ if (!IS_BUILTIN(RSND_DEBUG_NO_IRQ_STATUS)) \ - dev_dbg(dev, param) + dev_info(dev, param); \ +} while (0) /* * If you don't need rsnd_dai_call debug message, @@ -894,3 +902,14 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); dev_dbg(dev, param) #endif + +#ifdef CONFIG_DEBUG_FS +int rsnd_debugfs_probe(struct snd_soc_component *component); +void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr, + void __iomem *base, int offset, int size); +void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod, + int reg_id, int offset, int size); + +#else +#define rsnd_debugfs_probe NULL +#endif diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 628af8f3920d..42a100c6303d 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -17,7 +17,7 @@ /* * you can enable below define if you don't need * SSI interrupt status debug message when debugging - * see rsnd_dbg_irq_status() + * see rsnd_print_irq_status() * * #define RSND_DEBUG_NO_IRQ_STATUS 1 */ @@ -82,7 +82,7 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, int is_play = rsnd_io_is_play(io); return rsnd_dma_request_channel(rsnd_src_of_node(priv), - mod, + SRC_NAME, mod, is_play ? "rx" : "tx"); } @@ -421,8 +421,8 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod) status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); if ((status0 & val0) || (status1 & val1)) { - rsnd_dbg_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", - rsnd_mod_name(mod), status0, status1); + rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", + rsnd_mod_name(mod), status0, status1); ret = true; } @@ -597,6 +597,25 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, return ret; } +#ifdef CONFIG_DEBUG_FS +static void rsnd_src_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, + rsnd_mod_id(mod) * 0x20, 0x20); + seq_puts(m, "\n"); + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, + 0x1c0, 0x20); + seq_puts(m, "\n"); + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, + 0x200 + rsnd_mod_id(mod) * 0x40, 0x40); +} +#define DEBUG_INFO .debug_info = rsnd_src_debug_info +#else +#define DEBUG_INFO +#endif + static struct rsnd_mod_ops rsnd_src_ops = { .name = SRC_NAME, .dma_req = rsnd_src_dma_req, @@ -608,6 +627,7 @@ static struct rsnd_mod_ops rsnd_src_ops = { .irq = rsnd_src_irq, .pcm_new = rsnd_src_pcm_new, .get_status = rsnd_mod_get_status, + DEBUG_INFO }; struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) @@ -636,7 +656,7 @@ int rsnd_src_probe(struct rsnd_priv *priv) if (!node) return 0; /* not used is not error */ - nr = of_get_child_count(node); + nr = rsnd_node_count(priv, node, SRC_NAME); if (!nr) { ret = -EINVAL; goto rsnd_src_probe_done; @@ -656,6 +676,8 @@ int rsnd_src_probe(struct rsnd_priv *priv) if (!of_device_is_available(np)) goto skip; + i = rsnd_node_fixed_index(np, SRC_NAME, i); + src = rsnd_src_get(priv, i); snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index e29482c26d6a..27f34ca6059d 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -11,7 +11,7 @@ /* * you can enable below define if you don't need * SSI interrupt status debug message when debugging - * see rsnd_dbg_irq_status() + * see rsnd_print_irq_status() * * #define RSND_DEBUG_NO_IRQ_STATUS 1 */ @@ -117,8 +117,6 @@ struct rsnd_ssi { (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) #define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod)) -static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); - int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); @@ -359,96 +357,6 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, rsnd_adg_ssi_clk_stop(mod); } -/* enable busif buffer over/under run interrupt. */ -#define rsnd_ssi_busif_err_irq_enable(mod) rsnd_ssi_busif_err_irq_ctrl(mod, 1) -#define rsnd_ssi_busif_err_irq_disable(mod) rsnd_ssi_busif_err_irq_ctrl(mod, 0) -static void rsnd_ssi_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable) -{ - u32 sys_int_enable = 0; - int id = rsnd_mod_id(mod); - int i; - - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, SSI_SYS_INT_ENABLE(i * 2)); - if (enable) - sys_int_enable |= 0xf << (id * 4); - else - sys_int_enable &= ~(0xf << (id * 4)); - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE(i * 2), - sys_int_enable); - } - break; - case 9: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, SSI_SYS_INT_ENABLE((i * 2) + 1)); - if (enable) - sys_int_enable |= 0xf << 4; - else - sys_int_enable &= ~(0xf << 4); - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1), - sys_int_enable); - } - break; - } -} - -static bool rsnd_ssi_busif_err_status_clear(struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - u32 status; - bool stop = false; - int id = rsnd_mod_id(mod); - int i; - - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) { - status = rsnd_mod_read(mod, SSI_SYS_STATUS(i * 2)); - status &= 0xf << (id * 4); - - if (status) { - rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - rsnd_mod_write(mod, - SSI_SYS_STATUS(i * 2), - 0xf << (id * 4)); - stop = true; - } - } - break; - case 9: - for (i = 0; i < 4; i++) { - status = rsnd_mod_read(mod, SSI_SYS_STATUS((i * 2) + 1)); - status &= 0xf << 4; - - if (status) { - rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - rsnd_mod_write(mod, - SSI_SYS_STATUS((i * 2) + 1), - 0xf << 4); - stop = true; - } - } - break; - } - - return stop; -} - static void rsnd_ssi_config_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { @@ -536,10 +444,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, cr_mode = DIEN; /* PIO : enable Data interrupt */ } - /* enable busif buffer over/under run interrupt. */ - if (is_tdm || is_tdm_split) - rsnd_ssi_busif_err_irq_enable(mod); - init_end: ssi->cr_own = cr_own; ssi->cr_mode = cr_mode; @@ -594,10 +498,6 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); - int is_tdm, is_tdm_split; - - is_tdm = rsnd_runtime_is_tdm(io); - is_tdm_split = rsnd_runtime_is_tdm_split(io); if (!rsnd_ssi_is_run_mods(mod, io)) return 0; @@ -619,10 +519,6 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, ssi->wsr = 0; } - /* disable busif buffer over/under run interrupt. */ - if (is_tdm || is_tdm_split) - rsnd_ssi_busif_err_irq_disable(mod); - return 0; } @@ -775,10 +671,6 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, u32 status; bool elapsed = false; bool stop = false; - int is_tdm, is_tdm_split; - - is_tdm = rsnd_runtime_is_tdm(io); - is_tdm_split = rsnd_runtime_is_tdm_split(io); spin_lock(&priv->lock); @@ -794,14 +686,13 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, /* DMA only */ if (is_dma && (status & (UIRQ | OIRQ))) { - rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); + rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); stop = true; } - if (is_tdm || is_tdm_split) - stop |= rsnd_ssi_busif_err_status_clear(mod); + stop |= rsnd_ssiu_busif_err_status_clear(mod); rsnd_ssi_status_clear(mod); rsnd_ssi_interrupt_out: @@ -1128,8 +1019,36 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, name = is_play ? "rx" : "tx"; return rsnd_dma_request_channel(rsnd_ssi_of_node(priv), - mod, name); + SSI_NAME, mod, name); +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_ssi_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + seq_printf(m, "clock: %s\n", rsnd_rdai_is_clk_master(rdai) ? + "provider" : "consumer"); + seq_printf(m, "bit_clk_inv: %d\n", rdai->bit_clk_inv); + seq_printf(m, "frm_clk_inv: %d\n", rdai->frm_clk_inv); + seq_printf(m, "pin share: %d\n", __rsnd_ssi_is_pin_sharing(mod)); + seq_printf(m, "can out clk: %d\n", rsnd_ssi_can_output_clk(mod)); + seq_printf(m, "multi secondary: %d\n", rsnd_ssi_is_multi_secondary(mod, io)); + seq_printf(m, "tdm: %d, %d\n", rsnd_runtime_is_tdm(io), + rsnd_runtime_is_tdm_split(io)); + seq_printf(m, "chan: %d\n", ssi->chan); + seq_printf(m, "user: %d\n", ssi->usrcnt); + + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSI, + rsnd_mod_id(mod) * 0x40, 0x40); } +#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info +#else +#define DEBUG_INFO +#endif static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .name = SSI_NAME, @@ -1145,9 +1064,10 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .fallback = rsnd_ssi_fallback, .hw_params = rsnd_ssi_hw_params, .get_status = rsnd_ssi_get_status, + DEBUG_INFO }; -static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) +int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) { return mod->ops == &rsnd_ssi_dma_ops; } @@ -1195,7 +1115,11 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, i = 0; for_each_child_of_node(node, np) { - struct rsnd_mod *mod = rsnd_ssi_mod_get(priv, i); + struct rsnd_mod *mod; + + i = rsnd_node_fixed_index(np, SSI_NAME, i); + + mod = rsnd_ssi_mod_get(priv, i); if (np == playback) rsnd_ssi_connect(mod, &rdai->playback); @@ -1238,7 +1162,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) if (!node) return -EINVAL; - nr = of_get_child_count(node); + nr = rsnd_node_count(priv, node, SSI_NAME); if (!nr) { ret = -EINVAL; goto rsnd_ssi_probe_done; @@ -1258,6 +1182,8 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) if (!of_device_is_available(np)) goto skip; + i = rsnd_node_fixed_index(np, SSI_NAME, i); + ssi = rsnd_ssi_get(priv, i); snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 852cdeedf7e9..0d8f97633dd2 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -45,6 +45,85 @@ struct rsnd_ssiu { static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; +/* enable busif buffer over/under run interrupt. */ +#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1) +#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0) +static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable) +{ + int id = rsnd_mod_id(mod); + int shift, offset; + int i; + + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + shift = id; + offset = 0; + break; + case 9: + shift = 1; + offset = 1; + break; + } + + for (i = 0; i < 4; i++) { + enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset); + u32 val = 0xf << (shift * 4); + u32 sys_int_enable = rsnd_mod_read(mod, reg); + + if (enable) + sys_int_enable |= val; + else + sys_int_enable &= ~val; + rsnd_mod_write(mod, reg, sys_int_enable); + } +} + +bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod) +{ + bool error = false; + int id = rsnd_mod_id(mod); + int shift, offset; + int i; + + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + shift = id; + offset = 0; + break; + case 9: + shift = 1; + offset = 1; + break; + } + + for (i = 0; i < 4; i++) { + u32 reg = SSI_SYS_STATUS(i * 2) + offset; + u32 status = rsnd_mod_read(mod, reg); + u32 val = 0xf << (shift * 4); + + status &= val; + if (status) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); + error = true; + } + rsnd_mod_write(mod, reg, val); + } + + return error; +} + static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type) @@ -65,23 +144,9 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, int id = rsnd_mod_id(mod); int is_clk_master = rsnd_rdai_is_clk_master(rdai); u32 val1, val2; - int i; /* clear status */ - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) - rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4)); - break; - case 9: - for (i = 0; i < 4; i++) - rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4); - break; - } + rsnd_ssiu_busif_err_status_clear(mod); /* * SSI_MODE0 @@ -137,12 +202,31 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1); rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2); + /* + * Enable busif buffer over/under run interrupt. + * It will be handled from ssi.c + * see + * __rsnd_ssi_interrupt() + */ + rsnd_ssiu_busif_err_irq_enable(mod); + + return 0; +} + +static int rsnd_ssiu_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + /* disable busif buffer over/under run interrupt. */ + rsnd_ssiu_busif_err_irq_disable(mod); + return 0; } static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { .name = SSIU_NAME, .init = rsnd_ssiu_init, + .quit = rsnd_ssiu_quit, .get_status = rsnd_ssiu_get_status, }; @@ -311,9 +395,22 @@ static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io, name = is_play ? "rx" : "tx"; return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv), - mod, name); + SSIU_NAME, mod, name); } +#ifdef CONFIG_DEBUG_FS +static void rsnd_ssiu_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSIU, + rsnd_mod_id(mod) * 0x80, 0x80); +} +#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info +#else +#define DEBUG_INFO +#endif + static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { .name = SSIU_NAME, .dma_req = rsnd_ssiu_dma_req, @@ -321,6 +418,7 @@ static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { .start = rsnd_ssiu_start_gen2, .stop = rsnd_ssiu_stop_gen2, .get_status = rsnd_ssiu_get_status, + DEBUG_INFO }; static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) @@ -336,16 +434,20 @@ static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, { struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); struct rsnd_ssiu *ssiu; + int is_dma_mode; int i; if (!ssi_mod) return; + is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod); + /* select BUSIF0 */ for_each_rsnd_ssiu(ssiu, priv, i) { struct rsnd_mod *mod = rsnd_mod_get(ssiu); - if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && + if (is_dma_mode && + (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && (rsnd_mod_id_sub(mod) == 0)) { rsnd_dai_connect(mod, io, mod->type); return; @@ -368,7 +470,11 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, int i = 0; for_each_child_of_node(node, np) { - struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, i); + struct rsnd_mod *mod; + + i = rsnd_node_fixed_index(np, SSIU_NAME, i); + + mod = rsnd_ssiu_mod_get(priv, i); if (np == playback) rsnd_dai_connect(mod, io_p, mod->type); @@ -405,10 +511,13 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) */ node = rsnd_ssiu_of_node(priv); if (node) - nr = of_get_child_count(node); + nr = rsnd_node_count(priv, node, SSIU_NAME); else nr = priv->ssi_nr; + if (!nr) + return -EINVAL; + ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); if (!ssiu) return -ENOMEM; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a76974ccfce1..583f2381cfc8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -75,9 +75,9 @@ static ssize_t pmdown_time_show(struct device *dev, return sprintf(buf, "%ld\n", rtd->pmdown_time); } -static ssize_t pmdown_time_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t pmdown_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); int ret; @@ -89,7 +89,7 @@ static ssize_t pmdown_time_set(struct device *dev, return count; } -static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set); +static DEVICE_ATTR_RW(pmdown_time); static struct attribute *soc_dev_attrs[] = { &dev_attr_pmdown_time.attr, @@ -580,7 +580,7 @@ int snd_soc_suspend(struct device *dev) * Due to the resume being scheduled into a workqueue we could * suspend before that's finished - wait for it to complete. */ - snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); + snd_power_wait(card->snd_card); /* we're going to block userspace touching us until resume completes */ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); @@ -1054,6 +1054,218 @@ _err_defer: } EXPORT_SYMBOL_GPL(snd_soc_add_pcm_runtime); +static void snd_soc_runtime_get_dai_fmt(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct snd_soc_dai *dai, *not_used; + struct device *dev = rtd->dev; + u64 pos, possible_fmt; + unsigned int mask = 0, dai_fmt = 0; + int i, j, priority, pri, until; + + /* + * Get selectable format from each DAIs. + * + **************************** + * NOTE + * Using .auto_selectable_formats is not mandatory, + * we can select format manually from Sound Card. + * When use it, driver should list well tested format only. + **************************** + * + * ex) + * auto_selectable_formats (= SND_SOC_POSSIBLE_xxx) + * (A) (B) (C) + * DAI0_: { 0x000F, 0x00F0, 0x0F00 }; + * DAI1 : { 0xF000, 0x0F00 }; + * (X) (Y) + * + * "until" will be 3 in this case (MAX array size from DAI0 and DAI1) + * Here is dev_dbg() message and comments + * + * priority = 1 + * DAI0: (pri, fmt) = (1, 000000000000000F) // 1st check (A) DAI1 is not selected + * DAI1: (pri, fmt) = (0, 0000000000000000) // Necessary Waste + * DAI0: (pri, fmt) = (1, 000000000000000F) // 2nd check (A) + * DAI1: (pri, fmt) = (1, 000000000000F000) // (X) + * priority = 2 + * DAI0: (pri, fmt) = (2, 00000000000000FF) // 3rd check (A) + (B) + * DAI1: (pri, fmt) = (1, 000000000000F000) // (X) + * DAI0: (pri, fmt) = (2, 00000000000000FF) // 4th check (A) + (B) + * DAI1: (pri, fmt) = (2, 000000000000FF00) // (X) + (Y) + * priority = 3 + * DAI0: (pri, fmt) = (3, 0000000000000FFF) // 5th check (A) + (B) + (C) + * DAI1: (pri, fmt) = (2, 000000000000FF00) // (X) + (Y) + * found auto selected format: 0000000000000F00 + */ + until = snd_soc_dai_get_fmt_max_priority(rtd); + for (priority = 1; priority <= until; priority++) { + + dev_dbg(dev, "priority = %d\n", priority); + for_each_rtd_dais(rtd, j, not_used) { + + possible_fmt = ULLONG_MAX; + for_each_rtd_dais(rtd, i, dai) { + u64 fmt = 0; + + pri = (j >= i) ? priority : priority - 1; + fmt = snd_soc_dai_get_fmt(dai, pri); + dev_dbg(dev, "%s: (pri, fmt) = (%d, %016llX)\n", dai->name, pri, fmt); + possible_fmt &= fmt; + } + if (possible_fmt) + goto found; + } + } + /* Not Found */ + return; +found: + dev_dbg(dev, "found auto selected format: %016llX\n", possible_fmt); + + /* + * convert POSSIBLE_DAIFMT to DAIFMT + * + * Some basic/default settings on each is defined as 0. + * see + * SND_SOC_DAIFMT_NB_NF + * SND_SOC_DAIFMT_GATED + * + * SND_SOC_DAIFMT_xxx_MASK can't notice it if Sound Card specify + * these value, and will be overwrite to auto selected value. + * + * To avoid such issue, loop from 63 to 0 here. + * Small number of SND_SOC_POSSIBLE_xxx will be Hi priority. + * Basic/Default settings of each part and aboves are defined + * as Hi priority (= small number) of SND_SOC_POSSIBLE_xxx. + */ + for (i = 63; i >= 0; i--) { + pos = 1ULL << i; + switch (possible_fmt & pos) { + /* + * for format + */ + case SND_SOC_POSSIBLE_DAIFMT_I2S: + case SND_SOC_POSSIBLE_DAIFMT_RIGHT_J: + case SND_SOC_POSSIBLE_DAIFMT_LEFT_J: + case SND_SOC_POSSIBLE_DAIFMT_DSP_A: + case SND_SOC_POSSIBLE_DAIFMT_DSP_B: + case SND_SOC_POSSIBLE_DAIFMT_AC97: + case SND_SOC_POSSIBLE_DAIFMT_PDM: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_FORMAT_MASK) | i; + break; + /* + * for clock + */ + case SND_SOC_POSSIBLE_DAIFMT_CONT: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_MASK) | SND_SOC_DAIFMT_CONT; + break; + case SND_SOC_POSSIBLE_DAIFMT_GATED: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_MASK) | SND_SOC_DAIFMT_GATED; + break; + /* + * for clock invert + */ + case SND_SOC_POSSIBLE_DAIFMT_NB_NF: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_NB_NF; + break; + case SND_SOC_POSSIBLE_DAIFMT_NB_IF: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_NB_IF; + break; + case SND_SOC_POSSIBLE_DAIFMT_IB_NF: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_IB_NF; + break; + case SND_SOC_POSSIBLE_DAIFMT_IB_IF: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_INV_MASK) | SND_SOC_DAIFMT_IB_IF; + break; + /* + * for clock provider / consumer + */ + case SND_SOC_POSSIBLE_DAIFMT_CBP_CFP: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBP_CFP; + break; + case SND_SOC_POSSIBLE_DAIFMT_CBC_CFP: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBC_CFP; + break; + case SND_SOC_POSSIBLE_DAIFMT_CBP_CFC: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBP_CFC; + break; + case SND_SOC_POSSIBLE_DAIFMT_CBC_CFC: + dai_fmt = (dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) | SND_SOC_DAIFMT_CBC_CFC; + break; + } + } + + /* + * Some driver might have very complex limitation. + * In such case, user want to auto-select non-limitation part, + * and want to manually specify complex part. + * + * Or for example, if both CPU and Codec can be clock provider, + * but because of its quality, user want to specify it manually. + * + * Use manually specified settings if sound card did. + */ + if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK)) + mask |= SND_SOC_DAIFMT_FORMAT_MASK; + if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_CLOCK_MASK)) + mask |= SND_SOC_DAIFMT_CLOCK_MASK; + if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_INV_MASK)) + mask |= SND_SOC_DAIFMT_INV_MASK; + if (!(dai_link->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) + mask |= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + + dai_link->dai_fmt |= (dai_fmt & mask); +} + +/** + * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime + * @rtd: The runtime for which the DAI link format should be changed + * @dai_fmt: The new DAI link format + * + * This function updates the DAI link format for all DAIs connected to the DAI + * link for the specified runtime. + * + * Note: For setups with a static format set the dai_fmt field in the + * corresponding snd_dai_link struct instead of using this function. + * + * Returns 0 on success, otherwise a negative error code. + */ +int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, + unsigned int dai_fmt) +{ + struct snd_soc_dai *cpu_dai; + struct snd_soc_dai *codec_dai; + unsigned int inv_dai_fmt; + unsigned int i; + int ret; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); + if (ret != 0 && ret != -ENOTSUPP) + return ret; + } + + /* + * Flip the polarity for the "CPU" end of a CODEC<->CODEC link + * the component which has non_legacy_dai_naming is Codec + */ + inv_dai_fmt = snd_soc_daifmt_clock_provider_fliped(dai_fmt); + + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + unsigned int fmt = dai_fmt; + + if (cpu_dai->component->driver->non_legacy_dai_naming) + fmt = inv_dai_fmt; + + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret != 0 && ret != -ENOTSUPP) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); + static int soc_init_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { @@ -1070,6 +1282,7 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card, if (ret < 0) return ret; + snd_soc_runtime_get_dai_fmt(rtd); if (dai_link->dai_fmt) { ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt); if (ret) @@ -1402,68 +1615,6 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) } } -/** - * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime - * @rtd: The runtime for which the DAI link format should be changed - * @dai_fmt: The new DAI link format - * - * This function updates the DAI link format for all DAIs connected to the DAI - * link for the specified runtime. - * - * Note: For setups with a static format set the dai_fmt field in the - * corresponding snd_dai_link struct instead of using this function. - * - * Returns 0 on success, otherwise a negative error code. - */ -int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, - unsigned int dai_fmt) -{ - struct snd_soc_dai *cpu_dai; - struct snd_soc_dai *codec_dai; - unsigned int inv_dai_fmt; - unsigned int i; - int ret; - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); - if (ret != 0 && ret != -ENOTSUPP) - return ret; - } - - /* - * Flip the polarity for the "CPU" end of a CODEC<->CODEC link - * the component which has non_legacy_dai_naming is Codec - */ - inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK; - switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; - break; - case SND_SOC_DAIFMT_CBM_CFS: - inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; - break; - case SND_SOC_DAIFMT_CBS_CFM: - inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; - break; - case SND_SOC_DAIFMT_CBS_CFS: - inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; - break; - } - for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - unsigned int fmt = dai_fmt; - - if (cpu_dai->component->driver->non_legacy_dai_naming) - fmt = inv_dai_fmt; - - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret != 0 && ret != -ENOTSUPP) - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); - #ifdef CONFIG_DMI /* * If a DMI filed contain strings in this blacklist (e.g. @@ -2793,7 +2944,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, if (!routes) { dev_err(card->dev, "ASoC: Could not allocate DAPM route table\n"); - return -EINVAL; + return -ENOMEM; } for (i = 0; i < num_routes; i++) { @@ -2853,10 +3004,54 @@ int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname) } EXPORT_SYMBOL_GPL(snd_soc_of_parse_aux_devs); -unsigned int snd_soc_of_parse_daifmt(struct device_node *np, - const char *prefix, - struct device_node **bitclkmaster, - struct device_node **framemaster) +unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt) +{ + unsigned int inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; + + switch (dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + inv_dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; + break; + case SND_SOC_DAIFMT_CBP_CFC: + inv_dai_fmt |= SND_SOC_DAIFMT_CBC_CFP; + break; + case SND_SOC_DAIFMT_CBC_CFP: + inv_dai_fmt |= SND_SOC_DAIFMT_CBP_CFC; + break; + case SND_SOC_DAIFMT_CBC_CFC: + inv_dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; + break; + } + + return inv_dai_fmt; +} +EXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_fliped); + +unsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame) +{ + /* + * bit_frame is return value from + * snd_soc_daifmt_parse_clock_provider_raw() + */ + + /* Codec base */ + switch (bit_frame) { + case 0x11: + return SND_SOC_DAIFMT_CBP_CFP; + case 0x10: + return SND_SOC_DAIFMT_CBP_CFC; + case 0x01: + return SND_SOC_DAIFMT_CBC_CFP; + default: + return SND_SOC_DAIFMT_CBC_CFC; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_from_bitmap); + +unsigned int snd_soc_daifmt_parse_format(struct device_node *np, + const char *prefix) { int ret, i; char prop[128]; @@ -2936,10 +3131,24 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, break; } + return format; +} +EXPORT_SYMBOL_GPL(snd_soc_daifmt_parse_format); + +unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, + const char *prefix, + struct device_node **bitclkmaster, + struct device_node **framemaster) +{ + char prop[128]; + unsigned int bit, frame; + + if (!prefix) + prefix = ""; + /* * check "[prefix]bitclock-master" * check "[prefix]frame-master" - * SND_SOC_DAIFMT_MASTER_MASK area */ snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); bit = !!of_get_property(np, prop, NULL); @@ -2951,24 +3160,14 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, if (frame && framemaster) *framemaster = of_parse_phandle(np, prop, 0); - switch ((bit << 4) + frame) { - case 0x11: - format |= SND_SOC_DAIFMT_CBM_CFM; - break; - case 0x10: - format |= SND_SOC_DAIFMT_CBM_CFS; - break; - case 0x01: - format |= SND_SOC_DAIFMT_CBS_CFM; - break; - default: - format |= SND_SOC_DAIFMT_CBS_CFS; - break; - } - - return format; + /* + * return bitmap. + * It will be parameter of + * snd_soc_daifmt_clock_provider_from_bitmap() + */ + return (bit << 4) + frame; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); +EXPORT_SYMBOL_GPL(snd_soc_daifmt_parse_clock_provider_raw); int snd_soc_get_dai_id(struct device_node *ep) { diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 080fbe053fc5..a56dcc8d6fb7 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -134,6 +134,69 @@ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) } EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); +int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai; + int i, max = 0; + + /* + * return max num if *ALL* DAIs have .auto_selectable_formats + */ + for_each_rtd_dais(rtd, i, dai) { + if (dai->driver->ops && + dai->driver->ops->num_auto_selectable_formats) + max = max(max, dai->driver->ops->num_auto_selectable_formats); + else + return 0; + } + + return max; +} + +/** + * snd_soc_dai_get_fmt - get supported audio format. + * @dai: DAI + * @priority: priority level of supported audio format. + * + * This should return only formats implemented with high + * quality by the DAI so that the core can configure a + * format which will work well with other devices. + * For example devices which don't support both edges of the + * LRCLK signal in I2S style formats should only list DSP + * modes. This will mean that sometimes fewer formats + * are reported here than are supported by set_fmt(). + */ +u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority) +{ + const struct snd_soc_dai_ops *ops = dai->driver->ops; + u64 fmt = 0; + int i, max = 0, until = priority; + + /* + * Collect auto_selectable_formats until priority + * + * ex) + * auto_selectable_formats[] = { A, B, C }; + * (A, B, C = SND_SOC_POSSIBLE_DAIFMT_xxx) + * + * priority = 1 : A + * priority = 2 : A | B + * priority = 3 : A | B | C + * priority = 4 : A | B | C + * ... + */ + if (ops) + max = ops->num_auto_selectable_formats; + + if (max < until) + until = max; + + for (i = 0; i < until; i++) + fmt |= ops->auto_selectable_formats[i]; + + return fmt; +} + /** * snd_soc_dai_set_fmt - configure DAI hardware audio format. * @dai: DAI @@ -327,14 +390,15 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai, struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); int ret = 0; - /* perform any topology hw_params fixups before DAI */ - ret = snd_soc_link_be_hw_params_fixup(rtd, params); - if (ret < 0) - goto end; - if (dai->driver->ops && - dai->driver->ops->hw_params) + dai->driver->ops->hw_params) { + /* perform any topology hw_params fixups before DAI */ + ret = snd_soc_link_be_hw_params_fixup(rtd, params); + if (ret < 0) + goto end; + ret = dai->driver->ops->hw_params(substream, params, dai); + } /* mark substream if succeeded */ if (ret == 0) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8659089a87a0..46513bb97904 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1700,7 +1700,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, struct snd_soc_dpcm *dpcm; struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream); struct snd_soc_dai *fe_cpu_dai; - int err; + int err = 0; int i; /* apply symmetry for FE */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 4893a56208e0..0a24d0d409d2 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1203,249 +1203,216 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, return ret; } -static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( - struct soc_tplg *tplg, int num_kcontrols) +static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) { - struct snd_kcontrol_new *kc; struct soc_mixer_control *sm; struct snd_soc_tplg_mixer_control *mc; - int i, err; - - kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL); - if (kc == NULL) - return NULL; - - for (i = 0; i < num_kcontrols; i++) { - mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; - - /* validate kcontrol */ - if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - goto err_sm; + int err; - sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); - if (sm == NULL) - goto err_sm; + mc = (struct snd_soc_tplg_mixer_control *)tplg->pos; - tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + - le32_to_cpu(mc->priv.size)); + /* validate kcontrol */ + if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; - dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n", - mc->hdr.name, i); + sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); + if (!sm) + return -ENOMEM; - kc[i].private_value = (long)sm; - kc[i].name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL); - if (kc[i].name == NULL) - goto err_sm; - kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc[i].access = le32_to_cpu(mc->hdr.access); + tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) + + le32_to_cpu(mc->priv.size); - /* we only support FL/FR channel mapping atm */ - sm->reg = tplc_chan_get_reg(tplg, mc->channel, - SNDRV_CHMAP_FL); - sm->rreg = tplc_chan_get_reg(tplg, mc->channel, - SNDRV_CHMAP_FR); - sm->shift = tplc_chan_get_shift(tplg, mc->channel, - SNDRV_CHMAP_FL); - sm->rshift = tplc_chan_get_shift(tplg, mc->channel, - SNDRV_CHMAP_FR); + dev_dbg(tplg->dev, " adding DAPM widget mixer control %s\n", + mc->hdr.name); - sm->max = le32_to_cpu(mc->max); - sm->min = le32_to_cpu(mc->min); - sm->invert = le32_to_cpu(mc->invert); - sm->platform_max = le32_to_cpu(mc->platform_max); - sm->dobj.index = tplg->index; - INIT_LIST_HEAD(&sm->dobj.list); - - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], tplg); - if (err) { - soc_control_err(tplg, &mc->hdr, mc->hdr.name); - goto err_sm; - } + kc->private_value = (long)sm; + kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL); + if (!kc->name) + return -ENOMEM; + kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc->access = le32_to_cpu(mc->hdr.access); + + /* we only support FL/FR channel mapping atm */ + sm->reg = tplc_chan_get_reg(tplg, mc->channel, + SNDRV_CHMAP_FL); + sm->rreg = tplc_chan_get_reg(tplg, mc->channel, + SNDRV_CHMAP_FR); + sm->shift = tplc_chan_get_shift(tplg, mc->channel, + SNDRV_CHMAP_FL); + sm->rshift = tplc_chan_get_shift(tplg, mc->channel, + SNDRV_CHMAP_FR); + + sm->max = le32_to_cpu(mc->max); + sm->min = le32_to_cpu(mc->min); + sm->invert = le32_to_cpu(mc->invert); + sm->platform_max = le32_to_cpu(mc->platform_max); + sm->dobj.index = tplg->index; + INIT_LIST_HEAD(&sm->dobj.list); + + /* map io handlers */ + err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg); + if (err) { + soc_control_err(tplg, &mc->hdr, mc->hdr.name); + return err; + } - /* create any TLV data */ - err = soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", - mc->hdr.name); - goto err_sm; - } + /* create any TLV data */ + err = soc_tplg_create_tlv(tplg, kc, &mc->hdr); + if (err < 0) { + dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", + mc->hdr.name); + return err; + } - /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, &kc[i], - (struct snd_soc_tplg_ctl_hdr *)mc); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - mc->hdr.name); - goto err_sm; - } + /* pass control to driver for optional further init */ + err = soc_tplg_init_kcontrol(tplg, kc, + (struct snd_soc_tplg_ctl_hdr *)mc); + if (err < 0) { + dev_err(tplg->dev, "ASoC: failed to init %s\n", + mc->hdr.name); + return err; } - return kc; -err_sm: - return NULL; + return 0; } -static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( - struct soc_tplg *tplg, int num_kcontrols) +static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) { - struct snd_kcontrol_new *kc; struct snd_soc_tplg_enum_control *ec; struct soc_enum *se; - int i, err; - - kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL); - if (kc == NULL) - return NULL; - - for (i = 0; i < num_kcontrols; i++) { - ec = (struct snd_soc_tplg_enum_control *)tplg->pos; - /* validate kcontrol */ - if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - goto err_se; + int err; - se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL); - if (se == NULL) - goto err_se; + ec = (struct snd_soc_tplg_enum_control *)tplg->pos; + /* validate kcontrol */ + if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - le32_to_cpu(ec->priv.size)); + se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL); + if (!se) + return -ENOMEM; - dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", - ec->hdr.name); + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + + le32_to_cpu(ec->priv.size)); - kc[i].private_value = (long)se; - kc[i].name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL); - if (kc[i].name == NULL) - goto err_se; - kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc[i].access = le32_to_cpu(ec->hdr.access); + dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", + ec->hdr.name); - /* we only support FL/FR channel mapping atm */ - se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_l = tplc_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FL); - se->shift_r = tplc_chan_get_shift(tplg, ec->channel, - SNDRV_CHMAP_FR); + kc->private_value = (long)se; + kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL); + if (!kc->name) + return -ENOMEM; + kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc->access = le32_to_cpu(ec->hdr.access); - se->items = le32_to_cpu(ec->items); - se->mask = le32_to_cpu(ec->mask); - se->dobj.index = tplg->index; + /* we only support FL/FR channel mapping atm */ + se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); + se->shift_l = tplc_chan_get_shift(tplg, ec->channel, + SNDRV_CHMAP_FL); + se->shift_r = tplc_chan_get_shift(tplg, ec->channel, + SNDRV_CHMAP_FR); - switch (le32_to_cpu(ec->hdr.ops.info)) { - case SND_SOC_TPLG_CTL_ENUM_VALUE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - err = soc_tplg_denum_create_values(tplg, se, ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create values for %s\n", - ec->hdr.name); - goto err_se; - } - fallthrough; - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - err = soc_tplg_denum_create_texts(tplg, se, ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create texts for %s\n", - ec->hdr.name); - goto err_se; - } - break; - default: - dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", - ec->hdr.ops.info, ec->hdr.name); - goto err_se; - } + se->items = le32_to_cpu(ec->items); + se->mask = le32_to_cpu(ec->mask); + se->dobj.index = tplg->index; - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc[i], tplg); - if (err) { - soc_control_err(tplg, &ec->hdr, ec->hdr.name); - goto err_se; + switch (le32_to_cpu(ec->hdr.ops.info)) { + case SND_SOC_TPLG_CTL_ENUM_VALUE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + err = soc_tplg_denum_create_values(tplg, se, ec); + if (err < 0) { + dev_err(tplg->dev, "ASoC: could not create values for %s\n", + ec->hdr.name); + return err; } - - /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, &kc[i], - (struct snd_soc_tplg_ctl_hdr *)ec); + fallthrough; + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + err = soc_tplg_denum_create_texts(tplg, se, ec); if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", + dev_err(tplg->dev, "ASoC: could not create texts for %s\n", ec->hdr.name); - goto err_se; + return err; } + break; + default: + dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", + ec->hdr.ops.info, ec->hdr.name); + return -EINVAL; } - return kc; + /* map io handlers */ + err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg); + if (err) { + soc_control_err(tplg, &ec->hdr, ec->hdr.name); + return err; + } -err_se: - return NULL; + /* pass control to driver for optional further init */ + err = soc_tplg_init_kcontrol(tplg, kc, + (struct snd_soc_tplg_ctl_hdr *)ec); + if (err < 0) { + dev_err(tplg->dev, "ASoC: failed to init %s\n", + ec->hdr.name); + return err; + } + + return 0; } -static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( - struct soc_tplg *tplg, int num_kcontrols) +static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) { struct snd_soc_tplg_bytes_control *be; struct soc_bytes_ext *sbe; - struct snd_kcontrol_new *kc; - int i, err; - - kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL); - if (!kc) - return NULL; + int err; - for (i = 0; i < num_kcontrols; i++) { - be = (struct snd_soc_tplg_bytes_control *)tplg->pos; + be = (struct snd_soc_tplg_bytes_control *)tplg->pos; - /* validate kcontrol */ - if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - goto err_sbe; + /* validate kcontrol */ + if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; - sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); - if (sbe == NULL) - goto err_sbe; + sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); + if (!sbe) + return -ENOMEM; - tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + - le32_to_cpu(be->priv.size)); + tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + + le32_to_cpu(be->priv.size)); - dev_dbg(tplg->dev, - "ASoC: adding bytes kcontrol %s with access 0x%x\n", - be->hdr.name, be->hdr.access); + dev_dbg(tplg->dev, + "ASoC: adding bytes kcontrol %s with access 0x%x\n", + be->hdr.name, be->hdr.access); - kc[i].private_value = (long)sbe; - kc[i].name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL); - if (kc[i].name == NULL) - goto err_sbe; - kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc[i].access = le32_to_cpu(be->hdr.access); + kc->private_value = (long)sbe; + kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL); + if (!kc->name) + return -ENOMEM; + kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc->access = le32_to_cpu(be->hdr.access); - sbe->max = le32_to_cpu(be->max); - INIT_LIST_HEAD(&sbe->dobj.list); + sbe->max = le32_to_cpu(be->max); + INIT_LIST_HEAD(&sbe->dobj.list); - /* map standard io handlers and check for external handlers */ - err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], tplg); - if (err) { - soc_control_err(tplg, &be->hdr, be->hdr.name); - goto err_sbe; - } - - /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, &kc[i], - (struct snd_soc_tplg_ctl_hdr *)be); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - be->hdr.name); - goto err_sbe; - } + /* map standard io handlers and check for external handlers */ + err = soc_tplg_kcontrol_bind_io(&be->hdr, kc, tplg); + if (err) { + soc_control_err(tplg, &be->hdr, be->hdr.name); + return err; } - return kc; - -err_sbe: + /* pass control to driver for optional further init */ + err = soc_tplg_init_kcontrol(tplg, kc, + (struct snd_soc_tplg_ctl_hdr *)be); + if (err < 0) { + dev_err(tplg->dev, "ASoC: failed to init %s\n", + be->hdr.name); + return err; + } - return NULL; + return 0; } static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, @@ -1455,8 +1422,13 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, struct snd_soc_dapm_widget template, *widget; struct snd_soc_tplg_ctl_hdr *control_hdr; struct snd_soc_card *card = tplg->comp->card; - unsigned int kcontrol_type; + unsigned int *kcontrol_type = NULL; + struct snd_kcontrol_new *kc; + int mixer_count = 0; + int bytes_count = 0; + int enum_count = 0; int ret = 0; + int i; if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) @@ -1499,7 +1471,6 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, le32_to_cpu(w->priv.size)); if (w->num_kcontrols == 0) { - kcontrol_type = 0; template.num_kcontrols = 0; goto widget; } @@ -1508,57 +1479,66 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n", w->name, w->num_kcontrols, control_hdr->type); - switch (le32_to_cpu(control_hdr->ops.info)) { - case SND_SOC_TPLG_CTL_VOLSW: - case SND_SOC_TPLG_CTL_STROBE: - case SND_SOC_TPLG_CTL_VOLSW_SX: - case SND_SOC_TPLG_CTL_VOLSW_XR_SX: - case SND_SOC_TPLG_CTL_RANGE: - case SND_SOC_TPLG_DAPM_CTL_VOLSW: - kcontrol_type = SND_SOC_TPLG_TYPE_MIXER; /* volume mixer */ - template.num_kcontrols = le32_to_cpu(w->num_kcontrols); - template.kcontrol_news = - soc_tplg_dapm_widget_dmixer_create(tplg, - template.num_kcontrols); - if (!template.kcontrol_news) { - ret = -ENOMEM; - goto hdr_err; - } - break; - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_CTL_ENUM_VALUE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - kcontrol_type = SND_SOC_TPLG_TYPE_ENUM; /* enumerated mixer */ - template.num_kcontrols = le32_to_cpu(w->num_kcontrols); - template.kcontrol_news = - soc_tplg_dapm_widget_denum_create(tplg, - template.num_kcontrols); - if (!template.kcontrol_news) { - ret = -ENOMEM; - goto hdr_err; - } - break; - case SND_SOC_TPLG_CTL_BYTES: - kcontrol_type = SND_SOC_TPLG_TYPE_BYTES; /* bytes control */ - template.num_kcontrols = le32_to_cpu(w->num_kcontrols); - template.kcontrol_news = - soc_tplg_dapm_widget_dbytes_create(tplg, - template.num_kcontrols); - if (!template.kcontrol_news) { - ret = -ENOMEM; + template.num_kcontrols = le32_to_cpu(w->num_kcontrols); + kc = devm_kcalloc(tplg->dev, le32_to_cpu(w->num_kcontrols), sizeof(*kc), GFP_KERNEL); + if (!kc) + goto err; + + kcontrol_type = devm_kcalloc(tplg->dev, le32_to_cpu(w->num_kcontrols), sizeof(unsigned int), + GFP_KERNEL); + if (!kcontrol_type) + goto err; + + for (i = 0; i < w->num_kcontrols; i++) { + control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; + switch (le32_to_cpu(control_hdr->ops.info)) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_STROBE: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + case SND_SOC_TPLG_CTL_RANGE: + case SND_SOC_TPLG_DAPM_CTL_VOLSW: + /* volume mixer */ + kc[i].index = mixer_count; + kcontrol_type[i] = SND_SOC_TPLG_TYPE_MIXER; + mixer_count++; + ret = soc_tplg_dapm_widget_dmixer_create(tplg, &kc[i]); + if (ret < 0) + goto hdr_err; + break; + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + /* enumerated mixer */ + kc[i].index = enum_count; + kcontrol_type[i] = SND_SOC_TPLG_TYPE_ENUM; + enum_count++; + ret = soc_tplg_dapm_widget_denum_create(tplg, &kc[i]); + if (ret < 0) + goto hdr_err; + break; + case SND_SOC_TPLG_CTL_BYTES: + /* bytes control */ + kc[i].index = bytes_count; + kcontrol_type[i] = SND_SOC_TPLG_TYPE_BYTES; + bytes_count++; + ret = soc_tplg_dapm_widget_dbytes_create(tplg, &kc[i]); + if (ret < 0) + goto hdr_err; + break; + default: + dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n", + control_hdr->ops.get, control_hdr->ops.put, + le32_to_cpu(control_hdr->ops.info)); + ret = -EINVAL; goto hdr_err; } - break; - default: - dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n", - control_hdr->ops.get, control_hdr->ops.put, - le32_to_cpu(control_hdr->ops.info)); - ret = -EINVAL; - goto hdr_err; } + template.kcontrol_news = kc; + widget: ret = soc_tplg_widget_load(tplg, &template, w); if (ret < 0) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 98383fd76224..299b5d6ebfd1 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -97,6 +97,34 @@ static const struct snd_soc_component_driver dummy_codec = { SNDRV_PCM_FMTBIT_S32_LE | \ SNDRV_PCM_FMTBIT_U32_LE | \ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) + +/* + * Select these from Sound Card Manually + * SND_SOC_POSSIBLE_DAIFMT_CBP_CFP + * SND_SOC_POSSIBLE_DAIFMT_CBP_CFC + * SND_SOC_POSSIBLE_DAIFMT_CBC_CFP + * SND_SOC_POSSIBLE_DAIFMT_CBC_CFC + */ +static u64 dummy_dai_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B | + SND_SOC_POSSIBLE_DAIFMT_AC97 | + SND_SOC_POSSIBLE_DAIFMT_PDM | + SND_SOC_POSSIBLE_DAIFMT_GATED | + SND_SOC_POSSIBLE_DAIFMT_CONT | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + +static const struct snd_soc_dai_ops dummy_dai_ops = { + .auto_selectable_formats = &dummy_dai_formats, + .num_auto_selectable_formats = 1, +}; + /* * The dummy CODEC is only meant to be used in situations where there is no * actual hardware. @@ -122,6 +150,7 @@ static struct snd_soc_dai_driver dummy_dai = { .rates = STUB_RATES, .formats = STUB_FORMATS, }, + .ops = &dummy_dai_ops, }; int snd_soc_dai_is_dummy(struct snd_soc_dai *dai) diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index 2d4969c705a4..57d5bf0a171e 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -13,7 +13,7 @@ #include "ops.h" #include "probe.h" -struct snd_compress_ops sof_probe_compressed_ops = { +const struct snd_compress_ops sof_probe_compressed_ops = { .copy = sof_probe_compr_copy, }; EXPORT_SYMBOL(sof_probe_compressed_ops); diff --git a/sound/soc/sof/compress.h b/sound/soc/sof/compress.h index ca8790bd4b13..4448c799e14b 100644 --- a/sound/soc/sof/compress.h +++ b/sound/soc/sof/compress.h @@ -13,7 +13,7 @@ #include <sound/compress_driver.h> -extern struct snd_compress_ops sof_probe_compressed_ops; +extern const struct snd_compress_ops sof_probe_compressed_ops; int sof_probe_compr_open(struct snd_compr_stream *cstream, struct snd_soc_dai *dai); diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 4e7dccadd7d0..12fedf0984bd 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -315,6 +315,7 @@ static int imx8_probe(struct snd_sof_dev *sdev) } ret = of_address_to_resource(res_node, 0, &res); + of_node_put(res_node); if (ret) { dev_err(&pdev->dev, "failed to get reserved region address\n"); goto exit_pdev_unregister; diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index f3d6f7070fb3..feae487f0227 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -13,7 +13,10 @@ snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o snd-sof-intel-hda-objs := hda-codec.o -obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-acpi-intel-byt.o +snd-sof-intel-atom-objs := atom.o + +obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-intel-atom.o +obj-$(CONFIG_SND_SOC_SOF_BAYTRAIL) += snd-sof-acpi-intel-byt.o obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-acpi-intel-bdw.o obj-$(CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC) += snd-sof-intel-ipc.o obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c new file mode 100644 index 000000000000..d8804efede5e --- /dev/null +++ b/sound/soc/sof/intel/atom.c @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// + +/* + * Hardware interface for audio DSP on Atom devices + */ + +#include <linux/module.h> +#include <sound/sof.h> +#include <sound/sof/xtensa.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/intel-dsp-config.h> +#include "../ops.h" +#include "shim.h" +#include "atom.h" +#include "../sof-acpi-dev.h" +#include "../sof-audio.h" +#include "../../intel/common/soc-intel-quirks.h" + +static void atom_host_done(struct snd_sof_dev *sdev); +static void atom_dsp_done(struct snd_sof_dev *sdev); +static void atom_get_reply(struct snd_sof_dev *sdev); + +/* + * Debug + */ + +static void atom_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + u32 offset = sdev->dsp_oops_offset; + + /* first read regsisters */ + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* note: variable AR register array is not read */ + + /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } + offset += xoops->arch_hdr.totalsize; + sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); + + /* then get the stack */ + offset += sizeof(*panic_info); + sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32)); +} + +void atom_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[STACK_DUMP_SIZE]; + u64 status, panic, imrd, imrx; + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IPCD); + panic = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IPCX); + atom_get_registers(sdev, &xoops, &panic_info, stack, + STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, + STACK_DUMP_SIZE); + + /* provide some context for firmware debug */ + imrx = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IMRX); + imrd = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IMRD); + dev_err(sdev->dev, + "error: ipc host -> DSP: pending %s complete %s raw 0x%llx\n", + (panic & SHIM_IPCX_BUSY) ? "yes" : "no", + (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic); + dev_err(sdev->dev, + "error: mask host: pending %s complete %s raw 0x%llx\n", + (imrx & SHIM_IMRX_BUSY) ? "yes" : "no", + (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx); + dev_err(sdev->dev, + "error: ipc DSP -> host: pending %s complete %s raw 0x%llx\n", + (status & SHIM_IPCD_BUSY) ? "yes" : "no", + (status & SHIM_IPCD_DONE) ? "yes" : "no", status); + dev_err(sdev->dev, + "error: mask DSP: pending %s complete %s raw 0x%llx\n", + (imrd & SHIM_IMRD_BUSY) ? "yes" : "no", + (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd); + +} +EXPORT_SYMBOL_NS(atom_dump, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +/* + * IPC Doorbell IRQ handler and thread. + */ + +irqreturn_t atom_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + u64 ipcx, ipcd; + int ret = IRQ_NONE; + + ipcx = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IPCX); + ipcd = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IPCD); + + if (ipcx & SHIM_BYT_IPCX_DONE) { + + /* reply message from DSP, Mask Done interrupt first */ + snd_sof_dsp_update_bits64_unlocked(sdev, DSP_BAR, + SHIM_IMRX, + SHIM_IMRX_DONE, + SHIM_IMRX_DONE); + ret = IRQ_WAKE_THREAD; + } + + if (ipcd & SHIM_BYT_IPCD_BUSY) { + + /* new message from DSP, Mask Busy interrupt first */ + snd_sof_dsp_update_bits64_unlocked(sdev, DSP_BAR, + SHIM_IMRX, + SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + ret = IRQ_WAKE_THREAD; + } + + return ret; +} +EXPORT_SYMBOL_NS(atom_irq_handler, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +irqreturn_t atom_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + u64 ipcx, ipcd; + + ipcx = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IPCX); + ipcd = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IPCD); + + /* reply message from DSP */ + if (ipcx & SHIM_BYT_IPCX_DONE) { + + spin_lock_irq(&sdev->ipc_lock); + + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + atom_get_reply(sdev); + snd_sof_ipc_reply(sdev, ipcx); + + atom_dsp_done(sdev); + + spin_unlock_irq(&sdev->ipc_lock); + } + + /* new message from DSP */ + if (ipcd & SHIM_BYT_IPCD_BUSY) { + + /* Handle messages from DSP Core */ + if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, PANIC_OFFSET(ipcd) + + MBOX_OFFSET); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + + atom_host_done(sdev); + } + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_NS(atom_irq_thread, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + /* unmask and prepare to receive Done interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); + + /* send the message */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write64(sdev, DSP_BAR, SHIM_IPCX, SHIM_BYT_IPCX_BUSY); + + return 0; +} +EXPORT_SYMBOL_NS(atom_send_msg, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +static void atom_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + int ret = 0; + + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + + /* get reply */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + + msg->reply_error = ret; +} + +int atom_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} +EXPORT_SYMBOL_NS(atom_get_mailbox_offset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +int atom_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} +EXPORT_SYMBOL_NS(atom_get_window_offset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +static void atom_host_done(struct snd_sof_dev *sdev) +{ + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits64_unlocked(sdev, DSP_BAR, SHIM_IPCD, + SHIM_BYT_IPCD_BUSY | + SHIM_BYT_IPCD_DONE, + SHIM_BYT_IPCD_DONE); + + /* unmask and prepare to receive next new message */ + snd_sof_dsp_update_bits64_unlocked(sdev, DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); +} + +static void atom_dsp_done(struct snd_sof_dev *sdev) +{ + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits64_unlocked(sdev, DSP_BAR, SHIM_IPCX, + SHIM_BYT_IPCX_DONE, 0); +} + +/* + * DSP control. + */ + +int atom_run(struct snd_sof_dev *sdev) +{ + int tries = 10; + + /* release stall and wait to unstall */ + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_STALL, 0x0); + while (tries--) { + if (!(snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_CSR) & + SHIM_BYT_CSR_PWAITMODE)) + break; + msleep(100); + } + if (tries < 0) { + dev_err(sdev->dev, "error: unable to run DSP firmware\n"); + atom_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); + return -ENODEV; + } + + /* return init core mask */ + return 1; +} +EXPORT_SYMBOL_NS(atom_run, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +int atom_reset(struct snd_sof_dev *sdev) +{ + /* put DSP into reset, set reset vector and stall */ + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL | + SHIM_BYT_CSR_STALL, + SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL | + SHIM_BYT_CSR_STALL); + + usleep_range(10, 15); + + /* take DSP out of reset and keep stalled for FW loading */ + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_RST, 0); + + return 0; +} +EXPORT_SYMBOL_NS(atom_reset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +static const char *fixup_tplg_name(struct snd_sof_dev *sdev, + const char *sof_tplg_filename, + const char *ssp_str) +{ + const char *tplg_filename = NULL; + char *filename; + char *split_ext; + + filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL); + if (!filename) + return NULL; + + /* this assumes a .tplg extension */ + split_ext = strsep(&filename, "."); + if (split_ext) { + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s-%s.tplg", + split_ext, ssp_str); + if (!tplg_filename) + return NULL; + } + return tplg_filename; +} + +void atom_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_soc_acpi_mach *mach; + struct platform_device *pdev; + const char *tplg_filename; + + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { + dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); + return; + } + + pdev = to_platform_device(sdev->dev); + if (soc_intel_is_byt_cr(pdev)) { + dev_dbg(sdev->dev, + "BYT-CR detected, SSP0 used instead of SSP2\n"); + + tplg_filename = fixup_tplg_name(sdev, + mach->sof_tplg_filename, + "ssp0"); + } else { + tplg_filename = mach->sof_tplg_filename; + } + + if (!tplg_filename) { + dev_dbg(sdev->dev, + "error: no topology filename\n"); + return; + } + + sof_pdata->tplg_filename = tplg_filename; + mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; + sof_pdata->machine = mach; +} +EXPORT_SYMBOL_NS(atom_machine_select, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +/* Atom DAIs */ +struct snd_soc_dai_driver atom_dai[] = { +{ + .name = "ssp0-port", + .playback = { + .channels_min = 1, + .channels_max = 8, + }, + .capture = { + .channels_min = 1, + .channels_max = 8, + }, +}, +{ + .name = "ssp1-port", + .playback = { + .channels_min = 1, + .channels_max = 8, + }, + .capture = { + .channels_min = 1, + .channels_max = 8, + }, +}, +{ + .name = "ssp2-port", + .playback = { + .channels_min = 1, + .channels_max = 8, + }, + .capture = { + .channels_min = 1, + .channels_max = 8, + } +}, +{ + .name = "ssp3-port", + .playback = { + .channels_min = 1, + .channels_max = 8, + }, + .capture = { + .channels_min = 1, + .channels_max = 8, + }, +}, +{ + .name = "ssp4-port", + .playback = { + .channels_min = 1, + .channels_max = 8, + }, + .capture = { + .channels_min = 1, + .channels_max = 8, + }, +}, +{ + .name = "ssp5-port", + .playback = { + .channels_min = 1, + .channels_max = 8, + }, + .capture = { + .channels_min = 1, + .channels_max = 8, + }, +}, +}; +EXPORT_SYMBOL_NS(atom_dai, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +void atom_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct snd_soc_acpi_mach_params *mach_params; + + mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; + mach_params->platform = dev_name(sdev->dev); + mach_params->num_dai_drivers = desc->ops->num_drv; + mach_params->dai_drivers = desc->ops->drv; +} +EXPORT_SYMBOL_NS(atom_set_mach_params, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/atom.h b/sound/soc/sof/intel/atom.h new file mode 100644 index 000000000000..96a462c7a2e5 --- /dev/null +++ b/sound/soc/sof/intel/atom.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2017-2021 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> + */ + +#ifndef __SOF_INTEL_ATOM_H +#define __SOF_INTEL_ATOM_H + +/* DSP memories */ +#define IRAM_OFFSET 0x0C0000 +#define IRAM_SIZE (80 * 1024) +#define DRAM_OFFSET 0x100000 +#define DRAM_SIZE (160 * 1024) +#define SHIM_OFFSET 0x140000 +#define SHIM_SIZE_BYT 0x100 +#define SHIM_SIZE_CHT 0x118 +#define MBOX_OFFSET 0x144000 +#define MBOX_SIZE 0x1000 +#define EXCEPT_OFFSET 0x800 +#define EXCEPT_MAX_HDR_SIZE 0x400 + +/* DSP peripherals */ +#define DMAC0_OFFSET 0x098000 +#define DMAC1_OFFSET 0x09c000 +#define DMAC2_OFFSET 0x094000 +#define DMAC_SIZE 0x420 +#define SSP0_OFFSET 0x0a0000 +#define SSP1_OFFSET 0x0a1000 +#define SSP2_OFFSET 0x0a2000 +#define SSP3_OFFSET 0x0a4000 +#define SSP4_OFFSET 0x0a5000 +#define SSP5_OFFSET 0x0a6000 +#define SSP_SIZE 0x100 + +#define STACK_DUMP_SIZE 32 + +#define PCI_BAR_SIZE 0x200000 + +#define PANIC_OFFSET(x) (((x) & GENMASK_ULL(47, 32)) >> 32) + +/* + * Debug + */ + +#define MBOX_DUMP_SIZE 0x30 + +/* BARs */ +#define DSP_BAR 0 +#define PCI_BAR 1 +#define IMR_BAR 2 + +irqreturn_t atom_irq_handler(int irq, void *context); +irqreturn_t atom_irq_thread(int irq, void *context); + +int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); +int atom_get_mailbox_offset(struct snd_sof_dev *sdev); +int atom_get_window_offset(struct snd_sof_dev *sdev, u32 id); + +int atom_run(struct snd_sof_dev *sdev); +int atom_reset(struct snd_sof_dev *sdev); +void atom_dump(struct snd_sof_dev *sdev, u32 flags); + +void atom_machine_select(struct snd_sof_dev *sdev); +void atom_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct snd_sof_dev *sdev); + +extern struct snd_soc_dai_driver atom_dai[]; + +#endif diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index d9803e2ba67f..8edaf6fdd218 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -19,662 +19,66 @@ #include <sound/soc-acpi-intel-match.h> #include <sound/intel-dsp-config.h> #include "../ops.h" +#include "atom.h" #include "shim.h" #include "../sof-acpi-dev.h" #include "../sof-audio.h" #include "../../intel/common/soc-intel-quirks.h" -/* DSP memories */ -#define IRAM_OFFSET 0x0C0000 -#define IRAM_SIZE (80 * 1024) -#define DRAM_OFFSET 0x100000 -#define DRAM_SIZE (160 * 1024) -#define SHIM_OFFSET 0x140000 -#define SHIM_SIZE_BYT 0x100 -#define SHIM_SIZE_CHT 0x118 -#define MBOX_OFFSET 0x144000 -#define MBOX_SIZE 0x1000 -#define EXCEPT_OFFSET 0x800 -#define EXCEPT_MAX_HDR_SIZE 0x400 - -/* DSP peripherals */ -#define DMAC0_OFFSET 0x098000 -#define DMAC1_OFFSET 0x09c000 -#define DMAC2_OFFSET 0x094000 -#define DMAC_SIZE 0x420 -#define SSP0_OFFSET 0x0a0000 -#define SSP1_OFFSET 0x0a1000 -#define SSP2_OFFSET 0x0a2000 -#define SSP3_OFFSET 0x0a4000 -#define SSP4_OFFSET 0x0a5000 -#define SSP5_OFFSET 0x0a6000 -#define SSP_SIZE 0x100 - -#define BYT_STACK_DUMP_SIZE 32 - -#define BYT_PCI_BAR_SIZE 0x200000 - -#define BYT_PANIC_OFFSET(x) (((x) & GENMASK_ULL(47, 32)) >> 32) - -/* - * Debug - */ - -#define MBOX_DUMP_SIZE 0x30 - -/* BARs */ -#define BYT_DSP_BAR 0 -#define BYT_PCI_BAR 1 -#define BYT_IMR_BAR 2 - static const struct snd_sof_debugfs_map byt_debugfs[] = { - {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + {"dmac0", DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + {"dmac1", DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE, + {"ssp0", DSP_BAR, SSP0_OFFSET, SSP_SIZE, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE, + {"ssp1", DSP_BAR, SSP1_OFFSET, SSP_SIZE, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE, + {"ssp2", DSP_BAR, SSP2_OFFSET, SSP_SIZE, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE, + {"iram", DSP_BAR, IRAM_OFFSET, IRAM_SIZE, SOF_DEBUGFS_ACCESS_D0_ONLY}, - {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE, + {"dram", DSP_BAR, DRAM_OFFSET, DRAM_SIZE, SOF_DEBUGFS_ACCESS_D0_ONLY}, - {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE_BYT, + {"shim", DSP_BAR, SHIM_OFFSET, SHIM_SIZE_BYT, SOF_DEBUGFS_ACCESS_ALWAYS}, }; -static void byt_host_done(struct snd_sof_dev *sdev); -static void byt_dsp_done(struct snd_sof_dev *sdev); -static void byt_get_reply(struct snd_sof_dev *sdev); - -/* - * Debug - */ - -static void byt_get_registers(struct snd_sof_dev *sdev, - struct sof_ipc_dsp_oops_xtensa *xoops, - struct sof_ipc_panic_info *panic_info, - u32 *stack, size_t stack_words) -{ - u32 offset = sdev->dsp_oops_offset; - - /* first read regsisters */ - sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); - - /* note: variable AR register array is not read */ - - /* then get panic info */ - if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { - dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", - xoops->arch_hdr.totalsize); - return; - } - offset += xoops->arch_hdr.totalsize; - sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); - - /* then get the stack */ - offset += sizeof(*panic_info); - sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32)); -} - -static void byt_dump(struct snd_sof_dev *sdev, u32 flags) -{ - struct sof_ipc_dsp_oops_xtensa xoops; - struct sof_ipc_panic_info panic_info; - u32 stack[BYT_STACK_DUMP_SIZE]; - u64 status, panic, imrd, imrx; - - /* now try generic SOF status messages */ - status = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD); - panic = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); - byt_get_registers(sdev, &xoops, &panic_info, stack, - BYT_STACK_DUMP_SIZE); - snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, - BYT_STACK_DUMP_SIZE); - - /* provide some context for firmware debug */ - imrx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRX); - imrd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRD); - dev_err(sdev->dev, - "error: ipc host -> DSP: pending %s complete %s raw 0x%llx\n", - (panic & SHIM_IPCX_BUSY) ? "yes" : "no", - (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic); - dev_err(sdev->dev, - "error: mask host: pending %s complete %s raw 0x%llx\n", - (imrx & SHIM_IMRX_BUSY) ? "yes" : "no", - (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx); - dev_err(sdev->dev, - "error: ipc DSP -> host: pending %s complete %s raw 0x%llx\n", - (status & SHIM_IPCD_BUSY) ? "yes" : "no", - (status & SHIM_IPCD_DONE) ? "yes" : "no", status); - dev_err(sdev->dev, - "error: mask DSP: pending %s complete %s raw 0x%llx\n", - (imrd & SHIM_IMRD_BUSY) ? "yes" : "no", - (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd); - -} - -/* - * IPC Doorbell IRQ handler and thread. - */ - -static irqreturn_t byt_irq_handler(int irq, void *context) -{ - struct snd_sof_dev *sdev = context; - u64 ipcx, ipcd; - int ret = IRQ_NONE; - - ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); - ipcd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD); - - if (ipcx & SHIM_BYT_IPCX_DONE) { - - /* reply message from DSP, Mask Done interrupt first */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, - SHIM_IMRX, - SHIM_IMRX_DONE, - SHIM_IMRX_DONE); - ret = IRQ_WAKE_THREAD; - } - - if (ipcd & SHIM_BYT_IPCD_BUSY) { - - /* new message from DSP, Mask Busy interrupt first */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, - SHIM_IMRX, - SHIM_IMRX_BUSY, - SHIM_IMRX_BUSY); - ret = IRQ_WAKE_THREAD; - } - - return ret; -} - -static irqreturn_t byt_irq_thread(int irq, void *context) -{ - struct snd_sof_dev *sdev = context; - u64 ipcx, ipcd; - - ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); - ipcd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD); - - /* reply message from DSP */ - if (ipcx & SHIM_BYT_IPCX_DONE) { - - spin_lock_irq(&sdev->ipc_lock); - - /* - * handle immediate reply from DSP core. If the msg is - * found, set done bit in cmd_done which is called at the - * end of message processing function, else set it here - * because the done bit can't be set in cmd_done function - * which is triggered by msg - */ - byt_get_reply(sdev); - snd_sof_ipc_reply(sdev, ipcx); - - byt_dsp_done(sdev); - - spin_unlock_irq(&sdev->ipc_lock); - } - - /* new message from DSP */ - if (ipcd & SHIM_BYT_IPCD_BUSY) { - - /* Handle messages from DSP Core */ - if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { - snd_sof_dsp_panic(sdev, BYT_PANIC_OFFSET(ipcd) + - MBOX_OFFSET); - } else { - snd_sof_ipc_msgs_rx(sdev); - } - - byt_host_done(sdev); - } - - return IRQ_HANDLED; -} - -static int byt_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) -{ - /* unmask and prepare to receive Done interrupt */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, 0); - - /* send the message */ - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - snd_sof_dsp_write64(sdev, BYT_DSP_BAR, SHIM_IPCX, SHIM_BYT_IPCX_BUSY); - - return 0; -} - -static void byt_get_reply(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply reply; - int ret = 0; - - /* - * Sometimes, there is unexpected reply ipc arriving. The reply - * ipc belongs to none of the ipcs sent from driver. - * In this case, the driver must ignore the ipc. - */ - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); - return; - } - - /* get reply */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; - } else { - /* reply correct size ? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; -} - -static int byt_get_mailbox_offset(struct snd_sof_dev *sdev) -{ - return MBOX_OFFSET; -} - -static int byt_get_window_offset(struct snd_sof_dev *sdev, u32 id) -{ - return MBOX_OFFSET; -} - -static void byt_host_done(struct snd_sof_dev *sdev) -{ - /* clear BUSY bit and set DONE bit - accept new messages */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD, - SHIM_BYT_IPCD_BUSY | - SHIM_BYT_IPCD_DONE, - SHIM_BYT_IPCD_DONE); - - /* unmask and prepare to receive next new message */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, 0); -} - -static void byt_dsp_done(struct snd_sof_dev *sdev) -{ - /* clear DONE bit - tell DSP we have completed */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX, - SHIM_BYT_IPCX_DONE, 0); -} - -/* - * DSP control. - */ - -static int byt_run(struct snd_sof_dev *sdev) -{ - int tries = 10; - - /* release stall and wait to unstall */ - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, - SHIM_BYT_CSR_STALL, 0x0); - while (tries--) { - if (!(snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_CSR) & - SHIM_BYT_CSR_PWAITMODE)) - break; - msleep(100); - } - if (tries < 0) { - dev_err(sdev->dev, "error: unable to run DSP firmware\n"); - byt_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); - return -ENODEV; - } - - /* return init core mask */ - return 1; -} - -static int byt_reset(struct snd_sof_dev *sdev) -{ - /* put DSP into reset, set reset vector and stall */ - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, - SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL | - SHIM_BYT_CSR_STALL, - SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL | - SHIM_BYT_CSR_STALL); - - usleep_range(10, 15); - - /* take DSP out of reset and keep stalled for FW loading */ - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, - SHIM_BYT_CSR_RST, 0); - - return 0; -} - -static const char *fixup_tplg_name(struct snd_sof_dev *sdev, - const char *sof_tplg_filename, - const char *ssp_str) -{ - const char *tplg_filename = NULL; - char *filename; - char *split_ext; - - filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL); - if (!filename) - return NULL; - - /* this assumes a .tplg extension */ - split_ext = strsep(&filename, "."); - if (split_ext) { - tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s-%s.tplg", - split_ext, ssp_str); - if (!tplg_filename) - return NULL; - } - return tplg_filename; -} - -static void byt_machine_select(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *sof_pdata = sdev->pdata; - const struct sof_dev_desc *desc = sof_pdata->desc; - struct snd_soc_acpi_mach *mach; - struct platform_device *pdev; - const char *tplg_filename; - - mach = snd_soc_acpi_find_machine(desc->machines); - if (!mach) { - dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); - return; - } - - pdev = to_platform_device(sdev->dev); - if (soc_intel_is_byt_cr(pdev)) { - dev_dbg(sdev->dev, - "BYT-CR detected, SSP0 used instead of SSP2\n"); - - tplg_filename = fixup_tplg_name(sdev, - mach->sof_tplg_filename, - "ssp0"); - } else { - tplg_filename = mach->sof_tplg_filename; - } - - if (!tplg_filename) { - dev_dbg(sdev->dev, - "error: no topology filename\n"); - return; - } - - sof_pdata->tplg_filename = tplg_filename; - mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; - sof_pdata->machine = mach; -} - -/* Baytrail DAIs */ -static struct snd_soc_dai_driver byt_dai[] = { -{ - .name = "ssp0-port", - .playback = { - .channels_min = 1, - .channels_max = 8, - }, - .capture = { - .channels_min = 1, - .channels_max = 8, - }, -}, -{ - .name = "ssp1-port", - .playback = { - .channels_min = 1, - .channels_max = 8, - }, - .capture = { - .channels_min = 1, - .channels_max = 8, - }, -}, -{ - .name = "ssp2-port", - .playback = { - .channels_min = 1, - .channels_max = 8, - }, - .capture = { - .channels_min = 1, - .channels_max = 8, - } -}, -{ - .name = "ssp3-port", - .playback = { - .channels_min = 1, - .channels_max = 8, - }, - .capture = { - .channels_min = 1, - .channels_max = 8, - }, -}, -{ - .name = "ssp4-port", - .playback = { - .channels_min = 1, - .channels_max = 8, - }, - .capture = { - .channels_min = 1, - .channels_max = 8, - }, -}, -{ - .name = "ssp5-port", - .playback = { - .channels_min = 1, - .channels_max = 8, - }, - .capture = { - .channels_min = 1, - .channels_max = 8, - }, -}, -}; - -static void byt_set_mach_params(const struct snd_soc_acpi_mach *mach, - struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *pdata = sdev->pdata; - const struct sof_dev_desc *desc = pdata->desc; - struct snd_soc_acpi_mach_params *mach_params; - - mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; - mach_params->platform = dev_name(sdev->dev); - mach_params->num_dai_drivers = desc->ops->num_drv; - mach_params->dai_drivers = desc->ops->drv; -} - -/* - * Probe and remove. - */ - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) - -static int tangier_pci_probe(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *pdata = sdev->pdata; - const struct sof_dev_desc *desc = pdata->desc; - struct pci_dev *pci = to_pci_dev(sdev->dev); - u32 base, size; - int ret; - - /* DSP DMA can only access low 31 bits of host memory */ - ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31)); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); - return ret; - } - - /* LPE base */ - base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET; - size = BYT_PCI_BAR_SIZE; - - dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); - sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[BYT_DSP_BAR]) { - dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", - base, size); - return -ENODEV; - } - dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]); - - /* IMR base - optional */ - if (desc->resindex_imr_base == -1) - goto irq; - - base = pci_resource_start(pci, desc->resindex_imr_base); - size = pci_resource_len(pci, desc->resindex_imr_base); - - /* some BIOSes don't map IMR */ - if (base == 0x55aa55aa || base == 0x0) { - dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n"); - goto irq; - } - - dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); - sdev->bar[BYT_IMR_BAR] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[BYT_IMR_BAR]) { - dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", - base, size); - return -ENODEV; - } - dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]); - -irq: - /* register our IRQ */ - sdev->ipc_irq = pci->irq; - dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); - ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, - byt_irq_handler, byt_irq_thread, - 0, "AudioDSP", sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to register IRQ %d\n", - sdev->ipc_irq); - return ret; - } - - /* enable BUSY and disable DONE Interrupt by default */ - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY | SHIM_IMRX_DONE, - SHIM_IMRX_DONE); - - /* set default mailbox offset for FW ready message */ - sdev->dsp_box.offset = MBOX_OFFSET; - - return ret; -} - -const struct snd_sof_dsp_ops sof_tng_ops = { - /* device init */ - .probe = tangier_pci_probe, - - /* DSP core boot / reset */ - .run = byt_run, - .reset = byt_reset, - - /* Register IO */ - .write = sof_io_write, - .read = sof_io_read, - .write64 = sof_io_write64, - .read64 = sof_io_read64, - - /* Block IO */ - .block_read = sof_block_read, - .block_write = sof_block_write, - - /* doorbell */ - .irq_handler = byt_irq_handler, - .irq_thread = byt_irq_thread, - - /* ipc */ - .send_msg = byt_send_msg, - .fw_ready = sof_fw_ready, - .get_mailbox_offset = byt_get_mailbox_offset, - .get_window_offset = byt_get_window_offset, - - .ipc_msg_data = intel_ipc_msg_data, - .ipc_pcm_params = intel_ipc_pcm_params, - - /* machine driver */ - .machine_select = byt_machine_select, - .machine_register = sof_machine_register, - .machine_unregister = sof_machine_unregister, - .set_mach_params = byt_set_mach_params, - - /* debug */ - .debug_map = byt_debugfs, - .debug_map_count = ARRAY_SIZE(byt_debugfs), - .dbg_dump = byt_dump, - - /* stream callbacks */ - .pcm_open = intel_pcm_open, - .pcm_close = intel_pcm_close, - - /* module loading */ - .load_module = snd_sof_parse_module_memcpy, - - /*Firmware loading */ - .load_firmware = snd_sof_load_firmware_memcpy, - - /* DAI drivers */ - .drv = byt_dai, - .num_drv = 3, /* we have only 3 SSPs on byt*/ - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH, - - .arch_ops = &sof_xtensa_arch_ops, -}; -EXPORT_SYMBOL_NS(sof_tng_ops, SND_SOC_SOF_MERRIFIELD); - -const struct sof_intel_dsp_desc tng_chip_info = { - .cores_num = 1, - .host_managed_cores_mask = 1, +static const struct snd_sof_debugfs_map cht_debugfs[] = { + {"dmac0", DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac2", DSP_BAR, DMAC2_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp2", DSP_BAR, SSP2_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp3", DSP_BAR, SSP3_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp4", DSP_BAR, SSP4_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp5", DSP_BAR, SSP5_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", DSP_BAR, IRAM_OFFSET, IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", DSP_BAR, DRAM_OFFSET, DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", DSP_BAR, SHIM_OFFSET, SHIM_SIZE_CHT, + SOF_DEBUGFS_ACCESS_ALWAYS}, }; -EXPORT_SYMBOL_NS(tng_chip_info, SND_SOC_SOF_MERRIFIELD); - -#endif /* CONFIG_SND_SOC_SOF_MERRIFIELD */ - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) static void byt_reset_dsp_disable_int(struct snd_sof_dev *sdev) { /* Disable Interrupt from both sides */ - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x3); - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x3); + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_IMRX, 0x3, 0x3); + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_IMRD, 0x3, 0x3); /* Put DSP into reset, set reset vector */ - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_CSR, SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL, SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL); } @@ -689,7 +93,7 @@ static int byt_suspend(struct snd_sof_dev *sdev, u32 target_state) static int byt_resume(struct snd_sof_dev *sdev) { /* enable BUSY and disable DONE Interrupt by default */ - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_IMRX, SHIM_IMRX_BUSY | SHIM_IMRX_DONE, SHIM_IMRX_DONE); @@ -703,33 +107,6 @@ static int byt_remove(struct snd_sof_dev *sdev) return 0; } -static const struct snd_sof_debugfs_map cht_debugfs[] = { - {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"dmac2", BYT_DSP_BAR, DMAC2_OFFSET, DMAC_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp3", BYT_DSP_BAR, SSP3_OFFSET, SSP_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp4", BYT_DSP_BAR, SSP4_OFFSET, SSP_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp5", BYT_DSP_BAR, SSP5_OFFSET, SSP_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE, - SOF_DEBUGFS_ACCESS_D0_ONLY}, - {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE, - SOF_DEBUGFS_ACCESS_D0_ONLY}, - {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE_CHT, - SOF_DEBUGFS_ACCESS_ALWAYS}, -}; - static int byt_acpi_probe(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; @@ -760,17 +137,17 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); - sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[BYT_DSP_BAR]) { + sdev->bar[DSP_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[DSP_BAR]) { dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", base, size); return -ENODEV; } - dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]); + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[DSP_BAR]); /* TODO: add offsets */ - sdev->mmio_bar = BYT_DSP_BAR; - sdev->mailbox_bar = BYT_DSP_BAR; + sdev->mmio_bar = DSP_BAR; + sdev->mailbox_bar = DSP_BAR; /* IMR base - optional */ if (desc->resindex_imr_base == -1) @@ -794,13 +171,13 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); - sdev->bar[BYT_IMR_BAR] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[BYT_IMR_BAR]) { + sdev->bar[IMR_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[IMR_BAR]) { dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", base, size); return -ENODEV; } - dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]); + dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[IMR_BAR]); irq: /* register our IRQ */ @@ -810,7 +187,7 @@ irq: dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, - byt_irq_handler, byt_irq_thread, + atom_irq_handler, atom_irq_thread, IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", @@ -819,7 +196,7 @@ irq: } /* enable BUSY and disable DONE Interrupt by default */ - snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_IMRX, SHIM_IMRX_BUSY | SHIM_IMRX_DONE, SHIM_IMRX_DONE); @@ -836,8 +213,8 @@ static const struct snd_sof_dsp_ops sof_byt_ops = { .remove = byt_remove, /* DSP core boot / reset */ - .run = byt_run, - .reset = byt_reset, + .run = atom_run, + .reset = atom_reset, /* Register IO */ .write = sof_io_write, @@ -850,28 +227,28 @@ static const struct snd_sof_dsp_ops sof_byt_ops = { .block_write = sof_block_write, /* doorbell */ - .irq_handler = byt_irq_handler, - .irq_thread = byt_irq_thread, + .irq_handler = atom_irq_handler, + .irq_thread = atom_irq_thread, /* ipc */ - .send_msg = byt_send_msg, + .send_msg = atom_send_msg, .fw_ready = sof_fw_ready, - .get_mailbox_offset = byt_get_mailbox_offset, - .get_window_offset = byt_get_window_offset, + .get_mailbox_offset = atom_get_mailbox_offset, + .get_window_offset = atom_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, /* machine driver */ - .machine_select = byt_machine_select, + .machine_select = atom_machine_select, .machine_register = sof_machine_register, .machine_unregister = sof_machine_unregister, - .set_mach_params = byt_set_mach_params, + .set_mach_params = atom_set_mach_params, /* debug */ .debug_map = byt_debugfs, .debug_map_count = ARRAY_SIZE(byt_debugfs), - .dbg_dump = byt_dump, + .dbg_dump = atom_dump, /* stream callbacks */ .pcm_open = intel_pcm_open, @@ -888,7 +265,7 @@ static const struct snd_sof_dsp_ops sof_byt_ops = { .resume = byt_resume, /* DAI drivers */ - .drv = byt_dai, + .drv = atom_dai, .num_drv = 3, /* we have only 3 SSPs on byt*/ /* ALSA HW info flags */ @@ -913,8 +290,8 @@ static const struct snd_sof_dsp_ops sof_cht_ops = { .remove = byt_remove, /* DSP core boot / reset */ - .run = byt_run, - .reset = byt_reset, + .run = atom_run, + .reset = atom_reset, /* Register IO */ .write = sof_io_write, @@ -927,28 +304,28 @@ static const struct snd_sof_dsp_ops sof_cht_ops = { .block_write = sof_block_write, /* doorbell */ - .irq_handler = byt_irq_handler, - .irq_thread = byt_irq_thread, + .irq_handler = atom_irq_handler, + .irq_thread = atom_irq_thread, /* ipc */ - .send_msg = byt_send_msg, + .send_msg = atom_send_msg, .fw_ready = sof_fw_ready, - .get_mailbox_offset = byt_get_mailbox_offset, - .get_window_offset = byt_get_window_offset, + .get_mailbox_offset = atom_get_mailbox_offset, + .get_window_offset = atom_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, /* machine driver */ - .machine_select = byt_machine_select, + .machine_select = atom_machine_select, .machine_register = sof_machine_register, .machine_unregister = sof_machine_unregister, - .set_mach_params = byt_set_mach_params, + .set_mach_params = atom_set_mach_params, /* debug */ .debug_map = cht_debugfs, .debug_map_count = ARRAY_SIZE(cht_debugfs), - .dbg_dump = byt_dump, + .dbg_dump = atom_dump, /* stream callbacks */ .pcm_open = intel_pcm_open, @@ -965,9 +342,9 @@ static const struct snd_sof_dsp_ops sof_cht_ops = { .resume = byt_resume, /* DAI drivers */ - .drv = byt_dai, + .drv = atom_dai, /* all 6 SSPs may be available for cherrytrail */ - .num_drv = ARRAY_SIZE(byt_dai), + .num_drv = 6, /* ALSA HW info flags */ .hw_info = SNDRV_PCM_INFO_MMAP | @@ -1073,9 +450,8 @@ static struct platform_driver snd_sof_acpi_intel_byt_driver = { }; module_platform_driver(snd_sof_acpi_intel_byt_driver); -#endif /* CONFIG_SND_SOC_SOF_BAYTRAIL */ - MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); MODULE_IMPORT_NS(SND_SOC_SOF_ACPI_DEV); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_ATOM_HIFI_EP); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index fc25ee8f68dc..6f4771bf9de3 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -385,11 +385,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) if (i == HDA_FW_BOOT_ATTEMPTS) { dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", i, ret); - dev_err(sdev->dev, "ROM error=0x%x: FW status=0x%x\n", - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_ERROR), - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS)); goto cleanup; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b00e8fcb2312..e1e368ff2b12 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -277,10 +277,12 @@ struct hda_dsp_msg_code { const char *msg; }; -static bool hda_use_msi = IS_ENABLED(CONFIG_PCI); #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) +static bool hda_use_msi = true; module_param_named(use_msi, hda_use_msi, bool, 0444); MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); +#else +#define hda_use_msi (1) #endif static char *hda_model; @@ -392,28 +394,21 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[HDA_DSP_STACK_DUMP_SIZE]; - u32 status, panic; - /* try APL specific status message types first */ + /* print ROM/FW status */ hda_dsp_get_status(sdev); - /* now try generic SOF status messages */ - status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_FW_STATUS); - panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP); - + /* print panic info if FW boot is complete. Otherwise, print the extended ROM status */ if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) { + u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS); + u32 panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP); + hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); } else { - sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL, - "status = 0x%8.8x panic = 0x%8.8x\n", - status, panic); - hda_dsp_dump_ext_rom_status(sdev, flags); - hda_dsp_get_status(sdev); } } @@ -485,9 +480,7 @@ static int hda_init(struct snd_sof_dev *sdev) /* initialise hdac bus */ bus->addr = pci_resource_start(pci, 0); -#if IS_ENABLED(CONFIG_PCI) bus->remap_addr = pci_ioremap_bar(pci, 0); -#endif if (!bus->remap_addr) { dev_err(bus->dev, "error: ioremap error\n"); return -ENXIO; @@ -799,9 +792,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) goto hdac_bus_unmap; /* DSP base */ -#if IS_ENABLED(CONFIG_PCI) sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); -#endif if (!sdev->bar[HDA_DSP_BAR]) { dev_err(sdev->dev, "error: ioremap error\n"); ret = -ENXIO; @@ -1069,7 +1060,7 @@ static bool link_slaves_found(struct snd_sof_dev *sdev, /* find out how many identical parts are expected */ for (k = 0; k < link->num_adr; k++) { - u64 adr2 = link->adr_d[i].adr; + u64 adr2 = link->adr_d[k].adr; unsigned int part_id2, link_id2, mfg_id2; mfg_id2 = SDW_MFG_ID(adr2); diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 88c3bf404dd7..a00262184efa 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -116,6 +116,8 @@ static const struct pci_device_id sof_pci_ids[] = { .driver_data = (unsigned long)&adls_desc}, { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */ .driver_data = (unsigned long)&adl_desc}, + { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */ + .driver_data = (unsigned long)&adl_desc}, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 94b9704c0117..4ee1da397d4e 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -14,7 +14,10 @@ #include <sound/soc-acpi-intel-match.h> #include <sound/sof.h> #include "../ops.h" +#include "atom.h" +#include "shim.h" #include "../sof-pci-dev.h" +#include "../sof-audio.h" /* platform specific devices */ #include "shim.h" @@ -29,6 +32,170 @@ static struct snd_soc_acpi_mach sof_tng_machines[] = { {} }; +static const struct snd_sof_debugfs_map tng_debugfs[] = { + {"dmac0", DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp2", DSP_BAR, SSP2_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", DSP_BAR, IRAM_OFFSET, IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", DSP_BAR, DRAM_OFFSET, DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", DSP_BAR, SHIM_OFFSET, SHIM_SIZE_BYT, + SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +static int tangier_pci_probe(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct pci_dev *pci = to_pci_dev(sdev->dev); + u32 base, size; + int ret; + + /* DSP DMA can only access low 31 bits of host memory */ + ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); + return ret; + } + + /* LPE base */ + base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET; + size = PCI_BAR_SIZE; + + dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); + sdev->bar[DSP_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[DSP_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[DSP_BAR]); + + /* IMR base - optional */ + if (desc->resindex_imr_base == -1) + goto irq; + + base = pci_resource_start(pci, desc->resindex_imr_base); + size = pci_resource_len(pci, desc->resindex_imr_base); + + /* some BIOSes don't map IMR */ + if (base == 0x55aa55aa || base == 0x0) { + dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n"); + goto irq; + } + + dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); + sdev->bar[IMR_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[IMR_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[IMR_BAR]); + +irq: + /* register our IRQ */ + sdev->ipc_irq = pci->irq; + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + atom_irq_handler, atom_irq_thread, + 0, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + return ret; + } + + /* enable BUSY and disable DONE Interrupt by default */ + snd_sof_dsp_update_bits64(sdev, DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY | SHIM_IMRX_DONE, + SHIM_IMRX_DONE); + + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; + + return ret; +} + +const struct snd_sof_dsp_ops sof_tng_ops = { + /* device init */ + .probe = tangier_pci_probe, + + /* DSP core boot / reset */ + .run = atom_run, + .reset = atom_reset, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_handler = atom_irq_handler, + .irq_thread = atom_irq_thread, + + /* ipc */ + .send_msg = atom_send_msg, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = atom_get_mailbox_offset, + .get_window_offset = atom_get_window_offset, + + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + + /* machine driver */ + .machine_select = atom_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = atom_set_mach_params, + + /* debug */ + .debug_map = tng_debugfs, + .debug_map_count = ARRAY_SIZE(tng_debugfs), + .dbg_dump = atom_dump, + + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = atom_dai, + .num_drv = 3, /* we have only 3 SSPs on byt*/ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, + + .arch_ops = &sof_xtensa_arch_ops, +}; + +const struct sof_intel_dsp_desc tng_chip_info = { + .cores_num = 1, + .host_managed_cores_mask = 1, +}; + static const struct sof_dev_desc tng_desc = { .machines = sof_tng_machines, .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ @@ -66,5 +233,7 @@ static struct pci_driver snd_sof_pci_intel_tng_driver = { module_pci_driver(snd_sof_pci_intel_tng_driver); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_IMPORT_NS(SND_SOC_SOF_MERRIFIELD); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC); +MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_ATOM_HIFI_EP); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 6efaf766f2ab..2b38a77cd594 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -517,7 +517,7 @@ int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready)); + snd_sof_dsp_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready)); /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 323a0b3f561b..4a5d6e497f05 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -244,13 +244,13 @@ snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev, static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) { if (sof_ops(sdev)->dbg_dump) - return sof_ops(sdev)->dbg_dump(sdev, flags); + sof_ops(sdev)->dbg_dump(sdev, flags); } static inline void snd_sof_ipc_dump(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->ipc_dump) - return sof_ops(sdev)->ipc_dump(sdev); + sof_ops(sdev)->ipc_dump(sdev); } /* register IO */ @@ -546,14 +546,16 @@ static inline const struct snd_sof_dsp_ops (val) = snd_sof_dsp_read(sdev, bar, offset); \ if (cond) { \ dev_dbg(sdev->dev, \ - "FW Poll Status: reg=%#x successful\n", (val)); \ + "FW Poll Status: reg[%#x]=%#x successful\n", \ + (offset), (val)); \ break; \ } \ if (__timeout_us && \ ktime_compare(ktime_get(), __timeout) > 0) { \ (val) = snd_sof_dsp_read(sdev, bar, offset); \ dev_dbg(sdev->dev, \ - "FW Poll Status: reg=%#x timedout\n", (val)); \ + "FW Poll Status: reg[%#x]=%#x timedout\n", \ + (offset), (val)); \ break; \ } \ if (__sleep_us) \ diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 7fbf09f9f17e..74982c04497b 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -60,7 +60,6 @@ int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc { struct device *dev = &pdev->dev; struct snd_sof_pdata *sof_pdata; - const struct snd_sof_dsp_ops *ops; dev_dbg(dev, "ACPI DSP detected"); @@ -68,9 +67,7 @@ int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc if (!sof_pdata) return -ENOMEM; - /* get ops for platform */ - ops = desc->ops; - if (!ops) { + if (!desc->ops) { dev_err(dev, "error: no matching ACPI descriptor ops\n"); return -ENODEV; } diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index c9c70645b377..d1a21edfa05d 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -70,7 +70,6 @@ static int sof_of_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct sof_dev_desc *desc; struct snd_sof_pdata *sof_pdata; - const struct snd_sof_dsp_ops *ops; dev_info(&pdev->dev, "DT DSP detected"); @@ -82,9 +81,7 @@ static int sof_of_probe(struct platform_device *pdev) if (!desc) return -ENODEV; - /* get ops for platform */ - ops = desc->ops; - if (!ops) { + if (!desc->ops) { dev_err(dev, "error: no matching DT descriptor ops\n"); return -ENODEV; } diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 3489dc1b48f6..03119462f9e2 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -116,14 +116,11 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) const struct sof_dev_desc *desc = (const struct sof_dev_desc *)pci_id->driver_data; struct snd_sof_pdata *sof_pdata; - const struct snd_sof_dsp_ops *ops; int ret; dev_dbg(&pci->dev, "PCI DSP detected"); - /* get ops for platform */ - ops = desc->ops; - if (!ops) { + if (!desc->ops) { dev_err(dev, "error: no matching PCI descriptor ops\n"); return -ENODEV; } @@ -141,7 +138,7 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return ret; sof_pdata->name = pci_name(pci); - sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; + sof_pdata->desc = desc; sof_pdata->dev = dev; sof_pdata->fw_filename = desc->default_fw_filename; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 59abcfc9bd55..cc9585bfa4e9 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1063,6 +1063,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, scontrol->min_volume_step = le32_to_cpu(mc->min); scontrol->max_volume_step = le32_to_cpu(mc->max); scontrol->num_channels = le32_to_cpu(mc->num_channels); + scontrol->control_data->index = kc->index; /* set cmd for mixer control */ if (le32_to_cpu(mc->max) == 1) { @@ -1140,7 +1141,7 @@ static int sof_control_load_enum(struct snd_soc_component *scomp, scontrol->comp_id = sdev->next_comp_id; scontrol->num_channels = le32_to_cpu(ec->num_channels); - + scontrol->control_data->index = kc->index; scontrol->cmd = SOF_CTRL_CMD_ENUM; dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", @@ -1188,6 +1189,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, scontrol->comp_id = sdev->next_comp_id; scontrol->cmd = SOF_CTRL_CMD_BINARY; + scontrol->control_data->index = kc->index; dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); @@ -2133,7 +2135,7 @@ static int sof_get_control_data(struct snd_soc_component *scomp, for (i = 0; i < widget->num_kcontrols; i++) { kc = &widget->kcontrol_news[i]; - switch (widget->dobj.widget.kcontrol_type) { + switch (widget->dobj.widget.kcontrol_type[i]) { case SND_SOC_TPLG_TYPE_MIXER: sm = (struct soc_mixer_control *)kc->private_value; wdata[i].control = sm->dobj.private; @@ -2147,8 +2149,8 @@ static int sof_get_control_data(struct snd_soc_component *scomp, wdata[i].control = se->dobj.private; break; default: - dev_err(scomp->dev, "error: unknown kcontrol type %d in widget %s\n", - widget->dobj.widget.kcontrol_type, + dev_err(scomp->dev, "error: unknown kcontrol type %u in widget %s\n", + widget->dobj.widget.kcontrol_type[i], widget->name); return -EINVAL; } @@ -2164,7 +2166,8 @@ static int sof_get_control_data(struct snd_soc_component *scomp, return -EINVAL; /* make sure data is valid - data can be updated at runtime */ - if (wdata[i].pdata->magic != SOF_ABI_MAGIC) + if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES && + wdata[i].pdata->magic != SOF_ABI_MAGIC) return -EINVAL; *size += wdata[i].pdata->size; @@ -2605,7 +2608,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp, } for (i = 0; i < widget->num_kcontrols; i++) { kc = &widget->kcontrol_news[i]; - switch (dobj->widget.kcontrol_type) { + switch (widget->dobj.widget.kcontrol_type[i]) { case SND_SOC_TPLG_TYPE_MIXER: sm = (struct soc_mixer_control *)kc->private_value; scontrol = sm->dobj.private; @@ -3335,7 +3338,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, /* Copy common data to all config ipc structs */ for (i = 0; i < num_conf; i++) { config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; - config[i].format = hw_config[i].fmt; + config[i].format = le32_to_cpu(hw_config[i].fmt); config[i].type = common_config.type; config[i].dai_index = common_config.dai_index; } diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index 38f9fff5be6b..549295a6ed50 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c @@ -287,8 +287,7 @@ static int spdif_out_probe(struct platform_device *pdev) if (!host) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->io_base = devm_ioremap_resource(&pdev->dev, res); + host->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(host->io_base)) return PTR_ERR(host->io_base); diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c index 34b2ce733b54..f6a55fa60c1b 100644 --- a/sound/soc/sprd/sprd-mcdt.c +++ b/sound/soc/sprd/sprd-mcdt.c @@ -949,8 +949,7 @@ static int sprd_mcdt_probe(struct platform_device *pdev) if (!mcdt) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mcdt->base = devm_ioremap_resource(&pdev->dev, res); + mcdt->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(mcdt->base)) return PTR_ERR(mcdt->base); diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index e3561f00ed40..34668fe3909d 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -410,16 +410,8 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, *dai = sti_uniperiph_dai_template; dai->name = dev_data->dai_names; - /* Get resources */ - uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); - - if (!uni->mem_region) { - dev_err(dev, "Failed to get memory resource\n"); - return -ENODEV; - } - - uni->base = devm_ioremap_resource(dev, uni->mem_region); - + /* Get resources and base address */ + uni->base = devm_platform_get_and_ioremap_resource(priv->pdev, 0, &uni->mem_region); if (IS_ERR(uni->base)) return PTR_ERR(uni->base); diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 7d1672cf78cc..6254bacad6eb 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -1036,8 +1036,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, else return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2s->base = devm_ioremap_resource(&pdev->dev, res); + i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2s->base)) return PTR_ERR(i2s->base); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 3aa1cf262402..9c3b8e209656 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1361,8 +1361,7 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, if (!np) return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 1bfa3b2ba974..48145f553588 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -922,8 +922,7 @@ static int stm32_spdifrx_parse_of(struct platform_device *pdev, else return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - spdifrx->base = devm_ioremap_resource(&pdev->dev, res); + spdifrx->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(spdifrx->base)) return PTR_ERR(spdifrx->base); diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 6f3d9148a185..da597e456beb 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1709,8 +1709,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) scodec->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index c57feae3396e..1e9116cd365e 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1470,8 +1470,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, i2s); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index 228485fe0734..a10949bf0ca1 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -518,8 +518,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev) host->cpu_dai_drv.name = dev_name(&pdev->dev); /* Get the addresses */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index a4e6760944d0..83c87f35a7d3 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -117,9 +117,13 @@ config SND_SOC_TEGRA_AUDIO_GRAPH_CARD few things for Tegra audio. Most of the code is re-used from audio graph driver and the same DT bindings are used. +config SND_SOC_TEGRA_MACHINE_DRV + tristate + config SND_SOC_TEGRA_RT5640 tristate "SoC Audio support for Tegra boards using an RT5640 codec" depends on I2C && GPIOLIB + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_RT5640 help Say Y or M here if you want to add support for SoC audio on Tegra @@ -128,6 +132,7 @@ config SND_SOC_TEGRA_RT5640 config SND_SOC_TEGRA_WM8753 tristate "SoC Audio support for Tegra boards using a WM8753 codec" depends on I2C && GPIOLIB + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_WM8753 help Say Y or M here if you want to add support for SoC audio on Tegra @@ -136,6 +141,7 @@ config SND_SOC_TEGRA_WM8753 config SND_SOC_TEGRA_WM8903 tristate "SoC Audio support for Tegra boards using a WM8903 codec" depends on I2C && GPIOLIB + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_WM8903 help Say Y or M here if you want to add support for SoC audio on Tegra @@ -145,6 +151,7 @@ config SND_SOC_TEGRA_WM8903 config SND_SOC_TEGRA_WM9712 tristate "SoC Audio support for Tegra boards using a WM9712 codec" depends on GPIOLIB + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_TEGRA20_AC97 select SND_SOC_WM9712 help @@ -154,6 +161,7 @@ config SND_SOC_TEGRA_WM9712 config SND_SOC_TEGRA_TRIMSLICE tristate "SoC Audio support for TrimSlice board" depends on I2C + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_TLV320AIC23_I2C help Say Y or M here if you want to add support for SoC audio on the @@ -162,6 +170,7 @@ config SND_SOC_TEGRA_TRIMSLICE config SND_SOC_TEGRA_ALC5632 tristate "SoC Audio support for Tegra boards using an ALC5632 codec" depends on I2C && GPIOLIB + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_ALC5632 help Say Y or M here if you want to add support for SoC audio on the @@ -170,6 +179,7 @@ config SND_SOC_TEGRA_ALC5632 config SND_SOC_TEGRA_MAX98090 tristate "SoC Audio support for Tegra boards using a MAX98090 codec" depends on I2C && GPIOLIB + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_MAX98090 help Say Y or M here if you want to add support for SoC audio on Tegra @@ -178,6 +188,7 @@ config SND_SOC_TEGRA_MAX98090 config SND_SOC_TEGRA_RT5677 tristate "SoC Audio support for Tegra boards using a RT5677 codec" depends on I2C && GPIOLIB + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_RT5677 help Say Y or M here if you want to add support for SoC audio on Tegra @@ -186,6 +197,7 @@ config SND_SOC_TEGRA_RT5677 config SND_SOC_TEGRA_SGTL5000 tristate "SoC Audio support for Tegra boards using a SGTL5000 codec" depends on I2C && GPIOLIB + select SND_SOC_TEGRA_MACHINE_DRV select SND_SOC_SGTL5000 help Say Y or M here if you want to add support for SoC audio on Tegra diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index b17dd6eef92a..e2cec9ae31c9 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -15,7 +15,6 @@ snd-soc-tegra186-dspk-objs := tegra186_dspk.o snd-soc-tegra210-admaif-objs := tegra210_admaif.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o -obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o @@ -29,24 +28,10 @@ obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o # Tegra machine Support -snd-soc-tegra-rt5640-objs := tegra_rt5640.o -snd-soc-tegra-rt5677-objs := tegra_rt5677.o -snd-soc-tegra-wm8753-objs := tegra_wm8753.o snd-soc-tegra-wm8903-objs := tegra_wm8903.o -snd-soc-tegra-wm9712-objs := tegra_wm9712.o -snd-soc-tegra-trimslice-objs := trimslice.o -snd-soc-tegra-alc5632-objs := tegra_alc5632.o -snd-soc-tegra-max98090-objs := tegra_max98090.o -snd-soc-tegra-sgtl5000-objs := tegra_sgtl5000.o +snd-soc-tegra-machine-objs := tegra_asoc_machine.o snd-soc-tegra-audio-graph-card-objs := tegra_audio_graph_card.o -obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o -obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o -obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o -obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o -obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o -obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o -obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o -obj-$(CONFIG_SND_SOC_TEGRA_SGTL5000) += snd-soc-tegra-sgtl5000.o +obj-$(CONFIG_SND_SOC_TEGRA_MACHINE_DRV) += snd-soc-tegra-machine.o obj-$(CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD) += snd-soc-tegra-audio-graph-card.o diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index b280ebd72591..266d2cab9f49 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -377,8 +377,7 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) goto err; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err; diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index de698ff2a69c..7751575cd6d6 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -269,8 +269,7 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) return ret; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index 1268046b345d..0f9beef429a2 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -706,9 +706,7 @@ static int tegra_admaif_probe(struct platform_device *pdev) return -ENOMEM; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 4692c70ed933..b3e1df693381 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -550,8 +550,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) goto err_unset_ahub; } - res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs_apbif = devm_ioremap_resource(&pdev->dev, res0); + regs_apbif = devm_platform_get_and_ioremap_resource(pdev, 0, &res0); if (IS_ERR(regs_apbif)) { ret = PTR_ERR(regs_apbif); goto err_unset_ahub; diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c deleted file mode 100644 index 0a0efd24e4b0..000000000000 --- a/sound/soc/tegra/tegra_alc5632.c +++ /dev/null @@ -1,259 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* -* tegra_alc5632.c -- Toshiba AC100(PAZ00) machine ASoC driver - * - * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net> - * Copyright (C) 2012 - NVIDIA, Inc. - * - * Authors: Leon Romanovsky <leon@leon.nu> - * Andrey Danin <danindrey@mail.ru> - * Marc Dietrich <marvin24@gmx.de> - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../codecs/alc5632.h" - -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-alc5632" - -struct tegra_alc5632 { - struct tegra_asoc_utils_data util_data; - int gpio_hp_det; -}; - -static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_card *card = rtd->card; - struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card); - int srate, mclk; - int err; - - srate = params_rate(params); - mclk = 512 * srate; - - err = tegra_asoc_utils_set_rate(&alc5632->util_data, srate, mclk); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - - return 0; -} - -static const struct snd_soc_ops tegra_alc5632_asoc_ops = { - .hw_params = tegra_alc5632_asoc_hw_params, -}; - -static struct snd_soc_jack tegra_alc5632_hs_jack; - -static struct snd_soc_jack_pin tegra_alc5632_hs_jack_pins[] = { - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headset Stereophone", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static struct snd_soc_jack_gpio tegra_alc5632_hp_jack_gpio = { - .name = "Headset detection", - .report = SND_JACK_HEADSET, - .debounce_time = 150, -}; - -static const struct snd_soc_dapm_widget tegra_alc5632_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Int Spk", NULL), - SND_SOC_DAPM_HP("Headset Stereophone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Digital Mic", NULL), -}; - -static const struct snd_kcontrol_new tegra_alc5632_controls[] = { - SOC_DAPM_PIN_SWITCH("Int Spk"), -}; - -static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card); - - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET, - &tegra_alc5632_hs_jack, - tegra_alc5632_hs_jack_pins, - ARRAY_SIZE(tegra_alc5632_hs_jack_pins)); - if (ret) - return ret; - - if (gpio_is_valid(machine->gpio_hp_det)) { - tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; - snd_soc_jack_add_gpios(&tegra_alc5632_hs_jack, - 1, - &tegra_alc5632_hp_jack_gpio); - } - - snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "MICBIAS1"); - - return 0; -} - -SND_SOC_DAILINK_DEFS(pcm, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "alc5632-hifi")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link tegra_alc5632_dai = { - .name = "ALC5632", - .stream_name = "ALC5632 PCM", - .init = tegra_alc5632_asoc_init, - .ops = &tegra_alc5632_asoc_ops, - .dai_fmt = SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(pcm), -}; - -static struct snd_soc_card snd_soc_tegra_alc5632 = { - .name = "tegra-alc5632", - .owner = THIS_MODULE, - .dai_link = &tegra_alc5632_dai, - .num_links = 1, - .controls = tegra_alc5632_controls, - .num_controls = ARRAY_SIZE(tegra_alc5632_controls), - .dapm_widgets = tegra_alc5632_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_alc5632_dapm_widgets), - .fully_routed = true, -}; - -static int tegra_alc5632_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_alc5632; - struct tegra_alc5632 *alc5632; - int ret; - - alc5632 = devm_kzalloc(&pdev->dev, - sizeof(struct tegra_alc5632), GFP_KERNEL); - if (!alc5632) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, alc5632); - - alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (alc5632->gpio_hp_det == -EPROBE_DEFER) - return -EPROBE_DEFER; - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - goto err; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - goto err; - - tegra_alc5632_dai.codecs->of_node = of_parse_phandle( - pdev->dev.of_node, "nvidia,audio-codec", 0); - - if (!tegra_alc5632_dai.codecs->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - ret = -EINVAL; - goto err; - } - - tegra_alc5632_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_alc5632_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - ret = -EINVAL; - goto err_put_codec_of_node; - } - - tegra_alc5632_dai.platforms->of_node = tegra_alc5632_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev); - if (ret) - goto err_put_cpu_of_node; - - ret = snd_soc_register_card(card); - if (ret) { - dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); - goto err_put_cpu_of_node; - } - - return 0; - -err_put_cpu_of_node: - of_node_put(tegra_alc5632_dai.cpus->of_node); - tegra_alc5632_dai.cpus->of_node = NULL; - tegra_alc5632_dai.platforms->of_node = NULL; -err_put_codec_of_node: - of_node_put(tegra_alc5632_dai.codecs->of_node); - tegra_alc5632_dai.codecs->of_node = NULL; -err: - return ret; -} - -static int tegra_alc5632_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - of_node_put(tegra_alc5632_dai.cpus->of_node); - tegra_alc5632_dai.cpus->of_node = NULL; - tegra_alc5632_dai.platforms->of_node = NULL; - of_node_put(tegra_alc5632_dai.codecs->of_node); - tegra_alc5632_dai.codecs->of_node = NULL; - - return 0; -} - -static const struct of_device_id tegra_alc5632_of_match[] = { - { .compatible = "nvidia,tegra-audio-alc5632", }, - {}, -}; - -static struct platform_driver tegra_alc5632_driver = { - .driver = { - .name = DRV_NAME, - .pm = &snd_soc_pm_ops, - .of_match_table = tegra_alc5632_of_match, - }, - .probe = tegra_alc5632_probe, - .remove = tegra_alc5632_remove, -}; -module_platform_driver(tegra_alc5632_driver); - -MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>"); -MODULE_DESCRIPTION("Tegra+ALC5632 machine ASoC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_alc5632_of_match); diff --git a/sound/soc/tegra/tegra_asoc_machine.c b/sound/soc/tegra/tegra_asoc_machine.c new file mode 100644 index 000000000000..735909310a26 --- /dev/null +++ b/sound/soc/tegra/tegra_asoc_machine.c @@ -0,0 +1,854 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * tegra_asoc_machine.c - Universal ASoC machine driver for NVIDIA Tegra boards. + */ + +#include <linux/clk.h> +#include <linux/export.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra_asoc_machine.h" + +/* Headphones Jack */ + +static struct snd_soc_jack tegra_machine_hp_jack; + +static struct snd_soc_jack_pin tegra_machine_hp_jack_pins[] = { + { .pin = "Headphone", .mask = SND_JACK_HEADPHONE }, + { .pin = "Headphones", .mask = SND_JACK_HEADPHONE }, +}; + +static struct snd_soc_jack_gpio tegra_machine_hp_jack_gpio = { + .name = "Headphones detection", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, +}; + +/* Headset Jack */ + +static struct snd_soc_jack tegra_machine_headset_jack; + +static struct snd_soc_jack_pin tegra_machine_headset_jack_pins[] = { + { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE }, + { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE }, +}; + +static struct snd_soc_jack_gpio tegra_machine_headset_jack_gpio = { + .name = "Headset detection", + .report = SND_JACK_HEADSET, + .debounce_time = 150, +}; + +/* Mic Jack */ + +static struct snd_soc_jack tegra_machine_mic_jack; + +static struct snd_soc_jack_pin tegra_machine_mic_jack_pins[] = { + { .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE }, + { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE }, +}; + +static struct snd_soc_jack_gpio tegra_machine_mic_jack_gpio = { + .name = "Mic detection", + .report = SND_JACK_MICROPHONE, + .debounce_time = 150, +}; + +static int tegra_machine_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct tegra_machine *machine = snd_soc_card_get_drvdata(dapm->card); + + if (!strcmp(w->name, "Int Spk") || !strcmp(w->name, "Speakers")) + gpiod_set_value_cansleep(machine->gpiod_spkr_en, + SND_SOC_DAPM_EVENT_ON(event)); + + if (!strcmp(w->name, "Mic Jack")) + gpiod_set_value_cansleep(machine->gpiod_ext_mic_en, + SND_SOC_DAPM_EVENT_ON(event)); + + if (!strcmp(w->name, "Int Mic")) + gpiod_set_value_cansleep(machine->gpiod_int_mic_en, + SND_SOC_DAPM_EVENT_ON(event)); + + if (!strcmp(w->name, "Headphone") || !strcmp(w->name, "Headphone Jack")) + gpiod_set_value_cansleep(machine->gpiod_hp_mute, + !SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", tegra_machine_event), + SND_SOC_DAPM_HP("Headphone", tegra_machine_event), + SND_SOC_DAPM_HP("Headset Stereophone", NULL), + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_SPK("Speakers", tegra_machine_event), + SND_SOC_DAPM_SPK("Int Spk", tegra_machine_event), + SND_SOC_DAPM_MIC("Int Mic", tegra_machine_event), + SND_SOC_DAPM_MIC("Mic Jack", tegra_machine_event), + SND_SOC_DAPM_MIC("Internal Mic 1", NULL), + SND_SOC_DAPM_MIC("Internal Mic 2", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Digital Mic", NULL), + SND_SOC_DAPM_MIC("Mic", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), + SND_SOC_DAPM_LINE("LineIn", NULL), +}; + +static const struct snd_kcontrol_new tegra_machine_controls[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Int Spk"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic 1"), + SOC_DAPM_PIN_SWITCH("Internal Mic 2"), +}; + +int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct tegra_machine *machine = snd_soc_card_get_drvdata(card); + int err; + + if (machine->gpiod_hp_det && machine->asoc->add_hp_jack) { + err = snd_soc_card_jack_new(card, "Headphones Jack", + SND_JACK_HEADPHONE, + &tegra_machine_hp_jack, + tegra_machine_hp_jack_pins, + ARRAY_SIZE(tegra_machine_hp_jack_pins)); + if (err) { + dev_err(rtd->dev, + "Headphones Jack creation failed: %d\n", err); + return err; + } + + tegra_machine_hp_jack_gpio.desc = machine->gpiod_hp_det; + + err = snd_soc_jack_add_gpios(&tegra_machine_hp_jack, 1, + &tegra_machine_hp_jack_gpio); + if (err) + dev_err(rtd->dev, "HP GPIOs not added: %d\n", err); + } + + if (machine->gpiod_hp_det && machine->asoc->add_headset_jack) { + err = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET, + &tegra_machine_headset_jack, + tegra_machine_headset_jack_pins, + ARRAY_SIZE(tegra_machine_headset_jack_pins)); + if (err) { + dev_err(rtd->dev, + "Headset Jack creation failed: %d\n", err); + return err; + } + + tegra_machine_headset_jack_gpio.desc = machine->gpiod_hp_det; + + err = snd_soc_jack_add_gpios(&tegra_machine_headset_jack, 1, + &tegra_machine_headset_jack_gpio); + if (err) + dev_err(rtd->dev, "Headset GPIOs not added: %d\n", err); + } + + if (machine->gpiod_mic_det && machine->asoc->add_mic_jack) { + err = snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, + &tegra_machine_mic_jack, + tegra_machine_mic_jack_pins, + ARRAY_SIZE(tegra_machine_mic_jack_pins)); + if (err) { + dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err); + return err; + } + + tegra_machine_mic_jack_gpio.desc = machine->gpiod_mic_det; + + err = snd_soc_jack_add_gpios(&tegra_machine_mic_jack, 1, + &tegra_machine_mic_jack_gpio); + if (err) + dev_err(rtd->dev, "Mic GPIOs not added: %d\n", err); + } + + return 0; +} +EXPORT_SYMBOL_GPL(tegra_asoc_machine_init); + +static unsigned int tegra_machine_mclk_rate_128(unsigned int srate) +{ + return 128 * srate; +} + +static unsigned int tegra_machine_mclk_rate_256(unsigned int srate) +{ + return 256 * srate; +} + +static unsigned int tegra_machine_mclk_rate_512(unsigned int srate) +{ + return 512 * srate; +} + +static unsigned int tegra_machine_mclk_rate_12mhz(unsigned int srate) +{ + unsigned int mclk; + + switch (srate) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + case 64000: + case 96000: + mclk = 12288000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + default: + mclk = 12000000; + break; + } + + return mclk; +} + +static int tegra_machine_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_card *card = rtd->card; + struct tegra_machine *machine = snd_soc_card_get_drvdata(card); + unsigned int srate = params_rate(params); + unsigned int mclk = machine->asoc->mclk_rate(srate); + unsigned int clk_id = machine->asoc->mclk_id; + unsigned int new_baseclock; + int err; + + switch (srate) { + case 11025: + case 22050: + case 44100: + case 88200: + if (of_machine_is_compatible("nvidia,tegra20")) + new_baseclock = 56448000; + else if (of_machine_is_compatible("nvidia,tegra30")) + new_baseclock = 564480000; + else + new_baseclock = 282240000; + break; + case 8000: + case 16000: + case 32000: + case 48000: + case 64000: + case 96000: + if (of_machine_is_compatible("nvidia,tegra20")) + new_baseclock = 73728000; + else if (of_machine_is_compatible("nvidia,tegra30")) + new_baseclock = 552960000; + else + new_baseclock = 368640000; + break; + default: + dev_err(card->dev, "Invalid sound rate: %u\n", srate); + return -EINVAL; + } + + if (new_baseclock != machine->set_baseclock || + mclk != machine->set_mclk) { + machine->set_baseclock = 0; + machine->set_mclk = 0; + + clk_disable_unprepare(machine->clk_cdev1); + + err = clk_set_rate(machine->clk_pll_a, new_baseclock); + if (err) { + dev_err(card->dev, "Can't set pll_a rate: %d\n", err); + return err; + } + + err = clk_set_rate(machine->clk_pll_a_out0, mclk); + if (err) { + dev_err(card->dev, "Can't set pll_a_out0 rate: %d\n", err); + return err; + } + + /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */ + + err = clk_prepare_enable(machine->clk_cdev1); + if (err) { + dev_err(card->dev, "Can't enable cdev1: %d\n", err); + return err; + } + + machine->set_baseclock = new_baseclock; + machine->set_mclk = mclk; + } + + err = snd_soc_dai_set_sysclk(codec_dai, clk_id, mclk, SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set: %d\n", err); + return err; + } + + return 0; +} + +static struct snd_soc_ops tegra_machine_snd_ops = { + .hw_params = tegra_machine_hw_params, +}; + +static void tegra_machine_node_release(void *of_node) +{ + of_node_put(of_node); +} + +static struct device_node * +tegra_machine_parse_phandle(struct device *dev, const char *name) +{ + struct device_node *np; + int err; + + np = of_parse_phandle(dev->of_node, name, 0); + if (!np) { + dev_err(dev, "Property '%s' missing or invalid\n", name); + return ERR_PTR(-EINVAL); + } + + err = devm_add_action_or_reset(dev, tegra_machine_node_release, np); + if (err) + return ERR_PTR(err); + + return np; +} + +int tegra_asoc_machine_probe(struct platform_device *pdev) +{ + struct device_node *np_codec, *np_i2s; + const struct tegra_asoc_data *asoc; + struct device *dev = &pdev->dev; + struct tegra_machine *machine; + struct snd_soc_card *card; + struct gpio_desc *gpiod; + int err; + + machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL); + if (!machine) + return -ENOMEM; + + asoc = of_device_get_match_data(dev); + card = asoc->card; + card->dev = dev; + + machine->asoc = asoc; + machine->mic_jack = &tegra_machine_mic_jack; + machine->hp_jack_gpio = &tegra_machine_hp_jack_gpio; + snd_soc_card_set_drvdata(card, machine); + + gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-mute", GPIOD_OUT_HIGH); + machine->gpiod_hp_mute = gpiod; + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-det", GPIOD_IN); + machine->gpiod_hp_det = gpiod; + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + gpiod = devm_gpiod_get_optional(dev, "nvidia,mic-det", GPIOD_IN); + machine->gpiod_mic_det = gpiod; + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + gpiod = devm_gpiod_get_optional(dev, "nvidia,spkr-en", GPIOD_OUT_LOW); + machine->gpiod_spkr_en = gpiod; + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + gpiod = devm_gpiod_get_optional(dev, "nvidia,int-mic-en", GPIOD_OUT_LOW); + machine->gpiod_int_mic_en = gpiod; + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + gpiod = devm_gpiod_get_optional(dev, "nvidia,ext-mic-en", GPIOD_OUT_LOW); + machine->gpiod_ext_mic_en = gpiod; + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + err = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (err) + return err; + + if (!card->dapm_routes) { + err = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); + if (err) + return err; + } + + np_codec = tegra_machine_parse_phandle(dev, "nvidia,audio-codec"); + if (IS_ERR(np_codec)) + return PTR_ERR(np_codec); + + np_i2s = tegra_machine_parse_phandle(dev, "nvidia,i2s-controller"); + if (IS_ERR(np_i2s)) + return PTR_ERR(np_i2s); + + card->dai_link->cpus->of_node = np_i2s; + card->dai_link->codecs->of_node = np_codec; + card->dai_link->platforms->of_node = np_i2s; + + if (asoc->add_common_controls) { + card->controls = tegra_machine_controls; + card->num_controls = ARRAY_SIZE(tegra_machine_controls); + } + + if (asoc->add_common_dapm_widgets) { + card->dapm_widgets = tegra_machine_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(tegra_machine_dapm_widgets); + } + + if (asoc->add_common_snd_ops) + card->dai_link->ops = &tegra_machine_snd_ops; + + if (!card->owner) + card->owner = THIS_MODULE; + if (!card->driver_name) + card->driver_name = "tegra"; + + machine->clk_pll_a = devm_clk_get(dev, "pll_a"); + if (IS_ERR(machine->clk_pll_a)) { + dev_err(dev, "Can't retrieve clk pll_a\n"); + return PTR_ERR(machine->clk_pll_a); + } + + machine->clk_pll_a_out0 = devm_clk_get(dev, "pll_a_out0"); + if (IS_ERR(machine->clk_pll_a_out0)) { + dev_err(dev, "Can't retrieve clk pll_a_out0\n"); + return PTR_ERR(machine->clk_pll_a_out0); + } + + machine->clk_cdev1 = devm_clk_get(dev, "mclk"); + if (IS_ERR(machine->clk_cdev1)) { + dev_err(dev, "Can't retrieve clk cdev1\n"); + return PTR_ERR(machine->clk_cdev1); + } + + /* + * If clock parents are not set in DT, configure here to use clk_out_1 + * as mclk and extern1 as parent for Tegra30 and higher. + */ + if (!of_find_property(dev->of_node, "assigned-clock-parents", NULL) && + !of_machine_is_compatible("nvidia,tegra20")) { + struct clk *clk_out_1, *clk_extern1; + + dev_warn(dev, "Configuring clocks for a legacy device-tree\n"); + dev_warn(dev, "Please update DT to use assigned-clock-parents\n"); + + clk_extern1 = devm_clk_get(dev, "extern1"); + if (IS_ERR(clk_extern1)) { + dev_err(dev, "Can't retrieve clk extern1\n"); + return PTR_ERR(clk_extern1); + } + + err = clk_set_parent(clk_extern1, machine->clk_pll_a_out0); + if (err < 0) { + dev_err(dev, "Set parent failed for clk extern1\n"); + return err; + } + + clk_out_1 = devm_clk_get(dev, "pmc_clk_out_1"); + if (IS_ERR(clk_out_1)) { + dev_err(dev, "Can't retrieve pmc_clk_out_1\n"); + return PTR_ERR(clk_out_1); + } + + err = clk_set_parent(clk_out_1, clk_extern1); + if (err < 0) { + dev_err(dev, "Set parent failed for pmc_clk_out_1\n"); + return err; + } + + machine->clk_cdev1 = clk_out_1; + } + + if (asoc->set_ac97) { + /* + * AC97 rate is fixed at 24.576MHz and is used for both the + * host controller and the external codec + */ + err = clk_set_rate(machine->clk_pll_a, 73728000); + if (err) { + dev_err(dev, "Can't set pll_a rate: %d\n", err); + return err; + } + + err = clk_set_rate(machine->clk_pll_a_out0, 24576000); + if (err) { + dev_err(dev, "Can't set pll_a_out0 rate: %d\n", err); + return err; + } + + machine->set_baseclock = 73728000; + machine->set_mclk = 24576000; + } + + /* + * FIXME: There is some unknown dependency between audio MCLK disable + * and suspend-resume functionality on Tegra30, although audio MCLK is + * only needed for audio. + */ + err = clk_prepare_enable(machine->clk_cdev1); + if (err) { + dev_err(dev, "Can't enable cdev1: %d\n", err); + return err; + } + + err = devm_snd_soc_register_card(dev, card); + if (err) + return err; + + return 0; +} +EXPORT_SYMBOL_GPL(tegra_asoc_machine_probe); + +/* WM8753 machine */ + +SND_SOC_DAILINK_DEFS(wm8753_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8753-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_wm8753_dai = { + .name = "WM8753", + .stream_name = "WM8753 PCM", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(wm8753_hifi), +}; + +static struct snd_soc_card snd_soc_tegra_wm8753 = { + .components = "codec:wm8753", + .dai_link = &tegra_wm8753_dai, + .num_links = 1, + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_wm8753_data = { + .mclk_rate = tegra_machine_mclk_rate_12mhz, + .card = &snd_soc_tegra_wm8753, + .add_common_dapm_widgets = true, + .add_common_snd_ops = true, +}; + +/* WM9712 machine */ + +static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd) +{ + return snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias"); +} + +SND_SOC_DAILINK_DEFS(wm9712_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_wm9712_dai = { + .name = "AC97 HiFi", + .stream_name = "AC97 HiFi", + .init = tegra_wm9712_init, + SND_SOC_DAILINK_REG(wm9712_hifi), +}; + +static struct snd_soc_card snd_soc_tegra_wm9712 = { + .components = "codec:wm9712", + .dai_link = &tegra_wm9712_dai, + .num_links = 1, + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_wm9712_data = { + .card = &snd_soc_tegra_wm9712, + .add_common_dapm_widgets = true, + .set_ac97 = true, +}; + +/* MAX98090 machine */ + +SND_SOC_DAILINK_DEFS(max98090_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_max98090_dai = { + .name = "max98090", + .stream_name = "max98090 PCM", + .init = tegra_asoc_machine_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(max98090_hifi), +}; + +static struct snd_soc_card snd_soc_tegra_max98090 = { + .components = "codec:max98090", + .dai_link = &tegra_max98090_dai, + .num_links = 1, + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_max98090_data = { + .mclk_rate = tegra_machine_mclk_rate_12mhz, + .card = &snd_soc_tegra_max98090, + .add_common_dapm_widgets = true, + .add_common_controls = true, + .add_common_snd_ops = true, + .add_mic_jack = true, + .add_hp_jack = true, +}; + +/* SGTL5000 machine */ + +SND_SOC_DAILINK_DEFS(sgtl5000_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sgtl5000")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_sgtl5000_dai = { + .name = "sgtl5000", + .stream_name = "HiFi", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(sgtl5000_hifi), +}; + +static struct snd_soc_card snd_soc_tegra_sgtl5000 = { + .components = "codec:sgtl5000", + .dai_link = &tegra_sgtl5000_dai, + .num_links = 1, + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_sgtl5000_data = { + .mclk_rate = tegra_machine_mclk_rate_12mhz, + .card = &snd_soc_tegra_sgtl5000, + .add_common_dapm_widgets = true, + .add_common_snd_ops = true, +}; + +/* TLV320AIC23 machine */ + +static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = { + SND_SOC_DAPM_HP("Line Out", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static const struct snd_soc_dapm_route trimslice_audio_map[] = { + {"Line Out", NULL, "LOUT"}, + {"Line Out", NULL, "ROUT"}, + + {"LLINEIN", NULL, "Line In"}, + {"RLINEIN", NULL, "Line In"}, +}; + +SND_SOC_DAILINK_DEFS(tlv320aic23_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic23-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_tlv320aic23_dai = { + .name = "TLV320AIC23", + .stream_name = "AIC23", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(tlv320aic23_hifi), +}; + +static struct snd_soc_card snd_soc_tegra_trimslice = { + .components = "codec:tlv320aic23", + .dai_link = &tegra_tlv320aic23_dai, + .num_links = 1, + .dapm_widgets = trimslice_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), + .dapm_routes = trimslice_audio_map, + .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_trimslice_data = { + .mclk_rate = tegra_machine_mclk_rate_128, + .card = &snd_soc_tegra_trimslice, + .add_common_snd_ops = true, +}; + +/* RT5677 machine */ + +static int tegra_rt5677_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int err; + + err = tegra_asoc_machine_init(rtd); + if (err) + return err; + + snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS1"); + + return 0; +} + +SND_SOC_DAILINK_DEFS(rt5677_aif1, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif1")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_rt5677_dai = { + .name = "RT5677", + .stream_name = "RT5677 PCM", + .init = tegra_rt5677_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(rt5677_aif1), +}; + +static struct snd_soc_card snd_soc_tegra_rt5677 = { + .components = "codec:rt5677", + .dai_link = &tegra_rt5677_dai, + .num_links = 1, + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_rt5677_data = { + .mclk_rate = tegra_machine_mclk_rate_256, + .card = &snd_soc_tegra_rt5677, + .add_common_dapm_widgets = true, + .add_common_controls = true, + .add_common_snd_ops = true, + .add_mic_jack = true, + .add_hp_jack = true, +}; + +/* RT5640 machine */ + +SND_SOC_DAILINK_DEFS(rt5640_aif1, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5640-aif1")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_rt5640_dai = { + .name = "RT5640", + .stream_name = "RT5640 PCM", + .init = tegra_asoc_machine_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(rt5640_aif1), +}; + +static struct snd_soc_card snd_soc_tegra_rt5640 = { + .components = "codec:rt5640", + .dai_link = &tegra_rt5640_dai, + .num_links = 1, + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_rt5640_data = { + .mclk_rate = tegra_machine_mclk_rate_256, + .card = &snd_soc_tegra_rt5640, + .add_common_dapm_widgets = true, + .add_common_controls = true, + .add_common_snd_ops = true, + .add_hp_jack = true, +}; + +/* RT5632 machine */ + +SND_SOC_DAILINK_DEFS(rt5632_hifi, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "alc5632-hifi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link tegra_rt5632_dai = { + .name = "ALC5632", + .stream_name = "ALC5632 PCM", + .init = tegra_rt5677_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAILINK_REG(rt5632_hifi), +}; + +static struct snd_soc_card snd_soc_tegra_rt5632 = { + .components = "codec:rt5632", + .dai_link = &tegra_rt5632_dai, + .num_links = 1, + .fully_routed = true, +}; + +static const struct tegra_asoc_data tegra_rt5632_data = { + .mclk_rate = tegra_machine_mclk_rate_512, + .card = &snd_soc_tegra_rt5632, + .add_common_dapm_widgets = true, + .add_common_controls = true, + .add_common_snd_ops = true, + .add_headset_jack = true, +}; + +static const struct of_device_id tegra_machine_of_match[] = { + { .compatible = "nvidia,tegra-audio-trimslice", .data = &tegra_trimslice_data }, + { .compatible = "nvidia,tegra-audio-max98090", .data = &tegra_max98090_data }, + { .compatible = "nvidia,tegra-audio-sgtl5000", .data = &tegra_sgtl5000_data }, + { .compatible = "nvidia,tegra-audio-wm9712", .data = &tegra_wm9712_data }, + { .compatible = "nvidia,tegra-audio-wm8753", .data = &tegra_wm8753_data }, + { .compatible = "nvidia,tegra-audio-rt5677", .data = &tegra_rt5677_data }, + { .compatible = "nvidia,tegra-audio-rt5640", .data = &tegra_rt5640_data }, + { .compatible = "nvidia,tegra-audio-alc5632", .data = &tegra_rt5632_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_machine_of_match); + +static struct platform_driver tegra_asoc_machine_driver = { + .driver = { + .name = "tegra-audio", + .of_match_table = tegra_machine_of_match, + .pm = &snd_soc_pm_ops, + }, + .probe = tegra_asoc_machine_probe, +}; +module_platform_driver(tegra_asoc_machine_driver); + +MODULE_AUTHOR("Anatol Pomozov <anatol@google.com>"); +MODULE_AUTHOR("Andrey Danin <danindrey@mail.ru>"); +MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>"); +MODULE_AUTHOR("Ion Agorria <ion@agorria.com>"); +MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>"); +MODULE_AUTHOR("Lucas Stach <dev@lynxeye.de>"); +MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>"); +MODULE_AUTHOR("Marcel Ziswiler <marcel@ziswiler.com>"); +MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); +MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); +MODULE_DESCRIPTION("Tegra machine ASoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra_asoc_machine.h b/sound/soc/tegra/tegra_asoc_machine.h new file mode 100644 index 000000000000..8ee0ec814f67 --- /dev/null +++ b/sound/soc/tegra/tegra_asoc_machine.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __TEGRA_ASOC_MACHINE_H__ +#define __TEGRA_ASOC_MACHINE_H__ + +struct clk; +struct gpio_desc; +struct snd_soc_card; +struct snd_soc_jack; +struct platform_device; +struct snd_soc_jack_gpio; +struct snd_soc_pcm_runtime; + +struct tegra_asoc_data { + unsigned int (*mclk_rate)(unsigned int srate); + struct snd_soc_card *card; + unsigned int mclk_id; + bool hp_jack_gpio_active_low; + bool add_common_dapm_widgets; + bool add_common_controls; + bool add_common_snd_ops; + bool add_headset_jack; + bool add_mic_jack; + bool add_hp_jack; + bool set_ac97; +}; + +struct tegra_machine { + struct clk *clk_pll_a_out0; + struct clk *clk_pll_a; + struct clk *clk_cdev1; + unsigned int set_baseclock; + unsigned int set_mclk; + const struct tegra_asoc_data *asoc; + struct gpio_desc *gpiod_ext_mic_en; + struct gpio_desc *gpiod_int_mic_en; + struct gpio_desc *gpiod_spkr_en; + struct gpio_desc *gpiod_mic_det; + struct gpio_desc *gpiod_ear_sel; + struct gpio_desc *gpiod_hp_mute; + struct gpio_desc *gpiod_hp_det; + struct snd_soc_jack *mic_jack; + struct snd_soc_jack_gpio *hp_jack_gpio; +}; + +int tegra_asoc_machine_probe(struct platform_device *pdev); +int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd); + +#endif diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c deleted file mode 100644 index 587f62a288d1..000000000000 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ /dev/null @@ -1,225 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * tegra_asoc_utils.c - Harmony machine ASoC driver - * - * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010,2012 - NVIDIA, Inc. - */ - -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> - -#include "tegra_asoc_utils.h" - -int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, - int mclk) -{ - int new_baseclock; - bool clk_change; - int err; - - switch (srate) { - case 11025: - case 22050: - case 44100: - case 88200: - if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) - new_baseclock = 56448000; - else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30) - new_baseclock = 564480000; - else - new_baseclock = 282240000; - break; - case 8000: - case 16000: - case 32000: - case 48000: - case 64000: - case 96000: - if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20) - new_baseclock = 73728000; - else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30) - new_baseclock = 552960000; - else - new_baseclock = 368640000; - break; - default: - return -EINVAL; - } - - clk_change = ((new_baseclock != data->set_baseclock) || - (mclk != data->set_mclk)); - if (!clk_change) - return 0; - - data->set_baseclock = 0; - data->set_mclk = 0; - - clk_disable_unprepare(data->clk_cdev1); - - err = clk_set_rate(data->clk_pll_a, new_baseclock); - if (err) { - dev_err(data->dev, "Can't set pll_a rate: %d\n", err); - return err; - } - - err = clk_set_rate(data->clk_pll_a_out0, mclk); - if (err) { - dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err); - return err; - } - - /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */ - - err = clk_prepare_enable(data->clk_cdev1); - if (err) { - dev_err(data->dev, "Can't enable cdev1: %d\n", err); - return err; - } - - data->set_baseclock = new_baseclock; - data->set_mclk = mclk; - - return 0; -} -EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_rate); - -int tegra_asoc_utils_set_ac97_rate(struct tegra_asoc_utils_data *data) -{ - const int pll_rate = 73728000; - const int ac97_rate = 24576000; - int err; - - clk_disable_unprepare(data->clk_cdev1); - - /* - * AC97 rate is fixed at 24.576MHz and is used for both the host - * controller and the external codec - */ - err = clk_set_rate(data->clk_pll_a, pll_rate); - if (err) { - dev_err(data->dev, "Can't set pll_a rate: %d\n", err); - return err; - } - - err = clk_set_rate(data->clk_pll_a_out0, ac97_rate); - if (err) { - dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err); - return err; - } - - /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */ - - err = clk_prepare_enable(data->clk_cdev1); - if (err) { - dev_err(data->dev, "Can't enable cdev1: %d\n", err); - return err; - } - - data->set_baseclock = pll_rate; - data->set_mclk = ac97_rate; - - return 0; -} -EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_ac97_rate); - -int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, - struct device *dev) -{ - struct clk *clk_out_1, *clk_extern1; - int ret; - - data->dev = dev; - - if (of_machine_is_compatible("nvidia,tegra20")) - data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20; - else if (of_machine_is_compatible("nvidia,tegra30")) - data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30; - else if (of_machine_is_compatible("nvidia,tegra114")) - data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114; - else if (of_machine_is_compatible("nvidia,tegra124")) - data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA124; - else { - dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n"); - return -EINVAL; - } - - data->clk_pll_a = devm_clk_get(dev, "pll_a"); - if (IS_ERR(data->clk_pll_a)) { - dev_err(data->dev, "Can't retrieve clk pll_a\n"); - return PTR_ERR(data->clk_pll_a); - } - - data->clk_pll_a_out0 = devm_clk_get(dev, "pll_a_out0"); - if (IS_ERR(data->clk_pll_a_out0)) { - dev_err(data->dev, "Can't retrieve clk pll_a_out0\n"); - return PTR_ERR(data->clk_pll_a_out0); - } - - data->clk_cdev1 = devm_clk_get(dev, "mclk"); - if (IS_ERR(data->clk_cdev1)) { - dev_err(data->dev, "Can't retrieve clk cdev1\n"); - return PTR_ERR(data->clk_cdev1); - } - - /* - * If clock parents are not set in DT, configure here to use clk_out_1 - * as mclk and extern1 as parent for Tegra30 and higher. - */ - if (!of_find_property(dev->of_node, "assigned-clock-parents", NULL) && - data->soc > TEGRA_ASOC_UTILS_SOC_TEGRA20) { - dev_warn(data->dev, - "Configuring clocks for a legacy device-tree\n"); - dev_warn(data->dev, - "Please update DT to use assigned-clock-parents\n"); - clk_extern1 = devm_clk_get(dev, "extern1"); - if (IS_ERR(clk_extern1)) { - dev_err(data->dev, "Can't retrieve clk extern1\n"); - return PTR_ERR(clk_extern1); - } - - ret = clk_set_parent(clk_extern1, data->clk_pll_a_out0); - if (ret < 0) { - dev_err(data->dev, - "Set parent failed for clk extern1\n"); - return ret; - } - - clk_out_1 = devm_clk_get(dev, "pmc_clk_out_1"); - if (IS_ERR(clk_out_1)) { - dev_err(data->dev, "Can't retrieve pmc_clk_out_1\n"); - return PTR_ERR(clk_out_1); - } - - ret = clk_set_parent(clk_out_1, clk_extern1); - if (ret < 0) { - dev_err(data->dev, - "Set parent failed for pmc_clk_out_1\n"); - return ret; - } - - data->clk_cdev1 = clk_out_1; - } - - /* - * FIXME: There is some unknown dependency between audio mclk disable - * and suspend-resume functionality on Tegra30, although audio mclk is - * only needed for audio. - */ - ret = clk_prepare_enable(data->clk_cdev1); - if (ret) { - dev_err(data->dev, "Can't enable cdev1: %d\n", ret); - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(tegra_asoc_utils_init); - -MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); -MODULE_DESCRIPTION("Tegra ASoC utility code"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h deleted file mode 100644 index a34439587d59..000000000000 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * tegra_asoc_utils.h - Definitions for Tegra DAS driver - * - * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010,2012 - NVIDIA, Inc. - */ - -#ifndef __TEGRA_ASOC_UTILS_H__ -#define __TEGRA_ASOC_UTILS_H__ - -struct clk; -struct device; - -enum tegra_asoc_utils_soc { - TEGRA_ASOC_UTILS_SOC_TEGRA20, - TEGRA_ASOC_UTILS_SOC_TEGRA30, - TEGRA_ASOC_UTILS_SOC_TEGRA114, - TEGRA_ASOC_UTILS_SOC_TEGRA124, -}; - -struct tegra_asoc_utils_data { - struct device *dev; - enum tegra_asoc_utils_soc soc; - struct clk *clk_pll_a; - struct clk *clk_pll_a_out0; - struct clk *clk_cdev1; - int set_baseclock; - int set_mclk; -}; - -int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, - int mclk); -int tegra_asoc_utils_set_ac97_rate(struct tegra_asoc_utils_data *data); -int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, - struct device *dev); - -#endif diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c deleted file mode 100644 index 00c19704057b..000000000000 --- a/sound/soc/tegra/tegra_max98090.c +++ /dev/null @@ -1,276 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Tegra machine ASoC driver for boards using a MAX90809 CODEC. - * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * Based on code copyright/by: - * - * Copyright (C) 2010-2012 - NVIDIA, Inc. - * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net> - * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. - * Copyright 2007 Wolfson Microelectronics PLC. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-snd-max98090" - -struct tegra_max98090 { - struct tegra_asoc_utils_data util_data; - int gpio_hp_det; - int gpio_mic_det; -}; - -static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_card *card = rtd->card; - struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk; - int err; - - srate = params_rate(params); - switch (srate) { - case 8000: - case 16000: - case 24000: - case 32000: - case 48000: - case 64000: - case 96000: - mclk = 12288000; - break; - case 11025: - case 22050: - case 44100: - case 88200: - mclk = 11289600; - break; - default: - mclk = 12000000; - break; - } - - err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - - return 0; -} - -static const struct snd_soc_ops tegra_max98090_ops = { - .hw_params = tegra_max98090_asoc_hw_params, -}; - -static struct snd_soc_jack tegra_max98090_hp_jack; - -static struct snd_soc_jack_pin tegra_max98090_hp_jack_pins[] = { - { - .pin = "Headphones", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = { - .name = "Headphone detection", - .report = SND_JACK_HEADPHONE, - .debounce_time = 150, - .invert = 1, -}; - -static struct snd_soc_jack tegra_max98090_mic_jack; - -static struct snd_soc_jack_pin tegra_max98090_mic_jack_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static struct snd_soc_jack_gpio tegra_max98090_mic_jack_gpio = { - .name = "Mic detection", - .report = SND_JACK_MICROPHONE, - .debounce_time = 150, - .invert = 1, -}; - -static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphones", NULL), - SND_SOC_DAPM_SPK("Speakers", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("Int Mic", NULL), -}; - -static const struct snd_kcontrol_new tegra_max98090_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphones"), - SOC_DAPM_PIN_SWITCH("Speakers"), - SOC_DAPM_PIN_SWITCH("Mic Jack"), - SOC_DAPM_PIN_SWITCH("Int Mic"), -}; - -static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) -{ - struct tegra_max98090 *machine = snd_soc_card_get_drvdata(rtd->card); - - if (gpio_is_valid(machine->gpio_hp_det)) { - snd_soc_card_jack_new(rtd->card, "Headphones", - SND_JACK_HEADPHONE, - &tegra_max98090_hp_jack, - tegra_max98090_hp_jack_pins, - ARRAY_SIZE(tegra_max98090_hp_jack_pins)); - - tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det; - snd_soc_jack_add_gpios(&tegra_max98090_hp_jack, - 1, - &tegra_max98090_hp_jack_gpio); - } - - if (gpio_is_valid(machine->gpio_mic_det)) { - snd_soc_card_jack_new(rtd->card, "Mic Jack", - SND_JACK_MICROPHONE, - &tegra_max98090_mic_jack, - tegra_max98090_mic_jack_pins, - ARRAY_SIZE(tegra_max98090_mic_jack_pins)); - - tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det; - snd_soc_jack_add_gpios(&tegra_max98090_mic_jack, - 1, - &tegra_max98090_mic_jack_gpio); - } - - return 0; -} - -SND_SOC_DAILINK_DEFS(pcm, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link tegra_max98090_dai = { - .name = "max98090", - .stream_name = "max98090 PCM", - .init = tegra_max98090_asoc_init, - .ops = &tegra_max98090_ops, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(pcm), -}; - -static struct snd_soc_card snd_soc_tegra_max98090 = { - .name = "tegra-max98090", - .owner = THIS_MODULE, - .dai_link = &tegra_max98090_dai, - .num_links = 1, - .controls = tegra_max98090_controls, - .num_controls = ARRAY_SIZE(tegra_max98090_controls), - .dapm_widgets = tegra_max98090_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_max98090_dapm_widgets), - .fully_routed = true, -}; - -static int tegra_max98090_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_max98090; - struct tegra_max98090 *machine; - int ret; - - machine = devm_kzalloc(&pdev->dev, - sizeof(struct tegra_max98090), GFP_KERNEL); - if (!machine) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, machine); - - machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (machine->gpio_hp_det == -EPROBE_DEFER) - return -EPROBE_DEFER; - - machine->gpio_mic_det = - of_get_named_gpio(np, "nvidia,mic-det-gpios", 0); - if (machine->gpio_mic_det == -EPROBE_DEFER) - return -EPROBE_DEFER; - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - return ret; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - return ret; - - tegra_max98090_dai.codecs->of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); - if (!tegra_max98090_dai.codecs->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - return -EINVAL; - } - - tegra_max98090_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_max98090_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - return -EINVAL; - } - - tegra_max98090_dai.platforms->of_node = tegra_max98090_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); - if (ret) - return ret; - - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - return dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); - - return 0; -} - -static const struct of_device_id tegra_max98090_of_match[] = { - { .compatible = "nvidia,tegra-audio-max98090", }, - {}, -}; - -static struct platform_driver tegra_max98090_driver = { - .driver = { - .name = DRV_NAME, - .pm = &snd_soc_pm_ops, - .of_match_table = tegra_max98090_of_match, - }, - .probe = tegra_max98090_probe, -}; -module_platform_driver(tegra_max98090_driver); - -MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); -MODULE_DESCRIPTION("Tegra max98090 machine ASoC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_max98090_of_match); diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c deleted file mode 100644 index 9afba37a3b08..000000000000 --- a/sound/soc/tegra/tegra_rt5640.c +++ /dev/null @@ -1,222 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* -* tegra_rt5640.c - Tegra machine ASoC driver for boards using RT5640 codec. - * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * Based on code copyright/by: - * - * Copyright (C) 2010-2012 - NVIDIA, Inc. - * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net> - * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. - * Copyright 2007 Wolfson Microelectronics PLC. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../codecs/rt5640.h" - -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-snd-rt5640" - -struct tegra_rt5640 { - struct tegra_asoc_utils_data util_data; - int gpio_hp_det; - enum of_gpio_flags gpio_hp_det_flags; -}; - -static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_card *card = rtd->card; - struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk; - int err; - - srate = params_rate(params); - mclk = 256 * srate; - - err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - - return 0; -} - -static const struct snd_soc_ops tegra_rt5640_ops = { - .hw_params = tegra_rt5640_asoc_hw_params, -}; - -static struct snd_soc_jack tegra_rt5640_hp_jack; - -static struct snd_soc_jack_pin tegra_rt5640_hp_jack_pins[] = { - { - .pin = "Headphones", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static struct snd_soc_jack_gpio tegra_rt5640_hp_jack_gpio = { - .name = "Headphone detection", - .report = SND_JACK_HEADPHONE, - .debounce_time = 150, - .invert = 1, -}; - -static const struct snd_soc_dapm_widget tegra_rt5640_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphones", NULL), - SND_SOC_DAPM_SPK("Speakers", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), -}; - -static const struct snd_kcontrol_new tegra_rt5640_controls[] = { - SOC_DAPM_PIN_SWITCH("Speakers"), -}; - -static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd) -{ - struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(rtd->card); - - snd_soc_card_jack_new(rtd->card, "Headphones", SND_JACK_HEADPHONE, - &tegra_rt5640_hp_jack, tegra_rt5640_hp_jack_pins, - ARRAY_SIZE(tegra_rt5640_hp_jack_pins)); - - if (gpio_is_valid(machine->gpio_hp_det)) { - tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det; - tegra_rt5640_hp_jack_gpio.invert = - !!(machine->gpio_hp_det_flags & OF_GPIO_ACTIVE_LOW); - snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack, - 1, - &tegra_rt5640_hp_jack_gpio); - } - - return 0; -} - -SND_SOC_DAILINK_DEFS(aif1, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5640-aif1")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link tegra_rt5640_dai = { - .name = "RT5640", - .stream_name = "RT5640 PCM", - .init = tegra_rt5640_asoc_init, - .ops = &tegra_rt5640_ops, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(aif1), -}; - -static struct snd_soc_card snd_soc_tegra_rt5640 = { - .name = "tegra-rt5640", - .owner = THIS_MODULE, - .dai_link = &tegra_rt5640_dai, - .num_links = 1, - .controls = tegra_rt5640_controls, - .num_controls = ARRAY_SIZE(tegra_rt5640_controls), - .dapm_widgets = tegra_rt5640_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_rt5640_dapm_widgets), - .fully_routed = true, -}; - -static int tegra_rt5640_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_rt5640; - struct tegra_rt5640 *machine; - int ret; - - machine = devm_kzalloc(&pdev->dev, - sizeof(struct tegra_rt5640), GFP_KERNEL); - if (!machine) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, machine); - - machine->gpio_hp_det = of_get_named_gpio_flags( - np, "nvidia,hp-det-gpios", 0, &machine->gpio_hp_det_flags); - if (machine->gpio_hp_det == -EPROBE_DEFER) - return -EPROBE_DEFER; - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - return ret; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - return ret; - - tegra_rt5640_dai.codecs->of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); - if (!tegra_rt5640_dai.codecs->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - return -EINVAL; - } - - tegra_rt5640_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_rt5640_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - return -EINVAL; - } - - tegra_rt5640_dai.platforms->of_node = tegra_rt5640_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); - if (ret) - return ret; - - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - return dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); - - return 0; -} - -static const struct of_device_id tegra_rt5640_of_match[] = { - { .compatible = "nvidia,tegra-audio-rt5640", }, - {}, -}; - -static struct platform_driver tegra_rt5640_driver = { - .driver = { - .name = DRV_NAME, - .pm = &snd_soc_pm_ops, - .of_match_table = tegra_rt5640_of_match, - }, - .probe = tegra_rt5640_probe, -}; -module_platform_driver(tegra_rt5640_driver); - -MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); -MODULE_DESCRIPTION("Tegra+RT5640 machine ASoC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_rt5640_of_match); diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c deleted file mode 100644 index d30f8b6deda4..000000000000 --- a/sound/soc/tegra/tegra_rt5677.c +++ /dev/null @@ -1,324 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* -* tegra_rt5677.c - Tegra machine ASoC driver for boards using RT5677 codec. - * - * Copyright (c) 2014, The Chromium OS Authors. All rights reserved. - * - * Based on code copyright/by: - * - * Copyright (C) 2010-2012 - NVIDIA, Inc. - * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net> - * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. - * Copyright 2007 Wolfson Microelectronics PLC. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../codecs/rt5677.h" - -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-snd-rt5677" - -struct tegra_rt5677 { - struct tegra_asoc_utils_data util_data; - int gpio_hp_det; - int gpio_hp_en; - int gpio_mic_present; - int gpio_dmic_clk_en; -}; - -static int tegra_rt5677_asoc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_card *card = rtd->card; - struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk, err; - - srate = params_rate(params); - mclk = 256 * srate; - - err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - - return 0; -} - -static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); - - if (!gpio_is_valid(machine->gpio_hp_en)) - return 0; - - gpio_set_value_cansleep(machine->gpio_hp_en, - SND_SOC_DAPM_EVENT_ON(event)); - - return 0; -} - -static const struct snd_soc_ops tegra_rt5677_ops = { - .hw_params = tegra_rt5677_asoc_hw_params, -}; - -static struct snd_soc_jack tegra_rt5677_hp_jack; - -static struct snd_soc_jack_pin tegra_rt5677_hp_jack_pins = { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, -}; -static struct snd_soc_jack_gpio tegra_rt5677_hp_jack_gpio = { - .name = "Headphone detection", - .report = SND_JACK_HEADPHONE, - .debounce_time = 150, -}; - -static struct snd_soc_jack tegra_rt5677_mic_jack; - -static struct snd_soc_jack_pin tegra_rt5677_mic_jack_pins = { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, -}; - -static struct snd_soc_jack_gpio tegra_rt5677_mic_jack_gpio = { - .name = "Headset Mic detection", - .report = SND_JACK_MICROPHONE, - .debounce_time = 150, - .invert = 1 -}; - -static const struct snd_soc_dapm_widget tegra_rt5677_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_HP("Headphone", tegra_rt5677_event_hp), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Internal Mic 1", NULL), - SND_SOC_DAPM_MIC("Internal Mic 2", NULL), -}; - -static const struct snd_kcontrol_new tegra_rt5677_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Internal Mic 1"), - SOC_DAPM_PIN_SWITCH("Internal Mic 2"), -}; - -static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd) -{ - struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card); - - snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, - &tegra_rt5677_hp_jack, - &tegra_rt5677_hp_jack_pins, 1); - - if (gpio_is_valid(machine->gpio_hp_det)) { - tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det; - snd_soc_jack_add_gpios(&tegra_rt5677_hp_jack, 1, - &tegra_rt5677_hp_jack_gpio); - } - - - snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, - &tegra_rt5677_mic_jack, - &tegra_rt5677_mic_jack_pins, 1); - - if (gpio_is_valid(machine->gpio_mic_present)) { - tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present; - snd_soc_jack_add_gpios(&tegra_rt5677_mic_jack, 1, - &tegra_rt5677_mic_jack_gpio); - } - - snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "MICBIAS1"); - - return 0; -} - -SND_SOC_DAILINK_DEFS(pcm, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif1")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link tegra_rt5677_dai = { - .name = "RT5677", - .stream_name = "RT5677 PCM", - .init = tegra_rt5677_asoc_init, - .ops = &tegra_rt5677_ops, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(pcm), -}; - -static struct snd_soc_card snd_soc_tegra_rt5677 = { - .name = "tegra-rt5677", - .owner = THIS_MODULE, - .dai_link = &tegra_rt5677_dai, - .num_links = 1, - .controls = tegra_rt5677_controls, - .num_controls = ARRAY_SIZE(tegra_rt5677_controls), - .dapm_widgets = tegra_rt5677_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_rt5677_dapm_widgets), - .fully_routed = true, -}; - -static int tegra_rt5677_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_rt5677; - struct tegra_rt5677 *machine; - int ret; - - machine = devm_kzalloc(&pdev->dev, - sizeof(struct tegra_rt5677), GFP_KERNEL); - if (!machine) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, machine); - - machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (machine->gpio_hp_det == -EPROBE_DEFER) - return -EPROBE_DEFER; - - machine->gpio_mic_present = of_get_named_gpio(np, - "nvidia,mic-present-gpios", 0); - if (machine->gpio_mic_present == -EPROBE_DEFER) - return -EPROBE_DEFER; - - machine->gpio_hp_en = of_get_named_gpio(np, "nvidia,hp-en-gpios", 0); - if (machine->gpio_hp_en == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(machine->gpio_hp_en)) { - ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_en, - GPIOF_OUT_INIT_LOW, "hp_en"); - if (ret) { - dev_err(card->dev, "cannot get hp_en gpio\n"); - return ret; - } - } - - machine->gpio_dmic_clk_en = of_get_named_gpio(np, - "nvidia,dmic-clk-en-gpios", 0); - if (machine->gpio_dmic_clk_en == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(machine->gpio_dmic_clk_en)) { - ret = devm_gpio_request_one(&pdev->dev, - machine->gpio_dmic_clk_en, - GPIOF_OUT_INIT_HIGH, "dmic_clk_en"); - if (ret) { - dev_err(card->dev, "cannot get dmic_clk_en gpio\n"); - return ret; - } - } - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - goto err; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - goto err; - - tegra_rt5677_dai.codecs->of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); - if (!tegra_rt5677_dai.codecs->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - ret = -EINVAL; - goto err; - } - - tegra_rt5677_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_rt5677_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - ret = -EINVAL; - goto err_put_codec_of_node; - } - tegra_rt5677_dai.platforms->of_node = tegra_rt5677_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); - if (ret) - goto err_put_cpu_of_node; - - ret = snd_soc_register_card(card); - if (ret) { - dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); - goto err_put_cpu_of_node; - } - - return 0; - -err_put_cpu_of_node: - of_node_put(tegra_rt5677_dai.cpus->of_node); - tegra_rt5677_dai.cpus->of_node = NULL; - tegra_rt5677_dai.platforms->of_node = NULL; -err_put_codec_of_node: - of_node_put(tegra_rt5677_dai.codecs->of_node); - tegra_rt5677_dai.codecs->of_node = NULL; -err: - return ret; -} - -static int tegra_rt5677_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - tegra_rt5677_dai.platforms->of_node = NULL; - of_node_put(tegra_rt5677_dai.codecs->of_node); - tegra_rt5677_dai.codecs->of_node = NULL; - of_node_put(tegra_rt5677_dai.cpus->of_node); - tegra_rt5677_dai.cpus->of_node = NULL; - - return 0; -} - -static const struct of_device_id tegra_rt5677_of_match[] = { - { .compatible = "nvidia,tegra-audio-rt5677", }, - {}, -}; - -static struct platform_driver tegra_rt5677_driver = { - .driver = { - .name = DRV_NAME, - .pm = &snd_soc_pm_ops, - .of_match_table = tegra_rt5677_of_match, - }, - .probe = tegra_rt5677_probe, - .remove = tegra_rt5677_remove, -}; -module_platform_driver(tegra_rt5677_driver); - -MODULE_AUTHOR("Anatol Pomozov <anatol@google.com>"); -MODULE_DESCRIPTION("Tegra+RT5677 machine ASoC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_rt5677_of_match); diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c deleted file mode 100644 index 885332170c77..000000000000 --- a/sound/soc/tegra/tegra_sgtl5000.c +++ /dev/null @@ -1,211 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * tegra_sgtl5000.c - Tegra machine ASoC driver for boards using SGTL5000 codec - * - * Author: Marcel Ziswiler <marcel@ziswiler.com> - * - * Based on code copyright/by: - * - * Copyright (C) 2010-2012 - NVIDIA, Inc. - * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. - * Copyright 2007 Wolfson Microelectronics PLC. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../codecs/sgtl5000.h" - -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-snd-sgtl5000" - -struct tegra_sgtl5000 { - struct tegra_asoc_utils_data util_data; -}; - -static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_card *card = rtd->card; - struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk; - int err; - - srate = params_rate(params); - switch (srate) { - case 11025: - case 22050: - case 44100: - case 88200: - mclk = 11289600; - break; - default: - mclk = 12288000; - break; - } - - err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - - return 0; -} - -static const struct snd_soc_ops tegra_sgtl5000_ops = { - .hw_params = tegra_sgtl5000_hw_params, -}; - -static const struct snd_soc_dapm_widget tegra_sgtl5000_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_LINE("Line In Jack", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), -}; - -SND_SOC_DAILINK_DEFS(hifi, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sgtl5000")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link tegra_sgtl5000_dai = { - .name = "sgtl5000", - .stream_name = "HiFi", - .ops = &tegra_sgtl5000_ops, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(hifi), -}; - -static struct snd_soc_card snd_soc_tegra_sgtl5000 = { - .name = "tegra-sgtl5000", - .owner = THIS_MODULE, - .dai_link = &tegra_sgtl5000_dai, - .num_links = 1, - .dapm_widgets = tegra_sgtl5000_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_sgtl5000_dapm_widgets), - .fully_routed = true, -}; - -static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_sgtl5000; - struct tegra_sgtl5000 *machine; - int ret; - - machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_sgtl5000), - GFP_KERNEL); - if (!machine) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, machine); - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - goto err; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - goto err; - - tegra_sgtl5000_dai.codecs->of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); - if (!tegra_sgtl5000_dai.codecs->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - ret = -EINVAL; - goto err; - } - - tegra_sgtl5000_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_sgtl5000_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing/invalid\n"); - ret = -EINVAL; - goto err_put_codec_of_node; - } - - tegra_sgtl5000_dai.platforms->of_node = tegra_sgtl5000_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); - if (ret) - goto err_put_cpu_of_node; - - ret = snd_soc_register_card(card); - if (ret) { - dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); - goto err_put_cpu_of_node; - } - - return 0; - -err_put_cpu_of_node: - of_node_put(tegra_sgtl5000_dai.cpus->of_node); - tegra_sgtl5000_dai.cpus->of_node = NULL; - tegra_sgtl5000_dai.platforms->of_node = NULL; -err_put_codec_of_node: - of_node_put(tegra_sgtl5000_dai.codecs->of_node); - tegra_sgtl5000_dai.codecs->of_node = NULL; -err: - return ret; -} - -static int tegra_sgtl5000_driver_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - int ret; - - ret = snd_soc_unregister_card(card); - - of_node_put(tegra_sgtl5000_dai.cpus->of_node); - tegra_sgtl5000_dai.cpus->of_node = NULL; - tegra_sgtl5000_dai.platforms->of_node = NULL; - of_node_put(tegra_sgtl5000_dai.codecs->of_node); - tegra_sgtl5000_dai.codecs->of_node = NULL; - - return ret; -} - -static const struct of_device_id tegra_sgtl5000_of_match[] = { - { .compatible = "nvidia,tegra-audio-sgtl5000", }, - { /* sentinel */ }, -}; - -static struct platform_driver tegra_sgtl5000_driver = { - .driver = { - .name = DRV_NAME, - .pm = &snd_soc_pm_ops, - .of_match_table = tegra_sgtl5000_of_match, - }, - .probe = tegra_sgtl5000_driver_probe, - .remove = tegra_sgtl5000_driver_remove, -}; -module_platform_driver(tegra_sgtl5000_driver); - -MODULE_AUTHOR("Marcel Ziswiler <marcel@ziswiler.com>"); -MODULE_DESCRIPTION("Tegra SGTL5000 machine ASoC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_sgtl5000_of_match); diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c deleted file mode 100644 index efd793886689..000000000000 --- a/sound/soc/tegra/tegra_wm8753.c +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * tegra_wm8753.c - Tegra machine ASoC driver for boards using WM8753 codec. - * - * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010-2012 - NVIDIA, Inc. - * - * Based on code copyright/by: - * - * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. - * - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../codecs/wm8753.h" - -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-snd-wm8753" - -struct tegra_wm8753 { - struct tegra_asoc_utils_data util_data; -}; - -static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_card *card = rtd->card; - struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk; - int err; - - srate = params_rate(params); - switch (srate) { - case 11025: - case 22050: - case 44100: - case 88200: - mclk = 11289600; - break; - default: - mclk = 12288000; - break; - } - - err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - - return 0; -} - -static const struct snd_soc_ops tegra_wm8753_ops = { - .hw_params = tegra_wm8753_hw_params, -}; - -static const struct snd_soc_dapm_widget tegra_wm8753_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), -}; - -SND_SOC_DAILINK_DEFS(pcm, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8753-hifi")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link tegra_wm8753_dai = { - .name = "WM8753", - .stream_name = "WM8753 PCM", - .ops = &tegra_wm8753_ops, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(pcm), -}; - -static struct snd_soc_card snd_soc_tegra_wm8753 = { - .name = "tegra-wm8753", - .owner = THIS_MODULE, - .dai_link = &tegra_wm8753_dai, - .num_links = 1, - - .dapm_widgets = tegra_wm8753_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_wm8753_dapm_widgets), - .fully_routed = true, -}; - -static int tegra_wm8753_driver_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_wm8753; - struct tegra_wm8753 *machine; - int ret; - - machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8753), - GFP_KERNEL); - if (!machine) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, machine); - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - return ret; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - return ret; - - tegra_wm8753_dai.codecs->of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); - if (!tegra_wm8753_dai.codecs->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - return -EINVAL; - } - - tegra_wm8753_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_wm8753_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - return -EINVAL; - } - - tegra_wm8753_dai.platforms->of_node = tegra_wm8753_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); - if (ret) - return ret; - - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - return dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); - - return 0; -} - -static const struct of_device_id tegra_wm8753_of_match[] = { - { .compatible = "nvidia,tegra-audio-wm8753", }, - {}, -}; - -static struct platform_driver tegra_wm8753_driver = { - .driver = { - .name = DRV_NAME, - .pm = &snd_soc_pm_ops, - .of_match_table = tegra_wm8753_of_match, - }, - .probe = tegra_wm8753_driver_probe, -}; -module_platform_driver(tegra_wm8753_driver); - -MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); -MODULE_DESCRIPTION("Tegra+WM8753 machine ASoC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_wm8753_of_match); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index e4863fa37b0c..5751fb398c1a 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -14,44 +14,27 @@ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com */ +#include <linux/gpio/consumer.h> +#include <linux/of.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> #include <sound/core.h> #include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> #include <sound/soc.h> #include "../codecs/wm8903.h" -#include "tegra_asoc_utils.h" +#include "tegra_asoc_machine.h" -#define DRV_NAME "tegra-snd-wm8903" - -struct tegra_wm8903 { - int gpio_spkr_en; - int gpio_hp_det; - int gpio_hp_mute; - int gpio_int_mic_en; - int gpio_ext_mic_en; - struct tegra_asoc_utils_data util_data; +static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { + { .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE }, }; -static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static unsigned int tegra_wm8903_mclk_rate(unsigned int srate) { - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_card *card = rtd->card; - struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - int srate, mclk; - int err; + unsigned int mclk; - srate = params_rate(params); switch (srate) { case 64000: case 88200: @@ -66,140 +49,53 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, while (mclk < 6000000) mclk *= 2; - err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - - return 0; + return mclk; } -static const struct snd_soc_ops tegra_wm8903_ops = { - .hw_params = tegra_wm8903_hw_params, -}; - -static struct snd_soc_jack tegra_wm8903_hp_jack; - -static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = { - .name = "headphone detect", - .report = SND_JACK_HEADPHONE, - .debounce_time = 150, - .invert = 1, -}; - -static struct snd_soc_jack tegra_wm8903_mic_jack; - -static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - - if (!gpio_is_valid(machine->gpio_spkr_en)) - return 0; - - gpio_set_value_cansleep(machine->gpio_spkr_en, - SND_SOC_DAPM_EVENT_ON(event)); - - return 0; -} - -static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - - if (!gpio_is_valid(machine->gpio_hp_mute)) - return 0; - - gpio_set_value_cansleep(machine->gpio_hp_mute, - !SND_SOC_DAPM_EVENT_ON(event)); - - return 0; -} - -static int tegra_wm8903_event_int_mic(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) +static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - - if (!gpio_is_valid(machine->gpio_int_mic_en)) - return 0; + struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_card *card = rtd->card; + int err; - gpio_set_value_cansleep(machine->gpio_int_mic_en, - SND_SOC_DAPM_EVENT_ON(event)); + /* + * Older version of machine driver was ignoring GPIO polarity, + * forcing it to active-low. This means that all older device-trees + * which set the polarity to active-high are wrong and we need to fix + * them up. + */ + if (machine->asoc->hp_jack_gpio_active_low) { + bool active_low = gpiod_is_active_low(machine->gpiod_hp_det); - return 0; -} + machine->hp_jack_gpio->invert = !active_low; + } -static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), - SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("Int Mic", tegra_wm8903_event_int_mic), -}; + err = tegra_asoc_machine_init(rtd); + if (err) + return err; -static const struct snd_kcontrol_new tegra_wm8903_controls[] = { - SOC_DAPM_PIN_SWITCH("Int Spk"), - SOC_DAPM_PIN_SWITCH("Int Mic"), -}; + if (!machine->gpiod_mic_det && machine->asoc->add_mic_jack) { + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + int shrt = 0; + + err = snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, + machine->mic_jack, + tegra_wm8903_mic_jack_pins, + ARRAY_SIZE(tegra_wm8903_mic_jack_pins)); + if (err) { + dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err); + return err; + } -static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = codec_dai->component; - struct snd_soc_card *card = rtd->card; - struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); - int shrt = 0; + if (of_property_read_bool(card->dev->of_node, "nvidia,headset")) + shrt = SND_JACK_MICROPHONE; - if (gpio_is_valid(machine->gpio_hp_det)) { - tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det; - snd_soc_card_jack_new(rtd->card, "Headphone Jack", - SND_JACK_HEADPHONE, &tegra_wm8903_hp_jack, - tegra_wm8903_hp_jack_pins, - ARRAY_SIZE(tegra_wm8903_hp_jack_pins)); - snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, - 1, - &tegra_wm8903_hp_jack_gpio); + wm8903_mic_detect(component, machine->mic_jack, + SND_JACK_MICROPHONE, shrt); } - if (of_property_read_bool(card->dev->of_node, "nvidia,headset")) - shrt = SND_JACK_MICROPHONE; - - snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, - &tegra_wm8903_mic_jack, - tegra_wm8903_mic_jack_pins, - ARRAY_SIZE(tegra_wm8903_mic_jack_pins)); - wm8903_mic_detect(component, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, - shrt); - snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS"); return 0; @@ -207,8 +103,8 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) static int tegra_wm8903_remove(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = - snd_soc_get_pcm_runtime(card, &card->dai_link[0]); + struct snd_soc_dai_link *link = &card->dai_link[0]; + struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card, link); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; @@ -226,7 +122,6 @@ static struct snd_soc_dai_link tegra_wm8903_dai = { .name = "WM8903", .stream_name = "WM8903 PCM", .init = tegra_wm8903_init, - .ops = &tegra_wm8903_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -234,148 +129,60 @@ static struct snd_soc_dai_link tegra_wm8903_dai = { }; static struct snd_soc_card snd_soc_tegra_wm8903 = { - .name = "tegra-wm8903", + .components = "codec:wm8903", .owner = THIS_MODULE, .dai_link = &tegra_wm8903_dai, .num_links = 1, .remove = tegra_wm8903_remove, - .controls = tegra_wm8903_controls, - .num_controls = ARRAY_SIZE(tegra_wm8903_controls), - .dapm_widgets = tegra_wm8903_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets), .fully_routed = true, }; -static int tegra_wm8903_driver_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_wm8903; - struct tegra_wm8903 *machine; - int ret; - - machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903), - GFP_KERNEL); - if (!machine) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, machine); - - machine->gpio_spkr_en = of_get_named_gpio(np, "nvidia,spkr-en-gpios", - 0); - if (machine->gpio_spkr_en == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(machine->gpio_spkr_en)) { - ret = devm_gpio_request_one(&pdev->dev, machine->gpio_spkr_en, - GPIOF_OUT_INIT_LOW, "spkr_en"); - if (ret) { - dev_err(card->dev, "cannot get spkr_en gpio\n"); - return ret; - } - } - - machine->gpio_hp_mute = of_get_named_gpio(np, "nvidia,hp-mute-gpios", - 0); - if (machine->gpio_hp_mute == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(machine->gpio_hp_mute)) { - ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_mute, - GPIOF_OUT_INIT_HIGH, "hp_mute"); - if (ret) { - dev_err(card->dev, "cannot get hp_mute gpio\n"); - return ret; - } - } - - machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); - if (machine->gpio_hp_det == -EPROBE_DEFER) - return -EPROBE_DEFER; - - machine->gpio_int_mic_en = of_get_named_gpio(np, - "nvidia,int-mic-en-gpios", 0); - if (machine->gpio_int_mic_en == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(machine->gpio_int_mic_en)) { - /* Disable int mic; enable signal is active-high */ - ret = devm_gpio_request_one(&pdev->dev, - machine->gpio_int_mic_en, - GPIOF_OUT_INIT_LOW, "int_mic_en"); - if (ret) { - dev_err(card->dev, "cannot get int_mic_en gpio\n"); - return ret; - } - } - - machine->gpio_ext_mic_en = of_get_named_gpio(np, - "nvidia,ext-mic-en-gpios", 0); - if (machine->gpio_ext_mic_en == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(machine->gpio_ext_mic_en)) { - /* Enable ext mic; enable signal is active-low */ - ret = devm_gpio_request_one(&pdev->dev, - machine->gpio_ext_mic_en, - GPIOF_OUT_INIT_LOW, "ext_mic_en"); - if (ret) { - dev_err(card->dev, "cannot get ext_mic_en gpio\n"); - return ret; - } - } - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - return ret; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - return ret; - - tegra_wm8903_dai.codecs->of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); - if (!tegra_wm8903_dai.codecs->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - return -EINVAL; - } - - tegra_wm8903_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!tegra_wm8903_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - return -EINVAL; - } - - tegra_wm8903_dai.platforms->of_node = tegra_wm8903_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); - if (ret) - return ret; - - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - return dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); +/* older device-trees used wrong polarity for the headphones-detection GPIO */ +static const struct tegra_asoc_data tegra_wm8903_data_legacy = { + .mclk_rate = tegra_wm8903_mclk_rate, + .card = &snd_soc_tegra_wm8903, + .hp_jack_gpio_active_low = true, + .add_common_dapm_widgets = true, + .add_common_controls = true, + .add_common_snd_ops = true, + .add_mic_jack = true, + .add_hp_jack = true, +}; - return 0; -} +static const struct tegra_asoc_data tegra_wm8903_data = { + .mclk_rate = tegra_wm8903_mclk_rate, + .card = &snd_soc_tegra_wm8903, + .add_common_dapm_widgets = true, + .add_common_controls = true, + .add_common_snd_ops = true, + .add_mic_jack = true, + .add_hp_jack = true, +}; static const struct of_device_id tegra_wm8903_of_match[] = { - { .compatible = "nvidia,tegra-audio-wm8903", }, + { .compatible = "ad,tegra-audio-plutux", .data = &tegra_wm8903_data_legacy }, + { .compatible = "ad,tegra-audio-wm8903-medcom-wide", .data = &tegra_wm8903_data_legacy }, + { .compatible = "ad,tegra-audio-wm8903-tec", .data = &tegra_wm8903_data_legacy }, + { .compatible = "nvidia,tegra-audio-wm8903-cardhu", .data = &tegra_wm8903_data_legacy }, + { .compatible = "nvidia,tegra-audio-wm8903-harmony", .data = &tegra_wm8903_data_legacy }, + { .compatible = "nvidia,tegra-audio-wm8903-picasso", .data = &tegra_wm8903_data_legacy }, + { .compatible = "nvidia,tegra-audio-wm8903-seaboard", .data = &tegra_wm8903_data_legacy }, + { .compatible = "nvidia,tegra-audio-wm8903-ventana", .data = &tegra_wm8903_data_legacy }, + { .compatible = "nvidia,tegra-audio-wm8903", .data = &tegra_wm8903_data }, {}, }; +MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match); static struct platform_driver tegra_wm8903_driver = { .driver = { - .name = DRV_NAME, - .pm = &snd_soc_pm_ops, + .name = "tegra-wm8903", .of_match_table = tegra_wm8903_of_match, + .pm = &snd_soc_pm_ops, }, - .probe = tegra_wm8903_driver_probe, + .probe = tegra_asoc_machine_probe, }; module_platform_driver(tegra_wm8903_driver); MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match); diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c deleted file mode 100644 index 4f09a178049d..000000000000 --- a/sound/soc/tegra/tegra_wm9712.c +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * tegra20_wm9712.c - Tegra machine ASoC driver for boards using WM9712 codec. - * - * Copyright 2012 Lucas Stach <dev@lynxeye.de> - * - * Partly based on code copyright/by: - * Copyright 2011,2012 Toradex Inc. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-snd-wm9712" - -struct tegra_wm9712 { - struct platform_device *codec; - struct tegra_asoc_utils_data util_data; -}; - -static const struct snd_soc_dapm_widget tegra_wm9712_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_LINE("LineIn", NULL), - SND_SOC_DAPM_MIC("Mic", NULL), -}; - -static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd) -{ - return snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias"); -} - -SND_SOC_DAILINK_DEFS(hifi, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link tegra_wm9712_dai = { - .name = "AC97 HiFi", - .stream_name = "AC97 HiFi", - .init = tegra_wm9712_init, - SND_SOC_DAILINK_REG(hifi), -}; - -static struct snd_soc_card snd_soc_tegra_wm9712 = { - .name = "tegra-wm9712", - .owner = THIS_MODULE, - .dai_link = &tegra_wm9712_dai, - .num_links = 1, - - .dapm_widgets = tegra_wm9712_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tegra_wm9712_dapm_widgets), - .fully_routed = true, -}; - -static int tegra_wm9712_driver_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_tegra_wm9712; - struct tegra_wm9712 *machine; - int ret; - - machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712), - GFP_KERNEL); - if (!machine) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, machine); - - machine->codec = platform_device_alloc("wm9712-codec", -1); - if (!machine->codec) { - dev_err(&pdev->dev, "Can't allocate wm9712 platform device\n"); - return -ENOMEM; - } - - ret = platform_device_add(machine->codec); - if (ret) - goto codec_put; - - ret = snd_soc_of_parse_card_name(card, "nvidia,model"); - if (ret) - goto codec_unregister; - - ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); - if (ret) - goto codec_unregister; - - tegra_wm9712_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,ac97-controller", 0); - if (!tegra_wm9712_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,ac97-controller' missing or invalid\n"); - ret = -EINVAL; - goto codec_unregister; - } - - tegra_wm9712_dai.platforms->of_node = tegra_wm9712_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); - if (ret) - goto codec_unregister; - - ret = tegra_asoc_utils_set_ac97_rate(&machine->util_data); - if (ret) - goto codec_unregister; - - ret = snd_soc_register_card(card); - if (ret) { - dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); - goto codec_unregister; - } - - return 0; - -codec_unregister: - platform_device_del(machine->codec); -codec_put: - platform_device_put(machine->codec); - return ret; -} - -static int tegra_wm9712_driver_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct tegra_wm9712 *machine = snd_soc_card_get_drvdata(card); - - snd_soc_unregister_card(card); - - platform_device_unregister(machine->codec); - - return 0; -} - -static const struct of_device_id tegra_wm9712_of_match[] = { - { .compatible = "nvidia,tegra-audio-wm9712", }, - {}, -}; - -static struct platform_driver tegra_wm9712_driver = { - .driver = { - .name = DRV_NAME, - .pm = &snd_soc_pm_ops, - .of_match_table = tegra_wm9712_of_match, - }, - .probe = tegra_wm9712_driver_probe, - .remove = tegra_wm9712_driver_remove, -}; -module_platform_driver(tegra_wm9712_driver); - -MODULE_AUTHOR("Lucas Stach"); -MODULE_DESCRIPTION("Tegra+WM9712 machine ASoC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, tegra_wm9712_of_match); diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c deleted file mode 100644 index 6c1cc3d0ac33..000000000000 --- a/sound/soc/tegra/trimslice.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * trimslice.c - TrimSlice machine ASoC driver - * - * Copyright (C) 2011 - CompuLab, Ltd. - * Author: Mike Rapoport <mike@compulab.co.il> - * - * Based on code copyright/by: - * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010-2011 - NVIDIA, Inc. - */ - -#include <linux/module.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../codecs/tlv320aic23.h" - -#include "tegra_asoc_utils.h" - -#define DRV_NAME "tegra-snd-trimslice" - -struct tegra_trimslice { - struct tegra_asoc_utils_data util_data; -}; - -static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_card *card = rtd->card; - struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); - int srate, mclk; - int err; - - srate = params_rate(params); - mclk = 128 * srate; - - err = tegra_asoc_utils_set_rate(&trimslice->util_data, srate, mclk); - if (err < 0) { - dev_err(card->dev, "Can't configure clocks\n"); - return err; - } - - err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return err; - } - - return 0; -} - -static const struct snd_soc_ops trimslice_asoc_ops = { - .hw_params = trimslice_asoc_hw_params, -}; - -static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = { - SND_SOC_DAPM_HP("Line Out", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route trimslice_audio_map[] = { - {"Line Out", NULL, "LOUT"}, - {"Line Out", NULL, "ROUT"}, - - {"LLINEIN", NULL, "Line In"}, - {"RLINEIN", NULL, "Line In"}, -}; - -SND_SOC_DAILINK_DEFS(single_dsp, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic23-hifi")), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { - .name = "TLV320AIC23", - .stream_name = "AIC23", - .ops = &trimslice_asoc_ops, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - SND_SOC_DAILINK_REG(single_dsp), -}; - -static struct snd_soc_card snd_soc_trimslice = { - .name = "tegra-trimslice", - .owner = THIS_MODULE, - .dai_link = &trimslice_tlv320aic23_dai, - .num_links = 1, - - .dapm_widgets = trimslice_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), - .dapm_routes = trimslice_audio_map, - .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), - .fully_routed = true, -}; - -static int tegra_snd_trimslice_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &snd_soc_trimslice; - struct tegra_trimslice *trimslice; - int ret; - - trimslice = devm_kzalloc(&pdev->dev, sizeof(struct tegra_trimslice), - GFP_KERNEL); - if (!trimslice) - return -ENOMEM; - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, trimslice); - - trimslice_tlv320aic23_dai.codecs->of_node = of_parse_phandle(np, - "nvidia,audio-codec", 0); - if (!trimslice_tlv320aic23_dai.codecs->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,audio-codec' missing or invalid\n"); - return -EINVAL; - } - - trimslice_tlv320aic23_dai.cpus->of_node = of_parse_phandle(np, - "nvidia,i2s-controller", 0); - if (!trimslice_tlv320aic23_dai.cpus->of_node) { - dev_err(&pdev->dev, - "Property 'nvidia,i2s-controller' missing or invalid\n"); - return -EINVAL; - } - - trimslice_tlv320aic23_dai.platforms->of_node = - trimslice_tlv320aic23_dai.cpus->of_node; - - ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); - if (ret) - return ret; - - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - return dev_err_probe(&pdev->dev, ret, - "snd_soc_register_card failed\n"); - - return 0; -} - -static const struct of_device_id trimslice_of_match[] = { - { .compatible = "nvidia,tegra-audio-trimslice", }, - {}, -}; -MODULE_DEVICE_TABLE(of, trimslice_of_match); - -static struct platform_driver tegra_snd_trimslice_driver = { - .driver = { - .name = DRV_NAME, - .of_match_table = trimslice_of_match, - }, - .probe = tegra_snd_trimslice_probe, -}; -module_platform_driver(tegra_snd_trimslice_driver); - -MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); -MODULE_DESCRIPTION("Trimslice machine ASoC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index b94220306d1a..017a5a5e56cd 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2317,6 +2317,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) break; default: dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret); + fallthrough; case -EPROBE_DEFER: goto err; } diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index db47981768c5..4479d74f0a45 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -539,7 +539,7 @@ static ssize_t prop##_store(struct device *dev, \ return size; \ } \ \ -static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store) +static DEVICE_ATTR_RW(prop) THRESHOLD_PROP_BUILDER(max_tx_thres); THRESHOLD_PROP_BUILDER(max_rx_thres); diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index d24ae00878f5..c434b69a83f1 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -975,8 +975,9 @@ static int snd_amd7930_create(struct snd_card *card, spin_unlock_irqrestore(&amd->lock, flags); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - amd, &snd_amd7930_dev_ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, + amd, &snd_amd7930_dev_ops); + if (err < 0) { snd_amd7930_free(amd); return err; } @@ -1019,13 +1020,16 @@ static int amd7930_sbus_probe(struct platform_device *op) irq, dev_num, &amd)) < 0) goto out_err; - if ((err = snd_amd7930_pcm(amd)) < 0) + err = snd_amd7930_pcm(amd); + if (err < 0) goto out_err; - if ((err = snd_amd7930_mixer(amd)) < 0) + err = snd_amd7930_mixer(amd); + if (err < 0) goto out_err; - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto out_err; amd->next = amd7930_list; diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 35c17803a430..2942c8c7a236 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -1828,8 +1828,9 @@ static int snd_cs4231_sbus_create(struct snd_card *card, } snd_cs4231_init(chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &snd_cs4231_sbus_dev_ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, + chip, &snd_cs4231_sbus_dev_ops); + if (err < 0) { snd_cs4231_sbus_free(chip); return err; } @@ -2020,8 +2021,9 @@ static int snd_cs4231_ebus_create(struct snd_card *card, } snd_cs4231_init(chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &snd_cs4231_ebus_dev_ops)) < 0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, + chip, &snd_cs4231_ebus_dev_ops); + if (err < 0) { snd_cs4231_ebus_free(chip); return err; } diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index b055f5839578..6b84f66e4af4 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2226,11 +2226,12 @@ static int snd_dbri_pcm(struct snd_card *card) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(card, - /* ID */ "sun_dbri", - /* device */ 0, - /* playback count */ 1, - /* capture count */ 1, &pcm)) < 0) + err = snd_pcm_new(card, + /* ID */ "sun_dbri", + /* device */ 0, + /* playback count */ 1, + /* capture count */ 1, &pcm); + if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dbri_ops); diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index f65e6c7b139f..49d1976a132c 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -104,7 +104,8 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch if (emu->sflist == NULL) return -ENOMEM; - if ((err = snd_emux_init_hwdep(emu)) < 0) + err = snd_emux_init_hwdep(emu); + if (err < 0) return err; snd_emux_init_voices(emu); diff --git a/sound/synth/emux/emux_effect.c b/sound/synth/emux/emux_effect.c index afd119b11f39..3c7314f5fb19 100644 --- a/sound/synth/emux/emux_effect.c +++ b/sound/synth/emux/emux_effect.c @@ -181,7 +181,10 @@ snd_emux_send_effect(struct snd_emux_port *port, struct snd_midi_channel *chan, fx->flag[type] = mode; /* do we need to modify the register in realtime ? */ - if (! parm_defs[type].update || (offset = parm_defs[type].offset) < 0) + if (!parm_defs[type].update) + return; + offset = parm_defs[type].offset; + if (offset < 0) return; #ifdef SNDRV_LITTLE_ENDIAN @@ -223,13 +226,17 @@ snd_emux_setup_effect(struct snd_emux_voice *vp) unsigned char *srcp; int i; - if (! (fx = chan->private)) + fx = chan->private; + if (!fx) return; /* modify the register values via effect table */ for (i = 0; i < EMUX_FX_END; i++) { int offset; - if (! fx->flag[i] || (offset = parm_defs[i].offset) < 0) + if (!fx->flag[i]) + continue; + offset = parm_defs[i].offset; + if (offset < 0) continue; #ifdef SNDRV_LITTLE_ENDIAN if (parm_defs[i].type & PARM_IS_ALIGN_HI) diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index 8a965e2f160a..81719bfb8ed7 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c @@ -116,7 +116,8 @@ snd_emux_init_hwdep(struct snd_emux *emu) struct snd_hwdep *hw; int err; - if ((err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw)) < 0) + err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw); + if (err < 0) return err; emu->hwdep = hw; strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); @@ -127,7 +128,8 @@ snd_emux_init_hwdep(struct snd_emux *emu) hw->ops.ioctl_compat = snd_emux_hwdep_ioctl; hw->exclusive = 1; hw->private_data = emu; - if ((err = snd_card_register(emu->card)) < 0) + err = snd_card_register(emu->card); + if (err < 0) return err; return 0; diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 9ebc711afa6b..da3cf8912463 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -349,7 +349,8 @@ sf_zone_new(struct snd_sf_list *sflist, struct snd_soundfont *sf) { struct snd_sf_zone *zp; - if ((zp = kzalloc(sizeof(*zp), GFP_KERNEL)) == NULL) + zp = kzalloc(sizeof(*zp), GFP_KERNEL); + if (!zp) return NULL; zp->next = sf->zones; sf->zones = zp; @@ -381,7 +382,8 @@ sf_sample_new(struct snd_sf_list *sflist, struct snd_soundfont *sf) { struct snd_sf_sample *sp; - if ((sp = kzalloc(sizeof(*sp), GFP_KERNEL)) == NULL) + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (!sp) return NULL; sp->next = sf->samples; @@ -451,7 +453,8 @@ load_map(struct snd_sf_list *sflist, const void __user *data, int count) } /* create a new zone */ - if ((zp = sf_zone_new(sflist, sf)) == NULL) + zp = sf_zone_new(sflist, sf); + if (!zp) return -ENOMEM; zp->bank = map.map_bank; @@ -514,7 +517,8 @@ load_info(struct snd_sf_list *sflist, const void __user *data, long count) int i; /* patch must be opened */ - if ((sf = sflist->currsf) == NULL) + sf = sflist->currsf; + if (!sf) return -EINVAL; if (is_special_type(sf->type)) @@ -579,9 +583,9 @@ load_info(struct snd_sf_list *sflist, const void __user *data, long count) init_voice_parm(&tmpzone.v.parm); /* create a new zone */ - if ((zone = sf_zone_new(sflist, sf)) == NULL) { + zone = sf_zone_new(sflist, sf); + if (!zone) return -ENOMEM; - } /* copy the temporary data */ zone->bank = tmpzone.bank; @@ -700,7 +704,8 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count) long off; /* patch must be opened */ - if ((sf = sflist->currsf) == NULL) + sf = sflist->currsf; + if (!sf) return -EINVAL; if (is_special_type(sf->type)) @@ -723,7 +728,8 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count) } /* Allocate a new sample structure */ - if ((sp = sf_sample_new(sflist, sf)) == NULL) + sp = sf_sample_new(sflist, sf); + if (!sp) return -ENOMEM; sp->v = sample_info; @@ -958,7 +964,8 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_GUS|SNDRV_SFNT_PAT_SHARED, NULL); if (sf == NULL) return -ENOMEM; - if ((smp = sf_sample_new(sflist, sf)) == NULL) + smp = sf_sample_new(sflist, sf); + if (!smp) return -ENOMEM; sample_id = sflist->sample_counter; smp->v.sample = sample_id; @@ -996,7 +1003,8 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, smp->v.sf_id = sf->id; /* set up voice info */ - if ((zone = sf_zone_new(sflist, sf)) == NULL) { + zone = sf_zone_new(sflist, sf); + if (!zone) { sf_sample_delete(sflist, sf, smp); return -ENOMEM; } @@ -1181,7 +1189,8 @@ add_preset(struct snd_sf_list *sflist, struct snd_sf_zone *cur) } /* prepend this zone */ - if ((index = get_index(cur->bank, cur->instr, cur->v.low)) < 0) + index = get_index(cur->bank, cur->instr, cur->v.low); + if (index < 0) return; cur->next_zone = zone; /* zone link */ cur->next_instr = sflist->presets[index]; /* preset table link */ @@ -1197,7 +1206,8 @@ delete_preset(struct snd_sf_list *sflist, struct snd_sf_zone *zp) int index; struct snd_sf_zone *p; - if ((index = get_index(zp->bank, zp->instr, zp->v.low)) < 0) + index = get_index(zp->bank, zp->instr, zp->v.low); + if (index < 0) return; for (p = sflist->presets[index]; p; p = p->next_instr) { while (p->next_instr == zp) { @@ -1257,7 +1267,8 @@ search_first_zone(struct snd_sf_list *sflist, int bank, int preset, int key) int index; struct snd_sf_zone *zp; - if ((index = get_index(bank, preset, key)) < 0) + index = get_index(bank, preset, key); + if (index < 0) return NULL; for (zp = sflist->presets[index]; zp; zp = zp->next_instr) { if (zp->instr == preset && zp->bank == bank) @@ -1386,7 +1397,8 @@ snd_sf_new(struct snd_sf_callback *callback, struct snd_util_memhdr *hdr) { struct snd_sf_list *sflist; - if ((sflist = kzalloc(sizeof(*sflist), GFP_KERNEL)) == NULL) + sflist = kzalloc(sizeof(*sflist), GFP_KERNEL); + if (!sflist) return NULL; mutex_init(&sflist->presets_mutex); diff --git a/sound/usb/card.h b/sound/usb/card.h index a741e7da83a2..5577a776561b 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -54,6 +54,7 @@ struct snd_urb_ctx { struct snd_usb_endpoint *ep; int index; /* index for urb array */ int packets; /* number of packets per urb */ + int queued; /* queued data bytes by this urb */ int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */ struct list_head ready_list; }; @@ -158,8 +159,10 @@ struct snd_usb_substream { unsigned int running: 1; /* running status */ + unsigned int buffer_bytes; /* buffer size in bytes */ + unsigned int inflight_bytes; /* in-flight data bytes on buffer (for playback) */ unsigned int hwptr_done; /* processed byte position in the buffer */ - unsigned int transfer_done; /* processed frames since last period update */ + unsigned int transfer_done; /* processed frames since last period update */ unsigned int frame_limit; /* limits number of packets in URB */ /* data and sync endpoints for this stream */ @@ -174,8 +177,7 @@ struct snd_usb_substream { struct list_head fmt_list; /* format list */ spinlock_t lock; - int last_frame_number; /* stored frame number */ - int last_delay; /* stored delay */ + unsigned int last_frame_number; /* stored frame number */ struct { int marker; diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 17bbde73d4d1..52de52288e10 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -21,82 +21,77 @@ #include "clock.h" #include "quirks.h" +union uac23_clock_source_desc { + struct uac_clock_source_descriptor v2; + struct uac3_clock_source_descriptor v3; +}; + +union uac23_clock_selector_desc { + struct uac_clock_selector_descriptor v2; + struct uac3_clock_selector_descriptor v3; +}; + +union uac23_clock_multiplier_desc { + struct uac_clock_multiplier_descriptor v2; + struct uac_clock_multiplier_descriptor v3; +}; + +#define GET_VAL(p, proto, field) \ + ((proto) == UAC_VERSION_3 ? (p)->v3.field : (p)->v2.field) + static void *find_uac_clock_desc(struct usb_host_interface *iface, int id, - bool (*validator)(void *, int), u8 type) + bool (*validator)(void *, int, int), + u8 type, int proto) { void *cs = NULL; while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen, cs, type))) { - if (validator(cs, id)) + if (validator(cs, id, proto)) return cs; } return NULL; } -static bool validate_clock_source_v2(void *p, int id) +static bool validate_clock_source(void *p, int id, int proto) { - struct uac_clock_source_descriptor *cs = p; - return cs->bClockID == id; -} + union uac23_clock_source_desc *cs = p; -static bool validate_clock_source_v3(void *p, int id) -{ - struct uac3_clock_source_descriptor *cs = p; - return cs->bClockID == id; + return GET_VAL(cs, proto, bClockID) == id; } -static bool validate_clock_selector_v2(void *p, int id) +static bool validate_clock_selector(void *p, int id, int proto) { - struct uac_clock_selector_descriptor *cs = p; - return cs->bClockID == id; -} + union uac23_clock_selector_desc *cs = p; -static bool validate_clock_selector_v3(void *p, int id) -{ - struct uac3_clock_selector_descriptor *cs = p; - return cs->bClockID == id; + return GET_VAL(cs, proto, bClockID) == id; } -static bool validate_clock_multiplier_v2(void *p, int id) +static bool validate_clock_multiplier(void *p, int id, int proto) { - struct uac_clock_multiplier_descriptor *cs = p; - return cs->bClockID == id; -} + union uac23_clock_multiplier_desc *cs = p; -static bool validate_clock_multiplier_v3(void *p, int id) -{ - struct uac3_clock_multiplier_descriptor *cs = p; - return cs->bClockID == id; + return GET_VAL(cs, proto, bClockID) == id; } -#define DEFINE_FIND_HELPER(name, obj, validator, type) \ -static obj *name(struct usb_host_interface *iface, int id) \ -{ \ - return find_uac_clock_desc(iface, id, validator, type); \ +#define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \ +static obj *name(struct snd_usb_audio *chip, int id, int proto) \ +{ \ + return find_uac_clock_desc(chip->ctrl_intf, id, validator, \ + proto == UAC_VERSION_3 ? (type3) : (type2), \ + proto); \ } DEFINE_FIND_HELPER(snd_usb_find_clock_source, - struct uac_clock_source_descriptor, - validate_clock_source_v2, UAC2_CLOCK_SOURCE); -DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3, - struct uac3_clock_source_descriptor, - validate_clock_source_v3, UAC3_CLOCK_SOURCE); - + union uac23_clock_source_desc, validate_clock_source, + UAC2_CLOCK_SOURCE, UAC3_CLOCK_SOURCE); DEFINE_FIND_HELPER(snd_usb_find_clock_selector, - struct uac_clock_selector_descriptor, - validate_clock_selector_v2, UAC2_CLOCK_SELECTOR); -DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3, - struct uac3_clock_selector_descriptor, - validate_clock_selector_v3, UAC3_CLOCK_SELECTOR); - + union uac23_clock_selector_desc, validate_clock_selector, + UAC2_CLOCK_SELECTOR, UAC3_CLOCK_SELECTOR); DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier, - struct uac_clock_multiplier_descriptor, - validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER); -DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3, - struct uac3_clock_multiplier_descriptor, - validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER); + union uac23_clock_multiplier_desc, validate_clock_multiplier, + UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER); static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) { @@ -159,14 +154,13 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, int count; unsigned char data; struct usb_device *dev = chip->dev; + union uac23_clock_source_desc *cs_desc; - if (fmt->protocol == UAC_VERSION_2) { - struct uac_clock_source_descriptor *cs_desc = - snd_usb_find_clock_source(chip->ctrl_intf, source_id); - - if (!cs_desc) - return false; + cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol); + if (!cs_desc) + return false; + if (fmt->protocol == UAC_VERSION_2) { /* * Assume the clock is valid if clock source supports only one * single sample rate, the terminal is connected directly to it @@ -175,8 +169,8 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, * reports that clock is invalid. */ if (fmt->nr_rates == 1 && - (fmt->clock & 0xff) == cs_desc->bClockID && - (cs_desc->bmAttributes & 0x3) != + (fmt->clock & 0xff) == cs_desc->v2.bClockID && + (cs_desc->v2.bmAttributes & 0x3) != UAC_CLOCK_SOURCE_TYPE_EXT) return true; } @@ -222,22 +216,16 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, unsigned char data; struct usb_device *dev = chip->dev; u32 bmControls; + union uac23_clock_source_desc *cs_desc; - if (fmt->protocol == UAC_VERSION_3) { - struct uac3_clock_source_descriptor *cs_desc = - snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id); - - if (!cs_desc) - return false; - bmControls = le32_to_cpu(cs_desc->bmControls); - } else { /* UAC_VERSION_1/2 */ - struct uac_clock_source_descriptor *cs_desc = - snd_usb_find_clock_source(chip->ctrl_intf, source_id); + cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol); + if (!cs_desc) + return false; - if (!cs_desc) - return false; - bmControls = cs_desc->bmControls; - } + if (fmt->protocol == UAC_VERSION_3) + bmControls = le32_to_cpu(cs_desc->v3.bmControls); + else + bmControls = cs_desc->v2.bmControls; /* If a clock source can't tell us whether it's valid, we assume it is */ if (!uac_v2v3_control_is_readable(bmControls, @@ -267,9 +255,12 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, const struct audioformat *fmt, int entity_id, unsigned long *visited, bool validate) { - struct uac_clock_source_descriptor *source; - struct uac_clock_selector_descriptor *selector; - struct uac_clock_multiplier_descriptor *multiplier; + union uac23_clock_source_desc *source; + union uac23_clock_selector_desc *selector; + union uac23_clock_multiplier_desc *multiplier; + int ret, i, cur, err, pins, clock_id; + const u8 *sources; + int proto = fmt->protocol; entity_id &= 0xff; @@ -281,9 +272,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, } /* first, see if the ID we're looking for is a clock source already */ - source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); + source = snd_usb_find_clock_source(chip, entity_id, proto); if (source) { - entity_id = source->bClockID; + entity_id = GET_VAL(source, proto, bClockID); if (validate && !uac_clock_source_is_valid(chip, fmt, entity_id)) { usb_audio_err(chip, @@ -294,35 +285,43 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, return entity_id; } - selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); + selector = snd_usb_find_clock_selector(chip, entity_id, proto); if (selector) { - int ret, i, cur, err; + pins = GET_VAL(selector, proto, bNrInPins); + clock_id = GET_VAL(selector, proto, bClockID); + sources = GET_VAL(selector, proto, baCSourceID); + cur = 0; - if (selector->bNrInPins == 1) { + if (pins == 1) { ret = 1; goto find_source; } /* the entity ID we are looking for is a selector. * find out what it currently selects */ - ret = uac_clock_selector_get_val(chip, selector->bClockID); - if (ret < 0) - return ret; + ret = uac_clock_selector_get_val(chip, clock_id); + if (ret < 0) { + if (!chip->autoclock) + return ret; + goto find_others; + } /* Selector values are one-based */ - if (ret > selector->bNrInPins || ret < 1) { + if (ret > pins || ret < 1) { usb_audio_err(chip, "%s(): selector reported illegal value, id %d, ret %d\n", - __func__, selector->bClockID, ret); + __func__, clock_id, ret); - return -EINVAL; + if (!chip->autoclock) + return -EINVAL; + goto find_others; } find_source: cur = ret; ret = __uac_clock_find_source(chip, fmt, - selector->baCSourceID[ret - 1], + sources[ret - 1], visited, validate); if (ret > 0) { err = uac_clock_selector_set_val(chip, entity_id, cur); @@ -333,13 +332,14 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, if (!validate || ret > 0 || !chip->autoclock) return ret; + find_others: /* The current clock source is invalid, try others. */ - for (i = 1; i <= selector->bNrInPins; i++) { + for (i = 1; i <= pins; i++) { if (i == cur) continue; ret = __uac_clock_find_source(chip, fmt, - selector->baCSourceID[i - 1], + sources[i - 1], visited, true); if (ret < 0) continue; @@ -358,116 +358,15 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, } /* FIXME: multipliers only act as pass-thru element for now */ - multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id); + multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto); if (multiplier) return __uac_clock_find_source(chip, fmt, - multiplier->bCSourceID, + GET_VAL(multiplier, proto, bCSourceID), visited, validate); return -EINVAL; } -static int __uac3_clock_find_source(struct snd_usb_audio *chip, - const struct audioformat *fmt, int entity_id, - unsigned long *visited, bool validate) -{ - struct uac3_clock_source_descriptor *source; - struct uac3_clock_selector_descriptor *selector; - struct uac3_clock_multiplier_descriptor *multiplier; - - entity_id &= 0xff; - - if (test_and_set_bit(entity_id, visited)) { - usb_audio_warn(chip, - "%s(): recursive clock topology detected, id %d.\n", - __func__, entity_id); - return -EINVAL; - } - - /* first, see if the ID we're looking for is a clock source already */ - source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id); - if (source) { - entity_id = source->bClockID; - if (validate && !uac_clock_source_is_valid(chip, fmt, - entity_id)) { - usb_audio_err(chip, - "clock source %d is not valid, cannot use\n", - entity_id); - return -ENXIO; - } - return entity_id; - } - - selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id); - if (selector) { - int ret, i, cur, err; - - /* the entity ID we are looking for is a selector. - * find out what it currently selects */ - ret = uac_clock_selector_get_val(chip, selector->bClockID); - if (ret < 0) - return ret; - - /* Selector values are one-based */ - - if (ret > selector->bNrInPins || ret < 1) { - usb_audio_err(chip, - "%s(): selector reported illegal value, id %d, ret %d\n", - __func__, selector->bClockID, ret); - - return -EINVAL; - } - - cur = ret; - ret = __uac3_clock_find_source(chip, fmt, - selector->baCSourceID[ret - 1], - visited, validate); - if (ret > 0) { - err = uac_clock_selector_set_val(chip, entity_id, cur); - if (err < 0) - return err; - } - - if (!validate || ret > 0 || !chip->autoclock) - return ret; - - /* The current clock source is invalid, try others. */ - for (i = 1; i <= selector->bNrInPins; i++) { - int err; - - if (i == cur) - continue; - - ret = __uac3_clock_find_source(chip, fmt, - selector->baCSourceID[i - 1], - visited, true); - if (ret < 0) - continue; - - err = uac_clock_selector_set_val(chip, entity_id, i); - if (err < 0) - continue; - - usb_audio_info(chip, - "found and selected valid clock source %d\n", - ret); - return ret; - } - - return -ENXIO; - } - - /* FIXME: multipliers only act as pass-thru element for now */ - multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf, - entity_id); - if (multiplier) - return __uac3_clock_find_source(chip, fmt, - multiplier->bCSourceID, - visited, validate); - - return -EINVAL; -} - /* * For all kinds of sample rate settings and other device queries, * the clock source (end-leaf) must be used. However, clock selectors, @@ -487,10 +386,8 @@ int snd_usb_clock_find_source(struct snd_usb_audio *chip, switch (fmt->protocol) { case UAC_VERSION_2: - return __uac_clock_find_source(chip, fmt, fmt->clock, visited, - validate); case UAC_VERSION_3: - return __uac3_clock_find_source(chip, fmt, fmt->clock, visited, + return __uac_clock_find_source(chip, fmt, fmt->clock, visited, validate); default: return -EINVAL; @@ -593,18 +490,13 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, u32 bmControls; __le32 data; int err; + union uac23_clock_source_desc *cs_desc; - if (fmt->protocol == UAC_VERSION_3) { - struct uac3_clock_source_descriptor *cs_desc; - - cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); - bmControls = le32_to_cpu(cs_desc->bmControls); - } else { - struct uac_clock_source_descriptor *cs_desc; - - cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); - bmControls = cs_desc->bmControls; - } + cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol); + if (fmt->protocol == UAC_VERSION_3) + bmControls = le32_to_cpu(cs_desc->v3.bmControls); + else + bmControls = cs_desc->v2.bmControls; writeable = uac_v2v3_control_is_writeable(bmControls, UAC2_CS_CONTROL_SAM_FREQ); @@ -642,6 +534,13 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, * rate. */ clock = snd_usb_clock_find_source(chip, fmt, false); + + /* Denon DN-X1600 hardcoded + * Sample rate seems to be set on the hardware itself + */ + if (chip->usb_id == USB_ID(0x154e, 0x500e)) + return 0; + if (clock < 0) return clock; } diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 014c43862826..da649211bff3 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -275,6 +275,7 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep, urb->number_of_packets = ctx->packets; urb->transfer_buffer_length = offs * ep->stride + ctx->packets * extra; + ctx->queued = 0; } /* diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index eea4ca49876d..a668f675b52b 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -19,7 +19,6 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep); int snd_usb_endpoint_configure(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep); -void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep); bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep, diff --git a/sound/usb/format.c b/sound/usb/format.c index 2287f8c65315..eb216fef4ba7 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -223,9 +223,11 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof continue; /* C-Media CM6501 mislabels its 96 kHz altsetting */ /* Terratec Aureon 7.1 USB C-Media 6206, too */ + /* Ozone Z90 USB C-Media, too */ if (rate == 48000 && nr_rates == 1 && (chip->usb_id == USB_ID(0x0d8c, 0x0201) || chip->usb_id == USB_ID(0x0d8c, 0x0102) || + chip->usb_id == USB_ID(0x0d8c, 0x0078) || chip->usb_id == USB_ID(0x0ccd, 0x00b1)) && fp->altsetting == 5 && fp->maxpacksize == 392) rate = 96000; diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 428d581f988f..30b3e128e28d 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -3294,8 +3294,9 @@ static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, struct usb_mixer_elem_list *list) { struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); - static const char * const val_types[] = {"BOOLEAN", "INV_BOOLEAN", - "S8", "U8", "S16", "U16"}; + static const char * const val_types[] = { + "BOOLEAN", "INV_BOOLEAN", "S8", "U8", "S16", "U16", "S32", "U32", + }; snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " "channels=%i, type=\"%s\"\n", cval->head.id, cval->control, cval->cmask, cval->channels, @@ -3605,6 +3606,9 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list) struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); int c, err, idx; + if (cval->val_type == USB_MIXER_BESPOKEN) + return 0; + if (cval->cmask) { idx = 0; for (c = 0; c < MAX_CHANNELS; c++) { diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index e5a01f17bf3c..ea41e7a1f7bf 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -55,6 +55,7 @@ enum { USB_MIXER_U16, USB_MIXER_S32, USB_MIXER_U32, + USB_MIXER_BESPOKEN, /* non-standard type */ }; typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer, diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 37ad77524c0b..0a3cb8fd7d00 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3060,6 +3060,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */ case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */ case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */ + case USB_ID(0x1235, 0x8211): /* Focusrite Scarlett Solo 3rd Gen */ + case USB_ID(0x1235, 0x8210): /* Focusrite Scarlett 2i2 3rd Gen */ + case USB_ID(0x1235, 0x8212): /* Focusrite Scarlett 4i4 3rd Gen */ + case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */ + case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */ + case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */ err = snd_scarlett_gen2_init(mixer); break; diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 4caf379d5b99..f9d698a37153 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -1,8 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Focusrite Scarlett 6i6/18i8/18i20 Gen 2 Driver for ALSA + * Focusrite Scarlett Gen 2/3 Driver for ALSA * - * Copyright (c) 2018-2019 by Geoffrey D. Bennett <g at b4.vu> + * Supported models: + * - 6i6/18i8/18i20 Gen 2 + * - Solo/2i2/4i4/8i6/18i8/18i20 Gen 3 + * + * Copyright (c) 2018-2021 by Geoffrey D. Bennett <g at b4.vu> + * Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com> * * Based on the Scarlett (Gen 1) Driver for ALSA: * @@ -19,10 +24,6 @@ * David Henningsson <david.henningsson at canonical.com> */ -/* Mixer Interface for the Focusrite Scarlett 6i6/18i8/18i20 Gen 2 audio - * interface. Based on the Gen 1 driver and rewritten. - */ - /* The protocol was reverse engineered by looking at the communication * between Focusrite Control 2.3.4 and the Focusrite(R) Scarlett 18i20 * (firmware 1083) using usbmon in July-August 2018. @@ -32,12 +33,33 @@ * Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann * for providing usbmon output and testing). * - * This ALSA mixer gives access to: + * Scarlett 4i4/8i6 Gen 3 support added in May 2020 (thanks to Laurent + * Debricon for donating a 4i4 and to Fredrik Unger for providing 8i6 + * usbmon output and testing). + * + * Scarlett 18i8/18i20 Gen 3 support added in June 2020 (thanks to + * Darren Jaeckel, Alex Sedlack, and Clovis Lunel for providing usbmon + * output, protocol traces and testing). + * + * Support for loading mixer volume and mux configuration from the + * interface during driver initialisation added in May 2021 (thanks to + * Vladimir Sadovnikov for figuring out how). + * + * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander + * Vorona for 2i2 protocol traces). + * + * Support for phantom power, direct monitoring, speaker switching, + * and talkback added in May-June 2021. + * + * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes - * - 18x10 mixer-matrix gain stages - * - gain/volume controls + * - mixer-matrix gain stages + * - gain/volume/mute controls * - level meters - * - line/inst level and pad controls + * - line/inst level, pad, and air controls + * - phantom power, direct monitor, speaker switching, and talkback + * controls + * - disable/enable MSD mode * * <ditaa> * /--------------\ 18chn 20chn /--------------\ @@ -90,6 +112,14 @@ * \--------------/ * </ditaa> * + * Gen 3 devices have a Mass Storage Device (MSD) mode where a small + * disk with registration and driver download information is presented + * to the host. To access the full functionality of the device without + * proprietary software, MSD mode can be disabled by: + * - holding down the 48V button for five seconds while powering on + * the device, or + * - using this driver and alsamixer to change the "MSD Mode" setting + * to Off and power-cycling the device */ #include <linux/slab.h> @@ -108,6 +138,9 @@ /* device_setup value to enable */ #define SCARLETT2_ENABLE 0x01 +/* device_setup value to allow turning MSD mode back on */ +#define SCARLETT2_MSD_ENABLE 0x02 + /* some gui mixers can't handle negative ctl values */ #define SCARLETT2_VOLUME_BIAS 127 @@ -117,11 +150,12 @@ #define SCARLETT2_MIXER_MAX_DB 6 #define SCARLETT2_MIXER_MAX_VALUE \ ((SCARLETT2_MIXER_MAX_DB - SCARLETT2_MIXER_MIN_DB) * 2) +#define SCARLETT2_MIXER_VALUE_COUNT (SCARLETT2_MIXER_MAX_VALUE + 1) /* map from (dB + 80) * 2 to mixer value * for dB in 0 .. 172: int(8192 * pow(10, ((dB - 160) / 2 / 20))) */ -static const u16 scarlett2_mixer_values[173] = { +static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, @@ -143,23 +177,23 @@ static const u16 scarlett2_mixer_values[173] = { /* Maximum number of level and pad switches */ #define SCARLETT2_LEVEL_SWITCH_MAX 2 -#define SCARLETT2_PAD_SWITCH_MAX 4 +#define SCARLETT2_PAD_SWITCH_MAX 8 +#define SCARLETT2_AIR_SWITCH_MAX 8 +#define SCARLETT2_PHANTOM_SWITCH_MAX 2 /* Maximum number of inputs to the mixer */ -#define SCARLETT2_INPUT_MIX_MAX 18 +#define SCARLETT2_INPUT_MIX_MAX 25 /* Maximum number of outputs from the mixer */ -#define SCARLETT2_OUTPUT_MIX_MAX 10 +#define SCARLETT2_OUTPUT_MIX_MAX 12 /* Maximum size of the data in the USB mux assignment message: - * 18 inputs, 20 outputs, 18 matrix inputs, 8 spare + * 20 inputs, 20 outputs, 25 matrix inputs, 12 spare */ -#define SCARLETT2_MUX_MAX 64 +#define SCARLETT2_MUX_MAX 77 -/* Number of meters: - * 18 inputs, 20 outputs, 18 matrix inputs - */ -#define SCARLETT2_NUM_METERS 56 +/* Maximum number of meters (sum of output port counts) */ +#define SCARLETT2_MAX_METERS 65 /* Hardware port types: * - None (no input to mux) @@ -170,74 +204,219 @@ static const u16 scarlett2_mixer_values[173] = { * - PCM I/O */ enum { - SCARLETT2_PORT_TYPE_NONE = 0, + SCARLETT2_PORT_TYPE_NONE = 0, SCARLETT2_PORT_TYPE_ANALOGUE = 1, - SCARLETT2_PORT_TYPE_SPDIF = 2, - SCARLETT2_PORT_TYPE_ADAT = 3, - SCARLETT2_PORT_TYPE_MIX = 4, - SCARLETT2_PORT_TYPE_PCM = 5, - SCARLETT2_PORT_TYPE_COUNT = 6, + SCARLETT2_PORT_TYPE_SPDIF = 2, + SCARLETT2_PORT_TYPE_ADAT = 3, + SCARLETT2_PORT_TYPE_MIX = 4, + SCARLETT2_PORT_TYPE_PCM = 5, + SCARLETT2_PORT_TYPE_COUNT = 6, }; -/* Count of total I/O and number available at each sample rate */ +/* I/O count of each port type kept in struct scarlett2_ports */ enum { - SCARLETT2_PORT_IN = 0, - SCARLETT2_PORT_OUT = 1, - SCARLETT2_PORT_OUT_44 = 2, - SCARLETT2_PORT_OUT_88 = 3, - SCARLETT2_PORT_OUT_176 = 4, - SCARLETT2_PORT_DIRECTIONS = 5, + SCARLETT2_PORT_IN = 0, + SCARLETT2_PORT_OUT = 1, + SCARLETT2_PORT_DIRNS = 2, }; -/* Hardware buttons on the 18i20 */ -#define SCARLETT2_BUTTON_MAX 2 +/* Dim/Mute buttons on the 18i20 */ +enum { + SCARLETT2_BUTTON_MUTE = 0, + SCARLETT2_BUTTON_DIM = 1, + SCARLETT2_DIM_MUTE_COUNT = 2, +}; -static const char *const scarlett2_button_names[SCARLETT2_BUTTON_MAX] = { +static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = { "Mute", "Dim" }; /* Description of each hardware port type: - * - id: hardware ID for this port type - * - num: number of sources/destinations of this port type + * - id: hardware ID of this port type * - src_descr: printf format string for mux input selections * - src_num_offset: added to channel number for the fprintf * - dst_descr: printf format string for mixer controls */ -struct scarlett2_ports { +struct scarlett2_port { u16 id; - int num[SCARLETT2_PORT_DIRECTIONS]; const char * const src_descr; int src_num_offset; const char * const dst_descr; }; +static const struct scarlett2_port scarlett2_ports[SCARLETT2_PORT_TYPE_COUNT] = { + [SCARLETT2_PORT_TYPE_NONE] = { + .id = 0x000, + .src_descr = "Off" + }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { + .id = 0x080, + .src_descr = "Analogue %d", + .src_num_offset = 1, + .dst_descr = "Analogue Output %02d Playback" + }, + [SCARLETT2_PORT_TYPE_SPDIF] = { + .id = 0x180, + .src_descr = "S/PDIF %d", + .src_num_offset = 1, + .dst_descr = "S/PDIF Output %d Playback" + }, + [SCARLETT2_PORT_TYPE_ADAT] = { + .id = 0x200, + .src_descr = "ADAT %d", + .src_num_offset = 1, + .dst_descr = "ADAT Output %d Playback" + }, + [SCARLETT2_PORT_TYPE_MIX] = { + .id = 0x300, + .src_descr = "Mix %c", + .src_num_offset = 'A', + .dst_descr = "Mixer Input %02d Capture" + }, + [SCARLETT2_PORT_TYPE_PCM] = { + .id = 0x600, + .src_descr = "PCM %d", + .src_num_offset = 1, + .dst_descr = "PCM %02d Capture" + }, +}; + +/* Number of mux tables: one for each band of sample rates + * (44.1/48kHz, 88.2/96kHz, and 176.4/176kHz) + */ +#define SCARLETT2_MUX_TABLES 3 + +/* Maximum number of entries in a mux table */ +#define SCARLETT2_MAX_MUX_ENTRIES 10 + +/* One entry within mux_assignment defines the port type and range of + * ports to add to the set_mux message. The end of the list is marked + * with count == 0. + */ +struct scarlett2_mux_entry { + u8 port_type; + u8 start; + u8 count; +}; + struct scarlett2_device_info { - u8 line_out_hw_vol; /* line out hw volume is sw controlled */ - u8 button_count; /* number of buttons */ - u8 level_input_count; /* inputs with level selectable */ - u8 pad_input_count; /* inputs with pad selectable */ + u32 usb_id; /* USB device identifier */ + + /* Gen 3 devices have an internal MSD mode switch that needs + * to be disabled in order to access the full functionality of + * the device. + */ + u8 has_msd_mode; + + /* Gen 3 devices without a mixer have a different + * configuration set + */ + u8 has_mixer; + + /* line out hw volume is sw controlled */ + u8 line_out_hw_vol; + + /* support for main/alt speaker switching */ + u8 has_speaker_switching; + + /* support for talkback microphone */ + u8 has_talkback; + + /* the number of analogue inputs with a software switchable + * level control that can be set to line or instrument + */ + u8 level_input_count; + + /* the first input with a level control (0-based) */ + u8 level_input_first; + + /* the number of analogue inputs with a software switchable + * 10dB pad control + */ + u8 pad_input_count; + + /* the number of analogue inputs with a software switchable + * "air" control + */ + u8 air_input_count; + + /* the number of phantom (48V) software switchable controls */ + u8 phantom_count; + + /* the number of inputs each phantom switch controls */ + u8 inputs_per_phantom; + + /* the number of direct monitor options + * (0 = none, 1 = mono only, 2 = mono/stereo) + */ + u8 direct_monitor; + + /* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected + * internally to the analogue 7/8 outputs + */ + u8 line_out_remap_enable; + u8 line_out_remap[SCARLETT2_ANALOGUE_MAX]; + + /* additional description for the line out volume controls */ const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; - struct scarlett2_ports ports[SCARLETT2_PORT_TYPE_COUNT]; + + /* number of sources/destinations of each port type */ + const int port_count[SCARLETT2_PORT_TYPE_COUNT][SCARLETT2_PORT_DIRNS]; + + /* layout/order of the entries in the set_mux message */ + struct scarlett2_mux_entry mux_assignment[SCARLETT2_MUX_TABLES] + [SCARLETT2_MAX_MUX_ENTRIES]; }; -struct scarlett2_mixer_data { +struct scarlett2_data { struct usb_mixer_interface *mixer; struct mutex usb_mutex; /* prevent sending concurrent USB requests */ struct mutex data_mutex; /* lock access to this data */ struct delayed_work work; const struct scarlett2_device_info *info; + __u8 bInterfaceNumber; + __u8 bEndpointAddress; + __u16 wMaxPacketSize; + __u8 bInterval; int num_mux_srcs; + int num_mux_dsts; u16 scarlett2_seq; + u8 sync_updated; u8 vol_updated; + u8 input_other_updated; + u8 monitor_other_updated; + u8 mux_updated; + u8 speaker_switching_switched; + u8 sync; u8 master_vol; u8 vol[SCARLETT2_ANALOGUE_MAX]; u8 vol_sw_hw_switch[SCARLETT2_ANALOGUE_MAX]; + u8 mute_switch[SCARLETT2_ANALOGUE_MAX]; u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX]; u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; - u8 buttons[SCARLETT2_BUTTON_MAX]; + u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; + u8 air_switch[SCARLETT2_AIR_SWITCH_MAX]; + u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX]; + u8 phantom_persistence; + u8 direct_monitor_switch; + u8 speaker_switching_switch; + u8 talkback_switch; + u8 talkback_map[SCARLETT2_OUTPUT_MIX_MAX]; + u8 msd_switch; + struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; - struct snd_kcontrol *button_ctls[SCARLETT2_BUTTON_MAX]; + struct snd_kcontrol *sw_hw_ctls[SCARLETT2_ANALOGUE_MAX]; + struct snd_kcontrol *mute_ctls[SCARLETT2_ANALOGUE_MAX]; + struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT]; + struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX]; + struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX]; + struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX]; + struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; + struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX]; + struct snd_kcontrol *direct_monitor_ctl; + struct snd_kcontrol *speaker_switching_ctl; + struct snd_kcontrol *talkback_ctl; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; }; @@ -245,66 +424,56 @@ struct scarlett2_mixer_data { /*** Model-specific data ***/ static const struct scarlett2_device_info s6i6_gen2_info = { - /* The first two analogue inputs can be switched between line - * and instrument levels. - */ - .level_input_count = 2, + .usb_id = USB_ID(0x1235, 0x8203), - /* The first two analogue inputs have an optional pad. */ + .has_mixer = 1, + .level_input_count = 2, .pad_input_count = 2, .line_out_descrs = { - "Monitor L", - "Monitor R", - "Headphones L", - "Headphones R", + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", }, - .ports = { - [SCARLETT2_PORT_TYPE_NONE] = { - .id = 0x000, - .num = { 1, 0, 8, 8, 8 }, - .src_descr = "Off", - .src_num_offset = 0, - }, - [SCARLETT2_PORT_TYPE_ANALOGUE] = { - .id = 0x080, - .num = { 4, 4, 4, 4, 4 }, - .src_descr = "Analogue %d", - .src_num_offset = 1, - .dst_descr = "Analogue Output %02d Playback" - }, - [SCARLETT2_PORT_TYPE_SPDIF] = { - .id = 0x180, - .num = { 2, 2, 2, 2, 2 }, - .src_descr = "S/PDIF %d", - .src_num_offset = 1, - .dst_descr = "S/PDIF Output %d Playback" - }, - [SCARLETT2_PORT_TYPE_MIX] = { - .id = 0x300, - .num = { 10, 18, 18, 18, 18 }, - .src_descr = "Mix %c", - .src_num_offset = 65, - .dst_descr = "Mixer Input %02d Capture" - }, - [SCARLETT2_PORT_TYPE_PCM] = { - .id = 0x600, - .num = { 6, 6, 6, 6, 6 }, - .src_descr = "PCM %d", - .src_num_offset = 1, - .dst_descr = "PCM %02d Capture" - }, + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 4, 4 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_MIX] = { 10, 18 }, + [SCARLETT2_PORT_TYPE_PCM] = { 6, 6 }, }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 8 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 8 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 8 }, + { 0, 0, 0 }, + } }, }; static const struct scarlett2_device_info s18i8_gen2_info = { - /* The first two analogue inputs can be switched between line - * and instrument levels. - */ - .level_input_count = 2, + .usb_id = USB_ID(0x1235, 0x8204), - /* The first four analogue inputs have an optional pad. */ + .has_mixer = 1, + .level_input_count = 2, .pad_input_count = 4, .line_out_descrs = { @@ -316,62 +485,44 @@ static const struct scarlett2_device_info s18i8_gen2_info = { "Headphones 2 R", }, - .ports = { - [SCARLETT2_PORT_TYPE_NONE] = { - .id = 0x000, - .num = { 1, 0, 8, 8, 4 }, - .src_descr = "Off", - .src_num_offset = 0, - }, - [SCARLETT2_PORT_TYPE_ANALOGUE] = { - .id = 0x080, - .num = { 8, 6, 6, 6, 6 }, - .src_descr = "Analogue %d", - .src_num_offset = 1, - .dst_descr = "Analogue Output %02d Playback" - }, - [SCARLETT2_PORT_TYPE_SPDIF] = { - .id = 0x180, - /* S/PDIF outputs aren't available at 192kHz - * but are included in the USB mux I/O - * assignment message anyway - */ - .num = { 2, 2, 2, 2, 2 }, - .src_descr = "S/PDIF %d", - .src_num_offset = 1, - .dst_descr = "S/PDIF Output %d Playback" - }, - [SCARLETT2_PORT_TYPE_ADAT] = { - .id = 0x200, - .num = { 8, 0, 0, 0, 0 }, - .src_descr = "ADAT %d", - .src_num_offset = 1, - }, - [SCARLETT2_PORT_TYPE_MIX] = { - .id = 0x300, - .num = { 10, 18, 18, 18, 18 }, - .src_descr = "Mix %c", - .src_num_offset = 65, - .dst_descr = "Mixer Input %02d Capture" - }, - [SCARLETT2_PORT_TYPE_PCM] = { - .id = 0x600, - .num = { 20, 18, 18, 14, 10 }, - .src_descr = "PCM %d", - .src_num_offset = 1, - .dst_descr = "PCM %02d Capture" - }, + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 8, 6 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_ADAT] = { 8, 0 }, + [SCARLETT2_PORT_TYPE_MIX] = { 10, 18 }, + [SCARLETT2_PORT_TYPE_PCM] = { 8, 18 }, }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 18 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 6 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 8 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 14 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 6 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 8 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 6 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 4 }, + { 0, 0, 0 }, + } }, }; static const struct scarlett2_device_info s18i20_gen2_info = { - /* The analogue line outputs on the 18i20 can be switched - * between software and hardware volume control - */ - .line_out_hw_vol = 1, + .usb_id = USB_ID(0x1235, 0x8201), - /* Mute and dim buttons */ - .button_count = 2, + .has_mixer = 1, + .line_out_hw_vol = 1, .line_out_descrs = { "Monitor L", @@ -386,99 +537,364 @@ static const struct scarlett2_device_info s18i20_gen2_info = { "Headphones 2 R", }, - .ports = { - [SCARLETT2_PORT_TYPE_NONE] = { - .id = 0x000, - .num = { 1, 0, 8, 8, 6 }, - .src_descr = "Off", - .src_num_offset = 0, - }, - [SCARLETT2_PORT_TYPE_ANALOGUE] = { - .id = 0x080, - .num = { 8, 10, 10, 10, 10 }, - .src_descr = "Analogue %d", - .src_num_offset = 1, - .dst_descr = "Analogue Output %02d Playback" - }, - [SCARLETT2_PORT_TYPE_SPDIF] = { - /* S/PDIF outputs aren't available at 192kHz - * but are included in the USB mux I/O - * assignment message anyway - */ - .id = 0x180, - .num = { 2, 2, 2, 2, 2 }, - .src_descr = "S/PDIF %d", - .src_num_offset = 1, - .dst_descr = "S/PDIF Output %d Playback" - }, - [SCARLETT2_PORT_TYPE_ADAT] = { - .id = 0x200, - .num = { 8, 8, 8, 4, 0 }, - .src_descr = "ADAT %d", - .src_num_offset = 1, - .dst_descr = "ADAT Output %d Playback" - }, - [SCARLETT2_PORT_TYPE_MIX] = { - .id = 0x300, - .num = { 10, 18, 18, 18, 18 }, - .src_descr = "Mix %c", - .src_num_offset = 65, - .dst_descr = "Mixer Input %02d Capture" - }, - [SCARLETT2_PORT_TYPE_PCM] = { - .id = 0x600, - .num = { 20, 18, 18, 14, 10 }, - .src_descr = "PCM %d", - .src_num_offset = 1, - .dst_descr = "PCM %02d Capture" - }, + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 8, 10 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_ADAT] = { 8, 8 }, + [SCARLETT2_PORT_TYPE_MIX] = { 10, 18 }, + [SCARLETT2_PORT_TYPE_PCM] = { 20, 18 }, }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 18 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_ADAT, 0, 8 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 8 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 14 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_ADAT, 0, 4 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 8 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 18 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 6 }, + { 0, 0, 0 }, + } }, +}; + +static const struct scarlett2_device_info solo_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8211), + + .has_msd_mode = 1, + .level_input_count = 1, + .level_input_first = 1, + .air_input_count = 1, + .phantom_count = 1, + .inputs_per_phantom = 1, + .direct_monitor = 1, +}; + +static const struct scarlett2_device_info s2i2_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8210), + + .has_msd_mode = 1, + .level_input_count = 2, + .air_input_count = 2, + .phantom_count = 1, + .inputs_per_phantom = 2, + .direct_monitor = 2, +}; + +static const struct scarlett2_device_info s4i4_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8212), + + .has_msd_mode = 1, + .has_mixer = 1, + .level_input_count = 2, + .pad_input_count = 2, + .air_input_count = 2, + .phantom_count = 1, + .inputs_per_phantom = 2, + + .line_out_descrs = { + "Monitor L", + "Monitor R", + "Headphones L", + "Headphones R", + }, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 4, 4 }, + [SCARLETT2_PORT_TYPE_MIX] = { 6, 8 }, + [SCARLETT2_PORT_TYPE_PCM] = { 4, 6 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 16 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 16 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 16 }, + { 0, 0, 0 }, + } }, +}; + +static const struct scarlett2_device_info s8i6_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8213), + + .has_msd_mode = 1, + .has_mixer = 1, + .level_input_count = 2, + .pad_input_count = 2, + .air_input_count = 2, + .phantom_count = 1, + .inputs_per_phantom = 2, + + .line_out_descrs = { + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", + }, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 6, 4 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_MIX] = { 8, 8 }, + [SCARLETT2_PORT_TYPE_PCM] = { 6, 10 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 18 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 18 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 18 }, + { 0, 0, 0 }, + } }, +}; + +static const struct scarlett2_device_info s18i8_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8214), + + .has_msd_mode = 1, + .has_mixer = 1, + .line_out_hw_vol = 1, + .has_speaker_switching = 1, + .level_input_count = 2, + .pad_input_count = 4, + .air_input_count = 4, + .phantom_count = 2, + .inputs_per_phantom = 2, + + .line_out_remap_enable = 1, + .line_out_remap = { 0, 1, 6, 7, 2, 3, 4, 5 }, + + .line_out_descrs = { + "Monitor L", + "Monitor R", + "Alt Monitor L", + "Alt Monitor R", + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", + }, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 8, 8 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_ADAT] = { 8, 0 }, + [SCARLETT2_PORT_TYPE_MIX] = { 10, 20 }, + [SCARLETT2_PORT_TYPE_PCM] = { 8, 20 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_PCM, 12, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 6, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 2, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 10, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 20 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 10 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_PCM, 12, 4 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 6, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 2, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 10, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 20 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 10 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 6, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 2, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 20 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 10 }, + { 0, 0, 0 }, + } }, +}; + +static const struct scarlett2_device_info s18i20_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8215), + + .has_msd_mode = 1, + .has_mixer = 1, + .line_out_hw_vol = 1, + .has_speaker_switching = 1, + .has_talkback = 1, + .level_input_count = 2, + .pad_input_count = 8, + .air_input_count = 8, + .phantom_count = 2, + .inputs_per_phantom = 4, + + .line_out_descrs = { + "Monitor 1 L", + "Monitor 1 R", + "Monitor 2 L", + "Monitor 2 R", + NULL, + NULL, + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", + }, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 9, 10 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_ADAT] = { 8, 8 }, + [SCARLETT2_PORT_TYPE_MIX] = { 12, 25 }, + [SCARLETT2_PORT_TYPE_PCM] = { 20, 20 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_PCM, 10, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_ADAT, 0, 8 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 25 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 12 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_PCM, 10, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_ADAT, 0, 8 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 25 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 10 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 24 }, + { 0, 0, 0 }, + } }, +}; + +static const struct scarlett2_device_info *scarlett2_devices[] = { + /* Supported Gen 2 devices */ + &s6i6_gen2_info, + &s18i8_gen2_info, + &s18i20_gen2_info, + + /* Supported Gen 3 devices */ + &solo_gen3_info, + &s2i2_gen3_info, + &s4i4_gen3_info, + &s8i6_gen3_info, + &s18i8_gen3_info, + &s18i20_gen3_info, + + /* End of list */ + NULL }; /* get the starting port index number for a given port type/direction */ -static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports, - int direction, int port_type) +static int scarlett2_get_port_start_num( + const int port_count[][SCARLETT2_PORT_DIRNS], + int direction, int port_type) { int i, num = 0; for (i = 0; i < port_type; i++) - num += ports[i].num[direction]; + num += port_count[i][direction]; return num; } /*** USB Interactions ***/ -/* Vendor-Specific Interface, Endpoint, MaxPacketSize, Interval */ -#define SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE 5 -#define SCARLETT2_USB_INTERRUPT_ENDPOINT 4 -#define SCARLETT2_USB_INTERRUPT_MAX_DATA 64 -#define SCARLETT2_USB_INTERRUPT_INTERVAL 3 - -/* Interrupt flags for volume and mute/dim button changes */ -#define SCARLETT2_USB_INTERRUPT_VOL_CHANGE 0x400000 -#define SCARLETT2_USB_INTERRUPT_BUTTON_CHANGE 0x200000 +/* Notifications from the interface */ +#define SCARLETT2_USB_NOTIFY_SYNC 0x00000008 +#define SCARLETT2_USB_NOTIFY_DIM_MUTE 0x00200000 +#define SCARLETT2_USB_NOTIFY_MONITOR 0x00400000 +#define SCARLETT2_USB_NOTIFY_INPUT_OTHER 0x00800000 +#define SCARLETT2_USB_NOTIFY_MONITOR_OTHER 0x01000000 /* Commands for sending/receiving requests/responses */ -#define SCARLETT2_USB_VENDOR_SPECIFIC_CMD_REQ 2 -#define SCARLETT2_USB_VENDOR_SPECIFIC_CMD_RESP 3 - -#define SCARLETT2_USB_INIT_SEQ 0x00000000 -#define SCARLETT2_USB_GET_METER_LEVELS 0x00001001 -#define SCARLETT2_USB_SET_MIX 0x00002002 -#define SCARLETT2_USB_SET_MUX 0x00003002 -#define SCARLETT2_USB_GET_DATA 0x00800000 -#define SCARLETT2_USB_SET_DATA 0x00800001 -#define SCARLETT2_USB_DATA_CMD 0x00800002 +#define SCARLETT2_USB_CMD_INIT 0 +#define SCARLETT2_USB_CMD_REQ 2 +#define SCARLETT2_USB_CMD_RESP 3 + +#define SCARLETT2_USB_INIT_1 0x00000000 +#define SCARLETT2_USB_INIT_2 0x00000002 +#define SCARLETT2_USB_GET_METER 0x00001001 +#define SCARLETT2_USB_GET_MIX 0x00002001 +#define SCARLETT2_USB_SET_MIX 0x00002002 +#define SCARLETT2_USB_GET_MUX 0x00003001 +#define SCARLETT2_USB_SET_MUX 0x00003002 +#define SCARLETT2_USB_GET_SYNC 0x00006004 +#define SCARLETT2_USB_GET_DATA 0x00800000 +#define SCARLETT2_USB_SET_DATA 0x00800001 +#define SCARLETT2_USB_DATA_CMD 0x00800002 + #define SCARLETT2_USB_CONFIG_SAVE 6 #define SCARLETT2_USB_VOLUME_STATUS_OFFSET 0x31 #define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1 -/* volume status is read together (matches scarlett2_config_items[]) */ +/* volume status is read together (matches scarlett2_config_items[1]) */ struct scarlett2_usb_volume_status { - /* mute & dim buttons */ - u8 buttons[SCARLETT2_BUTTON_MAX]; + /* dim/mute buttons */ + u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; u8 pad1; @@ -488,7 +904,8 @@ struct scarlett2_usb_volume_status { /* actual volume of output inc. dim (-18dB) */ s16 hw_vol[SCARLETT2_ANALOGUE_MAX]; - u8 pad2[SCARLETT2_ANALOGUE_MAX]; + /* internal mute buttons */ + u8 mute_switch[SCARLETT2_ANALOGUE_MAX]; /* sw (0) or hw (1) controlled */ u8 sw_hw_switch[SCARLETT2_ANALOGUE_MAX]; @@ -501,16 +918,25 @@ struct scarlett2_usb_volume_status { /* Configuration parameters that can be read and written */ enum { - SCARLETT2_CONFIG_BUTTONS = 0, + SCARLETT2_CONFIG_DIM_MUTE = 0, SCARLETT2_CONFIG_LINE_OUT_VOLUME = 1, - SCARLETT2_CONFIG_SW_HW_SWITCH = 2, - SCARLETT2_CONFIG_LEVEL_SWITCH = 3, - SCARLETT2_CONFIG_PAD_SWITCH = 4, - SCARLETT2_CONFIG_COUNT = 5 + SCARLETT2_CONFIG_MUTE_SWITCH = 2, + SCARLETT2_CONFIG_SW_HW_SWITCH = 3, + SCARLETT2_CONFIG_LEVEL_SWITCH = 4, + SCARLETT2_CONFIG_PAD_SWITCH = 5, + SCARLETT2_CONFIG_MSD_SWITCH = 6, + SCARLETT2_CONFIG_AIR_SWITCH = 7, + SCARLETT2_CONFIG_PHANTOM_SWITCH = 8, + SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 9, + SCARLETT2_CONFIG_DIRECT_MONITOR = 10, + SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH = 11, + SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE = 12, + SCARLETT2_CONFIG_TALKBACK_MAP = 13, + SCARLETT2_CONFIG_COUNT = 14 }; /* Location, size, and activation command number for the configuration - * parameters + * parameters. Size is in bits and may be 1, 8, or 16. */ struct scarlett2_config { u8 offset; @@ -518,43 +944,73 @@ struct scarlett2_config { u8 activate; }; +/* scarlett2_config_items[0] is for devices without a mixer + * scarlett2_config_items[1] is for devices with a mixer + */ static const struct scarlett2_config - scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = { - /* Mute/Dim Buttons */ - { - .offset = 0x31, - .size = 1, - .activate = 2 - }, + scarlett2_config_items[2][SCARLETT2_CONFIG_COUNT] = - /* Line Out Volume */ - { - .offset = 0x34, - .size = 2, - .activate = 1 - }, +/* Devices without a mixer (Solo and 2i2 Gen 3) */ +{ { + [SCARLETT2_CONFIG_MSD_SWITCH] = { + .offset = 0x04, .size = 8, .activate = 6 }, - /* SW/HW Volume Switch */ - { - .offset = 0x66, - .size = 1, - .activate = 3 - }, + [SCARLETT2_CONFIG_PHANTOM_PERSISTENCE] = { + .offset = 0x05, .size = 8, .activate = 6 }, - /* Level Switch */ - { - .offset = 0x7c, - .size = 1, - .activate = 7 - }, + [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { + .offset = 0x06, .size = 8, .activate = 3 }, - /* Pad Switch */ - { - .offset = 0x84, - .size = 1, - .activate = 8 - } -}; + [SCARLETT2_CONFIG_DIRECT_MONITOR] = { + .offset = 0x07, .size = 8, .activate = 4 }, + + [SCARLETT2_CONFIG_LEVEL_SWITCH] = { + .offset = 0x08, .size = 1, .activate = 7 }, + + [SCARLETT2_CONFIG_AIR_SWITCH] = { + .offset = 0x09, .size = 1, .activate = 8 }, + +/* Devices with a mixer (Gen 2 and all other Gen 3) */ +}, { + [SCARLETT2_CONFIG_DIM_MUTE] = { + .offset = 0x31, .size = 8, .activate = 2 }, + + [SCARLETT2_CONFIG_LINE_OUT_VOLUME] = { + .offset = 0x34, .size = 16, .activate = 1 }, + + [SCARLETT2_CONFIG_MUTE_SWITCH] = { + .offset = 0x5c, .size = 8, .activate = 1 }, + + [SCARLETT2_CONFIG_SW_HW_SWITCH] = { + .offset = 0x66, .size = 8, .activate = 3 }, + + [SCARLETT2_CONFIG_LEVEL_SWITCH] = { + .offset = 0x7c, .size = 8, .activate = 7 }, + + [SCARLETT2_CONFIG_PAD_SWITCH] = { + .offset = 0x84, .size = 8, .activate = 8 }, + + [SCARLETT2_CONFIG_AIR_SWITCH] = { + .offset = 0x8c, .size = 8, .activate = 8 }, + + [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { + .offset = 0x9c, .size = 1, .activate = 8 }, + + [SCARLETT2_CONFIG_MSD_SWITCH] = { + .offset = 0x9d, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_PHANTOM_PERSISTENCE] = { + .offset = 0x9e, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH] = { + .offset = 0x9f, .size = 1, .activate = 10 }, + + [SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE] = { + .offset = 0xa0, .size = 1, .activate = 10 }, + + [SCARLETT2_CONFIG_TALKBACK_MAP] = { + .offset = 0xb0, .size = 16, .activate = 10 }, +} }; /* proprietary request/response format */ struct scarlett2_usb_packet { @@ -566,9 +1022,7 @@ struct scarlett2_usb_packet { u8 data[]; }; -#define SCARLETT2_USB_PACKET_LEN (sizeof(struct scarlett2_usb_packet)) - -static void scarlett2_fill_request_header(struct scarlett2_mixer_data *private, +static void scarlett2_fill_request_header(struct scarlett2_data *private, struct scarlett2_usb_packet *req, u32 cmd, u16 req_size) { @@ -582,16 +1036,35 @@ static void scarlett2_fill_request_header(struct scarlett2_mixer_data *private, req->pad = 0; } +static int scarlett2_usb_tx(struct usb_device *dev, int interface, + void *buf, u16 size) +{ + return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + SCARLETT2_USB_CMD_REQ, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + 0, interface, buf, size); +} + +static int scarlett2_usb_rx(struct usb_device *dev, int interface, + u32 usb_req, void *buf, u16 size) +{ + return snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + usb_req, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + 0, interface, buf, size); +} + /* Send a proprietary format request to the Scarlett interface */ static int scarlett2_usb( struct usb_mixer_interface *mixer, u32 cmd, void *req_data, u16 req_size, void *resp_data, u16 resp_size) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; + struct usb_device *dev = mixer->chip->dev; u16 req_buf_size = sizeof(struct scarlett2_usb_packet) + req_size; u16 resp_buf_size = sizeof(struct scarlett2_usb_packet) + resp_size; - struct scarlett2_usb_packet *req = NULL, *resp = NULL; - int err = 0; + struct scarlett2_usb_packet *req, *resp = NULL; + int err; req = kmalloc(req_buf_size, GFP_KERNEL); if (!req) { @@ -614,19 +1087,13 @@ static int scarlett2_usb( if (req_size) memcpy(req->data, req_data, req_size); - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), - SCARLETT2_USB_VENDOR_SPECIFIC_CMD_REQ, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - 0, - SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE, - req, - req_buf_size); + err = scarlett2_usb_tx(dev, private->bInterfaceNumber, + req, req_buf_size); if (err != req_buf_size) { usb_audio_err( mixer->chip, - "Scarlett Gen 2 USB request result cmd %x was %d\n", + "Scarlett Gen 2/3 USB request result cmd %x was %d\n", cmd, err); err = -EINVAL; goto unlock; @@ -634,34 +1101,34 @@ static int scarlett2_usb( /* send a second message to get the response */ - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_rcvctrlpipe(mixer->chip->dev, 0), - SCARLETT2_USB_VENDOR_SPECIFIC_CMD_RESP, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - 0, - SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE, - resp, - resp_buf_size); + err = scarlett2_usb_rx(dev, private->bInterfaceNumber, + SCARLETT2_USB_CMD_RESP, + resp, resp_buf_size); /* validate the response */ if (err != resp_buf_size) { usb_audio_err( mixer->chip, - "Scarlett Gen 2 USB response result cmd %x was %d\n", - cmd, err); + "Scarlett Gen 2/3 USB response result cmd %x was %d " + "expected %d\n", + cmd, err, resp_buf_size); err = -EINVAL; goto unlock; } + /* cmd/seq/size should match except when initialising + * seq sent = 1, response = 0 + */ if (resp->cmd != req->cmd || - resp->seq != req->seq || + (resp->seq != req->seq && + (le16_to_cpu(req->seq) != 1 || resp->seq != 0)) || resp_size != le16_to_cpu(resp->size) || resp->error || resp->pad) { usb_audio_err( mixer->chip, - "Scarlett Gen 2 USB invalid response; " + "Scarlett Gen 2/3 USB invalid response; " "cmd tx/rx %d/%d seq %d/%d size %d/%d " "error %d pad %d\n", le32_to_cpu(req->cmd), le32_to_cpu(resp->cmd), @@ -673,7 +1140,7 @@ static int scarlett2_usb( goto unlock; } - if (resp_size > 0) + if (resp_data && resp_size > 0) memcpy(resp_data, resp->data, resp_size); unlock: @@ -684,6 +1151,63 @@ error: return err; } +/* Send a USB message to get data; result placed in *buf */ +static int scarlett2_usb_get( + struct usb_mixer_interface *mixer, + int offset, void *buf, int size) +{ + struct { + __le32 offset; + __le32 size; + } __packed req; + + req.offset = cpu_to_le32(offset); + req.size = cpu_to_le32(size); + return scarlett2_usb(mixer, SCARLETT2_USB_GET_DATA, + &req, sizeof(req), buf, size); +} + +/* Send a USB message to get configuration parameters; result placed in *buf */ +static int scarlett2_usb_get_config( + struct usb_mixer_interface *mixer, + int config_item_num, int count, void *buf) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const struct scarlett2_config *config_item = + &scarlett2_config_items[info->has_mixer][config_item_num]; + int size, err, i; + u8 *buf_8; + u8 value; + + /* For byte-sized parameters, retrieve directly into buf */ + if (config_item->size >= 8) { + size = config_item->size / 8 * count; + err = scarlett2_usb_get(mixer, config_item->offset, buf, size); + if (err < 0) + return err; + if (size == 2) { + u16 *buf_16 = buf; + + for (i = 0; i < count; i++, buf_16++) + *buf_16 = le16_to_cpu(*(__le16 *)buf_16); + } + return 0; + } + + /* For bit-sized parameters, retrieve into value */ + err = scarlett2_usb_get(mixer, config_item->offset, &value, 1); + if (err < 0) + return err; + + /* then unpack from value into buf[] */ + buf_8 = buf; + for (i = 0; i < 8 && i < count; i++, value >>= 1) + *buf_8++ = value & 1; + + return 0; +} + /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */ static void scarlett2_config_save(struct usb_mixer_interface *mixer) { @@ -697,82 +1221,97 @@ static void scarlett2_config_save(struct usb_mixer_interface *mixer) /* Delayed work to save config */ static void scarlett2_config_save_work(struct work_struct *work) { - struct scarlett2_mixer_data *private = - container_of(work, struct scarlett2_mixer_data, work.work); + struct scarlett2_data *private = + container_of(work, struct scarlett2_data, work.work); scarlett2_config_save(private->mixer); } -/* Send a USB message to set a configuration parameter (volume level, - * sw/hw volume switch, line/inst level switch, or pad switch) - */ +/* Send a USB message to set a SCARLETT2_CONFIG_* parameter */ static int scarlett2_usb_set_config( struct usb_mixer_interface *mixer, int config_item_num, int index, int value) { - const struct scarlett2_config config_item = - scarlett2_config_items[config_item_num]; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const struct scarlett2_config *config_item = + &scarlett2_config_items[info->has_mixer][config_item_num]; struct { __le32 offset; __le32 bytes; __le32 value; } __packed req; __le32 req2; + int offset, size; int err; - struct scarlett2_mixer_data *private = mixer->private_data; /* Cancel any pending NVRAM save */ cancel_delayed_work_sync(&private->work); + /* Convert config_item->size in bits to size in bytes and + * calculate offset + */ + if (config_item->size >= 8) { + size = config_item->size / 8; + offset = config_item->offset + index * size; + + /* If updating a bit, retrieve the old value, set/clear the + * bit as needed, and update value + */ + } else { + u8 tmp; + + size = 1; + offset = config_item->offset; + + scarlett2_usb_get(mixer, offset, &tmp, 1); + if (value) + tmp |= (1 << index); + else + tmp &= ~(1 << index); + + value = tmp; + } + /* Send the configuration parameter data */ - req.offset = cpu_to_le32(config_item.offset + index * config_item.size); - req.bytes = cpu_to_le32(config_item.size); + req.offset = cpu_to_le32(offset); + req.bytes = cpu_to_le32(size); req.value = cpu_to_le32(value); err = scarlett2_usb(mixer, SCARLETT2_USB_SET_DATA, - &req, sizeof(u32) * 2 + config_item.size, + &req, sizeof(u32) * 2 + size, NULL, 0); if (err < 0) return err; /* Activate the change */ - req2 = cpu_to_le32(config_item.activate); + req2 = cpu_to_le32(config_item->activate); err = scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD, &req2, sizeof(req2), NULL, 0); if (err < 0) return err; /* Schedule the change to be written to NVRAM */ - schedule_delayed_work(&private->work, msecs_to_jiffies(2000)); + if (config_item->activate != SCARLETT2_USB_CONFIG_SAVE) + schedule_delayed_work(&private->work, msecs_to_jiffies(2000)); return 0; } -/* Send a USB message to get data; result placed in *buf */ -static int scarlett2_usb_get( +/* Send a USB message to get sync status; result placed in *sync */ +static int scarlett2_usb_get_sync_status( struct usb_mixer_interface *mixer, - int offset, void *buf, int size) + u8 *sync) { - struct { - __le32 offset; - __le32 size; - } __packed req; - - req.offset = cpu_to_le32(offset); - req.size = cpu_to_le32(size); - return scarlett2_usb(mixer, SCARLETT2_USB_GET_DATA, - &req, sizeof(req), buf, size); -} + __le32 data; + int err; -/* Send a USB message to get configuration parameters; result placed in *buf */ -static int scarlett2_usb_get_config( - struct usb_mixer_interface *mixer, - int config_item_num, int count, void *buf) -{ - const struct scarlett2_config config_item = - scarlett2_config_items[config_item_num]; - int size = config_item.size * count; + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_SYNC, + NULL, 0, &data, sizeof(data)); + if (err < 0) + return err; - return scarlett2_usb_get(mixer, config_item.offset, buf, size); + *sync = !!data; + return 0; } /* Send a USB message to get volume status; result placed in *buf */ @@ -784,13 +1323,56 @@ static int scarlett2_usb_get_volume_status( buf, sizeof(*buf)); } +/* Send a USB message to get the volumes for all inputs of one mix + * and put the values into private->mix[] + */ +static int scarlett2_usb_get_mix(struct usb_mixer_interface *mixer, + int mix_num) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + int num_mixer_in = + info->port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT]; + int err, i, j, k; + + struct { + __le16 mix_num; + __le16 count; + } __packed req; + + __le16 data[SCARLETT2_INPUT_MIX_MAX]; + + req.mix_num = cpu_to_le16(mix_num); + req.count = cpu_to_le16(num_mixer_in); + + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_MIX, + &req, sizeof(req), + data, num_mixer_in * sizeof(u16)); + if (err < 0) + return err; + + for (i = 0, j = mix_num * num_mixer_in; i < num_mixer_in; i++, j++) { + u16 mixer_value = le16_to_cpu(data[i]); + + for (k = 0; k < SCARLETT2_MIXER_VALUE_COUNT; k++) + if (scarlett2_mixer_values[k] >= mixer_value) + break; + if (k == SCARLETT2_MIXER_VALUE_COUNT) + k = SCARLETT2_MIXER_MAX_VALUE; + private->mix[j] = k; + } + + return 0; +} + /* Send a USB message to set the volumes for all inputs of one mix * (values obtained from private->mix[]) */ static int scarlett2_usb_set_mix(struct usb_mixer_interface *mixer, - int mix_num) + int mix_num) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; struct { @@ -800,7 +1382,7 @@ static int scarlett2_usb_set_mix(struct usb_mixer_interface *mixer, int i, j; int num_mixer_in = - info->ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; + info->port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT]; req.mix_num = cpu_to_le16(mix_num); @@ -814,40 +1396,120 @@ static int scarlett2_usb_set_mix(struct usb_mixer_interface *mixer, NULL, 0); } -/* Convert a port number index (per info->ports) to a hardware ID */ -static u32 scarlett2_mux_src_num_to_id(const struct scarlett2_ports *ports, - int num) +/* Convert a port number index (per info->port_count) to a hardware ID */ +static u32 scarlett2_mux_src_num_to_id( + const int port_count[][SCARLETT2_PORT_DIRNS], int num) +{ + int port_type; + + for (port_type = 0; + port_type < SCARLETT2_PORT_TYPE_COUNT; + port_type++) { + if (num < port_count[port_type][SCARLETT2_PORT_IN]) + return scarlett2_ports[port_type].id | num; + num -= port_count[port_type][SCARLETT2_PORT_IN]; + } + + /* Oops */ + return 0; +} + +/* Convert a hardware ID to a port number index */ +static u32 scarlett2_mux_id_to_num( + const int port_count[][SCARLETT2_PORT_DIRNS], int direction, u32 id) { int port_type; + int port_num = 0; for (port_type = 0; port_type < SCARLETT2_PORT_TYPE_COUNT; port_type++) { - if (num < ports[port_type].num[SCARLETT2_PORT_IN]) - return ports[port_type].id | num; - num -= ports[port_type].num[SCARLETT2_PORT_IN]; + int base = scarlett2_ports[port_type].id; + int count = port_count[port_type][direction]; + + if (id >= base && id < base + count) + return port_num + id - base; + port_num += count; } /* Oops */ + return -1; +} + +/* Convert one mux entry from the interface and load into private->mux[] */ +static void scarlett2_usb_populate_mux(struct scarlett2_data *private, + u32 mux_entry) +{ + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + + int dst_idx, src_idx; + + dst_idx = scarlett2_mux_id_to_num(port_count, SCARLETT2_PORT_OUT, + mux_entry & 0xFFF); + if (dst_idx < 0) + return; + + if (dst_idx >= private->num_mux_dsts) { + usb_audio_err(private->mixer->chip, + "BUG: scarlett2_mux_id_to_num(%06x, OUT): %d >= %d", + mux_entry, dst_idx, private->num_mux_dsts); + return; + } + + src_idx = scarlett2_mux_id_to_num(port_count, SCARLETT2_PORT_IN, + mux_entry >> 12); + if (src_idx < 0) + return; + + if (src_idx >= private->num_mux_srcs) { + usb_audio_err(private->mixer->chip, + "BUG: scarlett2_mux_id_to_num(%06x, IN): %d >= %d", + mux_entry, src_idx, private->num_mux_srcs); + return; + } + + private->mux[dst_idx] = src_idx; +} + +/* Send USB message to get mux inputs and then populate private->mux[] */ +static int scarlett2_usb_get_mux(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + int count = private->num_mux_dsts; + int err, i; + + struct { + __le16 num; + __le16 count; + } __packed req; + + __le32 data[SCARLETT2_MUX_MAX]; + + private->mux_updated = 0; + + req.num = 0; + req.count = cpu_to_le16(count); + + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_MUX, + &req, sizeof(req), + data, count * sizeof(u32)); + if (err < 0) + return err; + + for (i = 0; i < count; i++) + scarlett2_usb_populate_mux(private, le32_to_cpu(data[i])); + return 0; } /* Send USB messages to set mux inputs */ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - const struct scarlett2_ports *ports = info->ports; - int rate, port_dir_rate; - - static const int assignment_order[SCARLETT2_PORT_TYPE_COUNT] = { - SCARLETT2_PORT_TYPE_PCM, - SCARLETT2_PORT_TYPE_ANALOGUE, - SCARLETT2_PORT_TYPE_SPDIF, - SCARLETT2_PORT_TYPE_ADAT, - SCARLETT2_PORT_TYPE_MIX, - SCARLETT2_PORT_TYPE_NONE, - }; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int table; struct { __le16 pad; @@ -857,43 +1519,44 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) req.pad = 0; - /* mux settings for each rate */ - for (rate = 0, port_dir_rate = SCARLETT2_PORT_OUT_44; - port_dir_rate <= SCARLETT2_PORT_OUT_176; - rate++, port_dir_rate++) { - int order_num, i, err; - - req.num = cpu_to_le16(rate); - - for (order_num = 0, i = 0; - order_num < SCARLETT2_PORT_TYPE_COUNT; - order_num++) { - int port_type = assignment_order[order_num]; - int j = scarlett2_get_port_start_num(ports, - SCARLETT2_PORT_OUT, - port_type); - int port_id = ports[port_type].id; - int channel; - - for (channel = 0; - channel < ports[port_type].num[port_dir_rate]; - channel++, i++, j++) - /* lower 12 bits for the destination and - * next 12 bits for the source - */ - req.data[i] = !port_id - ? 0 - : cpu_to_le32( - port_id | - channel | - scarlett2_mux_src_num_to_id( - ports, private->mux[j] - ) << 12 - ); - - /* skip private->mux[j] entries not output */ - j += ports[port_type].num[SCARLETT2_PORT_OUT] - - ports[port_type].num[port_dir_rate]; + /* set mux settings for each rate */ + for (table = 0; table < SCARLETT2_MUX_TABLES; table++) { + const struct scarlett2_mux_entry *entry; + + /* i counts over the output array */ + int i = 0, err; + + req.num = cpu_to_le16(table); + + /* loop through each entry */ + for (entry = info->mux_assignment[table]; + entry->count; + entry++) { + int j; + int port_type = entry->port_type; + int port_idx = entry->start; + int mux_idx = scarlett2_get_port_start_num(port_count, + SCARLETT2_PORT_OUT, port_type) + port_idx; + int dst_id = scarlett2_ports[port_type].id + port_idx; + + /* Empty slots */ + if (!dst_id) { + for (j = 0; j < entry->count; j++) + req.data[i++] = 0; + continue; + } + + /* Non-empty mux slots use the lower 12 bits + * for the destination and next 12 bits for + * the source + */ + for (j = 0; j < entry->count; j++) { + int src_id = scarlett2_mux_src_num_to_id( + port_count, private->mux[mux_idx++]); + req.data[i++] = cpu_to_le32(dst_id | + src_id << 12); + dst_id++; + } } err = scarlett2_usb(mixer, SCARLETT2_USB_SET_MUX, @@ -908,26 +1571,26 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) /* Send USB message to get meter levels */ static int scarlett2_usb_get_meter_levels(struct usb_mixer_interface *mixer, - u16 *levels) + u16 num_meters, u16 *levels) { struct { __le16 pad; __le16 num_meters; __le32 magic; } __packed req; - u32 resp[SCARLETT2_NUM_METERS]; + u32 resp[SCARLETT2_MAX_METERS]; int i, err; req.pad = 0; - req.num_meters = cpu_to_le16(SCARLETT2_NUM_METERS); + req.num_meters = cpu_to_le16(num_meters); req.magic = cpu_to_le32(SCARLETT2_USB_METER_LEVELS_GET_MAGIC); - err = scarlett2_usb(mixer, SCARLETT2_USB_GET_METER_LEVELS, - &req, sizeof(req), resp, sizeof(resp)); + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_METER, + &req, sizeof(req), resp, num_meters * sizeof(u32)); if (err < 0) return err; /* copy, convert to u16 */ - for (i = 0; i < SCARLETT2_NUM_METERS; i++) + for (i = 0; i < num_meters; i++) levels[i] = resp[i]; return 0; @@ -949,10 +1612,15 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer, if (!elem) return -ENOMEM; + /* We set USB_MIXER_BESPOKEN type, so that the core USB mixer code + * ignores them for resume and other operations. + * Also, the head.id field is set to 0, as we don't use this field. + */ elem->head.mixer = mixer; elem->control = index; - elem->head.id = index; + elem->head.id = 0; elem->channels = channels; + elem->val_type = USB_MIXER_BESPOKEN; kctl = snd_ctl_new1(ncontrol, elem); if (!kctl) { @@ -973,6 +1641,64 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer, return 0; } +/*** Sync Control ***/ + +/* Update sync control after receiving notification that the status + * has changed + */ +static int scarlett2_update_sync(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + private->sync_updated = 0; + return scarlett2_usb_get_sync_status(mixer, &private->sync); +} + +static int scarlett2_sync_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + static const char *texts[2] = { + "Unlocked", "Locked" + }; + return snd_ctl_enum_info(uinfo, 1, 2, texts); +} + +static int scarlett2_sync_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->sync_updated) + scarlett2_update_sync(mixer); + ucontrol->value.enumerated.item[0] = private->sync; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static const struct snd_kcontrol_new scarlett2_sync_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .name = "", + .info = scarlett2_sync_ctl_info, + .get = scarlett2_sync_ctl_get +}; + +static int scarlett2_add_sync_ctl(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + /* devices without a mixer also don't support reporting sync status */ + if (!private->info->has_mixer) + return 0; + + return scarlett2_add_new_ctl(mixer, &scarlett2_sync_ctl, + 0, 1, "Sync Status", &private->sync_ctl); +} + /*** Analogue Line Out Volume Controls ***/ /* Update hardware volume controls after receiving notification that @@ -980,12 +1706,14 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer, */ static int scarlett2_update_volumes(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; - const struct scarlett2_ports *ports = private->info->ports; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; struct scarlett2_usb_volume_status volume_status; int num_line_out = - ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; int err, i; + int mute; private->vol_updated = 0; @@ -997,13 +1725,17 @@ static int scarlett2_update_volumes(struct usb_mixer_interface *mixer) volume_status.master_vol + SCARLETT2_VOLUME_BIAS, 0, SCARLETT2_VOLUME_BIAS); - for (i = 0; i < num_line_out; i++) { - if (private->vol_sw_hw_switch[i]) - private->vol[i] = private->master_vol; - } + if (info->line_out_hw_vol) + for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++) + private->dim_mute[i] = !!volume_status.dim_mute[i]; - for (i = 0; i < private->info->button_count; i++) - private->buttons[i] = !!volume_status.buttons[i]; + mute = private->dim_mute[SCARLETT2_BUTTON_MUTE]; + + for (i = 0; i < num_line_out; i++) + if (private->vol_sw_hw_switch[i]) { + private->vol[i] = private->master_vol; + private->mute_switch[i] = mute; + } return 0; } @@ -1026,31 +1758,38 @@ static int scarlett2_master_volume_ctl_get(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; - if (private->vol_updated) { - mutex_lock(&private->data_mutex); + mutex_lock(&private->data_mutex); + if (private->vol_updated) scarlett2_update_volumes(mixer); - mutex_unlock(&private->data_mutex); - } + mutex_unlock(&private->data_mutex); ucontrol->value.integer.value[0] = private->master_vol; return 0; } +static int line_out_remap(struct scarlett2_data *private, int index) +{ + const struct scarlett2_device_info *info = private->info; + + if (!info->line_out_remap_enable) + return index; + return info->line_out_remap[index]; +} + static int scarlett2_volume_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; - int index = elem->control; + struct scarlett2_data *private = mixer->private_data; + int index = line_out_remap(private, elem->control); - if (private->vol_updated) { - mutex_lock(&private->data_mutex); + mutex_lock(&private->data_mutex); + if (private->vol_updated) scarlett2_update_volumes(mixer); - mutex_unlock(&private->data_mutex); - } + mutex_unlock(&private->data_mutex); ucontrol->value.integer.value[0] = private->vol[index]; return 0; @@ -1061,8 +1800,8 @@ static int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; - int index = elem->control; + struct scarlett2_data *private = mixer->private_data; + int index = line_out_remap(private, elem->control); int oval, val, err = 0; mutex_lock(&private->data_mutex); @@ -1111,8 +1850,71 @@ static const struct snd_kcontrol_new scarlett2_line_out_volume_ctl = { .tlv = { .p = db_scale_scarlett2_gain } }; +/*** Mute Switch Controls ***/ + +static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + int index = line_out_remap(private, elem->control); + + ucontrol->value.integer.value[0] = private->mute_switch[index]; + return 0; +} + +static int scarlett2_mute_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int index = line_out_remap(private, elem->control); + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->mute_switch[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->mute_switch[index] = val; + + /* Send mute change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_MUTE_SWITCH, + index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_mute_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_mute_ctl_get, + .put = scarlett2_mute_ctl_put, +}; + /*** HW/SW Volume Switch Controls ***/ +static void scarlett2_sw_hw_ctl_ro(struct scarlett2_data *private, int index) +{ + private->sw_hw_ctls[index]->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_WRITE; +} + +static void scarlett2_sw_hw_ctl_rw(struct scarlett2_data *private, int index) +{ + private->sw_hw_ctls[index]->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_WRITE; +} + static int scarlett2_sw_hw_enum_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -1127,60 +1929,97 @@ static int scarlett2_sw_hw_enum_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + int index = line_out_remap(private, elem->control); - ucontrol->value.enumerated.item[0] = - private->vol_sw_hw_switch[elem->control]; + ucontrol->value.enumerated.item[0] = private->vol_sw_hw_switch[index]; return 0; } -static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) +static void scarlett2_vol_ctl_set_writable(struct usb_mixer_interface *mixer, + int index, int value) { - struct usb_mixer_elem_info *elem = kctl->private_data; - struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; - - int index = elem->control; - int oval, val, err = 0; + struct scarlett2_data *private = mixer->private_data; + struct snd_card *card = mixer->chip->card; - mutex_lock(&private->data_mutex); + /* Set/Clear write bits */ + if (value) { + private->vol_ctls[index]->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_WRITE; + private->mute_ctls[index]->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_WRITE; + } else { + private->vol_ctls[index]->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_WRITE; + private->mute_ctls[index]->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_WRITE; + } - oval = private->vol_sw_hw_switch[index]; - val = !!ucontrol->value.integer.value[0]; + /* Notify of write bit change */ + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->vol_ctls[index]->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->mute_ctls[index]->id); +} - if (oval == val) - goto unlock; +static int scarlett2_sw_hw_change(struct usb_mixer_interface *mixer, + int ctl_index, int val) +{ + struct scarlett2_data *private = mixer->private_data; + int index = line_out_remap(private, ctl_index); + int err; private->vol_sw_hw_switch[index] = val; /* Change access mode to RO (hardware controlled volume) * or RW (software controlled volume) */ - if (val) - private->vol_ctls[index]->vd[0].access &= - ~SNDRV_CTL_ELEM_ACCESS_WRITE; - else - private->vol_ctls[index]->vd[0].access |= - SNDRV_CTL_ELEM_ACCESS_WRITE; + scarlett2_vol_ctl_set_writable(mixer, ctl_index, !val); - /* Reset volume to master volume */ + /* Reset volume/mute to master volume/mute */ private->vol[index] = private->master_vol; + private->mute_switch[index] = private->dim_mute[SCARLETT2_BUTTON_MUTE]; /* Set SW volume to current HW volume */ err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, index, private->master_vol - SCARLETT2_VOLUME_BIAS); if (err < 0) - goto unlock; + return err; - /* Notify of RO/RW change */ - snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_INFO, - &private->vol_ctls[index]->id); + /* Set SW mute to current HW mute */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MUTE_SWITCH, + index, private->dim_mute[SCARLETT2_BUTTON_MUTE]); + if (err < 0) + return err; /* Send SW/HW switch change to the device */ - err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, - index, val); + return scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, + index, val); +} + +static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int ctl_index = elem->control; + int index = line_out_remap(private, ctl_index); + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->vol_sw_hw_switch[index]; + val = !!ucontrol->value.enumerated.item[0]; + + if (oval == val) + goto unlock; + + err = scarlett2_sw_hw_change(mixer, ctl_index, val); + if (err == 0) + err = 1; unlock: mutex_unlock(&private->data_mutex); @@ -1197,6 +2036,55 @@ static const struct snd_kcontrol_new scarlett2_sw_hw_enum_ctl = { /*** Line Level/Instrument Level Switch Controls ***/ +static int scarlett2_update_input_other(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + private->input_other_updated = 0; + + if (info->level_input_count) { + int err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_LEVEL_SWITCH, + info->level_input_count + info->level_input_first, + private->level_switch); + if (err < 0) + return err; + } + + if (info->pad_input_count) { + int err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PAD_SWITCH, + info->pad_input_count, private->pad_switch); + if (err < 0) + return err; + } + + if (info->air_input_count) { + int err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_AIR_SWITCH, + info->air_input_count, private->air_switch); + if (err < 0) + return err; + } + + if (info->phantom_count) { + int err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PHANTOM_SWITCH, + info->phantom_count, private->phantom_switch); + if (err < 0) + return err; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, + 1, &private->phantom_persistence); + if (err < 0) + return err; + } + + return 0; +} + static int scarlett2_level_enum_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -1211,10 +2099,18 @@ static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + int index = elem->control + info->level_input_first; + + mutex_lock(&private->data_mutex); + if (private->input_other_updated) + scarlett2_update_input_other(mixer); + ucontrol->value.enumerated.item[0] = private->level_switch[index]; + mutex_unlock(&private->data_mutex); - ucontrol->value.enumerated.item[0] = - private->level_switch[elem->control]; return 0; } @@ -1223,15 +2119,16 @@ static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; - int index = elem->control; + int index = elem->control + info->level_input_first; int oval, val, err = 0; mutex_lock(&private->data_mutex); oval = private->level_switch[index]; - val = !!ucontrol->value.integer.value[0]; + val = !!ucontrol->value.enumerated.item[0]; if (oval == val) goto unlock; @@ -1241,6 +2138,8 @@ static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_LEVEL_SWITCH, index, val); + if (err == 0) + err = 1; unlock: mutex_unlock(&private->data_mutex); @@ -1261,10 +2160,16 @@ static int scarlett2_pad_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; - ucontrol->value.enumerated.item[0] = + mutex_lock(&private->data_mutex); + if (private->input_other_updated) + scarlett2_update_input_other(mixer); + ucontrol->value.integer.value[0] = private->pad_switch[elem->control]; + mutex_unlock(&private->data_mutex); + return 0; } @@ -1273,7 +2178,7 @@ static int scarlett2_pad_ctl_put(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; int index = elem->control; int oval, val, err = 0; @@ -1291,6 +2196,8 @@ static int scarlett2_pad_ctl_put(struct snd_kcontrol *kctl, /* Send switch change to the device */ err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_PAD_SWITCH, index, val); + if (err == 0) + err = 1; unlock: mutex_unlock(&private->data_mutex); @@ -1305,71 +2212,734 @@ static const struct snd_kcontrol_new scarlett2_pad_ctl = { .put = scarlett2_pad_ctl_put, }; -/*** Mute/Dim Controls ***/ +/*** Air Switch Controls ***/ -static int scarlett2_button_ctl_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) +static int scarlett2_air_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; - if (private->vol_updated) { - mutex_lock(&private->data_mutex); - scarlett2_update_volumes(mixer); - mutex_unlock(&private->data_mutex); + mutex_lock(&private->data_mutex); + if (private->input_other_updated) + scarlett2_update_input_other(mixer); + ucontrol->value.integer.value[0] = private->air_switch[elem->control]; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static int scarlett2_air_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->air_switch[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->air_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_AIR_SWITCH, + index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_air_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_air_ctl_get, + .put = scarlett2_air_ctl_put, +}; + +/*** Phantom Switch Controls ***/ + +static int scarlett2_phantom_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->input_other_updated) + scarlett2_update_input_other(mixer); + ucontrol->value.integer.value[0] = + private->phantom_switch[elem->control]; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->phantom_switch[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->phantom_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_PHANTOM_SWITCH, + index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_phantom_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_phantom_ctl_get, + .put = scarlett2_phantom_ctl_put, +}; + +/*** Phantom Persistence Control ***/ + +static int scarlett2_phantom_persistence_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = private->phantom_persistence; + return 0; +} + +static int scarlett2_phantom_persistence_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->phantom_persistence; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->phantom_persistence = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_phantom_persistence_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_phantom_persistence_ctl_get, + .put = scarlett2_phantom_persistence_ctl_put, +}; + +/*** Direct Monitor Control ***/ + +static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int err; + + /* monitor_other_enable[0] enables speaker switching + * monitor_other_enable[1] enables talkback + */ + u8 monitor_other_enable[2]; + + /* monitor_other_switch[0] activates the alternate speakers + * monitor_other_switch[1] activates talkback + */ + u8 monitor_other_switch[2]; + + private->monitor_other_updated = 0; + + if (info->direct_monitor) + return scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, + 1, &private->direct_monitor_switch); + + /* if it doesn't do speaker switching then it also doesn't do + * talkback + */ + if (!info->has_speaker_switching) + return 0; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE, + 2, monitor_other_enable); + if (err < 0) + return err; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, + 2, monitor_other_switch); + if (err < 0) + return err; + + if (!monitor_other_enable[0]) + private->speaker_switching_switch = 0; + else + private->speaker_switching_switch = monitor_other_switch[0] + 1; + + if (info->has_talkback) { + const int (*port_count)[SCARLETT2_PORT_DIRNS] = + info->port_count; + int num_mixes = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN]; + u16 bitmap; + int i; + + if (!monitor_other_enable[1]) + private->talkback_switch = 0; + else + private->talkback_switch = monitor_other_switch[1] + 1; + + err = scarlett2_usb_get_config(mixer, + SCARLETT2_CONFIG_TALKBACK_MAP, + 1, &bitmap); + for (i = 0; i < num_mixes; i++, bitmap >>= 1) + private->talkback_map[i] = bitmap & 1; } - ucontrol->value.enumerated.item[0] = private->buttons[elem->control]; return 0; } -static int scarlett2_button_ctl_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) +static int scarlett2_direct_monitor_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = elem->head.mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->monitor_other_updated) + scarlett2_update_monitor_other(mixer); + ucontrol->value.enumerated.item[0] = private->direct_monitor_switch; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static int scarlett2_direct_monitor_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; int index = elem->control; int oval, val, err = 0; mutex_lock(&private->data_mutex); - oval = private->buttons[index]; + oval = private->direct_monitor_switch; + val = min(ucontrol->value.enumerated.item[0], 2U); + + if (oval == val) + goto unlock; + + private->direct_monitor_switch = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_direct_monitor_stereo_enum_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + static const char *const values[3] = { + "Off", "Mono", "Stereo" + }; + + return snd_ctl_enum_info(uinfo, 1, 3, values); +} + +/* Direct Monitor for Solo is mono-only and only needs a boolean control + * Direct Monitor for 2i2 is selectable between Off/Mono/Stereo + */ +static const struct snd_kcontrol_new scarlett2_direct_monitor_ctl[2] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_direct_monitor_ctl_get, + .put = scarlett2_direct_monitor_ctl_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_direct_monitor_stereo_enum_ctl_info, + .get = scarlett2_direct_monitor_ctl_get, + .put = scarlett2_direct_monitor_ctl_put, + } +}; + +static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + if (!info->direct_monitor) + return 0; + + return scarlett2_add_new_ctl( + mixer, &scarlett2_direct_monitor_ctl[info->direct_monitor - 1], + 0, 1, "Direct Monitor Playback Switch", + &private->direct_monitor_ctl); +} + +/*** Speaker Switching Control ***/ + +static int scarlett2_speaker_switch_enum_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + static const char *const values[3] = { + "Off", "Main", "Alt" + }; + + return snd_ctl_enum_info(uinfo, 1, 3, values); +} + +static int scarlett2_speaker_switch_enum_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->monitor_other_updated) + scarlett2_update_monitor_other(mixer); + ucontrol->value.enumerated.item[0] = private->speaker_switching_switch; + mutex_unlock(&private->data_mutex); + + return 0; +} + +/* when speaker switching gets enabled, switch the main/alt speakers + * to HW volume and disable those controls + */ +static int scarlett2_speaker_switch_enable(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + int i, err; + + for (i = 0; i < 4; i++) { + int index = line_out_remap(private, i); + + /* switch the main/alt speakers to HW volume */ + if (!private->vol_sw_hw_switch[index]) { + err = scarlett2_sw_hw_change(private->mixer, i, 1); + if (err < 0) + return err; + } + + /* disable the line out SW/HW switch */ + scarlett2_sw_hw_ctl_ro(private, i); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->sw_hw_ctls[i]->id); + } + + /* when the next monitor-other notify comes in, update the mux + * configuration + */ + private->speaker_switching_switched = 1; + + return 0; +} + +/* when speaker switching gets disabled, reenable the hw/sw controls + * and invalidate the routing + */ +static void scarlett2_speaker_switch_disable(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + int i; + + /* enable the line out SW/HW switch */ + for (i = 0; i < 4; i++) { + scarlett2_sw_hw_ctl_rw(private, i); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->sw_hw_ctls[i]->id); + } + + /* when the next monitor-other notify comes in, update the mux + * configuration + */ + private->speaker_switching_switched = 1; +} + +static int scarlett2_speaker_switch_enum_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->speaker_switching_switch; + val = min(ucontrol->value.enumerated.item[0], 2U); + + if (oval == val) + goto unlock; + + private->speaker_switching_switch = val; + + /* enable/disable speaker switching */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE, + 0, !!val); + if (err < 0) + goto unlock; + + /* if speaker switching is enabled, select main or alt */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, + 0, val == 2); + if (err < 0) + goto unlock; + + /* update controls if speaker switching gets enabled or disabled */ + if (!oval && val) + err = scarlett2_speaker_switch_enable(mixer); + else if (oval && !val) + scarlett2_speaker_switch_disable(mixer); + + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_speaker_switch_enum_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_speaker_switch_enum_ctl_info, + .get = scarlett2_speaker_switch_enum_ctl_get, + .put = scarlett2_speaker_switch_enum_ctl_put, +}; + +static int scarlett2_add_speaker_switch_ctl( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + if (!info->has_speaker_switching) + return 0; + + return scarlett2_add_new_ctl( + mixer, &scarlett2_speaker_switch_enum_ctl, + 0, 1, "Speaker Switching Playback Enum", + &private->speaker_switching_ctl); +} + +/*** Talkback and Talkback Map Controls ***/ + +static int scarlett2_talkback_enum_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + static const char *const values[3] = { + "Disabled", "Off", "On" + }; + + return snd_ctl_enum_info(uinfo, 1, 3, values); +} + +static int scarlett2_talkback_enum_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->monitor_other_updated) + scarlett2_update_monitor_other(mixer); + ucontrol->value.enumerated.item[0] = private->talkback_switch; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static int scarlett2_talkback_enum_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->talkback_switch; + val = min(ucontrol->value.enumerated.item[0], 2U); + + if (oval == val) + goto unlock; + + private->talkback_switch = val; + + /* enable/disable talkback */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE, + 1, !!val); + if (err < 0) + goto unlock; + + /* if talkback is enabled, select main or alt */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, + 1, val == 2); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_talkback_enum_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_talkback_enum_ctl_info, + .get = scarlett2_talkback_enum_ctl_get, + .put = scarlett2_talkback_enum_ctl_put, +}; + +static int scarlett2_talkback_map_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int index = elem->control; + + ucontrol->value.integer.value[0] = private->talkback_map[index]; + + return 0; +} + +static int scarlett2_talkback_map_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = + private->info->port_count; + int num_mixes = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN]; + + int index = elem->control; + int oval, val, err = 0, i; + u16 bitmap = 0; + + mutex_lock(&private->data_mutex); + + oval = private->talkback_map[index]; val = !!ucontrol->value.integer.value[0]; if (oval == val) goto unlock; - private->buttons[index] = val; + private->talkback_map[index] = val; + + for (i = 0; i < num_mixes; i++) + bitmap |= private->talkback_map[i] << i; + + /* Send updated bitmap to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_TALKBACK_MAP, + 0, bitmap); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_talkback_map_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_talkback_map_ctl_get, + .put = scarlett2_talkback_map_ctl_put, +}; + +static int scarlett2_add_talkback_ctls( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int num_mixes = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN]; + int err, i; + char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + if (!info->has_talkback) + return 0; + + err = scarlett2_add_new_ctl( + mixer, &scarlett2_talkback_enum_ctl, + 0, 1, "Talkback Playback Enum", + &private->talkback_ctl); + if (err < 0) + return err; + + for (i = 0; i < num_mixes; i++) { + snprintf(s, sizeof(s), + "Talkback Mix %c Playback Switch", i + 'A'); + err = scarlett2_add_new_ctl(mixer, &scarlett2_talkback_map_ctl, + i, 1, s, NULL); + if (err < 0) + return err; + } + + return 0; +} + +/*** Dim/Mute Controls ***/ + +static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->vol_updated) + scarlett2_update_volumes(mixer); + mutex_unlock(&private->data_mutex); + + ucontrol->value.integer.value[0] = private->dim_mute[elem->control]; + return 0; +} + +static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int num_line_out = + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; + + int index = elem->control; + int oval, val, err = 0, i; + + mutex_lock(&private->data_mutex); + + oval = private->dim_mute[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->dim_mute[index] = val; /* Send switch change to the device */ - err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_BUTTONS, + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_DIM_MUTE, index, val); + if (err == 0) + err = 1; + + if (index == SCARLETT2_BUTTON_MUTE) + for (i = 0; i < num_line_out; i++) { + int line_index = line_out_remap(private, i); + + if (private->vol_sw_hw_switch[line_index]) { + private->mute_switch[line_index] = val; + snd_ctl_notify(mixer->chip->card, + SNDRV_CTL_EVENT_MASK_INFO, + &private->mute_ctls[i]->id); + } + } unlock: mutex_unlock(&private->data_mutex); return err; } -static const struct snd_kcontrol_new scarlett2_button_ctl = { +static const struct snd_kcontrol_new scarlett2_dim_mute_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "", .info = snd_ctl_boolean_mono_info, - .get = scarlett2_button_ctl_get, - .put = scarlett2_button_ctl_put + .get = scarlett2_dim_mute_ctl_get, + .put = scarlett2_dim_mute_ctl_put }; /*** Create the analogue output controls ***/ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - const struct scarlett2_ports *ports = info->ports; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; int num_line_out = - ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; int err, i; char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; @@ -1385,6 +2955,7 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) /* Add volume controls */ for (i = 0; i < num_line_out; i++) { + int index = line_out_remap(private, i); /* Fader */ if (info->line_out_descrs[i]) @@ -1401,10 +2972,22 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) if (err < 0) return err; - /* Make the fader read-only if the SW/HW switch is set to HW */ - if (private->vol_sw_hw_switch[i]) - private->vol_ctls[i]->vd[0].access &= - ~SNDRV_CTL_ELEM_ACCESS_WRITE; + /* Mute Switch */ + snprintf(s, sizeof(s), + "Line %02d Mute Playback Switch", + i + 1); + err = scarlett2_add_new_ctl(mixer, + &scarlett2_mute_ctl, + i, 1, s, + &private->mute_ctls[i]); + if (err < 0) + return err; + + /* Make the fader and mute controls read-only if the + * SW/HW switch is set to HW + */ + if (private->vol_sw_hw_switch[index]) + scarlett2_vol_ctl_set_writable(mixer, i, 0); /* SW/HW Switch */ if (info->line_out_hw_vol) { @@ -1413,20 +2996,29 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) i + 1); err = scarlett2_add_new_ctl(mixer, &scarlett2_sw_hw_enum_ctl, - i, 1, s, NULL); + i, 1, s, + &private->sw_hw_ctls[i]); if (err < 0) return err; + + /* Make the switch read-only if the line is + * involved in speaker switching + */ + if (private->speaker_switching_switch && i < 4) + scarlett2_sw_hw_ctl_ro(private, i); } } - /* Add HW button controls */ - for (i = 0; i < private->info->button_count; i++) { - err = scarlett2_add_new_ctl(mixer, &scarlett2_button_ctl, - i, 1, scarlett2_button_names[i], - &private->button_ctls[i]); - if (err < 0) - return err; - } + /* Add dim/mute controls */ + if (info->line_out_hw_vol) + for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++) { + err = scarlett2_add_new_ctl( + mixer, &scarlett2_dim_mute_ctl, + i, 1, scarlett2_dim_mute_names[i], + &private->dim_mute_ctls[i]); + if (err < 0) + return err; + } return 0; } @@ -1435,25 +3027,70 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; int err, i; char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + const char *fmt = "Line In %d %s Capture %s"; + const char *fmt2 = "Line In %d-%d %s Capture %s"; /* Add input level (line/inst) controls */ for (i = 0; i < info->level_input_count; i++) { - snprintf(s, sizeof(s), "Line In %d Level Capture Enum", i + 1); + snprintf(s, sizeof(s), fmt, i + 1 + info->level_input_first, + "Level", "Enum"); err = scarlett2_add_new_ctl(mixer, &scarlett2_level_enum_ctl, - i, 1, s, NULL); + i, 1, s, &private->level_ctls[i]); if (err < 0) return err; } /* Add input pad controls */ for (i = 0; i < info->pad_input_count; i++) { - snprintf(s, sizeof(s), "Line In %d Pad Capture Switch", i + 1); + snprintf(s, sizeof(s), fmt, i + 1, "Pad", "Switch"); err = scarlett2_add_new_ctl(mixer, &scarlett2_pad_ctl, - i, 1, s, NULL); + i, 1, s, &private->pad_ctls[i]); + if (err < 0) + return err; + } + + /* Add input air controls */ + for (i = 0; i < info->air_input_count; i++) { + snprintf(s, sizeof(s), fmt, i + 1, "Air", "Switch"); + err = scarlett2_add_new_ctl(mixer, &scarlett2_air_ctl, + i, 1, s, &private->air_ctls[i]); + if (err < 0) + return err; + } + + /* Add input phantom controls */ + if (info->inputs_per_phantom == 1) { + for (i = 0; i < info->phantom_count; i++) { + snprintf(s, sizeof(s), fmt, i + 1, + "Phantom Power", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_phantom_ctl, + i, 1, s, &private->phantom_ctls[i]); + if (err < 0) + return err; + } + } else if (info->inputs_per_phantom > 1) { + for (i = 0; i < info->phantom_count; i++) { + int from = i * info->inputs_per_phantom + 1; + int to = (i + 1) * info->inputs_per_phantom; + + snprintf(s, sizeof(s), fmt2, from, to, + "Phantom Power", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_phantom_ctl, + i, 1, s, &private->phantom_ctls[i]); + if (err < 0) + return err; + } + } + if (info->phantom_count) { + err = scarlett2_add_new_ctl( + mixer, &scarlett2_phantom_persistence_ctl, 0, 1, + "Phantom Power Persistence Capture Switch", NULL); if (err < 0) return err; } @@ -1480,7 +3117,7 @@ static int scarlett2_mixer_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; ucontrol->value.integer.value[0] = private->mix[elem->control]; return 0; @@ -1491,22 +3128,23 @@ static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - const struct scarlett2_ports *ports = info->ports; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; int oval, val, num_mixer_in, mix_num, err = 0; + int index = elem->control; mutex_lock(&private->data_mutex); - oval = private->mix[elem->control]; + oval = private->mix[index]; val = ucontrol->value.integer.value[0]; - num_mixer_in = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; - mix_num = elem->control / num_mixer_in; + num_mixer_in = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT]; + mix_num = index / num_mixer_in; if (oval == val) goto unlock; - private->mix[elem->control] = val; + private->mix[index] = val; err = scarlett2_usb_set_mix(mixer, mix_num); if (err == 0) err = 1; @@ -1536,16 +3174,19 @@ static const struct snd_kcontrol_new scarlett2_mixer_ctl = { static int scarlett2_add_mixer_ctls(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; - const struct scarlett2_ports *ports = private->info->ports; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; int err, i, j; int index; char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - int num_inputs = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; - int num_outputs = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_IN]; + int num_inputs = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT]; + int num_outputs = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN]; - for (i = 0, index = 0; i < num_outputs; i++) { + for (i = 0, index = 0; i < num_outputs; i++) for (j = 0; j < num_inputs; j++, index++) { snprintf(s, sizeof(s), "Mix %c Input %02d Playback Volume", @@ -1555,7 +3196,6 @@ static int scarlett2_add_mixer_ctls(struct usb_mixer_interface *mixer) if (err < 0) return err; } - } return 0; } @@ -1566,8 +3206,9 @@ static int scarlett2_mux_src_enum_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_mixer_data *private = elem->head.mixer->private_data; - const struct scarlett2_ports *ports = private->info->ports; + struct scarlett2_data *private = elem->head.mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; unsigned int item = uinfo->value.enumerated.item; int items = private->num_mux_srcs; int port_type; @@ -1582,13 +3223,15 @@ static int scarlett2_mux_src_enum_ctl_info(struct snd_kcontrol *kctl, for (port_type = 0; port_type < SCARLETT2_PORT_TYPE_COUNT; port_type++) { - if (item < ports[port_type].num[SCARLETT2_PORT_IN]) { + if (item < port_count[port_type][SCARLETT2_PORT_IN]) { + const struct scarlett2_port *port = + &scarlett2_ports[port_type]; + sprintf(uinfo->value.enumerated.name, - ports[port_type].src_descr, - item + ports[port_type].src_num_offset); + port->src_descr, item + port->src_num_offset); return 0; } - item -= ports[port_type].num[SCARLETT2_PORT_IN]; + item -= port_count[port_type][SCARLETT2_PORT_IN]; } return -EINVAL; @@ -1598,9 +3241,23 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_mixer_data *private = elem->head.mixer->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int line_out_count = + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; + int index = elem->control; + + if (index < line_out_count) + index = line_out_remap(private, index); + + mutex_lock(&private->data_mutex); + if (private->mux_updated) + scarlett2_usb_get_mux(mixer); + ucontrol->value.enumerated.item[0] = private->mux[index]; + mutex_unlock(&private->data_mutex); - ucontrol->value.enumerated.item[0] = private->mux[elem->control]; return 0; } @@ -1609,15 +3266,22 @@ static int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int line_out_count = + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; int index = elem->control; int oval, val, err = 0; + if (index < line_out_count) + index = line_out_remap(private, index); + mutex_lock(&private->data_mutex); oval = private->mux[index]; - val = clamp(ucontrol->value.integer.value[0], - 0L, private->num_mux_srcs - 1L); + val = min(ucontrol->value.enumerated.item[0], + private->num_mux_srcs - 1U); if (oval == val) goto unlock; @@ -1642,26 +3306,29 @@ static const struct snd_kcontrol_new scarlett2_mux_src_enum_ctl = { static int scarlett2_add_mux_enums(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; - const struct scarlett2_ports *ports = private->info->ports; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; int port_type, channel, i; for (i = 0, port_type = 0; port_type < SCARLETT2_PORT_TYPE_COUNT; port_type++) { for (channel = 0; - channel < ports[port_type].num[SCARLETT2_PORT_OUT]; + channel < port_count[port_type][SCARLETT2_PORT_OUT]; channel++, i++) { int err; char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - const char *const descr = ports[port_type].dst_descr; + const char *const descr = + scarlett2_ports[port_type].dst_descr; snprintf(s, sizeof(s) - 5, descr, channel + 1); strcat(s, " Enum"); err = scarlett2_add_new_ctl(mixer, &scarlett2_mux_src_enum_ctl, - i, 1, s, NULL); + i, 1, s, + &private->mux_ctls[i]); if (err < 0) return err; } @@ -1689,10 +3356,11 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - u16 meter_levels[SCARLETT2_NUM_METERS]; + u16 meter_levels[SCARLETT2_MAX_METERS]; int i, err; - err = scarlett2_usb_get_meter_levels(elem->head.mixer, meter_levels); + err = scarlett2_usb_get_meter_levels(elem->head.mixer, elem->channels, + meter_levels); if (err < 0) return err; @@ -1712,16 +3380,89 @@ static const struct snd_kcontrol_new scarlett2_meter_ctl = { static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer) { + struct scarlett2_data *private = mixer->private_data; + + /* devices without a mixer also don't support reporting levels */ + if (!private->info->has_mixer) + return 0; + return scarlett2_add_new_ctl(mixer, &scarlett2_meter_ctl, - 0, SCARLETT2_NUM_METERS, + 0, private->num_mux_dsts, "Level Meter", NULL); } +/*** MSD Controls ***/ + +static int scarlett2_msd_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = private->msd_switch; + return 0; +} + +static int scarlett2_msd_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->msd_switch; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->msd_switch = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_MSD_SWITCH, + 0, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_msd_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_msd_ctl_get, + .put = scarlett2_msd_ctl_put, +}; + +static int scarlett2_add_msd_ctl(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + if (!info->has_msd_mode) + return 0; + + /* If MSD mode is off, hide the switch by default */ + if (!private->msd_switch && !(mixer->chip->setup & SCARLETT2_MSD_ENABLE)) + return 0; + + /* Add MSD control */ + return scarlett2_add_new_ctl(mixer, &scarlett2_msd_ctl, + 0, 1, "MSD Mode", NULL); +} + /*** Cleanup/Suspend Callbacks ***/ static void scarlett2_private_free(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; cancel_delayed_work_sync(&private->work); kfree(private); @@ -1730,7 +3471,7 @@ static void scarlett2_private_free(struct usb_mixer_interface *mixer) static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; if (cancel_delayed_work_sync(&private->work)) scarlett2_config_save(private->mixer); @@ -1738,77 +3479,61 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) /*** Initialisation ***/ -static int scarlett2_count_mux_srcs(const struct scarlett2_ports *ports) +static void scarlett2_count_mux_io(struct scarlett2_data *private) { - int port_type, count = 0; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int port_type, srcs = 0, dsts = 0; for (port_type = 0; port_type < SCARLETT2_PORT_TYPE_COUNT; - port_type++) - count += ports[port_type].num[SCARLETT2_PORT_IN]; + port_type++) { + srcs += port_count[port_type][SCARLETT2_PORT_IN]; + dsts += port_count[port_type][SCARLETT2_PORT_OUT]; + } - return count; + private->num_mux_srcs = srcs; + private->num_mux_dsts = dsts; } -/* Default routing connects PCM outputs and inputs to Analogue, - * S/PDIF, then ADAT +/* Look through the interface descriptors for the Focusrite Control + * interface (bInterfaceClass = 255 Vendor Specific Class) and set + * bInterfaceNumber, bEndpointAddress, wMaxPacketSize, and bInterval + * in private */ -static void scarlett2_init_routing(u8 *mux, - const struct scarlett2_ports *ports) +static int scarlett2_find_fc_interface(struct usb_device *dev, + struct scarlett2_data *private) { - int i, input_num, input_count, port_type; - int output_num, output_count, port_type_connect_num; + struct usb_host_config *config = dev->actconfig; + int i; - static const int connect_order[] = { - SCARLETT2_PORT_TYPE_ANALOGUE, - SCARLETT2_PORT_TYPE_SPDIF, - SCARLETT2_PORT_TYPE_ADAT, - -1 - }; + for (i = 0; i < config->desc.bNumInterfaces; i++) { + struct usb_interface *intf = config->interface[i]; + struct usb_interface_descriptor *desc = + &intf->altsetting[0].desc; + struct usb_endpoint_descriptor *epd; - /* Assign PCM inputs (routing outputs) */ - output_num = scarlett2_get_port_start_num(ports, - SCARLETT2_PORT_OUT, - SCARLETT2_PORT_TYPE_PCM); - output_count = ports[SCARLETT2_PORT_TYPE_PCM].num[SCARLETT2_PORT_OUT]; - - for (port_type = connect_order[port_type_connect_num = 0]; - port_type >= 0; - port_type = connect_order[++port_type_connect_num]) { - input_num = scarlett2_get_port_start_num( - ports, SCARLETT2_PORT_IN, port_type); - input_count = ports[port_type].num[SCARLETT2_PORT_IN]; - for (i = 0; - i < input_count && output_count; - i++, output_count--) - mux[output_num++] = input_num++; - } + if (desc->bInterfaceClass != 255) + continue; - /* Assign PCM outputs (routing inputs) */ - input_num = scarlett2_get_port_start_num(ports, - SCARLETT2_PORT_IN, - SCARLETT2_PORT_TYPE_PCM); - input_count = ports[SCARLETT2_PORT_TYPE_PCM].num[SCARLETT2_PORT_IN]; - - for (port_type = connect_order[port_type_connect_num = 0]; - port_type >= 0; - port_type = connect_order[++port_type_connect_num]) { - output_num = scarlett2_get_port_start_num( - ports, SCARLETT2_PORT_OUT, port_type); - output_count = ports[port_type].num[SCARLETT2_PORT_OUT]; - for (i = 0; - i < output_count && input_count; - i++, input_count--) - mux[output_num++] = input_num++; + epd = get_endpoint(intf->altsetting, 0); + private->bInterfaceNumber = desc->bInterfaceNumber; + private->bEndpointAddress = epd->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + private->wMaxPacketSize = le16_to_cpu(epd->wMaxPacketSize); + private->bInterval = epd->bInterval; + return 0; } + + return -EINVAL; } -/* Initialise private data, routing, sequence number */ +/* Initialise private data */ static int scarlett2_init_private(struct usb_mixer_interface *mixer, const struct scarlett2_device_info *info) { - struct scarlett2_mixer_data *private = - kzalloc(sizeof(struct scarlett2_mixer_data), GFP_KERNEL); + struct scarlett2_data *private = + kzalloc(sizeof(struct scarlett2_data), GFP_KERNEL); if (!private) return -ENOMEM; @@ -1816,68 +3541,102 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer, mutex_init(&private->usb_mutex); mutex_init(&private->data_mutex); INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); - private->info = info; - private->num_mux_srcs = scarlett2_count_mux_srcs(info->ports); - private->scarlett2_seq = 0; - private->mixer = mixer; + mixer->private_data = private; mixer->private_free = scarlett2_private_free; mixer->private_suspend = scarlett2_private_suspend; - /* Setup default routing */ - scarlett2_init_routing(private->mux, info->ports); + private->info = info; + scarlett2_count_mux_io(private); + private->scarlett2_seq = 0; + private->mixer = mixer; - /* Initialise the sequence number used for the proprietary commands */ - return scarlett2_usb(mixer, SCARLETT2_USB_INIT_SEQ, NULL, 0, NULL, 0); + return scarlett2_find_fc_interface(mixer->chip->dev, private); } -/* Read line-in config and line-out volume settings on start */ +/* Cargo cult proprietary initialisation sequence */ +static int scarlett2_usb_init(struct usb_mixer_interface *mixer) +{ + struct usb_device *dev = mixer->chip->dev; + struct scarlett2_data *private = mixer->private_data; + u8 buf[24]; + int err; + + if (usb_pipe_type_check(dev, usb_sndctrlpipe(dev, 0))) + return -EINVAL; + + /* step 0 */ + err = scarlett2_usb_rx(dev, private->bInterfaceNumber, + SCARLETT2_USB_CMD_INIT, buf, sizeof(buf)); + if (err < 0) + return err; + + /* step 1 */ + private->scarlett2_seq = 1; + err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_1, NULL, 0, NULL, 0); + if (err < 0) + return err; + + /* step 2 */ + private->scarlett2_seq = 1; + return scarlett2_usb(mixer, SCARLETT2_USB_INIT_2, NULL, 0, NULL, 84); +} + +/* Read configuration from the interface on start */ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - const struct scarlett2_ports *ports = info->ports; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; int num_line_out = - ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; - u8 level_switches[SCARLETT2_LEVEL_SWITCH_MAX]; - u8 pad_switches[SCARLETT2_PAD_SWITCH_MAX]; + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; + int num_mixer_out = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN]; struct scarlett2_usb_volume_status volume_status; int err, i; - if (info->level_input_count) { + if (info->has_msd_mode) { err = scarlett2_usb_get_config( - mixer, - SCARLETT2_CONFIG_LEVEL_SWITCH, - info->level_input_count, - level_switches); + mixer, SCARLETT2_CONFIG_MSD_SWITCH, + 1, &private->msd_switch); if (err < 0) return err; - for (i = 0; i < info->level_input_count; i++) - private->level_switch[i] = level_switches[i]; - } - if (info->pad_input_count) { - err = scarlett2_usb_get_config( - mixer, - SCARLETT2_CONFIG_PAD_SWITCH, - info->pad_input_count, - pad_switches); - if (err < 0) - return err; - for (i = 0; i < info->pad_input_count; i++) - private->pad_switch[i] = pad_switches[i]; + /* no other controls are created if MSD mode is on */ + if (private->msd_switch) + return 0; } + err = scarlett2_update_input_other(mixer); + if (err < 0) + return err; + + err = scarlett2_update_monitor_other(mixer); + if (err < 0) + return err; + + /* the rest of the configuration is for devices with a mixer */ + if (!info->has_mixer) + return 0; + + err = scarlett2_update_sync(mixer); + if (err < 0) + return err; + err = scarlett2_usb_get_volume_status(mixer, &volume_status); if (err < 0) return err; + if (info->line_out_hw_vol) + for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++) + private->dim_mute[i] = !!volume_status.dim_mute[i]; + private->master_vol = clamp( volume_status.master_vol + SCARLETT2_VOLUME_BIAS, 0, SCARLETT2_VOLUME_BIAS); for (i = 0; i < num_line_out; i++) { - int volume; + int volume, mute; private->vol_sw_hw_switch[i] = info->line_out_hw_vol @@ -1889,72 +3648,178 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) volume = clamp(volume + SCARLETT2_VOLUME_BIAS, 0, SCARLETT2_VOLUME_BIAS); private->vol[i] = volume; + + mute = private->vol_sw_hw_switch[i] + ? private->dim_mute[SCARLETT2_BUTTON_MUTE] + : volume_status.mute_switch[i]; + private->mute_switch[i] = mute; + } + + for (i = 0; i < num_mixer_out; i++) { + err = scarlett2_usb_get_mix(mixer, i); + if (err < 0) + return err; } - for (i = 0; i < info->button_count; i++) - private->buttons[i] = !!volume_status.buttons[i]; + return scarlett2_usb_get_mux(mixer); +} - return 0; +/* Notify on sync change */ +static void scarlett2_notify_sync( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + private->sync_updated = 1; + + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->sync_ctl->id); } -/* Notify on volume change */ -static void scarlett2_mixer_interrupt_vol_change( +/* Notify on monitor change */ +static void scarlett2_notify_monitor( struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; - const struct scarlett2_ports *ports = private->info->ports; + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; int num_line_out = - ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; int i; + /* if line_out_hw_vol is 0, there are no controls to update */ + if (!info->line_out_hw_vol) + return; + private->vol_updated = 1; snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &private->master_vol_ctl->id); - for (i = 0; i < num_line_out; i++) { - if (!private->vol_sw_hw_switch[i]) - continue; - snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - &private->vol_ctls[i]->id); - } + for (i = 0; i < num_line_out; i++) + if (private->vol_sw_hw_switch[line_out_remap(private, i)]) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->vol_ctls[i]->id); } -/* Notify on button change */ -static void scarlett2_mixer_interrupt_button_change( +/* Notify on dim/mute change */ +static void scarlett2_notify_dim_mute( struct usb_mixer_interface *mixer) { - struct scarlett2_mixer_data *private = mixer->private_data; + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int num_line_out = + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; int i; private->vol_updated = 1; - for (i = 0; i < private->info->button_count; i++) - snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - &private->button_ctls[i]->id); + if (!info->line_out_hw_vol) + return; + + for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->dim_mute_ctls[i]->id); + + for (i = 0; i < num_line_out; i++) + if (private->vol_sw_hw_switch[line_out_remap(private, i)]) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->mute_ctls[i]->id); +} + +/* Notify on "input other" change (level/pad/air) */ +static void scarlett2_notify_input_other( + struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int i; + + private->input_other_updated = 1; + + for (i = 0; i < info->level_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->level_ctls[i]->id); + for (i = 0; i < info->pad_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->pad_ctls[i]->id); + for (i = 0; i < info->air_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->air_ctls[i]->id); + for (i = 0; i < info->phantom_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->phantom_ctls[i]->id); +} + +/* Notify on "monitor other" change (direct monitor, speaker + * switching, talkback) + */ +static void scarlett2_notify_monitor_other( + struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + private->monitor_other_updated = 1; + + if (info->direct_monitor) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->direct_monitor_ctl->id); + return; + } + + if (info->has_speaker_switching) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->speaker_switching_ctl->id); + + if (info->has_talkback) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->talkback_ctl->id); + + /* if speaker switching was recently enabled or disabled, + * invalidate the dim/mute and mux enum controls + */ + if (private->speaker_switching_switched) { + int i; + + scarlett2_notify_dim_mute(mixer); + + private->speaker_switching_switched = 0; + private->mux_updated = 1; + + for (i = 0; i < private->num_mux_dsts; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->mux_ctls[i]->id); + } } /* Interrupt callback */ -static void scarlett2_mixer_interrupt(struct urb *urb) +static void scarlett2_notify(struct urb *urb) { struct usb_mixer_interface *mixer = urb->context; int len = urb->actual_length; int ustatus = urb->status; u32 data; - if (ustatus != 0) + if (ustatus != 0 || len != 8) goto requeue; - if (len == 8) { - data = le32_to_cpu(*(__le32 *)urb->transfer_buffer); - if (data & SCARLETT2_USB_INTERRUPT_VOL_CHANGE) - scarlett2_mixer_interrupt_vol_change(mixer); - if (data & SCARLETT2_USB_INTERRUPT_BUTTON_CHANGE) - scarlett2_mixer_interrupt_button_change(mixer); - } else { - usb_audio_err(mixer->chip, - "scarlett mixer interrupt length %d\n", len); - } + data = le32_to_cpu(*(__le32 *)urb->transfer_buffer); + if (data & SCARLETT2_USB_NOTIFY_SYNC) + scarlett2_notify_sync(mixer); + if (data & SCARLETT2_USB_NOTIFY_MONITOR) + scarlett2_notify_monitor(mixer); + if (data & SCARLETT2_USB_NOTIFY_DIM_MUTE) + scarlett2_notify_dim_mute(mixer); + if (data & SCARLETT2_USB_NOTIFY_INPUT_OTHER) + scarlett2_notify_input_other(mixer); + if (data & SCARLETT2_USB_NOTIFY_MONITOR_OTHER) + scarlett2_notify_monitor_other(mixer); requeue: if (ustatus != -ENOENT && @@ -1965,11 +3830,11 @@ requeue: } } -static int scarlett2_mixer_status_create(struct usb_mixer_interface *mixer) +static int scarlett2_init_notify(struct usb_mixer_interface *mixer) { struct usb_device *dev = mixer->chip->dev; - unsigned int pipe = usb_rcvintpipe(dev, - SCARLETT2_USB_INTERRUPT_ENDPOINT); + struct scarlett2_data *private = mixer->private_data; + unsigned int pipe = usb_rcvintpipe(dev, private->bEndpointAddress); void *transfer_buffer; if (mixer->urb) { @@ -1985,25 +3850,35 @@ static int scarlett2_mixer_status_create(struct usb_mixer_interface *mixer) if (!mixer->urb) return -ENOMEM; - transfer_buffer = kmalloc(SCARLETT2_USB_INTERRUPT_MAX_DATA, GFP_KERNEL); + transfer_buffer = kmalloc(private->wMaxPacketSize, GFP_KERNEL); if (!transfer_buffer) return -ENOMEM; usb_fill_int_urb(mixer->urb, dev, pipe, - transfer_buffer, SCARLETT2_USB_INTERRUPT_MAX_DATA, - scarlett2_mixer_interrupt, mixer, - SCARLETT2_USB_INTERRUPT_INTERVAL); + transfer_buffer, private->wMaxPacketSize, + scarlett2_notify, mixer, private->bInterval); return usb_submit_urb(mixer->urb, GFP_KERNEL); } -static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer, - const struct scarlett2_device_info *info) +static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer) { + const struct scarlett2_device_info **info = scarlett2_devices; int err; - /* Initialise private data, routing, sequence number */ - err = scarlett2_init_private(mixer, info); + /* Find device in scarlett2_devices */ + while (*info && (*info)->usb_id != mixer->chip->usb_id) + info++; + if (!*info) + return -EINVAL; + + /* Initialise private data */ + err = scarlett2_init_private(mixer, *info); + if (err < 0) + return err; + + /* Send proprietary USB initialisation sequence */ + err = scarlett2_usb_init(mixer); if (err < 0) return err; @@ -2012,6 +3887,15 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer, if (err < 0) return err; + /* Create the MSD control */ + err = scarlett2_add_msd_ctl(mixer); + if (err < 0) + return err; + + /* If MSD mode is enabled, don't create any other controls */ + if (((struct scarlett2_data *)mixer->private_data)->msd_switch) + return 0; + /* Create the analogue output controls */ err = scarlett2_add_line_out_ctls(mixer); if (err < 0) @@ -2037,12 +3921,30 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer, if (err < 0) return err; - /* Set up the interrupt polling if there are hardware buttons */ - if (info->button_count) { - err = scarlett2_mixer_status_create(mixer); - if (err < 0) - return err; - } + /* Create the sync control */ + err = scarlett2_add_sync_ctl(mixer); + if (err < 0) + return err; + + /* Create the direct monitor control */ + err = scarlett2_add_direct_monitor_ctl(mixer); + if (err < 0) + return err; + + /* Create the speaker switching control */ + err = scarlett2_add_speaker_switch_ctl(mixer); + if (err < 0) + return err; + + /* Create the talkback controls */ + err = scarlett2_add_talkback_ctls(mixer); + if (err < 0) + return err; + + /* Set up the interrupt polling */ + err = scarlett2_init_notify(mixer); + if (err < 0) + return err; return 0; } @@ -2050,30 +3952,15 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer, int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer) { struct snd_usb_audio *chip = mixer->chip; - const struct scarlett2_device_info *info; int err; /* only use UAC_VERSION_2 */ if (!mixer->protocol) return 0; - switch (chip->usb_id) { - case USB_ID(0x1235, 0x8203): - info = &s6i6_gen2_info; - break; - case USB_ID(0x1235, 0x8204): - info = &s18i8_gen2_info; - break; - case USB_ID(0x1235, 0x8201): - info = &s18i20_gen2_info; - break; - default: /* device not (yet) supported */ - return -EINVAL; - } - if (!(chip->setup & SCARLETT2_ENABLE)) { usb_audio_info(chip, - "Focusrite Scarlett Gen 2 Mixer Driver disabled; " + "Focusrite Scarlett Gen 2/3 Mixer Driver disabled; " "use options snd_usb_audio vid=0x%04x pid=0x%04x " "device_setup=1 to enable and report any issues " "to g@b4.vu", @@ -2083,10 +3970,10 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer) } usb_audio_info(chip, - "Focusrite Scarlett Gen 2 Mixer Driver enabled pid=0x%04x", + "Focusrite Scarlett Gen 2/3 Mixer Driver enabled pid=0x%04x", USB_ID_PRODUCT(chip->usb_id)); - err = snd_scarlett_gen2_controls_create(mixer, info); + err = snd_scarlett_gen2_controls_create(mixer); if (err < 0) usb_audio_err(mixer->chip, "Error initialising Scarlett Mixer Driver: %d", diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index e5311b6bb3f6..c66831ee15f9 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -29,15 +29,21 @@ #define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 /* return the estimated delay based on USB frame counters */ -snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, - unsigned int rate) +static snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime) { - int current_frame_number; - int frame_diff; + unsigned int current_frame_number; + unsigned int frame_diff; int est_delay; + int queued; - if (!subs->last_delay) - return 0; /* short path */ + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { + queued = bytes_to_frames(runtime, subs->inflight_bytes); + if (!queued) + return 0; + } else if (!subs->running) { + return 0; + } current_frame_number = usb_get_current_frame_number(subs->dev); /* @@ -49,14 +55,14 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, /* Approximation based on number of samples per USB frame (ms), some truncation for 44.1 but the estimate is good enough */ - est_delay = frame_diff * rate / 1000; - if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) - est_delay = subs->last_delay - est_delay; - else - est_delay = subs->last_delay + est_delay; + est_delay = frame_diff * runtime->rate / 1000; + + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { + est_delay = queued - est_delay; + if (est_delay < 0) + est_delay = 0; + } - if (est_delay < 0) - est_delay = 0; return est_delay; } @@ -65,17 +71,17 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, */ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) { - struct snd_usb_substream *subs = substream->runtime->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_usb_substream *subs = runtime->private_data; unsigned int hwptr_done; if (atomic_read(&subs->stream->chip->shutdown)) return SNDRV_PCM_POS_XRUN; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; - substream->runtime->delay = snd_usb_pcm_delay(subs, - substream->runtime->rate); + runtime->delay = snd_usb_pcm_delay(subs, runtime); spin_unlock(&subs->lock); - return hwptr_done / (substream->runtime->frame_bits >> 3); + return bytes_to_frames(runtime, hwptr_done); } /* @@ -600,17 +606,13 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; /* reset the pointer */ + subs->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size); + subs->inflight_bytes = 0; subs->hwptr_done = 0; subs->transfer_done = 0; - subs->last_delay = 0; subs->last_frame_number = 0; runtime->delay = 0; - /* for playback, submit the URBs now; otherwise, the first hwptr_done - * updates for all URBs would happen at the same time when starting */ - if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) - ret = start_endpoints(subs); - unlock: snd_usb_unlock_shutdown(chip); return ret; @@ -1147,28 +1149,23 @@ static void retire_capture_urb(struct snd_usb_substream *subs, spin_lock_irqsave(&subs->lock, flags); oldptr = subs->hwptr_done; subs->hwptr_done += bytes; - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; + if (subs->hwptr_done >= subs->buffer_bytes) + subs->hwptr_done -= subs->buffer_bytes; frames = (bytes + (oldptr % stride)) / stride; subs->transfer_done += frames; if (subs->transfer_done >= runtime->period_size) { subs->transfer_done -= runtime->period_size; period_elapsed = 1; } - /* capture delay is by construction limited to one URB, - * reset delays here - */ - runtime->delay = subs->last_delay = 0; /* realign last_frame_number */ subs->last_frame_number = current_frame_number; - subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ spin_unlock_irqrestore(&subs->lock, flags); /* copy a data chunk */ - if (oldptr + bytes > runtime->buffer_size * stride) { - unsigned int bytes1 = - runtime->buffer_size * stride - oldptr; + if (oldptr + bytes > subs->buffer_bytes) { + unsigned int bytes1 = subs->buffer_bytes - oldptr; + memcpy(runtime->dma_area + oldptr, cp, bytes1); memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); } else { @@ -1180,17 +1177,29 @@ static void retire_capture_urb(struct snd_usb_substream *subs, snd_pcm_period_elapsed(subs->pcm_substream); } +static void urb_ctx_queue_advance(struct snd_usb_substream *subs, + struct urb *urb, unsigned int bytes) +{ + struct snd_urb_ctx *ctx = urb->context; + + ctx->queued += bytes; + subs->inflight_bytes += bytes; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= subs->buffer_bytes) + subs->hwptr_done -= subs->buffer_bytes; +} + static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs, struct urb *urb, unsigned int bytes) { struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - unsigned int stride = runtime->frame_bits >> 3; unsigned int dst_idx = 0; unsigned int src_idx = subs->hwptr_done; - unsigned int wrap = runtime->buffer_size * stride; + unsigned int wrap = subs->buffer_bytes; u8 *dst = urb->transfer_buffer; u8 *src = runtime->dma_area; u8 marker[] = { 0x05, 0xfa }; + unsigned int queued = 0; /* * The DSP DOP format defines a way to transport DSD samples over @@ -1229,12 +1238,29 @@ static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs, dst[dst_idx++] = bitrev8(src[idx]); else dst[dst_idx++] = src[idx]; - - subs->hwptr_done++; + queued++; } } - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; + + urb_ctx_queue_advance(subs, urb, queued); +} + +/* copy bit-reversed bytes onto transfer buffer */ +static void fill_playback_urb_dsd_bitrev(struct snd_usb_substream *subs, + struct urb *urb, unsigned int bytes) +{ + struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; + const u8 *src = runtime->dma_area; + u8 *buf = urb->transfer_buffer; + int i, ofs = subs->hwptr_done; + + for (i = 0; i < bytes; i++) { + *buf++ = bitrev8(src[ofs]); + if (++ofs >= subs->buffer_bytes) + ofs = 0; + } + + urb_ctx_queue_advance(subs, urb, bytes); } static void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb, @@ -1242,10 +1268,10 @@ static void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb, { struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { + if (subs->hwptr_done + bytes > subs->buffer_bytes) { /* err, the transferred area goes over buffer boundary. */ - unsigned int bytes1 = - runtime->buffer_size * stride - subs->hwptr_done; + unsigned int bytes1 = subs->buffer_bytes - subs->hwptr_done; + memcpy(urb->transfer_buffer + offset, runtime->dma_area + subs->hwptr_done, bytes1); memcpy(urb->transfer_buffer + offset + bytes1, @@ -1254,9 +1280,8 @@ static void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb, memcpy(urb->transfer_buffer + offset, runtime->dma_area + subs->hwptr_done, bytes); } - subs->hwptr_done += bytes; - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; + + urb_ctx_queue_advance(subs, urb, bytes); } static unsigned int copy_to_urb_quirk(struct snd_usb_substream *subs, @@ -1295,17 +1320,18 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, int i, stride, period_elapsed = 0; unsigned long flags; - stride = runtime->frame_bits >> 3; + stride = ep->stride; frames = 0; + ctx->queued = 0; urb->number_of_packets = 0; spin_lock_irqsave(&subs->lock, flags); subs->frame_limit += ep->max_urb_frames; for (i = 0; i < ctx->packets; i++) { counts = snd_usb_endpoint_next_packet_size(ep, ctx, i); /* set up descriptor */ - urb->iso_frame_desc[i].offset = frames * ep->stride; - urb->iso_frame_desc[i].length = counts * ep->stride; + urb->iso_frame_desc[i].offset = frames * stride; + urb->iso_frame_desc[i].length = counts * stride; frames += counts; urb->number_of_packets++; subs->transfer_done += counts; @@ -1320,14 +1346,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, frames -= subs->transfer_done; counts -= subs->transfer_done; urb->iso_frame_desc[i].length = - counts * ep->stride; + counts * stride; subs->transfer_done = 0; } i++; if (i < ctx->packets) { /* add a transfer delimiter */ urb->iso_frame_desc[i].offset = - frames * ep->stride; + frames * stride; urb->iso_frame_desc[i].length = 0; urb->number_of_packets++; } @@ -1340,24 +1366,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, !snd_usb_endpoint_implicit_feedback_sink(ep)) break; } - bytes = frames * ep->stride; + bytes = frames * stride; if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE && subs->cur_audiofmt->dsd_dop)) { fill_playback_urb_dsd_dop(subs, urb, bytes); } else if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U8 && subs->cur_audiofmt->dsd_bitrev)) { - /* bit-reverse the bytes */ - u8 *buf = urb->transfer_buffer; - for (i = 0; i < bytes; i++) { - int idx = (subs->hwptr_done + i) - % (runtime->buffer_size * stride); - buf[i] = bitrev8(runtime->dma_area[idx]); - } - - subs->hwptr_done += bytes; - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; + fill_playback_urb_dsd_bitrev(subs, urb, bytes); } else { /* usual PCM */ if (!subs->tx_length_quirk) @@ -1367,14 +1383,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, /* bytes is now amount of outgoing data */ } - /* update delay with exact number of samples queued */ - runtime->delay = subs->last_delay; - runtime->delay += frames; - subs->last_delay = runtime->delay; - - /* realign last_frame_number */ subs->last_frame_number = usb_get_current_frame_number(subs->dev); - subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ if (subs->trigger_tstamp_pending_update) { /* this is the first actual URB submitted, @@ -1398,48 +1407,17 @@ static void retire_playback_urb(struct snd_usb_substream *subs, struct urb *urb) { unsigned long flags; - struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - struct snd_usb_endpoint *ep = subs->data_endpoint; - int processed = urb->transfer_buffer_length / ep->stride; - int est_delay; - - /* ignore the delay accounting when processed=0 is given, i.e. - * silent payloads are processed before handling the actual data - */ - if (!processed) - return; + struct snd_urb_ctx *ctx = urb->context; spin_lock_irqsave(&subs->lock, flags); - if (!subs->last_delay) - goto out; /* short path */ - - est_delay = snd_usb_pcm_delay(subs, runtime->rate); - /* update delay with exact number of samples played */ - if (processed > subs->last_delay) - subs->last_delay = 0; - else - subs->last_delay -= processed; - runtime->delay = subs->last_delay; - - /* - * Report when delay estimate is off by more than 2ms. - * The error should be lower than 2ms since the estimate relies - * on two reads of a counter updated every ms. - */ - if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) - dev_dbg_ratelimited(&subs->dev->dev, - "delay: estimated %d, actual %d\n", - est_delay, subs->last_delay); - - if (!subs->running) { - /* update last_frame_number for delay counting here since - * prepare_playback_urb won't be called during pause - */ - subs->last_frame_number = - usb_get_current_frame_number(subs->dev) & 0xff; + if (ctx->queued) { + if (subs->inflight_bytes >= ctx->queued) + subs->inflight_bytes -= ctx->queued; + else + subs->inflight_bytes = 0; } - out: + subs->last_frame_number = usb_get_current_frame_number(subs->dev); spin_unlock_irqrestore(&subs->lock, flags); } @@ -1447,6 +1425,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea int cmd) { struct snd_usb_substream *subs = substream->runtime->private_data; + int err; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1457,6 +1436,14 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea prepare_playback_urb, retire_playback_urb, subs); + if (cmd == SNDRV_PCM_TRIGGER_START) { + err = start_endpoints(subs); + if (err < 0) { + snd_usb_endpoint_set_callback(subs->data_endpoint, + NULL, NULL, NULL); + return err; + } + } subs->running = 1; dev_dbg(&subs->dev->dev, "%d:%d Start Playback PCM\n", subs->cur_audiofmt->iface, @@ -1504,6 +1491,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream snd_usb_endpoint_set_callback(subs->data_endpoint, NULL, retire_capture_urb, subs); + subs->last_frame_number = usb_get_current_frame_number(subs->dev); subs->running = 1; dev_dbg(&subs->dev->dev, "%d:%d Start Capture PCM\n", subs->cur_audiofmt->iface, diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index 06c586467d3f..493a4e34d78d 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -2,9 +2,6 @@ #ifndef __USBAUDIO_PCM_H #define __USBAUDIO_PCM_H -snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, - unsigned int rate); - void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); int snd_usb_pcm_suspend(struct snd_usb_stream *as); int snd_usb_pcm_resume(struct snd_usb_stream *as); diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index bdba37d0faab..19bb499c17da 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3044,6 +3044,76 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } }, +/* Denon DN-X1600 */ +{ + USB_AUDIO_DEVICE(0x154e, 0x500e), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Denon", + .product_name = "DN-X1600", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]){ + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE, + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = 0x0, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_ADAPTIVE, + .maxpacksize = 0x138, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = 0x0, + .endpoint = 0x85, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_ADAPTIVE, + .maxpacksize = 0x138, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 4, + .type = QUIRK_MIDI_STANDARD_INTERFACE, + }, + { + .ifnum = -1 + } + } + } +}, + /* Microsoft XboxLive Headset/Xbox Communicator */ { USB_DEVICE(0x045e, 0x0283), diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 6e1bfe894dd5..e558931cce16 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -49,7 +49,7 @@ static int us122l_create_usbmidi(struct snd_card *card) static const struct snd_usb_audio_quirk quirk = { .vendor_name = "US122L", .product_name = NAME_ALLCAPS, - .ifnum = 1, + .ifnum = 1, .type = QUIRK_MIDI_US122L, .data = &quirk_data }; @@ -71,7 +71,7 @@ static int us144_create_usbmidi(struct snd_card *card) static const struct snd_usb_audio_quirk quirk = { .vendor_name = "US144", .product_name = NAME_ALLCAPS, - .ifnum = 0, + .ifnum = 0, .type = QUIRK_MIDI_US122L, .data = &quirk_data }; @@ -95,6 +95,7 @@ static void pt_info_set(struct usb_device *dev, u8 v) static void usb_stream_hwdep_vm_open(struct vm_area_struct *area) { struct us122l *us122l = area->vm_private_data; + atomic_inc(&us122l->mmap_count); snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count)); } @@ -113,9 +114,9 @@ static vm_fault_t usb_stream_hwdep_vm_fault(struct vm_fault *vmf) goto unlock; offset = vmf->pgoff << PAGE_SHIFT; - if (offset < PAGE_ALIGN(s->read_size)) + if (offset < PAGE_ALIGN(s->read_size)) { vaddr = (char *)s + offset; - else { + } else { offset -= PAGE_ALIGN(s->read_size); if (offset >= PAGE_ALIGN(s->write_size)) goto unlock; @@ -138,6 +139,7 @@ unlock: static void usb_stream_hwdep_vm_close(struct vm_area_struct *area) { struct us122l *us122l = area->vm_private_data; + atomic_dec(&us122l->mmap_count); snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count)); } @@ -148,11 +150,11 @@ static const struct vm_operations_struct usb_stream_hwdep_vm_ops = { .close = usb_stream_hwdep_vm_close, }; - static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) { struct us122l *us122l = hw->private_data; struct usb_interface *iface; + snd_printdd(KERN_DEBUG "%p %p\n", hw, file); if (hw->used >= 2) return -EBUSY; @@ -173,6 +175,7 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) { struct us122l *us122l = hw->private_data; struct usb_interface *iface; + snd_printdd(KERN_DEBUG "%p %p\n", hw, file); if (us122l->is_us144) { @@ -235,7 +238,7 @@ static __poll_t usb_stream_hwdep_poll(struct snd_hwdep *hw, struct file *file, poll_table *wait) { struct us122l *us122l = hw->private_data; - unsigned *polled; + unsigned int *polled; __poll_t mask; poll_wait(file, &us122l->sk.sleep, wait); @@ -243,6 +246,7 @@ static __poll_t usb_stream_hwdep_poll(struct snd_hwdep *hw, mask = EPOLLIN | EPOLLOUT | EPOLLWRNORM | EPOLLERR; if (mutex_trylock(&us122l->mutex)) { struct usb_stream *s = us122l->sk.s; + if (s && s->state == usb_stream_ready) { if (us122l->first == file) polled = &s->periods_polled; @@ -251,8 +255,9 @@ static __poll_t usb_stream_hwdep_poll(struct snd_hwdep *hw, if (*polled != s->periods_done) { *polled = s->periods_done; mask = EPOLLIN | EPOLLOUT | EPOLLWRNORM; - } else + } else { mask = 0; + } } mutex_unlock(&us122l->mutex); } @@ -262,6 +267,7 @@ static __poll_t usb_stream_hwdep_poll(struct snd_hwdep *hw, static void us122l_stop(struct us122l *us122l) { struct list_head *p; + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); @@ -289,11 +295,11 @@ static int us122l_set_sample_rate(struct usb_device *dev, int rate) } static bool us122l_start(struct us122l *us122l, - unsigned rate, unsigned period_frames) + unsigned int rate, unsigned int period_frames) { struct list_head *p; int err; - unsigned use_packsize = 0; + unsigned int use_packsize = 0; bool success = false; if (us122l->dev->speed == USB_SPEED_HIGH) { @@ -320,13 +326,13 @@ static bool us122l_start(struct us122l *us122l, err = us122l_set_sample_rate(us122l->dev, rate); if (err < 0) { us122l_stop(us122l); - snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); + snd_printk(KERN_ERR "us122l_set_sample_rate error\n"); goto out; } err = usb_stream_start(&us122l->sk); if (err < 0) { us122l_stop(us122l); - snd_printk(KERN_ERR "us122l_start error %i \n", err); + snd_printk(KERN_ERR "%s error %i\n", __func__, err); goto out; } list_for_each(p, &us122l->midi_list) @@ -337,12 +343,12 @@ out: } static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, - unsigned cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { struct usb_stream_config cfg; struct us122l *us122l = hw->private_data; struct usb_stream *s; - unsigned min_period_frames; + unsigned int min_period_frames; int err = 0; bool high_speed; @@ -379,13 +385,13 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, if (cfg.period_frames < min_period_frames) return -EINVAL; - snd_power_wait(hw->card, SNDRV_CTL_POWER_D0); + snd_power_wait(hw->card); mutex_lock(&us122l->mutex); s = us122l->sk.s; - if (!us122l->master) + if (!us122l->master) { us122l->master = file; - else if (us122l->master != file) { + } else if (us122l->master != file) { if (!s || memcmp(&cfg, &s->cfg, sizeof(cfg))) { err = -EIO; goto unlock; @@ -431,7 +437,6 @@ static int usb_stream_hwdep_new(struct snd_card *card) return 0; } - static bool us122l_create_card(struct snd_card *card) { int err; @@ -440,13 +445,13 @@ static bool us122l_create_card(struct snd_card *card) if (us122l->is_us144) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { - snd_printk(KERN_ERR "usb_set_interface error \n"); + snd_printk(KERN_ERR "usb_set_interface error\n"); return false; } } err = usb_set_interface(us122l->dev, 1, 1); if (err) { - snd_printk(KERN_ERR "usb_set_interface error \n"); + snd_printk(KERN_ERR "usb_set_interface error\n"); return false; } @@ -461,13 +466,14 @@ static bool us122l_create_card(struct snd_card *card) else err = us122l_create_usbmidi(card); if (err < 0) { - snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err); + snd_printk(KERN_ERR "us122l_create_usbmidi error %i\n", err); goto stop; } err = usb_stream_hwdep_new(card); if (err < 0) { -/* release the midi resources */ + /* release the midi resources */ struct list_head *p; + list_for_each(p, &us122l->midi_list) snd_usbmidi_disconnect(p); @@ -484,7 +490,8 @@ static void snd_us122l_free(struct snd_card *card) { struct us122l *us122l = US122L(card); int index = us122l->card_index; - if (index >= 0 && index < SNDRV_CARDS) + + if (index >= 0 && index < SNDRV_CARDS) snd_us122l_card_used[index] = 0; } @@ -565,7 +572,7 @@ static int snd_us122l_probe(struct usb_interface *intf, if (id->driver_info & US122L_FLAG_US144 && device->speed == USB_SPEED_HIGH) { - snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); + snd_printk(KERN_ERR "disable ehci-hcd to run US-144\n"); return -ENODEV; } @@ -601,7 +608,7 @@ static void snd_us122l_disconnect(struct usb_interface *intf) us122l_stop(us122l); mutex_unlock(&us122l->mutex); -/* release the midi resources */ + /* release the midi resources */ list_for_each(p, &us122l->midi_list) { snd_usbmidi_disconnect(p); } @@ -661,13 +668,13 @@ static int snd_us122l_resume(struct usb_interface *intf) if (us122l->is_us144) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { - snd_printk(KERN_ERR "usb_set_interface error \n"); + snd_printk(KERN_ERR "usb_set_interface error\n"); goto unlock; } } err = usb_set_interface(us122l->dev, 1, 1); if (err) { - snd_printk(KERN_ERR "usb_set_interface error \n"); + snd_printk(KERN_ERR "usb_set_interface error\n"); goto unlock; } @@ -677,7 +684,7 @@ static int snd_us122l_resume(struct usb_interface *intf) err = us122l_set_sample_rate(us122l->dev, us122l->sk.s->cfg.sample_rate); if (err < 0) { - snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); + snd_printk(KERN_ERR "us122l_set_sample_rate error\n"); goto unlock; } err = usb_stream_start(&us122l->sk); @@ -717,8 +724,8 @@ static const struct usb_device_id snd_us122l_usb_id_table[] = { }, { /* terminator */ } }; - MODULE_DEVICE_TABLE(usb, snd_us122l_usb_id_table); + static struct usb_driver snd_us122l_usb_driver = { .name = "snd-usb-us122l", .probe = snd_us122l_probe, diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 34bea99d343c..c32ae5e981e9 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -11,7 +11,7 @@ struct us122l { struct mutex mutex; struct file *first; - unsigned second_periods_polled; + unsigned int second_periods_polled; struct file *master; struct file *slave; struct list_head midi_list; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 22412cd69e98..c29da0341bc5 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -21,15 +21,15 @@ static vm_fault_t snd_us428ctls_vm_fault(struct vm_fault *vmf) { unsigned long offset; - struct page * page; + struct page *page; void *vaddr; snd_printdd("ENTER, start %lXh, pgoff %ld\n", vmf->vma->vm_start, vmf->pgoff); - + offset = vmf->pgoff << PAGE_SHIFT; - vaddr = (char *)((struct usX2Ydev *)vmf->vma->vm_private_data)->us428ctls_sharedmem + offset; + vaddr = (char *)((struct usx2ydev *)vmf->vma->vm_private_data)->us428ctls_sharedmem + offset; page = virt_to_page(vaddr); get_page(page); vmf->page = page; @@ -44,30 +44,22 @@ static const struct vm_operations_struct us428ctls_vm_ops = { .fault = snd_us428ctls_vm_fault, }; -static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area) +static int snd_us428ctls_mmap(struct snd_hwdep *hw, struct file *filp, struct vm_area_struct *area) { unsigned long size = (unsigned long)(area->vm_end - area->vm_start); - struct usX2Ydev *us428 = hw->private_data; + struct usx2ydev *us428 = hw->private_data; // FIXME this hwdep interface is used twice: fpga download and mmap for controlling Lights etc. Maybe better using 2 hwdep devs? // so as long as the device isn't fully initialised yet we return -EBUSY here. - if (!(us428->chip_status & USX2Y_STAT_CHIP_INIT)) + if (!(us428->chip_status & USX2Y_STAT_CHIP_INIT)) return -EBUSY; - /* if userspace tries to mmap beyond end of our buffer, fail */ - if (size > PAGE_ALIGN(sizeof(struct us428ctls_sharedmem))) { - snd_printd( "%lu > %lu\n", size, (unsigned long)sizeof(struct us428ctls_sharedmem)); - return -EINVAL; + /* if userspace tries to mmap beyond end of our buffer, fail */ + if (size > US428_SHAREDMEM_PAGES) { + snd_printd("%lu > %lu\n", size, (unsigned long)US428_SHAREDMEM_PAGES); + return -EINVAL; } - if (!us428->us428ctls_sharedmem) { - init_waitqueue_head(&us428->us428ctls_wait_queue_head); - us428->us428ctls_sharedmem = alloc_pages_exact(sizeof(struct us428ctls_sharedmem), GFP_KERNEL); - if (!us428->us428ctls_sharedmem) - return -ENOMEM; - memset(us428->us428ctls_sharedmem, -1, sizeof(struct us428ctls_sharedmem)); - us428->us428ctls_sharedmem->CtlSnapShotLast = -2; - } area->vm_ops = &us428ctls_vm_ops; area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; area->vm_private_data = hw->private_data; @@ -77,21 +69,22 @@ static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct v static __poll_t snd_us428ctls_poll(struct snd_hwdep *hw, struct file *file, poll_table *wait) { __poll_t mask = 0; - struct usX2Ydev *us428 = hw->private_data; + struct usx2ydev *us428 = hw->private_data; struct us428ctls_sharedmem *shm = us428->us428ctls_sharedmem; + if (us428->chip_status & USX2Y_STAT_CHIP_HUP) return EPOLLHUP; poll_wait(file, &us428->us428ctls_wait_queue_head, wait); - if (shm != NULL && shm->CtlSnapShotLast != shm->CtlSnapShotRed) + if (shm && shm->ctl_snapshot_last != shm->ctl_snapshot_red) mask |= EPOLLIN; return mask; } -static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, +static int snd_usx2y_hwdep_dsp_status(struct snd_hwdep *hw, struct snd_hwdep_dsp_status *info) { static const char * const type_ids[USX2Y_TYPE_NUMS] = { @@ -99,7 +92,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, [USX2Y_TYPE_224] = "us224", [USX2Y_TYPE_428] = "us428", }; - struct usX2Ydev *us428 = hw->private_data; + struct usx2ydev *us428 = hw->private_data; int id = -1; switch (le16_to_cpu(us428->dev->descriptor.idProduct)) { @@ -113,7 +106,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, id = USX2Y_TYPE_428; break; } - if (0 > id) + if (id < 0) return -ENODEV; strcpy(info->id, type_ids[id]); info->num_dsps = 2; // 0: Prepad Data, 1: FPGA Code @@ -123,8 +116,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, return 0; } - -static int usX2Y_create_usbmidi(struct snd_card *card) +static int usx2y_create_usbmidi(struct snd_card *card) { static const struct snd_usb_midi_endpoint_info quirk_data_1 = { .out_ep = 0x06, @@ -135,8 +127,8 @@ static int usX2Y_create_usbmidi(struct snd_card *card) static const struct snd_usb_audio_quirk quirk_1 = { .vendor_name = "TASCAM", .product_name = NAME_ALLCAPS, - .ifnum = 0, - .type = QUIRK_MIDI_FIXED_ENDPOINT, + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &quirk_data_1 }; static const struct snd_usb_midi_endpoint_info quirk_data_2 = { @@ -148,49 +140,50 @@ static int usX2Y_create_usbmidi(struct snd_card *card) static const struct snd_usb_audio_quirk quirk_2 = { .vendor_name = "TASCAM", .product_name = "US428", - .ifnum = 0, - .type = QUIRK_MIDI_FIXED_ENDPOINT, + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &quirk_data_2 }; - struct usb_device *dev = usX2Y(card)->dev; + struct usb_device *dev = usx2y(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); const struct snd_usb_audio_quirk *quirk = le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ? &quirk_2 : &quirk_1; - snd_printdd("usX2Y_create_usbmidi \n"); - return snd_usbmidi_create(card, iface, &usX2Y(card)->midi_list, quirk); + snd_printdd("%s\n", __func__); + return snd_usbmidi_create(card, iface, &usx2y(card)->midi_list, quirk); } -static int usX2Y_create_alsa_devices(struct snd_card *card) +static int usx2y_create_alsa_devices(struct snd_card *card) { int err; - do { - if ((err = usX2Y_create_usbmidi(card)) < 0) { - snd_printk(KERN_ERR "usX2Y_create_alsa_devices: usX2Y_create_usbmidi error %i \n", err); - break; - } - if ((err = usX2Y_audio_create(card)) < 0) - break; - if ((err = usX2Y_hwdep_pcm_new(card)) < 0) - break; - if ((err = snd_card_register(card)) < 0) - break; - } while (0); - - return err; -} + err = usx2y_create_usbmidi(card); + if (err < 0) { + snd_printk(KERN_ERR "%s: usx2y_create_usbmidi error %i\n", __func__, err); + return err; + } + err = usx2y_audio_create(card); + if (err < 0) + return err; + err = usx2y_hwdep_pcm_new(card); + if (err < 0) + return err; + err = snd_card_register(card); + if (err < 0) + return err; + return 0; +} -static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, +static int snd_usx2y_hwdep_dsp_load(struct snd_hwdep *hw, struct snd_hwdep_dsp_image *dsp) { - struct usX2Ydev *priv = hw->private_data; - struct usb_device* dev = priv->dev; + struct usx2ydev *priv = hw->private_data; + struct usb_device *dev = priv->dev; int lret, err; char *buf; - snd_printdd( "dsp_load %s\n", dsp->name); + snd_printdd("dsp_load %s\n", dsp->name); buf = memdup_user(dsp->image, dsp->length); if (IS_ERR(buf)) @@ -198,7 +191,7 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, err = usb_set_interface(dev, 0, 1); if (err) - snd_printk(KERN_ERR "usb_set_interface error \n"); + snd_printk(KERN_ERR "usb_set_interface error\n"); else err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000); kfree(buf); @@ -206,45 +199,51 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, return err; if (dsp->index == 1) { msleep(250); // give the device some time - err = usX2Y_AsyncSeq04_init(priv); + err = usx2y_async_seq04_init(priv); if (err) { - snd_printk(KERN_ERR "usX2Y_AsyncSeq04_init error \n"); + snd_printk(KERN_ERR "usx2y_async_seq04_init error\n"); return err; } - err = usX2Y_In04_init(priv); + err = usx2y_in04_init(priv); if (err) { - snd_printk(KERN_ERR "usX2Y_In04_init error \n"); + snd_printk(KERN_ERR "usx2y_in04_init error\n"); return err; } - err = usX2Y_create_alsa_devices(hw->card); + err = usx2y_create_alsa_devices(hw->card); if (err) { - snd_printk(KERN_ERR "usX2Y_create_alsa_devices error %i \n", err); - snd_card_free(hw->card); + snd_printk(KERN_ERR "usx2y_create_alsa_devices error %i\n", err); return err; } - priv->chip_status |= USX2Y_STAT_CHIP_INIT; + priv->chip_status |= USX2Y_STAT_CHIP_INIT; snd_printdd("%s: alsa all started\n", hw->name); } return err; } - -int usX2Y_hwdep_new(struct snd_card *card, struct usb_device* device) +int usx2y_hwdep_new(struct snd_card *card, struct usb_device *device) { int err; struct snd_hwdep *hw; + struct usx2ydev *us428 = usx2y(card); - if ((err = snd_hwdep_new(card, SND_USX2Y_LOADER_ID, 0, &hw)) < 0) + err = snd_hwdep_new(card, SND_USX2Y_LOADER_ID, 0, &hw); + if (err < 0) return err; hw->iface = SNDRV_HWDEP_IFACE_USX2Y; - hw->private_data = usX2Y(card); - hw->ops.dsp_status = snd_usX2Y_hwdep_dsp_status; - hw->ops.dsp_load = snd_usX2Y_hwdep_dsp_load; + hw->private_data = us428; + hw->ops.dsp_status = snd_usx2y_hwdep_dsp_status; + hw->ops.dsp_load = snd_usx2y_hwdep_dsp_load; hw->ops.mmap = snd_us428ctls_mmap; hw->ops.poll = snd_us428ctls_poll; hw->exclusive = 1; sprintf(hw->name, "/dev/bus/usb/%03d/%03d", device->bus->busnum, device->devnum); + + us428->us428ctls_sharedmem = alloc_pages_exact(US428_SHAREDMEM_PAGES, GFP_KERNEL); + if (!us428->us428ctls_sharedmem) + return -ENOMEM; + memset(us428->us428ctls_sharedmem, -1, US428_SHAREDMEM_PAGES); + us428->us428ctls_sharedmem->ctl_snapshot_last = -2; + return 0; } - diff --git a/sound/usb/usx2y/usX2Yhwdep.h b/sound/usb/usx2y/usX2Yhwdep.h index 457199b5ed03..0c9946d9cd99 100644 --- a/sound/usb/usx2y/usX2Yhwdep.h +++ b/sound/usb/usx2y/usX2Yhwdep.h @@ -2,6 +2,6 @@ #ifndef USX2YHWDEP_H #define USX2YHWDEP_H -int usX2Y_hwdep_new(struct snd_card *card, struct usb_device* device); +int usx2y_hwdep_new(struct snd_card *card, struct usb_device *device); #endif diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index 091c071b270a..9d0e44793896 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -8,12 +8,12 @@ #include "usb_stream.h" - /* setup */ -static unsigned usb_stream_next_packet_size(struct usb_stream_kernel *sk) +static unsigned int usb_stream_next_packet_size(struct usb_stream_kernel *sk) { struct usb_stream *s = sk->s; + sk->out_phase_peeked = (sk->out_phase & 0xffff) + sk->freqn; return (sk->out_phase_peeked >> 16) * s->cfg.frame_size; } @@ -25,6 +25,7 @@ static void playback_prep_freqn(struct usb_stream_kernel *sk, struct urb *urb) for (pack = 0; pack < sk->n_o_ps; pack++) { int l = usb_stream_next_packet_size(sk); + if (s->idle_outsize + lb + l > s->period_size) goto check; @@ -43,9 +44,10 @@ check: lb, s->period_size); } -static int init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, - struct urb **urbs, char *transfer, - struct usb_device *dev, int pipe) +static int init_pipe_urbs(struct usb_stream_kernel *sk, + unsigned int use_packsize, + struct urb **urbs, char *transfer, + struct usb_device *dev, int pipe) { int u, p; int maxpacket = use_packsize ? @@ -56,6 +58,7 @@ static int init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, ++u, transfer += transfer_length) { struct urb *urb = urbs[u]; struct usb_iso_packet_descriptor *desc; + urb->transfer_buffer = transfer; urb->dev = dev; urb->pipe = pipe; @@ -80,13 +83,12 @@ static int init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, return 0; } -static int init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, - struct usb_device *dev, int in_pipe, int out_pipe) +static int init_urbs(struct usb_stream_kernel *sk, unsigned int use_packsize, + struct usb_device *dev, int in_pipe, int out_pipe) { struct usb_stream *s = sk->s; - char *indata = (char *)s + sizeof(*s) + - sizeof(struct usb_stream_packet) * - s->inpackets; + char *indata = + (char *)s + sizeof(*s) + sizeof(struct usb_stream_packet) * s->inpackets; int u; for (u = 0; u < USB_STREAM_NURBS; ++u) { @@ -107,12 +109,11 @@ static int init_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, return 0; } - /* * convert a sampling rate into our full speed format (fs/1000 in Q16.16) * this will overflow at approx 524 kHz */ -static inline unsigned get_usb_full_speed_rate(unsigned rate) +static inline unsigned int get_usb_full_speed_rate(unsigned int rate) { return ((rate << 13) + 62) / 125; } @@ -121,7 +122,7 @@ static inline unsigned get_usb_full_speed_rate(unsigned rate) * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) * this will overflow at approx 4 MHz */ -static inline unsigned get_usb_high_speed_rate(unsigned rate) +static inline unsigned int get_usb_high_speed_rate(unsigned int rate) { return ((rate << 10) + 62) / 125; } @@ -129,7 +130,7 @@ static inline unsigned get_usb_high_speed_rate(unsigned rate) void usb_stream_free(struct usb_stream_kernel *sk) { struct usb_stream *s; - unsigned u; + unsigned int u; for (u = 0; u < USB_STREAM_NURBS; ++u) { usb_free_urb(sk->inurb[u]); @@ -142,17 +143,23 @@ void usb_stream_free(struct usb_stream_kernel *sk) if (!s) return; - free_pages_exact(sk->write_page, s->write_size); - sk->write_page = NULL; + if (sk->write_page) { + free_pages_exact(sk->write_page, s->write_size); + sk->write_page = NULL; + } + free_pages_exact(s, s->read_size); sk->s = NULL; } struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk, struct usb_device *dev, - unsigned in_endpoint, unsigned out_endpoint, - unsigned sample_rate, unsigned use_packsize, - unsigned period_frames, unsigned frame_size) + unsigned int in_endpoint, + unsigned int out_endpoint, + unsigned int sample_rate, + unsigned int use_packsize, + unsigned int period_frames, + unsigned int frame_size) { int packets, max_packsize; int in_pipe, out_pipe; @@ -231,12 +238,12 @@ out: return sk->s; } - /* start */ static bool balance_check(struct usb_stream_kernel *sk, struct urb *urb) { bool r; + if (unlikely(urb->status)) { if (urb->status != -ESHUTDOWN && urb->status != -ENOENT) snd_printk(KERN_WARNING "status=%i\n", urb->status); @@ -267,6 +274,7 @@ static void subs_set_complete(struct urb **urbs, void (*complete)(struct urb *)) for (u = 0; u < USB_STREAM_NURBS; u++) { struct urb *urb = urbs[u]; + urb->complete = complete; } } @@ -284,6 +292,7 @@ static int usb_stream_prepare_playback(struct usb_stream_kernel *sk, for (; s->sync_packet < 0; ++p, ++s->sync_packet) { struct urb *ii = sk->completed_inurb; + id = ii->iso_frame_desc + ii->number_of_packets + s->sync_packet; l = id->actual_length; @@ -351,6 +360,7 @@ static int submit_urbs(struct usb_stream_kernel *sk, struct urb *inurb, struct urb *outurb) { int err; + prepare_inurb(sk->idle_outurb->number_of_packets, sk->idle_inurb); err = usb_submit_urb(sk->idle_inurb, GFP_ATOMIC); if (err < 0) @@ -447,6 +457,7 @@ static void stream_idle(struct usb_stream_kernel *sk, for (p = 0; p < inurb->number_of_packets; ++p) { struct usb_iso_packet_descriptor *id = inurb->iso_frame_desc; + l = id[p].actual_length; if (unlikely(l == 0 || id[p].status)) { snd_printk(KERN_WARNING "underrun, status=%u\n", @@ -503,6 +514,7 @@ err_out: static void i_capture_idle(struct urb *urb) { struct usb_stream_kernel *sk = urb->context; + if (balance_capture(sk, urb)) stream_idle(sk, urb, sk->i_urb); } @@ -510,6 +522,7 @@ static void i_capture_idle(struct urb *urb) static void i_playback_idle(struct urb *urb) { struct usb_stream_kernel *sk = urb->context; + if (balance_playback(sk, urb)) stream_idle(sk, sk->i_urb, urb); } @@ -518,10 +531,12 @@ static void stream_start(struct usb_stream_kernel *sk, struct urb *inurb, struct urb *outurb) { struct usb_stream *s = sk->s; + if (s->state >= usb_stream_sync1) { int l, p, max_diff, max_diff_0; int urb_size = 0; - unsigned frames_per_packet, min_frames = 0; + unsigned int frames_per_packet, min_frames = 0; + frames_per_packet = (s->period_size - s->idle_insize); frames_per_packet <<= 8; frames_per_packet /= @@ -536,6 +551,7 @@ static void stream_start(struct usb_stream_kernel *sk, max_diff = max_diff_0; for (p = 0; p < inurb->number_of_packets; ++p) { int diff; + l = inurb->iso_frame_desc[p].actual_length; urb_size += l; @@ -561,7 +577,8 @@ static void stream_start(struct usb_stream_kernel *sk, (s->inpacket_head + 1) % s->inpackets; s->next_inpacket_split_at = 0; } else { - unsigned split = s->inpacket_head; + unsigned int split = s->inpacket_head; + l = s->idle_insize; while (l > s->inpacket[split].length) { l -= s->inpacket[split].length; @@ -609,6 +626,7 @@ static void i_capture_start(struct urb *urb) for (p = 0; p < urb->number_of_packets; ++p) { int l = id[p].actual_length; + if (l < s->cfg.frame_size) { ++empty; if (s->state >= usb_stream_sync0) { @@ -628,6 +646,7 @@ static void i_capture_start(struct urb *urb) urb->iso_frame_desc[0].actual_length); for (pack = 1; pack < urb->number_of_packets; ++pack) { int l = urb->iso_frame_desc[pack].actual_length; + printk(KERN_CONT " %i", l); } printk(KERN_CONT "\n"); @@ -643,6 +662,7 @@ static void i_capture_start(struct urb *urb) static void i_playback_start(struct urb *urb) { struct usb_stream_kernel *sk = urb->context; + if (balance_playback(sk, urb)) stream_start(sk, sk->i_urb, urb); } @@ -671,6 +691,7 @@ dotry: for (u = 0; u < 2; u++) { struct urb *inurb = sk->inurb[u]; struct urb *outurb = sk->outurb[u]; + playback_prep_freqn(sk, outurb); inurb->number_of_packets = outurb->number_of_packets; inurb->transfer_buffer_length = @@ -680,6 +701,7 @@ dotry: if (u == 0) { int now; struct usb_device *dev = inurb->dev; + frame = usb_get_current_frame_number(dev); do { now = usb_get_current_frame_number(dev); @@ -688,14 +710,16 @@ dotry: } err = usb_submit_urb(inurb, GFP_ATOMIC); if (err < 0) { - snd_printk(KERN_ERR"usb_submit_urb(sk->inurb[%i])" - " returned %i\n", u, err); + snd_printk(KERN_ERR + "usb_submit_urb(sk->inurb[%i]) returned %i\n", + u, err); return err; } err = usb_submit_urb(outurb, GFP_ATOMIC); if (err < 0) { - snd_printk(KERN_ERR"usb_submit_urb(sk->outurb[%i])" - " returned %i\n", u, err); + snd_printk(KERN_ERR + "usb_submit_urb(sk->outurb[%i]) returned %i\n", + u, err); return err; } @@ -716,8 +740,8 @@ check_retry: snd_printd(KERN_DEBUG "goto dotry;\n"); goto dotry; } - snd_printk(KERN_WARNING"couldn't start" - " all urbs on the same start_frame.\n"); + snd_printk(KERN_WARNING + "couldn't start all urbs on the same start_frame.\n"); return -EFAULT; } @@ -729,6 +753,7 @@ check_retry: /* wait, check */ { int wait_ms = 3000; + while (s->state != usb_stream_ready && wait_ms > 0) { snd_printdd(KERN_DEBUG "%i\n", s->state); msleep(200); @@ -745,6 +770,7 @@ check_retry: void usb_stream_stop(struct usb_stream_kernel *sk) { int u; + if (!sk->s) return; for (u = 0; u < USB_STREAM_NURBS; ++u) { diff --git a/sound/usb/usx2y/usb_stream.h b/sound/usb/usx2y/usb_stream.h index 851358a8d709..73e57b341adc 100644 --- a/sound/usb/usx2y/usb_stream.h +++ b/sound/usb/usx2y/usb_stream.h @@ -12,7 +12,7 @@ struct usb_stream_kernel { void *write_page; - unsigned n_o_ps; + unsigned int n_o_ps; struct urb *inurb[USB_STREAM_NURBS]; struct urb *idle_inurb; @@ -26,18 +26,21 @@ struct usb_stream_kernel { wait_queue_head_t sleep; - unsigned out_phase; - unsigned out_phase_peeked; - unsigned freqn; + unsigned int out_phase; + unsigned int out_phase_peeked; + unsigned int freqn; }; struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk, struct usb_device *dev, - unsigned in_endpoint, unsigned out_endpoint, - unsigned sample_rate, unsigned use_packsize, - unsigned period_frames, unsigned frame_size); -void usb_stream_free(struct usb_stream_kernel *); -int usb_stream_start(struct usb_stream_kernel *); -void usb_stream_stop(struct usb_stream_kernel *); + unsigned int in_endpoint, + unsigned int out_endpoint, + unsigned int sample_rate, + unsigned int use_packsize, + unsigned int period_frames, + unsigned int frame_size); +void usb_stream_free(struct usb_stream_kernel *sk); +int usb_stream_start(struct usb_stream_kernel *sk); +void usb_stream_stop(struct usb_stream_kernel *sk); #endif /* __USB_STREAM_H */ diff --git a/sound/usb/usx2y/usbus428ctldefs.h b/sound/usb/usx2y/usbus428ctldefs.h index 5a7518ea3aeb..9ba15d974e63 100644 --- a/sound/usb/usx2y/usbus428ctldefs.h +++ b/sound/usb/usx2y/usbus428ctldefs.h @@ -4,28 +4,28 @@ * Copyright (c) 2003 by Karsten Wiese <annabellesgarden@yahoo.de> */ -enum E_In84{ - eFader0 = 0, - eFader1, - eFader2, - eFader3, - eFader4, - eFader5, - eFader6, - eFader7, - eFaderM, - eTransport, - eModifier = 10, - eFilterSelect, - eSelect, - eMute, +enum E_IN84 { + E_FADER_0 = 0, + E_FADER_1, + E_FADER_2, + E_FADER_3, + E_FADER_4, + E_FADER_5, + E_FADER_6, + E_FADER_7, + E_FADER_M, + E_TRANSPORT, + E_MODIFIER = 10, + E_FILTER_SELECT, + E_SELECT, + E_MUTE, - eSwitch = 15, - eWheelGain, - eWheelFreq, - eWheelQ, - eWheelPan, - eWheel = 20 + E_SWITCH = 15, + E_WHEEL_GAIN, + E_WHEEL_FREQ, + E_WHEEL_Q, + E_WHEEL_PAN, + E_WHEEL = 20 }; #define T_RECORD 1 @@ -39,53 +39,55 @@ enum E_In84{ struct us428_ctls { - unsigned char Fader[9]; - unsigned char Transport; - unsigned char Modifier; - unsigned char FilterSelect; - unsigned char Select; - unsigned char Mute; - unsigned char UNKNOWN; - unsigned char Switch; - unsigned char Wheel[5]; + unsigned char fader[9]; + unsigned char transport; + unsigned char modifier; + unsigned char filters_elect; + unsigned char select; + unsigned char mute; + unsigned char unknown; + unsigned char wswitch; + unsigned char wheel[5]; }; -struct us428_setByte { - unsigned char Offset, - Value; +struct us428_set_byte { + unsigned char offset, + value; }; enum { - eLT_Volume = 0, - eLT_Light + ELT_VOLUME = 0, + ELT_LIGHT }; -struct usX2Y_volume { - unsigned char Channel, - LH, - LL, - RH, - RL; +struct usx2y_volume { + unsigned char channel, + lh, + ll, + rh, + rl; }; struct us428_lights { - struct us428_setByte Light[7]; + struct us428_set_byte light[7]; }; struct us428_p4out { char type; union { - struct usX2Y_volume vol; + struct usx2y_volume vol; struct us428_lights lights; } val; }; -#define N_us428_ctl_BUFS 16 -#define N_us428_p4out_BUFS 16 -struct us428ctls_sharedmem{ - struct us428_ctls CtlSnapShot[N_us428_ctl_BUFS]; - int CtlSnapShotDiffersAt[N_us428_ctl_BUFS]; - int CtlSnapShotLast, CtlSnapShotRed; - struct us428_p4out p4out[N_us428_p4out_BUFS]; - int p4outLast, p4outSent; +#define N_US428_CTL_BUFS 16 +#define N_US428_P4OUT_BUFS 16 +struct us428ctls_sharedmem { + struct us428_ctls ctl_snapshot[N_US428_CTL_BUFS]; + int ctl_snapshot_differs_at[N_US428_CTL_BUFS]; + int ctl_snapshot_last, ctl_snapshot_red; + struct us428_p4out p4out[N_US428_P4OUT_BUFS]; + int p4out_last, p4out_sent; }; + +#define US428_SHAREDMEM_PAGES PAGE_ALIGN(sizeof(struct us428ctls_sharedmem)) diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 3cd28d24f0a7..099bee662af6 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -17,7 +17,7 @@ 2004-10-26 Karsten Wiese Version 0.8.6: - wake_up() process waiting in usX2Y_urbs_start() on error. + wake_up() process waiting in usx2y_urbs_start() on error. 2004-10-21 Karsten Wiese Version 0.8.5: @@ -48,7 +48,7 @@ 2004-06-12 Karsten Wiese Version 0.6.3: Made it thus the following rule is enforced: - "All pcm substreams of one usX2Y have to operate at the same rate & format." + "All pcm substreams of one usx2y have to operate at the same rate & format." 2004-04-06 Karsten Wiese Version 0.6.0: @@ -70,7 +70,7 @@ 2003-11-03 Karsten Wiese Version 0.3: - 24Bit support. + 24Bit support. "arecord -D hw:1 -c 2 -r 48000 -M -f S24_3LE|aplay -D hw:1 -c 2 -r 48000 -M -f S24_3LE" works. 2003-08-22 Karsten Wiese @@ -94,16 +94,15 @@ This helped me much on my slowish PII 400 & PIII 500. ACPI yet untested but might cause the same bad behaviour. Use a kernel with lowlatency and preemptiv patches applied. - To autoload snd-usb-midi append a line + To autoload snd-usb-midi append a line post-install snd-usb-us428 modprobe snd-usb-midi to /etc/modules.conf. known problems: sliders, knobs, lights not yet handled except MASTER Volume slider. - "pcm -c 2" doesn't work. "pcm -c 2 -m direct_interleaved" does. + "pcm -c 2" doesn't work. "pcm -c 2 -m direct_interleaved" does. KDE3: "Enable full duplex operation" deadlocks. - 2002-08-31 Karsten Wiese Version 0.0.3: audio also simplex; simplifying: iso urbs only 1 packet, melted structs. @@ -115,7 +114,7 @@ The firmware has been sniffed from win2k us-428 driver 3.09. * Copyright (c) 2002 - 2004 Karsten Wiese -*/ + */ #include <linux/init.h> #include <linux/module.h> @@ -132,14 +131,12 @@ #include "usbusx2y.h" #include "usX2Yhwdep.h" - - MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>"); MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2"); MODULE_LICENSE("GPL"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ -static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ module_param_array(index, int, NULL, 0444); @@ -149,305 +146,321 @@ MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS"."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS"."); +static int snd_usx2y_card_used[SNDRV_CARDS]; -static int snd_usX2Y_card_used[SNDRV_CARDS]; +static void snd_usx2y_card_private_free(struct snd_card *card); +static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s); -static void usX2Y_usb_disconnect(struct usb_device* usb_device, void* ptr); -static void snd_usX2Y_card_private_free(struct snd_card *card); - -/* - * pipe 4 is used for switching the lamps, setting samplerate, volumes .... +/* + * pipe 4 is used for switching the lamps, setting samplerate, volumes .... */ -static void i_usX2Y_Out04Int(struct urb *urb) +static void i_usx2y_out04_int(struct urb *urb) { #ifdef CONFIG_SND_DEBUG if (urb->status) { - int i; - struct usX2Ydev *usX2Y = urb->context; - for (i = 0; i < 10 && usX2Y->AS04.urb[i] != urb; i++); - snd_printdd("i_usX2Y_Out04Int() urb %i status=%i\n", i, urb->status); + int i; + struct usx2ydev *usx2y = urb->context; + + for (i = 0; i < 10 && usx2y->as04.urb[i] != urb; i++) + ; + snd_printdd("%s urb %i status=%i\n", __func__, i, urb->status); } #endif } -static void i_usX2Y_In04Int(struct urb *urb) +static void i_usx2y_in04_int(struct urb *urb) { int err = 0; - struct usX2Ydev *usX2Y = urb->context; - struct us428ctls_sharedmem *us428ctls = usX2Y->us428ctls_sharedmem; + struct usx2ydev *usx2y = urb->context; + struct us428ctls_sharedmem *us428ctls = usx2y->us428ctls_sharedmem; + struct us428_p4out *p4out; + int i, j, n, diff, send; - usX2Y->In04IntCalls++; + usx2y->in04_int_calls++; if (urb->status) { snd_printdd("Interrupt Pipe 4 came back with status=%i\n", urb->status); return; } - // printk("%i:0x%02X ", 8, (int)((unsigned char*)usX2Y->In04Buf)[8]); Master volume shows 0 here if fader is at max during boot ?!? + // printk("%i:0x%02X ", 8, (int)((unsigned char*)usx2y->in04_buf)[8]); Master volume shows 0 here if fader is at max during boot ?!? if (us428ctls) { - int diff = -1; - if (-2 == us428ctls->CtlSnapShotLast) { + diff = -1; + if (us428ctls->ctl_snapshot_last == -2) { diff = 0; - memcpy(usX2Y->In04Last, usX2Y->In04Buf, sizeof(usX2Y->In04Last)); - us428ctls->CtlSnapShotLast = -1; + memcpy(usx2y->in04_last, usx2y->in04_buf, sizeof(usx2y->in04_last)); + us428ctls->ctl_snapshot_last = -1; } else { - int i; for (i = 0; i < 21; i++) { - if (usX2Y->In04Last[i] != ((char*)usX2Y->In04Buf)[i]) { + if (usx2y->in04_last[i] != ((char *)usx2y->in04_buf)[i]) { if (diff < 0) diff = i; - usX2Y->In04Last[i] = ((char*)usX2Y->In04Buf)[i]; + usx2y->in04_last[i] = ((char *)usx2y->in04_buf)[i]; } } } - if (0 <= diff) { - int n = us428ctls->CtlSnapShotLast + 1; - if (n >= N_us428_ctl_BUFS || n < 0) + if (diff >= 0) { + n = us428ctls->ctl_snapshot_last + 1; + if (n >= N_US428_CTL_BUFS || n < 0) n = 0; - memcpy(us428ctls->CtlSnapShot + n, usX2Y->In04Buf, sizeof(us428ctls->CtlSnapShot[0])); - us428ctls->CtlSnapShotDiffersAt[n] = diff; - us428ctls->CtlSnapShotLast = n; - wake_up(&usX2Y->us428ctls_wait_queue_head); + memcpy(us428ctls->ctl_snapshot + n, usx2y->in04_buf, sizeof(us428ctls->ctl_snapshot[0])); + us428ctls->ctl_snapshot_differs_at[n] = diff; + us428ctls->ctl_snapshot_last = n; + wake_up(&usx2y->us428ctls_wait_queue_head); } } - - - if (usX2Y->US04) { - if (0 == usX2Y->US04->submitted) + + if (usx2y->us04) { + if (!usx2y->us04->submitted) { do { - err = usb_submit_urb(usX2Y->US04->urb[usX2Y->US04->submitted++], GFP_ATOMIC); - } while (!err && usX2Y->US04->submitted < usX2Y->US04->len); - } else - if (us428ctls && us428ctls->p4outLast >= 0 && us428ctls->p4outLast < N_us428_p4out_BUFS) { - if (us428ctls->p4outLast != us428ctls->p4outSent) { - int j, send = us428ctls->p4outSent + 1; - if (send >= N_us428_p4out_BUFS) + err = usb_submit_urb(usx2y->us04->urb[usx2y->us04->submitted++], GFP_ATOMIC); + } while (!err && usx2y->us04->submitted < usx2y->us04->len); + } + } else { + if (us428ctls && us428ctls->p4out_last >= 0 && us428ctls->p4out_last < N_US428_P4OUT_BUFS) { + if (us428ctls->p4out_last != us428ctls->p4out_sent) { + send = us428ctls->p4out_sent + 1; + if (send >= N_US428_P4OUT_BUFS) send = 0; - for (j = 0; j < URBS_AsyncSeq && !err; ++j) - if (0 == usX2Y->AS04.urb[j]->status) { - struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost. - usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->dev, - usb_sndbulkpipe(usX2Y->dev, 0x04), &p4out->val.vol, - p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5, - i_usX2Y_Out04Int, usX2Y); - err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC); - us428ctls->p4outSent = send; + for (j = 0; j < URBS_ASYNC_SEQ && !err; ++j) { + if (!usx2y->as04.urb[j]->status) { + p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost. + usb_fill_bulk_urb(usx2y->as04.urb[j], usx2y->dev, + usb_sndbulkpipe(usx2y->dev, 0x04), &p4out->val.vol, + p4out->type == ELT_LIGHT ? sizeof(struct us428_lights) : 5, + i_usx2y_out04_int, usx2y); + err = usb_submit_urb(usx2y->as04.urb[j], GFP_ATOMIC); + us428ctls->p4out_sent = send; break; } + } } } + } if (err) - snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err); + snd_printk(KERN_ERR "in04_int() usb_submit_urb err=%i\n", err); - urb->dev = usX2Y->dev; + urb->dev = usx2y->dev; usb_submit_urb(urb, GFP_ATOMIC); } /* * Prepare some urbs */ -int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y) +int usx2y_async_seq04_init(struct usx2ydev *usx2y) { - int err = 0, - i; + int err = 0, i; + + if (WARN_ON(usx2y->as04.buffer)) + return -EBUSY; - usX2Y->AS04.buffer = kmalloc_array(URBS_AsyncSeq, - URB_DataLen_AsyncSeq, GFP_KERNEL); - if (NULL == usX2Y->AS04.buffer) { + usx2y->as04.buffer = kmalloc_array(URBS_ASYNC_SEQ, + URB_DATA_LEN_ASYNC_SEQ, GFP_KERNEL); + if (!usx2y->as04.buffer) { err = -ENOMEM; - } else - for (i = 0; i < URBS_AsyncSeq; ++i) { - if (NULL == (usX2Y->AS04.urb[i] = usb_alloc_urb(0, GFP_KERNEL))) { + } else { + for (i = 0; i < URBS_ASYNC_SEQ; ++i) { + usx2y->as04.urb[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!usx2y->as04.urb[i]) { err = -ENOMEM; break; } - usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->dev, - usb_sndbulkpipe(usX2Y->dev, 0x04), - usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0, - i_usX2Y_Out04Int, usX2Y - ); - err = usb_urb_ep_type_check(usX2Y->AS04.urb[i]); + usb_fill_bulk_urb(usx2y->as04.urb[i], usx2y->dev, + usb_sndbulkpipe(usx2y->dev, 0x04), + usx2y->as04.buffer + URB_DATA_LEN_ASYNC_SEQ * i, 0, + i_usx2y_out04_int, usx2y); + err = usb_urb_ep_type_check(usx2y->as04.urb[i]); if (err < 0) break; } + } + if (err) + usx2y_unlinkseq(&usx2y->as04); return err; } -int usX2Y_In04_init(struct usX2Ydev *usX2Y) +int usx2y_in04_init(struct usx2ydev *usx2y) { - if (! (usX2Y->In04urb = usb_alloc_urb(0, GFP_KERNEL))) - return -ENOMEM; - - if (! (usX2Y->In04Buf = kmalloc(21, GFP_KERNEL))) - return -ENOMEM; - - init_waitqueue_head(&usX2Y->In04WaitQueue); - usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4), - usX2Y->In04Buf, 21, - i_usX2Y_In04Int, usX2Y, + int err; + + if (WARN_ON(usx2y->in04_urb)) + return -EBUSY; + + usx2y->in04_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!usx2y->in04_urb) { + err = -ENOMEM; + goto error; + } + + usx2y->in04_buf = kmalloc(21, GFP_KERNEL); + if (!usx2y->in04_buf) { + err = -ENOMEM; + goto error; + } + + init_waitqueue_head(&usx2y->in04_wait_queue); + usb_fill_int_urb(usx2y->in04_urb, usx2y->dev, usb_rcvintpipe(usx2y->dev, 0x4), + usx2y->in04_buf, 21, + i_usx2y_in04_int, usx2y, 10); - if (usb_urb_ep_type_check(usX2Y->In04urb)) - return -EINVAL; - return usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); + if (usb_urb_ep_type_check(usx2y->in04_urb)) { + err = -EINVAL; + goto error; + } + return usb_submit_urb(usx2y->in04_urb, GFP_KERNEL); + + error: + kfree(usx2y->in04_buf); + usb_free_urb(usx2y->in04_urb); + usx2y->in04_buf = NULL; + usx2y->in04_urb = NULL; + return err; } -static void usX2Y_unlinkSeq(struct snd_usX2Y_AsyncSeq *S) +static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s) { int i; - for (i = 0; i < URBS_AsyncSeq; ++i) { - usb_kill_urb(S->urb[i]); - usb_free_urb(S->urb[i]); - S->urb[i] = NULL; + + for (i = 0; i < URBS_ASYNC_SEQ; ++i) { + if (!s->urb[i]) + continue; + usb_kill_urb(s->urb[i]); + usb_free_urb(s->urb[i]); + s->urb[i] = NULL; } - kfree(S->buffer); + kfree(s->buffer); + s->buffer = NULL; } - -static const struct usb_device_id snd_usX2Y_usb_id_table[] = { +static const struct usb_device_id snd_usx2y_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x1604, - .idProduct = USB_ID_US428 + .idProduct = USB_ID_US428 }, { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x1604, - .idProduct = USB_ID_US122 + .idProduct = USB_ID_US122 }, - { + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x1604, .idProduct = USB_ID_US224 }, { /* terminator */ } }; +MODULE_DEVICE_TABLE(usb, snd_usx2y_usb_id_table); -static int usX2Y_create_card(struct usb_device *device, +static int usx2y_create_card(struct usb_device *device, struct usb_interface *intf, struct snd_card **cardp) { int dev; - struct snd_card * card; + struct snd_card *card; int err; for (dev = 0; dev < SNDRV_CARDS; ++dev) - if (enable[dev] && !snd_usX2Y_card_used[dev]) + if (enable[dev] && !snd_usx2y_card_used[dev]) break; if (dev >= SNDRV_CARDS) return -ENODEV; err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE, - sizeof(struct usX2Ydev), &card); + sizeof(struct usx2ydev), &card); if (err < 0) return err; - snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1; - card->private_free = snd_usX2Y_card_private_free; - usX2Y(card)->dev = device; - init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); - mutex_init(&usX2Y(card)->pcm_mutex); - INIT_LIST_HEAD(&usX2Y(card)->midi_list); + snd_usx2y_card_used[usx2y(card)->card_index = dev] = 1; + card->private_free = snd_usx2y_card_private_free; + usx2y(card)->dev = device; + init_waitqueue_head(&usx2y(card)->prepare_wait_queue); + init_waitqueue_head(&usx2y(card)->us428ctls_wait_queue_head); + mutex_init(&usx2y(card)->pcm_mutex); + INIT_LIST_HEAD(&usx2y(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", - card->shortname, + card->shortname, le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0,//us428(card)->usbmidi.ifnum, - usX2Y(card)->dev->bus->busnum, usX2Y(card)->dev->devnum - ); + usx2y(card)->dev->bus->busnum, usx2y(card)->dev->devnum); *cardp = card; return 0; } - -static int usX2Y_usb_probe(struct usb_device *device, - struct usb_interface *intf, - const struct usb_device_id *device_id, - struct snd_card **cardp) +static void snd_usx2y_card_private_free(struct snd_card *card) { - int err; - struct snd_card * card; + struct usx2ydev *usx2y = usx2y(card); + + kfree(usx2y->in04_buf); + usb_free_urb(usx2y->in04_urb); + if (usx2y->us428ctls_sharedmem) + free_pages_exact(usx2y->us428ctls_sharedmem, + US428_SHAREDMEM_PAGES); + if (usx2y->card_index >= 0 && usx2y->card_index < SNDRV_CARDS) + snd_usx2y_card_used[usx2y->card_index] = 0; +} - *cardp = NULL; - if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 || - (le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 && - le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 && - le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428)) - return -EINVAL; +static void snd_usx2y_disconnect(struct usb_interface *intf) +{ + struct snd_card *card; + struct usx2ydev *usx2y; + struct list_head *p; - err = usX2Y_create_card(device, intf, &card); - if (err < 0) - return err; - if ((err = usX2Y_hwdep_new(card, device)) < 0 || - (err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; + card = usb_get_intfdata(intf); + if (!card) + return; + usx2y = usx2y(card); + usx2y->chip_status = USX2Y_STAT_CHIP_HUP; + usx2y_unlinkseq(&usx2y->as04); + usb_kill_urb(usx2y->in04_urb); + snd_card_disconnect(card); + + /* release the midi resources */ + list_for_each(p, &usx2y->midi_list) { + snd_usbmidi_disconnect(p); } - *cardp = card; - return 0; + if (usx2y->us428ctls_sharedmem) + wake_up(&usx2y->us428ctls_wait_queue_head); + snd_card_free(card); } -/* - * new 2.5 USB kernel API - */ -static int snd_usX2Y_probe(struct usb_interface *intf, const struct usb_device_id *id) +static int snd_usx2y_probe(struct usb_interface *intf, + const struct usb_device_id *id) { + struct usb_device *device = interface_to_usbdev(intf); struct snd_card *card; int err; - err = usX2Y_usb_probe(interface_to_usbdev(intf), intf, id, &card); + if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 || + (le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 && + le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 && + le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428)) + return -EINVAL; + + err = usx2y_create_card(device, intf, &card); if (err < 0) return err; + err = usx2y_hwdep_new(card, device); + if (err < 0) + goto error; + err = snd_card_register(card); + if (err < 0) + goto error; + dev_set_drvdata(&intf->dev, card); return 0; -} -static void snd_usX2Y_disconnect(struct usb_interface *intf) -{ - usX2Y_usb_disconnect(interface_to_usbdev(intf), - usb_get_intfdata(intf)); + error: + snd_card_free(card); + return err; } -MODULE_DEVICE_TABLE(usb, snd_usX2Y_usb_id_table); -static struct usb_driver snd_usX2Y_usb_driver = { +static struct usb_driver snd_usx2y_usb_driver = { .name = "snd-usb-usx2y", - .probe = snd_usX2Y_probe, - .disconnect = snd_usX2Y_disconnect, - .id_table = snd_usX2Y_usb_id_table, + .probe = snd_usx2y_probe, + .disconnect = snd_usx2y_disconnect, + .id_table = snd_usx2y_usb_id_table, }; - -static void snd_usX2Y_card_private_free(struct snd_card *card) -{ - kfree(usX2Y(card)->In04Buf); - usb_free_urb(usX2Y(card)->In04urb); - if (usX2Y(card)->us428ctls_sharedmem) - free_pages_exact(usX2Y(card)->us428ctls_sharedmem, - sizeof(*usX2Y(card)->us428ctls_sharedmem)); - if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS) - snd_usX2Y_card_used[usX2Y(card)->card_index] = 0; -} - -/* - * Frees the device. - */ -static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr) -{ - if (ptr) { - struct snd_card *card = ptr; - struct usX2Ydev *usX2Y = usX2Y(card); - struct list_head *p; - usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; - usX2Y_unlinkSeq(&usX2Y->AS04); - usb_kill_urb(usX2Y->In04urb); - snd_card_disconnect(card); - /* release the midi resources */ - list_for_each(p, &usX2Y->midi_list) { - snd_usbmidi_disconnect(p); - } - if (usX2Y->us428ctls_sharedmem) - wake_up(&usX2Y->us428ctls_wait_queue_head); - snd_card_free(card); - } -} - -module_usb_driver(snd_usX2Y_usb_driver); +module_usb_driver(snd_usx2y_usb_driver); diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index 144b85f57bd2..8d82f5cc2fe1 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -3,19 +3,19 @@ #define USBUSX2Y_H #include "../usbaudio.h" #include "../midi.h" -#include "usbus428ctldefs.h" +#include "usbus428ctldefs.h" -#define NRURBS 2 +#define NRURBS 2 -#define URBS_AsyncSeq 10 -#define URB_DataLen_AsyncSeq 32 -struct snd_usX2Y_AsyncSeq { - struct urb *urb[URBS_AsyncSeq]; +#define URBS_ASYNC_SEQ 10 +#define URB_DATA_LEN_ASYNC_SEQ 32 +struct snd_usx2y_async_seq { + struct urb *urb[URBS_ASYNC_SEQ]; char *buffer; }; -struct snd_usX2Y_urbSeq { +struct snd_usx2y_urb_seq { int submitted; int len; struct urb *urb[]; @@ -23,17 +23,17 @@ struct snd_usX2Y_urbSeq { #include "usx2yhwdeppcm.h" -struct usX2Ydev { +struct usx2ydev { struct usb_device *dev; int card_index; int stride; - struct urb *In04urb; - void *In04Buf; - char In04Last[24]; - unsigned In04IntCalls; - struct snd_usX2Y_urbSeq *US04; - wait_queue_head_t In04WaitQueue; - struct snd_usX2Y_AsyncSeq AS04; + struct urb *in04_urb; + void *in04_buf; + char in04_last[24]; + unsigned int in04_int_calls; + struct snd_usx2y_urb_seq *us04; + wait_queue_head_t in04_wait_queue; + struct snd_usx2y_async_seq as04; unsigned int rate, format; int chip_status; @@ -41,31 +41,30 @@ struct usX2Ydev { struct us428ctls_sharedmem *us428ctls_sharedmem; int wait_iso_frame; wait_queue_head_t us428ctls_wait_queue_head; - struct snd_usX2Y_hwdep_pcm_shm *hwdep_pcm_shm; - struct snd_usX2Y_substream *subs[4]; - struct snd_usX2Y_substream * volatile prepare_subs; + struct snd_usx2y_hwdep_pcm_shm *hwdep_pcm_shm; + struct snd_usx2y_substream *subs[4]; + struct snd_usx2y_substream * volatile prepare_subs; wait_queue_head_t prepare_wait_queue; struct list_head midi_list; - struct list_head pcm_list; int pcm_devs; }; -struct snd_usX2Y_substream { - struct usX2Ydev *usX2Y; +struct snd_usx2y_substream { + struct usx2ydev *usx2y; struct snd_pcm_substream *pcm_substream; - int endpoint; + int endpoint; unsigned int maxpacksize; /* max packet size in bytes */ atomic_t state; -#define state_STOPPED 0 -#define state_STARTING1 1 -#define state_STARTING2 2 -#define state_STARTING3 3 -#define state_PREPARED 4 -#define state_PRERUNNING 6 -#define state_RUNNING 8 +#define STATE_STOPPED 0 +#define STATE_STARTING1 1 +#define STATE_STARTING2 2 +#define STATE_STARTING3 3 +#define STATE_PREPARED 4 +#define STATE_PRERUNNING 6 +#define STATE_RUNNING 8 int hwptr; /* free frame position in the buffer (only for playback) */ int hwptr_done; /* processed frame position in the buffer */ @@ -77,12 +76,12 @@ struct snd_usX2Y_substream { }; -#define usX2Y(c) ((struct usX2Ydev *)(c)->private_data) +#define usx2y(c) ((struct usx2ydev *)(c)->private_data) -int usX2Y_audio_create(struct snd_card *card); +int usx2y_audio_create(struct snd_card *card); -int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y); -int usX2Y_In04_init(struct usX2Ydev *usX2Y); +int usx2y_async_seq04_init(struct usx2ydev *usx2y); +int usx2y_in04_init(struct usx2ydev *usx2y); #define NAME_ALLCAPS "US-X2Y" diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index ecaf41265dcd..6154662d3097 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -11,7 +11,7 @@ * * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> * - * Many codes borrowed from audio.c by + * Many codes borrowed from audio.c by * Alan Cox (alan@lxorguk.ukuu.org.uk) * Thomas Sailer (sailer@ife.ee.ethz.ch) */ @@ -28,66 +28,69 @@ #include "usx2y.h" #include "usbusx2y.h" -#define USX2Y_NRPACKS 4 /* Default value used for nr of packs per urb. - 1 to 4 have been tested ok on uhci. - To use 3 on ohci, you'd need a patch: - look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on - "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425" - . - 1, 2 and 4 work out of the box on ohci, if I recall correctly. - Bigger is safer operation, - smaller gives lower latencies. - */ -#define USX2Y_NRPACKS_VARIABLE y /* If your system works ok with this module's parameter - nrpacks set to 1, you might as well comment - this #define out, and thereby produce smaller, faster code. - You'd also set USX2Y_NRPACKS to 1 then. - */ +/* Default value used for nr of packs per urb. + * 1 to 4 have been tested ok on uhci. + * To use 3 on ohci, you'd need a patch: + * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on + * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425" + * + * 1, 2 and 4 work out of the box on ohci, if I recall correctly. + * Bigger is safer operation, smaller gives lower latencies. + */ +#define USX2Y_NRPACKS 4 + +/* If your system works ok with this module's parameter + * nrpacks set to 1, you might as well comment + * this define out, and thereby produce smaller, faster code. + * You'd also set USX2Y_NRPACKS to 1 then. + */ +#define USX2Y_NRPACKS_VARIABLE 1 #ifdef USX2Y_NRPACKS_VARIABLE - static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */ - #define nr_of_packs() nrpacks - module_param(nrpacks, int, 0444); - MODULE_PARM_DESC(nrpacks, "Number of packets per URB."); +static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */ +#define nr_of_packs() nrpacks +module_param(nrpacks, int, 0444); +MODULE_PARM_DESC(nrpacks, "Number of packets per URB."); #else - #define nr_of_packs() USX2Y_NRPACKS +#define nr_of_packs() USX2Y_NRPACKS #endif - -static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs) +static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs) { struct urb *urb = subs->completed_urb; struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; unsigned char *cp; - int i, len, lens = 0, hwptr_done = subs->hwptr_done; - struct usX2Ydev *usX2Y = subs->usX2Y; + int i, len, lens = 0, hwptr_done = subs->hwptr_done; + int cnt, blen; + struct usx2ydev *usx2y = subs->usx2y; for (i = 0; i < nr_of_packs(); i++) { - cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset; + cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ - snd_printk(KERN_ERR "active frame status %i. " - "Most probably some hardware problem.\n", + snd_printk(KERN_ERR + "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } - len = urb->iso_frame_desc[i].actual_length / usX2Y->stride; - if (! len) { + len = urb->iso_frame_desc[i].actual_length / usx2y->stride; + if (!len) { snd_printd("0 == len ERROR!\n"); continue; } /* copy a data chunk */ if ((hwptr_done + len) > runtime->buffer_size) { - int cnt = runtime->buffer_size - hwptr_done; - int blen = cnt * usX2Y->stride; - memcpy(runtime->dma_area + hwptr_done * usX2Y->stride, cp, blen); - memcpy(runtime->dma_area, cp + blen, len * usX2Y->stride - blen); + cnt = runtime->buffer_size - hwptr_done; + blen = cnt * usx2y->stride; + memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp, blen); + memcpy(runtime->dma_area, cp + blen, len * usx2y->stride - blen); } else { - memcpy(runtime->dma_area + hwptr_done * usX2Y->stride, cp, - len * usX2Y->stride); + memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp, + len * usx2y->stride); } lens += len; - if ((hwptr_done += len) >= runtime->buffer_size) + hwptr_done += len; + if (hwptr_done >= runtime->buffer_size) hwptr_done -= runtime->buffer_size; } @@ -100,6 +103,7 @@ static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs) } return 0; } + /* * prepare urb for playback data pipe * @@ -110,18 +114,18 @@ static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs) * it directly from the buffer. thus the data is once copied to * a temporary buffer and urb points to that. */ -static int usX2Y_urb_play_prepare(struct snd_usX2Y_substream *subs, +static int usx2y_urb_play_prepare(struct snd_usx2y_substream *subs, struct urb *cap_urb, struct urb *urb) { - int count, counts, pack; - struct usX2Ydev *usX2Y = subs->usX2Y; + struct usx2ydev *usx2y = subs->usx2y; struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; + int count, counts, pack, len; count = 0; for (pack = 0; pack < nr_of_packs(); pack++) { /* calculate the size of a packet */ - counts = cap_urb->iso_frame_desc[pack].actual_length / usX2Y->stride; + counts = cap_urb->iso_frame_desc[pack].actual_length / usx2y->stride; count += counts; if (counts < 43 || counts > 50) { snd_printk(KERN_ERR "should not be here with counts=%i\n", counts); @@ -134,29 +138,30 @@ static int usX2Y_urb_play_prepare(struct snd_usX2Y_substream *subs, 0; urb->iso_frame_desc[pack].length = cap_urb->iso_frame_desc[pack].actual_length; } - if (atomic_read(&subs->state) >= state_PRERUNNING) + if (atomic_read(&subs->state) >= STATE_PRERUNNING) { if (subs->hwptr + count > runtime->buffer_size) { /* err, the transferred area goes over buffer boundary. * copy the data to the temp buffer. */ - int len; len = runtime->buffer_size - subs->hwptr; urb->transfer_buffer = subs->tmpbuf; memcpy(subs->tmpbuf, runtime->dma_area + - subs->hwptr * usX2Y->stride, len * usX2Y->stride); - memcpy(subs->tmpbuf + len * usX2Y->stride, - runtime->dma_area, (count - len) * usX2Y->stride); + subs->hwptr * usx2y->stride, len * usx2y->stride); + memcpy(subs->tmpbuf + len * usx2y->stride, + runtime->dma_area, (count - len) * usx2y->stride); subs->hwptr += count; subs->hwptr -= runtime->buffer_size; } else { /* set the buffer pointer */ - urb->transfer_buffer = runtime->dma_area + subs->hwptr * usX2Y->stride; - if ((subs->hwptr += count) >= runtime->buffer_size) + urb->transfer_buffer = runtime->dma_area + subs->hwptr * usx2y->stride; + subs->hwptr += count; + if (subs->hwptr >= runtime->buffer_size) subs->hwptr -= runtime->buffer_size; } - else + } else { urb->transfer_buffer = subs->tmpbuf; - urb->transfer_buffer_length = count * usX2Y->stride; + } + urb->transfer_buffer_length = count * usx2y->stride; return 0; } @@ -165,10 +170,10 @@ static int usX2Y_urb_play_prepare(struct snd_usX2Y_substream *subs, * * update the current position and call callback if a period is processed. */ -static void usX2Y_urb_play_retire(struct snd_usX2Y_substream *subs, struct urb *urb) +static void usx2y_urb_play_retire(struct snd_usx2y_substream *subs, struct urb *urb) { struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - int len = urb->actual_length / subs->usX2Y->stride; + int len = urb->actual_length / subs->usx2y->stride; subs->transfer_done += len; subs->hwptr_done += len; @@ -180,181 +185,195 @@ static void usX2Y_urb_play_retire(struct snd_usX2Y_substream *subs, struct urb * } } -static int usX2Y_urb_submit(struct snd_usX2Y_substream *subs, struct urb *urb, int frame) +static int usx2y_urb_submit(struct snd_usx2y_substream *subs, struct urb *urb, int frame) { int err; + if (!urb) return -ENODEV; - urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks + urb->start_frame = frame + NRURBS * nr_of_packs(); // let hcd do rollover sanity checks urb->hcpriv = NULL; - urb->dev = subs->usX2Y->dev; /* we need to set this at each time */ - if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + urb->dev = subs->usx2y->dev; /* we need to set this at each time */ + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0) { snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err); return err; } return 0; } -static inline int usX2Y_usbframe_complete(struct snd_usX2Y_substream *capsubs, - struct snd_usX2Y_substream *playbacksubs, - int frame) +static int usx2y_usbframe_complete(struct snd_usx2y_substream *capsubs, + struct snd_usx2y_substream *playbacksubs, + int frame) { int err, state; struct urb *urb = playbacksubs->completed_urb; state = atomic_read(&playbacksubs->state); - if (NULL != urb) { - if (state == state_RUNNING) - usX2Y_urb_play_retire(playbacksubs, urb); - else if (state >= state_PRERUNNING) + if (urb) { + if (state == STATE_RUNNING) + usx2y_urb_play_retire(playbacksubs, urb); + else if (state >= STATE_PRERUNNING) atomic_inc(&playbacksubs->state); } else { switch (state) { - case state_STARTING1: + case STATE_STARTING1: urb = playbacksubs->urb[0]; atomic_inc(&playbacksubs->state); break; - case state_STARTING2: + case STATE_STARTING2: urb = playbacksubs->urb[1]; atomic_inc(&playbacksubs->state); break; } } if (urb) { - if ((err = usX2Y_urb_play_prepare(playbacksubs, capsubs->completed_urb, urb)) || - (err = usX2Y_urb_submit(playbacksubs, urb, frame))) { + err = usx2y_urb_play_prepare(playbacksubs, capsubs->completed_urb, urb); + if (err) + return err; + err = usx2y_urb_submit(playbacksubs, urb, frame); + if (err) return err; - } } playbacksubs->completed_urb = NULL; state = atomic_read(&capsubs->state); - if (state >= state_PREPARED) { - if (state == state_RUNNING) { - if ((err = usX2Y_urb_capt_retire(capsubs))) + if (state >= STATE_PREPARED) { + if (state == STATE_RUNNING) { + err = usx2y_urb_capt_retire(capsubs); + if (err) return err; - } else if (state >= state_PRERUNNING) + } else if (state >= STATE_PRERUNNING) { atomic_inc(&capsubs->state); - if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame))) + } + err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame); + if (err) return err; } capsubs->completed_urb = NULL; return 0; } - -static void usX2Y_clients_stop(struct usX2Ydev *usX2Y) +static void usx2y_clients_stop(struct usx2ydev *usx2y) { + struct snd_usx2y_substream *subs; + struct urb *urb; int s, u; for (s = 0; s < 4; s++) { - struct snd_usX2Y_substream *subs = usX2Y->subs[s]; + subs = usx2y->subs[s]; if (subs) { snd_printdd("%i %p state=%i\n", s, subs, atomic_read(&subs->state)); - atomic_set(&subs->state, state_STOPPED); + atomic_set(&subs->state, STATE_STOPPED); } } for (s = 0; s < 4; s++) { - struct snd_usX2Y_substream *subs = usX2Y->subs[s]; + subs = usx2y->subs[s]; if (subs) { - if (atomic_read(&subs->state) >= state_PRERUNNING) + if (atomic_read(&subs->state) >= STATE_PRERUNNING) snd_pcm_stop_xrun(subs->pcm_substream); for (u = 0; u < NRURBS; u++) { - struct urb *urb = subs->urb[u]; - if (NULL != urb) + urb = subs->urb[u]; + if (urb) snd_printdd("%i status=%i start_frame=%i\n", u, urb->status, urb->start_frame); } } } - usX2Y->prepare_subs = NULL; - wake_up(&usX2Y->prepare_wait_queue); + usx2y->prepare_subs = NULL; + wake_up(&usx2y->prepare_wait_queue); } -static void usX2Y_error_urb_status(struct usX2Ydev *usX2Y, - struct snd_usX2Y_substream *subs, struct urb *urb) +static void usx2y_error_urb_status(struct usx2ydev *usx2y, + struct snd_usx2y_substream *subs, struct urb *urb) { snd_printk(KERN_ERR "ep=%i stalled with status=%i\n", subs->endpoint, urb->status); urb->status = 0; - usX2Y_clients_stop(usX2Y); + usx2y_clients_stop(usx2y); } -static void i_usX2Y_urb_complete(struct urb *urb) +static void i_usx2y_urb_complete(struct urb *urb) { - struct snd_usX2Y_substream *subs = urb->context; - struct usX2Ydev *usX2Y = subs->usX2Y; + struct snd_usx2y_substream *subs = urb->context; + struct usx2ydev *usx2y = subs->usx2y; + struct snd_usx2y_substream *capsubs, *playbacksubs; - if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { + if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->dev), + usb_get_current_frame_number(usx2y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; } if (unlikely(urb->status)) { - usX2Y_error_urb_status(usX2Y, subs, urb); + usx2y_error_urb_status(usx2y, subs, urb); return; } subs->completed_urb = urb; - { - struct snd_usX2Y_substream *capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE], - *playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - if (capsubs->completed_urb && - atomic_read(&capsubs->state) >= state_PREPARED && - (playbacksubs->completed_urb || - atomic_read(&playbacksubs->state) < state_PREPARED)) { - if (!usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame)) - usX2Y->wait_iso_frame += nr_of_packs(); - else { - snd_printdd("\n"); - usX2Y_clients_stop(usX2Y); - } + capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; + playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; + + if (capsubs->completed_urb && + atomic_read(&capsubs->state) >= STATE_PREPARED && + (playbacksubs->completed_urb || + atomic_read(&playbacksubs->state) < STATE_PREPARED)) { + if (!usx2y_usbframe_complete(capsubs, playbacksubs, urb->start_frame)) { + usx2y->wait_iso_frame += nr_of_packs(); + } else { + snd_printdd("\n"); + usx2y_clients_stop(usx2y); } } } -static void usX2Y_urbs_set_complete(struct usX2Ydev * usX2Y, +static void usx2y_urbs_set_complete(struct usx2ydev *usx2y, void (*complete)(struct urb *)) { + struct snd_usx2y_substream *subs; + struct urb *urb; int s, u; + for (s = 0; s < 4; s++) { - struct snd_usX2Y_substream *subs = usX2Y->subs[s]; - if (NULL != subs) + subs = usx2y->subs[s]; + if (subs) { for (u = 0; u < NRURBS; u++) { - struct urb * urb = subs->urb[u]; - if (NULL != urb) + urb = subs->urb[u]; + if (urb) urb->complete = complete; } + } } } -static void usX2Y_subs_startup_finish(struct usX2Ydev * usX2Y) +static void usx2y_subs_startup_finish(struct usx2ydev *usx2y) { - usX2Y_urbs_set_complete(usX2Y, i_usX2Y_urb_complete); - usX2Y->prepare_subs = NULL; + usx2y_urbs_set_complete(usx2y, i_usx2y_urb_complete); + usx2y->prepare_subs = NULL; } -static void i_usX2Y_subs_startup(struct urb *urb) +static void i_usx2y_subs_startup(struct urb *urb) { - struct snd_usX2Y_substream *subs = urb->context; - struct usX2Ydev *usX2Y = subs->usX2Y; - struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs; - if (NULL != prepare_subs) + struct snd_usx2y_substream *subs = urb->context; + struct usx2ydev *usx2y = subs->usx2y; + struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs; + + if (prepare_subs) { if (urb->start_frame == prepare_subs->urb[0]->start_frame) { - usX2Y_subs_startup_finish(usX2Y); + usx2y_subs_startup_finish(usx2y); atomic_inc(&prepare_subs->state); - wake_up(&usX2Y->prepare_wait_queue); + wake_up(&usx2y->prepare_wait_queue); } + } - i_usX2Y_urb_complete(urb); + i_usx2y_urb_complete(urb); } -static void usX2Y_subs_prepare(struct snd_usX2Y_substream *subs) +static void usx2y_subs_prepare(struct snd_usx2y_substream *subs) { - snd_printdd("usX2Y_substream_prepare(%p) ep=%i urb0=%p urb1=%p\n", + snd_printdd("usx2y_substream_prepare(%p) ep=%i urb0=%p urb1=%p\n", subs, subs->endpoint, subs->urb[0], subs->urb[1]); /* reset the pointer */ subs->hwptr = 0; @@ -362,8 +381,7 @@ static void usX2Y_subs_prepare(struct snd_usX2Y_substream *subs) subs->transfer_done = 0; } - -static void usX2Y_urb_release(struct urb **urb, int free_tb) +static void usx2y_urb_release(struct urb **urb, int free_tb) { if (*urb) { usb_kill_urb(*urb); @@ -373,29 +391,33 @@ static void usX2Y_urb_release(struct urb **urb, int free_tb) *urb = NULL; } } + /* * release a substreams urbs */ -static void usX2Y_urbs_release(struct snd_usX2Y_substream *subs) +static void usx2y_urbs_release(struct snd_usx2y_substream *subs) { int i; - snd_printdd("usX2Y_urbs_release() %i\n", subs->endpoint); + + snd_printdd("%s %i\n", __func__, subs->endpoint); for (i = 0; i < NRURBS; i++) - usX2Y_urb_release(subs->urb + i, - subs != subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]); + usx2y_urb_release(subs->urb + i, + subs != subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]); kfree(subs->tmpbuf); subs->tmpbuf = NULL; } + /* * initialize a substream's urbs */ -static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs) +static int usx2y_urbs_allocate(struct snd_usx2y_substream *subs) { int i; unsigned int pipe; - int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->dev; + int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; + struct usb_device *dev = subs->usx2y->dev; + struct urb **purb; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -403,21 +425,21 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs) if (!subs->maxpacksize) return -EINVAL; - if (is_playback && NULL == subs->tmpbuf) { /* allocate a temporary buffer for playback */ + if (is_playback && !subs->tmpbuf) { /* allocate a temporary buffer for playback */ subs->tmpbuf = kcalloc(nr_of_packs(), subs->maxpacksize, GFP_KERNEL); if (!subs->tmpbuf) return -ENOMEM; } /* allocate and initialize data urbs */ for (i = 0; i < NRURBS; i++) { - struct urb **purb = subs->urb + i; + purb = subs->urb + i; if (*purb) { usb_kill_urb(*purb); continue; } *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL); - if (NULL == *purb) { - usX2Y_urbs_release(subs); + if (!*purb) { + usx2y_urbs_release(subs); return -ENOMEM; } if (!is_playback && !(*purb)->transfer_buffer) { @@ -425,8 +447,8 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs) (*purb)->transfer_buffer = kmalloc_array(subs->maxpacksize, nr_of_packs(), GFP_KERNEL); - if (NULL == (*purb)->transfer_buffer) { - usX2Y_urbs_release(subs); + if (!(*purb)->transfer_buffer) { + usx2y_urbs_release(subs); return -ENOMEM; } } @@ -435,70 +457,76 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs) (*purb)->number_of_packets = nr_of_packs(); (*purb)->context = subs; (*purb)->interval = 1; - (*purb)->complete = i_usX2Y_subs_startup; + (*purb)->complete = i_usx2y_subs_startup; } return 0; } -static void usX2Y_subs_startup(struct snd_usX2Y_substream *subs) +static void usx2y_subs_startup(struct snd_usx2y_substream *subs) { - struct usX2Ydev *usX2Y = subs->usX2Y; - usX2Y->prepare_subs = subs; + struct usx2ydev *usx2y = subs->usx2y; + + usx2y->prepare_subs = subs; subs->urb[0]->start_frame = -1; wmb(); - usX2Y_urbs_set_complete(usX2Y, i_usX2Y_subs_startup); + usx2y_urbs_set_complete(usx2y, i_usx2y_subs_startup); } -static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) +static int usx2y_urbs_start(struct snd_usx2y_substream *subs) { int i, err; - struct usX2Ydev *usX2Y = subs->usX2Y; + struct usx2ydev *usx2y = subs->usx2y; + struct urb *urb; + unsigned long pack; - if ((err = usX2Y_urbs_allocate(subs)) < 0) + err = usx2y_urbs_allocate(subs); + if (err < 0) return err; subs->completed_urb = NULL; for (i = 0; i < 4; i++) { - struct snd_usX2Y_substream *subs = usX2Y->subs[i]; - if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED) + struct snd_usx2y_substream *subs = usx2y->subs[i]; + + if (subs && atomic_read(&subs->state) >= STATE_PREPARED) goto start; } start: - usX2Y_subs_startup(subs); + usx2y_subs_startup(subs); for (i = 0; i < NRURBS; i++) { - struct urb *urb = subs->urb[i]; + urb = subs->urb[i]; if (usb_pipein(urb->pipe)) { - unsigned long pack; - if (0 == i) - atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->dev; + if (!i) + atomic_set(&subs->state, STATE_STARTING3); + urb->dev = usx2y->dev; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack; urb->iso_frame_desc[pack].length = subs->maxpacksize; } - urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); - if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err); + urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0) { + snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err); err = -EPIPE; goto cleanup; - } else - if (i == 0) - usX2Y->wait_iso_frame = urb->start_frame; + } else { + if (!i) + usx2y->wait_iso_frame = urb->start_frame; + } urb->transfer_flags = 0; } else { - atomic_set(&subs->state, state_STARTING1); + atomic_set(&subs->state, STATE_STARTING1); break; } } err = 0; - wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs); - if (atomic_read(&subs->state) != state_PREPARED) + wait_event(usx2y->prepare_wait_queue, !usx2y->prepare_subs); + if (atomic_read(&subs->state) != STATE_PREPARED) err = -EPIPE; cleanup: if (err) { - usX2Y_subs_startup_finish(usX2Y); - usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything + usx2y_subs_startup_finish(usx2y); + usx2y_clients_stop(usx2y); // something is completely wroong > stop evrything } return err; } @@ -506,33 +534,35 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) /* * return the current pcm pointer. just return the hwptr_done value. */ -static snd_pcm_uframes_t snd_usX2Y_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t snd_usx2y_pcm_pointer(struct snd_pcm_substream *substream) { - struct snd_usX2Y_substream *subs = substream->runtime->private_data; + struct snd_usx2y_substream *subs = substream->runtime->private_data; + return subs->hwptr_done; } + /* * start/stop substream */ -static int snd_usX2Y_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int snd_usx2y_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_usX2Y_substream *subs = substream->runtime->private_data; + struct snd_usx2y_substream *subs = substream->runtime->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_printdd("snd_usX2Y_pcm_trigger(START)\n"); - if (atomic_read(&subs->state) == state_PREPARED && - atomic_read(&subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]->state) >= state_PREPARED) { - atomic_set(&subs->state, state_PRERUNNING); + snd_printdd("%s(START)\n", __func__); + if (atomic_read(&subs->state) == STATE_PREPARED && + atomic_read(&subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]->state) >= STATE_PREPARED) { + atomic_set(&subs->state, STATE_PRERUNNING); } else { snd_printdd("\n"); return -EPIPE; } break; case SNDRV_PCM_TRIGGER_STOP: - snd_printdd("snd_usX2Y_pcm_trigger(STOP)\n"); - if (atomic_read(&subs->state) >= state_PRERUNNING) - atomic_set(&subs->state, state_PREPARED); + snd_printdd("%s(STOP)\n", __func__); + if (atomic_read(&subs->state) >= STATE_PRERUNNING) + atomic_set(&subs->state, STATE_PREPARED); break; default: return -EINVAL; @@ -540,7 +570,6 @@ static int snd_usX2Y_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } - /* * allocate a buffer, setup samplerate * @@ -549,12 +578,11 @@ static int snd_usX2Y_pcm_trigger(struct snd_pcm_substream *substream, int cmd) * if sg buffer is supported on the later version of alsa, we'll follow * that. */ -static const struct s_c2 -{ +struct s_c2 { char c1, c2; -} - SetRate44100[] = -{ +}; + +static const struct s_c2 setrate_44100[] = { { 0x14, 0x08}, // this line sets 44100, well actually a little less { 0x18, 0x40}, // only tascam / frontier design knows the further lines ....... { 0x18, 0x42}, @@ -589,8 +617,8 @@ static const struct s_c2 { 0x18, 0x7C}, { 0x18, 0x7E} }; -static const struct s_c2 SetRate48000[] = -{ + +static const struct s_c2 setrate_48000[] = { { 0x14, 0x09}, // this line sets 48000, well actually a little less { 0x18, 0x40}, // only tascam / frontier design knows the further lines ....... { 0x18, 0x42}, @@ -625,62 +653,65 @@ static const struct s_c2 SetRate48000[] = { 0x18, 0x7C}, { 0x18, 0x7E} }; -#define NOOF_SETRATE_URBS ARRAY_SIZE(SetRate48000) -static void i_usX2Y_04Int(struct urb *urb) +#define NOOF_SETRATE_URBS ARRAY_SIZE(setrate_48000) + +static void i_usx2y_04int(struct urb *urb) { - struct usX2Ydev *usX2Y = urb->context; - + struct usx2ydev *usx2y = urb->context; + if (urb->status) - snd_printk(KERN_ERR "snd_usX2Y_04Int() urb->status=%i\n", urb->status); - if (0 == --usX2Y->US04->len) - wake_up(&usX2Y->In04WaitQueue); + snd_printk(KERN_ERR "snd_usx2y_04int() urb->status=%i\n", urb->status); + if (!--usx2y->us04->len) + wake_up(&usx2y->in04_wait_queue); } -static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) +static int usx2y_rate_set(struct usx2ydev *usx2y, int rate) { int err = 0, i; - struct snd_usX2Y_urbSeq *us = NULL; + struct snd_usx2y_urb_seq *us = NULL; int *usbdata = NULL; - const struct s_c2 *ra = rate == 48000 ? SetRate48000 : SetRate44100; + const struct s_c2 *ra = rate == 48000 ? setrate_48000 : setrate_44100; + struct urb *urb; - if (usX2Y->rate != rate) { - us = kzalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL); - if (NULL == us) { + if (usx2y->rate != rate) { + us = kzalloc(sizeof(*us) + sizeof(struct urb *) * NOOF_SETRATE_URBS, GFP_KERNEL); + if (!us) { err = -ENOMEM; goto cleanup; } usbdata = kmalloc_array(NOOF_SETRATE_URBS, sizeof(int), GFP_KERNEL); - if (NULL == usbdata) { + if (!usbdata) { err = -ENOMEM; goto cleanup; } for (i = 0; i < NOOF_SETRATE_URBS; ++i) { - if (NULL == (us->urb[i] = usb_alloc_urb(0, GFP_KERNEL))) { + us->urb[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!us->urb[i]) { err = -ENOMEM; goto cleanup; } - ((char*)(usbdata + i))[0] = ra[i].c1; - ((char*)(usbdata + i))[1] = ra[i].c2; - usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4), - usbdata + i, 2, i_usX2Y_04Int, usX2Y); + ((char *)(usbdata + i))[0] = ra[i].c1; + ((char *)(usbdata + i))[1] = ra[i].c2; + usb_fill_bulk_urb(us->urb[i], usx2y->dev, usb_sndbulkpipe(usx2y->dev, 4), + usbdata + i, 2, i_usx2y_04int, usx2y); } err = usb_urb_ep_type_check(us->urb[0]); if (err < 0) goto cleanup; us->submitted = 0; us->len = NOOF_SETRATE_URBS; - usX2Y->US04 = us; - wait_event_timeout(usX2Y->In04WaitQueue, 0 == us->len, HZ); - usX2Y->US04 = NULL; + usx2y->us04 = us; + wait_event_timeout(usx2y->in04_wait_queue, !us->len, HZ); + usx2y->us04 = NULL; if (us->len) err = -ENODEV; cleanup: if (us) { us->submitted = 2*NOOF_SETRATE_URBS; for (i = 0; i < NOOF_SETRATE_URBS; ++i) { - struct urb *urb = us->urb[i]; + urb = us->urb[i]; if (!urb) continue; if (urb->status) { @@ -690,67 +721,68 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) } usb_free_urb(urb); } - usX2Y->US04 = NULL; + usx2y->us04 = NULL; kfree(usbdata); kfree(us); if (!err) - usX2Y->rate = rate; + usx2y->rate = rate; } } return err; } - -static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) +static int usx2y_format_set(struct usx2ydev *usx2y, snd_pcm_format_t format) { int alternate, err; - struct list_head* p; + struct list_head *p; + if (format == SNDRV_PCM_FORMAT_S24_3LE) { alternate = 2; - usX2Y->stride = 6; + usx2y->stride = 6; } else { alternate = 1; - usX2Y->stride = 4; + usx2y->stride = 4; } - list_for_each(p, &usX2Y->midi_list) { + list_for_each(p, &usx2y->midi_list) { snd_usbmidi_input_stop(p); } - usb_kill_urb(usX2Y->In04urb); - if ((err = usb_set_interface(usX2Y->dev, 0, alternate))) { - snd_printk(KERN_ERR "usb_set_interface error \n"); + usb_kill_urb(usx2y->in04_urb); + err = usb_set_interface(usx2y->dev, 0, alternate); + if (err) { + snd_printk(KERN_ERR "usb_set_interface error\n"); return err; } - usX2Y->In04urb->dev = usX2Y->dev; - err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); - list_for_each(p, &usX2Y->midi_list) { + usx2y->in04_urb->dev = usx2y->dev; + err = usb_submit_urb(usx2y->in04_urb, GFP_KERNEL); + list_for_each(p, &usx2y->midi_list) { snd_usbmidi_input_start(p); } - usX2Y->format = format; - usX2Y->rate = 0; + usx2y->format = format; + usx2y->rate = 0; return err; } -static int snd_usX2Y_pcm_hw_params(struct snd_pcm_substream *substream, +static int snd_usx2y_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { int err = 0; unsigned int rate = params_rate(hw_params); snd_pcm_format_t format = params_format(hw_params); struct snd_card *card = substream->pstr->pcm->card; - struct usX2Ydev *dev = usX2Y(card); + struct usx2ydev *dev = usx2y(card); + struct snd_usx2y_substream *subs; + struct snd_pcm_substream *test_substream; int i; - mutex_lock(&usX2Y(card)->pcm_mutex); - snd_printdd("snd_usX2Y_hw_params(%p, %p)\n", substream, hw_params); - /* all pcm substreams off one usX2Y have to operate at the same + mutex_lock(&usx2y(card)->pcm_mutex); + snd_printdd("snd_usx2y_hw_params(%p, %p)\n", substream, hw_params); + /* all pcm substreams off one usx2y have to operate at the same * rate & format */ for (i = 0; i < dev->pcm_devs * 2; i++) { - struct snd_usX2Y_substream *subs = dev->subs[i]; - struct snd_pcm_substream *test_substream; - + subs = dev->subs[i]; if (!subs) continue; test_substream = subs->pcm_substream; @@ -767,81 +799,89 @@ static int snd_usX2Y_pcm_hw_params(struct snd_pcm_substream *substream, } error: - mutex_unlock(&usX2Y(card)->pcm_mutex); + mutex_unlock(&usx2y(card)->pcm_mutex); return err; } /* * free the buffer */ -static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream) +static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_usX2Y_substream *subs = runtime->private_data; - mutex_lock(&subs->usX2Y->pcm_mutex); - snd_printdd("snd_usX2Y_hw_free(%p)\n", substream); - - if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) { - struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]; - atomic_set(&subs->state, state_STOPPED); - usX2Y_urbs_release(subs); + struct snd_usx2y_substream *subs = runtime->private_data; + struct snd_usx2y_substream *cap_subs, *playback_subs; + + mutex_lock(&subs->usx2y->pcm_mutex); + snd_printdd("snd_usx2y_hw_free(%p)\n", substream); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; + atomic_set(&subs->state, STATE_STOPPED); + usx2y_urbs_release(subs); if (!cap_subs->pcm_substream || !cap_subs->pcm_substream->runtime || !cap_subs->pcm_substream->runtime->status || cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) { - atomic_set(&cap_subs->state, state_STOPPED); - usX2Y_urbs_release(cap_subs); + atomic_set(&cap_subs->state, STATE_STOPPED); + usx2y_urbs_release(cap_subs); } } else { - struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - if (atomic_read(&playback_subs->state) < state_PREPARED) { - atomic_set(&subs->state, state_STOPPED); - usX2Y_urbs_release(subs); + playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; + if (atomic_read(&playback_subs->state) < STATE_PREPARED) { + atomic_set(&subs->state, STATE_STOPPED); + usx2y_urbs_release(subs); } } - mutex_unlock(&subs->usX2Y->pcm_mutex); + mutex_unlock(&subs->usx2y->pcm_mutex); return 0; } + /* * prepare callback * * set format and initialize urbs */ -static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream) +static int snd_usx2y_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_usX2Y_substream *subs = runtime->private_data; - struct usX2Ydev *usX2Y = subs->usX2Y; - struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]; + struct snd_usx2y_substream *subs = runtime->private_data; + struct usx2ydev *usx2y = subs->usx2y; + struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; int err = 0; - snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream); - - mutex_lock(&usX2Y->pcm_mutex); - usX2Y_subs_prepare(subs); -// Start hardware streams -// SyncStream first.... - if (atomic_read(&capsubs->state) < state_PREPARED) { - if (usX2Y->format != runtime->format) - if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0) + + snd_printdd("%s(%p)\n", __func__, substream); + + mutex_lock(&usx2y->pcm_mutex); + usx2y_subs_prepare(subs); + // Start hardware streams + // SyncStream first.... + if (atomic_read(&capsubs->state) < STATE_PREPARED) { + if (usx2y->format != runtime->format) { + err = usx2y_format_set(usx2y, runtime->format); + if (err < 0) goto up_prepare_mutex; - if (usX2Y->rate != runtime->rate) - if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0) + } + if (usx2y->rate != runtime->rate) { + err = usx2y_rate_set(usx2y, runtime->rate); + if (err < 0) goto up_prepare_mutex; + } snd_printdd("starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe"); - if (0 > (err = usX2Y_urbs_start(capsubs))) + err = usx2y_urbs_start(capsubs); + if (err < 0) goto up_prepare_mutex; } - if (subs != capsubs && atomic_read(&subs->state) < state_PREPARED) - err = usX2Y_urbs_start(subs); + if (subs != capsubs && atomic_read(&subs->state) < STATE_PREPARED) + err = usx2y_urbs_start(subs); up_prepare_mutex: - mutex_unlock(&usX2Y->pcm_mutex); + mutex_unlock(&usx2y->pcm_mutex); return err; } -static const struct snd_pcm_hardware snd_usX2Y_2c = -{ +static const struct snd_pcm_hardware snd_usx2y_2c = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | @@ -860,106 +900,101 @@ static const struct snd_pcm_hardware snd_usX2Y_2c = .fifo_size = 0 }; - - -static int snd_usX2Y_pcm_open(struct snd_pcm_substream *substream) +static int snd_usx2y_pcm_open(struct snd_pcm_substream *substream) { - struct snd_usX2Y_substream *subs = ((struct snd_usX2Y_substream **) - snd_pcm_substream_chip(substream))[substream->stream]; + struct snd_usx2y_substream *subs = + ((struct snd_usx2y_substream **) + snd_pcm_substream_chip(substream))[substream->stream]; struct snd_pcm_runtime *runtime = substream->runtime; - if (subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS) + if (subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS) return -EBUSY; - runtime->hw = snd_usX2Y_2c; + runtime->hw = snd_usx2y_2c; runtime->private_data = subs; subs->pcm_substream = substream; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000); return 0; } - - -static int snd_usX2Y_pcm_close(struct snd_pcm_substream *substream) +static int snd_usx2y_pcm_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_usX2Y_substream *subs = runtime->private_data; + struct snd_usx2y_substream *subs = runtime->private_data; subs->pcm_substream = NULL; return 0; } - -static const struct snd_pcm_ops snd_usX2Y_pcm_ops = -{ - .open = snd_usX2Y_pcm_open, - .close = snd_usX2Y_pcm_close, - .hw_params = snd_usX2Y_pcm_hw_params, - .hw_free = snd_usX2Y_pcm_hw_free, - .prepare = snd_usX2Y_pcm_prepare, - .trigger = snd_usX2Y_pcm_trigger, - .pointer = snd_usX2Y_pcm_pointer, +static const struct snd_pcm_ops snd_usx2y_pcm_ops = { + .open = snd_usx2y_pcm_open, + .close = snd_usx2y_pcm_close, + .hw_params = snd_usx2y_pcm_hw_params, + .hw_free = snd_usx2y_pcm_hw_free, + .prepare = snd_usx2y_pcm_prepare, + .trigger = snd_usx2y_pcm_trigger, + .pointer = snd_usx2y_pcm_pointer, }; - /* * free a usb stream instance */ -static void usX2Y_audio_stream_free(struct snd_usX2Y_substream **usX2Y_substream) +static void usx2y_audio_stream_free(struct snd_usx2y_substream **usx2y_substream) { int stream; for_each_pcm_streams(stream) { - kfree(usX2Y_substream[stream]); - usX2Y_substream[stream] = NULL; + kfree(usx2y_substream[stream]); + usx2y_substream[stream] = NULL; } } -static void snd_usX2Y_pcm_private_free(struct snd_pcm *pcm) +static void snd_usx2y_pcm_private_free(struct snd_pcm *pcm) { - struct snd_usX2Y_substream **usX2Y_stream = pcm->private_data; - if (usX2Y_stream) - usX2Y_audio_stream_free(usX2Y_stream); + struct snd_usx2y_substream **usx2y_stream = pcm->private_data; + + if (usx2y_stream) + usx2y_audio_stream_free(usx2y_stream); } -static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, int capture_endpoint) +static int usx2y_audio_stream_new(struct snd_card *card, int playback_endpoint, int capture_endpoint) { struct snd_pcm *pcm; int err, i; - struct snd_usX2Y_substream **usX2Y_substream = - usX2Y(card)->subs + 2 * usX2Y(card)->pcm_devs; + struct snd_usx2y_substream **usx2y_substream = + usx2y(card)->subs + 2 * usx2y(card)->pcm_devs; for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; i <= SNDRV_PCM_STREAM_CAPTURE; ++i) { - usX2Y_substream[i] = kzalloc(sizeof(struct snd_usX2Y_substream), GFP_KERNEL); - if (!usX2Y_substream[i]) + usx2y_substream[i] = kzalloc(sizeof(struct snd_usx2y_substream), GFP_KERNEL); + if (!usx2y_substream[i]) return -ENOMEM; - usX2Y_substream[i]->usX2Y = usX2Y(card); + usx2y_substream[i]->usx2y = usx2y(card); } if (playback_endpoint) - usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint; - usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint; + usx2y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint; + usx2y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint; - err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->pcm_devs, + err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usx2y(card)->pcm_devs, playback_endpoint ? 1 : 0, 1, &pcm); if (err < 0) { - usX2Y_audio_stream_free(usX2Y_substream); + usx2y_audio_stream_free(usx2y_substream); return err; } if (playback_endpoint) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_pcm_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_pcm_ops); - pcm->private_data = usX2Y_substream; - pcm->private_free = snd_usX2Y_pcm_private_free; + pcm->private_data = usx2y_substream; + pcm->private_free = snd_usx2y_pcm_private_free; pcm->info_flags = 0; - sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs); + sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usx2y(card)->pcm_devs); if (playback_endpoint) { snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, @@ -972,7 +1007,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, SNDRV_DMA_TYPE_CONTINUOUS, NULL, 64*1024, 128*1024); - usX2Y(card)->pcm_devs++; + usx2y(card)->pcm_devs++; return 0; } @@ -980,18 +1015,19 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, /* * create a chip instance and set its names. */ -int usX2Y_audio_create(struct snd_card *card) +int usx2y_audio_create(struct snd_card *card) { - int err = 0; - - INIT_LIST_HEAD(&usX2Y(card)->pcm_list); + int err; - if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8))) + err = usx2y_audio_stream_new(card, 0xA, 0x8); + if (err < 0) return err; - if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) == USB_ID_US428) - if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA))) - return err; - if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) != USB_ID_US122) - err = usX2Y_rate_set(usX2Y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122. + if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) == USB_ID_US428) { + err = usx2y_audio_stream_new(card, 0, 0xA); + if (err < 0) + return err; + } + if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) != USB_ID_US122) + err = usx2y_rate_set(usx2y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122. return err; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 8253669c6a7d..da643c2dbb12 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -6,7 +6,7 @@ Its usb's unableness to atomically handle power of 2 period sized data chuncs at standard samplerates, - what led to this part of the usx2y module: + what led to this part of the usx2y module: It provides the alsa kernel half of the usx2y-alsa-jack driver pair. The pair uses a hardware dependent alsa-device for mmaped pcm transport. Advantage achieved: @@ -35,7 +35,7 @@ Kernel: - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio devices can use it. - Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y. + Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y. */ #include <linux/delay.h> @@ -46,28 +46,32 @@ #include <sound/hwdep.h> - -static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs) +static int usx2y_usbpcm_urb_capt_retire(struct snd_usx2y_substream *subs) { struct urb *urb = subs->completed_urb; struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - int i, lens = 0, hwptr_done = subs->hwptr_done; - struct usX2Ydev *usX2Y = subs->usX2Y; - if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) { //FIXME - int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1; - if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso)) + int i, lens = 0, hwptr_done = subs->hwptr_done; + struct usx2ydev *usx2y = subs->usx2y; + int head; + + if (usx2y->hwdep_pcm_shm->capture_iso_start < 0) { //FIXME + head = usx2y->hwdep_pcm_shm->captured_iso_head + 1; + if (head >= ARRAY_SIZE(usx2y->hwdep_pcm_shm->captured_iso)) head = 0; - usX2Y->hwdep_pcm_shm->capture_iso_start = head; + usx2y->hwdep_pcm_shm->capture_iso_start = head; snd_printdd("cap start %i\n", head); } for (i = 0; i < nr_of_packs(); i++) { if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ - snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status); + snd_printk(KERN_ERR + "active frame status %i. Most probably some hardware problem.\n", + urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } - lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride; + lens += urb->iso_frame_desc[i].actual_length / usx2y->stride; } - if ((hwptr_done += lens) >= runtime->buffer_size) + hwptr_done += lens; + if (hwptr_done >= runtime->buffer_size) hwptr_done -= runtime->buffer_size; subs->hwptr_done = hwptr_done; subs->transfer_done += lens; @@ -79,10 +83,10 @@ static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs) return 0; } -static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime, - struct usX2Ydev * usX2Y) +static int usx2y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime, + struct usx2ydev *usx2y) { - return (runtime->buffer_size * 1000) / usX2Y->rate + 1; //FIXME: so far only correct period_size == 2^x ? + return (runtime->buffer_size * 1000) / usx2y->rate + 1; //FIXME: so far only correct period_size == 2^x ? } /* @@ -95,18 +99,18 @@ static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime, * it directly from the buffer. thus the data is once copied to * a temporary buffer and urb points to that. */ -static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs, +static int usx2y_hwdep_urb_play_prepare(struct snd_usx2y_substream *subs, struct urb *urb) { int count, counts, pack; - struct usX2Ydev *usX2Y = subs->usX2Y; - struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm; + struct usx2ydev *usx2y = subs->usx2y; + struct snd_usx2y_hwdep_pcm_shm *shm = usx2y->hwdep_pcm_shm; struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - if (0 > shm->playback_iso_start) { + if (shm->playback_iso_start < 0) { shm->playback_iso_start = shm->captured_iso_head - - usX2Y_iso_frames_per_buffer(runtime, usX2Y); - if (0 > shm->playback_iso_start) + usx2y_iso_frames_per_buffer(runtime, usx2y); + if (shm->playback_iso_start < 0) shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso); shm->playback_iso_head = shm->playback_iso_start; } @@ -114,7 +118,7 @@ static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs, count = 0; for (pack = 0; pack < nr_of_packs(); pack++) { /* calculate the size of a packet */ - counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride; + counts = shm->captured_iso[shm->playback_iso_head].length / usx2y->stride; if (counts < 43 || counts > 50) { snd_printk(KERN_ERR "should not be here with counts=%i\n", counts); return -EPIPE; @@ -122,27 +126,29 @@ static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs, /* set up descriptor */ urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset; urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length; - if (atomic_read(&subs->state) != state_RUNNING) + if (atomic_read(&subs->state) != STATE_RUNNING) memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0, urb->iso_frame_desc[pack].length); if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso)) shm->playback_iso_head = 0; count += counts; } - urb->transfer_buffer_length = count * usX2Y->stride; + urb->transfer_buffer_length = count * usx2y->stride; return 0; } - -static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs, - struct urb *urb) +static void usx2y_usbpcm_urb_capt_iso_advance(struct snd_usx2y_substream *subs, + struct urb *urb) { - int pack; + struct usb_iso_packet_descriptor *desc; + struct snd_usx2y_hwdep_pcm_shm *shm; + int pack, head; + for (pack = 0; pack < nr_of_packs(); ++pack) { - struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack; - if (NULL != subs) { - struct snd_usX2Y_hwdep_pcm_shm *shm = subs->usX2Y->hwdep_pcm_shm; - int head = shm->captured_iso_head + 1; + desc = urb->iso_frame_desc + pack; + if (subs) { + shm = subs->usx2y->hwdep_pcm_shm; + head = shm->captured_iso_head + 1; if (head >= ARRAY_SIZE(shm->captured_iso)) head = 0; shm->captured_iso[head].frame = urb->start_frame + pack; @@ -151,106 +157,111 @@ static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream shm->captured_iso_head = head; shm->captured_iso_frames++; } - if ((desc->offset += desc->length * NRURBS*nr_of_packs()) + - desc->length >= SSS) + desc->offset += desc->length * NRURBS * nr_of_packs(); + if (desc->offset + desc->length >= SSS) desc->offset -= (SSS - desc->length); } } -static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *capsubs, - struct snd_usX2Y_substream *capsubs2, - struct snd_usX2Y_substream *playbacksubs, - int frame) +static int usx2y_usbpcm_usbframe_complete(struct snd_usx2y_substream *capsubs, + struct snd_usx2y_substream *capsubs2, + struct snd_usx2y_substream *playbacksubs, + int frame) { int err, state; struct urb *urb = playbacksubs->completed_urb; state = atomic_read(&playbacksubs->state); - if (NULL != urb) { - if (state == state_RUNNING) - usX2Y_urb_play_retire(playbacksubs, urb); - else if (state >= state_PRERUNNING) + if (urb) { + if (state == STATE_RUNNING) + usx2y_urb_play_retire(playbacksubs, urb); + else if (state >= STATE_PRERUNNING) atomic_inc(&playbacksubs->state); } else { switch (state) { - case state_STARTING1: + case STATE_STARTING1: urb = playbacksubs->urb[0]; atomic_inc(&playbacksubs->state); break; - case state_STARTING2: + case STATE_STARTING2: urb = playbacksubs->urb[1]; atomic_inc(&playbacksubs->state); break; } } if (urb) { - if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) || - (err = usX2Y_urb_submit(playbacksubs, urb, frame))) { + err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb); + if (err) + return err; + err = usx2y_hwdep_urb_play_prepare(playbacksubs, urb); + if (err) return err; - } } - + playbacksubs->completed_urb = NULL; state = atomic_read(&capsubs->state); - if (state >= state_PREPARED) { - if (state == state_RUNNING) { - if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs))) + if (state >= STATE_PREPARED) { + if (state == STATE_RUNNING) { + err = usx2y_usbpcm_urb_capt_retire(capsubs); + if (err) return err; - } else if (state >= state_PRERUNNING) + } else if (state >= STATE_PRERUNNING) { atomic_inc(&capsubs->state); - usX2Y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb); - if (NULL != capsubs2) - usX2Y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb); - if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame))) + } + usx2y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb); + if (capsubs2) + usx2y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb); + err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame); + if (err) return err; - if (NULL != capsubs2) - if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame))) + if (capsubs2) { + err = usx2y_urb_submit(capsubs2, capsubs2->completed_urb, frame); + if (err) return err; + } } capsubs->completed_urb = NULL; - if (NULL != capsubs2) + if (capsubs2) capsubs2->completed_urb = NULL; return 0; } - -static void i_usX2Y_usbpcm_urb_complete(struct urb *urb) +static void i_usx2y_usbpcm_urb_complete(struct urb *urb) { - struct snd_usX2Y_substream *subs = urb->context; - struct usX2Ydev *usX2Y = subs->usX2Y; - struct snd_usX2Y_substream *capsubs, *capsubs2, *playbacksubs; + struct snd_usx2y_substream *subs = urb->context; + struct usx2ydev *usx2y = subs->usx2y; + struct snd_usx2y_substream *capsubs, *capsubs2, *playbacksubs; - if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { + if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->dev), + usb_get_current_frame_number(usx2y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; } if (unlikely(urb->status)) { - usX2Y_error_urb_status(usX2Y, subs, urb); + usx2y_error_urb_status(usx2y, subs, urb); return; } subs->completed_urb = urb; - capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]; - capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; - playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED && - (NULL == capsubs2 || capsubs2->completed_urb) && - (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) { - if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) - usX2Y->wait_iso_frame += nr_of_packs(); - else { + capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; + capsubs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; + playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; + if (capsubs->completed_urb && atomic_read(&capsubs->state) >= STATE_PREPARED && + (!capsubs2 || capsubs2->completed_urb) && + (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < STATE_PREPARED)) { + if (!usx2y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) { + usx2y->wait_iso_frame += nr_of_packs(); + } else { snd_printdd("\n"); - usX2Y_clients_stop(usX2Y); + usx2y_clients_stop(usx2y); } } } - -static void usX2Y_hwdep_urb_release(struct urb **urb) +static void usx2y_hwdep_urb_release(struct urb **urb) { usb_kill_urb(*urb); usb_free_urb(*urb); @@ -260,49 +271,53 @@ static void usX2Y_hwdep_urb_release(struct urb **urb) /* * release a substream */ -static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs) +static void usx2y_usbpcm_urbs_release(struct snd_usx2y_substream *subs) { int i; - snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint); + + snd_printdd("snd_usx2y_urbs_release() %i\n", subs->endpoint); for (i = 0; i < NRURBS; i++) - usX2Y_hwdep_urb_release(subs->urb + i); + usx2y_hwdep_urb_release(subs->urb + i); } -static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y) +static void usx2y_usbpcm_subs_startup_finish(struct usx2ydev *usx2y) { - usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete); - usX2Y->prepare_subs = NULL; + usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_urb_complete); + usx2y->prepare_subs = NULL; } -static void i_usX2Y_usbpcm_subs_startup(struct urb *urb) +static void i_usx2y_usbpcm_subs_startup(struct urb *urb) { - struct snd_usX2Y_substream *subs = urb->context; - struct usX2Ydev *usX2Y = subs->usX2Y; - struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs; - if (NULL != prepare_subs && + struct snd_usx2y_substream *subs = urb->context; + struct usx2ydev *usx2y = subs->usx2y; + struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs; + struct snd_usx2y_substream *cap_subs2; + + if (prepare_subs && urb->start_frame == prepare_subs->urb[0]->start_frame) { atomic_inc(&prepare_subs->state); - if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) { - struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; - if (cap_subs2 != NULL) + if (prepare_subs == usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]) { + cap_subs2 = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; + if (cap_subs2) atomic_inc(&cap_subs2->state); } - usX2Y_usbpcm_subs_startup_finish(usX2Y); - wake_up(&usX2Y->prepare_wait_queue); + usx2y_usbpcm_subs_startup_finish(usx2y); + wake_up(&usx2y->prepare_wait_queue); } - i_usX2Y_usbpcm_urb_complete(urb); + i_usx2y_usbpcm_urb_complete(urb); } /* * initialize a substream's urbs */ -static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs) +static int usx2y_usbpcm_urbs_allocate(struct snd_usx2y_substream *subs) { int i; unsigned int pipe; - int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->dev; + int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; + struct usb_device *dev = subs->usx2y->dev; + struct urb **purb; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -312,28 +327,28 @@ static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs) /* allocate and initialize data urbs */ for (i = 0; i < NRURBS; i++) { - struct urb **purb = subs->urb + i; + purb = subs->urb + i; if (*purb) { usb_kill_urb(*purb); continue; } *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL); - if (NULL == *purb) { - usX2Y_usbpcm_urbs_release(subs); + if (!*purb) { + usx2y_usbpcm_urbs_release(subs); return -ENOMEM; } (*purb)->transfer_buffer = is_playback ? - subs->usX2Y->hwdep_pcm_shm->playback : ( + subs->usx2y->hwdep_pcm_shm->playback : ( subs->endpoint == 0x8 ? - subs->usX2Y->hwdep_pcm_shm->capture0x8 : - subs->usX2Y->hwdep_pcm_shm->capture0xA); + subs->usx2y->hwdep_pcm_shm->capture0x8 : + subs->usx2y->hwdep_pcm_shm->capture0xA); (*purb)->dev = dev; (*purb)->pipe = pipe; (*purb)->number_of_packets = nr_of_packs(); (*purb)->context = subs; (*purb)->interval = 1; - (*purb)->complete = i_usX2Y_usbpcm_subs_startup; + (*purb)->complete = i_usx2y_usbpcm_subs_startup; } return 0; } @@ -341,195 +356,216 @@ static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs) /* * free the buffer */ -static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream) +static int snd_usx2y_usbpcm_hw_free(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_usX2Y_substream *subs = runtime->private_data, - *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; - mutex_lock(&subs->usX2Y->pcm_mutex); - snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream); - - if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) { - struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]; - atomic_set(&subs->state, state_STOPPED); - usX2Y_usbpcm_urbs_release(subs); + struct snd_usx2y_substream *subs = runtime->private_data; + struct snd_usx2y_substream *cap_subs; + struct snd_usx2y_substream *playback_subs; + struct snd_usx2y_substream *cap_subs2; + + mutex_lock(&subs->usx2y->pcm_mutex); + snd_printdd("%s(%p)\n", __func__, substream); + + cap_subs2 = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; + atomic_set(&subs->state, STATE_STOPPED); + usx2y_usbpcm_urbs_release(subs); if (!cap_subs->pcm_substream || !cap_subs->pcm_substream->runtime || !cap_subs->pcm_substream->runtime->status || cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) { - atomic_set(&cap_subs->state, state_STOPPED); - if (NULL != cap_subs2) - atomic_set(&cap_subs2->state, state_STOPPED); - usX2Y_usbpcm_urbs_release(cap_subs); - if (NULL != cap_subs2) - usX2Y_usbpcm_urbs_release(cap_subs2); + atomic_set(&cap_subs->state, STATE_STOPPED); + if (cap_subs2) + atomic_set(&cap_subs2->state, STATE_STOPPED); + usx2y_usbpcm_urbs_release(cap_subs); + if (cap_subs2) + usx2y_usbpcm_urbs_release(cap_subs2); } } else { - struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - if (atomic_read(&playback_subs->state) < state_PREPARED) { - atomic_set(&subs->state, state_STOPPED); - if (NULL != cap_subs2) - atomic_set(&cap_subs2->state, state_STOPPED); - usX2Y_usbpcm_urbs_release(subs); - if (NULL != cap_subs2) - usX2Y_usbpcm_urbs_release(cap_subs2); + playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]; + if (atomic_read(&playback_subs->state) < STATE_PREPARED) { + atomic_set(&subs->state, STATE_STOPPED); + if (cap_subs2) + atomic_set(&cap_subs2->state, STATE_STOPPED); + usx2y_usbpcm_urbs_release(subs); + if (cap_subs2) + usx2y_usbpcm_urbs_release(cap_subs2); } } - mutex_unlock(&subs->usX2Y->pcm_mutex); + mutex_unlock(&subs->usx2y->pcm_mutex); return 0; } -static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs) +static void usx2y_usbpcm_subs_startup(struct snd_usx2y_substream *subs) { - struct usX2Ydev * usX2Y = subs->usX2Y; - usX2Y->prepare_subs = subs; + struct usx2ydev *usx2y = subs->usx2y; + + usx2y->prepare_subs = subs; subs->urb[0]->start_frame = -1; - smp_wmb(); // Make sure above modifications are seen by i_usX2Y_subs_startup() - usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup); + smp_wmb(); // Make sure above modifications are seen by i_usx2y_subs_startup() + usx2y_urbs_set_complete(usx2y, i_usx2y_usbpcm_subs_startup); } -static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs) +static int usx2y_usbpcm_urbs_start(struct snd_usx2y_substream *subs) { - int p, u, err, - stream = subs->pcm_substream->stream; - struct usX2Ydev *usX2Y = subs->usX2Y; - - if (SNDRV_PCM_STREAM_CAPTURE == stream) { - usX2Y->hwdep_pcm_shm->captured_iso_head = -1; - usX2Y->hwdep_pcm_shm->captured_iso_frames = 0; + int p, u, err, stream = subs->pcm_substream->stream; + struct usx2ydev *usx2y = subs->usx2y; + struct urb *urb; + unsigned long pack; + + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + usx2y->hwdep_pcm_shm->captured_iso_head = -1; + usx2y->hwdep_pcm_shm->captured_iso_frames = 0; } for (p = 0; 3 >= (stream + p); p += 2) { - struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p]; - if (subs != NULL) { - if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0) + struct snd_usx2y_substream *subs = usx2y->subs[stream + p]; + if (subs) { + err = usx2y_usbpcm_urbs_allocate(subs); + if (err < 0) return err; subs->completed_urb = NULL; } } for (p = 0; p < 4; p++) { - struct snd_usX2Y_substream *subs = usX2Y->subs[p]; - if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED) + struct snd_usx2y_substream *subs = usx2y->subs[p]; + + if (subs && atomic_read(&subs->state) >= STATE_PREPARED) goto start; } start: - usX2Y_usbpcm_subs_startup(subs); + usx2y_usbpcm_subs_startup(subs); for (u = 0; u < NRURBS; u++) { for (p = 0; 3 >= (stream + p); p += 2) { - struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p]; - if (subs != NULL) { - struct urb *urb = subs->urb[u]; - if (usb_pipein(urb->pipe)) { - unsigned long pack; - if (0 == u) - atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->dev; - for (pack = 0; pack < nr_of_packs(); pack++) { - urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); - urb->iso_frame_desc[pack].length = subs->maxpacksize; - } - urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); - if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) { - snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err); - err = -EPIPE; - goto cleanup; - } else { - snd_printdd("%i\n", urb->start_frame); - if (u == 0) - usX2Y->wait_iso_frame = urb->start_frame; - } - urb->transfer_flags = 0; - } else { - atomic_set(&subs->state, state_STARTING1); - break; - } + struct snd_usx2y_substream *subs = usx2y->subs[stream + p]; + + if (!subs) + continue; + urb = subs->urb[u]; + if (usb_pipein(urb->pipe)) { + if (!u) + atomic_set(&subs->state, STATE_STARTING3); + urb->dev = usx2y->dev; + for (pack = 0; pack < nr_of_packs(); pack++) { + urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); + urb->iso_frame_desc[pack].length = subs->maxpacksize; + } + urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); + err = usb_submit_urb(urb, GFP_KERNEL); + if (err < 0) { + snd_printk(KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err); + err = -EPIPE; + goto cleanup; + } else { + snd_printdd("%i\n", urb->start_frame); + if (!u) + usx2y->wait_iso_frame = urb->start_frame; + } + urb->transfer_flags = 0; + } else { + atomic_set(&subs->state, STATE_STARTING1); + break; } } } err = 0; - wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs); - if (atomic_read(&subs->state) != state_PREPARED) + wait_event(usx2y->prepare_wait_queue, !usx2y->prepare_subs); + if (atomic_read(&subs->state) != STATE_PREPARED) err = -EPIPE; - + cleanup: if (err) { - usX2Y_subs_startup_finish(usX2Y); // Call it now - usX2Y_clients_stop(usX2Y); // something is completely wroong > stop evrything + usx2y_subs_startup_finish(usx2y); // Call it now + usx2y_clients_stop(usx2y); // something is completely wroong > stop evrything } return err; } +#define USX2Y_HWDEP_PCM_PAGES \ + PAGE_ALIGN(sizeof(struct snd_usx2y_hwdep_pcm_shm)) + /* * prepare callback * * set format and initialize urbs */ -static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream) +static int snd_usx2y_usbpcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_usX2Y_substream *subs = runtime->private_data; - struct usX2Ydev *usX2Y = subs->usX2Y; - struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]; + struct snd_usx2y_substream *subs = runtime->private_data; + struct usx2ydev *usx2y = subs->usx2y; + struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]; int err = 0; - snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream); - if (NULL == usX2Y->hwdep_pcm_shm) { - usX2Y->hwdep_pcm_shm = alloc_pages_exact(sizeof(struct snd_usX2Y_hwdep_pcm_shm), + snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream); + + mutex_lock(&usx2y->pcm_mutex); + + if (!usx2y->hwdep_pcm_shm) { + usx2y->hwdep_pcm_shm = alloc_pages_exact(USX2Y_HWDEP_PCM_PAGES, GFP_KERNEL); - if (!usX2Y->hwdep_pcm_shm) - return -ENOMEM; - memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm)); + if (!usx2y->hwdep_pcm_shm) { + err = -ENOMEM; + goto up_prepare_mutex; + } + memset(usx2y->hwdep_pcm_shm, 0, USX2Y_HWDEP_PCM_PAGES); } - mutex_lock(&usX2Y->pcm_mutex); - usX2Y_subs_prepare(subs); -// Start hardware streams -// SyncStream first.... - if (atomic_read(&capsubs->state) < state_PREPARED) { - if (usX2Y->format != runtime->format) - if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0) + usx2y_subs_prepare(subs); + // Start hardware streams + // SyncStream first.... + if (atomic_read(&capsubs->state) < STATE_PREPARED) { + if (usx2y->format != runtime->format) { + err = usx2y_format_set(usx2y, runtime->format); + if (err < 0) goto up_prepare_mutex; - if (usX2Y->rate != runtime->rate) - if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0) + } + if (usx2y->rate != runtime->rate) { + err = usx2y_rate_set(usx2y, runtime->rate); + if (err < 0) goto up_prepare_mutex; + } snd_printdd("starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe"); - if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs))) + err = usx2y_usbpcm_urbs_start(capsubs); + if (err < 0) goto up_prepare_mutex; } if (subs != capsubs) { - usX2Y->hwdep_pcm_shm->playback_iso_start = -1; - if (atomic_read(&subs->state) < state_PREPARED) { - while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) > - usX2Y->hwdep_pcm_shm->captured_iso_frames) { - snd_printdd("Wait: iso_frames_per_buffer=%i," - "captured_iso_frames=%i\n", - usX2Y_iso_frames_per_buffer(runtime, usX2Y), - usX2Y->hwdep_pcm_shm->captured_iso_frames); + usx2y->hwdep_pcm_shm->playback_iso_start = -1; + if (atomic_read(&subs->state) < STATE_PREPARED) { + while (usx2y_iso_frames_per_buffer(runtime, usx2y) > + usx2y->hwdep_pcm_shm->captured_iso_frames) { + snd_printdd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", + usx2y_iso_frames_per_buffer(runtime, usx2y), + usx2y->hwdep_pcm_shm->captured_iso_frames); if (msleep_interruptible(10)) { err = -ERESTARTSYS; goto up_prepare_mutex; } - } - if (0 > (err = usX2Y_usbpcm_urbs_start(subs))) + } + err = usx2y_usbpcm_urbs_start(subs); + if (err < 0) goto up_prepare_mutex; } snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", - usX2Y_iso_frames_per_buffer(runtime, usX2Y), - usX2Y->hwdep_pcm_shm->captured_iso_frames); - } else - usX2Y->hwdep_pcm_shm->capture_iso_start = -1; + usx2y_iso_frames_per_buffer(runtime, usx2y), + usx2y->hwdep_pcm_shm->captured_iso_frames); + } else { + usx2y->hwdep_pcm_shm->capture_iso_start = -1; + } up_prepare_mutex: - mutex_unlock(&usX2Y->pcm_mutex); + mutex_unlock(&usx2y->pcm_mutex); return err; } -static const struct snd_pcm_hardware snd_usX2Y_4c = -{ +static const struct snd_pcm_hardware snd_usx2y_4c = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), @@ -547,55 +583,53 @@ static const struct snd_pcm_hardware snd_usX2Y_4c = .fifo_size = 0 }; - - -static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream) +static int snd_usx2y_usbpcm_open(struct snd_pcm_substream *substream) { - struct snd_usX2Y_substream *subs = ((struct snd_usX2Y_substream **) - snd_pcm_substream_chip(substream))[substream->stream]; + struct snd_usx2y_substream *subs = + ((struct snd_usx2y_substream **) + snd_pcm_substream_chip(substream))[substream->stream]; struct snd_pcm_runtime *runtime = substream->runtime; - if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS)) + if (!(subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS)) return -EBUSY; - runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c : - (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + runtime->hw = snd_usx2y_2c; + else + runtime->hw = (subs->usx2y->subs[3] ? snd_usx2y_4c : snd_usx2y_2c); runtime->private_data = subs; subs->pcm_substream = substream; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000); return 0; } - -static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream) +static int snd_usx2y_usbpcm_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_usX2Y_substream *subs = runtime->private_data; + struct snd_usx2y_substream *subs = runtime->private_data; subs->pcm_substream = NULL; return 0; } - -static const struct snd_pcm_ops snd_usX2Y_usbpcm_ops = -{ - .open = snd_usX2Y_usbpcm_open, - .close = snd_usX2Y_usbpcm_close, - .hw_params = snd_usX2Y_pcm_hw_params, - .hw_free = snd_usX2Y_usbpcm_hw_free, - .prepare = snd_usX2Y_usbpcm_prepare, - .trigger = snd_usX2Y_pcm_trigger, - .pointer = snd_usX2Y_pcm_pointer, +static const struct snd_pcm_ops snd_usx2y_usbpcm_ops = { + .open = snd_usx2y_usbpcm_open, + .close = snd_usx2y_usbpcm_close, + .hw_params = snd_usx2y_pcm_hw_params, + .hw_free = snd_usx2y_usbpcm_hw_free, + .prepare = snd_usx2y_usbpcm_prepare, + .trigger = snd_usx2y_pcm_trigger, + .pointer = snd_usx2y_pcm_pointer, }; - -static int usX2Y_pcms_busy_check(struct snd_card *card) +static int usx2y_pcms_busy_check(struct snd_card *card) { - struct usX2Ydev *dev = usX2Y(card); + struct usx2ydev *dev = usx2y(card); + struct snd_usx2y_substream *subs; int i; for (i = 0; i < dev->pcm_devs * 2; i++) { - struct snd_usX2Y_substream *subs = dev->subs[i]; + subs = dev->subs[i]; if (subs && subs->pcm_substream && SUBSTREAM_BUSY(subs->pcm_substream)) return -EBUSY; @@ -603,125 +637,120 @@ static int usX2Y_pcms_busy_check(struct snd_card *card) return 0; } -static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file) +static int snd_usx2y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file) { struct snd_card *card = hw->card; int err; - mutex_lock(&usX2Y(card)->pcm_mutex); - err = usX2Y_pcms_busy_check(card); + mutex_lock(&usx2y(card)->pcm_mutex); + err = usx2y_pcms_busy_check(card); if (!err) - usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS; - mutex_unlock(&usX2Y(card)->pcm_mutex); + usx2y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS; + mutex_unlock(&usx2y(card)->pcm_mutex); return err; } - -static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file) +static int snd_usx2y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file) { struct snd_card *card = hw->card; int err; - mutex_lock(&usX2Y(card)->pcm_mutex); - err = usX2Y_pcms_busy_check(card); + mutex_lock(&usx2y(card)->pcm_mutex); + err = usx2y_pcms_busy_check(card); if (!err) - usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS; - mutex_unlock(&usX2Y(card)->pcm_mutex); + usx2y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS; + mutex_unlock(&usx2y(card)->pcm_mutex); return err; } - -static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area) +static void snd_usx2y_hwdep_pcm_vm_open(struct vm_area_struct *area) { } - -static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area) +static void snd_usx2y_hwdep_pcm_vm_close(struct vm_area_struct *area) { } - -static vm_fault_t snd_usX2Y_hwdep_pcm_vm_fault(struct vm_fault *vmf) +static vm_fault_t snd_usx2y_hwdep_pcm_vm_fault(struct vm_fault *vmf) { unsigned long offset; void *vaddr; offset = vmf->pgoff << PAGE_SHIFT; - vaddr = (char *)((struct usX2Ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset; + vaddr = (char *)((struct usx2ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset; vmf->page = virt_to_page(vaddr); get_page(vmf->page); return 0; } - -static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = { - .open = snd_usX2Y_hwdep_pcm_vm_open, - .close = snd_usX2Y_hwdep_pcm_vm_close, - .fault = snd_usX2Y_hwdep_pcm_vm_fault, +static const struct vm_operations_struct snd_usx2y_hwdep_pcm_vm_ops = { + .open = snd_usx2y_hwdep_pcm_vm_open, + .close = snd_usx2y_hwdep_pcm_vm_close, + .fault = snd_usx2y_hwdep_pcm_vm_fault, }; - -static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area) +static int snd_usx2y_hwdep_pcm_mmap(struct snd_hwdep *hw, struct file *filp, struct vm_area_struct *area) { unsigned long size = (unsigned long)(area->vm_end - area->vm_start); - struct usX2Ydev *usX2Y = hw->private_data; + struct usx2ydev *usx2y = hw->private_data; - if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT)) + if (!(usx2y->chip_status & USX2Y_STAT_CHIP_INIT)) return -EBUSY; - /* if userspace tries to mmap beyond end of our buffer, fail */ - if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) { - snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm)); + /* if userspace tries to mmap beyond end of our buffer, fail */ + if (size > USX2Y_HWDEP_PCM_PAGES) { + snd_printd("%lu > %lu\n", size, (unsigned long)USX2Y_HWDEP_PCM_PAGES); return -EINVAL; } - if (!usX2Y->hwdep_pcm_shm) { + if (!usx2y->hwdep_pcm_shm) return -ENODEV; - } - area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops; + + area->vm_ops = &snd_usx2y_hwdep_pcm_vm_ops; area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; area->vm_private_data = hw->private_data; return 0; } - -static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep) +static void snd_usx2y_hwdep_pcm_private_free(struct snd_hwdep *hwdep) { - struct usX2Ydev *usX2Y = hwdep->private_data; - if (NULL != usX2Y->hwdep_pcm_shm) - free_pages_exact(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm)); -} + struct usx2ydev *usx2y = hwdep->private_data; + if (usx2y->hwdep_pcm_shm) + free_pages_exact(usx2y->hwdep_pcm_shm, USX2Y_HWDEP_PCM_PAGES); +} -int usX2Y_hwdep_pcm_new(struct snd_card *card) +int usx2y_hwdep_pcm_new(struct snd_card *card) { int err; struct snd_hwdep *hw; struct snd_pcm *pcm; - struct usb_device *dev = usX2Y(card)->dev; - if (1 != nr_of_packs()) + struct usb_device *dev = usx2y(card)->dev; + + if (nr_of_packs() != 1) return 0; - if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0) + err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw); + if (err < 0) return err; hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM; - hw->private_data = usX2Y(card); - hw->private_free = snd_usX2Y_hwdep_pcm_private_free; - hw->ops.open = snd_usX2Y_hwdep_pcm_open; - hw->ops.release = snd_usX2Y_hwdep_pcm_release; - hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap; + hw->private_data = usx2y(card); + hw->private_free = snd_usx2y_hwdep_pcm_private_free; + hw->ops.open = snd_usx2y_hwdep_pcm_open; + hw->ops.release = snd_usx2y_hwdep_pcm_release; + hw->ops.mmap = snd_usx2y_hwdep_pcm_mmap; hw->exclusive = 1; sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum); err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm); - if (err < 0) { + if (err < 0) return err; - } - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops); - pcm->private_data = usX2Y(card)->subs; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_usbpcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_usbpcm_ops); + + pcm->private_data = usx2y(card)->subs; pcm->info_flags = 0; sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio"); @@ -739,7 +768,7 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card) #else -int usX2Y_hwdep_pcm_new(struct snd_card *card) +int usx2y_hwdep_pcm_new(struct snd_card *card) { return 0; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.h b/sound/usb/usx2y/usx2yhwdeppcm.h index eb5a46466f0e..731b1c5a3474 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.h +++ b/sound/usb/usx2y/usx2yhwdeppcm.h @@ -4,7 +4,7 @@ #define MAXSTRIDE 3 #define SSS (((MAXPACK*MAXBUFFERMS*MAXSTRIDE + 4096) / 4096) * 4096) -struct snd_usX2Y_hwdep_pcm_shm { +struct snd_usx2y_hwdep_pcm_shm { char playback[SSS]; char capture0x8[SSS]; char capture0xA[SSS]; @@ -20,4 +20,4 @@ struct snd_usX2Y_hwdep_pcm_shm { int capture_iso_start; }; -int usX2Y_hwdep_pcm_new(struct snd_card *card); +int usx2y_hwdep_pcm_new(struct snd_card *card); |