colibri_imx6: fix video stdout in default environment
[oweals/u-boot.git] / drivers / gpio / gpio-uclass.c
index 84e5013cceb58e4af1c10c81dfa27d7d2fa71dc8..9eeab22eef5a63c72564083aa912dc944e7e1cab 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <common.h>
 #include <dm.h>
-#include <dm/device_compat.h>
+#include <log.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <dm/uclass-internal.h>
@@ -14,6 +14,7 @@
 #include <fdtdec.h>
 #include <malloc.h>
 #include <asm/gpio.h>
+#include <dm/device_compat.h>
 #include <linux/bug.h>
 #include <linux/ctype.h>
 
@@ -526,6 +527,21 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value)
 
        if (desc->flags & GPIOD_ACTIVE_LOW)
                value = !value;
+
+       /*
+        * Emulate open drain by not actively driving the line high or
+        * Emulate open source by not actively driving the line low
+        */
+       if ((desc->flags & GPIOD_OPEN_DRAIN && value) ||
+           (desc->flags & GPIOD_OPEN_SOURCE && !value))
+               return gpio_get_ops(desc->dev)->direction_input(desc->dev,
+                                                               desc->offset);
+       else if (desc->flags & GPIOD_OPEN_DRAIN ||
+                desc->flags & GPIOD_OPEN_SOURCE)
+               return gpio_get_ops(desc->dev)->direction_output(desc->dev,
+                                                               desc->offset,
+                                                               value);
+
        gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
        return 0;
 }
@@ -572,11 +588,16 @@ static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
                return ret;
        }
 
-       if (flags & GPIOD_IS_OUT) {
-               ret = ops->direction_output(dev, desc->offset,
-                                           GPIOD_FLAGS_OUTPUT(flags));
-       } else if (flags & GPIOD_IS_IN) {
-               ret = ops->direction_input(dev, desc->offset);
+       /* GPIOD_ are directly managed by driver in set_dir_flags*/
+       if (ops->set_dir_flags) {
+               ret = ops->set_dir_flags(dev, desc->offset, flags);
+       } else {
+               if (flags & GPIOD_IS_OUT) {
+                       ret = ops->direction_output(dev, desc->offset,
+                                                   GPIOD_FLAGS_OUTPUT(flags));
+               } else if (flags & GPIOD_IS_IN) {
+                       ret = ops->direction_input(dev, desc->offset);
+               }
        }
 
        return ret;
@@ -1146,6 +1167,8 @@ static int gpio_post_bind(struct udevice *dev)
                        ops->get_function += gd->reloc_off;
                if (ops->xlate)
                        ops->xlate += gd->reloc_off;
+               if (ops->set_dir_flags)
+                       ops->set_dir_flags += gd->reloc_off;
                if (ops->get_dir_flags)
                        ops->get_dir_flags += gd->reloc_off;