From 7c76d25a9190a9f277c2f0b459486a04e717286e Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Tue, 22 Jan 2019 10:13:02 +0100 Subject: [PATCH 01/12] api: gpio: Align GPIO dt-bindings flags with Linux DTS This commit makes following changes to GPIO dt-bindings flags: - Added GPIO_ACTIVE_LOW, GPIO_ACTIVE_HIGH to indicate pin active state. - Added GPIO_OPEN_DRAIN, GPIO_OPEN_SOURCE to configure single ended pin driving mode. - Added GPIO_PULL_UP, GPIO_PULL_DOWN flags. - GPIO_INPUT, GPIO_OUTPUT to configure pin as input or output. - Added GPIO_OUTPUT_LOW, GPIO_OUTPUT_HIGH flags to initialize output in low or high state. - reworked GPIO_INT_* flags to configure pin interrupts. - following flags were deprecated: GPIO_DIR_*, GPIO_DS_DISCONNECT_*, GPIO_PUD_*, GPIO_INT_ACTIVE_*, GPIO_INT_DOUBLE_EDGE, GPIO_POL_*. To be aligned with Linux DTS standard any GPIO flags that should not be used in DTS files are moved from include/dt-bindings/gpio/gpio.h file to include/drivers/gpio.h with an exception of several old flags which removal would cause DTS compilation errors. Those remaining old flags will be removed from include/dt-bindings/gpio/gpio.h at a later stage. Signed-off-by: Piotr Mienkowski --- include/drivers/gpio.h | 349 +++++++++++++++++++++++++++++++- include/dt-bindings/gpio/gpio.h | 183 +++++------------ 2 files changed, 395 insertions(+), 137 deletions(-) diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h index 4d87956969ba88..0cf0072c60cfb9 100644 --- a/include/drivers/gpio.h +++ b/include/drivers/gpio.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019 Piotr Mienkowski * Copyright (c) 2017 ARM Ltd * Copyright (c) 2015-2016 Intel Corporation. * @@ -32,6 +33,334 @@ extern "C" { * @{ */ +/** + * @name GPIO input/output configuration flags + * @{ + */ + +/** Enables pin as input. */ +#define GPIO_INPUT (1U << 8) + +/** Enables pin as output, no change to the output state. */ +#define GPIO_OUTPUT (1U << 9) + +/** @cond INTERNAL_HIDDEN */ + +/* Initializes output to a low state. */ +#define GPIO_OUTPUT_INIT_LOW (1U << 10) + +/* Initializes output to a high state. */ +#define GPIO_OUTPUT_INIT_HIGH (1U << 11) + +/** @endcond */ + +/** Configures GPIO pin as output and initializes it to a low state. */ +#define GPIO_OUTPUT_LOW (GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW) +/** Configures GPIO pin as output and initializes it to a high state. */ +#define GPIO_OUTPUT_HIGH (GPIO_OUTPUT | GPIO_OUTPUT_INIT_HIGH) + +/** @} */ + +/** + * @name GPIO interrupt configuration flags + * The `GPIO_INT_*` flags are used to specify how input GPIO pins will trigger + * interrupts. The interrupts can be sensitive to pin physical or logical level. + * Interrupts sensitive to pin logical level take into account GPIO_ACTIVE_LOW + * flag. If a pin was configured as Active Low, physical level low will be + * considered as logical level 1 (an active state), physical level high will + * be considered as logical level 0 (an inactive state). + * @{ + */ + +/** Disables GPIO pin interrupt. */ +#define GPIO_INT_DISABLE (0U << 12) + +/** @cond INTERNAL_HIDDEN */ + +/* Enables GPIO pin interrupt. */ +#define GPIO_INT_ENABLE (1U << 12) + +/* GPIO interrupt is sensitive to logical levels. + * + * This is a component flag that should be combined with other + * `GPIO_INT_*` flags to produce a meaningful configuration. + */ +#define GPIO_INT_LEVELS_LOGICAL (1U << 13) + +/* GPIO interrupt is edge sensitive. + * + * Note: by default interrupts are level sensitive. + * + * This is a component flag that should be combined with other + * `GPIO_INT_*` flags to produce a meaningful configuration. + */ +#define GPIO_INT_EDGE (1U << 14) + +/* Trigger detection when input state is (or transitions to) physical low or + * logical 0 level. + * + * This is a component flag that should be combined with other + * `GPIO_INT_*` flags to produce a meaningful configuration. + */ +#define GPIO_INT_LOW_0 (1U << 15) + +/* Trigger detection on input state is (or transitions to) physical high or + * logical 1 level. + * + * This is a component flag that should be combined with other + * `GPIO_INT_*` flags to produce a meaningful configuration. + */ +#define GPIO_INT_HIGH_1 (1U << 16) + +/** @endcond */ + +/** Configures GPIO interrupt to be triggered on pin rising edge and enables it. + */ +#define GPIO_INT_EDGE_RISING (GPIO_INT_ENABLE | \ + GPIO_INT_EDGE | \ + GPIO_INT_HIGH_1) + +/** Configures GPIO interrupt to be triggered on pin falling edge and enables + * it. + */ +#define GPIO_INT_EDGE_FALLING (GPIO_INT_ENABLE | \ + GPIO_INT_EDGE | \ + GPIO_INT_LOW_0) + +/** Configures GPIO interrupt to be triggered on pin rising or falling edge and + * enables it. + */ +#define GPIO_INT_EDGE_BOTH (GPIO_INT_ENABLE | \ + GPIO_INT_EDGE | \ + GPIO_INT_LOW_0 | \ + GPIO_INT_HIGH_1) + +/** Configures GPIO interrupt to be triggered on pin physical level low and + * enables it. + */ +#define GPIO_INT_LEVEL_LOW (GPIO_INT_ENABLE | \ + GPIO_INT_LOW_0) + +/** Configures GPIO interrupt to be triggered on pin physical level high and + * enables it. + */ +#define GPIO_INT_LEVEL_HIGH (GPIO_INT_ENABLE | \ + GPIO_INT_HIGH_1) + +/** Configures GPIO interrupt to be triggered on pin state change to logical + * level 0 and enables it. + */ +#define GPIO_INT_EDGE_TO_INACTIVE (GPIO_INT_ENABLE | \ + GPIO_INT_LEVELS_LOGICAL | \ + GPIO_INT_EDGE | \ + GPIO_INT_LOW_0) + +/** Configures GPIO interrupt to be triggered on pin state change to logical + * level 1 and enables it. + */ +#define GPIO_INT_EDGE_TO_ACTIVE (GPIO_INT_ENABLE | \ + GPIO_INT_LEVELS_LOGICAL | \ + GPIO_INT_EDGE | \ + GPIO_INT_HIGH_1) + +/** Configures GPIO interrupt to be triggered on pin logical level 0 and enables + * it. + */ +#define GPIO_INT_LEVEL_INACTIVE (GPIO_INT_ENABLE | \ + GPIO_INT_LEVELS_LOGICAL | \ + GPIO_INT_LOW_0) + +/** Configures GPIO interrupt to be triggered on pin logical level 1 and enables + * it. + */ +#define GPIO_INT_LEVEL_ACTIVE (GPIO_INT_ENABLE | \ + GPIO_INT_LEVELS_LOGICAL | \ + GPIO_INT_HIGH_1) + +/** @} */ + +/** Enable GPIO pin debounce. */ +#define GPIO_INT_DEBOUNCE (1U << 17) + +/** + * @name GPIO drive strength flags + * The `GPIO_DS_*` flags are used with `gpio_pin_configure` to specify the drive + * strength configuration of a GPIO pin. + * + * The drive strength of individual pins can be configured + * independently for when the pin output is low and high. + * + * The `GPIO_DS_*_LOW` enumerations define the drive strength of a pin + * when output is low. + + * The `GPIO_DS_*_HIGH` enumerations define the drive strength of a pin + * when output is high. + * + * The interface supports two different drive strengths: + * `DFLT` - The lowest drive strength supported by the HW + * `ALT` - The highest drive strength supported by the HW + * + * On hardware that supports only one standard drive strength, both + * `DFLT` and `ALT` have the same behavior. + * @{ + */ +/** @cond INTERNAL_HIDDEN */ +#define GPIO_DS_LOW_POS 18 +#define GPIO_DS_LOW_MASK (0x3U << GPIO_DS_LOW_POS) +/** @endcond */ + +/** Default drive strength standard when GPIO pin output is low. + */ +#define GPIO_DS_DFLT_LOW (0x0U << GPIO_DS_LOW_POS) + +/** Alternative drive strength when GPIO pin output is low. + * For hardware that does not support configurable drive strength + * use the default drive strength. + */ +#define GPIO_DS_ALT_LOW (0x1U << GPIO_DS_LOW_POS) + +/** @cond INTERNAL_HIDDEN */ +#define GPIO_DS_HIGH_POS 20 +#define GPIO_DS_HIGH_MASK (0x3U << GPIO_DS_HIGH_POS) +/** @endcond */ + +/** Default drive strength when GPIO pin output is high. + */ +#define GPIO_DS_DFLT_HIGH (0x0U << GPIO_DS_HIGH_POS) + +/** Alternative drive strength when GPIO pin output is high. + * For hardware that does not support configurable drive strengths + * use the default drive strength. + */ +#define GPIO_DS_ALT_HIGH (0x1U << GPIO_DS_HIGH_POS) +/** @} */ + +/** @name Deprecated Flags + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ +#define GPIO_DIR_SHIFT 8 +#define GPIO_DIR_MASK (0x3U << GPIO_DIR_SHIFT) +/** @endcond */ + +/** Legacy flag indicating pin is configured as input only. + * + * @deprecated Replace with `GPIO_INPUT`. + */ +#define GPIO_DIR_IN GPIO_INPUT + +/** Legacy flag indicating pin is configured as output. + * + * @deprecated Replace with `GPIO_OUTPUT`. + */ +#undef GPIO_DIR_OUT +#define GPIO_DIR_OUT GPIO_OUTPUT + +/** Legacy flag indicating pin is disconnected when GPIO pin output is low. + * + * @deprecated Replace with `GPIO_OPEN_SOURCE`. + */ +#define GPIO_DS_DISCONNECT_LOW GPIO_OPEN_SOURCE + +/** Legacy flag indicating pin is disconnected when GPIO pin output is high. + * + * @deprecated Replace with `GPIO_OPEN_DRAIN`. + */ +#define GPIO_DS_DISCONNECT_HIGH GPIO_OPEN_DRAIN + +/** @cond INTERNAL_HIDDEN */ +#define GPIO_PUD_SHIFT 4 +#define GPIO_PUD_MASK (0x3U << GPIO_PUD_SHIFT) +/** @endcond */ + +/** Pin is neither pull-up nor pull-down. + * + * @deprecated Not used any more + */ +#define GPIO_PUD_NORMAL 0U + +/** Enable GPIO pin pull-up. + * + * @deprecated Replace with `GPIO_PULL_UP`. + */ +#undef GPIO_PUD_PULL_UP +#define GPIO_PUD_PULL_UP GPIO_PULL_UP + +/** Enable GPIO pin pull-down. + * + * @deprecated Replace with `GPIO_PULL_DOWN`. + */ +#undef GPIO_PUD_PULL_DOWN +#define GPIO_PUD_PULL_DOWN GPIO_PULL_DOWN + +/** Legacy flag indicating that interrupt is enabled. + * + * @deprecated Replace with `GPIO_INT_ENABLE`. + */ +#define GPIO_INT GPIO_INT_ENABLE + +/** Legacy flag indicating that interrupt is level sensitive. + * + * @deprecated Replace with `GPIO_INT_LEVEL_LOW`, `GPIO_INT_LEVEL_HIGH`. + */ +#define GPIO_INT_LEVEL (0U << 14) + +/** Legacy flag setting indicating signal or interrupt active level. + * + * This flag was used both to indicate a signal's active level, and to + * indicate the level associated with an interrupt on a signal. As + * active level is also relevant to output signals the two + * interpretations have been separated. The legacy value supports + * testing for interrupt level as this is the most common use in + * existing code. + * + * @deprecated Replace with `GPIO_ACTIVE_LOW` or `GPIO_INT_LOW_0` + * depending on intent. + */ +#undef GPIO_INT_ACTIVE_LOW +#define GPIO_INT_ACTIVE_LOW GPIO_INT_LOW_0 + +/** Legacy flag setting indicating signal or interrupt active level. + * + * This flag was used both to indicate a signal's active level, and to + * indicate the level associated with an interrupt on a signal. As + * active level is also relevant to output signals the two + * interpretations have been separated. The legacy value supports + * testing for interrupt level as this is the most common use in + * existing code. + * + * @deprecated Replace with `GPIO_ACTIVE_HIGH` or `GPIO_INT_HIGH_1` + * depending on intent. + */ +#undef GPIO_INT_ACTIVE_HIGH +#define GPIO_INT_ACTIVE_HIGH GPIO_INT_HIGH_1 + +/** Legacy flag indicating interrupt triggers on both rising and falling edge. + * + * @deprecated Replace with `GPIO_INT_EDGE_BOTH`. + */ +#define GPIO_INT_DOUBLE_EDGE GPIO_INT_EDGE_BOTH + +/** @cond INTERNAL_HIDDEN */ +#define GPIO_POL_SHIFT 0 +#define GPIO_POL_MASK (1U << GPIO_POL_SHIFT) +/** @endcond */ + +/** Legacy flag indicating that GPIO pin polarity is normal. + * + * @deprecated Replace with `GPIO_ACTIVE_HIGH`. + */ +#define GPIO_POL_NORMAL GPIO_ACTIVE_HIGH + +/** Legacy flag indicating that GPIO pin polarity is inverted. + * + * @deprecated Replace with `GPIO_ACTIVE_LOW`. + */ +#define GPIO_POL_INV GPIO_ACTIVE_LOW + +/** @} */ + /** @cond INTERNAL_HIDDEN */ #define GPIO_ACCESS_BY_PIN 0 #define GPIO_ACCESS_BY_PORT 1 @@ -177,14 +506,28 @@ static inline int z_impl_gpio_disable_callback(struct device *port, /** * @brief Configure a single pin. + * * @param port Pointer to device structure for the driver instance. * @param pin Pin number to configure. - * @param flags Flags for pin configuration. IN/OUT, interrupt ... - * @return 0 if successful, negative errno code on failure. + * @param flags Flags for pin configuration: 'GPIO input/output configuration + * flags', 'GPIO drive strength flags', 'GPIO pin drive flags', 'GPIO pin + * bias flags', GPIO_INT_DEBOUNCE. + * + * @retval 0 If successful. + * @retval -ENOTSUP if any of the configuration options is not supported. + * @retval -EINVAL Invalid argument. */ static inline int gpio_pin_configure(struct device *port, u32_t pin, - int flags) + unsigned int flags) { + __ASSERT((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != + (GPIO_PULL_UP | GPIO_PULL_DOWN), + "Pull Up and Pull Down should not be enabled simultaneously"); + + __ASSERT((flags & (GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH)) == 0 + || (flags & GPIO_OUTPUT) != 0, + "Output needs to be enabled to be initialized low or high"); + return gpio_config(port, GPIO_ACCESS_BY_PIN, pin, flags); } diff --git a/include/dt-bindings/gpio/gpio.h b/include/dt-bindings/gpio/gpio.h index c365d449e347bd..adc0d8d2d5f5fb 100644 --- a/include/dt-bindings/gpio/gpio.h +++ b/include/dt-bindings/gpio/gpio.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2019 Piotr Mienkowski * Copyright (c) 2018 Linaro Limited * * SPDX-License-Identifier: Apache-2.0 @@ -6,175 +7,89 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_GPIO_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_GPIO_H_ - /** - * @name GPIO direction flags - * The `GPIO_DIR_*` flags are used with `gpio_pin_configure` or `gpio_port_configure`, - * to specify whether a GPIO pin will be used for input or output. + * @brief GPIO Driver APIs + * @defgroup gpio_interface GPIO Driver APIs + * @ingroup io_interfaces * @{ */ -/** GPIO pin to be input. */ -#define GPIO_DIR_IN (0 << 0) - -/** GPIO pin to be output. */ -#define GPIO_DIR_OUT (1 << 0) - -/** @cond INTERNAL_HIDDEN */ -#define GPIO_DIR_MASK 0x1 -/** @endcond */ -/** @} */ - /** - * @name GPIO interrupt flags - * The `GPIO_INT_*` flags are used with `gpio_pin_configure` or `gpio_port_configure`, - * to specify how input GPIO pins will trigger interrupts. + * @name GPIO pin active level flags * @{ */ -/** GPIO pin to trigger interrupt. */ -#define GPIO_INT (1 << 1) -/** GPIO pin trigger on level low or falling edge. */ -#define GPIO_INT_ACTIVE_LOW (0 << 2) +/** GPIO pin is active (has logical value '1') in low state. */ +#define GPIO_ACTIVE_LOW (1 << 0) +/** GPIO pin is active (has logical value '1') in high state. */ +#define GPIO_ACTIVE_HIGH (0 << 0) -/** GPIO pin trigger on level high or rising edge. */ -#define GPIO_INT_ACTIVE_HIGH (1 << 2) - -/** Enable GPIO pin debounce. */ -#define GPIO_INT_DEBOUNCE (1 << 4) - -/** Do Level trigger. */ -#define GPIO_INT_LEVEL (0 << 5) - -/** Do Edge trigger. */ -#define GPIO_INT_EDGE (1 << 5) - -/** Interrupt triggers on both rising and falling edge. - * Must be combined with GPIO_INT_EDGE. - */ -#define GPIO_INT_DOUBLE_EDGE (1 << 6) /** @} */ - /** - * @name GPIO polarity flags - * The `GPIO_POL_*` flags are used with `gpio_pin_configure` or `gpio_port_configure`, - * to specify the polarity of a GPIO pin. + * @name GPIO pin drive flags * @{ */ + /** @cond INTERNAL_HIDDEN */ -#define GPIO_POL_POS 7 -/** @endcond */ -/** GPIO pin polarity is normal. */ -#define GPIO_POL_NORMAL (0 << GPIO_POL_POS) +/* Configures GPIO output in single-ended mode (open drain or open source). */ +#define GPIO_SINGLE_ENDED (1 << 1) +/* Configures GPIO output in push-pull mode */ +#define GPIO_PUSH_PULL (0 << 1) -/** GPIO pin polarity is inverted. */ -#define GPIO_POL_INV (1 << GPIO_POL_POS) +/* Indicates single ended open drain mode (wired AND). */ +#define GPIO_LINE_OPEN_DRAIN (1 << 2) +/* Indicates single ended open source mode (wired OR). */ +#define GPIO_LINE_OPEN_SOURCE (0 << 2) -/** @cond INTERNAL_HIDDEN */ -#define GPIO_POL_MASK (1 << GPIO_POL_POS) /** @endcond */ -/** @} */ +/** Configures GPIO output in open drain mode (wired AND). + * + * @note 'Open Drain' mode also known as 'Open Collector' is an output + * configuration which behaves like a switch that is either connected to ground + * or disconnected. + */ +#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN) +/** Configures GPIO output in open source mode (wired OR). + * + * @note 'Open Source' is a term used by software engineers to describe output + * mode opposite to 'Open Drain'. It behaves like a switch that is either + * connected to power supply or disconnected. There exist no corresponding + * hardware schematic and the term is generally unknown to hardware engineers. + */ +#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE) + +/** @} */ /** - * @name GPIO pull flags - * The `GPIO_PUD_*` flags are used with `gpio_pin_configure` or `gpio_port_configure`, - * to specify the pull-up or pull-down electrical configuration of a GPIO pin. + * @name GPIO pin bias flags * @{ */ -/** @cond INTERNAL_HIDDEN */ -#define GPIO_PUD_POS 8 -/** @endcond */ - -/** Pin is neither pull-up nor pull-down. */ -#define GPIO_PUD_NORMAL (0 << GPIO_PUD_POS) -/** Enable GPIO pin pull-up. */ -#define GPIO_PUD_PULL_UP (1 << GPIO_PUD_POS) +/** Enables GPIO pin pull-up. */ +#define GPIO_PULL_UP (1 << 4) /** Enable GPIO pin pull-down. */ -#define GPIO_PUD_PULL_DOWN (2 << GPIO_PUD_POS) +#define GPIO_PULL_DOWN (1 << 5) -/** @cond INTERNAL_HIDDEN */ -#define GPIO_PUD_MASK (3 << GPIO_PUD_POS) -/** @endcond */ /** @} */ - /** - * @name GPIO drive strength flags - * The `GPIO_DS_*` flags are used with `gpio_pin_configure` or `gpio_port_configure`, - * to specify the drive strength configuration of a GPIO pin. - * - * The drive strength of individual pins can be configured - * independently for when the pin output is low and high. - * - * The `GPIO_DS_*_LOW` enumerations define the drive strength of a pin - * when output is low. - - * The `GPIO_DS_*_HIGH` enumerations define the drive strength of a pin - * when output is high. - * - * The `DISCONNECT` drive strength indicates that the pin is placed in a - * high impedance state and not driven, this option is used to - * configure hardware that supports a open collector drive mode. - * - * The interface supports two different drive strengths: - * `DFLT` - The lowest drive strength supported by the HW - * `ALT` - The highest drive strength supported by the HW + * @cond INTERNAL_HIDDEN * - * On hardware that supports only one standard drive strength, both - * `DFLT` and `ALT` have the same behavior. - * - * On hardware that does not support a disconnect mode, `DISCONNECT` - * will behave the same as `DFLT`. - * @{ + * Following defines are deprecated and shouldn't be used in DTS files. */ -/** @cond INTERNAL_HIDDEN */ -#define GPIO_DS_LOW_POS 12 -#define GPIO_DS_LOW_MASK (0x3 << GPIO_DS_LOW_POS) +#define GPIO_DIR_OUT (1 << 9) /* GPIO_OUTPUT */ +#define GPIO_PUD_PULL_UP GPIO_PULL_UP +#define GPIO_PUD_PULL_DOWN GPIO_PULL_DOWN +#define GPIO_INT_ACTIVE_LOW (1 << 15) /* GPIO_INT_LOW_0 */ +#define GPIO_INT_ACTIVE_HIGH (1 << 16) /* GPIO_INT_HIGH_1 */ /** @endcond */ -/** Default drive strength standard when GPIO pin output is low. - */ -#define GPIO_DS_DFLT_LOW (0x0 << GPIO_DS_LOW_POS) - -/** Alternative drive strength when GPIO pin output is low. - * For hardware that does not support configurable drive strength - * use the default drive strength. - */ -#define GPIO_DS_ALT_LOW (0x1 << GPIO_DS_LOW_POS) - -/** Disconnect pin when GPIO pin output is low. - * For hardware that does not support disconnect use the default - * drive strength. - */ -#define GPIO_DS_DISCONNECT_LOW (0x3 << GPIO_DS_LOW_POS) - -/** @cond INTERNAL_HIDDEN */ -#define GPIO_DS_HIGH_POS 14 -#define GPIO_DS_HIGH_MASK (0x3 << GPIO_DS_HIGH_POS) -/** @endcond */ - -/** Default drive strength when GPIO pin output is high. - */ -#define GPIO_DS_DFLT_HIGH (0x0 << GPIO_DS_HIGH_POS) - -/** Alternative drive strength when GPIO pin output is high. - * For hardware that does not support configurable drive strengths - * use the default drive strength. - */ -#define GPIO_DS_ALT_HIGH (0x1 << GPIO_DS_HIGH_POS) - -/** Disconnect pin when GPIO pin output is high. - * For hardware that does not support disconnect use the default - * drive strength. +/** + * @} */ -#define GPIO_DS_DISCONNECT_HIGH (0x3 << GPIO_DS_HIGH_POS) -/** @} */ - - #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_GPIO_H_ */ From 23a3bfd87ae97ad5fb537afa2f19da0b14538ca6 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Fri, 31 May 2019 11:00:13 +0200 Subject: [PATCH 02/12] gpio: add new functions to set/get pin/port values This commit adds following functions which work with pin logical levels (take into account GPIO_ACTIVE_LOW flag): - gpio_port_get, gpio_port_set_masked, gpio_port_set_bits, gpio_port_clear_bits, gpio_port_set_clr_bits - gpio_pin_get, gpio_pin_set Functions which work with pin physical levels: - gpio_port_get_raw, gpio_port_set_masked_raw, gpio_port_set_bits_raw, gpio_port_clear_bits_raw, gpio_port_set_clr_bits_raw - gpio_pin_get_raw, gpio_pin_set_raw As well as functions: - gpio_port_toggle_bits, gpio_pin_toggle_bits Signed-off-by: Piotr Mienkowski --- drivers/gpio/gpio_handlers.c | 43 ++++ include/drivers/gpio.h | 412 ++++++++++++++++++++++++++++++++++- 2 files changed, 452 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio_handlers.c b/drivers/gpio/gpio_handlers.c index 35016e91dc64a9..235df21c9eab84 100644 --- a/drivers/gpio/gpio_handlers.c +++ b/drivers/gpio/gpio_handlers.c @@ -33,6 +33,49 @@ static inline int z_vrfy_gpio_read(struct device *port, int access_op, } #include +static inline int z_vrfy_gpio_port_get_raw(struct device *port, + gpio_pins_t *value) +{ + Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_get_raw)); + Z_OOPS(Z_SYSCALL_MEMORY_WRITE(value, sizeof(gpio_pins_t))); + return z_impl_gpio_port_get_raw((struct device *)port, + (gpio_pins_t *)value); +} +#include + +static inline int z_vrfy_gpio_port_set_masked_raw(struct device *port, + gpio_pins_t mask, gpio_pins_t value) +{ + Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_set_masked_raw)); + return z_impl_gpio_port_set_masked_raw((struct device *)port, mask, + value); +} +#include + +static inline int z_vrfy_gpio_port_set_bits_raw(struct device *port, + gpio_pins_t pins) +{ + Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_set_bits_raw)); + return z_impl_gpio_port_set_bits_raw((struct device *)port, pins); +} +#include + +static inline int z_vrfy_gpio_port_clear_bits_raw(struct device *port, + gpio_pins_t pins) +{ + Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_clear_bits_raw)); + return z_impl_gpio_port_clear_bits_raw((struct device *)port, pins); +} +#include + +static inline int z_vrfy_gpio_port_toggle_bits(struct device *port, + gpio_pins_t pins) +{ + Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_toggle_bits)); + return z_impl_gpio_port_toggle_bits((struct device *)port, pins); +} +#include + static inline int z_vrfy_gpio_enable_callback(struct device *port, int access_op, u32_t pin) { diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h index 0cf0072c60cfb9..0e41af3c50adec 100644 --- a/include/drivers/gpio.h +++ b/include/drivers/gpio.h @@ -368,6 +368,24 @@ extern "C" { * @endcond */ +/** + * @brief Pins associated with a port. + * + * Value of this type identifies pins, or their value, associated with a port. + * Pin with index n, or its value, is identified by bit n (1U << n) in the value + * of type gpio_pins_t. + */ +typedef u32_t gpio_pins_t; + +/** + * @brief Maximum number of pins that are supported by gpio_pins_t + */ +#define GPIO_MAX_PINS_PER_PORT (sizeof(gpio_pins_t) * __CHAR_BIT__) + +struct gpio_driver_data { + gpio_pins_t invert; +}; + struct gpio_callback; /** @@ -385,7 +403,7 @@ struct gpio_callback; */ typedef void (*gpio_callback_handler_t)(struct device *port, struct gpio_callback *cb, - u32_t pins); + gpio_pins_t pins); /** * @brief GPIO callback structure @@ -412,7 +430,7 @@ struct gpio_callback { * called or not. The selected pins must be configured to trigger * an interrupt. */ - u32_t pin_mask; + gpio_pins_t pin_mask; }; /** @@ -426,6 +444,12 @@ struct gpio_driver_api { u32_t value); int (*read)(struct device *port, int access_op, u32_t pin, u32_t *value); + int (*port_get_raw)(struct device *port, gpio_pins_t *value); + int (*port_set_masked_raw)(struct device *port, gpio_pins_t mask, + gpio_pins_t value); + int (*port_set_bits_raw)(struct device *port, gpio_pins_t pins); + int (*port_clear_bits_raw)(struct device *port, gpio_pins_t pins); + int (*port_toggle_bits)(struct device *port, gpio_pins_t pins); int (*manage_callback)(struct device *port, struct gpio_callback *cb, bool set); int (*enable_callback)(struct device *port, int access_op, u32_t pin); @@ -531,6 +555,388 @@ static inline int gpio_pin_configure(struct device *port, u32_t pin, return gpio_config(port, GPIO_ACCESS_BY_PIN, pin, flags); } +/** + * @brief Get physical level of all input pins in a port. + * + * A low physical level on the pin will be interpreted as value 0. A high + * physical level will be interpreted as value 1. This function ignores + * GPIO_ACTIVE_LOW flag. + * + * Value of a pin with index n will be represented by bit n in the returned + * port value. + * + * @param port Pointer to the device structure for the driver instance. + * @param value Pointer to a variable where pin values will be stored. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +__syscall int gpio_port_get_raw(struct device *port, gpio_pins_t *value); + +static inline int z_impl_gpio_port_get_raw(struct device *port, + gpio_pins_t *value) +{ + const struct gpio_driver_api *api = + (const struct gpio_driver_api *)port->driver_api; + + return api->port_get_raw(port, value); +} + +/** + * @brief Get logical level of all input pins in a port. + * + * Get logical level of an input pin taking into account GPIO_ACTIVE_LOW flag. + * If pin is configured as Active High, a low physical level will be interpreted + * as logical value 0. If pin is configured as Active Low, a low physical level + * will be interpreted as logical value 1. + * + * Value of a pin with index n will be represented by bit n in the returned + * port value. + * + * @param port Pointer to the device structure for the driver instance. + * @param value Pointer to a variable where pin values will be stored. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_port_get(struct device *port, gpio_pins_t *value) +{ + struct gpio_driver_data *const data = + (struct gpio_driver_data *const)port->driver_data; + int ret; + + ret = gpio_port_get_raw(port, value); + if (ret == 0) { + *value ^= data->invert; + } + + return ret; +} + +/** + * @brief Set physical level of output pins in a port. + * + * Writing value 0 to the pin will set it to a low physical level. Writing + * value 1 will set it to a high physical level. This function ignores + * GPIO_ACTIVE_LOW flag. + * + * Pin with index n is represented by bit n in mask and value parameter. + * + * @param port Pointer to the device structure for the driver instance. + * @param mask Mask indicating which pins will be modified. + * @param value Value assigned to the output pins. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +__syscall int gpio_port_set_masked_raw(struct device *port, gpio_pins_t mask, + gpio_pins_t value); + +static inline int z_impl_gpio_port_set_masked_raw(struct device *port, + gpio_pins_t mask, gpio_pins_t value) +{ + const struct gpio_driver_api *api = + (const struct gpio_driver_api *)port->driver_api; + + return api->port_set_masked_raw(port, mask, value); +} + +/** + * @brief Set logical level of output pins in a port. + * + * Set logical level of an output pin taking into account GPIO_ACTIVE_LOW flag. + * Value 0 sets the pin in logical 0 / inactive state. Value 1 sets the pin in + * logical 1 / active state. If pin is configured as Active High, the default, + * setting it in inactive state will force the pin to a low physical level. If + * pin is configured as Active Low, setting it in inactive state will force the + * pin to a high physical level. + * + * Pin with index n is represented by bit n in mask and value parameter. + * + * @param port Pointer to the device structure for the driver instance. + * @param mask Mask indicating which pins will be modified. + * @param value Value assigned to the output pins. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_port_set_masked(struct device *port, gpio_pins_t mask, + gpio_pins_t value) +{ + struct gpio_driver_data *const data = + (struct gpio_driver_data *const)port->driver_data; + + value ^= data->invert; + + return gpio_port_set_masked_raw(port, mask, value); +} + +/** + * @brief Set physical level of selected output pins to high. + * + * @param port Pointer to the device structure for the driver instance. + * @param pins Value indicating which pins will be modified. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +__syscall int gpio_port_set_bits_raw(struct device *port, gpio_pins_t pins); + +static inline int z_impl_gpio_port_set_bits_raw(struct device *port, + gpio_pins_t pins) +{ + const struct gpio_driver_api *api = + (const struct gpio_driver_api *)port->driver_api; + + return api->port_set_bits_raw(port, pins); +} + +/** + * @brief Set logical level of selected output pins to active. + * + * @param port Pointer to the device structure for the driver instance. + * @param pins Value indicating which pins will be modified. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_port_set_bits(struct device *port, gpio_pins_t pins) +{ + return gpio_port_set_masked(port, pins, pins); +} + +/** + * @brief Set physical level of selected output pins to low. + * + * @param port Pointer to the device structure for the driver instance. + * @param pins Value indicating which pins will be modified. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +__syscall int gpio_port_clear_bits_raw(struct device *port, gpio_pins_t pins); + +static inline int z_impl_gpio_port_clear_bits_raw(struct device *port, + gpio_pins_t pins) +{ + const struct gpio_driver_api *api = + (const struct gpio_driver_api *)port->driver_api; + + return api->port_clear_bits_raw(port, pins); +} + +/** + * @brief Set logical level of selected output pins to inactive. + * + * @param port Pointer to the device structure for the driver instance. + * @param pins Value indicating which pins will be modified. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_port_clear_bits(struct device *port, gpio_pins_t pins) +{ + return gpio_port_set_masked(port, pins, 0); +} + +/** + * @brief Toggle level of selected output pins. + * + * @param port Pointer to the device structure for the driver instance. + * @param pins Value indicating which pins will be modified. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +__syscall int gpio_port_toggle_bits(struct device *port, gpio_pins_t pins); + +static inline int z_impl_gpio_port_toggle_bits(struct device *port, + gpio_pins_t pins) +{ + const struct gpio_driver_api *api = + (const struct gpio_driver_api *)port->driver_api; + + return api->port_toggle_bits(port, pins); +} + +/** + * @brief Set physical level of selected output pins. + * + * @param port Pointer to the device structure for the driver instance. + * @param set_pins Value indicating which pins will be set to high. + * @param clear_pins Value indicating which pins will be set to low. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_port_set_clr_bits_raw(struct device *port, + gpio_pins_t set_pins, gpio_pins_t clear_pins) +{ + __ASSERT((set_pins & clear_pins) == 0, "Set and Clear pins overlap"); + + return gpio_port_set_masked_raw(port, set_pins | clear_pins, set_pins); +} + +/** + * @brief Set logical level of selected output pins. + * + * @param port Pointer to the device structure for the driver instance. + * @param set_pins Value indicating which pins will be set to active. + * @param clear_pins Value indicating which pins will be set to inactive. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_port_set_clr_bits(struct device *port, + gpio_pins_t set_pins, gpio_pins_t clear_pins) +{ + __ASSERT((set_pins & clear_pins) == 0, "Set and Clear pins overlap"); + + return gpio_port_set_masked(port, set_pins | clear_pins, set_pins); +} + +/** + * @brief Get physical level of an input pin. + * + * A low physical level on the pin will be interpreted as value 0. A high + * physical level will be interpreted as value 1. This function ignores + * GPIO_ACTIVE_LOW flag. + * + * @param port Pointer to the device structure for the driver instance. + * @param pin Pin number. + * + * @retval 1 If pin physical level is high. + * @retval 0 If pin physical level is low. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_pin_get_raw(struct device *port, unsigned int pin) +{ + gpio_pins_t value; + int ret; + + __ASSERT(pin < GPIO_MAX_PINS_PER_PORT, "Invalid pin number"); + + ret = gpio_port_get_raw(port, &value); + if (ret == 0) { + ret = (value & BIT(pin)) != 0 ? 1 : 0; + } + + return ret; +} + +/** + * @brief Get logical level of an input pin. + * + * Get logical level of an input pin taking into account GPIO_ACTIVE_LOW flag. + * If pin is configured as Active High, a low physical level will be interpreted + * as logical value 0. If pin is configured as Active Low, a low physical level + * will be interpreted as logical value 1. + * + * Note: If pin is configured as Active High, the default, gpio_pin_get() + * function is equivalent to gpio_pin_get_raw(). + * + * @param port Pointer to the device structure for the driver instance. + * @param pin Pin number. + * + * @retval 1 If pin logical value is 1 / active. + * @retval 0 If pin logical value is 0 / inactive. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_pin_get(struct device *port, unsigned int pin) +{ + gpio_pins_t value; + int ret; + + __ASSERT(pin < GPIO_MAX_PINS_PER_PORT, "Invalid pin number"); + + ret = gpio_port_get(port, &value); + if (ret == 0) { + ret = (value & BIT(pin)) != 0 ? 1 : 0; + } + + return ret; +} + +/** + * @brief Set physical level of an output pin. + * + * Writing value 0 to the pin will set it to a low physical level. Writing any + * value other than 0 will set it to a high physical level. This function + * ignores GPIO_ACTIVE_LOW flag. + * + * @param port Pointer to the device structure for the driver instance. + * @param pin Pin number. + * @param value Value assigned to the pin. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_pin_set_raw(struct device *port, unsigned int pin, + int value) +{ + int ret; + + __ASSERT(pin < GPIO_MAX_PINS_PER_PORT, "Invalid pin number"); + + if (value != 0) { + ret = gpio_port_set_bits_raw(port, BIT(pin)); + } else { + ret = gpio_port_clear_bits_raw(port, BIT(pin)); + } + + return ret; +} + +/** + * @brief Set logical level of an output pin. + * + * Set logical level of an output pin taking into account GPIO_ACTIVE_LOW flag. + * Value 0 sets the pin in logical 0 / inactive state. Any value other than 0 + * sets the pin in logical 1 / active state. If pin is configured as Active + * High, the default, setting it in inactive state will force the pin to a low + * physical level. If pin is configured as Active Low, setting it in inactive + * state will force the pin to a high physical level. + * + * Note: If pin is configured as Active High, gpio_pin_set() function is + * equivalent to gpio_pin_set_raw(). + * + * @param port Pointer to the device structure for the driver instance. + * @param pin Pin number. + * @param value Value assigned to the pin. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_pin_set(struct device *port, unsigned int pin, int value) +{ + struct gpio_driver_data *const data = + (struct gpio_driver_data *const)port->driver_data; + + __ASSERT(pin < GPIO_MAX_PINS_PER_PORT, "Invalid pin number"); + + if (data->invert & BIT(pin)) { + value = (value != 0) ? 0 : 1; + } + + return gpio_pin_set_raw(port, pin, value); +} + +/** + * @brief Toggle pin level. + * + * @param port Pointer to the device structure for the driver instance. + * @param pin Pin number. + * + * @retval 0 If successful. + * @retval -EIO I/O error when accessing an external GPIO chip. + */ +static inline int gpio_pin_toggle(struct device *port, unsigned int pin) +{ + __ASSERT(pin < GPIO_MAX_PINS_PER_PORT, "Invalid pin number"); + + return gpio_port_toggle_bits(port, BIT(pin)); +} + /** * @brief Write the data value to a single pin. * @param port Pointer to the device structure for the driver instance. @@ -568,7 +974,7 @@ static inline int gpio_pin_read(struct device *port, u32_t pin, */ static inline void gpio_init_callback(struct gpio_callback *callback, gpio_callback_handler_t handler, - u32_t pin_mask) + gpio_pins_t pin_mask) { __ASSERT(callback, "Callback pointer should not be NULL"); __ASSERT(handler, "Callback handler pointer should not be NULL"); From bc2a539de27de2bbd337db3b2f3763c7961319b0 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Sun, 30 Jun 2019 21:52:18 +0200 Subject: [PATCH 03/12] gpio: add gpio_pin_interrupt_configure function This commit moves interrupt configuration for a single pin from gpio_pin_configure to gpio_pin_interrupt_configure function. Signed-off-by: Piotr Mienkowski --- drivers/gpio/gpio_handlers.c | 9 +++++++++ include/drivers/gpio.h | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/gpio/gpio_handlers.c b/drivers/gpio/gpio_handlers.c index 235df21c9eab84..466ce18a5cfa6b 100644 --- a/drivers/gpio/gpio_handlers.c +++ b/drivers/gpio/gpio_handlers.c @@ -76,6 +76,15 @@ static inline int z_vrfy_gpio_port_toggle_bits(struct device *port, } #include +static inline int z_vrfy_gpio_pin_interrupt_configure(struct device *port, + unsigned int pin, unsigned int flags) +{ + Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, pin_interrupt_configure)); + return z_impl_gpio_pin_interrupt_configure((struct device *)port, pin, + flags); +} +#include + static inline int z_vrfy_gpio_enable_callback(struct device *port, int access_op, u32_t pin) { diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h index 0e41af3c50adec..ba821a10dbd4ee 100644 --- a/include/drivers/gpio.h +++ b/include/drivers/gpio.h @@ -450,6 +450,8 @@ struct gpio_driver_api { int (*port_set_bits_raw)(struct device *port, gpio_pins_t pins); int (*port_clear_bits_raw)(struct device *port, gpio_pins_t pins); int (*port_toggle_bits)(struct device *port, gpio_pins_t pins); + int (*pin_interrupt_configure)(struct device *port, unsigned int pin, + unsigned int flags); int (*manage_callback)(struct device *port, struct gpio_callback *cb, bool set); int (*enable_callback)(struct device *port, int access_op, u32_t pin); @@ -966,6 +968,41 @@ static inline int gpio_pin_read(struct device *port, u32_t pin, return gpio_read(port, GPIO_ACCESS_BY_PIN, pin, value); } +/** + * @brief Configure pin interrupt. + * + * @note This function can also be used to configure interrupts on pins + * not controlled directly by the GPIO module. That is, pins which are + * routed to other modules such as I2C, SPI, UART. + * + * @param port Pointer to device structure for the driver instance. + * @param pin Pin number. + * @param flags Interrupt configuration flags as defined by GPIO_INT_*. + * + * @retval 0 If successful. + * @retval -ENOTSUP If any of the configuration options is not supported. + * @retval -EINVAL Invalid argument. + * @retval -EBUSY Interrupt line required to configure pin interrupt is + * already in use. + */ +__syscall int gpio_pin_interrupt_configure(struct device *port, + unsigned int pin, unsigned int flags); + +static inline int z_impl_gpio_pin_interrupt_configure(struct device *port, + unsigned int pin, unsigned int flags) +{ + const struct gpio_driver_api *api = + (const struct gpio_driver_api *)port->driver_api; + + __ASSERT(pin < GPIO_MAX_PINS_PER_PORT, "Invalid pin number"); + + __ASSERT(((flags & GPIO_INT_ENABLE) == 0) || + ((flags & (GPIO_INT_LOW_0 | GPIO_INT_HIGH_1)) != 0), + "At least one of GPIO_INT_LOW_0, GPIO_INT_HIGH_1 has to be " + "enabled."); + return api->pin_interrupt_configure(port, pin, flags); +} + /** * @brief Helper to initialize a struct gpio_callback properly * @param callback A valid Application's callback structure pointer. From ae7c8cf05604f26a026e5c4e7c0f3f45c5409605 Mon Sep 17 00:00:00 2001 From: Peter Bigot Date: Mon, 26 Aug 2019 11:44:01 -0500 Subject: [PATCH 04/12] gpio: use named types to distinguish pin sets from pin values Both pin sets and values encoding pin values are ultimately represented by 32-bit unsigned integers. Provide typedefs that make the role of a parameter explicit. Signed-off-by: Peter Bigot Signed-off-by: Piotr Mienkowski --- drivers/gpio/gpio_handlers.c | 14 +++--- include/drivers/gpio.h | 89 +++++++++++++++++++++--------------- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/drivers/gpio/gpio_handlers.c b/drivers/gpio/gpio_handlers.c index 466ce18a5cfa6b..ce4c2d8aa552e0 100644 --- a/drivers/gpio/gpio_handlers.c +++ b/drivers/gpio/gpio_handlers.c @@ -34,17 +34,17 @@ static inline int z_vrfy_gpio_read(struct device *port, int access_op, #include static inline int z_vrfy_gpio_port_get_raw(struct device *port, - gpio_pins_t *value) + gpio_port_value_t *value) { Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_get_raw)); - Z_OOPS(Z_SYSCALL_MEMORY_WRITE(value, sizeof(gpio_pins_t))); + Z_OOPS(Z_SYSCALL_MEMORY_WRITE(value, sizeof(gpio_port_value_t))); return z_impl_gpio_port_get_raw((struct device *)port, - (gpio_pins_t *)value); + (gpio_port_value_t *)value); } #include static inline int z_vrfy_gpio_port_set_masked_raw(struct device *port, - gpio_pins_t mask, gpio_pins_t value) + gpio_port_pins_t mask, gpio_port_value_t value) { Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_set_masked_raw)); return z_impl_gpio_port_set_masked_raw((struct device *)port, mask, @@ -53,7 +53,7 @@ static inline int z_vrfy_gpio_port_set_masked_raw(struct device *port, #include static inline int z_vrfy_gpio_port_set_bits_raw(struct device *port, - gpio_pins_t pins) + gpio_port_pins_t pins) { Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_set_bits_raw)); return z_impl_gpio_port_set_bits_raw((struct device *)port, pins); @@ -61,7 +61,7 @@ static inline int z_vrfy_gpio_port_set_bits_raw(struct device *port, #include static inline int z_vrfy_gpio_port_clear_bits_raw(struct device *port, - gpio_pins_t pins) + gpio_port_pins_t pins) { Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_clear_bits_raw)); return z_impl_gpio_port_clear_bits_raw((struct device *)port, pins); @@ -69,7 +69,7 @@ static inline int z_vrfy_gpio_port_clear_bits_raw(struct device *port, #include static inline int z_vrfy_gpio_port_toggle_bits(struct device *port, - gpio_pins_t pins) + gpio_port_pins_t pins) { Z_OOPS(Z_SYSCALL_DRIVER_GPIO(port, port_toggle_bits)); return z_impl_gpio_port_toggle_bits((struct device *)port, pins); diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h index ba821a10dbd4ee..778b92a1a5dc3f 100644 --- a/include/drivers/gpio.h +++ b/include/drivers/gpio.h @@ -369,21 +369,33 @@ extern "C" { */ /** - * @brief Pins associated with a port. + * @brief Identifies a set of pins associated with a port. * - * Value of this type identifies pins, or their value, associated with a port. - * Pin with index n, or its value, is identified by bit n (1U << n) in the value - * of type gpio_pins_t. + * The pin with index n is present in the set if and only if the bit + * identified by (1U << n) is set. */ -typedef u32_t gpio_pins_t; +typedef u32_t gpio_port_pins_t; /** - * @brief Maximum number of pins that are supported by gpio_pins_t + * @brief Provides values for a set of pins associated with a port. + * + * The value for a pin with index n is high (physical mode) or active + * (logical mode) if and only if the bit identified by (1U << n) is set. + * Otherwise the value for the pin is low (physical mode) or inactive + * (logical mode). + * + * Values of this type are often paired with a `gpio_port_pins_t` value + * that specifies which encoded pin values are valid for the operation. + */ +typedef u32_t gpio_port_value_t; + +/** + * @brief Maximum number of pins that are supported by `gpio_port_pins_t`. */ -#define GPIO_MAX_PINS_PER_PORT (sizeof(gpio_pins_t) * __CHAR_BIT__) +#define GPIO_MAX_PINS_PER_PORT (sizeof(gpio_port_pins_t) * __CHAR_BIT__) struct gpio_driver_data { - gpio_pins_t invert; + gpio_port_pins_t invert; }; struct gpio_callback; @@ -403,7 +415,7 @@ struct gpio_callback; */ typedef void (*gpio_callback_handler_t)(struct device *port, struct gpio_callback *cb, - gpio_pins_t pins); + gpio_port_pins_t pins); /** * @brief GPIO callback structure @@ -430,7 +442,7 @@ struct gpio_callback { * called or not. The selected pins must be configured to trigger * an interrupt. */ - gpio_pins_t pin_mask; + gpio_port_pins_t pin_mask; }; /** @@ -444,12 +456,12 @@ struct gpio_driver_api { u32_t value); int (*read)(struct device *port, int access_op, u32_t pin, u32_t *value); - int (*port_get_raw)(struct device *port, gpio_pins_t *value); - int (*port_set_masked_raw)(struct device *port, gpio_pins_t mask, - gpio_pins_t value); - int (*port_set_bits_raw)(struct device *port, gpio_pins_t pins); - int (*port_clear_bits_raw)(struct device *port, gpio_pins_t pins); - int (*port_toggle_bits)(struct device *port, gpio_pins_t pins); + int (*port_get_raw)(struct device *port, gpio_port_value_t *value); + int (*port_set_masked_raw)(struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value); + int (*port_set_bits_raw)(struct device *port, gpio_port_pins_t pins); + int (*port_clear_bits_raw)(struct device *port, gpio_port_pins_t pins); + int (*port_toggle_bits)(struct device *port, gpio_port_pins_t pins); int (*pin_interrupt_configure)(struct device *port, unsigned int pin, unsigned int flags); int (*manage_callback)(struct device *port, struct gpio_callback *cb, @@ -573,10 +585,10 @@ static inline int gpio_pin_configure(struct device *port, u32_t pin, * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -__syscall int gpio_port_get_raw(struct device *port, gpio_pins_t *value); +__syscall int gpio_port_get_raw(struct device *port, gpio_port_value_t *value); static inline int z_impl_gpio_port_get_raw(struct device *port, - gpio_pins_t *value) + gpio_port_value_t *value) { const struct gpio_driver_api *api = (const struct gpio_driver_api *)port->driver_api; @@ -601,7 +613,7 @@ static inline int z_impl_gpio_port_get_raw(struct device *port, * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -static inline int gpio_port_get(struct device *port, gpio_pins_t *value) +static inline int gpio_port_get(struct device *port, gpio_port_value_t *value) { struct gpio_driver_data *const data = (struct gpio_driver_data *const)port->driver_data; @@ -631,11 +643,11 @@ static inline int gpio_port_get(struct device *port, gpio_pins_t *value) * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -__syscall int gpio_port_set_masked_raw(struct device *port, gpio_pins_t mask, - gpio_pins_t value); +__syscall int gpio_port_set_masked_raw(struct device *port, + gpio_port_pins_t mask, gpio_port_value_t value); static inline int z_impl_gpio_port_set_masked_raw(struct device *port, - gpio_pins_t mask, gpio_pins_t value) + gpio_port_pins_t mask, gpio_port_value_t value) { const struct gpio_driver_api *api = (const struct gpio_driver_api *)port->driver_api; @@ -662,8 +674,8 @@ static inline int z_impl_gpio_port_set_masked_raw(struct device *port, * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -static inline int gpio_port_set_masked(struct device *port, gpio_pins_t mask, - gpio_pins_t value) +static inline int gpio_port_set_masked(struct device *port, + gpio_port_pins_t mask, gpio_port_value_t value) { struct gpio_driver_data *const data = (struct gpio_driver_data *const)port->driver_data; @@ -682,10 +694,11 @@ static inline int gpio_port_set_masked(struct device *port, gpio_pins_t mask, * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -__syscall int gpio_port_set_bits_raw(struct device *port, gpio_pins_t pins); +__syscall int gpio_port_set_bits_raw(struct device *port, + gpio_port_pins_t pins); static inline int z_impl_gpio_port_set_bits_raw(struct device *port, - gpio_pins_t pins) + gpio_port_pins_t pins) { const struct gpio_driver_api *api = (const struct gpio_driver_api *)port->driver_api; @@ -702,7 +715,7 @@ static inline int z_impl_gpio_port_set_bits_raw(struct device *port, * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -static inline int gpio_port_set_bits(struct device *port, gpio_pins_t pins) +static inline int gpio_port_set_bits(struct device *port, gpio_port_pins_t pins) { return gpio_port_set_masked(port, pins, pins); } @@ -716,10 +729,11 @@ static inline int gpio_port_set_bits(struct device *port, gpio_pins_t pins) * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -__syscall int gpio_port_clear_bits_raw(struct device *port, gpio_pins_t pins); +__syscall int gpio_port_clear_bits_raw(struct device *port, + gpio_port_pins_t pins); static inline int z_impl_gpio_port_clear_bits_raw(struct device *port, - gpio_pins_t pins) + gpio_port_pins_t pins) { const struct gpio_driver_api *api = (const struct gpio_driver_api *)port->driver_api; @@ -736,7 +750,8 @@ static inline int z_impl_gpio_port_clear_bits_raw(struct device *port, * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -static inline int gpio_port_clear_bits(struct device *port, gpio_pins_t pins) +static inline int gpio_port_clear_bits(struct device *port, + gpio_port_pins_t pins) { return gpio_port_set_masked(port, pins, 0); } @@ -750,10 +765,10 @@ static inline int gpio_port_clear_bits(struct device *port, gpio_pins_t pins) * @retval 0 If successful. * @retval -EIO I/O error when accessing an external GPIO chip. */ -__syscall int gpio_port_toggle_bits(struct device *port, gpio_pins_t pins); +__syscall int gpio_port_toggle_bits(struct device *port, gpio_port_pins_t pins); static inline int z_impl_gpio_port_toggle_bits(struct device *port, - gpio_pins_t pins) + gpio_port_pins_t pins) { const struct gpio_driver_api *api = (const struct gpio_driver_api *)port->driver_api; @@ -772,7 +787,7 @@ static inline int z_impl_gpio_port_toggle_bits(struct device *port, * @retval -EIO I/O error when accessing an external GPIO chip. */ static inline int gpio_port_set_clr_bits_raw(struct device *port, - gpio_pins_t set_pins, gpio_pins_t clear_pins) + gpio_port_pins_t set_pins, gpio_port_pins_t clear_pins) { __ASSERT((set_pins & clear_pins) == 0, "Set and Clear pins overlap"); @@ -790,7 +805,7 @@ static inline int gpio_port_set_clr_bits_raw(struct device *port, * @retval -EIO I/O error when accessing an external GPIO chip. */ static inline int gpio_port_set_clr_bits(struct device *port, - gpio_pins_t set_pins, gpio_pins_t clear_pins) + gpio_port_pins_t set_pins, gpio_port_pins_t clear_pins) { __ASSERT((set_pins & clear_pins) == 0, "Set and Clear pins overlap"); @@ -813,7 +828,7 @@ static inline int gpio_port_set_clr_bits(struct device *port, */ static inline int gpio_pin_get_raw(struct device *port, unsigned int pin) { - gpio_pins_t value; + gpio_port_value_t value; int ret; __ASSERT(pin < GPIO_MAX_PINS_PER_PORT, "Invalid pin number"); @@ -846,7 +861,7 @@ static inline int gpio_pin_get_raw(struct device *port, unsigned int pin) */ static inline int gpio_pin_get(struct device *port, unsigned int pin) { - gpio_pins_t value; + gpio_port_value_t value; int ret; __ASSERT(pin < GPIO_MAX_PINS_PER_PORT, "Invalid pin number"); @@ -1011,7 +1026,7 @@ static inline int z_impl_gpio_pin_interrupt_configure(struct device *port, */ static inline void gpio_init_callback(struct gpio_callback *callback, gpio_callback_handler_t handler, - gpio_pins_t pin_mask) + gpio_port_pins_t pin_mask) { __ASSERT(callback, "Callback pointer should not be NULL"); __ASSERT(handler, "Callback handler pointer should not be NULL"); From 3dcea2e1f782c5483587a4ffb86e00086887f396 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Tue, 3 Sep 2019 10:07:49 +0200 Subject: [PATCH 05/12] tests: add gpio_api_1pin testcase gpio_api_1pin testcase verifies following new GPIO API functionality: - pin active level flags - input/output configuration flags - pin drive flags - gpio_port_*, gpio_pin_* functions - pin interrupts The test is using only 1 GPIO pin (defined in DTS as LED0) and relies on the ability of the driver to configure pin simultanously as in/out. Drivers that do not allow to configure pins in in/out mode should still pass the test, however, most of the testcases will be skipped. The test does not require any modifications to board hardware. Signed-off-by: Piotr Mienkowski --- .../drivers/gpio/gpio_api_1pin/CMakeLists.txt | 8 + tests/drivers/gpio/gpio_api_1pin/prj.conf | 2 + tests/drivers/gpio/gpio_api_1pin/src/main.c | 39 ++ .../gpio/gpio_api_1pin/src/test_config.c | 310 ++++++++++ .../gpio/gpio_api_1pin/src/test_gpio_api.h | 54 ++ .../drivers/gpio/gpio_api_1pin/src/test_pin.c | 311 ++++++++++ .../gpio_api_1pin/src/test_pin_interrupt.c | 275 +++++++++ .../gpio/gpio_api_1pin/src/test_port.c | 538 ++++++++++++++++++ .../drivers/gpio/gpio_api_1pin/testcase.yaml | 6 + 9 files changed, 1543 insertions(+) create mode 100644 tests/drivers/gpio/gpio_api_1pin/CMakeLists.txt create mode 100644 tests/drivers/gpio/gpio_api_1pin/prj.conf create mode 100644 tests/drivers/gpio/gpio_api_1pin/src/main.c create mode 100644 tests/drivers/gpio/gpio_api_1pin/src/test_config.c create mode 100644 tests/drivers/gpio/gpio_api_1pin/src/test_gpio_api.h create mode 100644 tests/drivers/gpio/gpio_api_1pin/src/test_pin.c create mode 100644 tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c create mode 100644 tests/drivers/gpio/gpio_api_1pin/src/test_port.c create mode 100644 tests/drivers/gpio/gpio_api_1pin/testcase.yaml diff --git a/tests/drivers/gpio/gpio_api_1pin/CMakeLists.txt b/tests/drivers/gpio/gpio_api_1pin/CMakeLists.txt new file mode 100644 index 00000000000000..66e98a7b2ef5a3 --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(gpio_basic_api) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/gpio/gpio_api_1pin/prj.conf b/tests/drivers/gpio/gpio_api_1pin/prj.conf new file mode 100644 index 00000000000000..0e799280f514d9 --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_GPIO=y diff --git a/tests/drivers/gpio/gpio_api_1pin/src/main.c b/tests/drivers/gpio/gpio_api_1pin/src/main.c new file mode 100644 index 00000000000000..85b75ea8f84cc0 --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/src/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Piotr Mienkowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_gpio_api.h" + +void test_main(void) +{ + ztest_test_suite(gpio_api_1pin_test, + ztest_unit_test(test_gpio_pin_configure_push_pull), + ztest_unit_test(test_gpio_pin_configure_single_ended), + ztest_unit_test(test_gpio_pin_set_get_raw), + ztest_unit_test(test_gpio_pin_set_get), + ztest_unit_test(test_gpio_pin_set_get_active_high), + ztest_unit_test(test_gpio_pin_set_get_active_low), + ztest_unit_test(test_gpio_pin_toggle), + ztest_unit_test(test_gpio_port_set_masked_get_raw), + ztest_unit_test(test_gpio_port_set_masked_get), + ztest_unit_test(test_gpio_port_set_masked_get_active_high), + ztest_unit_test(test_gpio_port_set_masked_get_active_low), + ztest_unit_test(test_gpio_port_set_bits_clear_bits_raw), + ztest_unit_test(test_gpio_port_set_bits_clear_bits), + ztest_unit_test(test_gpio_port_set_clr_bits_raw), + ztest_unit_test(test_gpio_port_set_clr_bits), + ztest_unit_test(test_gpio_port_toggle), + ztest_unit_test(test_gpio_int_edge_rising), + ztest_unit_test(test_gpio_int_edge_falling), + ztest_unit_test(test_gpio_int_edge_both), + ztest_unit_test(test_gpio_int_edge_to_active), + ztest_unit_test(test_gpio_int_edge_to_inactive), + ztest_unit_test(test_gpio_int_level_high), + ztest_unit_test(test_gpio_int_level_low), + ztest_unit_test(test_gpio_int_level_active), + ztest_unit_test(test_gpio_int_level_inactive), + ztest_unit_test(test_gpio_pin_toggle_visual)); + ztest_run_test_suite(gpio_api_1pin_test); +} diff --git a/tests/drivers/gpio/gpio_api_1pin/src/test_config.c b/tests/drivers/gpio/gpio_api_1pin/src/test_config.c new file mode 100644 index 00000000000000..b957beb0423a53 --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/src/test_config.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2019 Piotr Mienkowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @addtogroup t_gpio_api + * @{ + * @defgroup t_gpio_api_config test_gpio_api_config + * @brief TestPurpose: verify the gpio config functions using single pin + * configured as input/output. + * @} + */ + +#include +#include +#include "test_gpio_api.h" + +#define TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS 100 +#define TEST_POINT(n) (n) + +static void pin_get_raw_and_verify(struct device *port, unsigned int pin, + int val_expected, int idx) +{ + int val_actual; + + val_actual = gpio_pin_get_raw(port, pin); + zassert_true(val_actual >= 0, + "Test point %d: failed to get pin value", idx); + zassert_equal(val_expected, val_actual, + "Test point %d: invalid pin get value", idx); +} + +static void pin_set_raw_and_verify(struct device *port, unsigned int pin, + int val, int idx) +{ + zassert_equal(gpio_pin_set_raw(port, pin, val), 0, + "Test point %d: failed to set pin value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +/** @brief Verify gpio_pin_configure function in push pull mode. + * + * - Configure pin in in/out mode, verify that gpio_pin_set_raw / + * gpio_pin_get_raw operations change pin state. + * - Verify that GPIO_OUTPUT_HIGH flag is initializing the pin to high. + * - Verify that GPIO_OUTPUT_LOW flag is initializing the pin to low. + * - Verify that configuring the pin as an output without initializing it + * to high or low does not change pin state. + * - Verify that it is not possible to change value of a pin via + * gpio_pin_set_raw function if pin is configured as an input. + */ +void test_gpio_pin_configure_push_pull(void) +{ + struct device *port; + int ret; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT); + zassert_equal(ret, 0, "Failed to configure the pin as an output"); + + pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(1)); + pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(1)); + + /* Configure pin in in/out mode, verify that gpio_pin_set_raw / + * gpio_pin_get_raw operations change pin state. + */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin in in/out mode"); + + pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2)); + pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2)); + + pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3)); + pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3)); + + pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4)); + pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4)); + + /* Verify that GPIO_OUTPUT_HIGH flag is initializing the pin to high. */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH | GPIO_INPUT); + zassert_equal(ret, 0, + "Failed to configure the pin in in/out mode and " + "initialize it to high"); + + pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(5)); + + /* Verify that configuring the pin as an output without initializing it + * to high or low does not change pin state. + */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + zassert_equal(ret, 0, "Failed to configure the pin in in/out mode"); + + pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6)); + + /* Verify that GPIO_OUTPUT_LOW flag is initializing the pin to low. */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW | GPIO_INPUT); + zassert_equal(ret, 0, + "Failed to configure the pin in in/out mode and " + "initialize it to low"); + + pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(7)); + + /* Verify that configuring the pin as an output without initializing it + * to high or low does not change pin state. + */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + zassert_equal(ret, 0, "Failed to configure the pin in in/out mode"); + + pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(8)); + + /* Verify that it is not possible to change value of a pin via + * gpio_pin_set_raw function if pin is configured as an input. + */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT); + zassert_equal(ret, 0, "Failed to configure the pin as an input"); + + int pin_in_val; + + pin_in_val = gpio_pin_get_raw(port, TEST_PIN); + zassert_true(pin_in_val >= 0, + "Test point %d: failed to get pin value", TEST_POINT(9)); + + pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(10)); + pin_get_raw_and_verify(port, TEST_PIN, pin_in_val, TEST_POINT(10)); + + pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(11)); + pin_get_raw_and_verify(port, TEST_PIN, pin_in_val, TEST_POINT(11)); +} + +/** @brief Verify gpio_pin_configure function in single ended mode. + * + * @note This test verifies single ended mode only partially. It should not be + * used as a sign off test. + * + * - Verify that pin configured in Open Drain mode and initialized + * to high results in pin high value if the same pin configured + * as input is high. Drivers that do not support Open Drain flag + * return ENOTSUP. + * - Setting pin configured in Open Drain mode to low results in + * pin low value if the same pin configured as input is high. + * - Verify that pin configured in Open Source mode and + * initialized to low results in pin high value if the same pin + * configured as input is high. Drivers that do not support Open + * Source flag return ENOTSUP. + * - Verify that pin configured in Open Source mode and + * initialized to low results in pin low value if the same pin + * configured as input is low. Drivers that do not support Open + * Source flag return ENOTSUP. + * - Setting pin configured in Open Source mode to high results in + * pin high value if the same pin configured as input is low. + * - Verify that pin configured in Open Drain mode and + * initialized to high results in pin low value if the same pin + * configured as input is low. Drivers that do not support Open + * Drain flag return ENOTSUP. + */ +void test_gpio_pin_configure_single_ended(void) +{ + struct device *port; + int pin_in_val; + int pin_val; + unsigned int cfg_flag; + int ret; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + /* If the LED is connected directly between the MCU pin and power or + * ground we can test only one of the Open Drain / Open Source modes. + * Guess pin level when the LED is off. If the pin is not connected + * directly to LED but instead the signal is routed to an input of + * another chip we could test both modes. However, there is no way to + * find it out so only one mode is tested. + */ + if ((TEST_PIN_DTS_FLAGS & GPIO_ACTIVE_LOW) != 0) { + cfg_flag = GPIO_PULL_UP; + pin_val = 1; + } else { + cfg_flag = GPIO_PULL_DOWN; + pin_val = 0; + } + + /* Configure pin as an input with pull up/down and check input level. */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_flag); + if (ret == -ENOTSUP) { + TC_PRINT("Pull Up / Pull Down pin bias is not supported\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure pin as an input"); + + k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS)); + + pin_in_val = gpio_pin_get_raw(port, TEST_PIN); + zassert_true(pin_in_val >= 0, "Failed to get pin value"); + + if (pin_val != pin_in_val) { + TC_PRINT("Board configuration does not allow to run the test\n"); + ztest_test_skip(); + return; + } + + if (pin_val == 1) { + TC_PRINT("When configured as input test pin value is high\n"); + /* Verify that pin configured in Open Drain mode and initialized + * to high results in pin high value if the same pin configured + * as input is high. Drivers that do not support Open Drain flag + * return -ENOTSUP. + */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH | + GPIO_OPEN_DRAIN | GPIO_INPUT | GPIO_PULL_UP); + if (ret == -ENOTSUP) { + TC_PRINT("Open Drain configuration or Pull Up pin " + "bias is not supported\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, + "Failed to configure the pin in Open Drain mode"); + + pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(1)); + + /* Setting pin configured in Open Drain mode to low results in + * pin low value if the same pin configured as input is high. + */ + pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2)); + pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2)); + + /* Verify that pin configured in Open Source mode and + * initialized to low results in pin high value if the same pin + * configured as input is high. Drivers that do not support Open + * Source flag return -ENOTSUP. + */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW | + GPIO_OPEN_SOURCE | GPIO_INPUT | GPIO_PULL_UP); + if (ret == -ENOTSUP) { + TC_PRINT("Open Source configuration or Pull Up pin " + "bias is not supported\n"); + return; + } + zassert_equal(ret, 0, + "Failed to configure the pin in Open Source mode"); + + k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS)); + + pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3)); + + pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4)); + pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(4)); + } else { + TC_PRINT("When configured as input test pin value is low\n"); + /* Verify that pin configured in Open Source mode and + * initialized to low results in pin low value if the same pin + * configured as input is low. Drivers that do not support Open + * Source flag return -ENOTSUP. + */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW | + GPIO_OPEN_SOURCE | GPIO_INPUT | GPIO_PULL_DOWN); + if (ret == -ENOTSUP) { + TC_PRINT("Open Source configuration or Pull Down pin " + "bias is not supported\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, + "Failed to configure the pin in Open Source mode"); + + pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(5)); + + /* Setting pin configured in Open Source mode to high results in + * pin high value if the same pin configured as input is low. + */ + pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6)); + pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6)); + + /* Verify that pin configured in Open Drain mode and + * initialized to high results in pin low value if the same pin + * configured as input is low. Drivers that do not support Open + * Drain flag return -ENOTSUP. + */ + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH | + GPIO_OPEN_DRAIN | GPIO_INPUT | GPIO_PULL_DOWN); + if (ret == -ENOTSUP) { + TC_PRINT("Open Drain configuration or Pull Down pin " + "bias is not supported\n"); + return; + } + zassert_equal(ret, 0, + "Failed to configure the pin in Open Drain mode"); + + k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS)); + + pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(7)); + + pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(8)); + pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(8)); + } +} diff --git a/tests/drivers/gpio/gpio_api_1pin/src/test_gpio_api.h b/tests/drivers/gpio/gpio_api_1pin/src/test_gpio_api.h new file mode 100644 index 00000000000000..afba5b16e10519 --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/src/test_gpio_api.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 Piotr Mienkowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_GPIO_API_H_ +#define TEST_GPIO_API_H_ + +#include +#include +#include + +#if defined(DT_ALIAS_LED0_GPIOS_CONTROLLER) +#define TEST_DEV DT_ALIAS_LED0_GPIOS_CONTROLLER +#define TEST_PIN DT_ALIAS_LED0_GPIOS_PIN +#define TEST_PIN_DTS_FLAGS DT_ALIAS_LED0_GPIOS_FLAGS +#else +#error Unsupported board +#endif + +#define TEST_GPIO_MAX_RISE_FALL_TIME_US 200 + +void test_gpio_pin_configure_push_pull(void); +void test_gpio_pin_configure_single_ended(void); + +void test_gpio_pin_set_get_raw(void); +void test_gpio_pin_set_get(void); +void test_gpio_pin_set_get_active_high(void); +void test_gpio_pin_set_get_active_low(void); +void test_gpio_pin_toggle(void); +void test_gpio_pin_toggle_visual(void); + +void test_gpio_port_set_masked_get_raw(void); +void test_gpio_port_set_masked_get(void); +void test_gpio_port_set_masked_get_active_high(void); +void test_gpio_port_set_masked_get_active_low(void); +void test_gpio_port_set_bits_clear_bits_raw(void); +void test_gpio_port_set_bits_clear_bits(void); +void test_gpio_port_set_clr_bits_raw(void); +void test_gpio_port_set_clr_bits(void); +void test_gpio_port_toggle(void); + +void test_gpio_int_edge_rising(void); +void test_gpio_int_edge_falling(void); +void test_gpio_int_edge_both(void); +void test_gpio_int_edge_to_active(void); +void test_gpio_int_edge_to_inactive(void); +void test_gpio_int_level_high(void); +void test_gpio_int_level_low(void); +void test_gpio_int_level_active(void); +void test_gpio_int_level_inactive(void); + +#endif /* TEST_GPIO_API_H_ */ diff --git a/tests/drivers/gpio/gpio_api_1pin/src/test_pin.c b/tests/drivers/gpio/gpio_api_1pin/src/test_pin.c new file mode 100644 index 00000000000000..382cc7f58bfe89 --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/src/test_pin.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2019 Piotr Mienkowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @addtogroup t_gpio_api + * @{ + * @defgroup t_gpio_api_pin test_gpio_api_pin + * @brief TestPurpose: verify all gpio pin functions using single pin configured + * as input/output. + * @} + */ + +#include +#include +#include "test_gpio_api.h" + +static void pin_get_raw_and_verify(struct device *port, unsigned int pin, + int val_expected, int idx) +{ + int val_actual; + + val_actual = gpio_pin_get_raw(port, pin); + zassert_true(val_actual >= 0, + "Test point %d: failed to get physical pin value", idx); + zassert_equal(val_expected, val_actual, + "Test point %d: invalid physical pin get value", idx); +} + +static void pin_get_and_verify(struct device *port, unsigned int pin, + int val_expected, int idx) +{ + int val_actual; + + val_actual = gpio_pin_get(port, pin); + zassert_true(val_actual >= 0, + "Test point %d: failed to get logical pin value", idx); + zassert_equal(val_expected, val_actual, + "Test point %d: invalid logical pin get value", idx); +} + +static void pin_set_raw_and_verify(struct device *port, unsigned int pin, + int val, int idx) +{ + zassert_equal(gpio_pin_set_raw(port, pin, val), 0, + "Test point %d: failed to set physical pin value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +static void pin_set_and_verify(struct device *port, unsigned int pin, int val, + int idx) +{ + zassert_equal(gpio_pin_set(port, pin, val), 0, + "Test point %d: failed to set logical pin value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +/** @brief Verify gpio_pin_toggle function. + * + * - Verify that gpio_pin_toggle function changes pin state from active to + * inactive and vice versa. + */ +void test_gpio_pin_toggle(void) +{ + struct device *port; + int val_expected; + int ret; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + pin_set_raw_and_verify(port, TEST_PIN, 1, 0); + + for (int i = 0; i < 5; i++) { + ret = gpio_pin_toggle(port, TEST_PIN); + zassert_equal(ret, 0, "Failed to toggle pin value"); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); + + val_expected = i % 2; + + pin_get_raw_and_verify(port, TEST_PIN, val_expected, i); + } +} + +/** @brief Verify visually gpio_pin_toggle function. + * + * This test configures the pin using board DTS flags which should + * correctly set pin active state via GPIO_ACTIVE_LOW/_HIGH flags. + * It is possible to do a visual check to confirm that "LED ON", "LED OFF" + * messages correspond to the LED being turned ON or OFF. + * + * - Verify visually that gpio_pin_toggle function changes pin state from active + * to inactive and vice versa. + */ +void test_gpio_pin_toggle_visual(void) +{ + struct device *port; + int val_expected; + int ret; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | + TEST_PIN_DTS_FLAGS); + zassert_equal(ret, 0, "Failed to configure the pin"); + + pin_set_and_verify(port, TEST_PIN, 1, 0); + TC_PRINT("LED ON\n"); + + for (int i = 0; i < 3; i++) { + k_sleep(K_SECONDS(2)); + + ret = gpio_pin_toggle(port, TEST_PIN); + zassert_equal(ret, 0, "Failed to toggle pin value"); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); + + val_expected = i % 2; + TC_PRINT("LED %s\n", val_expected == 1 ? "ON" : "OFF"); + } +} + +/** @brief Verify gpio_pin_set_raw, gpio_pin_get_raw functions. + * + * - Verify that gpio_pin_get_raw reads the same value as set by + * gpio_pin_set_raw function. + */ +void test_gpio_pin_set_get_raw(void) +{ + struct device *port; + int val_expected; + int ret; + + const int test_vector[] = { + 4, 1, 45, 0, 0, -7, 0, 0, 0, INT_MAX, INT_MIN, 0 + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + pin_set_raw_and_verify(port, TEST_PIN, test_vector[i], i); + + val_expected = test_vector[i] != 0 ? 1 : 0; + + pin_get_raw_and_verify(port, TEST_PIN, val_expected, i); + } +} + +/** @brief Verify gpio_pin_set, gpio_pin_get functions. + * + * - Verify that gpio_pin_get reads the same value as set by gpio_pin_set + * function. + */ +void test_gpio_pin_set_get(void) +{ + struct device *port; + int val_expected; + int ret; + + const int test_vector[] = { + 1, 2, 3, 0, 4, 0, 0, 0, 17, INT_MAX, INT_MIN, 0 + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + pin_set_and_verify(port, TEST_PIN, test_vector[i], i); + + val_expected = test_vector[i] != 0 ? 1 : 0; + + pin_get_and_verify(port, TEST_PIN, val_expected, i); + } +} + +/** @brief Verify GPIO_ACTIVE_HIGH flag. + * + * - Verify that there is no functional difference between gpio_pin_set_raw and + * gpio_pin_set functions if the pin is configured as Active High. + * - Verify that there is no functional difference between gpio_pin_get_raw and + * gpio_pin_get functions if the pin is configured as Active High. + */ +void test_gpio_pin_set_get_active_high(void) +{ + struct device *port; + int val_expected; + int ret; + + const int test_vector[] = {0, 2, 0, 9, -1, 0, 0, 1, INT_MAX, INT_MIN}; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT | + GPIO_ACTIVE_HIGH); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + TC_PRINT("Step 1: Set logical, get logical and physical pin value\n"); + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + pin_set_and_verify(port, TEST_PIN, test_vector[i], i); + + val_expected = test_vector[i] != 0 ? 1 : 0; + + pin_get_and_verify(port, TEST_PIN, val_expected, i); + pin_get_raw_and_verify(port, TEST_PIN, val_expected, i); + } + + TC_PRINT("Step 2: Set physical, get logical and physical pin value\n"); + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + pin_set_raw_and_verify(port, TEST_PIN, test_vector[i], i); + + val_expected = test_vector[i] != 0 ? 1 : 0; + + pin_get_and_verify(port, TEST_PIN, val_expected, i); + pin_get_raw_and_verify(port, TEST_PIN, val_expected, i); + } +} + +/** @brief Verify GPIO_ACTIVE_LOW flag. + * + * - Verify that value set by gpio_pin_set function is inverted compared to + * gpio_pin_set_raw if the pin is configured as Active Low. + * - Verify that value read by gpio_pin_get function is inverted compared to + * gpio_pin_get_raw if the pin is configured as Active Low. + */ +void test_gpio_pin_set_get_active_low(void) +{ + struct device *port; + int val_expected, val_raw_expected; + int ret; + + const int test_vector[] = {0, 4, 0, 0, 1, 8, -3, -12, 0}; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT | + GPIO_ACTIVE_LOW); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + TC_PRINT("Step 1: Set logical, get logical and physical pin value\n"); + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + pin_set_and_verify(port, TEST_PIN, test_vector[i], i); + + val_expected = (test_vector[i] != 0) ? 1 : 0; + val_raw_expected = (val_expected != 0) ? 0 : 1; + + pin_get_and_verify(port, TEST_PIN, val_expected, i); + pin_get_raw_and_verify(port, TEST_PIN, val_raw_expected, i); + } + + TC_PRINT("Step 2: Set physical, get logical and physical pin value\n"); + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + pin_set_raw_and_verify(port, TEST_PIN, test_vector[i], i); + + val_expected = (test_vector[i] != 0) ? 0 : 1; + val_raw_expected = (val_expected != 0) ? 0 : 1; + + pin_get_and_verify(port, TEST_PIN, val_expected, i); + pin_get_raw_and_verify(port, TEST_PIN, val_raw_expected, i); + } +} diff --git a/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c b/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c new file mode 100644 index 00000000000000..d6f85619a9f8f3 --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/src/test_pin_interrupt.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2019 Piotr Mienkowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @addtogroup t_gpio_api + * @{ + * @defgroup t_gpio_api_pin_interrupt test_gpio_api_pin_interrupt + * @brief TestPurpose: verify gpio_pin_interrupt_configure function using single + * pin configured as input/output. + * @} + */ + +#include +#include +#include "test_gpio_api.h" + +struct gpio_callback gpio_cb; +static int cb_count; + +static void callback_edge(struct device *port, struct gpio_callback *cb, + u32_t pins) +{ + zassert_equal(pins, 1 << TEST_PIN, + "Detected interrupt on an invalid pin"); + cb_count++; +} + +static void callback_level(struct device *port, struct gpio_callback *cb, + u32_t pins) +{ + int ret; + + zassert_equal(pins, 1 << TEST_PIN, + "Detected interrupt on an invalid pin"); + + ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE); + zassert_equal(ret, 0, + "Failed to disable pin interrupt in the callback"); + + cb_count++; +} + +static void pin_set_and_verify(struct device *port, unsigned int pin, int val, + int idx) +{ + zassert_equal(gpio_pin_set(port, pin, val), 0, + "Test point %d: failed to set logical pin value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +void test_gpio_pin_interrupt_edge(unsigned int cfg_flags, + unsigned int int_flags) +{ + struct device *port; + int cb_count_expected; + unsigned int cfg_out_flag; + int ret; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | GPIO_OUTPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + if ((cfg_flags & GPIO_ACTIVE_LOW) != 0) { + cfg_out_flag = GPIO_OUTPUT_HIGH; + } else { + cfg_out_flag = GPIO_OUTPUT_LOW; + } + ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_out_flag | + cfg_flags); + zassert_equal(ret, 0, "Failed to configure the pin"); + + cb_count = 0; + cb_count_expected = 0; + + gpio_init_callback(&gpio_cb, callback_edge, BIT(TEST_PIN)); + ret = gpio_add_callback(port, &gpio_cb); + + ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags); + if (ret == -ENOTSUP) { + TC_PRINT("Pin interrupt is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure pin interrupt"); + + for (int i = 0; i < 6; i++) { + pin_set_and_verify(port, TEST_PIN, 1, i); + if (int_flags & GPIO_INT_HIGH_1) { + cb_count_expected++; + } + zassert_equal(cb_count, cb_count_expected, + "Test point %d: Pin interrupt triggered invalid " + "number of times on rising/to active edge", i); + + pin_set_and_verify(port, TEST_PIN, 0, i); + if (int_flags & GPIO_INT_LOW_0) { + cb_count_expected++; + } + zassert_equal(cb_count, cb_count_expected, + "Test point %d: Pin interrupt triggered invalid " + "number of times on falling/to inactive edge", i); + } + + ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE); + zassert_equal(ret, 0, "Failed to disable pin interrupt"); + + for (int i = 0; i < 6; i++) { + pin_set_and_verify(port, TEST_PIN, 1, i); + pin_set_and_verify(port, TEST_PIN, 0, i); + zassert_equal(cb_count, cb_count_expected, + "Pin interrupt triggered when disabled"); + } +} + +void test_gpio_pin_interrupt_level(unsigned int cfg_flags, + int unsigned int_flags) +{ + struct device *port; + int cb_count_expected; + unsigned int cfg_out_flag; + int pin_out_val; + int ret; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | GPIO_OUTPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + pin_out_val = ((int_flags & GPIO_INT_HIGH_1) != 0) ? 0 : 1; + + if ((cfg_flags & GPIO_ACTIVE_LOW) != 0) { + cfg_out_flag = (pin_out_val != 0) ? GPIO_OUTPUT_LOW : + GPIO_OUTPUT_HIGH; + } else { + cfg_out_flag = (pin_out_val != 0) ? GPIO_OUTPUT_HIGH : + GPIO_OUTPUT_LOW; + } + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_out_flag | + cfg_flags); + zassert_equal(ret, 0, "Failed to configure the pin"); + + cb_count = 0; + cb_count_expected = 0; + + gpio_init_callback(&gpio_cb, callback_level, BIT(TEST_PIN)); + ret = gpio_add_callback(port, &gpio_cb); + + ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags); + if (ret == -ENOTSUP) { + TC_PRINT("Pin interrupt is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure pin interrupt"); + + zassert_equal(cb_count, cb_count_expected, + "Pin interrupt triggered on level %d", pin_out_val); + + for (int i = 0; i < 6; i++) { + pin_out_val = (pin_out_val != 0) ? 0 : 1; + pin_set_and_verify(port, TEST_PIN, pin_out_val, i); + cb_count_expected++; + zassert_equal(cb_count, cb_count_expected, + "Test point %d: Pin interrupt triggered invalid " + "number of times on level %d", i, pin_out_val); + + pin_out_val = (pin_out_val != 0) ? 0 : 1; + pin_set_and_verify(port, TEST_PIN, pin_out_val, i); + zassert_equal(cb_count, cb_count_expected, + "Test point %d: Pin interrupt triggered invalid " + "number of times on level %d", i, pin_out_val); + + /* Re-enable pin level interrupt */ + ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags); + zassert_equal(ret, 0, + "Failed to re-enable pin level interrupt"); + } + + ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE); + zassert_equal(ret, 0, "Failed to disable pin interrupt"); + + for (int i = 0; i < 6; i++) { + pin_set_and_verify(port, TEST_PIN, 1, i); + pin_set_and_verify(port, TEST_PIN, 0, i); + zassert_equal(cb_count, cb_count_expected, + "Pin interrupt triggered when disabled"); + } +} + +/** @brief Verify GPIO_INT_EDGE_RISING flag. */ +void test_gpio_int_edge_rising(void) +{ + test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_RISING); +} + +/** @brief Verify GPIO_INT_EDGE_FALLING flag. */ +void test_gpio_int_edge_falling(void) +{ + test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_FALLING); +} + +/** @brief Verify GPIO_INT_EDGE_BOTH flag. */ +void test_gpio_int_edge_both(void) +{ + test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_BOTH); +} + +/** @brief Verify GPIO_INT_EDGE_TO_ACTIVE flag. */ +void test_gpio_int_edge_to_active(void) +{ + TC_PRINT("Step 1: Configure pin as active high\n"); + test_gpio_pin_interrupt_edge(GPIO_ACTIVE_HIGH, GPIO_INT_EDGE_TO_ACTIVE); + TC_PRINT("Step 2: Configure pin as active low\n"); + test_gpio_pin_interrupt_edge(GPIO_ACTIVE_LOW, GPIO_INT_EDGE_TO_ACTIVE); +} + +/** @brief Verify GPIO_INT_EDGE_TO_INACTIVE flag. */ +void test_gpio_int_edge_to_inactive(void) +{ + TC_PRINT("Step 1: Configure pin as active high\n"); + test_gpio_pin_interrupt_edge(GPIO_ACTIVE_HIGH, GPIO_INT_EDGE_TO_INACTIVE); + TC_PRINT("Step 2: Configure pin as active low\n"); + test_gpio_pin_interrupt_edge(GPIO_ACTIVE_LOW, GPIO_INT_EDGE_TO_INACTIVE); +} + +/** @brief Verify GPIO_INT_LEVEL_HIGH flag. */ +void test_gpio_int_level_high(void) +{ + test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_HIGH); +} + +/** @brief Verify GPIO_INT_LEVEL_LOW flag. */ +void test_gpio_int_level_low(void) +{ + test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_LOW); +} + +/** @brief Verify GPIO_INT_LEVEL_ACTIVE flag. */ +void test_gpio_int_level_active(void) +{ + TC_PRINT("Step 1: Configure pin as active high\n"); + test_gpio_pin_interrupt_level(GPIO_ACTIVE_HIGH, GPIO_INT_LEVEL_ACTIVE); + TC_PRINT("Step 2: Configure pin as active low\n"); + test_gpio_pin_interrupt_level(GPIO_ACTIVE_LOW, GPIO_INT_LEVEL_ACTIVE); +} + +/** @brief Verify GPIO_INT_LEVEL_INACTIVE flag. */ +void test_gpio_int_level_inactive(void) +{ + TC_PRINT("Step 1: Configure pin as active high\n"); + test_gpio_pin_interrupt_level(GPIO_ACTIVE_HIGH, GPIO_INT_LEVEL_INACTIVE); + TC_PRINT("Step 2: Configure pin as active low\n"); + test_gpio_pin_interrupt_level(GPIO_ACTIVE_LOW, GPIO_INT_LEVEL_INACTIVE); +} diff --git a/tests/drivers/gpio/gpio_api_1pin/src/test_port.c b/tests/drivers/gpio/gpio_api_1pin/src/test_port.c new file mode 100644 index 00000000000000..389b5b0fff960c --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/src/test_port.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2019 Piotr Mienkowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @addtogroup t_gpio_api + * @{ + * @defgroup t_gpio_api_port test_gpio_api_port + * @brief TestPurpose: verify all gpio port functions using single pin + * configured as input/output. + * @} + */ + +#include +#include +#include "test_gpio_api.h" + +#define TEST_GPIO_PORT_VALUE_MAX ((1LLU << GPIO_MAX_PINS_PER_PORT) - 1) + +static void port_get_raw_and_verify(struct device *port, + gpio_port_value_t val_expected, int idx) +{ + gpio_port_value_t val_actual; + + zassert_equal(gpio_port_get_raw(port, &val_actual), 0, + "Test point %d: failed to get physical port value", idx); + zassert_equal(val_expected, val_actual, + "Test point %d: invalid physical port get value", idx); +} + +static void port_get_and_verify(struct device *port, + gpio_port_value_t val_expected, int idx) +{ + gpio_port_value_t val_actual; + + zassert_equal(gpio_port_get(port, &val_actual), 0, + "Test point %d: failed to get logical port value", idx); + zassert_equal(val_expected, val_actual, + "Test point %d: invalid logical port get value", idx); +} + +static void port_set_masked_raw_and_verify(struct device *port, + gpio_port_pins_t mask, gpio_port_value_t value, int idx) +{ + zassert_equal(gpio_port_set_masked_raw(port, mask, value), 0, + "Test point %d: failed to set physical port value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +static void port_set_masked_and_verify(struct device *port, + gpio_port_pins_t mask, gpio_port_value_t value, int idx) +{ + zassert_equal(gpio_port_set_masked(port, mask, value), 0, + "Test point %d: failed to set logical port value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +static void port_set_bits_raw_and_verify(struct device *port, + gpio_port_pins_t pins, int idx) +{ + zassert_equal(gpio_port_set_bits_raw(port, pins), 0, + "Test point %d: failed to set physical port value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +static void port_set_bits_and_verify(struct device *port, + gpio_port_pins_t pins, int idx) +{ + zassert_equal(gpio_port_set_bits(port, pins), 0, + "Test point %d: failed to set logical port value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +static void port_clear_bits_raw_and_verify(struct device *port, + gpio_port_pins_t pins, int idx) +{ + zassert_equal(gpio_port_clear_bits_raw(port, pins), 0, + "Test point %d: failed to set physical port value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +static void port_clear_bits_and_verify(struct device *port, + gpio_port_pins_t pins, int idx) +{ + zassert_equal(gpio_port_clear_bits(port, pins), 0, + "Test point %d: failed to set logical port value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +static void port_set_clr_bits_raw(struct device *port, + gpio_port_pins_t set_pins, gpio_port_pins_t clear_pins, int idx) +{ + zassert_equal(gpio_port_set_clr_bits_raw(port, set_pins, clear_pins), 0, + "Test point %d: failed to set physical port value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +static void port_set_clr_bits(struct device *port, + gpio_port_pins_t set_pins, gpio_port_pins_t clear_pins, int idx) +{ + zassert_equal(gpio_port_set_clr_bits(port, set_pins, clear_pins), 0, + "Test point %d: failed to set logical port value", idx); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); +} + +/** @brief Verify gpio_port_toggle_bits function. + * + * - Verify that gpio_port_toggle_bits function changes pin state from active to + * inactive and vice versa. + */ +void test_gpio_port_toggle(void) +{ + struct device *port; + gpio_port_value_t val_expected; + int ret; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + port_set_bits_raw_and_verify(port, 1 << TEST_PIN, 0); + + zassert_equal(gpio_port_get(port, &val_expected), 0, + "Failed to get logical port value"); + + for (int i = 0; i < 5; i++) { + ret = gpio_port_toggle_bits(port, 1 << TEST_PIN); + zassert_equal(ret, 0, "Failed to toggle pin value"); + k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US); + + val_expected ^= 1 << TEST_PIN; + + port_get_raw_and_verify(port, val_expected, i); + } +} + +void test_gpio_port_set_masked_get_raw(void) +{ + struct device *port; + gpio_port_value_t val_expected; + int ret; + + const gpio_port_value_t test_vector[] = { + 0xEE11EE11, + 0x11EE11EE, + TEST_GPIO_PORT_VALUE_MAX, + TEST_GPIO_PORT_VALUE_MAX, + 0x00000000, + 0x00000000, + 0x55555555, + 0xAAAAAAAA, + 0x00000000, + 0x00000000, + TEST_GPIO_PORT_VALUE_MAX, + TEST_GPIO_PORT_VALUE_MAX, + 0x00000000, + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + ret = gpio_port_get_raw(port, &val_expected); + zassert_equal(ret, 0, "Failed to get physical port value"); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_masked_raw_and_verify(port, 1 << TEST_PIN, test_vector[i], i); + + val_expected &= ~(1 << TEST_PIN); + val_expected |= test_vector[i] & (1 << TEST_PIN); + + port_get_raw_and_verify(port, val_expected, i); + } +} + +void test_gpio_port_set_masked_get(void) +{ + struct device *port; + gpio_port_value_t val_expected; + int ret; + + const gpio_port_value_t test_vector[] = { + 0xEE11EE11, + 0x11EE11EE, + TEST_GPIO_PORT_VALUE_MAX, + TEST_GPIO_PORT_VALUE_MAX, + 0x00000000, + 0x00000000, + 0x55555555, + 0xAAAAAAAA, + 0x00000000, + 0x00000000, + TEST_GPIO_PORT_VALUE_MAX, + TEST_GPIO_PORT_VALUE_MAX, + 0x00000000, + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + ret = gpio_port_get(port, &val_expected); + zassert_equal(ret, 0, "Failed to get logical port value"); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_masked_and_verify(port, 1 << TEST_PIN, test_vector[i], i); + + val_expected &= ~(1 << TEST_PIN); + val_expected |= test_vector[i] & (1 << TEST_PIN); + + port_get_and_verify(port, val_expected, i); + } +} + +void test_gpio_port_set_masked_get_active_high(void) +{ + struct device *port; + gpio_port_value_t val_expected; + int ret; + + const gpio_port_value_t test_vector[] = { + 0xCC33CC33, + 0x33CC33CC, + TEST_GPIO_PORT_VALUE_MAX, + TEST_GPIO_PORT_VALUE_MAX, + TEST_GPIO_PORT_VALUE_MAX, + 0x00000000, + 0x00000000, + 0x00000000, + 0x55555555, + 0x00000000, + 0xAAAAAAAA, + 0x00000000, + TEST_GPIO_PORT_VALUE_MAX, + 0x00000000, + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT | + GPIO_ACTIVE_HIGH); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + ret = gpio_port_get(port, &val_expected); + zassert_equal(ret, 0, "Failed to get logical port value"); + + TC_PRINT("Step 1: Set logical, get logical and physical port value\n"); + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_masked_and_verify(port, 1 << TEST_PIN, test_vector[i], i); + + val_expected &= ~(1 << TEST_PIN); + val_expected |= test_vector[i] & (1 << TEST_PIN); + + port_get_and_verify(port, val_expected, i); + port_get_raw_and_verify(port, val_expected, i); + } + + TC_PRINT("Step 2: Set physical, get logical and physical port value\n"); + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_masked_raw_and_verify(port, 1 << TEST_PIN, test_vector[i], i); + + val_expected &= ~(1 << TEST_PIN); + val_expected |= test_vector[i] & (1 << TEST_PIN); + + port_get_and_verify(port, val_expected, i); + port_get_raw_and_verify(port, val_expected, i); + } +} + +void test_gpio_port_set_masked_get_active_low(void) +{ + struct device *port; + gpio_port_value_t val_expected, val_raw_expected; + int ret; + + const gpio_port_value_t test_vector[] = { + 0xCC33CC33, + 0x33CC33CC, + TEST_GPIO_PORT_VALUE_MAX, + TEST_GPIO_PORT_VALUE_MAX, + TEST_GPIO_PORT_VALUE_MAX, + 0x00000000, + 0x00000000, + 0x00000000, + 0x55555555, + 0x00000000, + 0xAAAAAAAA, + 0x00000000, + TEST_GPIO_PORT_VALUE_MAX, + 0x00000000, + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT | + GPIO_ACTIVE_LOW); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + ret = gpio_port_get_raw(port, &val_raw_expected); + zassert_equal(ret, 0, "Failed to get physical port value"); + ret = gpio_port_get(port, &val_expected); + zassert_equal(ret, 0, "Failed to get logical port value"); + + TC_PRINT("Step 1: Set logical, get logical and physical port value\n"); + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_masked_and_verify(port, 1 << TEST_PIN, test_vector[i], i); + + val_raw_expected &= ~(1 << TEST_PIN); + val_raw_expected |= (test_vector[i] & (1 << TEST_PIN)) ^ (1 << TEST_PIN); + val_expected &= ~(1 << TEST_PIN); + val_expected |= test_vector[i] & (1 << TEST_PIN); + + port_get_and_verify(port, val_expected, i); + port_get_raw_and_verify(port, val_raw_expected, i); + } + + TC_PRINT("Step 2: Set physical, get logical and physical port value\n"); + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_masked_raw_and_verify(port, 1 << TEST_PIN, test_vector[i], i); + + val_raw_expected &= ~(1 << TEST_PIN); + val_raw_expected |= test_vector[i] & (1 << TEST_PIN); + val_expected &= ~(1 << TEST_PIN); + val_expected |= (test_vector[i] & (1 << TEST_PIN)) ^ (1 << TEST_PIN); + + port_get_and_verify(port, val_expected, i); + port_get_raw_and_verify(port, val_raw_expected, i); + } +} + +void test_gpio_port_set_bits_clear_bits_raw(void) +{ + struct device *port; + gpio_port_value_t val_expected; + int ret; + + const gpio_port_value_t test_vector[][2] = { + /* set value, clear value */ + {0xEE11EE11, 0xEE11EE11}, + {0x11EE11EE, TEST_GPIO_PORT_VALUE_MAX}, + {0x00000000, 0x55555555}, + {TEST_GPIO_PORT_VALUE_MAX, 0xAAAAAAAA}, + {TEST_GPIO_PORT_VALUE_MAX, TEST_GPIO_PORT_VALUE_MAX}, + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + ret = gpio_port_get_raw(port, &val_expected); + zassert_equal(ret, 0, "Failed to get logical port value"); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_bits_raw_and_verify(port, test_vector[i][0], i); + val_expected |= test_vector[i][0] & (1 << TEST_PIN); + port_get_raw_and_verify(port, val_expected, i); + + port_clear_bits_raw_and_verify(port, test_vector[i][1], i); + val_expected &= ~(test_vector[i][1] & (1 << TEST_PIN)); + port_get_raw_and_verify(port, val_expected, i); + } +} + +void test_gpio_port_set_bits_clear_bits(void) +{ + struct device *port; + gpio_port_value_t val_expected; + int ret; + + const gpio_port_value_t test_vector[][2] = { + /* set value, clear value */ + {TEST_GPIO_PORT_VALUE_MAX, 0xAAAAAAAA}, + {0x00000000, TEST_GPIO_PORT_VALUE_MAX}, + {0xCC33CC33, 0x33CC33CC}, + {0x33CC33CC, 0x33CC33CC}, + {0x00000000, 0x55555555}, + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + ret = gpio_port_get(port, &val_expected); + zassert_equal(ret, 0, "Failed to get logical port value"); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_bits_and_verify(port, test_vector[i][0], i); + val_expected |= test_vector[i][0] & (1 << TEST_PIN); + port_get_and_verify(port, val_expected, i); + + port_clear_bits_and_verify(port, test_vector[i][1], i); + val_expected &= ~(test_vector[i][1] & (1 << TEST_PIN)); + port_get_and_verify(port, val_expected, i); + } +} + +void test_gpio_port_set_clr_bits_raw(void) +{ + struct device *port; + gpio_port_value_t val_expected; + int ret; + + const gpio_port_value_t test_vector[][2] = { + /* set value, clear value */ + {0xEE11EE11, 0x11EE11EE}, + {0x00000000, TEST_GPIO_PORT_VALUE_MAX}, + {0x55555555, 0x00000000}, + {TEST_GPIO_PORT_VALUE_MAX, 0x00000000}, + {0xAAAAAAAA, 0x00000000}, + {0x00000000, TEST_GPIO_PORT_VALUE_MAX}, + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + ret = gpio_port_get_raw(port, &val_expected); + zassert_equal(ret, 0, "Failed to get logical port value"); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_clr_bits_raw(port, test_vector[i][0], test_vector[i][1], i); + val_expected |= test_vector[i][0] & (1 << TEST_PIN); + val_expected &= ~(test_vector[i][1] & (1 << TEST_PIN)); + port_get_raw_and_verify(port, val_expected, i); + } +} + +void test_gpio_port_set_clr_bits(void) +{ + struct device *port; + gpio_port_value_t val_expected; + int ret; + + const gpio_port_value_t test_vector[][2] = { + /* set value, clear value */ + {0xEE11EE11, 0x11EE11EE}, + {0x00000000, TEST_GPIO_PORT_VALUE_MAX}, + {0x55555555, 0x00000000}, + {TEST_GPIO_PORT_VALUE_MAX, 0x00000000}, + {0xAAAAAAAA, 0x00000000}, + {0x00000000, TEST_GPIO_PORT_VALUE_MAX}, + }; + + port = device_get_binding(TEST_DEV); + zassert_not_null(port, "device " TEST_DEV " not found"); + + TC_PRINT("Running test on port=%s, pin=%d\n", TEST_DEV, TEST_PIN); + + ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT); + if (ret == -ENOTSUP) { + TC_PRINT("Simultaneous pin in/out mode is not supported.\n"); + ztest_test_skip(); + return; + } + zassert_equal(ret, 0, "Failed to configure the pin"); + + ret = gpio_port_get(port, &val_expected); + zassert_equal(ret, 0, "Failed to get logical port value"); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + port_set_clr_bits(port, test_vector[i][0], test_vector[i][1], i); + val_expected |= test_vector[i][0] & (1 << TEST_PIN); + val_expected &= ~(test_vector[i][1] & (1 << TEST_PIN)); + port_get_and_verify(port, val_expected, i); + } +} diff --git a/tests/drivers/gpio/gpio_api_1pin/testcase.yaml b/tests/drivers/gpio/gpio_api_1pin/testcase.yaml new file mode 100644 index 00000000000000..ca1ec3a7459e2b --- /dev/null +++ b/tests/drivers/gpio/gpio_api_1pin/testcase.yaml @@ -0,0 +1,6 @@ +tests: + peripheral.gpio: + tags: drivers gpio + depends_on: gpio + min_flash: 48 + filter: DT_ALIAS_LED0_GPIOS_CONTROLLER From b005e3eeeacc565cb9bbdd7df41bc5efe6d68b56 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Tue, 29 Jan 2019 00:30:28 +0100 Subject: [PATCH 06/12] drivers: gpio_gecko: update to use new GPIO API Update driver code and board files to use new GPIO configuration flags such as GPIO_ACTIVE_LOW. Also add implementation of new port_* driver API as well as gpio_pin_interrupt_configure function. Tested on efr32_slwstk6061a board. Signed-off-by: Piotr Mienkowski --- boards/arm/efm32hg_slstk3400a/board.c | 3 +- .../efm32hg_slstk3400a/efm32hg_slstk3400a.dts | 4 +- boards/arm/efm32pg_stk3402a/board.c | 3 +- .../arm/efm32pg_stk3402a/efm32pg_stk3402a.dts | 4 +- boards/arm/efm32wg_stk3800/board.c | 3 +- .../arm/efm32wg_stk3800/efm32wg_stk3800.dts | 4 +- boards/arm/efr32_slwstk6061a/board.c | 3 +- .../efr32_slwstk6061a/efr32_slwstk6061a.dts | 4 +- .../arm/efr32mg_sltb004a/efr32mg_sltb004a.dts | 4 +- drivers/gpio/gpio_gecko.c | 171 +++++++++++++++--- 10 files changed, 162 insertions(+), 41 deletions(-) diff --git a/boards/arm/efm32hg_slstk3400a/board.c b/boards/arm/efm32hg_slstk3400a/board.c index 24f102c2cb3dee..f8485af46861e0 100644 --- a/boards/arm/efm32hg_slstk3400a/board.c +++ b/boards/arm/efm32hg_slstk3400a/board.c @@ -23,8 +23,7 @@ static int efm32hg_slstk3400a_init(struct device *dev) return -ENODEV; } - gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_DIR_OUT); - gpio_pin_write(bce_dev, BC_ENABLE_GPIO_PIN, 1); + gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); return 0; } diff --git a/boards/arm/efm32hg_slstk3400a/efm32hg_slstk3400a.dts b/boards/arm/efm32hg_slstk3400a/efm32hg_slstk3400a.dts index 03b8913466817e..501909bfa5f676 100644 --- a/boards/arm/efm32hg_slstk3400a/efm32hg_slstk3400a.dts +++ b/boards/arm/efm32hg_slstk3400a/efm32hg_slstk3400a.dts @@ -42,12 +42,12 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpioc 9 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpioc 9 GPIO_ACTIVE_LOW>; label = "User Push Button 0"; }; button1: button_1 { /* gpio flags need validation */ - gpios = <&gpioc 10 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpioc 10 GPIO_ACTIVE_LOW>; label = "User Push Button 1"; }; }; diff --git a/boards/arm/efm32pg_stk3402a/board.c b/boards/arm/efm32pg_stk3402a/board.c index c3b0518ee74d87..65ffc219ad73bc 100644 --- a/boards/arm/efm32pg_stk3402a/board.c +++ b/boards/arm/efm32pg_stk3402a/board.c @@ -23,8 +23,7 @@ static int efm32pg_stk3402a_init(struct device *dev) return -ENODEV; } - gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_DIR_OUT); - gpio_pin_write(bce_dev, BC_ENABLE_GPIO_PIN, 1); + gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); return 0; } diff --git a/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a.dts b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a.dts index f0a6e7e06a0eb4..690d3a88542dd7 100644 --- a/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a.dts +++ b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a.dts @@ -42,12 +42,12 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpiof 6 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiof 6 GPIO_ACTIVE_LOW>; label = "User Push Button 0"; }; button1: button_1 { /* gpio flags need validation */ - gpios = <&gpiof 7 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiof 7 GPIO_ACTIVE_LOW>; label = "User Push Button 1"; }; }; diff --git a/boards/arm/efm32wg_stk3800/board.c b/boards/arm/efm32wg_stk3800/board.c index 16915fb345c68b..26ce8287f21591 100644 --- a/boards/arm/efm32wg_stk3800/board.c +++ b/boards/arm/efm32wg_stk3800/board.c @@ -23,8 +23,7 @@ static int efm32wg_stk3800_init(struct device *dev) return -ENODEV; } - gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_DIR_OUT); - gpio_pin_write(bce_dev, BC_ENABLE_GPIO_PIN, 1); + gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); return 0; } diff --git a/boards/arm/efm32wg_stk3800/efm32wg_stk3800.dts b/boards/arm/efm32wg_stk3800/efm32wg_stk3800.dts index 7a2a610b29e4ca..a9d5a80ca60765 100644 --- a/boards/arm/efm32wg_stk3800/efm32wg_stk3800.dts +++ b/boards/arm/efm32wg_stk3800/efm32wg_stk3800.dts @@ -42,12 +42,12 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpiob 9 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiob 9 GPIO_ACTIVE_LOW>; label = "User Push Button 0"; }; button1: button_1 { /* gpio flags need validation */ - gpios = <&gpiob 19 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiob 19 GPIO_ACTIVE_LOW>; label = "User Push Button 1"; }; }; diff --git a/boards/arm/efr32_slwstk6061a/board.c b/boards/arm/efr32_slwstk6061a/board.c index aa723c1960c85e..6d87357bae9b4d 100644 --- a/boards/arm/efr32_slwstk6061a/board.c +++ b/boards/arm/efr32_slwstk6061a/board.c @@ -23,8 +23,7 @@ static int efr32_slwstk6061a_init(struct device *dev) return -ENODEV; } - gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_DIR_OUT); - gpio_pin_write(bce_dev, BC_ENABLE_GPIO_PIN, 1); + gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); return 0; } diff --git a/boards/arm/efr32_slwstk6061a/efr32_slwstk6061a.dts b/boards/arm/efr32_slwstk6061a/efr32_slwstk6061a.dts index 3478ea524dd31f..04801147497f65 100644 --- a/boards/arm/efr32_slwstk6061a/efr32_slwstk6061a.dts +++ b/boards/arm/efr32_slwstk6061a/efr32_slwstk6061a.dts @@ -43,12 +43,12 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpiof 6 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiof 6 GPIO_ACTIVE_LOW>; label = "User Push Button 0"; }; button1: button_1 { /* gpio flags need validation */ - gpios = <&gpiof 7 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiof 7 GPIO_ACTIVE_LOW>; label = "User Push Button 1"; }; }; diff --git a/boards/arm/efr32mg_sltb004a/efr32mg_sltb004a.dts b/boards/arm/efr32mg_sltb004a/efr32mg_sltb004a.dts index 554b8a5546c65d..bfadae5a132015 100644 --- a/boards/arm/efr32mg_sltb004a/efr32mg_sltb004a.dts +++ b/boards/arm/efr32mg_sltb004a/efr32mg_sltb004a.dts @@ -41,12 +41,12 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpiod 14 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiod 14 GPIO_ACTIVE_LOW>; label = "User Push Button 0"; }; button1: button_1 { /* gpio flags need validation */ - gpios = <&gpiod 15 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiod 15 GPIO_ACTIVE_LOW>; label = "User Push Button 1"; }; }; diff --git a/drivers/gpio/gpio_gecko.c b/drivers/gpio/gpio_gecko.c index e3e97ddfba518f..8da6b758378b66 100644 --- a/drivers/gpio/gpio_gecko.c +++ b/drivers/gpio/gpio_gecko.c @@ -53,12 +53,16 @@ struct gpio_gecko_config { }; struct gpio_gecko_data { + struct gpio_driver_data general; /* port ISR callback routine address */ sys_slist_t callbacks; /* pin callback routine enable flags, by pin number */ u32_t pin_callback_enables; }; +static int gpio_gecko_pin_interrupt_configure(struct device *dev, u32_t pin, + unsigned int flags); + static inline void gpio_gecko_add_port(struct gpio_gecko_common_data *data, struct device *dev) { @@ -66,43 +70,53 @@ static inline void gpio_gecko_add_port(struct gpio_gecko_common_data *data, data->ports[data->count++] = dev; } - static int gpio_gecko_configure(struct device *dev, int access_op, u32_t pin, int flags) { const struct gpio_gecko_config *config = dev->config->config_info; GPIO_P_TypeDef *gpio_base = config->gpio_base; GPIO_Port_TypeDef gpio_index = config->gpio_index; + struct gpio_gecko_data *data = dev->driver_data; GPIO_Mode_TypeDef mode; unsigned int out = 0U; - - /* Check for an invalid pin configuration */ - if ((flags & GPIO_INT) && (flags & GPIO_DIR_OUT)) { - return -EINVAL; - } - - /* Interrupt on static level is not supported by the hardware */ - if ((flags & GPIO_INT) && !(flags & GPIO_INT_EDGE)) { - return -ENOTSUP; - } + int ret; /* Setting interrupt flags for a complete port is not implemented */ - if ((flags & GPIO_INT) && (access_op == GPIO_ACCESS_BY_PORT)) { + if ((flags & GPIO_INT_ENABLE) && (access_op == GPIO_ACCESS_BY_PORT)) { return -ENOTSUP; } - if ((flags & GPIO_DIR_MASK) == GPIO_DIR_IN) { - if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_UP) { + if (flags & GPIO_OUTPUT) { + /* Following modes enable both output and input */ + if (flags & GPIO_SINGLE_ENDED) { + if (flags & GPIO_LINE_OPEN_DRAIN) { + mode = gpioModeWiredAnd; + } else { + mode = gpioModeWiredOr; + } + } else { + mode = gpioModePushPull; + } + if (flags & GPIO_OUTPUT_INIT_HIGH) { + out = 1U; + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + out = 0U; + } else { + out = GPIO_PinOutGet(gpio_index, pin); + } + } else if (flags & GPIO_INPUT) { + if (flags & GPIO_PULL_UP) { mode = gpioModeInputPull; out = 1U; /* pull-up*/ - } else if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_DOWN) { + } else if (flags & GPIO_PULL_DOWN) { mode = gpioModeInputPull; /* out = 0 means pull-down*/ } else { mode = gpioModeInput; } - } else { /* GPIO_DIR_OUT */ - mode = gpioModePushPull; + } else { + /* Neither input nor output mode is selected */ + mode = gpioModeDisabled; } /* The flags contain options that require touching registers in the * GPIO module and the corresponding PORT module. @@ -113,6 +127,12 @@ static int gpio_gecko_configure(struct device *dev, if (access_op == GPIO_ACCESS_BY_PIN) { GPIO_PinModeSet(gpio_index, pin, mode, out); + if (flags & GPIO_ACTIVE_LOW) { + data->general.invert |= BIT(pin); + } else { + data->general.invert &= ~BIT(pin); + } + } else { /* GPIO_ACCESS_BY_PORT */ gpio_base->MODEL = GECKO_GPIO_MODEL(7, mode) | GECKO_GPIO_MODEL(6, mode) | GECKO_GPIO_MODEL(5, mode) @@ -131,12 +151,10 @@ static int gpio_gecko_configure(struct device *dev, } if (access_op == GPIO_ACCESS_BY_PIN) { - GPIO_IntConfig(gpio_index, pin, - (flags & GPIO_INT_ACTIVE_HIGH) - || (flags & GPIO_INT_DOUBLE_EDGE), - !(flags & GPIO_INT_ACTIVE_HIGH) - || (flags & GPIO_INT_DOUBLE_EDGE), - !!(flags & GPIO_INT)); + ret = gpio_gecko_pin_interrupt_configure(dev, pin, flags); + if (ret != 0) { + return ret; + } } return 0; @@ -187,6 +205,107 @@ static int gpio_gecko_read(struct device *dev, return 0; } +static int gpio_gecko_port_get_raw(struct device *dev, u32_t *value) +{ + const struct gpio_gecko_config *config = dev->config->config_info; + GPIO_P_TypeDef *gpio_base = config->gpio_base; + + *value = gpio_base->DIN; + + return 0; +} + +static int gpio_gecko_port_set_masked_raw(struct device *dev, u32_t mask, + u32_t value) +{ + const struct gpio_gecko_config *config = dev->config->config_info; + GPIO_P_TypeDef *gpio_base = config->gpio_base; + + gpio_base->DOUT = (gpio_base->DOUT & ~mask) | (mask & value); + + return 0; +} + +static int gpio_gecko_port_set_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_gecko_config *config = dev->config->config_info; + GPIO_P_TypeDef *gpio_base = config->gpio_base; + +#if defined(_GPIO_P_DOUTSET_MASK) + gpio_base->DOUTSET = mask; +#else + BUS_RegMaskedSet(&gpio_base->DOUT, mask); +#endif + + return 0; +} + +static int gpio_gecko_port_clear_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_gecko_config *config = dev->config->config_info; + GPIO_P_TypeDef *gpio_base = config->gpio_base; + +#if defined(_GPIO_P_DOUTCLR_MASK) + gpio_base->DOUTCLR = mask; +#else + BUS_RegMaskedClear(&gpio_base->DOUT, mask); +#endif + + return 0; +} + +static int gpio_gecko_port_toggle_bits(struct device *dev, u32_t mask) +{ + const struct gpio_gecko_config *config = dev->config->config_info; + GPIO_P_TypeDef *gpio_base = config->gpio_base; + + gpio_base->DOUTTGL = mask; + + return 0; +} + +static int gpio_gecko_pin_interrupt_configure(struct device *dev, + unsigned int pin, unsigned int flags) +{ + const struct gpio_gecko_config *config = dev->config->config_info; + struct gpio_gecko_data *data = dev->driver_data; + bool rising_edge; + bool falling_edge; + + if ((flags & GPIO_INT_ENABLE) != 0) { + /* Interrupt on static level is not supported by the hardware */ + if ((flags & GPIO_INT_EDGE) == 0) { + return -ENOTSUP; + } + + /* Interrupt line is already in use */ + if ((GPIO->IEN & BIT(pin)) != 0) { + /* TODO: Return an error only if request is done for + * a pin from a different port. + */ + return -EBUSY; + } + + if (((flags & GPIO_INT_LEVELS_LOGICAL) != 0) && + ((data->general.invert & BIT(pin)) != 0)) { + rising_edge = flags & GPIO_INT_LOW_0; + falling_edge = flags & GPIO_INT_HIGH_1; + } else { + rising_edge = flags & GPIO_INT_HIGH_1; + falling_edge = flags & GPIO_INT_LOW_0; + } + + GPIO_IntConfig(config->gpio_index, pin, + rising_edge, falling_edge, true); + } else { + GPIO_IntDisable(BIT(pin)); + } + + WRITE_BIT(data->pin_callback_enables, pin, flags & GPIO_INT_ENABLE); + + return 0; +} + static int gpio_gecko_manage_callback(struct device *dev, struct gpio_callback *callback, bool set) { @@ -256,6 +375,12 @@ static const struct gpio_driver_api gpio_gecko_driver_api = { .config = gpio_gecko_configure, .write = gpio_gecko_write, .read = gpio_gecko_read, + .port_get_raw = gpio_gecko_port_get_raw, + .port_set_masked_raw = gpio_gecko_port_set_masked_raw, + .port_set_bits_raw = gpio_gecko_port_set_bits_raw, + .port_clear_bits_raw = gpio_gecko_port_clear_bits_raw, + .port_toggle_bits = gpio_gecko_port_toggle_bits, + .pin_interrupt_configure = gpio_gecko_pin_interrupt_configure, .manage_callback = gpio_gecko_manage_callback, .enable_callback = gpio_gecko_enable_callback, .disable_callback = gpio_gecko_disable_callback, From 0bd12fb5e4dc328729bf7d1c329f30b2898a633d Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Tue, 29 Jan 2019 02:39:43 +0100 Subject: [PATCH 07/12] drivers: gpio_sam: update to use new GPIO API Update driver code and board files to use new GPIO configuration flags such as GPIO_ACTIVE_LOW. Also add implementation of new port_* driver API as well as gpio_pin_interrupt_configure function. Tested on sam_e70_xplained board. Signed-off-by: Piotr Mienkowski --- boards/arm/sam4s_xplained/sam4s_xplained.dts | 7 +- .../arm/sam_e70_xplained/sam_e70_xplained.dts | 5 +- drivers/gpio/gpio_sam.c | 240 ++++++++++++++---- 3 files changed, 192 insertions(+), 60 deletions(-) diff --git a/boards/arm/sam4s_xplained/sam4s_xplained.dts b/boards/arm/sam4s_xplained/sam4s_xplained.dts index 43daf0855f54de..79b2ee8e4974e5 100644 --- a/boards/arm/sam4s_xplained/sam4s_xplained.dts +++ b/boards/arm/sam4s_xplained/sam4s_xplained.dts @@ -30,11 +30,11 @@ leds { compatible = "gpio-leds"; yellow_led_1: led_1 { - gpios = <&portc 10 0>; + gpios = <&portc 10 GPIO_ACTIVE_LOW>; label = "LED 1"; }; yellow_led_2: led_2 { - gpios = <&portc 17 0>; + gpios = <&portc 17 GPIO_ACTIVE_LOW>; label = "LED 2"; }; }; @@ -43,8 +43,7 @@ compatible = "gpio-keys"; user_button: button_1 { label = "User Button"; - gpios = <&porta 5 (GPIO_PUD_PULL_UP | - GPIO_INT_ACTIVE_LOW)>; + gpios = <&porta 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; }; }; }; diff --git a/boards/arm/sam_e70_xplained/sam_e70_xplained.dts b/boards/arm/sam_e70_xplained/sam_e70_xplained.dts index ee7c634af5b6bb..30952715341f1d 100644 --- a/boards/arm/sam_e70_xplained/sam_e70_xplained.dts +++ b/boards/arm/sam_e70_xplained/sam_e70_xplained.dts @@ -33,7 +33,7 @@ leds { compatible = "gpio-leds"; green_led: led_0 { - gpios = <&portc 8 0>; + gpios = <&portc 8 GPIO_ACTIVE_LOW>; label = "User LED"; }; }; @@ -46,8 +46,7 @@ */ sw0_user_button: button_1 { label = "User Button"; - gpios = <&porta 11 (GPIO_PUD_PULL_UP | - GPIO_INT_ACTIVE_LOW)>; + gpios = <&porta 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; }; }; }; diff --git a/drivers/gpio/gpio_sam.c b/drivers/gpio/gpio_sam.c index 6c9b2130e798f8..59a6a25d8d4df6 100644 --- a/drivers/gpio/gpio_sam.c +++ b/drivers/gpio/gpio_sam.c @@ -22,56 +22,79 @@ struct gpio_sam_config { }; struct gpio_sam_runtime { + struct gpio_driver_data general; sys_slist_t cb; }; #define DEV_CFG(dev) \ - ((const struct gpio_sam_config *const)(dev)->config->config_info) + ((const struct gpio_sam_config * const)(dev)->config->config_info) +#define DEV_DATA(dev) \ + ((struct gpio_sam_runtime * const)(dev)->driver_data) -static int gpio_sam_config_pin(Pio * const pio, u32_t mask, int flags) +#define GPIO_SAM_ALL_PINS 0xFFFFFFFF + +static int gpio_sam_port_interrupt_configure(struct device *dev, u32_t mask, + unsigned int flags); + +static int gpio_sam_port_configure(struct device *dev, u32_t mask, int flags) { - /* Setup the pin direcion. */ - if ((flags & GPIO_DIR_MASK) == GPIO_DIR_OUT) { - pio->PIO_OER = mask; - } else { - pio->PIO_ODR = mask; + const struct gpio_sam_config * const cfg = DEV_CFG(dev); + struct gpio_sam_runtime * const dev_data = DEV_DATA(dev); + Pio * const pio = cfg->regs; + + if (flags & GPIO_SINGLE_ENDED) { + /* TODO: Add support for Open Source, Open Drain mode */ + return -ENOTSUP; } - /* Setup interrupt configuration. */ - if (flags & GPIO_INT) { - if (flags & GPIO_INT_DOUBLE_EDGE) { - return -ENOTSUP; - } + if (!(flags & (GPIO_OUTPUT | GPIO_INPUT))) { + /* Neither input nor output mode is selected */ - /* Enable the interrupt. */ - pio->PIO_IER = mask; + /* Disable the interrupt. */ + pio->PIO_IDR = mask; + /* Disable pull-up. */ + pio->PIO_PUDR = mask; +#if defined(CONFIG_SOC_SERIES_SAM4S) || defined(CONFIG_SOC_SERIES_SAME70) + /* Disable pull-down. */ + pio->PIO_PPDDR = mask; +#endif + /* Let the PIO control the pin (instead of a peripheral). */ + pio->PIO_PER = mask; + /* Disable output. */ + pio->PIO_ODR = mask; - /* Enable the additional interrupt modes. */ - pio->PIO_AIMER = mask; + return 0; + } - if (flags & GPIO_INT_EDGE) { - pio->PIO_ESR = mask; - } else { - pio->PIO_LSR = mask; + /* Setup the pin direcion. */ + if (flags & GPIO_OUTPUT) { + if (flags & GPIO_OUTPUT_INIT_HIGH) { + /* Set the pin. */ + pio->PIO_SODR = mask; } - - if (flags & GPIO_INT_ACTIVE_HIGH) { - /* Set to high-level or rising edge. */ - pio->PIO_REHLSR = mask; - } else { - /* Set to low-level or falling edge. */ - pio->PIO_FELLSR = mask; + if (flags & GPIO_OUTPUT_INIT_LOW) { + /* Clear the pin. */ + pio->PIO_CODR = mask; } + /* Enable the output */ + pio->PIO_OER = mask; + /* Enable direct control of output level via PIO_ODSR */ + pio->PIO_OWER = mask; } else { - /* Disable the interrupt. */ - pio->PIO_IDR = mask; + /* Disable the output */ + pio->PIO_ODR = mask; + } + + /* Note: Input is always enabled. */ - /* Disable their additional interrupt modes. */ - pio->PIO_AIMDR = mask; + if (flags & GPIO_ACTIVE_LOW) { + dev_data->general.invert |= mask; + } else { + dev_data->general.invert &= ~mask; } /* Setup Pull-up resistor. */ - if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_UP) { + if (flags & GPIO_PULL_UP) { /* Enable pull-up. */ pio->PIO_PUER = mask; } else { @@ -80,7 +103,7 @@ static int gpio_sam_config_pin(Pio * const pio, u32_t mask, int flags) #if defined(CONFIG_SOC_SERIES_SAM4S) || defined(CONFIG_SOC_SERIES_SAME70) /* Setup Pull-down resistor. */ - if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_DOWN) { + if (flags & GPIO_PULL_DOWN) { pio->PIO_PPDER = mask; } else { pio->PIO_PPDDR = mask; @@ -106,40 +129,35 @@ static int gpio_sam_config_pin(Pio * const pio, u32_t mask, int flags) /* Enable the PIO to control the pin (instead of a peripheral). */ pio->PIO_PER = mask; - return 0; + int ret = gpio_sam_port_interrupt_configure(dev, mask, flags); + + return ret; } static int gpio_sam_config(struct device *dev, int access_op, u32_t pin, int flags) { - const struct gpio_sam_config * const cfg = DEV_CFG(dev); - Pio * const pio = cfg->regs; - int i, result; + int ret; switch (access_op) { case GPIO_ACCESS_BY_PIN: - gpio_sam_config_pin(pio, BIT(pin), flags); + ret = gpio_sam_port_configure(dev, BIT(pin), flags); break; case GPIO_ACCESS_BY_PORT: - for (i = 0; i < 32; i++) { - result = gpio_sam_config_pin(pio, BIT(i), flags); - if (result < 0) { - return result; - } - } + ret = gpio_sam_port_configure(dev, GPIO_SAM_ALL_PINS, flags); break; default: - return -ENOTSUP; + ret = -ENOTSUP; } - return 0; + return ret; } static int gpio_sam_write(struct device *dev, int access_op, u32_t pin, u32_t value) { const struct gpio_sam_config * const cfg = DEV_CFG(dev); - Pio *const pio = cfg->regs; + Pio * const pio = cfg->regs; u32_t mask = 1 << pin; switch (access_op) { @@ -153,9 +171,7 @@ static int gpio_sam_write(struct device *dev, int access_op, u32_t pin, } break; case GPIO_ACCESS_BY_PORT: - pio->PIO_OWER = pio->PIO_OSR; /* Write those out pin only */ pio->PIO_ODSR = value; - pio->PIO_OWDR = 0xffffffff; /* Disable write ODSR */ break; default: return -ENOTSUP; @@ -168,7 +184,7 @@ static int gpio_sam_read(struct device *dev, int access_op, u32_t pin, u32_t *value) { const struct gpio_sam_config * const cfg = DEV_CFG(dev); - Pio *const pio = cfg->regs; + Pio * const pio = cfg->regs; *value = pio->PIO_PDSR; @@ -185,11 +201,123 @@ static int gpio_sam_read(struct device *dev, int access_op, u32_t pin, return 0; } +static int gpio_sam_port_get_raw(struct device *dev, u32_t *value) +{ + const struct gpio_sam_config * const cfg = DEV_CFG(dev); + Pio * const pio = cfg->regs; + + *value = pio->PIO_PDSR; + + return 0; +} + +static int gpio_sam_port_set_masked_raw(struct device *dev, u32_t mask, + u32_t value) +{ + const struct gpio_sam_config * const cfg = DEV_CFG(dev); + Pio * const pio = cfg->regs; + + pio->PIO_ODSR = (pio->PIO_ODSR & ~mask) | (mask & value); + + return 0; +} + +static int gpio_sam_port_set_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_sam_config * const cfg = DEV_CFG(dev); + Pio * const pio = cfg->regs; + + /* Set pins. */ + pio->PIO_SODR = mask; + + return 0; +} + +static int gpio_sam_port_clear_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_sam_config * const cfg = DEV_CFG(dev); + Pio * const pio = cfg->regs; + + /* Clear pins. */ + pio->PIO_CODR = mask; + + return 0; +} + +static int gpio_sam_port_toggle_bits(struct device *dev, u32_t mask) +{ + const struct gpio_sam_config * const cfg = DEV_CFG(dev); + Pio * const pio = cfg->regs; + + /* Toggle pins. */ + pio->PIO_ODSR ^= mask; + + return 0; +} + +static int gpio_sam_port_interrupt_configure(struct device *dev, u32_t mask, + unsigned int flags) +{ + const struct gpio_sam_config * const cfg = DEV_CFG(dev); + struct gpio_sam_runtime * const dev_data = DEV_DATA(dev); + Pio * const pio = cfg->regs; + + /* Disable the interrupt. */ + pio->PIO_IDR = mask; + /* Disable additional interrupt modes. */ + pio->PIO_AIMDR = mask; + + if (!((flags & GPIO_INT_LOW_0) && (flags & GPIO_INT_HIGH_1))) { + /* Enable additional interrupt modes to support single + * edge/level detection. + */ + pio->PIO_AIMER = mask; + + if (flags & GPIO_INT_EDGE) { + pio->PIO_ESR = mask; + } else { + pio->PIO_LSR = mask; + } + + u32_t rising_edge; + + if (flags & GPIO_INT_HIGH_1) { + rising_edge = mask; + } else { + rising_edge = ~mask; + } + + if (flags & GPIO_INT_LEVELS_LOGICAL) { + rising_edge ^= dev_data->general.invert & mask; + } + + /* Set to high-level or rising edge. */ + pio->PIO_REHLSR = rising_edge & mask; + /* Set to low-level or falling edge. */ + pio->PIO_FELLSR = ~rising_edge & mask; + } + + if (flags & GPIO_INT_ENABLE) { + /* Clear any pending interrupts */ + (void)pio->PIO_ISR; + /* Enable the interrupt. */ + pio->PIO_IER = mask; + } + + return 0; +} + +static int gpio_sam_pin_interrupt_configure(struct device *dev, + unsigned int pin, unsigned int flags) +{ + return gpio_sam_port_interrupt_configure(dev, BIT(pin), flags); +} + static void gpio_sam_isr(void *arg) { struct device *dev = (struct device *)arg; const struct gpio_sam_config * const cfg = DEV_CFG(dev); - Pio *const pio = cfg->regs; + Pio * const pio = cfg->regs; struct gpio_sam_runtime *context = dev->driver_data; u32_t int_stat; @@ -211,7 +339,7 @@ static int gpio_sam_enable_callback(struct device *port, int access_op, u32_t pin) { const struct gpio_sam_config * const cfg = DEV_CFG(port); - Pio *const pio = cfg->regs; + Pio * const pio = cfg->regs; u32_t mask; switch (access_op) { @@ -234,7 +362,7 @@ static int gpio_sam_disable_callback(struct device *port, int access_op, u32_t pin) { const struct gpio_sam_config * const cfg = DEV_CFG(port); - Pio *const pio = cfg->regs; + Pio * const pio = cfg->regs; u32_t mask; switch (access_op) { @@ -257,6 +385,12 @@ static const struct gpio_driver_api gpio_sam_api = { .config = gpio_sam_config, .write = gpio_sam_write, .read = gpio_sam_read, + .port_get_raw = gpio_sam_port_get_raw, + .port_set_masked_raw = gpio_sam_port_set_masked_raw, + .port_set_bits_raw = gpio_sam_port_set_bits_raw, + .port_clear_bits_raw = gpio_sam_port_clear_bits_raw, + .port_toggle_bits = gpio_sam_port_toggle_bits, + .pin_interrupt_configure = gpio_sam_pin_interrupt_configure, .manage_callback = gpio_sam_manage_callback, .enable_callback = gpio_sam_enable_callback, .disable_callback = gpio_sam_disable_callback, From ff873b8a49b30cc7b20c91d7fee058d30d060d33 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Tue, 6 Aug 2019 00:56:05 +0200 Subject: [PATCH 08/12] drivers: gpio_nrfx: update to use new GPIO API Update driver code and board files to use new GPIO configuration flags such as GPIO_ACTIVE_LOW. Also add implementation of new port_* driver API as well as gpio_pin_interrupt_configure function. Tested on nrf52840_pca10056 board. Signed-off-by: Piotr Mienkowski Signed-off-by: Peter Bigot --- boards/arm/nrf51_ble400/nrf51_ble400.dts | 8 +- boards/arm/nrf51_pca10028/nrf51_pca10028.dts | 16 +- boards/arm/nrf51_pca10031/nrf51_pca10031.dts | 6 +- boards/arm/nrf51_vbluno51/nrf51_vbluno51.dts | 2 +- .../nrf52810_pca10040/nrf52810_pca10040.dts | 16 +- .../nrf52811_pca10056/nrf52811_pca10056.dts | 16 +- boards/arm/nrf52832_mdk/nrf52832_mdk.dts | 8 +- boards/arm/nrf52840_blip/nrf52840_blip.dts | 8 +- boards/arm/nrf52840_mdk/nrf52840_mdk.dts | 8 +- boards/arm/nrf52840_papyr/nrf52840_papyr.dts | 8 +- .../nrf52840_pca10056/nrf52840_pca10056.dts | 16 +- .../nrf52840_pca10059/nrf52840_pca10059.dts | 10 +- boards/arm/nrf52840_pca10090/board.c | 17 +- .../nrf52_adafruit_feather.dts | 3 +- boards/arm/nrf52_pca10040/nrf52_pca10040.dts | 16 +- boards/arm/nrf52_pca20020/board.c | 3 +- boards/arm/nrf52_pca20020/nrf52_pca20020.dts | 4 +- boards/arm/nrf52_sparkfun/nrf52_sparkfun.dts | 4 +- boards/arm/nrf52_vbluno52/nrf52_vbluno52.dts | 2 +- boards/arm/nrf9160_pca10090/nrf52840_reset.c | 15 +- .../nrf9160_pca10090_common.dts | 24 +-- drivers/gpio/gpio_nrfx.c | 153 ++++++++++++++---- 22 files changed, 222 insertions(+), 141 deletions(-) diff --git a/boards/arm/nrf51_ble400/nrf51_ble400.dts b/boards/arm/nrf51_ble400/nrf51_ble400.dts index 393af2076ac59f..07fd607bc25f8a 100644 --- a/boards/arm/nrf51_ble400/nrf51_ble400.dts +++ b/boards/arm/nrf51_ble400/nrf51_ble400.dts @@ -59,16 +59,12 @@ /* Push button switch 0 KEY1 */ compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 16 (GPIO_PUD_PULL_UP | - GPIO_INT_ACTIVE_LOW | - GPIO_INT_EDGE)>; + gpios = <&gpio0 16 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 0"; }; /* Push button switch 1 KEY2 */ button1: button_1 { - gpios = <&gpio0 17 (GPIO_PUD_PULL_UP | - GPIO_INT_ACTIVE_LOW | - GPIO_INT_EDGE)>; + gpios = <&gpio0 17 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 1"; }; }; diff --git a/boards/arm/nrf51_pca10028/nrf51_pca10028.dts b/boards/arm/nrf51_pca10028/nrf51_pca10028.dts index 6f02a342bbfc39..426cdabace36db 100644 --- a/boards/arm/nrf51_pca10028/nrf51_pca10028.dts +++ b/boards/arm/nrf51_pca10028/nrf51_pca10028.dts @@ -26,19 +26,19 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 21 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1: led_1 { - gpios = <&gpio0 22 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; label = "Green LED 1"; }; led2: led_2 { - gpios = <&gpio0 23 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 23 GPIO_ACTIVE_LOW>; label = "Green LED 2"; }; led3: led_3 { - gpios = <&gpio0 24 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; label = "Green LED 3"; }; }; @@ -46,19 +46,19 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 17 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 17 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 0"; }; button1: button_1 { - gpios = <&gpio0 18 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 18 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 1"; }; button2: button_2 { - gpios = <&gpio0 19 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 2"; }; button3: button_3 { - gpios = <&gpio0 20 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 20 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 3"; }; }; diff --git a/boards/arm/nrf51_pca10031/nrf51_pca10031.dts b/boards/arm/nrf51_pca10031/nrf51_pca10031.dts index 292179a04029aa..c0a4bd404e5269 100644 --- a/boards/arm/nrf51_pca10031/nrf51_pca10031.dts +++ b/boards/arm/nrf51_pca10031/nrf51_pca10031.dts @@ -26,15 +26,15 @@ leds { compatible = "gpio-leds"; led0_red: led_0 { - gpios = <&gpio0 21 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; label = "Red LED 0"; }; led0_green: led_1 { - gpios = <&gpio0 22 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led0_blue: led_2 { - gpios = <&gpio0 23 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 23 GPIO_ACTIVE_LOW>; label = "Blue LED 0"; }; }; diff --git a/boards/arm/nrf51_vbluno51/nrf51_vbluno51.dts b/boards/arm/nrf51_vbluno51/nrf51_vbluno51.dts index d8e7358c68646c..f755ab86df6ab3 100644 --- a/boards/arm/nrf51_vbluno51/nrf51_vbluno51.dts +++ b/boards/arm/nrf51_vbluno51/nrf51_vbluno51.dts @@ -41,7 +41,7 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpio0 15 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; label = "Button"; }; }; diff --git a/boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts b/boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts index 4855f2040689d7..41de0225becb5a 100644 --- a/boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts +++ b/boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts @@ -28,19 +28,19 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 17 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1: led_1 { - gpios = <&gpio0 18 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; label = "Green LED 1"; }; led2: led_2 { - gpios = <&gpio0 19 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 19 GPIO_ACTIVE_LOW>; label = "Green LED 2"; }; led3: led_3 { - gpios = <&gpio0 20 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; label = "Green LED 3"; }; }; @@ -49,19 +49,19 @@ compatible = "gpio-keys"; button0: button_0 { label = "Push button switch 0"; - gpios = <&gpio0 13 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; }; button1: button_1 { label = "Push button switch 1"; - gpios = <&gpio0 14 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 14 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; }; button2: button_2 { label = "Push button switch 2"; - gpios = <&gpio0 15 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 15 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; }; button3: button_3 { label = "Push button switch 3"; - gpios = <&gpio0 16 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 16 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; }; }; diff --git a/boards/arm/nrf52811_pca10056/nrf52811_pca10056.dts b/boards/arm/nrf52811_pca10056/nrf52811_pca10056.dts index 9d052a638398b4..22c830499be464 100644 --- a/boards/arm/nrf52811_pca10056/nrf52811_pca10056.dts +++ b/boards/arm/nrf52811_pca10056/nrf52811_pca10056.dts @@ -26,19 +26,19 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 13 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1: led_1 { - gpios = <&gpio0 14 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; label = "Green LED 1"; }; led2: led_2 { - gpios = <&gpio0 15 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; label = "Green LED 2"; }; led3: led_3 { - gpios = <&gpio0 16 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 16 GPIO_ACTIVE_LOW>; label = "Green LED 3"; }; }; @@ -46,19 +46,19 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 11 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 0"; }; button1: button_1 { - gpios = <&gpio0 12 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 12 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 1"; }; button2: button_2 { - gpios = <&gpio0 24 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 24 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 2"; }; button3: button_3 { - gpios = <&gpio0 25 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 25 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 3"; }; }; diff --git a/boards/arm/nrf52832_mdk/nrf52832_mdk.dts b/boards/arm/nrf52832_mdk/nrf52832_mdk.dts index 22c98080fd5fd2..aefe0f01bd4fb9 100644 --- a/boards/arm/nrf52832_mdk/nrf52832_mdk.dts +++ b/boards/arm/nrf52832_mdk/nrf52832_mdk.dts @@ -27,15 +27,15 @@ leds { compatible = "gpio-leds"; led0_green: led_0 { - gpios = <&gpio0 22 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1_red: led_1 { - gpios = <&gpio0 23 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 23 GPIO_ACTIVE_LOW>; label = "Red LED 1"; }; led2_blue: led_2 { - gpios = <&gpio0 24 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; label = "Blue LED 1"; }; }; @@ -43,7 +43,7 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 18 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 18 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 0"; }; }; diff --git a/boards/arm/nrf52840_blip/nrf52840_blip.dts b/boards/arm/nrf52840_blip/nrf52840_blip.dts index 621401a46fc987..fb879334f41670 100644 --- a/boards/arm/nrf52840_blip/nrf52840_blip.dts +++ b/boards/arm/nrf52840_blip/nrf52840_blip.dts @@ -28,15 +28,15 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 13 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1: led_1 { - gpios = <&gpio0 14 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; label = "Red LED 1"; }; led2: led_2 { - gpios = <&gpio0 15 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; label = "Blue LED 2"; }; }; @@ -44,7 +44,7 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio1 7 GPIO_PUD_PULL_UP>; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; label = "Push button switch 0"; }; }; diff --git a/boards/arm/nrf52840_mdk/nrf52840_mdk.dts b/boards/arm/nrf52840_mdk/nrf52840_mdk.dts index 432ccc7625beca..545cf8d0d90249 100644 --- a/boards/arm/nrf52840_mdk/nrf52840_mdk.dts +++ b/boards/arm/nrf52840_mdk/nrf52840_mdk.dts @@ -26,15 +26,15 @@ leds { compatible = "gpio-leds"; led0_green: led_0 { - gpios = <&gpio0 22 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1_red: led_1 { - gpios = <&gpio0 23 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 23 GPIO_ACTIVE_LOW>; label = "Red LED 1"; }; led2_blue: led_2 { - gpios = <&gpio0 24 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; label = "Blue LED 2"; }; }; @@ -42,7 +42,7 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio1 0 GPIO_PUD_PULL_UP>; + gpios = <&gpio1 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 0"; }; }; diff --git a/boards/arm/nrf52840_papyr/nrf52840_papyr.dts b/boards/arm/nrf52840_papyr/nrf52840_papyr.dts index 92c2559c51f9c7..54ecd9e39c8b91 100644 --- a/boards/arm/nrf52840_papyr/nrf52840_papyr.dts +++ b/boards/arm/nrf52840_papyr/nrf52840_papyr.dts @@ -25,15 +25,15 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 13 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1: led_1 { - gpios = <&gpio0 15 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; label = "Blue LED 1"; }; led2: led_2 { - gpios = <&gpio0 14 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; label = "Red LED 2"; }; }; @@ -41,7 +41,7 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 18 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; label = "Push button switch 0"; }; }; diff --git a/boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts b/boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts index d90b1dd684564f..e6151ea87314ad 100644 --- a/boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts +++ b/boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts @@ -26,19 +26,19 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 13 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1: led_1 { - gpios = <&gpio0 14 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; label = "Green LED 1"; }; led2: led_2 { - gpios = <&gpio0 15 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; label = "Green LED 2"; }; led3: led_3 { - gpios = <&gpio0 16 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 16 GPIO_ACTIVE_LOW>; label = "Green LED 3"; }; }; @@ -46,19 +46,19 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 11 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 0"; }; button1: button_1 { - gpios = <&gpio0 12 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 12 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 1"; }; button2: button_2 { - gpios = <&gpio0 24 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 24 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 2"; }; button3: button_3 { - gpios = <&gpio0 25 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 25 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 3"; }; }; diff --git a/boards/arm/nrf52840_pca10059/nrf52840_pca10059.dts b/boards/arm/nrf52840_pca10059/nrf52840_pca10059.dts index 809690347e68a8..dabb762cd92eb7 100644 --- a/boards/arm/nrf52840_pca10059/nrf52840_pca10059.dts +++ b/boards/arm/nrf52840_pca10059/nrf52840_pca10059.dts @@ -27,19 +27,19 @@ leds { compatible = "gpio-leds"; led0_green: led_0 { - gpios = <&gpio0 6 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1_red: led_1 { - gpios = <&gpio0 8 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; label = "Red LED 1"; }; led1_green: led_2 { - gpios = <&gpio1 9 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; label = "Green LED 1"; }; led1_blue: led_3 { - gpios = <&gpio0 12 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; label = "Blue LED 1"; }; }; @@ -47,7 +47,7 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio1 6 GPIO_PUD_PULL_UP>; + gpios = <&gpio1 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 0"; }; }; diff --git a/boards/arm/nrf52840_pca10090/board.c b/boards/arm/nrf52840_pca10090/board.c index e52a5f334dbae4..26dd18516b0439 100644 --- a/boards/arm/nrf52840_pca10090/board.c +++ b/boards/arm/nrf52840_pca10090/board.c @@ -184,12 +184,12 @@ static int pins_configure(struct device *port, const struct pin_config cfg[], /* The swiches on the board are active low, so we need * to negate the IS_ENABLED() value from the tables. */ - err = gpio_pin_write(port, cfg[i].pin, !cfg[i].val); + err = gpio_pin_set(port, cfg[i].pin, !cfg[i].val); if (err) { return cfg[i].pin; } - err = gpio_pin_configure(port, cfg[i].pin, GPIO_DIR_OUT); + err = gpio_pin_configure(port, cfg[i].pin, GPIO_OUTPUT); if (err) { return cfg[i].pin; } @@ -214,13 +214,12 @@ static void chip_reset(struct device *gpio, static void reset_pin_wait_low(struct device *port, u32_t pin) { - int err; - u32_t val; + int val; /* Wait until the pin is pulled low */ do { - err = gpio_pin_read(port, pin, &val); - } while (err == 0 && val != 0); + val = gpio_pin_get(port, pin); + } while (val > 0); } static int reset_pin_configure(struct device *p0, struct device *p1) @@ -260,9 +259,7 @@ static int reset_pin_configure(struct device *p0, struct device *p1) __ASSERT_NO_MSG(port != NULL); - err = gpio_pin_configure(port, pin, - GPIO_DIR_IN | GPIO_INT | GPIO_PUD_PULL_DOWN | - GPIO_INT_ACTIVE_HIGH | GPIO_INT_EDGE); + err = gpio_pin_configure(port, pin, GPIO_INPUT | GPIO_PULL_DOWN); if (err) { return err; } @@ -274,7 +271,7 @@ static int reset_pin_configure(struct device *p0, struct device *p1) return err; } - err = gpio_pin_enable_callback(port, pin); + err = gpio_pin_interrupt_configure(port, pin, GPIO_INT_EDGE_RISING); if (err) { return err; } diff --git a/boards/arm/nrf52_adafruit_feather/nrf52_adafruit_feather.dts b/boards/arm/nrf52_adafruit_feather/nrf52_adafruit_feather.dts index 51c619c7f7dd56..2f2993935a2674 100644 --- a/boards/arm/nrf52_adafruit_feather/nrf52_adafruit_feather.dts +++ b/boards/arm/nrf52_adafruit_feather/nrf52_adafruit_feather.dts @@ -46,8 +46,7 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 20 (GPIO_PUD_PULL_UP | - GPIO_INT_ACTIVE_LOW)>; + gpios = <&gpio0 20 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Button"; }; }; diff --git a/boards/arm/nrf52_pca10040/nrf52_pca10040.dts b/boards/arm/nrf52_pca10040/nrf52_pca10040.dts index 6209b90856fda7..514ea2cc1d1ff7 100644 --- a/boards/arm/nrf52_pca10040/nrf52_pca10040.dts +++ b/boards/arm/nrf52_pca10040/nrf52_pca10040.dts @@ -27,19 +27,19 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 17 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; label = "Green LED 0"; }; led1: led_1 { - gpios = <&gpio0 18 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; label = "Green LED 1"; }; led2: led_2 { - gpios = <&gpio0 19 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 19 GPIO_ACTIVE_LOW>; label = "Green LED 2"; }; led3: led_3 { - gpios = <&gpio0 20 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; label = "Green LED 3"; }; }; @@ -47,19 +47,19 @@ buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 13 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 0"; }; button1: button_1 { - gpios = <&gpio0 14 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 14 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 1"; }; button2: button_2 { - gpios = <&gpio0 15 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 15 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 2"; }; button3: button_3 { - gpios = <&gpio0 16 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 16 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button switch 3"; }; }; diff --git a/boards/arm/nrf52_pca20020/board.c b/boards/arm/nrf52_pca20020/board.c index 4de76762c50487..6bff9d75f24356 100644 --- a/boards/arm/nrf52_pca20020/board.c +++ b/boards/arm/nrf52_pca20020/board.c @@ -27,8 +27,7 @@ static int pwr_ctrl_init(struct device *dev) return -ENODEV; } - gpio_pin_configure(gpio, cfg->pin, GPIO_DIR_OUT); - gpio_pin_write(gpio, cfg->pin, 1); + gpio_pin_configure(gpio, cfg->pin, GPIO_OUTPUT_HIGH); k_sleep(1); /* Wait for the rail to come up and stabilize */ diff --git a/boards/arm/nrf52_pca20020/nrf52_pca20020.dts b/boards/arm/nrf52_pca20020/nrf52_pca20020.dts index 32056e1023fe8f..7d4d65f6fc65fb 100644 --- a/boards/arm/nrf52_pca20020/nrf52_pca20020.dts +++ b/boards/arm/nrf52_pca20020/nrf52_pca20020.dts @@ -51,7 +51,7 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpio0 11 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Button"; }; }; @@ -101,7 +101,7 @@ compatible = "st,hts221"; reg = <0x5f>; label = "HTS221"; - drdy-gpios = <&gpio0 24 GPIO_INT_ACTIVE_HIGH>; + drdy-gpios = <&gpio0 24 0>; }; ccs811: ccs811@5a { diff --git a/boards/arm/nrf52_sparkfun/nrf52_sparkfun.dts b/boards/arm/nrf52_sparkfun/nrf52_sparkfun.dts index d7972d5731472a..9e9ff8cb3b047c 100644 --- a/boards/arm/nrf52_sparkfun/nrf52_sparkfun.dts +++ b/boards/arm/nrf52_sparkfun/nrf52_sparkfun.dts @@ -32,7 +32,7 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 7 0>; + gpios = <&gpio0 7 GPIO_ACTIVE_LOW>; label = "LED"; }; }; @@ -41,7 +41,7 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpio0 6 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Button"; }; }; diff --git a/boards/arm/nrf52_vbluno52/nrf52_vbluno52.dts b/boards/arm/nrf52_vbluno52/nrf52_vbluno52.dts index 4e4729bb0aa148..5b1131af756e16 100644 --- a/boards/arm/nrf52_vbluno52/nrf52_vbluno52.dts +++ b/boards/arm/nrf52_vbluno52/nrf52_vbluno52.dts @@ -40,7 +40,7 @@ compatible = "gpio-keys"; button0: button_0 { /* gpio flags need validation */ - gpios = <&gpio0 17 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; label = "Button"; }; }; diff --git a/boards/arm/nrf9160_pca10090/nrf52840_reset.c b/boards/arm/nrf9160_pca10090/nrf52840_reset.c index dd7ded9f0e64bb..c793b5076eaa81 100644 --- a/boards/arm/nrf9160_pca10090/nrf52840_reset.c +++ b/boards/arm/nrf9160_pca10090/nrf52840_reset.c @@ -27,15 +27,8 @@ int bt_hci_transport_setup(struct device *h4) return -EIO; } - /* Pull the pin low before configuring it as output, to ensure that - * it is driven to the correct level as soon as it is configured. - */ - err = gpio_pin_write(port, RESET_PIN, 0); - if (err) { - return err; - } - - err = gpio_pin_configure(port, RESET_PIN, GPIO_DIR_OUT); + /* Configure pin as output and initialize it to low. */ + err = gpio_pin_configure(port, RESET_PIN, GPIO_OUTPUT_LOW); if (err) { return err; } @@ -45,7 +38,7 @@ int bt_hci_transport_setup(struct device *h4) * that it won't send any data until the H4 device * is setup and ready to receive. */ - err = gpio_pin_write(port, RESET_PIN, 1); + err = gpio_pin_set(port, RESET_PIN, 1); if (err) { return err; } @@ -63,7 +56,7 @@ int bt_hci_transport_setup(struct device *h4) } /* We are ready, let the nRF52840 run to main */ - err = gpio_pin_write(port, RESET_PIN, 0); + err = gpio_pin_set(port, RESET_PIN, 0); if (err) { return err; } diff --git a/boards/arm/nrf9160_pca10090/nrf9160_pca10090_common.dts b/boards/arm/nrf9160_pca10090/nrf9160_pca10090_common.dts index c441bffa4ecf05..6db9ec2912bd4e 100644 --- a/boards/arm/nrf9160_pca10090/nrf9160_pca10090_common.dts +++ b/boards/arm/nrf9160_pca10090/nrf9160_pca10090_common.dts @@ -18,39 +18,39 @@ leds { compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio0 2 GPIO_INT_ACTIVE_HIGH>; - label = "Green LED 0"; + gpios = <&gpio0 2 0>; + label = "Green LED 1"; }; led1: led_1 { - gpios = <&gpio0 3 GPIO_INT_ACTIVE_HIGH>; - label = "Green LED 1"; + gpios = <&gpio0 3 0>; + label = "Green LED 2"; }; led2: led_2 { - gpios = <&gpio0 4 GPIO_INT_ACTIVE_HIGH>; - label = "Green LED 2"; + gpios = <&gpio0 4 0>; + label = "Green LED 3"; }; led3: led_3 { - gpios = <&gpio0 5 GPIO_INT_ACTIVE_HIGH>; - label = "Green LED 3"; + gpios = <&gpio0 5 0>; + label = "Green LED 4"; }; }; buttons { compatible = "gpio-keys"; button0: button_0 { - gpios = <&gpio0 8 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Switch 1"; }; button1: button_1 { - gpios = <&gpio0 9 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Switch 2"; }; button2: button_2 { - gpios = <&gpio0 6 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button 1"; }; button3: button_3 { - gpios = <&gpio0 7 GPIO_PUD_PULL_UP>; + gpios = <&gpio0 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; label = "Push button 2"; }; }; diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index 5050ee9c284e49..36216eeb1146a6 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -11,6 +11,7 @@ #include "gpio_utils.h" struct gpio_nrfx_data { + struct gpio_driver_data general; sys_slist_t callbacks; /* Mask holding information about which pins have been configured to @@ -23,10 +24,9 @@ struct gpio_nrfx_data { */ u32_t int_en; - u32_t active_level; + u32_t int_active_level; u32_t trig_edge; u32_t double_edge; - u32_t inverted; }; struct gpio_nrfx_cfg { @@ -34,6 +34,9 @@ struct gpio_nrfx_cfg { u8_t port_num; }; +static int gpio_nrfx_pin_interrupt_configure(struct device *port, u32_t pin, + unsigned int flags); + static inline struct gpio_nrfx_data *get_port_data(struct device *port) { return port->driver_data; @@ -79,7 +82,7 @@ static void gpiote_channel_free(u32_t abs_pin) static inline u32_t sense_for_pin(const struct gpio_nrfx_data *data, u32_t pin) { - if ((BIT(pin) & (data->active_level ^ data->inverted)) != 0) { + if ((BIT(pin) & data->int_active_level) != 0U) { return NRF_GPIO_PIN_SENSE_HIGH; } return NRF_GPIO_PIN_SENSE_LOW; @@ -105,8 +108,7 @@ static int gpiote_pin_int_cfg(struct device *port, u32_t pin) if (data->double_edge & BIT(pin)) { pol = NRF_GPIOTE_POLARITY_TOGGLE; - } else if (((data->active_level & BIT(pin)) != 0U) - ^ ((BIT(pin) & data->inverted) != 0)) { + } else if ((data->int_active_level & BIT(pin)) != 0U) { pol = NRF_GPIOTE_POLARITY_LOTOHI; } else { pol = NRF_GPIOTE_POLARITY_HITOLO; @@ -126,6 +128,7 @@ static int gpiote_pin_int_cfg(struct device *port, u32_t pin) static int gpio_nrfx_config(struct device *port, int access_op, u32_t pin, int flags) { + NRF_GPIO_Type *reg = get_port_cfg(port)->port; struct gpio_nrfx_data *data = get_port_data(port); nrf_gpio_pin_pull_t pull; nrf_gpio_pin_drive_t drive; @@ -134,14 +137,15 @@ static int gpio_nrfx_config(struct device *port, int access_op, u8_t from_pin; u8_t to_pin; - switch (flags & (GPIO_DS_LOW_MASK | GPIO_DS_HIGH_MASK)) { + switch (flags & (GPIO_DS_LOW_MASK | GPIO_DS_HIGH_MASK | + GPIO_OPEN_DRAIN)) { case GPIO_DS_DFLT_LOW | GPIO_DS_DFLT_HIGH: drive = NRF_GPIO_PIN_S0S1; break; case GPIO_DS_DFLT_LOW | GPIO_DS_ALT_HIGH: drive = NRF_GPIO_PIN_S0H1; break; - case GPIO_DS_DFLT_LOW | GPIO_DS_DISCONNECT_HIGH: + case GPIO_DS_DFLT_LOW | GPIO_OPEN_DRAIN: drive = NRF_GPIO_PIN_S0D1; break; @@ -151,14 +155,14 @@ static int gpio_nrfx_config(struct device *port, int access_op, case GPIO_DS_ALT_LOW | GPIO_DS_ALT_HIGH: drive = NRF_GPIO_PIN_H0H1; break; - case GPIO_DS_ALT_LOW | GPIO_DS_DISCONNECT_HIGH: + case GPIO_DS_ALT_LOW | GPIO_OPEN_DRAIN: drive = NRF_GPIO_PIN_H0D1; break; - case GPIO_DS_DISCONNECT_LOW | GPIO_DS_DFLT_HIGH: + case GPIO_DS_DFLT_HIGH | GPIO_OPEN_SOURCE: drive = NRF_GPIO_PIN_D0S1; break; - case GPIO_DS_DISCONNECT_LOW | GPIO_DS_ALT_HIGH: + case GPIO_DS_ALT_HIGH | GPIO_OPEN_SOURCE: drive = NRF_GPIO_PIN_D0H1; break; @@ -166,19 +170,19 @@ static int gpio_nrfx_config(struct device *port, int access_op, return -EINVAL; } - if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_UP) { + if ((flags & GPIO_PULL_UP) != 0) { pull = NRF_GPIO_PIN_PULLUP; - } else if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_DOWN) { + } else if ((flags & GPIO_PULL_DOWN) != 0) { pull = NRF_GPIO_PIN_PULLDOWN; } else { pull = NRF_GPIO_PIN_NOPULL; } - dir = ((flags & GPIO_DIR_MASK) == GPIO_DIR_OUT) + dir = ((flags & GPIO_OUTPUT) != 0) ? NRF_GPIO_PIN_DIR_OUTPUT : NRF_GPIO_PIN_DIR_INPUT; - input = (dir == NRF_GPIO_PIN_DIR_INPUT) + input = ((flags & GPIO_INPUT) != 0) ? NRF_GPIO_PIN_INPUT_CONNECT : NRF_GPIO_PIN_INPUT_DISCONNECT; @@ -193,19 +197,22 @@ static int gpio_nrfx_config(struct device *port, int access_op, for (u8_t curr_pin = from_pin; curr_pin <= to_pin; ++curr_pin) { int res; + if ((flags & GPIO_OUTPUT) != 0) { + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { + nrf_gpio_port_out_set(reg, BIT(curr_pin)); + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { + nrf_gpio_port_out_clear(reg, BIT(curr_pin)); + } + } + nrf_gpio_cfg(NRF_GPIO_PIN_MAP(get_port_cfg(port)->port_num, curr_pin), dir, input, pull, drive, NRF_GPIO_PIN_NOSENSE); - WRITE_BIT(data->pin_int_en, curr_pin, flags & GPIO_INT); - WRITE_BIT(data->trig_edge, curr_pin, flags & GPIO_INT_EDGE); - WRITE_BIT(data->double_edge, curr_pin, - flags & GPIO_INT_DOUBLE_EDGE); - WRITE_BIT(data->active_level, curr_pin, - flags & GPIO_INT_ACTIVE_HIGH); - WRITE_BIT(data->inverted, curr_pin, flags & GPIO_POL_INV); + WRITE_BIT(data->general.invert, curr_pin, + flags & GPIO_ACTIVE_LOW); - res = gpiote_pin_int_cfg(port, curr_pin); + res = gpio_nrfx_pin_interrupt_configure(port, curr_pin, flags); if (res != 0) { return res; } @@ -221,9 +228,9 @@ static int gpio_nrfx_write(struct device *port, int access_op, struct gpio_nrfx_data *data = get_port_data(port); if (access_op == GPIO_ACCESS_BY_PORT) { - nrf_gpio_port_out_write(reg, value ^ data->inverted); + nrf_gpio_port_out_write(reg, value ^ data->general.invert); } else { - if ((value > 0) ^ ((BIT(pin) & data->inverted) != 0)) { + if ((value > 0) ^ ((BIT(pin) & data->general.invert) != 0)) { nrf_gpio_port_out_set(reg, BIT(pin)); } else { nrf_gpio_port_out_clear(reg, BIT(pin)); @@ -242,7 +249,7 @@ static int gpio_nrfx_read(struct device *port, int access_op, u32_t dir = nrf_gpio_port_dir_read(reg); u32_t port_in = nrf_gpio_port_in_read(reg) & ~dir; u32_t port_out = nrf_gpio_port_out_read(reg) & dir; - u32_t port_val = (port_in | port_out) ^ data->inverted; + u32_t port_val = (port_in | port_out) ^ data->general.invert; if (access_op == GPIO_ACCESS_BY_PORT) { *value = port_val; @@ -253,6 +260,91 @@ static int gpio_nrfx_read(struct device *port, int access_op, return 0; } +static int gpio_nrfx_port_get_raw(struct device *port, u32_t *value) +{ + NRF_GPIO_Type *reg = get_port_cfg(port)->port; + + *value = nrf_gpio_port_in_read(reg); + + return 0; +} + +static int gpio_nrfx_port_set_masked_raw(struct device *port, u32_t mask, + u32_t value) +{ + NRF_GPIO_Type *reg = get_port_cfg(port)->port; + u32_t value_tmp; + + value_tmp = nrf_gpio_port_out_read(reg) & ~mask; + nrf_gpio_port_out_write(reg, value_tmp | (mask & value)); + + return 0; +} + +static int gpio_nrfx_port_set_bits_raw(struct device *port, u32_t mask) +{ + NRF_GPIO_Type *reg = get_port_cfg(port)->port; + + nrf_gpio_port_out_set(reg, mask); + + return 0; +} + +static int gpio_nrfx_port_clear_bits_raw(struct device *port, u32_t mask) +{ + NRF_GPIO_Type *reg = get_port_cfg(port)->port; + + nrf_gpio_port_out_clear(reg, mask); + + return 0; +} + +static int gpio_nrfx_port_toggle_bits(struct device *port, u32_t mask) +{ + NRF_GPIO_Type *reg = get_port_cfg(port)->port; + u32_t value; + + value = nrf_gpio_port_out_read(reg); + nrf_gpio_port_out_write(reg, value ^ mask); + + return 0; +} + +static int gpio_nrfx_pin_interrupt_configure(struct device *port, + unsigned int pin, unsigned int flags) +{ + struct gpio_nrfx_data *data = get_port_data(port); + u32_t abs_pin = NRF_GPIO_PIN_MAP(get_port_cfg(port)->port_num, pin); + + if (((flags & GPIO_INT_ENABLE) != 0) && + ((flags & GPIO_INT_EDGE) != 0) && + (nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_OUTPUT)) { + /* + * The pin's output value as specified in the GPIO will be + * ignored as long as the pin is controlled by GPIOTE. + * Pin with output enabled cannot be used as an edge interrupt + * source. + */ + return -ENOTSUP; + } + + WRITE_BIT(data->pin_int_en, pin, flags & GPIO_INT_ENABLE); + WRITE_BIT(data->int_en, pin, true); + WRITE_BIT(data->trig_edge, pin, flags & GPIO_INT_EDGE); + WRITE_BIT(data->double_edge, pin, (flags & GPIO_INT_LOW_0) && + (flags & GPIO_INT_HIGH_1)); + + bool active_high = ((flags & GPIO_INT_HIGH_1) != 0); + + if (((flags & GPIO_INT_LEVELS_LOGICAL) != 0) && + ((data->general.invert & BIT(pin)) != 0)) { + active_high = !active_high; + } + WRITE_BIT(data->int_active_level, pin, active_high); + + return gpiote_pin_int_cfg(port, pin); +} + static int gpio_nrfx_manage_callback(struct device *port, struct gpio_callback *callback, bool set) @@ -309,6 +401,12 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { .config = gpio_nrfx_config, .write = gpio_nrfx_write, .read = gpio_nrfx_read, + .port_get_raw = gpio_nrfx_port_get_raw, + .port_set_masked_raw = gpio_nrfx_port_set_masked_raw, + .port_set_bits_raw = gpio_nrfx_port_set_bits_raw, + .port_clear_bits_raw = gpio_nrfx_port_clear_bits_raw, + .port_toggle_bits = gpio_nrfx_port_toggle_bits, + .pin_interrupt_configure = gpio_nrfx_pin_interrupt_configure, .manage_callback = gpio_nrfx_manage_callback, .enable_callback = gpio_nrfx_pin_enable_callback, .disable_callback = gpio_nrfx_pin_disable_callback @@ -369,10 +467,9 @@ static u32_t check_level_trigger_pins(struct device *port) u32_t level_pins = get_level_pins(port); u32_t port_in = nrf_gpio_port_in_read(cfg->port); - /* Extract which pins after inversion, have logic level same as - * interrupt trigger level. + /* Extract which pins have logic level same as interrupt trigger level. */ - u32_t pin_states = ~(port_in ^ data->inverted ^ data->active_level); + u32_t pin_states = ~(port_in ^ data->int_active_level); /* Discard pins that aren't configured for level. */ u32_t out = pin_states & level_pins; From 8b4e7e45a4bd444aaa052cd1f707c32b2ecb7450 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Fri, 9 Aug 2019 01:28:40 +0200 Subject: [PATCH 09/12] drivers: gpio_mcux: update to use new GPIO API Update driver code and board files to use new GPIO configuration flags such as GPIO_ACTIVE_LOW. Also add implementation of new port_* driver API as well as gpio_pin_interrupt_configure function. Tested on frdm_k64f board. Signed-off-by: Piotr Mienkowski --- boards/arm/frdm_k64f/frdm_k64f.dts | 10 +- boards/arm/frdm_kl25z/frdm_kl25z.dts | 10 +- boards/arm/frdm_kw41z/frdm_kw41z.dts | 10 +- boards/arm/hexiwear_k64/hexiwear_k64.dts | 6 +- boards/arm/twr_ke18f/twr_ke18f.dts | 18 +- boards/arm/usb_kw24d512/usb_kw24d512.dts | 6 +- drivers/gpio/gpio_mcux.c | 200 +++++++++++++++++++---- 7 files changed, 197 insertions(+), 63 deletions(-) diff --git a/boards/arm/frdm_k64f/frdm_k64f.dts b/boards/arm/frdm_k64f/frdm_k64f.dts index da159f95e6f845..a672d97ed62c0b 100644 --- a/boards/arm/frdm_k64f/frdm_k64f.dts +++ b/boards/arm/frdm_k64f/frdm_k64f.dts @@ -51,15 +51,15 @@ leds { compatible = "gpio-leds"; red_led: led_0 { - gpios = <&gpiob 22 0>; + gpios = <&gpiob 22 GPIO_ACTIVE_LOW>; label = "User LD1"; }; green_led: led_1 { - gpios = <&gpioe 26 0>; + gpios = <&gpioe 26 GPIO_ACTIVE_LOW>; label = "User LD2"; }; blue_led: led_2 { - gpios = <&gpiob 21 0>; + gpios = <&gpiob 21 GPIO_ACTIVE_LOW>; label = "User LD3"; }; }; @@ -68,11 +68,11 @@ compatible = "gpio-keys"; user_button_2: button_0 { label = "User SW2"; - gpios = <&gpioc 6 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpioc 6 GPIO_ACTIVE_LOW>; }; user_button_3: button_1 { label = "User SW3"; - gpios = <&gpioa 4 (GPIO_INT_ACTIVE_LOW | GPIO_PUD_PULL_UP)>; + gpios = <&gpioa 4 GPIO_ACTIVE_LOW>; }; }; diff --git a/boards/arm/frdm_kl25z/frdm_kl25z.dts b/boards/arm/frdm_kl25z/frdm_kl25z.dts index 8b38cb2dc1faa5..1491ee1686e992 100644 --- a/boards/arm/frdm_kl25z/frdm_kl25z.dts +++ b/boards/arm/frdm_kl25z/frdm_kl25z.dts @@ -35,15 +35,15 @@ leds { compatible = "gpio-leds"; red_led: led_0 { - gpios = <&gpiob 18 0>; + gpios = <&gpiob 18 GPIO_ACTIVE_LOW>; label = "User LD1"; }; green_led: led_1 { - gpios = <&gpiob 19 0>; + gpios = <&gpiob 19 GPIO_ACTIVE_LOW>; label = "User LD2"; }; blue_led: led_2 { - gpios = <&gpiod 1 0>; + gpios = <&gpiod 1 GPIO_ACTIVE_LOW>; label = "User LD3"; }; }; @@ -52,11 +52,11 @@ compatible = "gpio-keys"; user_button_0: button_0 { label = "User SW0"; - gpios = <&gpioa 16 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpioa 16 GPIO_ACTIVE_LOW>; }; user_button_1: button_1 { label = "User SW1"; - gpios = <&gpioa 17 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpioa 17 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/boards/arm/frdm_kw41z/frdm_kw41z.dts b/boards/arm/frdm_kw41z/frdm_kw41z.dts index 1a1aa78a5100f7..5045de78c04d35 100644 --- a/boards/arm/frdm_kw41z/frdm_kw41z.dts +++ b/boards/arm/frdm_kw41z/frdm_kw41z.dts @@ -37,15 +37,15 @@ leds { compatible = "gpio-leds"; red_led: led_0 { - gpios = <&gpioc 1 0>; + gpios = <&gpioc 1 GPIO_ACTIVE_LOW>; label = "User LD1"; }; green_led: led_1 { - gpios = <&gpioa 19 0>; + gpios = <&gpioa 19 GPIO_ACTIVE_LOW>; label = "User LD2"; }; blue_led: led_2 { - gpios = <&gpioa 18 0>; + gpios = <&gpioa 18 GPIO_ACTIVE_LOW>; label = "User LD3"; }; }; @@ -54,11 +54,11 @@ compatible = "gpio-keys"; user_button_3: button_0 { label = "User SW3"; - gpios = <&gpioc 4 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpioc 4 GPIO_ACTIVE_LOW>; }; user_button_4: button_1 { label = "User SW4"; - gpios = <&gpioc 5 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpioc 5 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/boards/arm/hexiwear_k64/hexiwear_k64.dts b/boards/arm/hexiwear_k64/hexiwear_k64.dts index 9c845697f067de..100779c946ea31 100644 --- a/boards/arm/hexiwear_k64/hexiwear_k64.dts +++ b/boards/arm/hexiwear_k64/hexiwear_k64.dts @@ -51,15 +51,15 @@ leds { compatible = "gpio-leds"; red_led: led_0 { - gpios = <&gpioc 8 0>; + gpios = <&gpioc 8 GPIO_ACTIVE_LOW>; label = "User LD1"; }; green_led: led_1 { - gpios = <&gpiod 0 0>; + gpios = <&gpiod 0 GPIO_ACTIVE_LOW>; label = "User LD2"; }; blue_led: led_2 { - gpios = <&gpioc 9 0>; + gpios = <&gpioc 9 GPIO_ACTIVE_LOW>; label = "User LD3"; }; }; diff --git a/boards/arm/twr_ke18f/twr_ke18f.dts b/boards/arm/twr_ke18f/twr_ke18f.dts index cff5ba75507ad8..d6752a304ec325 100644 --- a/boards/arm/twr_ke18f/twr_ke18f.dts +++ b/boards/arm/twr_ke18f/twr_ke18f.dts @@ -44,32 +44,32 @@ leds { compatible = "gpio-leds"; orange_led: led_0 { - gpios = <&gpioc 13 0>; + gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; label = "User LED D9"; }; yellow_led: led_1 { - gpios = <&gpioc 12 0>; + gpios = <&gpioc 12 GPIO_ACTIVE_LOW>; label = "User LED D8"; }; green_led: led_2 { - gpios = <&gpioc 11 0>; + gpios = <&gpioc 11 GPIO_ACTIVE_LOW>; label = "User LED D7"; }; red_led: led_3 { - gpios = <&gpioc 10 0>; + gpios = <&gpioc 10 GPIO_ACTIVE_LOW>; label = "User LED D6"; }; tri_red_led: led_4 { - gpios = <&gpiod 16 0>; + gpios = <&gpiod 16 GPIO_ACTIVE_LOW>; label = "User Tricolor LED D5 (Red)"; }; tri_green_led: led_5 { - gpios = <&gpiod 15 0>; + gpios = <&gpiod 15 GPIO_ACTIVE_LOW>; label = "User Tricolor LED D5 (Green)"; }; tri_blue_led: led_6 { - gpios = <&gpiob 5 0>; + gpios = <&gpiob 5 GPIO_ACTIVE_LOW>; label = "User Tricolor LED D5 (Blue)"; }; }; @@ -111,11 +111,11 @@ compatible = "gpio-keys"; user_button_2: button_0 { label = "User SW2"; - gpios = <&gpiod 3 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiod 3 GPIO_ACTIVE_LOW>; }; user_button_3: button_1 { label = "User SW3"; - gpios = <&gpiod 6 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpiod 6 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/boards/arm/usb_kw24d512/usb_kw24d512.dts b/boards/arm/usb_kw24d512/usb_kw24d512.dts index 03cf5b8dd22d2d..e88e11ab93aca4 100644 --- a/boards/arm/usb_kw24d512/usb_kw24d512.dts +++ b/boards/arm/usb_kw24d512/usb_kw24d512.dts @@ -37,11 +37,11 @@ leds { compatible = "gpio-leds"; led_0: led_0 { - gpios = <&gpiod 4 0>; + gpios = <&gpiod 4 GPIO_ACTIVE_LOW>; label = "User LD1"; }; led_1: led_1 { - gpios = <&gpiod 5 0>; + gpios = <&gpiod 5 GPIO_ACTIVE_LOW>; label = "User LD2"; }; }; @@ -50,7 +50,7 @@ compatible = "gpio-keys"; user_button_1: button_0 { label = "User SW1"; - gpios = <&gpioc 4 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpioc 4 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/drivers/gpio/gpio_mcux.c b/drivers/gpio/gpio_mcux.c index 796ea792e4ad0b..8d6ab367b755b2 100644 --- a/drivers/gpio/gpio_mcux.c +++ b/drivers/gpio/gpio_mcux.c @@ -21,19 +21,60 @@ struct gpio_mcux_config { }; struct gpio_mcux_data { + struct gpio_driver_data general; /* port ISR callback routine address */ sys_slist_t callbacks; /* pin callback routine enable flags, by pin number */ u32_t pin_callback_enables; }; +static u32_t get_port_pcr_irqc_value_from_flags(struct device *dev, + u32_t pin, unsigned int flags) +{ + struct gpio_mcux_data *data = dev->driver_data; + port_interrupt_t port_interrupt = 0; + bool rising_edge; + bool falling_edge; + + if ((flags & GPIO_INT_LEVELS_LOGICAL) && + (data->general.invert & BIT(pin))) { + rising_edge = flags & GPIO_INT_LOW_0; + falling_edge = flags & GPIO_INT_HIGH_1; + } else { + rising_edge = flags & GPIO_INT_HIGH_1; + falling_edge = flags & GPIO_INT_LOW_0; + } + + if (flags & GPIO_INT_ENABLE) { + if (flags & GPIO_INT_EDGE) { + if (rising_edge && falling_edge) { + port_interrupt = kPORT_InterruptEitherEdge; + } else if (rising_edge) { + port_interrupt = kPORT_InterruptRisingEdge; + } else { + port_interrupt = kPORT_InterruptFallingEdge; + } + } else { /* GPIO_INT_LEVEL */ + if (rising_edge) { + port_interrupt = kPORT_InterruptLogicOne; + } else { + port_interrupt = kPORT_InterruptLogicZero; + } + } + } else { + port_interrupt = kPORT_InterruptOrDMADisabled; + } + + return PORT_PCR_IRQC(port_interrupt); +} + static int gpio_mcux_configure(struct device *dev, int access_op, u32_t pin, int flags) { const struct gpio_mcux_config *config = dev->config->config_info; GPIO_Type *gpio_base = config->gpio_base; PORT_Type *port_base = config->port_base; - port_interrupt_t port_interrupt = 0; + struct gpio_mcux_data *data = dev->driver_data; u32_t mask = 0U; u32_t pcr = 0U; u8_t i; @@ -44,15 +85,30 @@ static int gpio_mcux_configure(struct device *dev, } /* Check for an invalid pin configuration */ - if ((flags & GPIO_INT) && (flags & GPIO_DIR_OUT)) { + if ((flags & GPIO_INT_ENABLE) && ((flags & GPIO_INPUT) == 0)) { return -EINVAL; } + if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) { + return -ENOTSUP; + } + + if ((flags & GPIO_SINGLE_ENDED) != 0) { + return -ENOTSUP; + } + /* Check if GPIO port supports interrupts */ - if ((flags & GPIO_INT) && ((config->flags & GPIO_INT) == 0U)) { + if ((flags & GPIO_INT_ENABLE) && + ((config->flags & GPIO_INT_ENABLE) == 0U)) { return -ENOTSUP; } + if ((flags & GPIO_ACTIVE_LOW) != 0) { + data->general.invert |= BIT(pin); + } else { + data->general.invert &= ~BIT(pin); + } + /* The flags contain options that require touching registers in the * GPIO module and the corresponding PORT module. * @@ -61,15 +117,20 @@ static int gpio_mcux_configure(struct device *dev, */ if (access_op == GPIO_ACCESS_BY_PIN) { - if ((flags & GPIO_DIR_MASK) == GPIO_DIR_IN) { + if ((flags & GPIO_INPUT) != 0) { gpio_base->PDDR &= ~BIT(pin); - } else { /* GPIO_DIR_OUT */ + } else { /* GPIO_OUTPUT */ + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { + gpio_base->PSOR = BIT(pin); + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { + gpio_base->PCOR = BIT(pin); + } gpio_base->PDDR |= BIT(pin); } } else { /* GPIO_ACCESS_BY_PORT */ - if ((flags & GPIO_DIR_MASK) == GPIO_DIR_IN) { + if ((flags & GPIO_INPUT) != 0) { gpio_base->PDDR = 0x0; - } else { /* GPIO_DIR_OUT */ + } else { /* GPIO_OUTPUT */ gpio_base->PDDR = 0xFFFFFFFF; } } @@ -79,11 +140,11 @@ static int gpio_mcux_configure(struct device *dev, */ mask |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; - if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_UP) { + if ((flags & GPIO_PULL_UP) != 0) { /* Enable the pull and select the pullup resistor. */ pcr |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; - } else if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_DOWN) { + } else if ((flags & GPIO_PULL_DOWN) != 0) { /* Enable the pull and select the pulldown resistor (deselect * the pullup resistor. */ @@ -94,25 +155,7 @@ static int gpio_mcux_configure(struct device *dev, * but don't write it to the PCR register yet. */ mask |= PORT_PCR_IRQC_MASK; - - if (flags & GPIO_INT) { - if (flags & GPIO_INT_EDGE) { - if (flags & GPIO_INT_ACTIVE_HIGH) { - port_interrupt = kPORT_InterruptRisingEdge; - } else if (flags & GPIO_INT_DOUBLE_EDGE) { - port_interrupt = kPORT_InterruptEitherEdge; - } else { - port_interrupt = kPORT_InterruptFallingEdge; - } - } else { /* GPIO_INT_LEVEL */ - if (flags & GPIO_INT_ACTIVE_HIGH) { - port_interrupt = kPORT_InterruptLogicOne; - } else { - port_interrupt = kPORT_InterruptLogicZero; - } - } - pcr |= PORT_PCR_IRQC(port_interrupt); - } + pcr |= get_port_pcr_irqc_value_from_flags(dev, pin, flags); /* Now we can write the PORT PCR register(s). If accessing by pin, we * only need to write one PCR register. Otherwise, write all the PCR @@ -120,10 +163,17 @@ static int gpio_mcux_configure(struct device *dev, */ if (access_op == GPIO_ACCESS_BY_PIN) { port_base->PCR[pin] = (port_base->PCR[pin] & ~mask) | pcr; + WRITE_BIT(data->pin_callback_enables, pin, + flags & GPIO_INT_ENABLE); } else { /* GPIO_ACCESS_BY_PORT */ for (i = 0U; i < ARRAY_SIZE(port_base->PCR); i++) { port_base->PCR[i] = (port_base->PCR[pin] & ~mask) | pcr; } + if (flags & GPIO_INT_ENABLE) { + data->pin_callback_enables = 0xFFFFFFFF; + } else { + data->pin_callback_enables = 0x0; + } } return 0; @@ -174,6 +224,84 @@ static int gpio_mcux_read(struct device *dev, return 0; } +static int gpio_mcux_port_get_raw(struct device *dev, u32_t *value) +{ + const struct gpio_mcux_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + *value = gpio_base->PDIR; + + return 0; +} + +static int gpio_mcux_port_set_masked_raw(struct device *dev, u32_t mask, + u32_t value) +{ + const struct gpio_mcux_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + gpio_base->PDOR = (gpio_base->PDOR & ~mask) | (mask & value); + + return 0; +} + +static int gpio_mcux_port_set_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_mcux_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + gpio_base->PSOR = mask; + + return 0; +} + +static int gpio_mcux_port_clear_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_mcux_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + gpio_base->PCOR = mask; + + return 0; +} + +static int gpio_mcux_port_toggle_bits(struct device *dev, u32_t mask) +{ + const struct gpio_mcux_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + gpio_base->PTOR = mask; + + return 0; +} + +static int gpio_mcux_pin_interrupt_configure(struct device *dev, + unsigned int pin, unsigned int flags) +{ + const struct gpio_mcux_config *config = dev->config->config_info; + PORT_Type *port_base = config->port_base; + struct gpio_mcux_data *data = dev->driver_data; + + /* Check for an invalid pin number */ + if (pin >= ARRAY_SIZE(port_base->PCR)) { + return -EINVAL; + } + + /* Check if GPIO port supports interrupts */ + if ((flags & GPIO_INT_ENABLE) && + ((config->flags & GPIO_INT_ENABLE) == 0U)) { + return -ENOTSUP; + } + + u32_t pcr = get_port_pcr_irqc_value_from_flags(dev, pin, flags); + + port_base->PCR[pin] = (port_base->PCR[pin] & ~PORT_PCR_IRQC_MASK) | pcr; + + WRITE_BIT(data->pin_callback_enables, pin, flags & GPIO_INT_ENABLE); + + return 0; +} + static int gpio_mcux_manage_callback(struct device *dev, struct gpio_callback *callback, bool set) { @@ -231,6 +359,12 @@ static const struct gpio_driver_api gpio_mcux_driver_api = { .config = gpio_mcux_configure, .write = gpio_mcux_write, .read = gpio_mcux_read, + .port_get_raw = gpio_mcux_port_get_raw, + .port_set_masked_raw = gpio_mcux_port_set_masked_raw, + .port_set_bits_raw = gpio_mcux_port_set_bits_raw, + .port_clear_bits_raw = gpio_mcux_port_clear_bits_raw, + .port_toggle_bits = gpio_mcux_port_toggle_bits, + .pin_interrupt_configure = gpio_mcux_pin_interrupt_configure, .manage_callback = gpio_mcux_manage_callback, .enable_callback = gpio_mcux_enable_callback, .disable_callback = gpio_mcux_disable_callback, @@ -243,7 +377,7 @@ static const struct gpio_mcux_config gpio_mcux_porta_config = { .gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_A_BASE_ADDRESS, .port_base = PORTA, #ifdef DT_NXP_KINETIS_GPIO_GPIO_A_IRQ_0 - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -276,7 +410,7 @@ static const struct gpio_mcux_config gpio_mcux_portb_config = { .gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_B_BASE_ADDRESS, .port_base = PORTB, #ifdef DT_NXP_KINETIS_GPIO_GPIO_B_IRQ_0 - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -309,7 +443,7 @@ static const struct gpio_mcux_config gpio_mcux_portc_config = { .gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_C_BASE_ADDRESS, .port_base = PORTC, #ifdef DT_NXP_KINETIS_GPIO_GPIO_C_IRQ_0 - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -342,7 +476,7 @@ static const struct gpio_mcux_config gpio_mcux_portd_config = { .gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_D_BASE_ADDRESS, .port_base = PORTD, #ifdef DT_NXP_KINETIS_GPIO_GPIO_D_IRQ_0 - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -375,7 +509,7 @@ static const struct gpio_mcux_config gpio_mcux_porte_config = { .gpio_base = (GPIO_Type *) DT_NXP_KINETIS_GPIO_GPIO_E_BASE_ADDRESS, .port_base = PORTE, #ifdef DT_NXP_KINETIS_GPIO_GPIO_E_IRQ_0 - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif From b1a3ead86c391cb71c82c4f6623fa90bd8032c35 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Tue, 29 Jan 2019 00:33:10 +0100 Subject: [PATCH 10/12] samples: blinky: update to use new GPIO API Update gpio_pin_configure() to take into account GPIO flags defined by the devicetree. Signed-off-by: Piotr Mienkowski --- samples/basic/blinky/src/main.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/samples/basic/blinky/src/main.c b/samples/basic/blinky/src/main.c index edb6661df6e87d..aad77f70b3205a 100644 --- a/samples/basic/blinky/src/main.c +++ b/samples/basic/blinky/src/main.c @@ -8,25 +8,28 @@ #include #include -#define LED_PORT DT_ALIAS_LED0_GPIOS_CONTROLLER -#define LED DT_ALIAS_LED0_GPIOS_PIN - -/* 1000 msec = 1 sec */ -#define SLEEP_TIME 1000 +#define SLEEP_TIME_MS 1000 void main(void) { - int cnt = 0; struct device *dev; + bool led_is_on = false; + int ret; + + dev = device_get_binding(DT_ALIAS_LED0_GPIOS_CONTROLLER); + if (dev == NULL) { + return; + } - dev = device_get_binding(LED_PORT); - /* Set LED pin as output */ - gpio_pin_configure(dev, LED, GPIO_DIR_OUT); + ret = gpio_pin_configure(dev, DT_ALIAS_LED0_GPIOS_PIN, GPIO_OUTPUT | + DT_ALIAS_LED0_GPIOS_FLAGS); + if (ret < 0) { + return; + } while (1) { - /* Set pin to HIGH/LOW every 1 second */ - gpio_pin_write(dev, LED, cnt % 2); - cnt++; - k_sleep(SLEEP_TIME); + gpio_pin_set(dev, DT_ALIAS_LED0_GPIOS_PIN, (int)led_is_on); + led_is_on = !led_is_on; + k_sleep(SLEEP_TIME_MS); } } From 09298e40fd4a8af09497b487ba97c4995c022578 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Mon, 3 Jun 2019 12:29:18 +0200 Subject: [PATCH 11/12] samples: button: update to use new GPIO API Update gpio_pin_configure() to take into account GPIO flags defined by the devicetree. Use gpio_pin_get/gpio_pin_set to verify reading/writing of logical pin values. Use gpio_pin_interrupt_configure() to configure interrupts. Signed-off-by: Piotr Mienkowski --- samples/basic/button/src/main.c | 108 +++++++++++++++----------------- 1 file changed, 52 insertions(+), 56 deletions(-) diff --git a/samples/basic/button/src/main.c b/samples/basic/button/src/main.c index d55147c171a781..d92c1d53f6064b 100644 --- a/samples/basic/button/src/main.c +++ b/samples/basic/button/src/main.c @@ -11,79 +11,75 @@ #include #include -/* change this to use another GPIO port */ -#ifndef DT_ALIAS_SW0_GPIOS_CONTROLLER -#ifdef SW0_GPIO_NAME -#define DT_ALIAS_SW0_GPIOS_CONTROLLER SW0_GPIO_NAME -#else -#error SW0_GPIO_NAME or DT_ALIAS_SW0_GPIOS_CONTROLLER needs to be set in board.h -#endif -#endif -#define PORT DT_ALIAS_SW0_GPIOS_CONTROLLER - -/* change this to use another GPIO pin */ -#ifdef DT_ALIAS_SW0_GPIOS_PIN -#define PIN DT_ALIAS_SW0_GPIOS_PIN -#else -#error DT_ALIAS_SW0_GPIOS_PIN needs to be set in board.h -#endif - -/* change to use another GPIO pin interrupt config */ -#ifdef DT_ALIAS_SW0_GPIOS_FLAGS -#define EDGE (DT_ALIAS_SW0_GPIOS_FLAGS | GPIO_INT_EDGE) -#else -/* - * If DT_ALIAS_SW0_GPIOS_FLAGS not defined used default EDGE value. - * Change this to use a different interrupt trigger - */ -#define EDGE (GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW) -#endif - -/* change this to enable pull-up/pull-down */ -#ifndef DT_ALIAS_SW0_GPIOS_FLAGS -#ifdef DT_ALIAS_SW0_GPIOS_PIN_PUD -#define DT_ALIAS_SW0_GPIOS_FLAGS DT_ALIAS_SW0_GPIOS_PIN_PUD -#else -#define DT_ALIAS_SW0_GPIOS_FLAGS 0 -#endif -#endif -#define PULL_UP DT_ALIAS_SW0_GPIOS_FLAGS - -/* Sleep time */ -#define SLEEP_TIME 500 - +#define SLEEP_TIME_MS 1 -void button_pressed(struct device *gpiob, struct gpio_callback *cb, +void button_pressed(struct device *dev, struct gpio_callback *cb, u32_t pins) { printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32()); } -static struct gpio_callback gpio_cb; +static struct gpio_callback button_cb_data; void main(void) { - struct device *gpiob; + struct device *dev_button; + int ret; - printk("Press the user defined button on the board\n"); - gpiob = device_get_binding(PORT); - if (!gpiob) { - printk("error\n"); + dev_button = device_get_binding(DT_ALIAS_SW0_GPIOS_CONTROLLER); + if (dev_button == NULL) { + printk("Error: didn't find %s device\n", + DT_ALIAS_SW0_GPIOS_CONTROLLER); return; } - gpio_pin_configure(gpiob, PIN, - GPIO_DIR_IN | GPIO_INT | PULL_UP | EDGE); + ret = gpio_pin_configure(dev_button, DT_ALIAS_SW0_GPIOS_PIN, + DT_ALIAS_SW0_GPIOS_FLAGS | GPIO_INPUT); + if (ret != 0) { + printk("Error %d: failed to configure pin %d '%s'\n", + ret, DT_ALIAS_SW0_GPIOS_PIN, DT_ALIAS_SW0_LABEL); + return; + } - gpio_init_callback(&gpio_cb, button_pressed, BIT(PIN)); + ret = gpio_pin_interrupt_configure(dev_button, DT_ALIAS_SW0_GPIOS_PIN, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0) { + printk("Error %d: failed to configure interrupt on pin %d '%s'\n", + ret, DT_ALIAS_SW0_GPIOS_PIN, DT_ALIAS_SW0_LABEL); + return; + } - gpio_add_callback(gpiob, &gpio_cb); - gpio_pin_enable_callback(gpiob, PIN); + gpio_init_callback(&button_cb_data, button_pressed, + BIT(DT_ALIAS_SW0_GPIOS_PIN)); + gpio_add_callback(dev_button, &button_cb_data); + +#ifdef DT_ALIAS_LED0_GPIOS_CONTROLLER + struct device *dev_led; + + dev_led = device_get_binding(DT_ALIAS_LED0_GPIOS_CONTROLLER); + if (dev_led == NULL) { + printk("Error: didn't find %s device\n", + DT_ALIAS_LED0_GPIOS_CONTROLLER); + return; + } + + ret = gpio_pin_configure(dev_led, DT_ALIAS_LED0_GPIOS_PIN, + DT_ALIAS_LED0_GPIOS_FLAGS | GPIO_OUTPUT); + if (ret != 0) { + printk("Error %d: failed to configure pin %d '%s'\n", + ret, DT_ALIAS_LED0_GPIOS_PIN, DT_ALIAS_LED0_LABEL); + return; + } +#endif + printk("Press %s on the board\n", DT_ALIAS_SW0_LABEL); while (1) { - u32_t val = 0U; +#ifdef DT_ALIAS_LED0_GPIOS_CONTROLLER + bool val; - gpio_pin_read(gpiob, PIN, &val); - k_sleep(SLEEP_TIME); + val = gpio_pin_get(dev_button, DT_ALIAS_SW0_GPIOS_PIN); + gpio_pin_set(dev_led, DT_ALIAS_LED0_GPIOS_PIN, val); + k_sleep(SLEEP_TIME_MS); +#endif } } From db88003d6e76cdd823654f407681180e816f0042 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 17 Sep 2019 05:20:13 -0500 Subject: [PATCH 12/12] ci: bump number of minions to see if this builds Temp patch to see if this at least passes a full shippable build or not. Signed-off-by: Kumar Gala --- .shippable.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.shippable.yml b/.shippable.yml index 605fd41be89535..9aaddad6280444 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -6,13 +6,18 @@ env: global: - ZEPHYR_SDK_INSTALL_DIR=/opt/sdk/zephyr-sdk-0.10.3 - ZEPHYR_TOOLCHAIN_VARIANT=zephyr - - MATRIX_BUILDS="5" + - MATRIX_BUILDS="10" matrix: - MATRIX_BUILD="1" - MATRIX_BUILD="2" - MATRIX_BUILD="3" - MATRIX_BUILD="4" - MATRIX_BUILD="5" + - MATRIX_BUILD="6" + - MATRIX_BUILD="7" + - MATRIX_BUILD="8" + - MATRIX_BUILD="9" + - MATRIX_BUILD="10" build: cache: false