.../bindings/gpio/gpio-line-mux.yaml | 107 +++++++++++++++ MAINTAINERS | 6 + drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-line-mux.c | 126 ++++++++++++++++++ 5 files changed, 249 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-line-mux.yaml create mode 100644 drivers/gpio/gpio-line-mux.c
This proposes a new type of virtual GPIO controller and corresponding
driver to provide a 1-to-many mapping between virtual GPIOs and a single
real GPIO in combination with a multiplexer. Existing drivers apparently
do not serve the purpose for what I need.
I came across an issue with a switch device from Zyxel which has two
SFP+ cages. Most similar switches either wire up the SFP signals
(RX_LOS, MOD_ABS, TX_FAULT, TX_DISABLE) directly to the SoC (if it has
enough GPIOs) or two a GPIO expander (for which a driver usually
exists). However, Zyxel decided to do it differently in the following
way:
The signals RX_LOS, MOD_ABS and TX_FAULT share a single GPIO line to
the SoC. Which one is actually connected to that GPIO line at a time
is controlled by a separate multiplexer, a GPIO multiplexer in this
case (which uses two other GPIOs). Only the TX_DISABLE is separate.
The SFP core/driver doesn't seem to support such a usecase for now, for
each signal one needs to specify a separate GPIO like:
los-gpio = <&gpio0 0 GPIO_ACTIVE_HIGH>;
mod-def0-gpio = <&gpio0 1 GPIO_ACTIVE_LOW>;
...
But for my device, I actually need to directly specify multiplexing
behavior in the SFP node or provide a mux-controller with 'mux-controls'.
To fill this gap, I created a dt-schema and a working driver which
exactly does what is needed. It takes a phandle to a mux-controller and
the 'shared' gpio, and provides several virtual GPIOs based on the
gpio-line-mux-states property.
This virtual gpio-controller can then be referenced in the '-gpio'
properties of the SFP node (or other nodes depending on the usecase) as
usual and do not require any modification to the SFP core/driver.
---
Changelog:
v7: - dt-bindings fixes:
- dropped unneeded reference
- adjusted presumably confusing example
- added missing colon
Link to v6:
https://lore.kernel.org/linux-gpio/20251111092705.196465-1-jelonek.jonas@gmail.com/
v6: - added count member + __counted_by attribute for gpio_mux_states
- included Reviewed-by tags
Link to v5:
https://lore.kernel.org/linux-gpio/20251105163610.610793-1-jelonek.jonas@gmail.com/
v5: - renamed "shared" to "muxed" to avoid confusion with Bartosz' work
- dropped Reviewed-by of Krzysztof due to binding change
- use GPIOD_IN in devm_gpiod_get instead of calling
gpiod_direction_input explicitly afterwards
Link to v4:
https://lore.kernel.org/linux-gpio/20251105103607.393353-1-jelonek.jonas@gmail.com/
v4: - dropped useless cast (as suggested by Thomas)
- dropped unneeded locking (as suggested by Peter)
- fixed wording in commit message
- included Reviewed-by of Krzysztof
Link to v3:
https://lore.kernel.org/linux-gpio/20251104210021.247476-1-jelonek.jonas@gmail.com/
v3: - fixed dt_binding_check errors in DT schema
- as requested by Rob (for DT schema):
- removed example from gpio-mux.yaml
- added '|' to preserve formatting
- 'shared-gpio' --> 'shared-gpios'
- general fixes to DT schema
- use mux_control_select_delay (as suggested by Peter) with
hopefully reasonable delay of 100us
- gpiochip ops implementation changes:
- drop '.set' implementation (as suggested by Peter)
- new '.set' implementation just returning -EOPNOTSUPP
- '.direction_output' and '.direction_input' dropped
- '.get_direction' returns fixed value for 'input'
- direction of shared gpio set to input during probe
- as suggested by Thomas
- usage of dev_err_probe
- further simplifications
Since the consensus was that this should be input-only,
'.direction_output' and '.direction_input' have been dropped
completely, as suggested in the docs of struct gpio_chip. '.set' is
kept but returns -ENOTSUPP.
The shared GPIO is set to input during probe, thus '.direction_input'
doesn't need to be implemented. '.get_direction' is kept (as
suggested in docs of struct gpio_chip) but always returns
GPIO_LINE_DIRECTION_IN.
Link to v2:
https://lore.kernel.org/linux-gpio/20251026231754.2368904-1-jelonek.jonas@gmail.com/
v2: - as requested by Linus:
- renamed from 'gpio-split' to 'gpio-line-mux'
- added better description and examples to DT bindings
- simplified driver
- added missing parts to DT bindings
- dropped RFC tag
- renamed patchset
Link to v1 (in case it isn't linked properly due to changed title):
https://lore.kernel.org/linux-gpio/20251009223501.570949-1-jelonek.jonas@gmail.com/
---
Jonas Jelonek (2):
dt-bindings: gpio: add gpio-line-mux controller
gpio: add gpio-line-mux driver
.../bindings/gpio/gpio-line-mux.yaml | 107 +++++++++++++++
MAINTAINERS | 6 +
drivers/gpio/Kconfig | 9 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-line-mux.c | 126 ++++++++++++++++++
5 files changed, 249 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-line-mux.yaml
create mode 100644 drivers/gpio/gpio-line-mux.c
base-commit: 48befae0d6eee275c3e30d1cd45f39d6ba011e19
--
2.48.1
On Sat, Dec 27, 2025 at 7:01 PM Jonas Jelonek <jelonek.jonas@gmail.com> wrote: > This proposes a new type of virtual GPIO controller and corresponding > driver to provide a 1-to-many mapping between virtual GPIOs and a single > real GPIO in combination with a multiplexer. Existing drivers apparently > do not serve the purpose for what I need. Thanks for persisting and doing this the right way all the way through, Jonas! This driver will probably be helpful for other users with the same quirk in the future. Yours, Linus Walleij
On Sat, 27 Dec 2025 18:01:32 +0000, Jonas Jelonek wrote:
> This proposes a new type of virtual GPIO controller and corresponding
> driver to provide a 1-to-many mapping between virtual GPIOs and a single
> real GPIO in combination with a multiplexer. Existing drivers apparently
> do not serve the purpose for what I need.
>
> I came across an issue with a switch device from Zyxel which has two
> SFP+ cages. Most similar switches either wire up the SFP signals
> (RX_LOS, MOD_ABS, TX_FAULT, TX_DISABLE) directly to the SoC (if it has
> enough GPIOs) or two a GPIO expander (for which a driver usually
> exists). However, Zyxel decided to do it differently in the following
> way:
> The signals RX_LOS, MOD_ABS and TX_FAULT share a single GPIO line to
> the SoC. Which one is actually connected to that GPIO line at a time
> is controlled by a separate multiplexer, a GPIO multiplexer in this
> case (which uses two other GPIOs). Only the TX_DISABLE is separate.
>
> [...]
Applied, thanks!
[1/2] dt-bindings: gpio: add gpio-line-mux controller
commit: 2a7618ba8698874e9871a8ec5453e0068e94d9e5
[2/2] gpio: add gpio-line-mux driver
commit: 2b03d9a40cd1fea42fd65d2b66df80edc0f374c8
Best regards,
--
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
© 2016 - 2026 Red Hat, Inc.