diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 255700ab18d2d93cf107fcbf3b5a10b2e66e855f..2f3c36b48ff652d4f81a169a67f97c6a45acfab5 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -13,14 +13,16 @@
 
 /**
  * gpio_to_device() - Convert global GPIO number to device, number
- * gpio:	The numeric representation of the GPIO
  *
  * Convert the GPIO number to an entry in the list of GPIOs
  * or GPIO blocks registered with the GPIO controller. Returns
  * entry on success, NULL on error.
+ *
+ * @gpio:	The numeric representation of the GPIO
+ * @desc:	Returns description (desc->flags will always be 0)
+ * @return 0 if found, -ENOENT if not found
  */
-static int gpio_to_device(unsigned int gpio, struct udevice **devp,
-			  unsigned int *offset)
+static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
 {
 	struct gpio_dev_priv *uc_priv;
 	struct udevice *dev;
@@ -32,14 +34,15 @@ static int gpio_to_device(unsigned int gpio, struct udevice **devp,
 		uc_priv = dev->uclass_priv;
 		if (gpio >= uc_priv->gpio_base &&
 		    gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
-			*devp = dev;
-			*offset = gpio - uc_priv->gpio_base;
+			desc->dev = dev;
+			desc->offset = gpio - uc_priv->gpio_base;
+			desc->flags = 0;
 			return 0;
 		}
 	}
 
 	/* No such GPIO */
-	return ret ? ret : -EINVAL;
+	return ret ? ret : -ENOENT;
 }
 
 int gpio_lookup_name(const char *name, struct udevice **devp,
@@ -88,6 +91,31 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
 	return 0;
 }
 
+static int dm_gpio_request(struct gpio_desc *desc, const char *label)
+{
+	struct udevice *dev = desc->dev;
+	struct gpio_dev_priv *uc_priv;
+	char *str;
+	int ret;
+
+	uc_priv = dev->uclass_priv;
+	if (uc_priv->name[desc->offset])
+		return -EBUSY;
+	str = strdup(label);
+	if (!str)
+		return -ENOMEM;
+	if (gpio_get_ops(dev)->request) {
+		ret = gpio_get_ops(dev)->request(dev, desc->offset, label);
+		if (ret) {
+			free(str);
+			return ret;
+		}
+	}
+	uc_priv->name[desc->offset] = str;
+
+	return 0;
+}
+
 /**
  * gpio_request() - [COMPAT] Request GPIO
  * gpio:	GPIO number
@@ -102,32 +130,14 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
  */
 int gpio_request(unsigned gpio, const char *label)
 {
-	struct gpio_dev_priv *uc_priv;
-	unsigned int offset;
-	struct udevice *dev;
-	char *str;
+	struct gpio_desc desc;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
 
-	uc_priv = dev->uclass_priv;
-	if (uc_priv->name[offset])
-		return -EBUSY;
-	str = strdup(label);
-	if (!str)
-		return -ENOMEM;
-	if (gpio_get_ops(dev)->request) {
-		ret = gpio_get_ops(dev)->request(dev, offset, label);
-		if (ret) {
-			free(str);
-			return ret;
-		}
-	}
-	uc_priv->name[offset] = str;
-
-	return 0;
+	return dm_gpio_request(&desc, label);
 }
 
 /**
@@ -151,25 +161,11 @@ int gpio_requestf(unsigned gpio, const char *fmt, ...)
 	return gpio_request(gpio, buf);
 }
 
-/**
- * gpio_free() - [COMPAT] Relinquish GPIO
- * gpio:	GPIO number
- *
- * This function implements the API that's compatible with current
- * GPIO API used in U-Boot. The request is forwarded to particular
- * GPIO driver. Returns 0 on success, negative value on error.
- */
-int gpio_free(unsigned gpio)
+int _dm_gpio_free(struct udevice *dev, uint offset)
 {
 	struct gpio_dev_priv *uc_priv;
-	unsigned int offset;
-	struct udevice *dev;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
-	if (ret)
-		return ret;
-
 	uc_priv = dev->uclass_priv;
 	if (!uc_priv->name[offset])
 		return -ENXIO;
@@ -185,15 +181,35 @@ int gpio_free(unsigned gpio)
 	return 0;
 }
 
