gpio: add support for configuring debounce

This commit is contained in:
Vanya A. Sergeev
2025-11-02 00:01:25 -05:00
parent 5c12d31384
commit bebd393f71
7 changed files with 86 additions and 12 deletions
+8 -2
View File
@@ -32,6 +32,7 @@ int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios
int gpio_get_direction(gpio_t *gpio, gpio_direction_t *direction);
int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge);
int gpio_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clock);
int gpio_get_debounce_us(gpio_t *gpio, uint32_t *debounce_us);
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias);
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive);
int gpio_get_inverted(gpio_t *gpio, bool *inverted);
@@ -40,6 +41,7 @@ int gpio_get_inverted(gpio_t *gpio, bool *inverted);
int gpio_set_direction(gpio_t *gpio, gpio_direction_t direction);
int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge);
int gpio_set_event_clock(gpio_t *gpio, gpio_event_clock_t event_clock);
int gpio_set_debounce_us(gpio_t *gpio, uint32_t *debounce_us);
int gpio_set_bias(gpio_t *gpio, gpio_bias_t bias);
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive);
int gpio_set_inverted(gpio_t *gpio, bool inverted);
@@ -127,6 +129,7 @@ typedef struct gpio_config {
gpio_direction_t direction;
gpio_edge_t edge;
gpio_event_clock_t event_clock;
uint32_t debounce_us;
gpio_bias_t bias;
gpio_drive_t drive;
bool inverted;
@@ -148,6 +151,7 @@ typedef struct gpio_config {
gpio_direction_t direction;
gpio_edge_t edge;
gpio_event_clock_t event_clock;
uint32_t debounce_us;
gpio_bias_t bias;
gpio_drive_t drive;
bool inverted;
@@ -259,11 +263,12 @@ Free a GPIO handle.
int gpio_get_direction(gpio_t *gpio, gpio_direction_t *direction);
int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge);
int gpio_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clock);
int gpio_get_debounce_us(gpio_t *gpio, uint32_t *debounce_us);
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias);
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive);
int gpio_get_inverted(gpio_t *gpio, bool *inverted);
```
Get the configured direction, interrupt edge, event clock, line bias, line drive, inverted (active low) properties, respectively, of the GPIO.
Get the configured direction, interrupt edge, event clock, debounce period properties, line bias, line drive, inverted (active low), respectively, of the GPIO.
Line bias and line drive properties are not supported by sysfs GPIOs.
@@ -277,11 +282,12 @@ Returns 0 on success, or a negative [GPIO error code](#return-value) on failure.
int gpio_set_direction(gpio_t *gpio, gpio_direction_t direction);
int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge);
int gpio_set_event_clock(gpio_t *gpio, gpio_event_clock_t event_clock);
int gpio_set_debounce_us(gpio_t *gpio, uint32_t debounce_us);
int gpio_set_bias(gpio_t *gpio, gpio_bias_t bias);
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive);
int gpio_set_inverted(gpio_t *gpio, bool inverted);
```
Set the direction, interrupt edge, event clock, line bias, line drive, inverted (active low) properties, respectively, of the GPIO.
Set the direction, interrupt edge, event clock, debounce period properties, line bias, line drive, inverted (active low), respectively, of the GPIO.
Line bias and line drive properties are not supported by sysfs GPIOs.
+8
View File
@@ -119,6 +119,10 @@ int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
return gpio->ops->get_bias(gpio, bias);
}
int gpio_get_debounce_us(gpio_t *gpio, uint32_t *debounce_us) {
return gpio->ops->get_debounce_us(gpio, debounce_us);
}
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive) {
return gpio->ops->get_drive(gpio, drive);
}
@@ -143,6 +147,10 @@ int gpio_set_bias(gpio_t *gpio, gpio_bias_t bias) {
return gpio->ops->set_bias(gpio, bias);
}
int gpio_set_debounce_us(gpio_t *gpio, uint32_t debounce_us) {
return gpio->ops->set_debounce_us(gpio, debounce_us);
}
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive) {
return gpio->ops->set_drive(gpio, drive);
}
+3
View File
@@ -65,6 +65,7 @@ typedef struct gpio_config {
gpio_direction_t direction;
gpio_edge_t edge;
gpio_event_clock_t event_clock;
uint32_t debounce_us;
gpio_bias_t bias;
gpio_drive_t drive;
bool inverted;
@@ -96,6 +97,7 @@ int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios
int gpio_get_direction(gpio_t *gpio, gpio_direction_t *direction);
int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge);
int gpio_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clock);
int gpio_get_debounce_us(gpio_t *gpio, uint32_t *debounce_us);
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias);
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive);
int gpio_get_inverted(gpio_t *gpio, bool *inverted);
@@ -104,6 +106,7 @@ int gpio_get_inverted(gpio_t *gpio, bool *inverted);
int gpio_set_direction(gpio_t *gpio, gpio_direction_t direction);
int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge);
int gpio_set_event_clock(gpio_t *gpio, gpio_event_clock_t event_clock);
int gpio_set_debounce_us(gpio_t *gpio, uint32_t debounce_us);
int gpio_set_bias(gpio_t *gpio, gpio_bias_t bias);
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive);
int gpio_set_inverted(gpio_t *gpio, bool inverted);
+15
View File
@@ -222,6 +222,11 @@ static int gpio_cdev_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clo
return 0;
}
static int gpio_cdev_get_debounce_us(gpio_t *gpio, uint32_t *debounce_us) {
*debounce_us = gpio->u.cdev.debounce_us;
return 0;
}
static int gpio_cdev_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
*bias = gpio->u.cdev.bias;
return 0;
@@ -267,6 +272,11 @@ static int gpio_cdev_set_event_clock(gpio_t *gpio, gpio_event_clock_t event_cloc
return 0;
}
static int gpio_cdev_set_debounce_us(gpio_t *gpio, uint32_t debounce_us) {
(void)debounce_us;
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "Kernel version does not support configuring debounce");
}
static int gpio_cdev_set_bias(gpio_t *gpio, gpio_bias_t bias) {
if (bias != GPIO_BIAS_DEFAULT && bias != GPIO_BIAS_PULL_UP && bias != GPIO_BIAS_PULL_DOWN && bias != GPIO_BIAS_DISABLE)
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO line bias (can be default, pull_up, pull_down, disable)");
@@ -460,12 +470,14 @@ const struct gpio_ops gpio_cdev_ops = {
.get_direction = gpio_cdev_get_direction,
.get_edge = gpio_cdev_get_edge,
.get_event_clock = gpio_cdev_get_event_clock,
.get_debounce_us = gpio_cdev_get_debounce_us,
.get_bias = gpio_cdev_get_bias,
.get_drive = gpio_cdev_get_drive,
.get_inverted = gpio_cdev_get_inverted,
.set_direction = gpio_cdev_set_direction,
.set_edge = gpio_cdev_set_edge,
.set_event_clock = gpio_cdev_set_event_clock,
.set_debounce_us = gpio_cdev_set_debounce_us,
.set_bias = gpio_cdev_set_bias,
.set_drive = gpio_cdev_set_drive,
.set_inverted = gpio_cdev_set_inverted,
@@ -503,6 +515,9 @@ int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const
if (config->event_clock != GPIO_EVENT_CLOCK_REALTIME)
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Kernel version does not support configuring event clock");
if (config->debounce_us != 0)
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "Kernel version does not support configuring debounce");
/* Open GPIO chip */
if ((fd = open(path, 0)) < 0)
return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO chip");
+37 -10
View File
@@ -28,7 +28,7 @@
#if PERIPHERY_GPIO_CDEV_SUPPORT == 2
static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge_t edge, gpio_event_clock_t event_clock, gpio_bias_t bias, gpio_drive_t drive, bool inverted) {
static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge_t edge, gpio_event_clock_t event_clock, uint32_t debounce_us, gpio_bias_t bias, gpio_drive_t drive, bool inverted) {
uint32_t flags = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
@@ -84,6 +84,12 @@ static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge
line_request.config.flags = flags;
line_request.num_lines = 1;
if (debounce_us) {
line_request.config.num_attrs = 1;
line_request.config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
line_request.config.attrs[0].attr.debounce_period_us = debounce_us;
}
if (ioctl(gpio->u.cdev.chip_fd, GPIO_V2_GET_LINE_IOCTL, &line_request) < 0)
return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening input line handle");
@@ -115,6 +121,7 @@ static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge
gpio->u.cdev.direction = (direction == GPIO_DIR_IN) ? GPIO_DIR_IN : GPIO_DIR_OUT;
gpio->u.cdev.edge = edge;
gpio->u.cdev.event_clock = event_clock;
gpio->u.cdev.debounce_us = debounce_us;
gpio->u.cdev.bias = bias;
gpio->u.cdev.drive = drive;
gpio->u.cdev.inverted = inverted;
@@ -220,6 +227,11 @@ static int gpio_cdev_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clo
return 0;
}
static int gpio_cdev_get_debounce_us(gpio_t *gpio, uint32_t *debounce_us) {
*debounce_us = gpio->u.cdev.debounce_us;
return 0;
}
static int gpio_cdev_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
*bias = gpio->u.cdev.bias;
return 0;
@@ -242,7 +254,7 @@ static int gpio_cdev_set_direction(gpio_t *gpio, gpio_direction_t direction) {
if (gpio->u.cdev.direction == direction)
return 0;
return _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE, gpio->u.cdev.event_clock, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
return _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE, gpio->u.cdev.event_clock, gpio->u.cdev.debounce_us, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_edge(gpio_t *gpio, gpio_edge_t edge) {
@@ -255,7 +267,7 @@ static int gpio_cdev_set_edge(gpio_t *gpio, gpio_edge_t edge) {
if (gpio->u.cdev.edge == edge)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, edge, gpio->u.cdev.event_clock, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, edge, gpio->u.cdev.event_clock, gpio->u.cdev.debounce_us, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_event_clock(gpio_t *gpio, gpio_event_clock_t event_clock) {
@@ -268,7 +280,17 @@ static int gpio_cdev_set_event_clock(gpio_t *gpio, gpio_event_clock_t event_cloc
if (gpio->u.cdev.event_clock == event_clock)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, event_clock, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, event_clock, gpio->u.cdev.debounce_us, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_debounce_us(gpio_t *gpio, uint32_t debounce_us) {
if (gpio->u.cdev.direction != GPIO_DIR_IN)
return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: cannot set debounce on output GPIO");
if (gpio->u.cdev.debounce_us == debounce_us)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.event_clock, debounce_us, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_bias(gpio_t *gpio, gpio_bias_t bias) {
@@ -278,7 +300,7 @@ static int gpio_cdev_set_bias(gpio_t *gpio, gpio_bias_t bias) {
if (gpio->u.cdev.bias == bias)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.event_clock, bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.event_clock, gpio->u.cdev.debounce_us, bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_drive(gpio_t *gpio, gpio_drive_t drive) {
@@ -291,14 +313,14 @@ static int gpio_cdev_set_drive(gpio_t *gpio, gpio_drive_t drive) {
if (gpio->u.cdev.drive == drive)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.event_clock, gpio->u.cdev.bias, drive, gpio->u.cdev.inverted);
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.event_clock, gpio->u.cdev.debounce_us, gpio->u.cdev.bias, drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_inverted(gpio_t *gpio, bool inverted) {
if (gpio->u.cdev.inverted == inverted)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.event_clock, gpio->u.cdev.bias, gpio->u.cdev.drive, inverted);
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.event_clock, gpio->u.cdev.debounce_us, gpio->u.cdev.bias, gpio->u.cdev.drive, inverted);
}
static unsigned int gpio_cdev_line(gpio_t *gpio) {
@@ -460,8 +482,8 @@ static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) {
else
chip_label_str = chip_label;
return snprintf(str, len, "GPIO %u (name=\"%s\", label=\"%s\", line_fd=%d, chip_fd=%d, direction=%s, edge=%s, event_clock=%s, bias=%s, drive=%s, inverted=%s, chip_name=\"%s\", chip_label=\"%s\", type=cdev)",
gpio->u.cdev.line, line_name_str, line_label_str, gpio->u.cdev.line_fd, gpio->u.cdev.chip_fd, direction_str, edge_str, event_clock_str, bias_str, drive_str, inverted_str, chip_name_str, chip_label_str);
return snprintf(str, len, "GPIO %u (name=\"%s\", label=\"%s\", line_fd=%d, chip_fd=%d, direction=%s, edge=%s, event_clock=%s, debounce_us=%u, bias=%s, drive=%s, inverted=%s, chip_name=\"%s\", chip_label=\"%s\", type=cdev)",
gpio->u.cdev.line, line_name_str, line_label_str, gpio->u.cdev.line_fd, gpio->u.cdev.chip_fd, direction_str, edge_str, event_clock_str, gpio->u.cdev.debounce_us, bias_str, drive_str, inverted_str, chip_name_str, chip_label_str);
}
const struct gpio_ops gpio_cdev_ops = {
@@ -473,12 +495,14 @@ const struct gpio_ops gpio_cdev_ops = {
.get_direction = gpio_cdev_get_direction,
.get_edge = gpio_cdev_get_edge,
.get_event_clock = gpio_cdev_get_event_clock,
.get_debounce_us = gpio_cdev_get_debounce_us,
.get_bias = gpio_cdev_get_bias,
.get_drive = gpio_cdev_get_drive,
.get_inverted = gpio_cdev_get_inverted,
.set_direction = gpio_cdev_set_direction,
.set_edge = gpio_cdev_set_edge,
.set_event_clock = gpio_cdev_set_event_clock,
.set_debounce_us = gpio_cdev_set_debounce_us,
.set_bias = gpio_cdev_set_bias,
.set_drive = gpio_cdev_set_drive,
.set_inverted = gpio_cdev_set_inverted,
@@ -507,6 +531,9 @@ int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const
if (config->direction != GPIO_DIR_IN && config->edge != GPIO_EDGE_NONE)
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO edge for output GPIO");
if (config->direction != GPIO_DIR_IN && config->debounce_us != 0)
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO debounce for output GPIO");
if (config->bias != GPIO_BIAS_DEFAULT && config->bias != GPIO_BIAS_PULL_UP && config->bias != GPIO_BIAS_PULL_DOWN && config->bias != GPIO_BIAS_DISABLE)
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO line bias (can be default, pull_up, pull_down, disable)");
@@ -529,7 +556,7 @@ int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const
gpio->u.cdev.label[sizeof(gpio->u.cdev.label) - 1] = '\0';
/* Open GPIO line */
ret = _gpio_cdev_reopen(gpio, config->direction, config->edge, config->event_clock, config->bias, config->drive, config->inverted);
ret = _gpio_cdev_reopen(gpio, config->direction, config->edge, config->event_clock, config->debounce_us, config->bias, config->drive, config->inverted);
if (ret < 0) {
close(gpio->u.cdev.chip_fd);
gpio->u.cdev.chip_fd = -1;
+3
View File
@@ -24,12 +24,14 @@ struct gpio_ops {
int (*get_direction)(gpio_t *gpio, gpio_direction_t *direction);
int (*get_edge)(gpio_t *gpio, gpio_edge_t *edge);
int (*get_event_clock)(gpio_t *gpio, gpio_event_clock_t *event_clock);
int (*get_debounce_us)(gpio_t *gpio, uint32_t *debounce_us);
int (*get_bias)(gpio_t *gpio, gpio_bias_t *bias);
int (*get_drive)(gpio_t *gpio, gpio_drive_t *drive);
int (*get_inverted)(gpio_t *gpio, bool *inverted);
int (*set_direction)(gpio_t *gpio, gpio_direction_t direction);
int (*set_edge)(gpio_t *gpio, gpio_edge_t edge);
int (*set_event_clock)(gpio_t *gpio, gpio_event_clock_t event_clock);
int (*set_debounce_us)(gpio_t *gpio, uint32_t debounce_us);
int (*set_bias)(gpio_t *gpio, gpio_bias_t bias);
int (*set_drive)(gpio_t *gpio, gpio_drive_t drive);
int (*set_inverted)(gpio_t *gpio, bool inverted);
@@ -54,6 +56,7 @@ struct gpio_handle {
gpio_direction_t direction;
gpio_edge_t edge;
gpio_event_clock_t event_clock;
uint32_t debounce_us;
gpio_bias_t bias;
gpio_drive_t drive;
bool inverted;
+12
View File
@@ -275,6 +275,16 @@ static int gpio_sysfs_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_cl
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support event clock configuration");
}
static int gpio_sysfs_set_debounce_us(gpio_t *gpio, uint32_t debounce_us) {
(void)debounce_us;
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support debounce attribute");
}
static int gpio_sysfs_get_debounce_us(gpio_t *gpio, uint32_t *debounce_us) {
(void)debounce_us;
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support debounce attribute");
}
static int gpio_sysfs_set_bias(gpio_t *gpio, gpio_bias_t bias) {
(void)bias;
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support line bias attribute");
@@ -492,12 +502,14 @@ const struct gpio_ops gpio_sysfs_ops = {
.get_direction = gpio_sysfs_get_direction,
.get_edge = gpio_sysfs_get_edge,
.get_event_clock = gpio_sysfs_get_event_clock,
.get_debounce_us = gpio_sysfs_get_debounce_us,
.get_bias = gpio_sysfs_get_bias,
.get_drive = gpio_sysfs_get_drive,
.get_inverted = gpio_sysfs_get_inverted,
.set_direction = gpio_sysfs_set_direction,
.set_edge = gpio_sysfs_set_edge,
.set_event_clock = gpio_sysfs_set_event_clock,
.set_debounce_us = gpio_sysfs_set_debounce_us,
.set_bias = gpio_sysfs_set_bias,
.set_drive = gpio_sysfs_set_drive,
.set_inverted = gpio_sysfs_set_inverted,