From 13979fc44667cbc577f3c4d07b6692de104a3174 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:21:55 -0700 Subject: dm: gpio: Rename set_dir_flags() method to update_flags() The current method is a misnomer since it is also used (e.g. by stm32) to update pull settings and open source/open drain. Rename it and expand the documentation to cover a few more details. Signed-off-by: Simon Glass Reviewed-by: Pratyush Yadav Reviewed-by: Patrick Delaunay --- test/dm/gpio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test/dm/gpio.c') diff --git a/test/dm/gpio.c b/test/dm/gpio.c index d7b85e74ce..36bbaedb01 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -81,12 +81,12 @@ static int dm_test_gpio(struct unit_test_state *uts) /* Make it an open drain output, and reset it */ ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, sandbox_gpio_get_dir_flags(dev, offset)); - ut_assertok(ops->set_dir_flags(dev, offset, - GPIOD_IS_OUT | GPIOD_OPEN_DRAIN)); + ut_assertok(ops->set_flags(dev, offset, + GPIOD_IS_OUT | GPIOD_OPEN_DRAIN)); ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, sandbox_gpio_get_dir_flags(dev, offset)); - ut_assertok(ops->set_dir_flags(dev, offset, - GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE)); + ut_assertok(ops->set_flags(dev, offset, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE)); ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, sandbox_gpio_get_dir_flags(dev, offset)); -- cgit v1.2.3 From c0c1e62c6e47ffccca953c57df4624d685493584 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:21:57 -0700 Subject: gpio: Rename dm_gpio_get_dir_flags() to dm_gpio_get_flags() This function can be used to get any flags, not just direction flags. Rename it to avoid confusion. Signed-off-by: Simon Glass Reviewed-by: Patrick Delaunay Reviewed-by: Pratyush Yadav --- drivers/gpio/gpio-uclass.c | 2 +- include/asm-generic/gpio.h | 6 +++--- test/dm/gpio.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'test/dm/gpio.c') diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 4d15162bc4..42479dba4d 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -683,7 +683,7 @@ int dm_gpio_set_dir(struct gpio_desc *desc) return _dm_gpio_set_flags(desc, desc->flags); } -int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flagsp) +int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp) { struct udevice *dev = desc->dev; int ret, value; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 153312d8af..4f8d1938da 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -683,16 +683,16 @@ int dm_gpio_set_dir(struct gpio_desc *desc); int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags); /** - * dm_gpio_get_dir_flags() - Get direction flags + * dm_gpio_get_flags() - Get flags * - * read the current direction flags + * Read the current flags * * @desc: GPIO description containing device, offset and flags, * previously returned by gpio_request_by_name() * @flags: place to put the used flags * @return 0 if OK, -ve on error, in which case desc->flags is not updated */ -int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags); +int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flags); /** * gpio_get_number() - Get the global GPIO number of a GPIO diff --git a/test/dm/gpio.c b/test/dm/gpio.c index 36bbaedb01..c583d2b344 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -397,22 +397,22 @@ static int dm_test_gpio_get_dir_flags(struct unit_test_state *uts) ut_asserteq(6, gpio_request_list_by_name(dev, "test3-gpios", desc_list, ARRAY_SIZE(desc_list), 0)); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[0], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[0], &flags)); ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[1], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[1], &flags)); ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[2], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[2], &flags)); ut_asserteq(GPIOD_IS_OUT, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[3], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[3], &flags)); ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[4], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[4], &flags)); ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_DOWN, flags); - ut_assertok(dm_gpio_get_dir_flags(&desc_list[5], &flags)); + ut_assertok(dm_gpio_get_flags(&desc_list[5], &flags)); ut_asserteq(GPIOD_IS_IN, flags); ut_assertok(gpio_free_list(dev, desc_list, 6)); -- cgit v1.2.3 From a03a0aa7e833ab6af62728d6c0591b7772ffa9a8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:21:59 -0700 Subject: gpio: sandbox: Rename GPIO dir_flags to flags Adjust the terminology in this driver to reflect that fact that all flags are handled, not just direction flags. Create a new access function to get the full GPIO state, not just the direction flags. Drop the static invalid_dir_flags since we can rely on a segfault if something is wrong. Signed-off-by: Simon Glass Reviewed-by: Patrick Delaunay --- arch/sandbox/include/asm/gpio.h | 8 +++--- drivers/gpio/sandbox.c | 60 +++++++++++++++++++++++------------------ test/dm/gpio.c | 18 ++++++------- 3 files changed, 47 insertions(+), 39 deletions(-) (limited to 'test/dm/gpio.c') diff --git a/arch/sandbox/include/asm/gpio.h b/arch/sandbox/include/asm/gpio.h index df4ba4fb5f..20d7829655 100644 --- a/arch/sandbox/include/asm/gpio.h +++ b/arch/sandbox/include/asm/gpio.h @@ -69,17 +69,17 @@ int sandbox_gpio_set_direction(struct udevice *dev, unsigned int offset, * @param offset GPIO offset within bank * @return dir_flags: bitfield accesses by GPIOD_ defines */ -ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset); +ulong sandbox_gpio_get_flags(struct udevice *dev, unsigned int offset); /** * Set the simulated flags of a GPIO (used only in sandbox test code) * * @param dev device to use * @param offset GPIO offset within bank - * @param flags dir_flags: bitfield accesses by GPIOD_ defines + * @param flags bitfield accesses by GPIOD_ defines * @return -1 on error, 0 if ok */ -int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, - ulong flags); +int sandbox_gpio_set_flags(struct udevice *dev, unsigned int offset, + ulong flags); #endif diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index 38dc34ee91..6f2eed50bf 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -22,34 +22,44 @@ struct gpio_state { const char *label; /* label given by requester */ - ulong dir_flags; /* dir_flags (GPIOD_...) */ + ulong flags; /* flags (GPIOD_...) */ }; -/* Access routines for GPIO dir flags */ -static ulong *get_gpio_dir_flags(struct udevice *dev, unsigned int offset) +/* Access routines for GPIO info */ +static struct gpio_state *get_gpio_state(struct udevice *dev, uint offset) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct gpio_state *state = dev_get_priv(dev); if (offset >= uc_priv->gpio_count) { - static ulong invalid_dir_flags; printf("sandbox_gpio: error: invalid gpio %u\n", offset); - return &invalid_dir_flags; + return NULL; } - return &state[offset].dir_flags; + return &state[offset]; +} + +/* Access routines for GPIO flags */ +static ulong *get_gpio_flags(struct udevice *dev, unsigned int offset) +{ + struct gpio_state *state = get_gpio_state(dev, offset); + + if (!state) + return NULL; + + return &state->flags; } static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag) { - return (*get_gpio_dir_flags(dev, offset) & flag) != 0; + return (*get_gpio_flags(dev, offset) & flag) != 0; } static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag, int value) { - ulong *gpio = get_gpio_dir_flags(dev, offset); + ulong *gpio = get_gpio_flags(dev, offset); if (value) *gpio |= flag; @@ -88,15 +98,14 @@ int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output) return 0; } -ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset) +ulong sandbox_gpio_get_flags(struct udevice *dev, uint offset) { - return *get_gpio_dir_flags(dev, offset); + return *get_gpio_flags(dev, offset); } -int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, - ulong flags) +int sandbox_gpio_set_flags(struct udevice *dev, uint offset, ulong flags) { - *get_gpio_dir_flags(dev, offset) = flags; + *get_gpio_flags(dev, offset) = flags; return 0; } @@ -180,30 +189,29 @@ static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset, ulong flags) { - ulong *dir_flags; + ulong *newf; - debug("%s: offset:%u, dir_flags = %lx\n", __func__, offset, flags); + debug("%s: offset:%u, flags = %lx\n", __func__, offset, flags); - dir_flags = get_gpio_dir_flags(dev, offset); + newf = get_gpio_flags(dev, offset); /* * For testing purposes keep the output value when switching to input. * This allows us to manipulate the input value via the gpio command. */ if (flags & GPIOD_IS_IN) - *dir_flags = (flags & ~GPIOD_IS_OUT_ACTIVE) | - (*dir_flags & GPIOD_IS_OUT_ACTIVE); + *newf = (flags & ~GPIOD_IS_OUT_ACTIVE) | + (*newf & GPIOD_IS_OUT_ACTIVE); else - *dir_flags = flags; + *newf = flags; return 0; } -static int sb_gpio_get_flags(struct udevice *dev, unsigned int offset, - ulong *flagsp) +static int sb_gpio_get_flags(struct udevice *dev, uint offset, ulong *flagsp) { debug("%s: offset:%u\n", __func__, offset); - *flagsp = *get_gpio_dir_flags(dev, offset); + *flagsp = *get_gpio_flags(dev, offset); return 0; } @@ -456,7 +464,7 @@ static const char *sb_pinctrl_get_pin_name(struct udevice *dev, return pin_name; } -static char *get_dir_flags_string(ulong flags) +static char *get_flags_string(ulong flags) { if (flags & GPIOD_OPEN_DRAIN) return "drive-open-drain"; @@ -475,7 +483,7 @@ static int sb_pinctrl_get_pin_muxing(struct udevice *dev, { struct udevice *gpio_dev; unsigned int gpio_idx; - ulong dir_flags; + ulong flags; int function; /* look up for the bank which owns the requested pin */ @@ -484,11 +492,11 @@ static int sb_pinctrl_get_pin_muxing(struct udevice *dev, snprintf(buf, size, "Error"); } else { function = sb_gpio_get_function(gpio_dev, gpio_idx); - dir_flags = *get_gpio_dir_flags(gpio_dev, gpio_idx); + flags = *get_gpio_flags(gpio_dev, gpio_idx); snprintf(buf, size, "gpio %s %s", function == GPIOF_OUTPUT ? "output" : "input", - get_dir_flags_string(dir_flags)); + get_flags_string(flags)); } return 0; diff --git a/test/dm/gpio.c b/test/dm/gpio.c index c583d2b344..dfbb634bf7 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -80,15 +80,15 @@ static int dm_test_gpio(struct unit_test_state *uts) /* Make it an open drain output, and reset it */ ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, - sandbox_gpio_get_dir_flags(dev, offset)); + sandbox_gpio_get_flags(dev, offset)); ut_assertok(ops->set_flags(dev, offset, GPIOD_IS_OUT | GPIOD_OPEN_DRAIN)); ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, - sandbox_gpio_get_dir_flags(dev, offset)); + sandbox_gpio_get_flags(dev, offset)); ut_assertok(ops->set_flags(dev, offset, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE)); ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, - sandbox_gpio_get_dir_flags(dev, offset)); + sandbox_gpio_get_flags(dev, offset)); /* Make it an input */ ut_assertok(ops->direction_input(dev, offset)); @@ -176,7 +176,7 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) /* GPIO 0 is (GPIO_OUT|GPIO_OPEN_DRAIN) */ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, - sandbox_gpio_get_dir_flags(gpio_c, 0)); + sandbox_gpio_get_flags(gpio_c, 0)); /* Set it as output high, should become an input */ ut_assertok(dm_gpio_set_value(&desc_list[0], 1)); @@ -190,7 +190,7 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) /* GPIO 1 is (GPIO_OUT|GPIO_OPEN_SOURCE) */ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, - sandbox_gpio_get_dir_flags(gpio_c, 1)); + sandbox_gpio_get_flags(gpio_c, 1)); /* Set it as output high, should become output high */ ut_assertok(dm_gpio_set_value(&desc_list[1], 1)); @@ -204,7 +204,7 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) /* GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN) */ ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, - sandbox_gpio_get_dir_flags(gpio_c, 6)); + sandbox_gpio_get_flags(gpio_c, 6)); /* Set it as output high, should become output low */ ut_assertok(dm_gpio_set_value(&desc_list[6], 1)); @@ -218,7 +218,7 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) /* GPIO 7 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_SOURCE) */ ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, - sandbox_gpio_get_dir_flags(gpio_c, 7)); + sandbox_gpio_get_flags(gpio_c, 7)); /* Set it as output high, should become an input */ ut_assertok(dm_gpio_set_value(&desc_list[7], 1)); @@ -363,12 +363,12 @@ static int dm_test_gpio_phandles(struct unit_test_state *uts) ut_assertok(gpio_free_list(dev, desc_list, 3)); ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, - sandbox_gpio_get_dir_flags(gpio_a, 1)); + sandbox_gpio_get_flags(gpio_a, 1)); ut_asserteq(6, gpio_request_list_by_name(dev, "test2-gpios", desc_list, ARRAY_SIZE(desc_list), 0)); /* This was set to output previously but flags resetted to 0 = INPUT */ - ut_asserteq(0, sandbox_gpio_get_dir_flags(gpio_a, 1)); + ut_asserteq(0, sandbox_gpio_get_flags(gpio_a, 1)); ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_a, 1, NULL)); /* Active low should invert the input value */ -- cgit v1.2.3 From 7e0a96d559da493812220731535f5ba6351bcea1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:22:03 -0700 Subject: dm: gpio: Add a way to update flags It is convenient to be able to adjust some of the flags for a GPIO while leaving others alone. Add a function for this. Update dm_gpio_set_dir_flags() to make use of this. Also update dm_gpio_set_value() to use this also, since this allows the open-drain / open-source features to be implemented directly in the driver, rather than using the uclass workaround. Update the sandbox tests accordingly. This involves a lot of changes to dm_test_gpio_opendrain_opensource() since we no-longer have the direciion being reported differently depending on the open drain/open source flags. Also update the STM32 drivers to let the uclass handle the active low/high logic. Drop the GPIOD_FLAGS_OUTPUT() macro which is no-longer used. Signed-off-by: Simon Glass Tested-by: Kory Maincent Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay Reviewed-by: Patrick Delaunay Tested-by: Patrick Delaunay --- drivers/gpio/gpio-uclass.c | 75 +++++++++++++++++------ drivers/gpio/stm32_gpio.c | 3 +- drivers/pinctrl/pinctrl-stmfx.c | 5 +- include/asm-generic/gpio.h | 31 ++++++++-- test/dm/gpio.c | 132 ++++++++++++++++++++++++++++++++++------ 5 files changed, 203 insertions(+), 43 deletions(-) (limited to 'test/dm/gpio.c') diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 42479dba4d..eb8850dfe5 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -569,6 +569,7 @@ int dm_gpio_get_value(const struct gpio_desc *desc) int dm_gpio_set_value(const struct gpio_desc *desc, int value) { + const struct dm_gpio_ops *ops; int ret; ret = check_reserved(desc, "set_value"); @@ -578,21 +579,33 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value) if (desc->flags & GPIOD_ACTIVE_LOW) value = !value; + /* GPIOD_ are directly managed by driver in set_flags */ + ops = gpio_get_ops(desc->dev); + if (ops->set_flags) { + ulong flags = desc->flags; + + if (value) + flags |= GPIOD_IS_OUT_ACTIVE; + else + flags &= ~GPIOD_IS_OUT_ACTIVE; + return ops->set_flags(desc->dev, desc->offset, flags); + } + /* * 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); + return ops->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); + return ops->direction_output(desc->dev, desc->offset, value); + + ret = ops->set_value(desc->dev, desc->offset, value); + if (ret) + return ret; - gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value); return 0; } @@ -620,6 +633,17 @@ static int check_dir_flags(ulong flags) return 0; } +/** + * _dm_gpio_set_flags() - Send flags to the driver + * + * This uses the best available method to send the given flags to the driver. + * Note that if flags & GPIOD_ACTIVE_LOW, the driver sees the opposite value + * of GPIOD_IS_OUT_ACTIVE. + * + * @desc: GPIO description + * @flags: flags value to set + * @return 0 if OK, -ve on error + */ static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags) { struct udevice *dev = desc->dev; @@ -638,38 +662,52 @@ static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags) return ret; } + /* If active low, invert the output state */ + if ((flags & (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)) == + (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)) + flags ^= GPIOD_IS_OUT_ACTIVE; + /* GPIOD_ are directly managed by driver in set_flags */ if (ops->set_flags) { ret = ops->set_flags(dev, desc->offset, flags); } else { if (flags & GPIOD_IS_OUT) { - ret = ops->direction_output(dev, desc->offset, - GPIOD_FLAGS_OUTPUT(flags)); + bool value = flags & GPIOD_IS_OUT_ACTIVE; + + ret = ops->direction_output(dev, desc->offset, value); } else if (flags & GPIOD_IS_IN) { ret = ops->direction_input(dev, desc->offset); } } - /* save the flags also in descriptor */ - if (!ret) - desc->flags = flags; - return ret; } -int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) +int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set) { + ulong flags; int ret; ret = check_reserved(desc, "set_dir_flags"); if (ret) return ret; - /* combine the requested flags (for IN/OUT) and the descriptor flags */ - flags |= desc->flags; + flags = (desc->flags & ~clr) | set; + ret = _dm_gpio_set_flags(desc, flags); + if (ret) + return ret; - return ret; + /* save the flags also in descriptor */ + desc->flags = flags; + + return 0; +} + +int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) +{ + /* combine the requested flags (for IN/OUT) and the descriptor flags */ + return dm_gpio_clrset_flags(desc, GPIOD_MASK_DIR, flags); } int dm_gpio_set_dir(struct gpio_desc *desc) @@ -1011,7 +1049,10 @@ static int gpio_request_tail(int ret, const char *nodename, debug("%s: dm_gpio_requestf failed\n", __func__); goto err; } - ret = dm_gpio_set_dir_flags(desc, flags); + + /* Keep any direction flags provided by the devicetree */ + ret = dm_gpio_set_dir_flags(desc, + flags | (desc->flags & GPIOD_MASK_DIR)); if (ret) { debug("%s: dm_gpio_set_dir failed\n", __func__); goto err; diff --git a/drivers/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index c2d7046c0d..125c237551 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -203,12 +203,13 @@ static int stm32_gpio_set_flags(struct udevice *dev, unsigned int offset, return idx; if (flags & GPIOD_IS_OUT) { - int value = GPIOD_FLAGS_OUTPUT(flags); + bool value = flags & GPIOD_IS_OUT_ACTIVE; if (flags & GPIOD_OPEN_DRAIN) stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_OD); else stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_PP); + stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT); writel(BSRR_BIT(idx, value), ®s->bsrr); diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 6ba56a16a3..fe7a59d431 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -169,6 +169,8 @@ static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset, int ret = -ENOTSUPP; if (flags & GPIOD_IS_OUT) { + bool value = flags & GPIOD_IS_OUT_ACTIVE; + if (flags & GPIOD_OPEN_SOURCE) return -ENOTSUPP; if (flags & GPIOD_OPEN_DRAIN) @@ -177,8 +179,7 @@ static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset, ret = stmfx_conf_set_type(dev, offset, 1); if (ret) return ret; - ret = stmfx_gpio_direction_output(dev, offset, - GPIOD_FLAGS_OUTPUT(flags)); + ret = stmfx_gpio_direction_output(dev, offset, value); } else if (flags & GPIOD_IS_IN) { ret = stmfx_gpio_direction_input(dev, offset); if (ret) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 4f8d1938da..7d1e19ad53 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -128,6 +128,12 @@ struct gpio_desc { #define GPIOD_PULL_UP BIT(7) /* GPIO has pull-up enabled */ #define GPIOD_PULL_DOWN BIT(8) /* GPIO has pull-down enabled */ +/* Flags for updating the above */ +#define GPIOD_MASK_DIR (GPIOD_IS_OUT | GPIOD_IS_IN | \ + GPIOD_IS_OUT_ACTIVE) +#define GPIOD_MASK_DSTYPE (GPIOD_OPEN_DRAIN | GPIOD_OPEN_SOURCE) +#define GPIOD_MASK_PULL (GPIOD_PULL_UP | GPIOD_PULL_DOWN) + uint offset; /* GPIO offset within the device */ /* * We could consider adding the GPIO label in here. Possibly we could @@ -135,12 +141,6 @@ struct gpio_desc { */ }; -/* helper to compute the value of the gpio output */ -#define GPIOD_FLAGS_OUTPUT_MASK (GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE) -#define GPIOD_FLAGS_OUTPUT(flags) \ - (((((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_IS_OUT_ACTIVE) || \ - (((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_ACTIVE_LOW))) - /** * dm_gpio_is_valid() - Check if a GPIO is valid * @@ -668,6 +668,25 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value); */ int dm_gpio_set_dir(struct gpio_desc *desc); +/** + * dm_gpio_clrset_flags() - Update flags + * + * This updates the flags as directled. Note that desc->flags is updated by this + * function on success. If any changes cannot be made, best efforts are made. + * + * By use of @clr and @set any of flags can be individually updated, or left + * alone + * + * @desc: GPIO description containing device, offset and flags, + * previously returned by gpio_request_by_name() + * @clr: Flags to clear (GPIOD_...) + * @set: Flags to set (GPIOD_...) + * @return 0 if OK, -EINVAL if the flags had obvious conflicts, + * -ERECALLCONFLICT if there was a non-obvious hardware conflict when attempting + * to set the flags + */ +int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set); + /** * dm_gpio_set_dir_flags() - Set direction using description and added flags * diff --git a/test/dm/gpio.c b/test/dm/gpio.c index dfbb634bf7..be5da95304 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -178,15 +178,15 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, sandbox_gpio_get_flags(gpio_c, 0)); - /* Set it as output high, should become an input */ + /* Set it as output high */ ut_assertok(dm_gpio_set_value(&desc_list[0], 1)); - ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf))); - ut_asserteq_str("c0: input: 0 [x] a-test.test3-gpios0", buf); + ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN | GPIOD_IS_OUT_ACTIVE, + sandbox_gpio_get_flags(gpio_c, 0)); - /* Set it as output low, should become output low */ + /* Set it as output low */ ut_assertok(dm_gpio_set_value(&desc_list[0], 0)); - ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf))); - ut_asserteq_str("c0: output: 0 [x] a-test.test3-gpios0", buf); + ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, + sandbox_gpio_get_flags(gpio_c, 0)); /* GPIO 1 is (GPIO_OUT|GPIO_OPEN_SOURCE) */ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, @@ -197,13 +197,21 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf))); ut_asserteq_str("c1: output: 1 [x] a-test.test3-gpios1", buf); - /* Set it as output low, should become an input */ + /* Set it as output low */ ut_assertok(dm_gpio_set_value(&desc_list[1], 0)); + ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, + sandbox_gpio_get_flags(gpio_c, 1)); + ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf))); - ut_asserteq_str("c1: input: 1 [x] a-test.test3-gpios1", buf); + ut_asserteq_str("c1: output: 0 [x] a-test.test3-gpios1", buf); - /* GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN) */ - ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, + /* + * GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN). Looking at it + * directlt from the driver, we get GPIOD_IS_OUT_ACTIVE also, since it + * is active low + */ + ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN | + GPIOD_IS_OUT_ACTIVE, sandbox_gpio_get_flags(gpio_c, 6)); /* Set it as output high, should become output low */ @@ -211,19 +219,21 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts) ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf))); ut_asserteq_str("c6: output: 0 [x] a-test.test3-gpios6", buf); - /* Set it as output low, should become an input */ + /* Set it as output low */ ut_assertok(dm_gpio_set_value(&desc_list[6], 0)); - ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf))); - ut_asserteq_str("c6: input: 0 [x] a-test.test3-gpios6", buf); + ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN | + GPIOD_IS_OUT_ACTIVE, + sandbox_gpio_get_flags(gpio_c, 6)); /* GPIO 7 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_SOURCE) */ - ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, + ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE | + GPIOD_IS_OUT_ACTIVE, sandbox_gpio_get_flags(gpio_c, 7)); - /* Set it as output high, should become an input */ + /* Set it as output high */ ut_assertok(dm_gpio_set_value(&desc_list[7], 1)); - ut_assertok(gpio_get_status(gpio_c, 7, buf, sizeof(buf))); - ut_asserteq_str("c7: input: 0 [x] a-test.test3-gpios7", buf); + ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, + sandbox_gpio_get_flags(gpio_c, 7)); /* Set it as output low, should become output high */ ut_assertok(dm_gpio_set_value(&desc_list[7], 0)); @@ -582,3 +592,91 @@ static int dm_test_gpio_devm(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_gpio_devm, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int dm_test_clrset_flags(struct unit_test_state *uts) +{ + struct gpio_desc desc; + struct udevice *dev; + ulong flags; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, 0)); + + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_OUT)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_OUT, flags); + ut_asserteq(GPIOD_IS_OUT, desc.flags); + ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset)); + + ut_assertok(dm_gpio_clrset_flags(&desc, 0, GPIOD_IS_OUT_ACTIVE)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, flags); + ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, desc.flags); + ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset)); + ut_asserteq(1, dm_gpio_get_value(&desc)); + + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_IN, flags & GPIOD_MASK_DIR); + ut_asserteq(GPIOD_IS_IN, desc.flags & GPIOD_MASK_DIR); + + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_PULL, + GPIOD_PULL_UP)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags); + ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, desc.flags); + + /* Check we cannot set both PULL_UP and PULL_DOWN */ + ut_asserteq(-EINVAL, dm_gpio_clrset_flags(&desc, 0, GPIOD_PULL_DOWN)); + + return 0; +} +DM_TEST(dm_test_clrset_flags, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Check that an active-low GPIO works as expected */ +static int dm_test_clrset_flags_invert(struct unit_test_state *uts) +{ + struct gpio_desc desc; + struct udevice *dev; + ulong flags; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)); + + /* + * From this size we see it as 0 (active low), but the sandbox driver + * sees the pin value high + */ + ut_asserteq(0, dm_gpio_get_value(&desc)); + ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset)); + + ut_assertok(dm_gpio_set_value(&desc, 1)); + ut_asserteq(1, dm_gpio_get_value(&desc)); + ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset)); + + /* Do the same with dm_gpio_clrset_flags() */ + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_OUT_ACTIVE, 0)); + ut_asserteq(0, dm_gpio_get_value(&desc)); + ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset)); + + ut_assertok(dm_gpio_clrset_flags(&desc, 0, GPIOD_IS_OUT_ACTIVE)); + ut_asserteq(1, dm_gpio_get_value(&desc)); + ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset)); + + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE, + flags); + ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE, + desc.flags); + + ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_OUT_ACTIVE, 0)); + ut_assertok(dm_gpio_get_flags(&desc, &flags)); + ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW, flags); + ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW, desc.flags); + + return 0; +} +DM_TEST(dm_test_clrset_flags_invert, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From 8a45b2205749252f61d26508d5de9dcce020b2ef Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Feb 2021 21:22:09 -0700 Subject: gpio: Add a way to read 3-way strapping pins Using the internal vs. external pull resistors it is possible to get 27 different combinations from 3 strapping pins. Add an implementation of this. This involves updating the sandbox GPIO driver to model external and (weaker) internal pull resistors. The get_value() method now takes account of what is driving a pin: sandbox: GPIOD_EXT_DRIVEN - in which case GPIO_EXT_HIGH provides the value outside source - in which case GPIO_EXT_PULL_UP/DOWN indicates the external state and we work the final state using those flags and the internal GPIOD_PULL_UP/DOWN flags Of course the outside source does not really exist in sandbox. We are just modelling it for test purpose. Signed-off-by: Simon Glass --- arch/sandbox/include/asm/gpio.h | 5 ++- drivers/gpio/gpio-uclass.c | 81 ++++++++++++++++++++++++++++++++++ drivers/gpio/sandbox.c | 13 ++++-- include/asm-generic/gpio.h | 40 +++++++++++++++++ test/dm/gpio.c | 98 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 232 insertions(+), 5 deletions(-) (limited to 'test/dm/gpio.c') diff --git a/arch/sandbox/include/asm/gpio.h b/arch/sandbox/include/asm/gpio.h index 33b83ea4cc..9e10052667 100644 --- a/arch/sandbox/include/asm/gpio.h +++ b/arch/sandbox/include/asm/gpio.h @@ -26,8 +26,11 @@ /* Our own private GPIO flags, which musn't conflict with GPIOD_... */ #define GPIOD_EXT_HIGH BIT(31) /* external source is high (else low) */ #define GPIOD_EXT_DRIVEN BIT(30) /* external source is driven */ +#define GPIOD_EXT_PULL_UP BIT(29) /* GPIO has external pull-up */ +#define GPIOD_EXT_PULL_DOWN BIT(28) /* GPIO has external pull-down */ -#define GPIOD_SANDBOX_MASK GENMASK(31, 30) +#define GPIOD_EXT_PULL (BIT(28) | BIT(29)) +#define GPIOD_SANDBOX_MASK GENMASK(31, 28) /** * Return the simulated value of a GPIO (used only in sandbox test code) diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 729e41033b..f24db87ef0 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -23,6 +23,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -723,6 +724,21 @@ int dm_gpio_set_dir(struct gpio_desc *desc) return _dm_gpio_set_flags(desc, desc->flags); } +int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr, + ulong set) +{ + int ret; + int i; + + for (i = 0; i < count; i++) { + ret = dm_gpio_clrset_flags(&desc[i], clr, set); + if (ret) + return log_ret(ret); + } + + return 0; +} + int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp) { struct udevice *dev = desc->dev; @@ -989,6 +1005,71 @@ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count) return vector; } +int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list, + int count) +{ + static const char tristate[] = "01z"; + enum { + PULLUP, + PULLDOWN, + + NUM_OPTIONS, + }; + int vals[NUM_OPTIONS]; + uint mask; + uint vector = 0; + int ret, i; + + /* + * Limit to 19 digits which should be plenty. This avoids overflow of a + * 32-bit int + */ + assert(count < 20); + + for (i = 0; i < NUM_OPTIONS; i++) { + uint flags = GPIOD_IS_IN; + + flags |= (i == PULLDOWN) ? GPIOD_PULL_DOWN : GPIOD_PULL_UP; + ret = dm_gpios_clrset_flags(desc_list, count, GPIOD_MASK_PULL, + flags); + if (ret) + return log_msg_ret("pu", ret); + + /* Give the lines time to settle */ + udelay(10); + + ret = dm_gpio_get_values_as_int(desc_list, count); + if (ret < 0) + return log_msg_ret("get1", ret); + vals[i] = ret; + } + + log_debug("values: %x %x, count = %d\n", vals[0], vals[1], count); + for (i = count - 1, mask = 1 << i; i >= 0; i--, mask >>= 1) { + uint pd = vals[PULLDOWN] & mask ? 1 : 0; + uint pu = vals[PULLUP] & mask ? 1 : 0; + uint digit; + + /* + * Get value with internal pulldown active. If this is 1 then + * there is a stronger external pullup, which we call 1. If not + * then call it 0. + * + * If the values differ then the pin is floating so we call + * this a 2. + */ + if (pu == pd) + digit = pd; + else + digit = 2; + log_debug("%c ", tristate[digit]); + vector = 3 * vector + digit; + } + log_debug("vector=%d\n", vector); + + return vector; +} + /** * gpio_request_tail: common work for requesting a gpio. * diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index 700098446b..d008fdd222 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -19,7 +19,6 @@ #include #include - struct gpio_state { const char *label; /* label given by requester */ ulong flags; /* flags (GPIOD_...) */ @@ -81,10 +80,16 @@ int sandbox_gpio_get_value(struct udevice *dev, unsigned offset) if (get_gpio_flag(dev, offset, GPIOD_IS_OUT)) debug("sandbox_gpio: get_value on output gpio %u\n", offset); - if (state->flags & GPIOD_EXT_DRIVEN) + if (state->flags & GPIOD_EXT_DRIVEN) { val = state->flags & GPIOD_EXT_HIGH; - else - val = false; + } else { + if (state->flags & GPIOD_EXT_PULL_UP) + val = true; + else if (state->flags & GPIOD_EXT_PULL_DOWN) + val = false; + else + val = state->flags & GPIOD_PULL_UP; + } return val; } diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index f0c835e60b..2cb0500aec 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -497,6 +497,31 @@ int gpio_get_values_as_int(const int *gpio_list); */ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count); +/** + * dm_gpio_get_values_as_int_base3() - Create a base-3 int from a list of GPIOs + * + * This uses pull-ups/pull-downs to figure out whether a GPIO line is externally + * pulled down, pulled up or floating. This allows three different strap values + * for each pin: + * 0 : external pull-down + * 1 : external pull-up + * 2 : floating + * + * With this it is possible to obtain more combinations from the same number of + * strapping pins, when compared to dm_gpio_get_values_as_int(). The external + * pull resistors should be made stronger that the internal SoC pull resistors, + * for this to work. + * + * With 2 pins, 6 combinations are possible, compared with 4 + * With 3 pins, 27 are possible, compared with 8 + * + * @desc_list: List of GPIOs to collect + * @count: Number of GPIOs + * @return resulting integer value, or -ve on error + */ +int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list, + int count); + /** * gpio_claim_vector() - claim a number of GPIOs for input * @@ -725,6 +750,21 @@ int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set); */ int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags); +/** + * dm_gpios_clrset_flags() - Sets flags for a set of GPIOs + * + * This clears and sets flags individually for each GPIO. + * + * @desc: List of GPIOs to update + * @count: Number of GPIOs in the list + * @clr: Flags to clear (GPIOD_...), e.g. GPIOD_MASK_DIR if you are + * changing the direction + * @set: Flags to set (GPIOD_...) + * @return 0 if OK, -ve on error + */ +int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr, + ulong set); + /** * dm_gpio_get_flags() - Get flags * diff --git a/test/dm/gpio.c b/test/dm/gpio.c index be5da95304..33ae98701f 100644 --- a/test/dm/gpio.c +++ b/test/dm/gpio.c @@ -680,3 +680,101 @@ static int dm_test_clrset_flags_invert(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_clrset_flags_invert, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +static int set_gpios(struct unit_test_state *uts, struct gpio_desc *desc, + int count, uint value) +{ + int i; + + for (i = 0; i < count; i++) { + const uint mask = 1 << i; + + ut_assertok(sandbox_gpio_set_value(desc[i].dev, desc[i].offset, + value & mask)); + } + + return 0; +} + +/* Check that an active-low GPIO works as expected */ +static int dm_test_gpio_get_values_as_int(struct unit_test_state *uts) +{ + const int gpio_count = 3; + struct gpio_desc desc[gpio_count]; + struct udevice *dev; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + + ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc, + gpio_count, GPIOD_IS_IN)); + ut_assertok(set_gpios(uts, desc, gpio_count, 0)); + ut_asserteq(0, dm_gpio_get_values_as_int(desc, gpio_count)); + + ut_assertok(set_gpios(uts, desc, gpio_count, 5)); + ut_asserteq(5, dm_gpio_get_values_as_int(desc, gpio_count)); + + ut_assertok(set_gpios(uts, desc, gpio_count, 7)); + ut_asserteq(7, dm_gpio_get_values_as_int(desc, gpio_count)); + + return 0; +} +DM_TEST(dm_test_gpio_get_values_as_int, + UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Check that an active-low GPIO works as expected */ +static int dm_test_gpio_get_values_as_int_base3(struct unit_test_state *uts) +{ + const int gpio_count = 3; + struct gpio_desc desc[gpio_count]; + struct udevice *dev; + + ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); + ut_asserteq_str("a-test", dev->name); + + ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc, + gpio_count, GPIOD_IS_IN)); + + /* + * First test the sandbox GPIO driver works as expected. The external + * pull resistor should be stronger than the internal one. + */ + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, + GPIOD_IS_IN | GPIOD_EXT_PULL_UP | GPIOD_PULL_UP); + ut_asserteq(1, dm_gpio_get_value(desc)); + + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_IS_IN | + GPIOD_EXT_PULL_DOWN | GPIOD_PULL_UP); + ut_asserteq(0, dm_gpio_get_value(desc)); + + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, + GPIOD_IS_IN | GPIOD_PULL_UP); + ut_asserteq(1, dm_gpio_get_value(desc)); + + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_PULL_DOWN); + ut_asserteq(0, dm_gpio_get_value(desc)); + + /* + * Set up pins: pull-up (1), pull-down (0) and floating (2). This should + * result in digits 2 0 1, i.e. 2 * 9 + 1 * 3 = 19 + */ + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_EXT_PULL_UP); + sandbox_gpio_set_flags(desc[1].dev, desc[1].offset, + GPIOD_EXT_PULL_DOWN); + sandbox_gpio_set_flags(desc[2].dev, desc[2].offset, 0); + ut_asserteq(19, dm_gpio_get_values_as_int_base3(desc, gpio_count)); + + /* + * Set up pins: floating (2), pull-up (1) and pull-down (0). This should + * result in digits 0 1 2, i.e. 1 * 3 + 2 = 5 + */ + sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, 0); + sandbox_gpio_set_flags(desc[1].dev, desc[1].offset, GPIOD_EXT_PULL_UP); + sandbox_gpio_set_flags(desc[2].dev, desc[2].offset, + GPIOD_EXT_PULL_DOWN); + ut_asserteq(5, dm_gpio_get_values_as_int_base3(desc, gpio_count)); + + return 0; +} +DM_TEST(dm_test_gpio_get_values_as_int_base3, + UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -- cgit v1.2.3