This commit manages the flags that can be used in GPIO specifiers to
indicate if a pull-up resistor or pull-down resistor should be
enabled for output GPIO and the Open Drain/Open Source configuration
for input GPIO.

It is managed in driver with a new ops in gpio uclass set_config.

These flags are already support in Linux kernel in gpiolib.

Signed-off-by: Patrick Delaunay <patrick.delau...@st.com>
---

 drivers/gpio/gpio-uclass.c | 62 +++++++++++++++++++++++++++++++++++++-
 include/asm-generic/gpio.h | 56 ++++++++++++++++++++++++++++++++++
 2 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 90fbed455b..c6c6e8b343 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -128,7 +128,19 @@ int gpio_xlate_offs_flags(struct udevice *dev, struct 
gpio_desc *desc,
                return 0;
 
        if (args->args[1] & GPIO_ACTIVE_LOW)
-               desc->flags = GPIOD_ACTIVE_LOW;
+               desc->flags |= GPIOD_ACTIVE_LOW;
+
+       if ((args->args[1] & GPIO_OPEN_DRAIN) == GPIO_OPEN_DRAIN)
+               desc->flags |= GPIOD_OPEN_DRAIN;
+
+       if ((args->args[1] & GPIO_OPEN_SOURCE) == GPIO_OPEN_SOURCE)
+               desc->flags |= GPIOD_OPEN_SOURCE;
+
+       if (args->args[1] & GPIO_PULL_UP)
+               desc->flags |= GPIOD_PULL_UP;
+
+       if (args->args[1] & GPIO_PULL_DOWN)
+               desc->flags |= GPIOD_PULL_DOWN;
 
        return 0;
 }
@@ -517,12 +529,31 @@ int dm_gpio_set_open_drain(struct gpio_desc *desc, int 
value)
 
        if (ops->set_open_drain)
                ret = ops->set_open_drain(desc->dev, desc->offset, value);
+       else if (ops->set_config)
+               ret = ops->set_config(desc->dev, desc->offset,
+                                     value ? GPIO_CONF_DRIVE_OPEN_DRAIN :
+                                             GPIO_CONF_DRIVE_PULL_PUSH);
        else
                return 0; /* feature not supported -> ignore setting */
 
        return ret;
 }
 
+int gpio_get_config(const struct gpio_desc *desc)
+{
+       struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
+       int ret;
+
+       ret = check_reserved(desc, "get_config");
+       if (ret)
+               return ret;
+
+       if (ops->set_config)
+               return ops->get_config(desc->dev, desc->offset);
+       else
+               return -ENOSYS;
+}
+
 int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
 {
        struct udevice *dev = desc->dev;
@@ -533,14 +564,39 @@ int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong 
flags)
        if (ret)
                return ret;
 
+       /* both pull-up and pull-down enabled, invalid configuration */
+       if ((flags & GPIOD_PULL_UP) && (flags & GPIOD_PULL_DOWN))
+               return -EINVAL;
+
        if (flags & GPIOD_IS_OUT) {
                int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
 
+               if (ops->set_config) {
+                       if (flags & GPIOD_OPEN_DRAIN)
+                               ops->set_config(dev, desc->offset,
+                                               GPIO_CONF_DRIVE_OPEN_DRAIN);
+                       else if (flags & GPIOD_OPEN_SOURCE)
+                               ops->set_config(dev, desc->offset,
+                                               GPIO_CONF_DRIVE_OPEN_SOURCE);
+                       else
+                               ops->set_config(dev, desc->offset,
+                                               GPIO_CONF_DRIVE_PULL_PUSH);
+               }
+
                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 (ops->set_config) {
+                       if (flags & GPIOD_PULL_UP)
+                               ops->set_config(dev, desc->offset,
+                                               GPIO_CONF_BIAS_PULL_UP);
+                       else if (flags & GPIOD_PULL_DOWN)
+                               ops->set_config(dev, desc->offset,
+                                               GPIO_CONF_BIAS_PULL_DOWN);
+               }
        }
        if (ret)
                return ret;
@@ -1061,6 +1117,10 @@ 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_config)
+                       ops->set_config += gd->reloc_off;
+               if (ops->get_config)
+                       ops->get_config += gd->reloc_off;
 
                reloc_done++;
        }
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d6cf18744f..9441e7dccc 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -112,6 +112,17 @@ enum gpio_func_t {
        GPIOF_COUNT,
 };
 
+enum gpio_config {
+       GPIO_CONF_NONE,
+       GPIO_CONF_DRIVE_OPEN_DRAIN,
+       GPIO_CONF_DRIVE_OPEN_SOURCE,
+       GPIO_CONF_DRIVE_PULL_PUSH,
+       GPIO_CONF_BIAS_PULL_DOWN,
+       GPIO_CONF_BIAS_PULL_UP,
+
+       GPIO_CONF_COUNT,
+};
+
 struct udevice;
 
 struct gpio_desc {
@@ -122,6 +133,10 @@ struct gpio_desc {
 #define GPIOD_IS_IN            (1 << 2)        /* GPIO is an input */
 #define GPIOD_ACTIVE_LOW       (1 << 3)        /* value has active low */
 #define GPIOD_IS_OUT_ACTIVE    (1 << 4)        /* set output active */
+#define GPIOD_OPEN_DRAIN       (1 << 5)        /* GPIO is open drain type */
+#define GPIOD_OPEN_SOURCE      (1 << 6)        /* GPIO is open source type */
+#define GPIOD_PULL_UP          (1 << 7)        /* GPIO has pull up enabled */
+#define GPIOD_PULL_DOWN                (1 << 8)        /* GPIO has pull down 
enabled */
 
        uint offset;            /* GPIO offset within the device */
        /*
@@ -290,6 +305,36 @@ struct dm_gpio_ops {
         */
        int (*xlate)(struct udevice *dev, struct gpio_desc *desc,
                     struct ofnode_phandle_args *args);
+
+       /**
+        * set_config() - Set GPIO configuration
+        *
+        * This function should set up the GPIO configuration according to the
+        * information in the arguments.
+        *
+        * This method is optional.
+        *
+        * @dev:        GPIO device
+        * @offset:     GPIO offset within that device
+        * @config:     GPIO configuration
+        * @return 0 if OK, -ve on error
+        */
+       int (*set_config)(struct udevice *dev, unsigned offset,
+                         enum gpio_config config);
+
+       /**
+        * set_config() - Set GPIO configuration
+        *
+        * This function return the GPIO configuration according to the
+        * information in the arguments.
+        *
+        * This method is optional.
+        *
+        * @dev:        GPIO device
+        * @offset:     GPIO offset within that device
+        * @return GPIO configuration (GPIO_CONF_) if OK, -ve on error
+        */
+       int (*get_config)(struct udevice *dev, unsigned offset);
 };
 
 /**
@@ -657,4 +702,15 @@ int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong 
flags);
  */
 int gpio_get_number(const struct gpio_desc *desc);
 
+/**
+ * gpio_get_config() - get the current GPIO pin configuration
+ *
+ * Obtain the current GPIO pin configuration
+ *
+ * @desc:      GPIO description containing device, offset and flags,
+ *             previously returned by gpio_request_by_name()
+ * @return GPIO configuration (GPIO_CONF_) if OK, -ve on error
+ */
+int gpio_get_config(const struct gpio_desc *desc);
+
 #endif /* _ASM_GENERIC_GPIO_H_ */
-- 
2.17.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to