The XMOS XVF3500 VocalFusion Voice Processor[1] is a low-latency, 32-bit multicore controller for voice processing. This simple driver provides the power sequence the device requires, which consists of enabling the regulators that control the device supplies and a reset de-assertion after a delay of at least 100ns. Simple PM operations to handle the power sequence after resuming from a power-down mode are also provided. Once in normal operation, the device registers itself as a USB device. Therefore, this driver requires USB to be available in order to guarantee full support. [1] https://www.xmos.com/xvf3500/ Signed-off-by: Javier Carrasco <javier.carrasco@xxxxxxxxxxxxxx> --- MAINTAINERS | 7 +++ sound/usb/Kconfig | 9 +++ sound/usb/Makefile | 3 +- sound/usb/xvf3500/Makefile | 4 ++ sound/usb/xvf3500/xvf3500.c | 140 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a7c4cf8201e0..fb9be0e12c71 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23960,6 +23960,13 @@ S: Supported W: http://www.marvell.com F: drivers/i2c/busses/i2c-xlp9xx.c +XMOS XVF3500 VOICE PROCESSOR DRIVER +M: Javier Carrasco <javier.carrasco@xxxxxxxxxxxxxx> +L: linux-sound@xxxxxxxxxxxxxxx +S: Supported +F: Documentation/devicetree/bindings/sound/xmos,xvf3500.yaml +F: sound/usb/xvf3500/xvf3500.c + XRA1403 GPIO EXPANDER M: Nandor Han <nandor.han@xxxxxx> L: linux-gpio@xxxxxxxxxxxxxxx diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 4a9569a3a39a..11565429163b 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -176,6 +176,15 @@ config SND_BCD2000 To compile this driver as a module, choose M here: the module will be called snd-bcd2000. +config SND_XVF3500 + tristate "XMOS XVF3500 voice processor driver" + help + Say Y here to include support for the XMOS XVF3500 voice + processor. + + To compile this driver as a module, choose M here: the module + will be called snd-xvf3500. + source "sound/usb/line6/Kconfig" endif # SND_USB diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 8c657c2753c8..4171db0f483c 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -34,5 +34,6 @@ obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o -obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ +obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ xvf3500/ obj-$(CONFIG_SND_USB_LINE6) += line6/ + diff --git a/sound/usb/xvf3500/Makefile b/sound/usb/xvf3500/Makefile new file mode 100644 index 000000000000..51a61c8f165d --- /dev/null +++ b/sound/usb/xvf3500/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +snd-xvf3500-y := xvf3500.o + +obj-$(CONFIG_SND_XVF3500) += snd-xvf3500.o diff --git a/sound/usb/xvf3500/xvf3500.c b/sound/usb/xvf3500/xvf3500.c new file mode 100644 index 000000000000..647e5d09d1e5 --- /dev/null +++ b/sound/usb/xvf3500/xvf3500.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the XMOS XVF3500 VocalFusion Voice Processor. + * + * Copyright (C) 2023 WolfVision GmbH. + * + */ + +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +static const char * const supply_names[] = { + "vcc1v0", + "vcc3v3", +}; + +#define NUM_SUPPLIES ARRAY_SIZE(supply_names) + +struct xvf3500 { + struct regulator_bulk_data supplies[NUM_SUPPLIES]; + struct device *dev; + struct gpio_desc *reset; +}; + +static int xvf3500_power(struct xvf3500 *priv, bool on) +{ + int ret; + + if (on) { + ret = regulator_bulk_enable(NUM_SUPPLIES, priv->supplies); + if (ret) { + dev_err(priv->dev, "failed to enable supplies: %d\n", ret); + return ret; + } + /* + * A delay of >=100ns + regulator startup is needed before releasing + * the reset here. Wait for 10 ms to be on the safe side. + */ + fsleep(10000); + gpiod_set_value_cansleep(priv->reset, 0); + } else { + gpiod_set_value_cansleep(priv->reset, 1); + ret = regulator_bulk_disable(NUM_SUPPLIES, priv->supplies); + if (ret) { + dev_err(priv->dev, "failed to disable supplies: %d\n", ret); + return ret; + } + } + + return 0; +} + +static int xvf3500_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct xvf3500 *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + dev_set_drvdata(dev, priv); + + regulator_bulk_set_supply_names(priv->supplies, supply_names, + NUM_SUPPLIES); + + ret = devm_regulator_bulk_get(dev, NUM_SUPPLIES, priv->supplies); + if (ret) { + dev_err_probe(dev, ret, "Failed to get regulator supplies\n"); + return ret; + } + + priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(priv->reset)) + return dev_err_probe(priv->dev, PTR_ERR(priv->reset), + "failed to get reset GPIO\n"); + + return xvf3500_power(priv, true); +} + +static void xvf3500_remove(struct platform_device *pdev) +{ + struct xvf3500 *priv = dev_get_drvdata(&pdev->dev); + + xvf3500_power(priv, false); +} + +#ifdef CONFIG_PM_SLEEP +static int xvf3500_suspend(struct device *dev) +{ + struct xvf3500 *priv = dev_get_drvdata(dev); + + xvf3500_power(priv, false); + + return 0; +} + +static int xvf3500_resume(struct device *dev) +{ + struct xvf3500 *priv = dev_get_drvdata(dev); + + xvf3500_power(priv, true); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(xvf3500_pm, xvf3500_suspend, xvf3500_resume); +#define XVF3500_PM_OPS (&xvf3500_pm) +#else +#define XVF3500_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static const struct of_device_id xvf3500_of_table[] = { + { + .compatible = "xmos,xvf3500", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, xvf3500_of_table); + +static struct platform_driver xvf3500_driver = { + .driver = { + .name = "xvf3500", + .of_match_table = xvf3500_of_table, + .pm = XVF3500_PM_OPS, + }, + .probe = xvf3500_probe, + .remove_new = xvf3500_remove, +}; +module_platform_driver(xvf3500_driver); + +MODULE_AUTHOR("Javier Carrasco <javier.carrasco@xxxxxxxxxxxxxx>"); +MODULE_DESCRIPTION("XMOS XVF3500 Voice Processor"); +MODULE_LICENSE("GPL"); -- 2.39.2