Changelog: https://cdn.kernel.org/pub/linux/kernel/v6.x/ChangeLog-6.18.34 Removed upstreamed: backport-6.18/627-v7.1-net-pse-pd-fix-sign-on-ENOENT-check-in-of_load_pse_p.patch[1] ath79/patches-6.18/301-irqchip-irq-ath79-cpu-drop-OF-init-helper.patch[2] ipq40xx/patches-6.18/708-pinctrl-qcom-ipq4019-mark-gpio-as-a-GPIO-pin-function.patch[3] All other patches automatically rebased via update_kernel.sh 1. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v6.18.34&id=dac025c4e8f9c5cf9467eeac8be4639469aa5ac5 2. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v6.18.34&id=617a2564d8634c06d19097dc0f89bd3a72bcb1b4 3. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v6.18.34&id=00aca89f5e3453b30b73e31aa31099b1433f8370 Build system: x86/64 Build-tested: x86/64-glibc Run-tested: x86/64-glibc Signed-off-by: John Audia <therealgraysky@proton.me> Link: https://github.com/openwrt/openwrt/pull/23618 Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
210 lines
6.5 KiB
Diff
210 lines
6.5 KiB
Diff
From 2b03d9a40cd1fea42fd65d2b66df80edc0f374c8 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Jelonek <jelonek.jonas@gmail.com>
|
|
Date: Sat, 27 Dec 2025 18:01:34 +0000
|
|
Subject: [PATCH] gpio: add gpio-line-mux driver
|
|
|
|
Add a new driver which provides a 1-to-many mapping for a single real
|
|
GPIO using a multiplexer. Each virtual GPIO corresponds to a multiplexer
|
|
state which, if set for the multiplexer, connects the real GPIO to the
|
|
corresponding virtual GPIO.
|
|
|
|
This can help in various usecases. One practical case is the special
|
|
hardware design of the Realtek-based XS1930-10 switch from Zyxel. It
|
|
features two SFP+ ports/cages whose signals are wired directly to the
|
|
switch SoC. Although Realtek SoCs are short on GPIOs, there are usually
|
|
enough the fit the SFP signals without any hacks.
|
|
|
|
However, Zyxel did some weird design and connected RX_LOS, MOD_ABS and
|
|
TX_FAULT of one SFP cage onto a single GPIO line controlled by a
|
|
multiplexer (the same for the other SFP cage). The single multiplexer
|
|
controls the lines for both SFP and depending on the state, the
|
|
designated 'signal GPIO lines' are connected to one of the three SFP
|
|
signals.
|
|
|
|
Because the SFP core/driver doesn't support multiplexer but needs single
|
|
GPIOs for each of the signals, this driver fills the gap between both.
|
|
It registers a gpio_chip, provides multiple virtual GPIOs and sets the
|
|
backing multiplexer accordingly.
|
|
|
|
Due to several practical issues, this is input-only and doesn't support
|
|
IRQs.
|
|
|
|
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
|
|
Reviewed-by: Thomas Richard <thomas.richard@bootlin.com>
|
|
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
|
|
Link: https://lore.kernel.org/r/20251227180134.1262138-3-jelonek.jonas@gmail.com
|
|
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
|
|
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -10656,6 +10656,12 @@ S: Maintained
|
|
F: Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.yaml
|
|
F: drivers/media/rc/gpio-ir-tx.c
|
|
|
|
+GPIO LINE MUX
|
|
+M: Jonas Jelonek <jelonek.jonas@gmail.com>
|
|
+S: Maintained
|
|
+F: Documentation/devicetree/bindings/gpio/gpio-line-mux.yaml
|
|
+F: drivers/gpio/gpio-line-mux.c
|
|
+
|
|
GPIO MOCKUP DRIVER
|
|
M: Bamvor Jian Zhang <bamv2005@gmail.com>
|
|
L: linux-gpio@vger.kernel.org
|
|
--- a/drivers/gpio/Kconfig
|
|
+++ b/drivers/gpio/Kconfig
|
|
@@ -1984,6 +1984,15 @@ config GPIO_LATCH
|
|
Say yes here to enable a driver for GPIO multiplexers based on latches
|
|
connected to other GPIOs.
|
|
|
|
+config GPIO_LINE_MUX
|
|
+ tristate "GPIO line mux driver"
|
|
+ depends on OF_GPIO
|
|
+ select MULTIPLEXER
|
|
+ help
|
|
+ Say Y here to support the GPIO line mux, which can provide virtual
|
|
+ GPIOs backed by a shared real GPIO and a multiplexer in a 1-to-many
|
|
+ fashion.
|
|
+
|
|
config GPIO_MOCKUP
|
|
tristate "GPIO Testing Driver (DEPRECATED)"
|
|
select IRQ_SIM
|
|
--- a/drivers/gpio/Makefile
|
|
+++ b/drivers/gpio/Makefile
|
|
@@ -89,6 +89,7 @@ obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4x
|
|
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
|
|
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
|
|
obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
|
|
+obj-$(CONFIG_GPIO_LINE_MUX) += gpio-line-mux.o
|
|
obj-$(CONFIG_GPIO_LJCA) += gpio-ljca.o
|
|
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
|
|
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
|
|
--- /dev/null
|
|
+++ b/drivers/gpio/gpio-line-mux.c
|
|
@@ -0,0 +1,126 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * GPIO line mux which acts as virtual gpiochip and provides a 1-to-many
|
|
+ * mapping between virtual GPIOs and a real GPIO + multiplexer.
|
|
+ *
|
|
+ * Copyright (c) 2025 Jonas Jelonek <jelonek.jonas@gmail.com>
|
|
+ */
|
|
+
|
|
+#include <linux/gpio/consumer.h>
|
|
+#include <linux/gpio/driver.h>
|
|
+#include <linux/mod_devicetable.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/mux/consumer.h>
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+#define MUX_SELECT_DELAY_US 100
|
|
+
|
|
+struct gpio_lmux {
|
|
+ struct gpio_chip gc;
|
|
+ struct mux_control *mux;
|
|
+ struct gpio_desc *muxed_gpio;
|
|
+
|
|
+ u32 num_gpio_mux_states;
|
|
+ unsigned int gpio_mux_states[] __counted_by(num_gpio_mux_states);
|
|
+};
|
|
+
|
|
+static int gpio_lmux_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
|
+{
|
|
+ struct gpio_lmux *glm = gpiochip_get_data(gc);
|
|
+ int ret;
|
|
+
|
|
+ if (offset > gc->ngpio)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ret = mux_control_select_delay(glm->mux, glm->gpio_mux_states[offset],
|
|
+ MUX_SELECT_DELAY_US);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ret = gpiod_get_raw_value_cansleep(glm->muxed_gpio);
|
|
+ mux_control_deselect(glm->mux);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int gpio_lmux_gpio_set(struct gpio_chip *gc, unsigned int offset,
|
|
+ int value)
|
|
+{
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static int gpio_lmux_gpio_get_direction(struct gpio_chip *gc,
|
|
+ unsigned int offset)
|
|
+{
|
|
+ return GPIO_LINE_DIRECTION_IN;
|
|
+}
|
|
+
|
|
+static int gpio_lmux_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct gpio_lmux *glm;
|
|
+ unsigned int ngpio;
|
|
+ size_t size;
|
|
+ int ret;
|
|
+
|
|
+ ngpio = device_property_count_u32(dev, "gpio-line-mux-states");
|
|
+ if (!ngpio)
|
|
+ return -EINVAL;
|
|
+
|
|
+ size = struct_size(glm, gpio_mux_states, ngpio);
|
|
+ glm = devm_kzalloc(dev, size, GFP_KERNEL);
|
|
+ if (!glm)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ glm->gc.base = -1;
|
|
+ glm->gc.can_sleep = true;
|
|
+ glm->gc.fwnode = dev_fwnode(dev);
|
|
+ glm->gc.label = dev_name(dev);
|
|
+ glm->gc.ngpio = ngpio;
|
|
+ glm->gc.owner = THIS_MODULE;
|
|
+ glm->gc.parent = dev;
|
|
+
|
|
+ glm->gc.get = gpio_lmux_gpio_get;
|
|
+ glm->gc.set = gpio_lmux_gpio_set;
|
|
+ glm->gc.get_direction = gpio_lmux_gpio_get_direction;
|
|
+
|
|
+ glm->mux = devm_mux_control_get(dev, NULL);
|
|
+ if (IS_ERR(glm->mux))
|
|
+ return dev_err_probe(dev, PTR_ERR(glm->mux),
|
|
+ "could not get mux controller\n");
|
|
+
|
|
+ glm->muxed_gpio = devm_gpiod_get(dev, "muxed", GPIOD_IN);
|
|
+ if (IS_ERR(glm->muxed_gpio))
|
|
+ return dev_err_probe(dev, PTR_ERR(glm->muxed_gpio),
|
|
+ "could not get muxed-gpio\n");
|
|
+
|
|
+ glm->num_gpio_mux_states = ngpio;
|
|
+ ret = device_property_read_u32_array(dev, "gpio-line-mux-states",
|
|
+ &glm->gpio_mux_states[0], ngpio);
|
|
+ if (ret)
|
|
+ return dev_err_probe(dev, ret, "could not get mux states\n");
|
|
+
|
|
+ ret = devm_gpiochip_add_data(dev, &glm->gc, glm);
|
|
+ if (ret)
|
|
+ return dev_err_probe(dev, ret, "failed to add gpiochip\n");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id gpio_lmux_of_match[] = {
|
|
+ { .compatible = "gpio-line-mux" },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, gpio_lmux_of_match);
|
|
+
|
|
+static struct platform_driver gpio_lmux_driver = {
|
|
+ .driver = {
|
|
+ .name = "gpio-line-mux",
|
|
+ .of_match_table = gpio_lmux_of_match,
|
|
+ },
|
|
+ .probe = gpio_lmux_probe,
|
|
+};
|
|
+module_platform_driver(gpio_lmux_driver);
|
|
+
|
|
+MODULE_AUTHOR("Jonas Jelonek <jelonek.jonas@gmail.com>");
|
|
+MODULE_DESCRIPTION("GPIO line mux driver");
|
|
+MODULE_LICENSE("GPL");
|