lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251219143244.21674-3-antoniu.miclaus@analog.com>
Date: Fri, 19 Dec 2025 16:31:45 +0200
From: Antoniu Miclaus <antoniu.miclaus@...log.com>
To: Peter Rosin <peda@...ntia.se>, Rob Herring <robh@...nel.org>,
        Krzysztof
 Kozlowski <krzk+dt@...nel.org>,
        Conor Dooley <conor+dt@...nel.org>,
        Antoniu
 Miclaus <antoniu.miclaus@...log.com>,
        Greg Kroah-Hartman
	<gregkh@...uxfoundation.org>,
        Arnd Bergmann <arnd@...db.de>, <devicetree@...r.kernel.org>,
        <linux-kernel@...r.kernel.org>
Subject: [PATCH 2/2] mux: adg2404: add driver support

Add support for ADG2404, a 4:1 analog multiplexer.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@...log.com>
---
 drivers/mux/Kconfig   |  12 ++++
 drivers/mux/Makefile  |   2 +
 drivers/mux/adg2404.c | 133 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 147 insertions(+)
 create mode 100644 drivers/mux/adg2404.c

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index c68132e38138..5aba66e6e210 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -9,6 +9,18 @@ config MULTIPLEXER
 menu "Multiplexer drivers"
 	depends on MULTIPLEXER
 
+config MUX_ADG2404
+	tristate "Analog Devices ADG2404 Multiplexer"
+	depends on GPIOLIB || COMPILE_TEST
+	help
+	  ADG2404 4:1 single-ended analog multiplexer controlled by GPIO.
+
+	  The multiplexer state is controlled by 3 GPIO pins: A0, A1
+	  (address selection) and EN (enable).
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called mux-adg2404.
+
 config MUX_ADG792A
 	tristate "Analog Devices ADG792A/ADG792G Multiplexers"
 	depends on I2C
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 6e9fa47daf56..d3df403f8978 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -4,12 +4,14 @@
 #
 
 mux-core-objs			:= core.o
+mux-adg2404-objs		:= adg2404.o
 mux-adg792a-objs		:= adg792a.o
 mux-adgs1408-objs		:= adgs1408.o
 mux-gpio-objs			:= gpio.o
 mux-mmio-objs			:= mmio.o
 
 obj-$(CONFIG_MULTIPLEXER)	+= mux-core.o
+obj-$(CONFIG_MUX_ADG2404)	+= mux-adg2404.o
 obj-$(CONFIG_MUX_ADG792A)	+= mux-adg792a.o
 obj-$(CONFIG_MUX_ADGS1408)	+= mux-adgs1408.o
 obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
diff --git a/drivers/mux/adg2404.c b/drivers/mux/adg2404.c
new file mode 100644
index 000000000000..5e7352ac7290
--- /dev/null
+++ b/drivers/mux/adg2404.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices ADG2404 4:1 multiplexer driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ *
+ * Author: Antoniu Miclaus <antoniu.miclaus@...log.com>
+ */
+
+#include <linux/bitmap.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mux/driver.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define ADG2404_CHANNELS	4
+
+struct adg2404_mux {
+	struct gpio_descs *addr_gpios;
+	struct gpio_desc *en_gpio;
+};
+
+static int adg2404_set(struct mux_control *mux, int state)
+{
+	struct adg2404_mux *adg2404 = mux_chip_priv(mux->chip);
+	DECLARE_BITMAP(values, BITS_PER_TYPE(state));
+	u32 value = state;
+
+	if (state == MUX_IDLE_DISCONNECT) {
+		gpiod_set_value_cansleep(adg2404->en_gpio, 0);
+		return 0;
+	}
+
+	/*
+	 * Disable the mux before changing address lines to prevent
+	 * glitches. Changing address while enabled could briefly activate
+	 * an unintended channel during the transition.
+	 */
+	gpiod_set_value_cansleep(adg2404->en_gpio, 0);
+
+	bitmap_from_arr32(values, &value, BITS_PER_TYPE(value));
+	gpiod_set_array_value_cansleep(adg2404->addr_gpios->ndescs,
+				       adg2404->addr_gpios->desc,
+				       adg2404->addr_gpios->info,
+				       values);
+
+	/* Enable the mux with the new address */
+	gpiod_set_value_cansleep(adg2404->en_gpio, 1);
+
+	return 0;
+}
+
+static const struct mux_control_ops adg2404_ops = {
+	.set = adg2404_set,
+};
+
+static int adg2404_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mux_chip *mux_chip;
+	struct adg2404_mux *adg2404;
+	s32 idle_state;
+	int ret;
+
+	mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*adg2404));
+	if (IS_ERR(mux_chip))
+		return PTR_ERR(mux_chip);
+
+	adg2404 = mux_chip_priv(mux_chip);
+	mux_chip->ops = &adg2404_ops;
+
+	adg2404->addr_gpios = devm_gpiod_get_array(dev, "addr", GPIOD_OUT_LOW);
+	if (IS_ERR(adg2404->addr_gpios))
+		return dev_err_probe(dev, PTR_ERR(adg2404->addr_gpios),
+				     "failed to get addr gpios\n");
+
+	if (adg2404->addr_gpios->ndescs != 2)
+		return dev_err_probe(dev, -EINVAL,
+				     "addr-gpios must have exactly 2 GPIOs\n");
+
+	adg2404->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_LOW);
+	if (IS_ERR(adg2404->en_gpio))
+		return dev_err_probe(dev, PTR_ERR(adg2404->en_gpio),
+				     "failed to get en gpio\n");
+
+	mux_chip->mux->states = ADG2404_CHANNELS;
+
+	ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state);
+	if (ret < 0)
+		idle_state = MUX_IDLE_AS_IS;
+
+	switch (idle_state) {
+	case MUX_IDLE_DISCONNECT:
+	case MUX_IDLE_AS_IS:
+	case 0 ... ADG2404_CHANNELS - 1:
+		mux_chip->mux->idle_state = idle_state;
+		break;
+	default:
+		dev_err(dev, "invalid idle-state %d\n", idle_state);
+		return -EINVAL;
+	}
+
+	ret = devm_mux_chip_register(dev, mux_chip);
+	if (ret < 0)
+		return ret;
+
+	dev_info(dev, "ADG2404 %u-way mux-controller registered\n",
+		 mux_chip->mux->states);
+
+	return 0;
+}
+
+static const struct of_device_id adg2404_dt_ids[] = {
+	{ .compatible = "adi,adg2404", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adg2404_dt_ids);
+
+static struct platform_driver adg2404_driver = {
+	.driver = {
+		.name = "adg2404",
+		.of_match_table	= adg2404_dt_ids,
+	},
+	.probe = adg2404_probe,
+};
+module_platform_driver(adg2404_driver);
+
+MODULE_DESCRIPTION("Analog Devices ADG2404 multiplexer driver");
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@...log.com>");
+MODULE_LICENSE("GPL");
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