diff options
Diffstat (limited to 'include/linux/gpio')
| -rw-r--r-- | include/linux/gpio/aspeed.h | 19 | ||||
| -rw-r--r-- | include/linux/gpio/consumer.h | 700 | ||||
| -rw-r--r-- | include/linux/gpio/driver.h | 906 | ||||
| -rw-r--r-- | include/linux/gpio/forwarder.h | 41 | ||||
| -rw-r--r-- | include/linux/gpio/generic.h | 190 | ||||
| -rw-r--r-- | include/linux/gpio/gpio-nomadik.h | 292 | ||||
| -rw-r--r-- | include/linux/gpio/gpio-reg.h | 18 | ||||
| -rw-r--r-- | include/linux/gpio/machine.h | 127 | ||||
| -rw-r--r-- | include/linux/gpio/property.h | 14 | ||||
| -rw-r--r-- | include/linux/gpio/regmap.h | 117 |
10 files changed, 2424 insertions, 0 deletions
diff --git a/include/linux/gpio/aspeed.h b/include/linux/gpio/aspeed.h new file mode 100644 index 000000000000..9a547e66c8c4 --- /dev/null +++ b/include/linux/gpio/aspeed.h @@ -0,0 +1,19 @@ +#ifndef __GPIO_ASPEED_H +#define __GPIO_ASPEED_H + +#include <linux/types.h> + +struct gpio_desc; + +struct aspeed_gpio_copro_ops { + int (*request_access)(void *data); + int (*release_access)(void *data); +}; + +int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, + u16 *vreg_offset, u16 *dreg_offset, u8 *bit); +int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc); +int aspeed_gpio_copro_set_ops(const struct aspeed_gpio_copro_ops *ops, void *data); + + +#endif /* __GPIO_ASPEED_H */ diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h new file mode 100644 index 000000000000..cafeb7a40ad1 --- /dev/null +++ b/include/linux/gpio/consumer.h @@ -0,0 +1,700 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_GPIO_CONSUMER_H +#define __LINUX_GPIO_CONSUMER_H + +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/types.h> + +struct acpi_device; +struct device; +struct fwnode_handle; + +struct gpio_array; +struct gpio_desc; + +/** + * struct gpio_descs - Struct containing an array of descriptors that can be + * obtained using gpiod_get_array() + * + * @info: Pointer to the opaque gpio_array structure + * @ndescs: Number of held descriptors + * @desc: Array of pointers to GPIO descriptors + */ +struct gpio_descs { + struct gpio_array *info; + unsigned int ndescs; + struct gpio_desc *desc[]; +}; + +#define GPIOD_FLAGS_BIT_DIR_SET BIT(0) +#define GPIOD_FLAGS_BIT_DIR_OUT BIT(1) +#define GPIOD_FLAGS_BIT_DIR_VAL BIT(2) +#define GPIOD_FLAGS_BIT_OPEN_DRAIN BIT(3) +/* GPIOD_FLAGS_BIT_NONEXCLUSIVE is DEPRECATED, don't use in new code. */ +#define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4) + +/** + * enum gpiod_flags - Optional flags that can be passed to one of gpiod_* to + * configure direction and output value. These values + * cannot be OR'd. + * + * @GPIOD_ASIS: Don't change anything + * @GPIOD_IN: Set lines to input mode + * @GPIOD_OUT_LOW: Set lines to output and drive them low + * @GPIOD_OUT_HIGH: Set lines to output and drive them high + * @GPIOD_OUT_LOW_OPEN_DRAIN: Set lines to open-drain output and drive them low + * @GPIOD_OUT_HIGH_OPEN_DRAIN: Set lines to open-drain output and drive them high + */ +enum gpiod_flags { + GPIOD_ASIS = 0, + GPIOD_IN = GPIOD_FLAGS_BIT_DIR_SET, + GPIOD_OUT_LOW = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT, + GPIOD_OUT_HIGH = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT | + GPIOD_FLAGS_BIT_DIR_VAL, + GPIOD_OUT_LOW_OPEN_DRAIN = GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_OPEN_DRAIN, + GPIOD_OUT_HIGH_OPEN_DRAIN = GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_OPEN_DRAIN, +}; + +#ifdef CONFIG_GPIOLIB + +/* Return the number of GPIOs associated with a device / function */ +int gpiod_count(struct device *dev, const char *con_id); + +/* Acquire and dispose GPIOs */ +struct gpio_desc *__must_check gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags); +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, + const char *con_id, + unsigned int index, + enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +void gpiod_put(struct gpio_desc *desc); +void gpiod_put_array(struct gpio_descs *descs); + +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags); +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_desc *__must_check +devm_gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags); +struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags); +void devm_gpiod_put(struct device *dev, struct gpio_desc *desc); +void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc); +void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs); + +int gpiod_get_direction(struct gpio_desc *desc); +int gpiod_direction_input(struct gpio_desc *desc); +int gpiod_direction_output(struct gpio_desc *desc, int value); +int gpiod_direction_output_raw(struct gpio_desc *desc, int value); + +/* Value get/set from non-sleeping context */ +int gpiod_get_value(const struct gpio_desc *desc); +int gpiod_get_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); +int gpiod_set_value(struct gpio_desc *desc, int value); +int gpiod_set_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); +int gpiod_get_raw_value(const struct gpio_desc *desc); +int gpiod_get_raw_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); +int gpiod_set_raw_value(struct gpio_desc *desc, int value); +int gpiod_set_raw_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); + +/* Value get/set from sleeping context */ +int gpiod_get_value_cansleep(const struct gpio_desc *desc); +int gpiod_get_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); +int gpiod_set_value_cansleep(struct gpio_desc *desc, int value); +int gpiod_set_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); +int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc); +int gpiod_get_raw_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); +int gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value); +int gpiod_set_raw_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); + +int gpiod_set_config(struct gpio_desc *desc, unsigned long config); +int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce); +void gpiod_toggle_active_low(struct gpio_desc *desc); + +int gpiod_is_active_low(const struct gpio_desc *desc); +int gpiod_cansleep(const struct gpio_desc *desc); + +int gpiod_to_irq(const struct gpio_desc *desc); +int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name); + +bool gpiod_is_shared(const struct gpio_desc *desc); + +/* Convert between the old gpio_ and new gpiod_ interfaces */ +struct gpio_desc *gpio_to_desc(unsigned gpio); +int desc_to_gpio(const struct gpio_desc *desc); + +int gpiod_hwgpio(const struct gpio_desc *desc); + +struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label); +struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, + struct fwnode_handle *child, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label); + +bool gpiod_is_equal(const struct gpio_desc *desc, + const struct gpio_desc *other); + +#else /* CONFIG_GPIOLIB */ + +#include <linux/bug.h> +#include <linux/kernel.h> + +static inline int gpiod_count(struct device *dev, const char *con_id) +{ + return 0; +} + +static inline struct gpio_desc *__must_check gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} +static inline struct gpio_desc *__must_check +gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_desc *__must_check +gpiod_get_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return NULL; +} + +static inline struct gpio_desc *__must_check +gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags) +{ + return NULL; +} + +static inline struct gpio_descs *__must_check +gpiod_get_array(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return NULL; +} + +static inline void gpiod_put(struct gpio_desc *desc) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(desc); +} + +static inline void devm_gpiod_unhinge(struct device *dev, + struct gpio_desc *desc) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(desc); +} + +static inline void gpiod_put_array(struct gpio_descs *descs) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(descs); +} + +static inline struct gpio_desc *__must_check +devm_gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} +static inline +struct gpio_desc *__must_check +devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_desc *__must_check +devm_gpiod_get_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return NULL; +} + +static inline struct gpio_desc *__must_check +devm_gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags) +{ + return NULL; +} + +static inline struct gpio_descs *__must_check +devm_gpiod_get_array(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return NULL; +} + +static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(desc); +} + +static inline void devm_gpiod_put_array(struct device *dev, + struct gpio_descs *descs) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(descs); +} + + +static inline int gpiod_get_direction(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -ENOSYS; +} +static inline int gpiod_direction_input(struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -ENOSYS; +} +static inline int gpiod_direction_output(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -ENOSYS; +} +static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -ENOSYS; +} +static inline int gpiod_get_value(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_get_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) +{ + /* GPIO can never have been requested */ + WARN_ON(desc_array); + return 0; +} +static inline int gpiod_set_value(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_set_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) +{ + /* GPIO can never have been requested */ + WARN_ON(desc_array); + return 0; +} +static inline int gpiod_get_raw_value(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_get_raw_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) +{ + /* GPIO can never have been requested */ + WARN_ON(desc_array); + return 0; +} +static inline int gpiod_set_raw_value(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_set_raw_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) +{ + /* GPIO can never have been requested */ + WARN_ON(desc_array); + return 0; +} + +static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_get_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) +{ + /* GPIO can never have been requested */ + WARN_ON(desc_array); + return 0; +} +static inline int gpiod_set_value_cansleep(struct gpio_desc *desc, int value) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_set_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) +{ + /* GPIO can never have been requested */ + WARN_ON(desc_array); + return 0; +} +static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) +{ + /* GPIO can never have been requested */ + WARN_ON(desc_array); + return 0; +} +static inline int gpiod_set_raw_value_cansleep(struct gpio_desc *desc, + int value) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) +{ + /* GPIO can never have been requested */ + WARN_ON(desc_array); + return 0; +} + +static inline int gpiod_set_config(struct gpio_desc *desc, unsigned long config) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -ENOSYS; +} + +static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -ENOSYS; +} + +static inline void gpiod_toggle_active_low(struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); +} + +static inline int gpiod_is_active_low(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} +static inline int gpiod_cansleep(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return 0; +} + +static inline int gpiod_to_irq(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -EINVAL; +} + +static inline int gpiod_set_consumer_name(struct gpio_desc *desc, + const char *name) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -EINVAL; +} + +static inline bool gpiod_is_shared(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return false; +} + +static inline struct gpio_desc *gpio_to_desc(unsigned gpio) +{ + return NULL; +} + +static inline int desc_to_gpio(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return -EINVAL; +} + +static inline +struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label) +{ + return ERR_PTR(-ENOSYS); +} + +static inline +struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, int index, + enum gpiod_flags flags, + const char *label) +{ + return ERR_PTR(-ENOSYS); +} + +static inline bool +gpiod_is_equal(const struct gpio_desc *desc, const struct gpio_desc *other) +{ + WARN_ON(desc || other); + return false; +} + +#endif /* CONFIG_GPIOLIB */ + +#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_HTE) +int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags); +int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags); +#else + +#include <linux/bug.h> + +static inline int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, + unsigned long flags) +{ + if (!IS_ENABLED(CONFIG_GPIOLIB)) + WARN_ON(desc); + + return -ENOSYS; +} +static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, + unsigned long flags) +{ + if (!IS_ENABLED(CONFIG_GPIOLIB)) + WARN_ON(desc); + + return -ENOSYS; +} +#endif /* CONFIG_GPIOLIB && CONFIG_HTE */ + +static inline +struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev, + struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags, + const char *label) +{ + return devm_fwnode_gpiod_get_index(dev, fwnode, con_id, 0, + flags, label); +} + +struct acpi_gpio_params { + unsigned int crs_entry_index; + unsigned short line_index; + bool active_low; +}; + +struct acpi_gpio_mapping { + const char *name; + const struct acpi_gpio_params *data; + unsigned int size; + +/* Ignore IoRestriction field */ +#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0) +/* + * When ACPI GPIO mapping table is in use the index parameter inside it + * refers to the GPIO resource in _CRS method. That index has no + * distinction of actual type of the resource. When consumer wants to + * get GpioIo type explicitly, this quirk may be used. + */ +#define ACPI_GPIO_QUIRK_ONLY_GPIOIO BIT(1) +/* Use given pin as an absolute GPIO number in the system */ +#define ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER BIT(2) + + unsigned int quirks; +}; + +#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_ACPI) + +int acpi_dev_add_driver_gpios(struct acpi_device *adev, + const struct acpi_gpio_mapping *gpios); +void acpi_dev_remove_driver_gpios(struct acpi_device *adev); + +int devm_acpi_dev_add_driver_gpios(struct device *dev, + const struct acpi_gpio_mapping *gpios); + +#else /* CONFIG_GPIOLIB && CONFIG_ACPI */ + +static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev, + const struct acpi_gpio_mapping *gpios) +{ + return -ENXIO; +} +static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {} + +static inline int devm_acpi_dev_add_driver_gpios(struct device *dev, + const struct acpi_gpio_mapping *gpios) +{ + return -ENXIO; +} + +#endif /* CONFIG_GPIOLIB && CONFIG_ACPI */ + + +#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) + +int gpiod_export(struct gpio_desc *desc, bool direction_may_change); +int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc); +void gpiod_unexport(struct gpio_desc *desc); + +#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ + +static inline int gpiod_export(struct gpio_desc *desc, + bool direction_may_change) +{ + return -ENOSYS; +} + +static inline int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) +{ + return -ENOSYS; +} + +static inline void gpiod_unexport(struct gpio_desc *desc) +{ +} + +#endif /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ + +static inline int gpiod_multi_set_value_cansleep(struct gpio_descs *descs, + unsigned long *value_bitmap) +{ + if (IS_ERR_OR_NULL(descs)) + return PTR_ERR_OR_ZERO(descs); + + return gpiod_set_array_value_cansleep(descs->ndescs, descs->desc, + descs->info, value_bitmap); +} + +#endif diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h new file mode 100644 index 000000000000..fabe2baf7b50 --- /dev/null +++ b/include/linux/gpio/driver.h @@ -0,0 +1,906 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_GPIO_DRIVER_H +#define __LINUX_GPIO_DRIVER_H + +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/err.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> +#include <linux/irqhandler.h> +#include <linux/lockdep.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/property.h> +#include <linux/spinlock_types.h> +#include <linux/types.h> +#include <linux/util_macros.h> + +#ifdef CONFIG_GENERIC_MSI_IRQ +#include <asm/msi.h> +#endif + +struct device; +struct irq_chip; +struct irq_data; +struct module; +struct of_phandle_args; +struct pinctrl_dev; +struct seq_file; + +struct gpio_chip; +struct gpio_desc; +struct gpio_device; + +enum gpio_lookup_flags; +enum gpiod_flags; + +union gpio_irq_fwspec { + struct irq_fwspec fwspec; +#ifdef CONFIG_GENERIC_MSI_IRQ + msi_alloc_info_t msiinfo; +#endif +}; + +#define GPIO_LINE_DIRECTION_IN 1 +#define GPIO_LINE_DIRECTION_OUT 0 + +/** + * struct gpio_irq_chip - GPIO interrupt controller + */ +struct gpio_irq_chip { + /** + * @chip: + * + * GPIO IRQ chip implementation, provided by GPIO driver. + */ + struct irq_chip *chip; + + /** + * @domain: + * + * Interrupt translation domain; responsible for mapping between GPIO + * hwirq number and Linux IRQ number. + */ + struct irq_domain *domain; + +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + /** + * @fwnode: + * + * Firmware node corresponding to this gpiochip/irqchip, necessary + * for hierarchical irqdomain support. + */ + struct fwnode_handle *fwnode; + + /** + * @parent_domain: + * + * If non-NULL, will be set as the parent of this GPIO interrupt + * controller's IRQ domain to establish a hierarchical interrupt + * domain. The presence of this will activate the hierarchical + * interrupt support. + */ + struct irq_domain *parent_domain; + + /** + * @child_to_parent_hwirq: + * + * This callback translates a child hardware IRQ offset to a parent + * hardware IRQ offset on a hierarchical interrupt chip. The child + * hardware IRQs correspond to the GPIO index 0..ngpio-1 (see the + * ngpio field of struct gpio_chip) and the corresponding parent + * hardware IRQ and type (such as IRQ_TYPE_*) shall be returned by + * the driver. The driver can calculate this from an offset or using + * a lookup table or whatever method is best for this chip. Return + * 0 on successful translation in the driver. + * + * If some ranges of hardware IRQs do not have a corresponding parent + * HWIRQ, return -EINVAL, but also make sure to fill in @valid_mask and + * @need_valid_mask to make these GPIO lines unavailable for + * translation. + */ + int (*child_to_parent_hwirq)(struct gpio_chip *gc, + unsigned int child_hwirq, + unsigned int child_type, + unsigned int *parent_hwirq, + unsigned int *parent_type); + + /** + * @populate_parent_alloc_arg : + * + * This optional callback allocates and populates the specific struct + * for the parent's IRQ domain. If this is not specified, then + * &gpiochip_populate_parent_fwspec_twocell will be used. A four-cell + * variant named &gpiochip_populate_parent_fwspec_fourcell is also + * available. + */ + int (*populate_parent_alloc_arg)(struct gpio_chip *gc, + union gpio_irq_fwspec *fwspec, + unsigned int parent_hwirq, + unsigned int parent_type); + + /** + * @child_offset_to_irq: + * + * This optional callback is used to translate the child's GPIO line + * offset on the GPIO chip to an IRQ number for the GPIO to_irq() + * callback. If this is not specified, then a default callback will be + * provided that returns the line offset. + */ + unsigned int (*child_offset_to_irq)(struct gpio_chip *gc, + unsigned int pin); + + /** + * @child_irq_domain_ops: + * + * The IRQ domain operations that will be used for this GPIO IRQ + * chip. If no operations are provided, then default callbacks will + * be populated to setup the IRQ hierarchy. Some drivers need to + * supply their own translate function. + */ + struct irq_domain_ops child_irq_domain_ops; +#endif + + /** + * @handler: + * + * The IRQ handler to use (often a predefined IRQ core function) for + * GPIO IRQs, provided by GPIO driver. + */ + irq_flow_handler_t handler; + + /** + * @default_type: + * + * Default IRQ triggering type applied during GPIO driver + * initialization, provided by GPIO driver. + */ + unsigned int default_type; + + /** + * @lock_key: + * + * Per GPIO IRQ chip lockdep class for IRQ lock. + */ + struct lock_class_key *lock_key; + + /** + * @request_key: + * + * Per GPIO IRQ chip lockdep class for IRQ request. + */ + struct lock_class_key *request_key; + + /** + * @parent_handler: + * + * The interrupt handler for the GPIO chip's parent interrupts, may be + * NULL if the parent interrupts are nested rather than cascaded. + */ + irq_flow_handler_t parent_handler; + + union { + /** + * @parent_handler_data: + * + * If @per_parent_data is false, @parent_handler_data is a + * single pointer used as the data associated with every + * parent interrupt. + */ + void *parent_handler_data; + + /** + * @parent_handler_data_array: + * + * If @per_parent_data is true, @parent_handler_data_array is + * an array of @num_parents pointers, and is used to associate + * different data for each parent. This cannot be NULL if + * @per_parent_data is true. + */ + void **parent_handler_data_array; + }; + + /** + * @num_parents: + * + * The number of interrupt parents of a GPIO chip. + */ + unsigned int num_parents; + + /** + * @parents: + * + * A list of interrupt parents of a GPIO chip. This is owned by the + * driver, so the core will only reference this list, not modify it. + */ + unsigned int *parents; + + /** + * @map: + * + * A list of interrupt parents for each line of a GPIO chip. + */ + unsigned int *map; + + /** + * @threaded: + * + * True if set the interrupt handling uses nested threads. + */ + bool threaded; + + /** + * @per_parent_data: + * + * True if parent_handler_data_array describes a @num_parents + * sized array to be used as parent data. + */ + bool per_parent_data; + + /** + * @initialized: + * + * Flag to track GPIO chip irq member's initialization. + * This flag will make sure GPIO chip irq members are not used + * before they are initialized. + */ + bool initialized; + + /** + * @domain_is_allocated_externally: + * + * True it the irq_domain was allocated outside of gpiolib, in which + * case gpiolib won't free the irq_domain itself. + */ + bool domain_is_allocated_externally; + + /** + * @init_hw: optional routine to initialize hardware before + * an IRQ chip will be added. This is quite useful when + * a particular driver wants to clear IRQ related registers + * in order to avoid undesired events. + */ + int (*init_hw)(struct gpio_chip *gc); + + /** + * @init_valid_mask: optional routine to initialize @valid_mask, to be + * used if not all GPIO lines are valid interrupts. Sometimes some + * lines just cannot fire interrupts, and this routine, when defined, + * is passed a bitmap in "valid_mask" and it will have ngpios + * bits from 0..(ngpios-1) set to "1" as in valid. The callback can + * then directly set some bits to "0" if they cannot be used for + * interrupts. + */ + void (*init_valid_mask)(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios); + + /** + * @valid_mask: + * + * If not %NULL, holds bitmask of GPIOs which are valid to be included + * in IRQ domain of the chip. + */ + unsigned long *valid_mask; + + /** + * @first: + * + * Required for static IRQ allocation. If set, + * irq_domain_create_simple() will allocate and map all IRQs + * during initialization. + */ + unsigned int first; + + /** + * @irq_enable: + * + * Store old irq_chip irq_enable callback + */ + void (*irq_enable)(struct irq_data *data); + + /** + * @irq_disable: + * + * Store old irq_chip irq_disable callback + */ + void (*irq_disable)(struct irq_data *data); + /** + * @irq_unmask: + * + * Store old irq_chip irq_unmask callback + */ + void (*irq_unmask)(struct irq_data *data); + + /** + * @irq_mask: + * + * Store old irq_chip irq_mask callback + */ + void (*irq_mask)(struct irq_data *data); +}; + +/** + * struct gpio_chip - abstract a GPIO controller + * @label: a functional name for the GPIO device, such as a part + * number or the name of the SoC IP-block implementing it. + * @gpiodev: the internal state holder, opaque struct + * @parent: optional parent device providing the GPIOs + * @fwnode: optional fwnode providing this controller's properties + * @owner: helps prevent removal of modules exporting active GPIOs + * @request: optional hook for chip-specific activation, such as + * enabling module power and clock; may sleep; must return 0 on success + * or negative error number on failure + * @free: optional hook for chip-specific deactivation, such as + * disabling module power and clock; may sleep + * @get_direction: returns direction for signal "offset", 0=out, 1=in, + * (same as GPIO_LINE_DIRECTION_OUT / GPIO_LINE_DIRECTION_IN), + * or negative error. It is recommended to always implement this + * function, even on input-only or output-only gpio chips. + * @direction_input: configures signal "offset" as input, returns 0 on success + * or a negative error number. This can be omitted on input-only or + * output-only gpio chips. + * @direction_output: configures signal "offset" as output, returns 0 on + * success or a negative error number. This can be omitted on input-only + * or output-only gpio chips. + * @get: returns value for signal "offset", 0=low, 1=high, or negative error + * @get_multiple: reads values for multiple signals defined by "mask" and + * stores them in "bits", returns 0 on success or negative error + * @set: assigns output value for signal "offset", returns 0 on success or + * negative error value + * @set_multiple: assigns output values for multiple signals defined by + * "mask", returns 0 on success or negative error value + * @set_config: optional hook for all kinds of settings. Uses the same + * packed config format as generic pinconf. Must return 0 on success and + * a negative error number on failure. + * @to_irq: optional hook supporting non-static gpiod_to_irq() mappings; + * implementation may not sleep + * @dbg_show: optional routine to show contents in debugfs; default code + * will be used when this is omitted, but custom code can show extra + * state (such as pullup/pulldown configuration). + * @init_valid_mask: optional routine to initialize @valid_mask, to be used if + * not all GPIOs are valid. + * @add_pin_ranges: optional routine to initialize pin ranges, to be used when + * requires special mapping of the pins that provides GPIO functionality. + * It is called after adding GPIO chip and before adding IRQ chip. + * @en_hw_timestamp: Dependent on GPIO chip, an optional routine to + * enable hardware timestamp. + * @dis_hw_timestamp: Dependent on GPIO chip, an optional routine to + * disable hardware timestamp. + * @base: identifies the first GPIO number handled by this chip; + * or, if negative during registration, requests dynamic ID allocation. + * DEPRECATION: providing anything non-negative and nailing the base + * offset of GPIO chips is deprecated. Please pass -1 as base to + * let gpiolib select the chip base in all possible cases. We want to + * get rid of the static GPIO number space in the long run. + * @ngpio: the number of GPIOs handled by this controller; the last GPIO + * handled is (base + ngpio - 1). + * @offset: when multiple gpio chips belong to the same device this + * can be used as offset within the device so friendly names can + * be properly assigned. + * @names: if set, must be an array of strings to use as alternative + * names for the GPIOs in this chip. Any entry in the array + * may be NULL if there is no alias for the GPIO, however the + * array must be @ngpio entries long. + * @can_sleep: flag must be set iff get()/set() methods sleep, as they + * must while accessing GPIO expander chips over I2C or SPI. This + * implies that if the chip supports IRQs, these IRQs need to be threaded + * as the chip access may sleep when e.g. reading out the IRQ status + * registers. + * + * A gpio_chip can help platforms abstract various sources of GPIOs so + * they can all be accessed through a common programming interface. + * Example sources would be SOC controllers, FPGAs, multifunction + * chips, dedicated GPIO expanders, and so on. + * + * Each chip controls a number of signals, identified in method calls + * by "offset" values in the range 0..(@ngpio - 1). When those signals + * are referenced through calls like gpio_get_value(gpio), the offset + * is calculated by subtracting @base from the gpio number. + */ +struct gpio_chip { + const char *label; + struct gpio_device *gpiodev; + struct device *parent; + struct fwnode_handle *fwnode; + struct module *owner; + + int (*request)(struct gpio_chip *gc, + unsigned int offset); + void (*free)(struct gpio_chip *gc, + unsigned int offset); + int (*get_direction)(struct gpio_chip *gc, + unsigned int offset); + int (*direction_input)(struct gpio_chip *gc, + unsigned int offset); + int (*direction_output)(struct gpio_chip *gc, + unsigned int offset, int value); + int (*get)(struct gpio_chip *gc, + unsigned int offset); + int (*get_multiple)(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits); + int (*set)(struct gpio_chip *gc, + unsigned int offset, int value); + int (*set_multiple)(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits); + int (*set_config)(struct gpio_chip *gc, + unsigned int offset, + unsigned long config); + int (*to_irq)(struct gpio_chip *gc, + unsigned int offset); + + void (*dbg_show)(struct seq_file *s, + struct gpio_chip *gc); + + int (*init_valid_mask)(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios); + + int (*add_pin_ranges)(struct gpio_chip *gc); + + int (*en_hw_timestamp)(struct gpio_chip *gc, + u32 offset, + unsigned long flags); + int (*dis_hw_timestamp)(struct gpio_chip *gc, + u32 offset, + unsigned long flags); + int base; + u16 ngpio; + u16 offset; + const char *const *names; + bool can_sleep; + +#ifdef CONFIG_GPIOLIB_IRQCHIP + /* + * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib + * to handle IRQs for most practical cases. + */ + + /** + * @irq: + * + * Integrates interrupt chip functionality with the GPIO chip. Can be + * used to handle IRQs for most practical cases. + */ + struct gpio_irq_chip irq; +#endif /* CONFIG_GPIOLIB_IRQCHIP */ + +#if defined(CONFIG_OF_GPIO) + /* + * If CONFIG_OF_GPIO is enabled, then all GPIO controllers described in + * the device tree automatically may have an OF translation + */ + + /** + * @of_gpio_n_cells: + * + * Number of cells used to form the GPIO specifier. The standard is 2 + * cells: + * + * gpios = <&gpio offset flags>; + * + * some complex GPIO controllers instantiate more than one chip per + * device tree node and have 3 cells: + * + * gpios = <&gpio instance offset flags>; + * + * Legacy GPIO controllers may even have 1 cell: + * + * gpios = <&gpio offset>; + */ + unsigned int of_gpio_n_cells; + + /** + * @of_node_instance_match: + * + * Determine if a chip is the right instance. Must be implemented by + * any driver using more than one gpio_chip per device tree node. + * Returns true if gc is the instance indicated by i (which is the + * first cell in the phandles for GPIO lines and gpio-ranges). + */ + bool (*of_node_instance_match)(struct gpio_chip *gc, unsigned int i); + + /** + * @of_xlate: + * + * Callback to translate a device tree GPIO specifier into a chip- + * relative GPIO number and flags. + */ + int (*of_xlate)(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags); +#endif /* CONFIG_OF_GPIO */ +}; + +char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset); + + +struct _gpiochip_for_each_data { + const char **label; + unsigned int *i; +}; + +DEFINE_CLASS(_gpiochip_for_each_data, + struct _gpiochip_for_each_data, + if (*_T.label) kfree(*_T.label), + ({ + struct _gpiochip_for_each_data _data = { label, i }; + *_data.i = 0; + _data; + }), + const char **label, int *i) + +/** + * for_each_hwgpio_in_range - Iterates over all GPIOs in a given range + * @_chip: Chip to iterate over. + * @_i: Loop counter. + * @_base: First GPIO in the ranger. + * @_size: Amount of GPIOs to check starting from @base. + * @_label: Place to store the address of the label if the GPIO is requested. + * Set to NULL for unused GPIOs. + */ +#define for_each_hwgpio_in_range(_chip, _i, _base, _size, _label) \ + for (CLASS(_gpiochip_for_each_data, _data)(&_label, &_i); \ + _i < _size; \ + _i++, kfree(_label), _label = NULL) \ + for_each_if(!IS_ERR(_label = gpiochip_dup_line_label(_chip, _base + _i))) + +/** + * for_each_hwgpio - Iterates over all GPIOs for given chip. + * @_chip: Chip to iterate over. + * @_i: Loop counter. + * @_label: Place to store the address of the label if the GPIO is requested. + * Set to NULL for unused GPIOs. + */ +#define for_each_hwgpio(_chip, _i, _label) \ + for_each_hwgpio_in_range(_chip, _i, 0, _chip->ngpio, _label) + +/** + * for_each_requested_gpio_in_range - iterates over requested GPIOs in a given range + * @_chip: the chip to query + * @_i: loop variable + * @_base: first GPIO in the range + * @_size: amount of GPIOs to check starting from @base + * @_label: label of current GPIO + */ +#define for_each_requested_gpio_in_range(_chip, _i, _base, _size, _label) \ + for_each_hwgpio_in_range(_chip, _i, _base, _size, _label) \ + for_each_if(_label) + +/* Iterates over all requested GPIO of the given @chip */ +#define for_each_requested_gpio(chip, i, label) \ + for_each_requested_gpio_in_range(chip, i, 0, chip->ngpio, label) + +/* add/remove chips */ +int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, + struct lock_class_key *lock_key, + struct lock_class_key *request_key); + +/** + * gpiochip_add_data() - register a gpio_chip + * @gc: the chip to register, with gc->base initialized + * @data: driver-private data associated with this chip + * + * Context: potentially before irqs will work + * + * When gpiochip_add_data() is called very early during boot, so that GPIOs + * can be freely used, the gc->parent device must be registered before + * the gpio framework's arch_initcall(). Otherwise sysfs initialization + * for GPIOs will fail rudely. + * + * gpiochip_add_data() must only be called after gpiolib initialization, + * i.e. after core_initcall(). + * + * If gc->base is negative, this requests dynamic assignment of + * a range of valid GPIOs. + * + * Returns: + * A negative errno if the chip can't be registered, such as because the + * gc->base is invalid or already associated with a different chip. + * Otherwise it returns zero as a success code. + */ +#ifdef CONFIG_LOCKDEP +#define gpiochip_add_data(gc, data) ({ \ + static struct lock_class_key lock_key; \ + static struct lock_class_key request_key; \ + gpiochip_add_data_with_key(gc, data, &lock_key, \ + &request_key); \ + }) +#define devm_gpiochip_add_data(dev, gc, data) ({ \ + static struct lock_class_key lock_key; \ + static struct lock_class_key request_key; \ + devm_gpiochip_add_data_with_key(dev, gc, data, &lock_key, \ + &request_key); \ + }) +#else +#define gpiochip_add_data(gc, data) gpiochip_add_data_with_key(gc, data, NULL, NULL) +#define devm_gpiochip_add_data(dev, gc, data) \ + devm_gpiochip_add_data_with_key(dev, gc, data, NULL, NULL) +#endif /* CONFIG_LOCKDEP */ + +void gpiochip_remove(struct gpio_chip *gc); +int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, + void *data, struct lock_class_key *lock_key, + struct lock_class_key *request_key); + +struct gpio_device *gpio_device_find(const void *data, + int (*match)(struct gpio_chip *gc, + const void *data)); + +struct gpio_device *gpio_device_get(struct gpio_device *gdev); +void gpio_device_put(struct gpio_device *gdev); + +DEFINE_FREE(gpio_device_put, struct gpio_device *, + if (!IS_ERR_OR_NULL(_T)) gpio_device_put(_T)) + +struct device *gpio_device_to_device(struct gpio_device *gdev); + +bool gpiochip_line_is_irq(struct gpio_chip *gc, unsigned int offset); +int gpiochip_reqres_irq(struct gpio_chip *gc, unsigned int offset); +void gpiochip_relres_irq(struct gpio_chip *gc, unsigned int offset); +void gpiochip_disable_irq(struct gpio_chip *gc, unsigned int offset); +void gpiochip_enable_irq(struct gpio_chip *gc, unsigned int offset); + +/* irq_data versions of the above */ +int gpiochip_irq_reqres(struct irq_data *data); +void gpiochip_irq_relres(struct irq_data *data); + +/* Paste this in your irq_chip structure */ +#define GPIOCHIP_IRQ_RESOURCE_HELPERS \ + .irq_request_resources = gpiochip_irq_reqres, \ + .irq_release_resources = gpiochip_irq_relres + +static inline void gpio_irq_chip_set_chip(struct gpio_irq_chip *girq, + const struct irq_chip *chip) +{ + /* Yes, dropping const is ugly, but it isn't like we have a choice */ + girq->chip = (struct irq_chip *)chip; +} + +/* Line status inquiry for drivers */ +bool gpiochip_line_is_open_drain(struct gpio_chip *gc, unsigned int offset); +bool gpiochip_line_is_open_source(struct gpio_chip *gc, unsigned int offset); + +/* Sleep persistence inquiry for drivers */ +bool gpiochip_line_is_persistent(struct gpio_chip *gc, unsigned int offset); +bool gpiochip_line_is_valid(const struct gpio_chip *gc, unsigned int offset); +const unsigned long *gpiochip_query_valid_mask(const struct gpio_chip *gc); + +/* get driver data */ +void *gpiochip_get_data(struct gpio_chip *gc); + +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + +int gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc, + union gpio_irq_fwspec *gfwspec, + unsigned int parent_hwirq, + unsigned int parent_type); +int gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc, + union gpio_irq_fwspec *gfwspec, + unsigned int parent_hwirq, + unsigned int parent_type); + +#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ + +#ifdef CONFIG_GPIOLIB_IRQCHIP +int gpiochip_irqchip_add_domain(struct gpio_chip *gc, + struct irq_domain *domain); +#else + +#include <asm/bug.h> + +static inline int gpiochip_irqchip_add_domain(struct gpio_chip *gc, + struct irq_domain *domain) +{ + WARN_ON(1); + return -EINVAL; +} +#endif + +int gpiochip_generic_request(struct gpio_chip *gc, unsigned int offset); +void gpiochip_generic_free(struct gpio_chip *gc, unsigned int offset); +int gpiochip_generic_config(struct gpio_chip *gc, unsigned int offset, + unsigned long config); + +/** + * struct gpio_pin_range - pin range controlled by a gpio chip + * @node: list for maintaining set of pin ranges, used internally + * @pctldev: pinctrl device which handles corresponding pins + * @range: actual range of pins controlled by a gpio controller + */ +struct gpio_pin_range { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range range; +}; + +#ifdef CONFIG_PINCTRL + +int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int pin_offset, + unsigned int const *pins, + unsigned int npins); +int gpiochip_add_pingroup_range(struct gpio_chip *gc, + struct pinctrl_dev *pctldev, + unsigned int gpio_offset, const char *pin_group); +void gpiochip_remove_pin_ranges(struct gpio_chip *gc); + +static inline int +gpiochip_add_pin_range(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int pin_offset, + unsigned int npins) +{ + return gpiochip_add_pin_range_with_pins(gc, pinctl_name, gpio_offset, + pin_offset, NULL, npins); +} + +static inline int +gpiochip_add_sparse_pin_range(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int const *pins, + unsigned int npins) +{ + return gpiochip_add_pin_range_with_pins(gc, pinctl_name, gpio_offset, 0, + pins, npins); +} +#else /* ! CONFIG_PINCTRL */ + +static inline int +gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int pin_offset, + unsigned int npins) +{ + return 0; +} + +static inline int +gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name, + unsigned int gpio_offset, unsigned int pin_offset, + unsigned int npins) +{ + return 0; +} + +static inline int +gpiochip_add_sparse_pin_range(struct gpio_chip *gc, + const char *pinctl_name, + unsigned int gpio_offset, + unsigned int const *pins, + unsigned int npins) +{ + return 0; +} + +static inline int +gpiochip_add_pingroup_range(struct gpio_chip *gc, + struct pinctrl_dev *pctldev, + unsigned int gpio_offset, const char *pin_group) +{ + return 0; +} + +static inline void +gpiochip_remove_pin_ranges(struct gpio_chip *gc) +{ +} + +#endif /* CONFIG_PINCTRL */ + +struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc, + unsigned int hwnum, + const char *label, + enum gpio_lookup_flags lflags, + enum gpiod_flags dflags); +void gpiochip_free_own_desc(struct gpio_desc *desc); + +struct gpio_desc * +gpio_device_get_desc(struct gpio_device *gdev, unsigned int hwnum); + +struct gpio_chip *gpio_device_get_chip(struct gpio_device *gdev); + +#ifdef CONFIG_GPIOLIB + +/* lock/unlock as IRQ */ +int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset); +void gpiochip_unlock_as_irq(struct gpio_chip *gc, unsigned int offset); + +struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc); +struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc); + +/* struct gpio_device getters */ +int gpio_device_get_base(struct gpio_device *gdev); +const char *gpio_device_get_label(struct gpio_device *gdev); + +struct gpio_device *gpio_device_find_by_label(const char *label); +struct gpio_device *gpio_device_find_by_fwnode(const struct fwnode_handle *fwnode); + +#else /* CONFIG_GPIOLIB */ + +#include <asm/bug.h> + +static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(1); + return ERR_PTR(-ENODEV); +} + +static inline struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc) +{ + WARN_ON(1); + return ERR_PTR(-ENODEV); +} + +static inline int gpio_device_get_base(struct gpio_device *gdev) +{ + WARN_ON(1); + return -ENODEV; +} + +static inline const char *gpio_device_get_label(struct gpio_device *gdev) +{ + WARN_ON(1); + return NULL; +} + +static inline struct gpio_device *gpio_device_find_by_label(const char *label) +{ + WARN_ON(1); + return NULL; +} + +static inline struct gpio_device *gpio_device_find_by_fwnode(const struct fwnode_handle *fwnode) +{ + WARN_ON(1); + return NULL; +} + +static inline int gpiochip_lock_as_irq(struct gpio_chip *gc, + unsigned int offset) +{ + WARN_ON(1); + return -EINVAL; +} + +static inline void gpiochip_unlock_as_irq(struct gpio_chip *gc, + unsigned int offset) +{ + WARN_ON(1); +} +#endif /* CONFIG_GPIOLIB */ + +#define for_each_gpiochip_node(dev, child) \ + device_for_each_child_node(dev, child) \ + for_each_if(fwnode_property_present(child, "gpio-controller")) + +static inline unsigned int gpiochip_node_count(struct device *dev) +{ + struct fwnode_handle *child; + unsigned int count = 0; + + for_each_gpiochip_node(dev, child) + count++; + + return count; +} + +static inline struct fwnode_handle *gpiochip_node_get_first(struct device *dev) +{ + struct fwnode_handle *fwnode; + + for_each_gpiochip_node(dev, fwnode) + return fwnode; + + return NULL; +} + +#endif /* __LINUX_GPIO_DRIVER_H */ diff --git a/include/linux/gpio/forwarder.h b/include/linux/gpio/forwarder.h new file mode 100644 index 000000000000..ee5d8355f735 --- /dev/null +++ b/include/linux/gpio/forwarder.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_GPIO_FORWARDER_H +#define __LINUX_GPIO_FORWARDER_H + +struct gpio_desc; +struct gpio_chip; +struct gpiochip_fwd; + +struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev, + unsigned int ngpios); +int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, + struct gpio_desc *desc, unsigned int offset); +void gpiochip_fwd_desc_free(struct gpiochip_fwd *fwd, unsigned int offset); +int gpiochip_fwd_register(struct gpiochip_fwd *fwd, void *data); + +struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd); + +void *gpiochip_fwd_get_data(struct gpiochip_fwd *fwd); + +int gpiochip_fwd_gpio_request(struct gpiochip_fwd *fwd, unsigned int offset); +int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd, + unsigned int offset); +int gpiochip_fwd_gpio_direction_input(struct gpiochip_fwd *fwd, + unsigned int offset); +int gpiochip_fwd_gpio_direction_output(struct gpiochip_fwd *fwd, + unsigned int offset, + int value); +int gpiochip_fwd_gpio_get(struct gpiochip_fwd *fwd, unsigned int offset); +int gpiochip_fwd_gpio_get_multiple(struct gpiochip_fwd *fwd, + unsigned long *mask, + unsigned long *bits); +int gpiochip_fwd_gpio_set(struct gpiochip_fwd *fwd, unsigned int offset, + int value); +int gpiochip_fwd_gpio_set_multiple(struct gpiochip_fwd *fwd, + unsigned long *mask, + unsigned long *bits); +int gpiochip_fwd_gpio_set_config(struct gpiochip_fwd *fwd, unsigned int offset, + unsigned long config); +int gpiochip_fwd_gpio_to_irq(struct gpiochip_fwd *fwd, unsigned int offset); + +#endif diff --git a/include/linux/gpio/generic.h b/include/linux/gpio/generic.h new file mode 100644 index 000000000000..ff566dc9c3cb --- /dev/null +++ b/include/linux/gpio/generic.h @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LINUX_GPIO_GENERIC_H +#define __LINUX_GPIO_GENERIC_H + +#include <linux/cleanup.h> +#include <linux/gpio/driver.h> +#include <linux/spinlock.h> + +struct device; + +#define GPIO_GENERIC_BIG_ENDIAN BIT(0) +#define GPIO_GENERIC_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */ +#define GPIO_GENERIC_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */ +#define GPIO_GENERIC_BIG_ENDIAN_BYTE_ORDER BIT(3) +#define GPIO_GENERIC_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ +#define GPIO_GENERIC_NO_OUTPUT BIT(5) /* only input */ +#define GPIO_GENERIC_NO_SET_ON_INPUT BIT(6) +#define GPIO_GENERIC_PINCTRL_BACKEND BIT(7) /* Call pinctrl direction setters */ +#define GPIO_GENERIC_NO_INPUT BIT(8) /* only output */ + +/** + * struct gpio_generic_chip_config - Generic GPIO chip configuration data + * @dev: Parent device of the new GPIO chip (compulsory). + * @sz: Size (width) of the MMIO registers in bytes, typically 1, 2 or 4. + * @dat: MMIO address for the register to READ the value of the GPIO lines, it + * is expected that a 1 in the corresponding bit in this register means + * the line is asserted. + * @set: MMIO address for the register to SET the value of the GPIO lines, it + * is expected that we write the line with 1 in this register to drive + * the GPIO line high. + * @clr: MMIO address for the register to CLEAR the value of the GPIO lines, + * it is expected that we write the line with 1 in this register to + * drive the GPIO line low. It is allowed to leave this address as NULL, + * in that case the SET register will be assumed to also clear the GPIO + * lines, by actively writing the line with 0. + * @dirout: MMIO address for the register to set the line as OUTPUT. It is + * assumed that setting a line to 1 in this register will turn that + * line into an output line. Conversely, setting the line to 0 will + * turn that line into an input. + * @dirin: MMIO address for the register to set this line as INPUT. It is + * assumed that setting a line to 1 in this register will turn that + * line into an input line. Conversely, setting the line to 0 will + * turn that line into an output. + * @flags: Different flags that will affect the behaviour of the device, such + * as endianness etc. + */ +struct gpio_generic_chip_config { + struct device *dev; + unsigned long sz; + void __iomem *dat; + void __iomem *set; + void __iomem *clr; + void __iomem *dirout; + void __iomem *dirin; + unsigned long flags; +}; + +/** + * struct gpio_generic_chip - Generic GPIO chip implementation. + * @gc: The underlying struct gpio_chip object, implementing low-level GPIO + * chip routines. + * @read_reg: reader function for generic GPIO + * @write_reg: writer function for generic GPIO + * @be_bits: if the generic GPIO has big endian bit order (bit 31 is + * representing line 0, bit 30 is line 1 ... bit 0 is line 31) this + * is set to true by the generic GPIO core. It is for internal + * housekeeping only. + * @reg_dat: data (in) register for generic GPIO + * @reg_set: output set register (out=high) for generic GPIO + * @reg_clr: output clear register (out=low) for generic GPIO + * @reg_dir_out: direction out setting register for generic GPIO + * @reg_dir_in: direction in setting register for generic GPIO + * @dir_unreadable: indicates that the direction register(s) cannot be read and + * we need to rely on out internal state tracking. + * @pinctrl: the generic GPIO uses a pin control backend. + * @bits: number of register bits used for a generic GPIO + * i.e. <register width> * 8 + * @lock: used to lock chip->sdata. Also, this is needed to keep + * shadowed and real data registers writes together. + * @sdata: shadowed data register for generic GPIO to clear/set bits safely. + * @sdir: shadowed direction register for generic GPIO to clear/set direction + * safely. A "1" in this word means the line is set as output. + */ +struct gpio_generic_chip { + struct gpio_chip gc; + unsigned long (*read_reg)(void __iomem *reg); + void (*write_reg)(void __iomem *reg, unsigned long data); + bool be_bits; + void __iomem *reg_dat; + void __iomem *reg_set; + void __iomem *reg_clr; + void __iomem *reg_dir_out; + void __iomem *reg_dir_in; + bool dir_unreadable; + bool pinctrl; + int bits; + raw_spinlock_t lock; + unsigned long sdata; + unsigned long sdir; +}; + +static inline struct gpio_generic_chip * +to_gpio_generic_chip(struct gpio_chip *gc) +{ + return container_of(gc, struct gpio_generic_chip, gc); +} + +int gpio_generic_chip_init(struct gpio_generic_chip *chip, + const struct gpio_generic_chip_config *cfg); + +/** + * gpio_generic_chip_set() - Set the GPIO line value of the generic GPIO chip. + * @chip: Generic GPIO chip to use. + * @offset: Hardware offset of the line to set. + * @value: New GPIO line value. + * + * Some modules using the generic GPIO chip, need to set line values in their + * direction setters but they don't have access to the gpio-mmio symbols so + * they use the function pointer in struct gpio_chip directly. This is not + * optimal and can lead to crashes at run-time in some instances. This wrapper + * provides a safe interface for users. + * + * Returns: 0 on success, negative error number of failure. + */ +static inline int +gpio_generic_chip_set(struct gpio_generic_chip *chip, unsigned int offset, + int value) +{ + if (WARN_ON(!chip->gc.set)) + return -EOPNOTSUPP; + + return chip->gc.set(&chip->gc, offset, value); +} + +/** + * gpio_generic_read_reg() - Read a register using the underlying callback. + * @chip: Generic GPIO chip to use. + * @reg: Register to read. + * + * Returns: value read from register. + */ +static inline unsigned long +gpio_generic_read_reg(struct gpio_generic_chip *chip, void __iomem *reg) +{ + if (WARN_ON(!chip->read_reg)) + return 0; + + return chip->read_reg(reg); +} + +/** + * gpio_generic_write_reg() - Write a register using the underlying callback. + * @chip: Generic GPIO chip to use. + * @reg: Register to write to. + * @val: New value to write. + */ +static inline void gpio_generic_write_reg(struct gpio_generic_chip *chip, + void __iomem *reg, unsigned long val) +{ + if (WARN_ON(!chip->write_reg)) + return; + + chip->write_reg(reg, val); +} + +#define gpio_generic_chip_lock(gen_gc) \ + raw_spin_lock(&(gen_gc)->lock) + +#define gpio_generic_chip_unlock(gen_gc) \ + raw_spin_unlock(&(gen_gc)->lock) + +#define gpio_generic_chip_lock_irqsave(gen_gc, flags) \ + raw_spin_lock_irqsave(&(gen_gc)->lock, flags) + +#define gpio_generic_chip_unlock_irqrestore(gen_gc, flags) \ + raw_spin_unlock_irqrestore(&(gen_gc)->lock, flags) + +DEFINE_LOCK_GUARD_1(gpio_generic_lock, + struct gpio_generic_chip, + gpio_generic_chip_lock(_T->lock), + gpio_generic_chip_unlock(_T->lock)) + +DEFINE_LOCK_GUARD_1(gpio_generic_lock_irqsave, + struct gpio_generic_chip, + gpio_generic_chip_lock_irqsave(_T->lock, _T->flags), + gpio_generic_chip_unlock_irqrestore(_T->lock, _T->flags), + unsigned long flags) + +#endif /* __LINUX_GPIO_GENERIC_H */ diff --git a/include/linux/gpio/gpio-nomadik.h b/include/linux/gpio/gpio-nomadik.h new file mode 100644 index 000000000000..592a774a53cd --- /dev/null +++ b/include/linux/gpio/gpio-nomadik.h @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_GPIO_NOMADIK_H +#define __LINUX_GPIO_NOMADIK_H + +struct fwnode_handle; + +/* Package definitions */ +#define PINCTRL_NMK_STN8815 0 +#define PINCTRL_NMK_DB8500 1 + +#define GPIO_BLOCK_SHIFT 5 +#define NMK_GPIO_PER_CHIP BIT(GPIO_BLOCK_SHIFT) +#define NMK_MAX_BANKS DIV_ROUND_UP(512, NMK_GPIO_PER_CHIP) + +/* Register in the logic block */ +#define NMK_GPIO_DAT 0x00 +#define NMK_GPIO_DATS 0x04 +#define NMK_GPIO_DATC 0x08 +#define NMK_GPIO_PDIS 0x0c +#define NMK_GPIO_DIR 0x10 +#define NMK_GPIO_DIRS 0x14 +#define NMK_GPIO_DIRC 0x18 +#define NMK_GPIO_SLPC 0x1c +#define NMK_GPIO_AFSLA 0x20 +#define NMK_GPIO_AFSLB 0x24 +#define NMK_GPIO_LOWEMI 0x28 + +#define NMK_GPIO_RIMSC 0x40 +#define NMK_GPIO_FIMSC 0x44 +#define NMK_GPIO_IS 0x48 +#define NMK_GPIO_IC 0x4c +#define NMK_GPIO_RWIMSC 0x50 +#define NMK_GPIO_FWIMSC 0x54 +#define NMK_GPIO_WKS 0x58 +/* These appear in DB8540 and later ASICs */ +#define NMK_GPIO_EDGELEVEL 0x5C +#define NMK_GPIO_LEVEL 0x60 + +/* Pull up/down values */ +enum nmk_gpio_pull { + NMK_GPIO_PULL_NONE, + NMK_GPIO_PULL_UP, + NMK_GPIO_PULL_DOWN, +}; + +/* Sleep mode */ +enum nmk_gpio_slpm { + NMK_GPIO_SLPM_INPUT, + NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT, + NMK_GPIO_SLPM_NOCHANGE, + NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE, +}; + +struct nmk_gpio_chip { + struct gpio_chip chip; + void __iomem *addr; + struct clk *clk; + unsigned int bank; + void (*set_ioforce)(bool enable); + spinlock_t lock; + bool sleepmode; + bool is_mobileye_soc; + /* Keep track of configured edges */ + u32 edge_rising; + u32 edge_falling; + u32 real_wake; + u32 rwimsc; + u32 fwimsc; + u32 rimsc; + u32 fimsc; + u32 pull_up; + u32 lowemi; +}; + +/* Alternate functions: function C is set in hw by setting both A and B */ +#define NMK_GPIO_ALT_GPIO 0 +#define NMK_GPIO_ALT_A 1 +#define NMK_GPIO_ALT_B 2 +#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) + +#define NMK_GPIO_ALT_CX_SHIFT 2 +#define NMK_GPIO_ALT_C1 ((1<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C2 ((2<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C3 ((3<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C4 ((4<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) + +#define PRCM_GPIOCR_ALTCX(pin_num,\ + altc1_used, altc1_ri, altc1_cb,\ + altc2_used, altc2_ri, altc2_cb,\ + altc3_used, altc3_ri, altc3_cb,\ + altc4_used, altc4_ri, altc4_cb)\ +{\ + .pin = pin_num,\ + .altcx[PRCM_IDX_GPIOCR_ALTC1] = {\ + .used = altc1_used,\ + .reg_index = altc1_ri,\ + .control_bit = altc1_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC2] = {\ + .used = altc2_used,\ + .reg_index = altc2_ri,\ + .control_bit = altc2_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC3] = {\ + .used = altc3_used,\ + .reg_index = altc3_ri,\ + .control_bit = altc3_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC4] = {\ + .used = altc4_used,\ + .reg_index = altc4_ri,\ + .control_bit = altc4_cb\ + },\ +} + +/** + * enum prcm_gpiocr_reg_index + * Used to reference an PRCM GPIOCR register address. + */ +enum prcm_gpiocr_reg_index { + PRCM_IDX_GPIOCR1, + PRCM_IDX_GPIOCR2, + PRCM_IDX_GPIOCR3 +}; +/** + * enum prcm_gpiocr_altcx_index + * Used to reference an Other alternate-C function. + */ +enum prcm_gpiocr_altcx_index { + PRCM_IDX_GPIOCR_ALTC1, + PRCM_IDX_GPIOCR_ALTC2, + PRCM_IDX_GPIOCR_ALTC3, + PRCM_IDX_GPIOCR_ALTC4, + PRCM_IDX_GPIOCR_ALTC_MAX, +}; + +/** + * struct prcm_gpio_altcx - Other alternate-C function + * @used: other alternate-C function availability + * @reg_index: PRCM GPIOCR register index used to control the function + * @control_bit: PRCM GPIOCR bit used to control the function + */ +struct prcm_gpiocr_altcx { + bool used:1; + u8 reg_index:2; + u8 control_bit:5; +} __packed; + +/** + * struct prcm_gpio_altcx_pin_desc - Other alternate-C pin + * @pin: The pin number + * @altcx: array of other alternate-C[1-4] functions + */ +struct prcm_gpiocr_altcx_pin_desc { + unsigned short pin; + struct prcm_gpiocr_altcx altcx[PRCM_IDX_GPIOCR_ALTC_MAX]; +}; + +/** + * struct nmk_function - Nomadik pinctrl mux function + * @name: The name of the function, exported to pinctrl core. + * @groups: An array of pin groups that may select this function. + * @ngroups: The number of entries in @groups. + */ +struct nmk_function { + const char *name; + const char * const *groups; + unsigned int ngroups; +}; + +/** + * struct nmk_pingroup - describes a Nomadik pin group + * @grp: Generic data of the pin group (name and pins) + * @altsetting: the altsetting to apply to all pins in this group to + * configure them to be used by a function + */ +struct nmk_pingroup { + struct pingroup grp; + int altsetting; +}; + +#define NMK_PIN_GROUP(a, b) \ + { \ + .grp = PINCTRL_PINGROUP(#a, a##_pins, ARRAY_SIZE(a##_pins)), \ + .altsetting = b, \ + } + +/** + * struct nmk_pinctrl_soc_data - Nomadik pin controller per-SoC configuration + * @pins: An array describing all pins the pin controller affects. + * All pins which are also GPIOs must be listed first within the + * array, and be numbered identically to the GPIO controller's + * numbering. + * @npins: The number of entries in @pins. + * @functions: The functions supported on this SoC. + * @nfunction: The number of entries in @functions. + * @groups: An array describing all pin groups the pin SoC supports. + * @ngroups: The number of entries in @groups. + * @altcx_pins: The pins that support Other alternate-C function on this SoC + * @npins_altcx: The number of Other alternate-C pins + * @prcm_gpiocr_registers: The array of PRCM GPIOCR registers on this SoC + */ +struct nmk_pinctrl_soc_data { + const struct pinctrl_pin_desc *pins; + unsigned int npins; + const struct nmk_function *functions; + unsigned int nfunctions; + const struct nmk_pingroup *groups; + unsigned int ngroups; + const struct prcm_gpiocr_altcx_pin_desc *altcx_pins; + unsigned int npins_altcx; + const u16 *prcm_gpiocr_registers; +}; + +#ifdef CONFIG_PINCTRL_STN8815 + +void nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc); + +#else + +static inline void +nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc) +{ +} + +#endif + +#ifdef CONFIG_PINCTRL_DB8500 + +void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc); + +#else + +static inline void +nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc) +{ +} + +#endif + +#ifdef CONFIG_PINCTRL_DB8540 + +void nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc); + +#else + +static inline void +nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc) +{ +} + +#endif + +struct platform_device; + +#ifdef CONFIG_DEBUG_FS + +/* + * Symbols declared in gpio-nomadik used by pinctrl-nomadik. If pinctrl-nomadik + * is enabled, then gpio-nomadik is enabled as well; the reverse if not always + * true. + */ +void nmk_gpio_dbg_show_one(struct seq_file *s, struct pinctrl_dev *pctldev, + struct gpio_chip *chip, unsigned int offset); + +#else + +static inline void nmk_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, + struct gpio_chip *chip, + unsigned int offset) +{ +} + +#endif + +void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip, + unsigned int offset, int val); +void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip, unsigned int offset, + enum nmk_gpio_slpm mode); +struct nmk_gpio_chip *nmk_gpio_populate_chip(struct fwnode_handle *fwnode, + struct platform_device *pdev); + +/* Symbols declared in pinctrl-nomadik used by gpio-nomadik. */ +#ifdef CONFIG_PINCTRL_NOMADIK +extern struct nmk_gpio_chip *nmk_gpio_chips[NMK_MAX_BANKS]; +extern spinlock_t nmk_gpio_slpm_lock; +int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, + int gpio); +#endif + +#endif /* __LINUX_GPIO_NOMADIK_H */ diff --git a/include/linux/gpio/gpio-reg.h b/include/linux/gpio/gpio-reg.h new file mode 100644 index 000000000000..3913b6660ed1 --- /dev/null +++ b/include/linux/gpio/gpio-reg.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef GPIO_REG_H +#define GPIO_REG_H + +#include <linux/types.h> + +struct device; +struct irq_domain; + +struct gpio_chip; + +struct gpio_chip *gpio_reg_init(struct device *dev, void __iomem *reg, + int base, int num, const char *label, u32 direction, u32 def_out, + const char *const *names, struct irq_domain *irqdom, const int *irqs); + +int gpio_reg_resume(struct gpio_chip *gc); + +#endif /* GPIO_REG_H */ diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h new file mode 100644 index 000000000000..44e5f162973e --- /dev/null +++ b/include/linux/gpio/machine.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_GPIO_MACHINE_H +#define __LINUX_GPIO_MACHINE_H + +#include <linux/types.h> + +enum gpio_lookup_flags { + GPIO_ACTIVE_HIGH = (0 << 0), + GPIO_ACTIVE_LOW = (1 << 0), + GPIO_OPEN_DRAIN = (1 << 1), + GPIO_OPEN_SOURCE = (1 << 2), + GPIO_PERSISTENT = (0 << 3), + GPIO_TRANSITORY = (1 << 3), + GPIO_PULL_UP = (1 << 4), + GPIO_PULL_DOWN = (1 << 5), + GPIO_PULL_DISABLE = (1 << 6), + + GPIO_LOOKUP_FLAGS_DEFAULT = GPIO_ACTIVE_HIGH | GPIO_PERSISTENT, +}; + +/** + * struct gpiod_lookup - lookup table + * @key: either the name of the chip the GPIO belongs to, or the GPIO line name + * Note that GPIO line names are not guaranteed to be globally unique, + * so this will use the first match found! + * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO, or + * U16_MAX to indicate that @key is a GPIO line name + * @con_id: name of the GPIO from the device's point of view + * @idx: index of the GPIO in case several GPIOs share the same name + * @flags: bitmask of gpio_lookup_flags GPIO_* values + * + * gpiod_lookup is a lookup table for associating GPIOs to specific devices and + * functions using platform data. + */ +struct gpiod_lookup { + const char *key; + u16 chip_hwnum; + const char *con_id; + unsigned int idx; + unsigned long flags; +}; + +struct gpiod_lookup_table { + struct list_head list; + const char *dev_id; + struct gpiod_lookup table[]; +}; + +/** + * struct gpiod_hog - GPIO line hog table + * @chip_label: name of the chip the GPIO belongs to + * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO + * @line_name: consumer name for the hogged line + * @lflags: bitmask of gpio_lookup_flags GPIO_* values + * @dflags: GPIO flags used to specify the direction and value + */ +struct gpiod_hog { + struct list_head list; + const char *chip_label; + u16 chip_hwnum; + const char *line_name; + unsigned long lflags; + int dflags; +}; + +/* + * Helper for lookup tables with just one single lookup for a device. + */ +#define GPIO_LOOKUP_SINGLE(_name, _dev_id, _key, _chip_hwnum, _con_id, _flags) \ +static struct gpiod_lookup_table _name = { \ + .dev_id = _dev_id, \ + .table = { \ + GPIO_LOOKUP(_key, _chip_hwnum, _con_id, _flags), \ + {}, \ + }, \ +} + +/* + * Simple definition of a single GPIO under a con_id + */ +#define GPIO_LOOKUP(_key, _chip_hwnum, _con_id, _flags) \ + GPIO_LOOKUP_IDX(_key, _chip_hwnum, _con_id, 0, _flags) + +/* + * Use this macro if you need to have several GPIOs under the same con_id. + * Each GPIO needs to use a different index and can be accessed using + * gpiod_get_index() + */ +#define GPIO_LOOKUP_IDX(_key, _chip_hwnum, _con_id, _idx, _flags) \ +(struct gpiod_lookup) { \ + .key = _key, \ + .chip_hwnum = _chip_hwnum, \ + .con_id = _con_id, \ + .idx = _idx, \ + .flags = _flags, \ +} + +/* + * Simple definition of a single GPIO hog in an array. + */ +#define GPIO_HOG(_chip_label, _chip_hwnum, _line_name, _lflags, _dflags) \ +(struct gpiod_hog) { \ + .chip_label = _chip_label, \ + .chip_hwnum = _chip_hwnum, \ + .line_name = _line_name, \ + .lflags = _lflags, \ + .dflags = _dflags, \ +} + +#ifdef CONFIG_GPIOLIB +void gpiod_add_lookup_table(struct gpiod_lookup_table *table); +void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n); +void gpiod_remove_lookup_table(struct gpiod_lookup_table *table); +void gpiod_add_hogs(struct gpiod_hog *hogs); +void gpiod_remove_hogs(struct gpiod_hog *hogs); +#else /* ! CONFIG_GPIOLIB */ +static inline +void gpiod_add_lookup_table(struct gpiod_lookup_table *table) {} +static inline +void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) {} +static inline +void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) {} +static inline void gpiod_add_hogs(struct gpiod_hog *hogs) {} +static inline void gpiod_remove_hogs(struct gpiod_hog *hogs) {} +#endif /* CONFIG_GPIOLIB */ + +#endif /* __LINUX_GPIO_MACHINE_H */ diff --git a/include/linux/gpio/property.h b/include/linux/gpio/property.h new file mode 100644 index 000000000000..0d2209308002 --- /dev/null +++ b/include/linux/gpio/property.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +#ifndef __LINUX_GPIO_PROPERTY_H +#define __LINUX_GPIO_PROPERTY_H + +#include <linux/property.h> + +struct software_node; + +#define PROPERTY_ENTRY_GPIO(_name_, _chip_node_, _idx_, _flags_) \ + PROPERTY_ENTRY_REF(_name_, _chip_node_, _idx_, _flags_) + +extern const struct software_node swnode_gpio_undefined; + +#endif /* __LINUX_GPIO_PROPERTY_H */ diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h new file mode 100644 index 000000000000..12d154732ca9 --- /dev/null +++ b/include/linux/gpio/regmap.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _LINUX_GPIO_REGMAP_H +#define _LINUX_GPIO_REGMAP_H + +struct device; +struct fwnode_handle; +struct gpio_regmap; +struct gpio_chip; +struct irq_domain; +struct regmap; + +#define GPIO_REGMAP_ADDR_ZERO ((unsigned int)(-1)) +#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO) + +/** + * struct gpio_regmap_config - Description of a generic regmap gpio_chip. + * @parent: The parent device + * @regmap: The regmap used to access the registers + * given, the name of the device is used + * @fwnode: (Optional) The firmware node. + * If not given, the fwnode of the parent is used. + * @label: (Optional) Descriptive name for GPIO controller. + * If not given, the name of the device is used. + * @ngpio: (Optional) Number of GPIOs + * @names: (Optional) Array of names for gpios + * @reg_dat_base: (Optional) (in) register base address + * @reg_set_base: (Optional) set register base address + * @reg_clr_base: (Optional) clear register base address + * @reg_dir_in_base: (Optional) in setting register base address + * @reg_dir_out_base: (Optional) out setting register base address + * @reg_stride: (Optional) May be set if the registers (of the + * same type, dat, set, etc) are not consecutive. + * @ngpio_per_reg: (Optional) Number of GPIOs per register + * @irq_domain: (Optional) IRQ domain if the controller is + * interrupt-capable + * @reg_mask_xlate: (Optional) Translates base address and GPIO + * offset to a register/bitmask pair. If not + * given the default gpio_regmap_simple_xlate() + * is used. + * @fixed_direction_output: + * (Optional) Bitmap representing the fixed direction of + * the GPIO lines. Useful when there are GPIO lines with a + * fixed direction mixed together in the same register. + * @drvdata: (Optional) Pointer to driver specific data which is + * not used by gpio-remap but is provided "as is" to the + * driver callback(s). + * @init_valid_mask: (Optional) Routine to initialize @valid_mask, to be used + * if not all GPIOs are valid. + * @regmap_irq_chip: (Optional) Pointer on an regmap_irq_chip structure. If + * set, a regmap-irq device will be created and the IRQ + * domain will be set accordingly. + * @regmap_irq_line: (Optional) The IRQ the device uses to signal interrupts. + * @regmap_irq_flags: (Optional) The IRQF_ flags to use for the interrupt. + * + * The ->reg_mask_xlate translates a given base address and GPIO offset to + * register and mask pair. The base address is one of the given register + * base addresses in this structure. + * + * Although all register base addresses are marked as optional, there are + * several rules: + * 1. if you only have @reg_dat_base set, then it is input-only + * 2. if you only have @reg_set_base set, then it is output-only + * 3. if you have either @reg_dir_in_base or @reg_dir_out_base set, then + * you have to set both @reg_dat_base and @reg_set_base + * 4. if you have @reg_set_base set, you may also set @reg_clr_base to have + * two different registers for setting and clearing the output. This is + * also valid for the output-only case. + * 5. @reg_dir_in_base and @reg_dir_out_base are exclusive; is there really + * hardware which has redundant registers? + * + * Note: All base addresses may have the special value %GPIO_REGMAP_ADDR_ZERO + * which forces the address to the value 0. + */ +struct gpio_regmap_config { + struct device *parent; + struct regmap *regmap; + struct fwnode_handle *fwnode; + + const char *label; + int ngpio; + const char *const *names; + + unsigned int reg_dat_base; + unsigned int reg_set_base; + unsigned int reg_clr_base; + unsigned int reg_dir_in_base; + unsigned int reg_dir_out_base; + int reg_stride; + int ngpio_per_reg; + struct irq_domain *irq_domain; + unsigned long *fixed_direction_output; + +#ifdef CONFIG_REGMAP_IRQ + struct regmap_irq_chip *regmap_irq_chip; + int regmap_irq_line; + unsigned long regmap_irq_flags; +#endif + + int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask); + + int (*init_valid_mask)(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios); + + void *drvdata; +}; + +struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config); +void gpio_regmap_unregister(struct gpio_regmap *gpio); +struct gpio_regmap *devm_gpio_regmap_register(struct device *dev, + const struct gpio_regmap_config *config); +void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio); + +#endif /* _LINUX_GPIO_REGMAP_H */ |
