From 0af88d2512b94bb0e3d81058beaa220448e46119 Mon Sep 17 00:00:00 2001 From: Martin Schiller Date: Fri, 4 Aug 2023 12:59:03 +0200 Subject: [PATCH] linux/named-gpio-export: add support for OPEN_DRAIN and OPEN_SOURCE flag This change makes it possible to use the GPIO_OPEN_DRAIN / GPIO_OPEN_SOURCE Flags when exporting GPIOs via dts. We need to emulate the open-source or open-drain functionalities for the initial value, because the used functions (gpiod_direction_output_raw) do not take this into account. Signed-off-by: Martin Schiller --- .../800-GPIO-add-named-gpio-exports.patch | 38 ++++++++++++++++--- .../800-GPIO-add-named-gpio-exports.patch | 38 ++++++++++++++++--- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/target/linux/generic/hack-5.15/800-GPIO-add-named-gpio-exports.patch b/target/linux/generic/hack-5.15/800-GPIO-add-named-gpio-exports.patch index 0a2c82cacb..f27b7ef9de 100644 --- a/target/linux/generic/hack-5.15/800-GPIO-add-named-gpio-exports.patch +++ b/target/linux/generic/hack-5.15/800-GPIO-add-named-gpio-exports.patch @@ -15,7 +15,7 @@ Signed-off-by: John Crispin #include "gpiolib.h" #include "gpiolib-of.h" -@@ -1059,3 +1061,72 @@ void of_gpio_dev_init(struct gpio_chip * +@@ -1059,3 +1061,100 @@ void of_gpio_dev_init(struct gpio_chip * else gc->of_node = gdev->dev.of_node; } @@ -47,6 +47,7 @@ Signed-off-by: John Crispin + max_gpio = of_gpio_count(cnp); + + for (i = 0; i < max_gpio; i++) { ++ struct gpio_desc *desc; + unsigned flags = 0; + enum of_gpio_flags of_flags; + @@ -54,17 +55,44 @@ Signed-off-by: John Crispin + if (!gpio_is_valid(gpio)) + return gpio; + -+ if (of_flags == OF_GPIO_ACTIVE_LOW) ++ if (of_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; + -+ if (!of_property_read_u32(cnp, "gpio-export,output", &val)) -+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; -+ else ++ if (!of_property_read_u32(cnp, "gpio-export,output", &val)) { ++ if (of_flags & OF_GPIO_SINGLE_ENDED) { ++ /* ++ * As gpiod_direction_output_raw() is used, we ++ * need to emulate open drain or open source here. ++ */ ++ if (of_flags & OF_GPIO_OPEN_DRAIN) { ++ flags |= GPIOF_OPEN_DRAIN; ++ flags |= val ? GPIOF_IN : GPIOF_OUT_INIT_LOW; ++ } else { ++ flags |= GPIOF_OPEN_SOURCE; ++ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_IN; ++ } ++ } else { ++ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ } ++ } else { + flags |= GPIOF_IN; ++ } + + if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np))) + continue; + ++ /* ++ * When emulating open-source or open-drain functionalities by not ++ * actively driving the line (setting mode to input) we still need to ++ * set the IS_OUT flag or otherwise we won't be able to set the line ++ * value anymore. ++ */ ++ if ((flags & GPIOF_IN) && ++ ((flags & GPIOF_OPEN_DRAIN) || (flags & GPIOF_OPEN_SOURCE))) { ++ desc = gpio_to_desc(gpio); ++ set_bit(FLAG_IS_OUT, &desc->flags); ++ } ++ + dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); + gpio_export_with_name(gpio, dmc, name); + nb++; diff --git a/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch b/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch index 658d9c3806..ba5351275d 100644 --- a/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch +++ b/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch @@ -15,7 +15,7 @@ Signed-off-by: John Crispin #include "gpiolib.h" #include "gpiolib-of.h" -@@ -1030,3 +1032,72 @@ void of_gpio_dev_init(struct gpio_chip * +@@ -1030,3 +1032,100 @@ void of_gpio_dev_init(struct gpio_chip * else gc->of_node = gdev->dev.of_node; } @@ -47,6 +47,7 @@ Signed-off-by: John Crispin + max_gpio = of_gpio_count(cnp); + + for (i = 0; i < max_gpio; i++) { ++ struct gpio_desc *desc; + unsigned flags = 0; + enum of_gpio_flags of_flags; + @@ -54,17 +55,44 @@ Signed-off-by: John Crispin + if (!gpio_is_valid(gpio)) + return gpio; + -+ if (of_flags == OF_GPIO_ACTIVE_LOW) ++ if (of_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; + -+ if (!of_property_read_u32(cnp, "gpio-export,output", &val)) -+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; -+ else ++ if (!of_property_read_u32(cnp, "gpio-export,output", &val)) { ++ if (of_flags & OF_GPIO_SINGLE_ENDED) { ++ /* ++ * As gpiod_direction_output_raw() is used, we ++ * need to emulate open drain or open source here. ++ */ ++ if (of_flags & OF_GPIO_OPEN_DRAIN) { ++ flags |= GPIOF_OPEN_DRAIN; ++ flags |= val ? GPIOF_IN : GPIOF_OUT_INIT_LOW; ++ } else { ++ flags |= GPIOF_OPEN_SOURCE; ++ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_IN; ++ } ++ } else { ++ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ } ++ } else { + flags |= GPIOF_IN; ++ } + + if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np))) + continue; + ++ /* ++ * When emulating open-source or open-drain functionalities by not ++ * actively driving the line (setting mode to input) we still need to ++ * set the IS_OUT flag or otherwise we won't be able to set the line ++ * value anymore. ++ */ ++ if ((flags & GPIOF_IN) && ++ ((flags & GPIOF_OPEN_DRAIN) || (flags & GPIOF_OPEN_SOURCE))) { ++ desc = gpio_to_desc(gpio); ++ set_bit(FLAG_IS_OUT, &desc->flags); ++ } ++ + dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); + gpio_export_with_name(gpio, dmc, name); + nb++; -- 2.30.2