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