gpio: emulate open drain & open source in dm_gpio_set_value()

Handle the GPIOD_OPEN_DRAIN & GPIOD_OPEN_SOURCE flags to emulate open drain
and open source by setting the GPIO line as input depending on the
requested value.

The behaviour is taken from the Linux gpiolib.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 757ab71..d3cea11 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -526,6 +526,21 @@
 
 	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;
 }