summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.h
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-30 09:22:00 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-30 09:22:00 -0700
commit034dd340b08be1f2f0477ad16131d609f9dbd53c (patch)
tree2536f4b2d7893ccd916b5abdf3c454ad6edc03c2 /drivers/gpio/gpiolib.h
downloadlinux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.tar.gz
linux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.zip
Merge tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-tracegrafted
Pull tracing fixes from Steven Rostedt: - Fix error output of boot instance creation failure Currently if a boot instance creation fails, instead of printing out the name of the instance that failed, it prints "(null)". That is because it prints "cur_str" that had already been processed by strsep(). Print the saved name instead. While at it, print the error code of the failure. - Fix use-after-free for same named historgrams Histograms can be named so that they can be used in multiple events. But if the named histogram has a variable attached, the second event that uses the named histogram which duplicates it and needs to free the original after duplication leaves the old variable in place and still visible. If another histogram uses than variable, it will use the stale one which will try to reference the freed duplicate histogram and crash the kernel. Free the duplicate variables along with the duplicated histogram data. - Check return value of kthread_run() in event self test The events self tests uses a kthread for testing but does not check if it succeeded in creating a kthread. If the kthread creation were to fail, the code will still try to call kthread_stop() on the error returned. - Fix race between reading trace_pipe and updating subbuffer size If a user is reading the trace_pipe file at the same time they update the ring buffer sub-buffer size, can cause the trace_pipe read to read stale data. Add trace_access_lock() around updating the ring buffer sub-buffer size. - Fix eventfs_inode on failure path in creation of the events directory In the creation of the "events" directory, if after allocating the eventfs_inode a failure is detected, it calls cleanup_ei() which calls free_ei(). The free_ei() will test if eventfs_inode being freed has no children. It is a bug if it does. But on the failure case of the creation of the "events" directory, the children lists have not yet been initialized and the free will trigger a warning because list_empty() on an uninitialized list returns false. Move the initialization into init_ei() where it makes more sense and makes sure that a created eventfs_inode has its lists initialized upon creation. - Check return value of kthread_run() in ftrace direct sample code The sample code that shows how to use the ftrace direct calls does not test the return of kthread_run() to see if it succeeds. Return a failure if the kthread_run() doesn't succeed. - Clear user events state on fork in case of alloc failure On fork, the child gets a pointer to the parent's user events state. It makes a copy of it then updates the child's pointer to it. But if the allocation fails, the duplication function leaves the child with a pointer to its parent's descriptor. When the child cleans up its data, it will free the parent's descriptor while the parent is still using it. In the duplication function, set the child's user_event_mm to NULL before testing if the allocation succeeded, and when it exits it will not free the parent's descriptor. - Fix retry exhaustion in simple ring buffer reader swap simple_ring_buffer_swap_reader_page() starts with retry set to 8 and post-decrements it only after a failed link replacement. On the final attempt, a successful replacement leaves retry at zero, while a failed replacement leaves it at -1. But the check for success expects the retry value to be non-zero and exits with an error on zero. This is the opposite result. Fix it. - Fail nicely when the remote swap_reader_page() returns an error Currently, if the swap_reader_page() of a remote buffer fails, it triggers a WARN_ON_ONCE() and continues normally. Instead, have it exit with an error and a pr_warn() print instead of a full WARNING. * tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: ring-buffer: Stop remote reader update when page swap fails tracing: Fix retry exhaustion in simple ring buffer reader swap tracing/user_events: Clear copied tracing state before fork duplication samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-multi-modify samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-modify eventfs: Initialize ei->children and ei->list in init_ei() tracing: Fix use-after-free in trace_pipe read on sub-buffer order change tracing: Fix crash passing ERR_PTR to kthread_stop() tracing: Fix use-after-free with same-name named triggers tracing: Fix logged instance name on creation failure
Diffstat (limited to 'drivers/gpio/gpiolib.h')
-rw-r--r--drivers/gpio/gpiolib.h310
1 files changed, 310 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
new file mode 100644
index 000000000..650a70274
--- /dev/null
+++ b/drivers/gpio/gpiolib.h
@@ -0,0 +1,310 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Internal GPIO functions.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ */
+
+#ifndef GPIOLIB_H
+#define GPIOLIB_H
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h> /* for enum gpiod_flags */
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/srcu.h>
+#include <linux/workqueue.h>
+
+#define GPIOCHIP_NAME "gpiochip"
+
+struct fwnode_handle;
+
+/**
+ * struct gpio_device - internal state container for GPIO devices
+ * @dev: the GPIO device struct
+ * @chrdev: character device for the GPIO device
+ * @id: numerical ID number for the GPIO chip
+ * @owner: helps prevent removal of modules exporting active GPIOs
+ * @chip: pointer to the corresponding gpiochip, holding static
+ * data for this device
+ * @descs: array of ngpio descriptors.
+ * @valid_mask: If not %NULL, holds bitmask of GPIOs which are valid to be
+ * used from the chip.
+ * @desc_srcu: ensures consistent state of GPIO descriptors exposed to users
+ * @ngpio: the number of GPIO lines on this GPIO device, equal to the size
+ * of the @descs array.
+ * @can_sleep: indicate whether the GPIO chip driver's callbacks can sleep
+ * implying that they cannot be used from atomic context
+ * @base: GPIO base in the DEPRECATED global Linux GPIO numberspace, assigned
+ * at device creation time.
+ * @label: a descriptive name for the GPIO device, such as the part number
+ * or name of the IP component in a System on Chip.
+ * @data: per-instance data assigned by the driver
+ * @list: links gpio_device:s together for traversal
+ * @line_state_notifier: used to notify subscribers about lines being
+ * requested, released or reconfigured
+ * @line_state_lock: RW-spinlock protecting the line state notifier
+ * @line_state_wq: used to emit line state events from a separate thread in
+ * process context
+ * @device_notifier: used to notify character device wait queues about the GPIO
+ * device being unregistered
+ * @srcu: protects the pointer to the underlying GPIO chip
+ * @pin_ranges: range of pins served by the GPIO driver
+ *
+ * This state container holds most of the runtime variable data
+ * for a GPIO device and can hold references and live on after the
+ * GPIO chip has been removed, if it is still being used from
+ * userspace.
+ */
+struct gpio_device {
+ struct device dev;
+ struct cdev chrdev;
+ int id;
+ struct module *owner;
+ struct gpio_chip __rcu *chip;
+ struct gpio_desc *descs;
+ unsigned long *valid_mask;
+ struct srcu_struct desc_srcu;
+ unsigned int base;
+ u16 ngpio;
+ bool can_sleep;
+ const char *label;
+ void *data;
+ struct list_head list;
+ struct raw_notifier_head line_state_notifier;
+ rwlock_t line_state_lock;
+ struct workqueue_struct *line_state_wq;
+ struct blocking_notifier_head device_notifier;
+ struct srcu_struct srcu;
+
+#ifdef CONFIG_PINCTRL
+ /*
+ * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
+ * describe the actual pin range which they serve in an SoC. This
+ * information would be used by pinctrl subsystem to configure
+ * corresponding pins for gpio usage.
+ */
+ struct list_head pin_ranges;
+#endif
+};
+
+static inline struct gpio_device *to_gpio_device(struct device *dev)
+{
+ return container_of(dev, struct gpio_device, dev);
+}
+
+/* GPIO suffixes used for ACPI and device tree lookup */
+extern const char *const gpio_suffixes[];
+
+#define for_each_gpio_property_name(propname, con_id) \
+ for (const char * const *__suffixes = gpio_suffixes; \
+ *__suffixes && ({ \
+ const char *__gs = *__suffixes; \
+ \
+ if (con_id) \
+ snprintf(propname, sizeof(propname), "%s-%s", con_id, __gs); \
+ else \
+ strscpy(propname, __gs); \
+ 1; \
+ }); \
+ __suffixes++)
+
+/**
+ * struct gpio_array - Opaque descriptor for a structure of GPIO array attributes
+ *
+ * @desc: Array of pointers to the GPIO descriptors
+ * @size: Number of elements in desc
+ * @gdev: Parent GPIO device
+ * @get_mask: Get mask used in fastpath
+ * @set_mask: Set mask used in fastpath
+ * @invert_mask: Invert mask used in fastpath
+ *
+ * This structure is attached to struct gpiod_descs obtained from
+ * gpiod_get_array() and can be passed back to get/set array functions in order
+ * to activate fast processing path if applicable.
+ */
+struct gpio_array {
+ struct gpio_desc **desc;
+ unsigned int size;
+ struct gpio_device *gdev;
+ unsigned long *get_mask;
+ unsigned long *set_mask;
+ unsigned long invert_mask[];
+};
+
+#define for_each_gpio_desc(gc, desc) \
+ for (unsigned int __i = 0; \
+ __i < gc->ngpio && (desc = gpiochip_get_desc(gc, __i)); \
+ __i++) \
+
+#define for_each_gpio_desc_with_flag(gc, desc, flag) \
+ for_each_gpio_desc(gc, desc) \
+ if (!test_bit(flag, &desc->flags)) {} else
+
+int gpiod_get_array_value_complex(bool raw, bool can_sleep,
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap);
+int gpiod_set_array_value_complex(bool raw, bool can_sleep,
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap);
+
+int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
+
+void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);
+int gpiod_direction_output_nonotify(struct gpio_desc *desc, int value);
+int gpiod_direction_input_nonotify(struct gpio_desc *desc);
+
+struct gpio_desc_label {
+ struct rcu_head rh;
+ char str[];
+};
+
+/**
+ * struct gpio_desc - Opaque descriptor for a GPIO
+ *
+ * @gdev: Pointer to the parent GPIO device
+ * @flags: Binary descriptor flags
+ * @label: Name of the consumer
+ * @name: Line name
+ * @hog: Pointer to the device node that hogs this line (if any)
+ * @debounce_period_us: Debounce period in microseconds
+ *
+ * These are obtained using gpiod_get() and are preferable to the old
+ * integer-based handles.
+ *
+ * Contrary to integers, a pointer to a &struct gpio_desc is guaranteed to be
+ * valid until the GPIO is released.
+ */
+struct gpio_desc {
+ struct gpio_device *gdev;
+ unsigned long flags;
+/* flag symbols are bit numbers */
+#define GPIOD_FLAG_REQUESTED 0 /* GPIO is in use */
+#define GPIOD_FLAG_IS_OUT 1 /* GPIO is in output mode */
+#define GPIOD_FLAG_EXPORT 2 /* GPIO is exported to user-space */
+#define GPIOD_FLAG_SYSFS 3 /* GPIO is exported via /sys/class/gpio */
+#define GPIOD_FLAG_ACTIVE_LOW 6 /* GPIO is active-low */
+#define GPIOD_FLAG_OPEN_DRAIN 7 /* GPIO is open drain type */
+#define GPIOD_FLAG_OPEN_SOURCE 8 /* GPIO is open source type */
+#define GPIOD_FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
+#define GPIOD_FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */
+#define GPIOD_FLAG_IS_HOGGED 11 /* GPIO is hogged */
+#define GPIOD_FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */
+#define GPIOD_FLAG_PULL_UP 13 /* GPIO has pull up enabled */
+#define GPIOD_FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */
+#define GPIOD_FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */
+#define GPIOD_FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */
+#define GPIOD_FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */
+#define GPIOD_FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */
+#define GPIOD_FLAG_EVENT_CLOCK_HTE 19 /* GPIO CDEV reports hardware timestamps in events */
+#define GPIOD_FLAG_SHARED 20 /* GPIO is shared by multiple consumers */
+#define GPIOD_FLAG_SHARED_PROXY 21 /* GPIO is a virtual proxy to a physically shared pin. */
+
+ /* Connection label */
+ struct gpio_desc_label __rcu *label;
+ /* Name of the GPIO */
+ const char *name;
+#ifdef CONFIG_OF_DYNAMIC
+ struct device_node *hog;
+#endif
+#ifdef CONFIG_GPIO_CDEV
+ /* debounce period in microseconds */
+ unsigned int debounce_period_us;
+#endif
+};
+
+#define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
+
+struct gpio_chip_guard {
+ struct gpio_device *gdev;
+ struct gpio_chip *gc;
+ int idx;
+};
+
+DEFINE_CLASS(gpio_chip_guard,
+ struct gpio_chip_guard,
+ srcu_read_unlock(&_T.gdev->srcu, _T.idx),
+ ({
+ struct gpio_chip_guard _guard;
+
+ _guard.gdev = desc->gdev;
+ _guard.idx = srcu_read_lock(&_guard.gdev->srcu);
+ _guard.gc = srcu_dereference(_guard.gdev->chip,
+ &_guard.gdev->srcu);
+
+ _guard;
+ }),
+ const struct gpio_desc *desc)
+
+int gpiod_request(struct gpio_desc *desc, const char *label);
+int gpiod_request_commit(struct gpio_desc *desc, const char *label);
+void gpiod_free(struct gpio_desc *desc);
+void gpiod_free_commit(struct gpio_desc *desc);
+
+static inline int gpiod_request_user(struct gpio_desc *desc, const char *label)
+{
+ int ret;
+
+ ret = gpiod_request(desc, label);
+ if (ret == -EPROBE_DEFER)
+ ret = -ENODEV;
+
+ return ret;
+}
+
+struct gpio_desc *gpiod_find_and_request(struct device *consumer,
+ struct fwnode_handle *fwnode,
+ const char *con_id,
+ unsigned int idx,
+ enum gpiod_flags flags,
+ const char *label,
+ bool platform_lookup_allowed);
+
+int gpio_do_set_config(struct gpio_desc *desc, unsigned long config);
+int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
+ unsigned long lflags, enum gpiod_flags dflags);
+int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
+int gpiod_hog(struct gpio_desc *desc, const char *name,
+ unsigned long lflags, enum gpiod_flags dflags);
+int gpiochip_add_hog(struct gpio_chip *gc, struct fwnode_handle *fwnode);
+int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev);
+struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum);
+const char *gpiod_get_label(struct gpio_desc *desc);
+
+/* With descriptor prefix */
+
+#define __gpiod_pr(level, desc, fmt, ...) \
+do { \
+ scoped_guard(srcu, &desc->gdev->desc_srcu) { \
+ pr_##level("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
+ gpiod_get_label(desc) ?: "?", ##__VA_ARGS__); \
+ } \
+} while (0)
+
+#define gpiod_err(desc, fmt, ...) __gpiod_pr(err, desc, fmt, ##__VA_ARGS__)
+#define gpiod_warn(desc, fmt, ...) __gpiod_pr(warn, desc, fmt, ##__VA_ARGS__)
+#define gpiod_dbg(desc, fmt, ...) __gpiod_pr(debug, desc, fmt, ##__VA_ARGS__)
+
+/* With chip prefix */
+
+#define __gpiochip_pr(level, gc, fmt, ...) \
+do { \
+ dev_##level(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__); \
+} while (0)
+
+#define gpiochip_err(gc, fmt, ...) __gpiochip_pr(err, gc, fmt, ##__VA_ARGS__)
+#define gpiochip_warn(gc, fmt, ...) __gpiochip_pr(warn, gc, fmt, ##__VA_ARGS__)
+#define gpiochip_info(gc, fmt, ...) __gpiochip_pr(info, gc, fmt, ##__VA_ARGS__)
+#define gpiochip_dbg(gc, fmt, ...) __gpiochip_pr(dbg, gc, fmt, ##__VA_ARGS__)
+
+#endif /* GPIOLIB_H */