[<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