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 for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251219143554.22793-3-antoniu.miclaus@analog.com>
Date: Fri, 19 Dec 2025 16:35:27 +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: adg1736: add driver support

Add support for ADG1736 analog multiplexer. The device
features two independent 2:1 analog multiplexers, each
controlled by a GPIO pin. Each switch connects its drain
terminal (D) to one of two source terminals (SA or SB) based on
the control input state.

The driver implements two independent mux controllers with a shared
enable GPIO that can disable all switches when set low. Each mux
controller supports idle-state configuration for disconnecting
when not in use.

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

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index c68132e38138..bdf16e0983cc 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -21,6 +21,18 @@ config MUX_ADG792A
 	  To compile the driver as a module, choose M here: the module will
 	  be called mux-adg792a.
 
+config MUX_ADG1736
+	tristate "Analog Devices ADG1736 Dual SPDT Switch Multiplexer"
+	depends on GPIOLIB || COMPILE_TEST
+	help
+	  ADG1736 Dual SPDT (single-pole, double-throw) Switch.
+
+	  The driver supports two independent 2:1 multiplexers, each
+	  controlled by a GPIO pin.
+
+	  To compile the driver as a module, choose M here: the module will
+	  be called mux-adg1736.
+
 config MUX_ADGS1408
 	tristate "Analog Devices ADGS1408/ADGS1409 Multiplexers"
 	depends on SPI
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 6e9fa47daf56..f1497c319bcf 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -5,12 +5,14 @@
 
 mux-core-objs			:= core.o
 mux-adg792a-objs		:= adg792a.o
+mux-adg1736-objs		:= adg1736.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_ADG792A)	+= mux-adg792a.o
+obj-$(CONFIG_MUX_ADG1736)	+= mux-adg1736.o
 obj-$(CONFIG_MUX_ADGS1408)	+= mux-adgs1408.o
 obj-$(CONFIG_MUX_GPIO)		+= mux-gpio.o
 obj-$(CONFIG_MUX_MMIO)		+= mux-mmio.o
diff --git a/drivers/mux/adg1736.c b/drivers/mux/adg1736.c
new file mode 100644
index 000000000000..b3998121487e
--- /dev/null
+++ b/drivers/mux/adg1736.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices ADG1736 Dual SPDT Switch Multiplexer driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ *
+ * Author: Antoniu Miclaus <antoniu.miclaus@...log.com>
+ */
+
+#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 ADG1736_MUX_CONTROLLERS	2
+#define ADG1736_MUX_STATES	2
+
+struct adg1736_mux {
+	struct gpio_desc *ctrl_gpios[ADG1736_MUX_CONTROLLERS];
+	struct gpio_desc *en_gpio;
+};
+
+static int adg1736_set(struct mux_control *mux, int state)
+{
+	struct adg1736_mux *adg1736 = mux_chip_priv(mux->chip);
+	unsigned int controller = mux_control_get_index(mux);
+
+	if (controller >= ADG1736_MUX_CONTROLLERS)
+		return -EINVAL;
+
+	if (state == MUX_IDLE_DISCONNECT) {
+		/* When idle disconnect is requested, disable the EN pin */
+		if (controller == 0)
+			gpiod_set_value_cansleep(adg1736->en_gpio, 0);
+		return 0;
+	}
+
+	/* Set the control GPIO for this mux controller */
+	gpiod_set_value_cansleep(adg1736->ctrl_gpios[controller], state);
+
+	/* Enable the mux if disabled */
+	gpiod_set_value_cansleep(adg1736->en_gpio, 1);
+
+	return 0;
+}
+
+static const struct mux_control_ops adg1736_ops = {
+	.set = adg1736_set,
+};
+
+static int adg1736_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mux_chip *mux_chip;
+	struct adg1736_mux *adg1736;
+	s32 idle_state[ADG1736_MUX_CONTROLLERS];
+	char gpio_name[16];
+	int ret, i;
+
+	mux_chip = devm_mux_chip_alloc(dev, ADG1736_MUX_CONTROLLERS,
+				       sizeof(*adg1736));
+	if (IS_ERR(mux_chip))
+		return PTR_ERR(mux_chip);
+
+	adg1736 = mux_chip_priv(mux_chip);
+	mux_chip->ops = &adg1736_ops;
+
+	/* Get control GPIOs (IN1, IN2) */
+	for (i = 0; i < ADG1736_MUX_CONTROLLERS; i++) {
+		snprintf(gpio_name, sizeof(gpio_name), "ctrl%d", i);
+		adg1736->ctrl_gpios[i] = devm_gpiod_get_index(dev, "ctrl", i,
+							      GPIOD_OUT_LOW);
+		if (IS_ERR(adg1736->ctrl_gpios[i]))
+			return dev_err_probe(dev, PTR_ERR(adg1736->ctrl_gpios[i]),
+					     "failed to get ctrl%d gpio\n", i);
+	}
+
+	/* Get enable GPIO (EN) */
+	adg1736->en_gpio = devm_gpiod_get(dev, "en", GPIOD_OUT_LOW);
+	if (IS_ERR(adg1736->en_gpio))
+		return dev_err_probe(dev, PTR_ERR(adg1736->en_gpio),
+				     "failed to get en gpio\n");
+
+	/* Read idle-state property */
+	ret = device_property_read_u32_array(dev, "idle-state",
+					     (u32 *)idle_state,
+					     ADG1736_MUX_CONTROLLERS);
+	if (ret < 0) {
+		/* Default to AS_IS if not specified */
+		idle_state[0] = MUX_IDLE_AS_IS;
+		idle_state[1] = MUX_IDLE_AS_IS;
+	}
+
+	/* Configure each mux controller */
+	for (i = 0; i < ADG1736_MUX_CONTROLLERS; i++) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		mux->states = ADG1736_MUX_STATES;
+
+		switch (idle_state[i]) {
+		case MUX_IDLE_DISCONNECT:
+		case MUX_IDLE_AS_IS:
+		case 0 ... ADG1736_MUX_STATES - 1:
+			mux->idle_state = idle_state[i];
+			break;
+		default:
+			dev_err(dev, "invalid idle-state[%d] = %d\n",
+				i, idle_state[i]);
+			return -EINVAL;
+		}
+	}
+
+	ret = devm_mux_chip_register(dev, mux_chip);
+	if (ret < 0)
+		return ret;
+
+	dev_info(dev, "ADG1736 %u dual SPDT mux controllers registered\n",
+		 mux_chip->controllers);
+
+	return 0;
+}
+
+static const struct of_device_id adg1736_dt_ids[] = {
+	{ .compatible = "adi,adg1736", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adg1736_dt_ids);
+
+static struct platform_driver adg1736_driver = {
+	.driver = {
+		.name = "adg1736",
+		.of_match_table = adg1736_dt_ids,
+	},
+	.probe = adg1736_probe,
+};
+module_platform_driver(adg1736_driver);
+
+MODULE_DESCRIPTION("Analog Devices ADG1736 Dual SPDT Switch 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