-static int check_reserved(struct udevice *dev, unsigned offset,
-			  const char *func)
+/**
+ * gpio_free() - [COMPAT] Relinquish GPIO
+ * gpio:	GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_free(unsigned gpio)
 {
-	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+	struct gpio_desc desc;
+	int ret;
+
+	ret = gpio_to_device(gpio, &desc);
+	if (ret)
+		return ret;
+
+	return _dm_gpio_free(desc.dev, desc.offset);
+}
 
-	if (!uc_priv->name[offset]) {
+static int check_reserved(struct gpio_desc *desc, const char *func)
+{
+	struct gpio_dev_priv *uc_priv = desc->dev->uclass_priv;
+
+	if (!uc_priv->name[desc->offset]) {
 		printf("%s: %s: error: gpio %s%d not reserved\n",
-		       dev->name, func,
-		       uc_priv->bank_name ? uc_priv->bank_name : "", offset);
+		       desc->dev->name, func,
+		       uc_priv->bank_name ? uc_priv->bank_name : "",
+		       desc->offset);
 		return -EBUSY;
 	}
 
@@ -210,16 +226,17 @@ static int check_reserved(struct udevice *dev, unsigned offset,
  */
 int gpio_direction_input(unsigned gpio)
 {
-	unsigned int offset;
-	struct udevice *dev;
+	struct gpio_desc desc;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	ret = gpio_to_device(gpio, &desc);
+	if (ret)
+		return ret;
+	ret = check_reserved(&desc, "dir_input");
 	if (ret)
 		return ret;
-	ret = check_reserved(dev, offset, "dir_input");
 
-	return ret ? ret : gpio_get_ops(dev)->direction_input(dev, offset);
+	return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset);
 }
 
 /**
@@ -233,17 +250,81 @@ int gpio_direction_input(unsigned gpio)
  */
 int gpio_direction_output(unsigned gpio, int value)
 {
-	unsigned int offset;
-	struct udevice *dev;
+	struct gpio_desc desc;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	ret = gpio_to_device(gpio, &desc);
+	if (ret)
+		return ret;
+	ret = check_reserved(&desc, "dir_output");
+	if (ret)
+		return ret;
+
+	return gpio_get_ops(desc.dev)->direction_output(desc.dev,
+							desc.offset, value);
+}
+
+int dm_gpio_get_value(struct gpio_desc *desc)
+{
+	int value;
+	int ret;
+
+	ret = check_reserved(desc, "get_value");
 	if (ret)
 		return ret;
-	ret = check_reserved(dev, offset, "dir_output");
 
-	return ret ? ret :
-		gpio_get_ops(dev)->direction_output(dev, offset, value);
+	value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
+
+	return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
+}
+
+int dm_gpio_set_value(struct gpio_desc *desc, int value)
+{
+	int ret;
+
+	ret = check_reserved(desc, "set_value");
+	if (ret)
+		return ret;
+
+	if (desc->flags & GPIOD_ACTIVE_LOW)
+		value = !value;
+	gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
+	return 0;
+}
+
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+{
+	struct udevice *dev = desc->dev;
+	struct dm_gpio_ops *ops = gpio_get_ops(dev);
+	int ret;
+
+	ret = check_reserved(desc, "set_dir");
+	if (ret)
+		return ret;
+
+	if (flags & GPIOD_IS_OUT) {
+		int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
+
+		if (flags & GPIOD_ACTIVE_LOW)
+			value = !value;
+		ret = ops->direction_output(dev, desc->offset, value);
+	} else  if (flags & GPIOD_IS_IN) {
+		ret = ops->direction_input(dev, desc->offset);
+	}
+	if (ret)
+		return ret;
+	/*
+	 * Update desc->flags here, so that GPIO_ACTIVE_LOW is honoured in
+	 * futures
+	 */
+	desc->flags = flags;
+
+	return 0;
+}
+
+int dm_gpio_set_dir(struct gpio_desc *desc)
+{
+	return dm_gpio_set_dir_flags(desc, desc->flags);
 }
 
 /**
@@ -257,16 +338,14 @@ int gpio_direction_output(unsigned gpio, int value)
  */
 int gpio_get_value(unsigned gpio)
 {
-	unsigned int offset;
-	struct udevice *dev;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	struct gpio_desc desc;
+
+	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
-	ret = check_reserved(dev, offset, "get_value");
-
-	return ret ? ret : gpio_get_ops(dev)->get_value(dev, offset);
+	return dm_gpio_get_value(&desc);
 }
 
 /**
@@ -280,16 +359,13 @@ int gpio_get_value(unsigned gpio)
  */
 int gpio_set_value(unsigned gpio, int value)
 {
-	unsigned int offset;
-	struct udevice *dev;
+	struct gpio_desc desc;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
-	ret = check_reserved(dev, offset, "set_value");
-
-	return ret ? ret : gpio_get_ops(dev)->set_value(dev, offset, value);
+	return dm_gpio_set_value(&desc, value);
 }
 
 const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 36a36c64b8a6a19879e5236eb85af2fd5960a43d..a827a56f5e11679002caeb0ec48e1052d357aa15 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -95,6 +95,22 @@ enum gpio_func_t {
 
 struct udevice;
 
+struct gpio_desc {
+	struct udevice *dev;	/* Device, NULL for invalid GPIO */
+	unsigned long flags;
+#define GPIOD_REQUESTED		(1 << 0)	/* Requested/claimed */
+#define GPIOD_IS_OUT		(1 << 1)	/* GPIO is an output */
+#define GPIOD_IS_IN		(1 << 2)	/* GPIO is an output */
+#define GPIOD_ACTIVE_LOW	(1 << 3)	/* value has active low */
+#define GPIOD_IS_OUT_ACTIVE	(1 << 4)	/* set output active */
+
+	uint offset;		/* GPIO offset within the device */
+	/*
+	 * We could consider adding the GPIO label in here. Possibly we could
+	 * use this structure for internal GPIO information.
+	 */
+};
+
 /**
  * gpio_get_status() - get the current GPIO status as a string
  *