#include "gpiolib.h"
#include "gpiolib-of.h"
-@@ -1059,3 +1061,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;
}
+ 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;
+
+ 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++;
{
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
-@@ -712,6 +712,7 @@ static inline void devm_acpi_dev_remove_
+@@ -715,6 +715,7 @@ static inline struct gpio_desc *acpi_get
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
-@@ -719,6 +720,13 @@ void gpiod_unexport(struct gpio_desc *de
+@@ -722,6 +723,13 @@ void gpiod_unexport(struct gpio_desc *de
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
{
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
-@@ -561,7 +561,7 @@ static struct class gpio_class = {
+@@ -547,7 +547,7 @@ static struct class gpio_class = {
*
* Returns zero on success, else an error.
*/
{
struct gpio_chip *chip;
struct gpio_device *gdev;
-@@ -623,6 +623,8 @@ int gpiod_export(struct gpio_desc *desc,
+@@ -609,6 +609,8 @@ int gpiod_export(struct gpio_desc *desc,
offset = gpio_chip_hwgpio(desc);
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
dev = device_create_with_groups(&gpio_class, &gdev->dev,
MKDEV(0, 0), data, gpio_groups,
-@@ -644,6 +646,12 @@ err_unlock:
+@@ -630,6 +632,12 @@ err_unlock:
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}