dm: test: Add GPIO open drain tests

Add some tests for the new open drain setting feature of the GPIO
uclass, and extend the capabilities of the sandbox GPIO driver
accordingly.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: York Sun <york.sun@nxp.com>
diff --git a/arch/sandbox/include/asm/gpio.h b/arch/sandbox/include/asm/gpio.h
index 8317db1..427af2c 100644
--- a/arch/sandbox/include/asm/gpio.h
+++ b/arch/sandbox/include/asm/gpio.h
@@ -41,6 +41,26 @@
 int sandbox_gpio_set_value(struct udevice *dev, unsigned int offset, int value);
 
 /**
+ * Set or reset the simulated open drain mode of a GPIO (used only in sandbox
+ * test code)
+ *
+ * @param gp	GPIO number
+ * @param value	value to set (0 for enabled open drain mode, non-zero for
+ * 		disabled)
+ * @return -1 on error, 0 if ok
+ */
+int sandbox_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value);
+
+/**
+ * Return the state of the simulated open drain mode of a GPIO (used only in
+ * sandbox test code)
+ *
+ * @param gp	GPIO number
+ * @return -1 on error, 0 if GPIO is input, >0 if output
+ */
+int sandbox_gpio_get_open_drain(struct udevice *dev, unsigned offset);
+
+/**
  * Return the simulated direction of a GPIO (used only in sandbox test code)
  *
  * @param gp	GPIO number
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index a9b1efcd..f6435a0 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -15,6 +15,7 @@
 /* Flags for each GPIO */
 #define GPIOF_OUTPUT	(1 << 0)	/* Currently set as an output */
 #define GPIOF_HIGH	(1 << 1)	/* Currently set high */
+#define GPIOF_ODR	(1 << 2)	/* Currently set to open drain mode */
 
 struct gpio_state {
 	const char *label;	/* label given by requester */
@@ -70,6 +71,16 @@
 	return set_gpio_flag(dev, offset, GPIOF_HIGH, value);
 }
 
+int sandbox_gpio_get_open_drain(struct udevice *dev, unsigned offset)
+{
+	return get_gpio_flag(dev, offset, GPIOF_ODR);
+}
+
+int sandbox_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value)
+{
+	return set_gpio_flag(dev, offset, GPIOF_ODR, value);
+}
+
 int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
 {
 	return get_gpio_flag(dev, offset, GPIOF_OUTPUT);
@@ -124,6 +135,28 @@
 	return sandbox_gpio_set_value(dev, offset, value);
 }
 
+/* read GPIO ODR value of port 'offset' */
+static int sb_gpio_get_open_drain(struct udevice *dev, unsigned offset)
+{
+	debug("%s: offset:%u\n", __func__, offset);
+
+	return sandbox_gpio_get_open_drain(dev, offset);
+}
+
+/* write GPIO ODR value to port 'offset' */
+static int sb_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value)
+{
+	debug("%s: offset:%u, value = %d\n", __func__, offset, value);
+
+	if (!sandbox_gpio_get_direction(dev, offset)) {
+		printf("sandbox_gpio: error: set_open_drain on input gpio %u\n",
+		       offset);
+		return -1;
+	}
+
+	return sandbox_gpio_set_open_drain(dev, offset, value);
+}
+
 static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
 {
 	if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
@@ -154,6 +187,8 @@
 	.direction_output	= sb_gpio_direction_output,
 	.get_value		= sb_gpio_get_value,
 	.set_value		= sb_gpio_set_value,
+	.get_open_drain		= sb_gpio_get_open_drain,
+	.set_open_drain		= sb_gpio_set_open_drain,
 	.get_function		= sb_gpio_get_function,
 	.xlate			= sb_gpio_xlate,
 };
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index 727db18..b994523 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -75,6 +75,13 @@
 	ut_assertok(ops->set_value(dev, offset, 1));
 	ut_asserteq(1, ops->get_value(dev, offset));
 
+	/* Make it an open drain output, and reset it */
+	ut_asserteq(0, sandbox_gpio_get_open_drain(dev, offset));
+	ut_assertok(ops->set_open_drain(dev, offset, 1));
+	ut_asserteq(1, sandbox_gpio_get_open_drain(dev, offset));
+	ut_assertok(ops->set_open_drain(dev, offset, 0));
+	ut_asserteq(0, sandbox_gpio_get_open_drain(dev, offset));
+
 	/* Make it an input */
 	ut_assertok(ops->direction_input(dev, offset));
 	ut_assertok(gpio_get_status(dev, offset, buf, sizeof(buf)));