mirror of
https://github.com/vsergeev/c-periphery.git
synced 2026-03-24 08:53:32 +08:00
gpio: add support for configuring event clock
This commit is contained in:
15
docs/gpio.md
15
docs/gpio.md
@@ -31,6 +31,7 @@ int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios
|
||||
/* Getters */
|
||||
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_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);
|
||||
@@ -38,6 +39,7 @@ int gpio_get_inverted(gpio_t *gpio, bool *inverted);
|
||||
/* Setters */
|
||||
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_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);
|
||||
@@ -71,6 +73,11 @@ const char *gpio_errmsg(gpio_t *gpio);
|
||||
* `GPIO_EDGE_FALLING`: Falling edge (1 -> 0 transition)
|
||||
* `GPIO_EDGE_BOTH`: Both edges (X -> !X transition)
|
||||
|
||||
* `gpio_event_clock_t`
|
||||
* `GPIO_EVENT_CLOCK_REALTIME`: Realtime
|
||||
* `GPIO_EVENT_CLOCK_MONOTONIC`: Monotonic
|
||||
* `GPIO_EVENT_CLOCK_HTE`: Hardware timestamping engine
|
||||
|
||||
* `gpio_bias_t`
|
||||
* `GPIO_BIAS_DEFAULT`: Default line bias
|
||||
* `GPIO_BIAS_PULL_UP`: Pull-up
|
||||
@@ -119,6 +126,7 @@ Returns 0 on success, or a negative [GPIO error code](#return-value) on failure.
|
||||
typedef struct gpio_config {
|
||||
gpio_direction_t direction;
|
||||
gpio_edge_t edge;
|
||||
gpio_event_clock_t event_clock;
|
||||
gpio_bias_t bias;
|
||||
gpio_drive_t drive;
|
||||
bool inverted;
|
||||
@@ -139,6 +147,7 @@ Returns 0 on success, or a negative [GPIO error code](#return-value) on failure.
|
||||
typedef struct gpio_config {
|
||||
gpio_direction_t direction;
|
||||
gpio_edge_t edge;
|
||||
gpio_event_clock_t event_clock;
|
||||
gpio_bias_t bias;
|
||||
gpio_drive_t drive;
|
||||
bool inverted;
|
||||
@@ -249,11 +258,12 @@ Free a GPIO handle.
|
||||
```c
|
||||
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_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, line bias, line drive, inverted (active low) properties, respectively, of the GPIO.
|
||||
Get the configured direction, interrupt edge, event clock, line bias, line drive, inverted (active low) properties, respectively, of the GPIO.
|
||||
|
||||
Line bias and line drive properties are not supported by sysfs GPIOs.
|
||||
|
||||
@@ -266,11 +276,12 @@ Returns 0 on success, or a negative [GPIO error code](#return-value) on failure.
|
||||
```c
|
||||
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_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, line bias, line drive, inverted (active low) properties, respectively, of the GPIO.
|
||||
Set the direction, interrupt edge, event clock, line bias, line drive, inverted (active low) properties, respectively, of the GPIO.
|
||||
|
||||
Line bias and line drive properties are not supported by sysfs GPIOs.
|
||||
|
||||
|
||||
@@ -111,6 +111,10 @@ int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge) {
|
||||
return gpio->ops->get_edge(gpio, edge);
|
||||
}
|
||||
|
||||
int gpio_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clock) {
|
||||
return gpio->ops->get_event_clock(gpio, event_clock);
|
||||
}
|
||||
|
||||
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
|
||||
return gpio->ops->get_bias(gpio, bias);
|
||||
}
|
||||
@@ -131,6 +135,10 @@ int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge) {
|
||||
return gpio->ops->set_edge(gpio, edge);
|
||||
}
|
||||
|
||||
int gpio_set_event_clock(gpio_t *gpio, gpio_event_clock_t event_clock) {
|
||||
return gpio->ops->set_event_clock(gpio, event_clock);
|
||||
}
|
||||
|
||||
int gpio_set_bias(gpio_t *gpio, gpio_bias_t bias) {
|
||||
return gpio->ops->set_bias(gpio, bias);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,12 @@ typedef enum gpio_edge {
|
||||
GPIO_EDGE_BOTH /* Both edges X -> !X */
|
||||
} gpio_edge_t;
|
||||
|
||||
typedef enum gpio_event_clock {
|
||||
GPIO_EVENT_CLOCK_REALTIME, /* Realtime */
|
||||
GPIO_EVENT_CLOCK_MONOTONIC, /* Monotonic */
|
||||
GPIO_EVENT_CLOCK_HTE /* Hardware Timestamping Engine */
|
||||
} gpio_event_clock_t;
|
||||
|
||||
typedef enum gpio_bias {
|
||||
GPIO_BIAS_DEFAULT, /* Default line bias */
|
||||
GPIO_BIAS_PULL_UP, /* Pull-up */
|
||||
@@ -58,6 +64,7 @@ typedef enum gpio_drive {
|
||||
typedef struct gpio_config {
|
||||
gpio_direction_t direction;
|
||||
gpio_edge_t edge;
|
||||
gpio_event_clock_t event_clock;
|
||||
gpio_bias_t bias;
|
||||
gpio_drive_t drive;
|
||||
bool inverted;
|
||||
@@ -88,6 +95,7 @@ int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios
|
||||
/* Getters */
|
||||
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_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);
|
||||
@@ -95,6 +103,7 @@ int gpio_get_inverted(gpio_t *gpio, bool *inverted);
|
||||
/* Setters */
|
||||
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_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);
|
||||
|
||||
@@ -27,9 +27,12 @@
|
||||
|
||||
#if PERIPHERY_GPIO_CDEV_SUPPORT == 1
|
||||
|
||||
static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge_t edge, 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, gpio_bias_t bias, gpio_drive_t drive, bool inverted) {
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (event_clock != GPIO_EVENT_CLOCK_REALTIME)
|
||||
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "Kernel version does not support configuring GPIO event clock");
|
||||
|
||||
#ifdef GPIOHANDLE_REQUEST_BIAS_PULL_UP
|
||||
if (bias == GPIO_BIAS_PULL_UP)
|
||||
flags |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;
|
||||
@@ -116,6 +119,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.bias = bias;
|
||||
gpio->u.cdev.drive = drive;
|
||||
gpio->u.cdev.inverted = inverted;
|
||||
@@ -216,6 +220,11 @@ static int gpio_cdev_get_edge(gpio_t *gpio, gpio_edge_t *edge) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_cdev_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clock) {
|
||||
*event_clock = gpio->u.cdev.event_clock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_cdev_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
|
||||
*bias = gpio->u.cdev.bias;
|
||||
return 0;
|
||||
@@ -238,7 +247,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.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.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
|
||||
}
|
||||
|
||||
static int gpio_cdev_set_edge(gpio_t *gpio, gpio_edge_t edge) {
|
||||
@@ -251,7 +260,20 @@ 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.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.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) {
|
||||
if (event_clock != GPIO_EVENT_CLOCK_REALTIME && event_clock != GPIO_EVENT_CLOCK_MONOTONIC && event_clock != GPIO_EVENT_CLOCK_HTE)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO event clock (can be realtime, monotonic, hte)");
|
||||
|
||||
if (gpio->u.cdev.direction != GPIO_DIR_IN)
|
||||
return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: cannot set event clock on output GPIO");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int gpio_cdev_set_bias(gpio_t *gpio, gpio_bias_t bias) {
|
||||
@@ -261,7 +283,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, 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, bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
|
||||
}
|
||||
|
||||
static int gpio_cdev_set_drive(gpio_t *gpio, gpio_drive_t drive) {
|
||||
@@ -274,14 +296,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.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.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.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.bias, gpio->u.cdev.drive, inverted);
|
||||
}
|
||||
|
||||
static unsigned int gpio_cdev_line(gpio_t *gpio) {
|
||||
@@ -365,6 +387,8 @@ static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) {
|
||||
const char *direction_str;
|
||||
gpio_edge_t edge;
|
||||
const char *edge_str;
|
||||
gpio_event_clock_t event_clock;
|
||||
const char *event_clock_str;
|
||||
gpio_bias_t bias;
|
||||
const char *bias_str;
|
||||
gpio_drive_t drive;
|
||||
@@ -394,6 +418,13 @@ static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) {
|
||||
(edge == GPIO_EDGE_FALLING) ? "falling" :
|
||||
(edge == GPIO_EDGE_BOTH) ? "both" : "unknown";
|
||||
|
||||
if (gpio_cdev_get_event_clock(gpio, &event_clock) < 0)
|
||||
event_clock_str = "<error>";
|
||||
else
|
||||
event_clock_str = (event_clock == GPIO_EVENT_CLOCK_REALTIME) ? "realtime" :
|
||||
(event_clock == GPIO_EVENT_CLOCK_MONOTONIC) ? "monotonic" :
|
||||
(event_clock == GPIO_EVENT_CLOCK_HTE) ? "hte" : "unknown";
|
||||
|
||||
if (gpio_cdev_get_bias(gpio, &bias) < 0)
|
||||
bias_str = "<error>";
|
||||
else
|
||||
@@ -434,8 +465,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, 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, 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, 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);
|
||||
}
|
||||
|
||||
const struct gpio_ops gpio_cdev_ops = {
|
||||
@@ -446,11 +477,13 @@ const struct gpio_ops gpio_cdev_ops = {
|
||||
.close = gpio_cdev_close,
|
||||
.get_direction = gpio_cdev_get_direction,
|
||||
.get_edge = gpio_cdev_get_edge,
|
||||
.get_event_clock = gpio_cdev_get_event_clock,
|
||||
.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_bias = gpio_cdev_set_bias,
|
||||
.set_drive = gpio_cdev_set_drive,
|
||||
.set_inverted = gpio_cdev_set_inverted,
|
||||
@@ -473,6 +506,9 @@ int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const
|
||||
if (config->edge != GPIO_EDGE_NONE && config->edge != GPIO_EDGE_RISING && config->edge != GPIO_EDGE_FALLING && config->edge != GPIO_EDGE_BOTH)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO interrupt edge (can be none, rising, falling, both)");
|
||||
|
||||
if (config->event_clock != GPIO_EVENT_CLOCK_REALTIME && config->event_clock != GPIO_EVENT_CLOCK_MONOTONIC && config->event_clock != GPIO_EVENT_CLOCK_HTE)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO event clock (can be realtime, monotonic, hte)");
|
||||
|
||||
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");
|
||||
|
||||
@@ -498,7 +534,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->bias, config->drive, config->inverted);
|
||||
ret = _gpio_cdev_reopen(gpio, config->direction, config->edge, config->event_clock, config->bias, config->drive, config->inverted);
|
||||
if (ret < 0) {
|
||||
close(gpio->u.cdev.chip_fd);
|
||||
gpio->u.cdev.chip_fd = -1;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#if PERIPHERY_GPIO_CDEV_SUPPORT == 2
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/version.h>
|
||||
#endif
|
||||
|
||||
/*********************************************************************************/
|
||||
@@ -27,9 +28,14 @@
|
||||
|
||||
#if PERIPHERY_GPIO_CDEV_SUPPORT == 2
|
||||
|
||||
static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge_t edge, 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, gpio_bias_t bias, gpio_drive_t drive, bool inverted) {
|
||||
uint32_t flags = 0;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
|
||||
if (event_clock == GPIO_EVENT_CLOCK_HTE)
|
||||
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "Kernel version does not support GPIO event clock HTE");
|
||||
#endif
|
||||
|
||||
if (bias == GPIO_BIAS_PULL_UP)
|
||||
flags |= GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
|
||||
else if (bias == GPIO_BIAS_PULL_DOWN)
|
||||
@@ -63,7 +69,14 @@ static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge
|
||||
flags |= (edge == GPIO_EDGE_RISING) ? GPIO_V2_LINE_FLAG_EDGE_RISING :
|
||||
(edge == GPIO_EDGE_FALLING) ? GPIO_V2_LINE_FLAG_EDGE_FALLING :
|
||||
(edge == GPIO_EDGE_BOTH) ? (GPIO_V2_LINE_FLAG_EDGE_RISING | GPIO_V2_LINE_FLAG_EDGE_FALLING) : 0;
|
||||
flags |= (edge != GPIO_EDGE_NONE) ? GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME : 0;
|
||||
flags |= (edge != GPIO_EDGE_NONE) ?
|
||||
(event_clock == GPIO_EVENT_CLOCK_REALTIME) ? GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME :
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)
|
||||
(event_clock == GPIO_EVENT_CLOCK_HTE) ? GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE : 0
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
: 0;
|
||||
|
||||
line_request.offsets[0] = gpio->u.cdev.line;
|
||||
strncpy(line_request.consumer, gpio->u.cdev.label, sizeof(line_request.consumer) - 1);
|
||||
@@ -101,6 +114,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.bias = bias;
|
||||
gpio->u.cdev.drive = drive;
|
||||
gpio->u.cdev.inverted = inverted;
|
||||
@@ -201,6 +215,11 @@ static int gpio_cdev_get_edge(gpio_t *gpio, gpio_edge_t *edge) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_cdev_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clock) {
|
||||
*event_clock = gpio->u.cdev.event_clock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_cdev_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
|
||||
*bias = gpio->u.cdev.bias;
|
||||
return 0;
|
||||
@@ -223,7 +242,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.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.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
|
||||
}
|
||||
|
||||
static int gpio_cdev_set_edge(gpio_t *gpio, gpio_edge_t edge) {
|
||||
@@ -236,7 +255,20 @@ 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.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.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) {
|
||||
if (event_clock != GPIO_EVENT_CLOCK_REALTIME && event_clock != GPIO_EVENT_CLOCK_MONOTONIC && event_clock != GPIO_EVENT_CLOCK_HTE)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO event clock (can be realtime, monotonic, hte)");
|
||||
|
||||
if (gpio->u.cdev.direction != GPIO_DIR_IN)
|
||||
return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: cannot set event clock on output GPIO");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int gpio_cdev_set_bias(gpio_t *gpio, gpio_bias_t bias) {
|
||||
@@ -246,7 +278,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, 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, bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
|
||||
}
|
||||
|
||||
static int gpio_cdev_set_drive(gpio_t *gpio, gpio_drive_t drive) {
|
||||
@@ -259,14 +291,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.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.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.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.bias, gpio->u.cdev.drive, inverted);
|
||||
}
|
||||
|
||||
static unsigned int gpio_cdev_line(gpio_t *gpio) {
|
||||
@@ -350,6 +382,8 @@ static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) {
|
||||
const char *direction_str;
|
||||
gpio_edge_t edge;
|
||||
const char *edge_str;
|
||||
gpio_event_clock_t event_clock;
|
||||
const char *event_clock_str;
|
||||
gpio_bias_t bias;
|
||||
const char *bias_str;
|
||||
gpio_drive_t drive;
|
||||
@@ -379,6 +413,13 @@ static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) {
|
||||
(edge == GPIO_EDGE_FALLING) ? "falling" :
|
||||
(edge == GPIO_EDGE_BOTH) ? "both" : "unknown";
|
||||
|
||||
if (gpio_cdev_get_event_clock(gpio, &event_clock) < 0)
|
||||
event_clock_str = "<error>";
|
||||
else
|
||||
event_clock_str = (event_clock == GPIO_EVENT_CLOCK_REALTIME) ? "realtime" :
|
||||
(event_clock == GPIO_EVENT_CLOCK_MONOTONIC) ? "monotonic" :
|
||||
(event_clock == GPIO_EVENT_CLOCK_HTE) ? "hte" : "unknown";
|
||||
|
||||
if (gpio_cdev_get_bias(gpio, &bias) < 0)
|
||||
bias_str = "<error>";
|
||||
else
|
||||
@@ -419,8 +460,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, 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, 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, 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);
|
||||
}
|
||||
|
||||
const struct gpio_ops gpio_cdev_ops = {
|
||||
@@ -431,11 +472,13 @@ const struct gpio_ops gpio_cdev_ops = {
|
||||
.close = gpio_cdev_close,
|
||||
.get_direction = gpio_cdev_get_direction,
|
||||
.get_edge = gpio_cdev_get_edge,
|
||||
.get_event_clock = gpio_cdev_get_event_clock,
|
||||
.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_bias = gpio_cdev_set_bias,
|
||||
.set_drive = gpio_cdev_set_drive,
|
||||
.set_inverted = gpio_cdev_set_inverted,
|
||||
@@ -458,6 +501,9 @@ int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const
|
||||
if (config->edge != GPIO_EDGE_NONE && config->edge != GPIO_EDGE_RISING && config->edge != GPIO_EDGE_FALLING && config->edge != GPIO_EDGE_BOTH)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO interrupt edge (can be none, rising, falling, both)");
|
||||
|
||||
if (config->event_clock != GPIO_EVENT_CLOCK_REALTIME && config->event_clock != GPIO_EVENT_CLOCK_MONOTONIC && config->event_clock != GPIO_EVENT_CLOCK_HTE)
|
||||
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO event clock (can be realtime, monotonic, hte)");
|
||||
|
||||
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");
|
||||
|
||||
@@ -483,7 +529,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->bias, config->drive, config->inverted);
|
||||
ret = _gpio_cdev_reopen(gpio, config->direction, config->edge, config->event_clock, config->bias, config->drive, config->inverted);
|
||||
if (ret < 0) {
|
||||
close(gpio->u.cdev.chip_fd);
|
||||
gpio->u.cdev.chip_fd = -1;
|
||||
|
||||
@@ -23,11 +23,13 @@ struct gpio_ops {
|
||||
int (*close)(gpio_t *gpio);
|
||||
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_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_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);
|
||||
@@ -51,6 +53,7 @@ struct gpio_handle {
|
||||
int chip_fd;
|
||||
gpio_direction_t direction;
|
||||
gpio_edge_t edge;
|
||||
gpio_event_clock_t event_clock;
|
||||
gpio_bias_t bias;
|
||||
gpio_drive_t drive;
|
||||
bool inverted;
|
||||
|
||||
@@ -265,6 +265,16 @@ static int gpio_sysfs_get_edge(gpio_t *gpio, gpio_edge_t *edge) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_sysfs_set_event_clock(gpio_t *gpio, gpio_event_clock_t event_clock) {
|
||||
(void)event_clock;
|
||||
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support event clock configuration");
|
||||
}
|
||||
|
||||
static int gpio_sysfs_get_event_clock(gpio_t *gpio, gpio_event_clock_t *event_clock) {
|
||||
(void)event_clock;
|
||||
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support event clock configuration");
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -481,11 +491,13 @@ const struct gpio_ops gpio_sysfs_ops = {
|
||||
.close = gpio_sysfs_close,
|
||||
.get_direction = gpio_sysfs_get_direction,
|
||||
.get_edge = gpio_sysfs_get_edge,
|
||||
.get_event_clock = gpio_sysfs_get_event_clock,
|
||||
.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_bias = gpio_sysfs_set_bias,
|
||||
.set_drive = gpio_sysfs_set_drive,
|
||||
.set_inverted = gpio_sysfs_set_inverted,
|
||||
|
||||
Reference in New Issue
Block a user