summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpiolib-cdev.c
diff options
context:
space:
mode:
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>2024-10-18 11:10:16 +0200
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>2024-10-22 08:59:09 +0200
commit07c61d4da43fa3b34c152b28010d20be115a96db (patch)
tree2427ca5376d5ccc484ebb72836de9019e1af6565 /drivers/gpio/gpiolib-cdev.c
parentfcc8b637c542d1a0c19e5797ad72f9258e10464c (diff)
gpiolib: notify user-space about in-kernel line state changes
We currently only notify user-space about line config changes that are made from user-space. Any kernel config changes are not signalled. Let's improve the situation by emitting the events closer to the source. To that end let's call the relevant notifier chain from the functions setting direction, gpiod_set_config(), gpiod_set_consumer_name() and gpiod_toggle_active_low(). This covers all the options that we can inform the user-space about. We ignore events which don't have corresponding flags exported to user-space on purpose - otherwise the user would see a config-changed event but the associated line-info would remain unchanged. gpiod_direction_output/input() can be called from any context. Fortunately, we now emit line state events using an atomic notifier chain, so it's no longer an issue. Let's also add non-notifying wrappers around the direction setters in order to not emit superfluous reconfigure events when requesting the lines as the initial config should be part of the request notification. Use gpio_do_set_config() instead of gpiod_set_debounce() for configuring debouncing via hardware from the character device code to avoid multiple reconfigure events. Reviewed-by: Kent Gibson <warthog618@gmail.com> Link: https://lore.kernel.org/r/20241018-gpio-notify-in-kernel-events-v5-8-c79135e58a1c@linaro.org Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib-cdev.c')
-rw-r--r--drivers/gpio/gpiolib-cdev.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index cb4fb55e2696..13d83675bf4f 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -187,11 +187,11 @@ static long linehandle_set_config(struct linehandle_state *lh,
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!gcnf.default_values[i];
- ret = gpiod_direction_output(desc, val);
+ ret = gpiod_direction_output_nonotify(desc, val);
if (ret)
return ret;
} else {
- ret = gpiod_direction_input(desc);
+ ret = gpiod_direction_input_nonotify(desc);
if (ret)
return ret;
}
@@ -362,11 +362,11 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!handlereq.default_values[i];
- ret = gpiod_direction_output(desc, val);
+ ret = gpiod_direction_output_nonotify(desc, val);
if (ret)
goto out_free_lh;
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
- ret = gpiod_direction_input(desc);
+ ret = gpiod_direction_input_nonotify(desc);
if (ret)
goto out_free_lh;
}
@@ -922,8 +922,13 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us)
int ret, level, irq;
char *label;
- /* try hardware */
- ret = gpiod_set_debounce(line->desc, debounce_period_us);
+ /*
+ * Try hardware. Skip gpiod_set_config() to avoid emitting two
+ * CHANGED_CONFIG line state events.
+ */
+ ret = gpio_do_set_config(line->desc,
+ pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE,
+ debounce_period_us));
if (!ret) {
WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us);
return ret;
@@ -1433,11 +1438,11 @@ static long linereq_set_config(struct linereq *lr, void __user *ip)
int val = gpio_v2_line_config_output_value(&lc, i);
edge_detector_stop(line);
- ret = gpiod_direction_output(desc, val);
+ ret = gpiod_direction_output_nonotify(desc, val);
if (ret)
return ret;
} else {
- ret = gpiod_direction_input(desc);
+ ret = gpiod_direction_input_nonotify(desc);
if (ret)
return ret;
@@ -1700,11 +1705,11 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
if (flags & GPIO_V2_LINE_FLAG_OUTPUT) {
int val = gpio_v2_line_config_output_value(lc, i);
- ret = gpiod_direction_output(desc, val);
+ ret = gpiod_direction_output_nonotify(desc, val);
if (ret)
goto out_free_linereq;
} else if (flags & GPIO_V2_LINE_FLAG_INPUT) {
- ret = gpiod_direction_input(desc);
+ ret = gpiod_direction_input_nonotify(desc);
if (ret)
goto out_free_linereq;