From 4398693a9e24bcab0b99ea219073917991d0792b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 8 Feb 2022 11:48:31 +0100 Subject: gpiolib: make struct comments into real kernel docs We have several comments that start with '/**' but don't conform to the kernel doc standard. Add proper detailed descriptions for the affected definitions and move the docs from the forward declarations to the struct definitions where applicable. Reported-by: Randy Dunlap Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Tested-by: Randy Dunlap --- include/linux/gpio/consumer.h | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'include/linux/gpio') diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 3ad67b4a72be..c3aa8b330e1c 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -8,27 +8,16 @@ #include struct device; - -/** - * Opaque descriptor for a GPIO. These are obtained using gpiod_get() and are - * preferable to the old integer-based handles. - * - * Contrary to integers, a pointer to a gpio_desc is guaranteed to be valid - * until the GPIO is released. - */ struct gpio_desc; - -/** - * Opaque descriptor for a structure of GPIO array attributes. 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 containing an array of descriptors that can be obtained using - * gpiod_get_array(). + * 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; @@ -43,8 +32,16 @@ struct gpio_descs { #define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4) /** - * Optional flags that can be passed to one of gpiod_* to configure direction - * and output value. These values cannot be OR'd. + * 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, -- cgit v1.2.3 From 48ec13d36d3ff716a8a08e6583a925def7a2564d Mon Sep 17 00:00:00 2001 From: Joey Gouly Date: Fri, 18 Mar 2022 12:12:33 +0000 Subject: gpio: Properly document parent data union Suppress a warning in the html docs by documenting these fields separately. Signed-off-by: Joey Gouly Link: https://lore.kernel.org/lkml/20211027220118.71a229ab@canb.auug.org.au/ Cc: Linus Walleij Cc: Bartosz Golaszewski Cc: Marc Zyngier Cc: Stephen Rothwell Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- include/linux/gpio/driver.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'include/linux/gpio') diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index b0728c8ad90c..98c93510640e 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -168,13 +168,16 @@ struct gpio_irq_chip { /** * @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. + * * @parent_handler_data_array: * - * Data associated, and passed to, the handler for the parent - * interrupt. Can either be a single pointer if @per_parent_data - * is false, or an array of @num_parents pointers otherwise. If - * @per_parent_data is true, @parent_handler_data_array cannot be - * NULL. + * 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. */ union { void *parent_handler_data; -- cgit v1.2.3 From 5467801f1fcbdc46bc7298a84dbf3ca1ff2a7320 Mon Sep 17 00:00:00 2001 From: Shreeya Patel Date: Mon, 21 Mar 2022 19:02:41 +0530 Subject: gpio: Restrict usage of GPIO chip irq members before initialization GPIO chip irq members are exposed before they could be completely initialized and this leads to race conditions. One such issue was observed for the gc->irq.domain variable which was accessed through the I2C interface in gpiochip_to_irq() before it could be initialized by gpiochip_add_irqchip(). This resulted in Kernel NULL pointer dereference. Following are the logs for reference :- kernel: Call Trace: kernel: gpiod_to_irq+0x53/0x70 kernel: acpi_dev_gpio_irq_get_by+0x113/0x1f0 kernel: i2c_acpi_get_irq+0xc0/0xd0 kernel: i2c_device_probe+0x28a/0x2a0 kernel: really_probe+0xf2/0x460 kernel: RIP: 0010:gpiochip_to_irq+0x47/0xc0 To avoid such scenarios, restrict usage of GPIO chip irq members before they are completely initialized. Signed-off-by: Shreeya Patel Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 19 +++++++++++++++++++ include/linux/gpio/driver.h | 9 +++++++++ 2 files changed, 28 insertions(+) (limited to 'include/linux/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e59884cc12a7..085348e08986 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1404,6 +1404,16 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset) { struct irq_domain *domain = gc->irq.domain; +#ifdef CONFIG_GPIOLIB_IRQCHIP + /* + * Avoid race condition with other code, which tries to lookup + * an IRQ before the irqchip has been properly registered, + * i.e. while gpiochip is still being brought up. + */ + if (!gc->irq.initialized) + return -EPROBE_DEFER; +#endif + if (!gpiochip_irqchip_irq_valid(gc, offset)) return -ENXIO; @@ -1593,6 +1603,15 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc, acpi_gpiochip_request_interrupts(gc); + /* + * Using barrier() here to prevent compiler from reordering + * gc->irq.initialized before initialization of above + * GPIO chip irq members. + */ + barrier(); + + gc->irq.initialized = true; + return 0; } diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 98c93510640e..874aabd270c9 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -221,6 +221,15 @@ struct gpio_irq_chip { */ 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; + /** * @init_hw: optional routine to initialize hardware before * an IRQ chip will be added. This is quite useful when -- cgit v1.2.3 From 0c2cae09a765b1c1d842eb9328982976ec735926 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 17 Mar 2022 11:33:11 +0200 Subject: gpiolib: acpi: Convert type for pin to be unsigned A pin that comes from ACPI tables is of unsigned type. This also applies to the internal APIs which use unsigned int to store the pin. Convert type for pin to be unsigned in the places where it's not yet true. While at it, add a stub for acpi_get_and_request_gpiod() for the sake of consistency in the APIs. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 18 ++++++++++-------- include/linux/gpio/consumer.h | 8 +++++++- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'include/linux/gpio') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index b7c2f2af1dee..c2523ac26fac 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -108,7 +108,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) * controller does not have GPIO chip registered at the moment. This is to * support probe deferral. */ -static struct gpio_desc *acpi_get_gpiod(char *path, int pin) +static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin) { struct gpio_chip *chip; acpi_handle handle; @@ -136,7 +136,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) * as it is intended for use outside of the GPIO layer (in a similar fashion to * gpiod_get_index() for example) it also holds a reference to the GPIO device. */ -struct gpio_desc *acpi_get_and_request_gpiod(char *path, int pin, char *label) +struct gpio_desc *acpi_get_and_request_gpiod(char *path, unsigned int pin, char *label) { struct gpio_desc *gpio; int ret; @@ -317,11 +317,12 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip, return desc; } -static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in) +static bool acpi_gpio_in_ignore_list(const char *controller_in, unsigned int pin_in) { const char *controller, *pin_str; - int len, pin; + unsigned int pin; char *endp; + int len; controller = ignore_wake; while (controller) { @@ -354,13 +355,13 @@ err: static bool acpi_gpio_irq_is_wake(struct device *parent, struct acpi_resource_gpio *agpio) { - int pin = agpio->pin_table[0]; + unsigned int pin = agpio->pin_table[0]; if (agpio->wake_capable != ACPI_WAKE_CAPABLE) return false; if (acpi_gpio_in_ignore_list(dev_name(parent), pin)) { - dev_info(parent, "Ignoring wakeup on pin %d\n", pin); + dev_info(parent, "Ignoring wakeup on pin %u\n", pin); return false; } @@ -378,7 +379,8 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, struct acpi_gpio_event *event; irq_handler_t handler = NULL; struct gpio_desc *desc; - int ret, pin, irq; + unsigned int pin; + int ret, irq; if (!acpi_gpio_get_irq_resource(ares, &agpio)) return AE_OK; @@ -1098,7 +1100,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, length = min_t(u16, agpio->pin_table_length, pin_index + bits); for (i = pin_index; i < length; ++i) { - int pin = agpio->pin_table[i]; + unsigned int pin = agpio->pin_table[i]; struct acpi_gpio_connection *conn; struct gpio_desc *desc; bool found; diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index c3aa8b330e1c..e71f6e1bfafe 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -688,7 +688,7 @@ 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); -struct gpio_desc *acpi_get_and_request_gpiod(char *path, int pin, char *label); +struct gpio_desc *acpi_get_and_request_gpiod(char *path, unsigned int pin, char *label); #else /* CONFIG_GPIOLIB && CONFIG_ACPI */ @@ -705,6 +705,12 @@ static inline int devm_acpi_dev_add_driver_gpios(struct device *dev, return -ENXIO; } +static inline struct gpio_desc *acpi_get_and_request_gpiod(char *path, unsigned int pin, + char *label) +{ + return ERR_PTR(-ENOSYS); +} + #endif /* CONFIG_GPIOLIB && CONFIG_ACPI */ -- cgit v1.2.3 From 85ebb1a6bd62147ebcfa70500d513331a8daf9e0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Apr 2022 13:35:52 +0300 Subject: gpiolib: Introduce for_each_gpiochip_node() loop helper Introduce for_each_gpiochip_node() loop helper which iterates over the GPIO controller child nodes of a given device. Signed-off-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Acked-by: Bartosz Golaszewski --- include/linux/gpio/driver.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'include/linux/gpio') diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 98c93510640e..bfc91f122d5f 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -3,13 +3,14 @@ #define __LINUX_GPIO_DRIVER_H #include -#include #include #include #include #include #include #include +#include +#include struct gpio_desc; struct of_phandle_args; @@ -750,4 +751,8 @@ static inline void gpiochip_unlock_as_irq(struct gpio_chip *gc, } #endif /* CONFIG_GPIOLIB */ +#define for_each_gpiochip_node(dev, child) \ + device_for_each_child_node(dev, child) \ + if (!fwnode_property_present(child, "gpio-controller")) {} else + #endif /* __LINUX_GPIO_DRIVER_H */ -- cgit v1.2.3 From 0b19dde90ad004592792a928c75e80612be3e2e8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Apr 2022 13:35:53 +0300 Subject: gpiolib: Introduce gpiochip_node_count() helper The gpiochip_node_count() helper iterates over the device child nodes that have the "gpio-controller" property set. It returns the number of such nodes under a given device. Signed-off-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Acked-by: Bartosz Golaszewski --- include/linux/gpio/driver.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include/linux/gpio') diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index bfc91f122d5f..12de0b22b4ef 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -755,4 +755,15 @@ static inline void gpiochip_unlock_as_irq(struct gpio_chip *gc, device_for_each_child_node(dev, child) \ if (!fwnode_property_present(child, "gpio-controller")) {} else +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; +} + #endif /* __LINUX_GPIO_DRIVER_H */ -- cgit v1.2.3 From af47d8033fc731f19600efd27ba4a7d0fdfcc77c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 Apr 2022 21:42:48 +0300 Subject: gpiolib: Introduce a helper to get first GPIO controller node Introduce a helper to get first GPIO controller node which drivers may want to use. Signed-off-by: Andy Shevchenko Tested-by: Marek Szyprowski --- include/linux/gpio/driver.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/linux/gpio') diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 12de0b22b4ef..83e2d72e51bb 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -766,4 +766,14 @@ static inline unsigned int gpiochip_node_count(struct device *dev) 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 */ -- cgit v1.2.3 From 704f08753b6dcd0e08c1953af0b2c7f3fac87111 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 19 Apr 2022 15:18:38 +0100 Subject: gpio: Expose the gpiochip_irq_re[ql]res helpers The GPIO subsystem has a couple of internal helpers to manage resources on behalf of the irqchip. Expose them so that GPIO drivers can use them directly. Reviewed-by: Andy Shevchenko Reviewed-by: Bartosz Golaszewski Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220419141846.598305-3-maz@kernel.org --- drivers/gpio/gpiolib.c | 6 ++++-- include/linux/gpio/driver.h | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include/linux/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 48191e62a3cc..36e436a66e09 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1423,19 +1423,21 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset) return irq_create_mapping(domain, offset); } -static int gpiochip_irq_reqres(struct irq_data *d) +int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); return gpiochip_reqres_irq(gc, d->hwirq); } +EXPORT_SYMBOL(gpiochip_irq_reqres); -static void gpiochip_irq_relres(struct irq_data *d) +void gpiochip_irq_relres(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); gpiochip_relres_irq(gc, d->hwirq); } +EXPORT_SYMBOL(gpiochip_irq_relres); static void gpiochip_irq_mask(struct irq_data *d) { diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 98c93510640e..066bcfdf878d 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -579,6 +579,10 @@ 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); + /* 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); -- cgit v1.2.3 From 36b78aae4bfee749bbde73be570796bfd0f56bec Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 19 Apr 2022 15:18:39 +0100 Subject: gpio: Add helpers to ease the transition towards immutable irq_chip Add a couple of new helpers to make it slightly simpler to convert drivers to immutable irq_chip structures: - GPIOCHIP_IRQ_RESOURCE_HELPERS populates the irq_chip structure with the resource management callbacks - gpio_irq_chip_set_chip() populates the gpio_irq_chip.chip structure, avoiding the proliferation of ugly casts Reviewed-by: Andy Shevchenko Reviewed-by: Bartosz Golaszewski Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220419141846.598305-4-maz@kernel.org --- include/linux/gpio/driver.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include/linux/gpio') diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 066bcfdf878d..832990099097 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -583,6 +583,18 @@ void gpiochip_enable_irq(struct gpio_chip *gc, unsigned int offset); 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); -- cgit v1.2.3 From 3550bba25d5587a701e6edf20e20984d2ee72c78 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 9 Apr 2022 11:51:28 +0200 Subject: gpiolib: of: Introduce hook for missing gpio-ranges Since commit 2ab73c6d8323 ("gpio: Support GPIO controllers without pin-ranges") the device tree nodes of GPIO controller need the gpio-ranges property to handle gpio-hogs. Unfortunately it's impossible to guarantee that every new kernel is shipped with an updated device tree binary. In order to provide backward compatibility with those older DTB, we need a callback within of_gpiochip_add_pin_range() so the relevant platform driver can handle this case. Fixes: 2ab73c6d8323 ("gpio: Support GPIO controllers without pin-ranges") Signed-off-by: Stefan Wahren Reviewed-by: Florian Fainelli Tested-by: Florian Fainelli Acked-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20220409095129.45786-2-stefan.wahren@i2se.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 5 +++++ include/linux/gpio/driver.h | 12 ++++++++++++ 2 files changed, 17 insertions(+) (limited to 'include/linux/gpio') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index ae1ce319cd78..d9b235c88b54 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -931,6 +931,11 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) if (!np) return 0; + if (!of_property_read_bool(np, "gpio-ranges") && + chip->of_gpio_ranges_fallback) { + return chip->of_gpio_ranges_fallback(chip, np); + } + group_names = of_find_property(np, group_names_propname, NULL); for (;; index++) { diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 98c93510640e..c2041bd01f90 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -492,6 +492,18 @@ struct gpio_chip { */ int (*of_xlate)(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags); + + /** + * @of_gpio_ranges_fallback: + * + * Optional hook for the case that no gpio-ranges property is defined + * within the device tree node "np" (usually DT before introduction + * of gpio-ranges). So this callback is helpful to provide the + * necessary backward compatibility for the pin ranges. + */ + int (*of_gpio_ranges_fallback)(struct gpio_chip *gc, + struct device_node *np); + #endif /* CONFIG_OF_GPIO */ }; -- cgit v1.2.3 From 3c938cc5cebcbd2291fe97f523c0705a2c24c77d Mon Sep 17 00:00:00 2001 From: Schspa Shi Date: Tue, 19 Apr 2022 09:28:10 +0800 Subject: gpio: use raw spinlock for gpio chip shadowed data In case of PREEMPT_RT, there is a raw_spinlock -> spinlock dependency as the lockdep report shows. __irq_set_handler irq_get_desc_buslock __irq_get_desc_lock raw_spin_lock_irqsave(&desc->lock, *flags); // raw spinlock get here __irq_do_set_handler mask_ack_irq dwapb_irq_ack spin_lock_irqsave(&gc->bgpio_lock, flags); // sleep able spinlock irq_put_desc_busunlock Replace with a raw lock to avoid BUGs. This lock is only used to access registers, and It's safe to replace with the raw lock without bad influence. [ 15.090359][ T1] ============================= [ 15.090365][ T1] [ BUG: Invalid wait context ] [ 15.090373][ T1] 5.10.59-rt52-00983-g186a6841c682-dirty #3 Not tainted [ 15.090386][ T1] ----------------------------- [ 15.090392][ T1] swapper/0/1 is trying to lock: [ 15.090402][ T1] 70ff00018507c188 (&gc->bgpio_lock){....}-{3:3}, at: _raw_spin_lock_irqsave+0x1c/0x28 [ 15.090470][ T1] other info that might help us debug this: [ 15.090477][ T1] context-{5:5} [ 15.090485][ T1] 3 locks held by swapper/0/1: [ 15.090497][ T1] #0: c2ff0001816de1a0 (&dev->mutex){....}-{4:4}, at: __device_driver_lock+0x98/0x104 [ 15.090553][ T1] #1: ffff90001485b4b8 (irq_domain_mutex){+.+.}-{4:4}, at: irq_domain_associate+0xbc/0x6d4 [ 15.090606][ T1] #2: 4bff000185d7a8e0 (lock_class){....}-{2:2}, at: _raw_spin_lock_irqsave+0x1c/0x28 [ 15.090654][ T1] stack backtrace: [ 15.090661][ T1] CPU: 4 PID: 1 Comm: swapper/0 Not tainted 5.10.59-rt52-00983-g186a6841c682-dirty #3 [ 15.090682][ T1] Hardware name: Horizon Robotics Journey 5 DVB (DT) [ 15.090692][ T1] Call trace: ...... [ 15.090811][ T1] _raw_spin_lock_irqsave+0x1c/0x28 [ 15.090828][ T1] dwapb_irq_ack+0xb4/0x300 [ 15.090846][ T1] __irq_do_set_handler+0x494/0xb2c [ 15.090864][ T1] __irq_set_handler+0x74/0x114 [ 15.090881][ T1] irq_set_chip_and_handler_name+0x44/0x58 [ 15.090900][ T1] gpiochip_irq_map+0x210/0x644 Signed-off-by: Schspa Shi Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij Acked-by: Doug Berger Acked-by: Serge Semin Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-amdpt.c | 10 ++++----- drivers/gpio/gpio-brcmstb.c | 12 +++++------ drivers/gpio/gpio-cadence.c | 12 +++++------ drivers/gpio/gpio-dwapb.c | 36 +++++++++++++++---------------- drivers/gpio/gpio-grgpio.c | 30 +++++++++++++------------- drivers/gpio/gpio-hlwd.c | 18 ++++++++-------- drivers/gpio/gpio-idt3243x.c | 12 +++++------ drivers/gpio/gpio-ixp4xx.c | 4 ++-- drivers/gpio/gpio-loongson1.c | 8 +++---- drivers/gpio/gpio-menz127.c | 8 +++---- drivers/gpio/gpio-mlxbf2.c | 18 ++++++++-------- drivers/gpio/gpio-mmio.c | 22 +++++++++---------- drivers/gpio/gpio-sifive.c | 12 +++++------ drivers/gpio/gpio-tb10x.c | 4 ++-- drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c | 8 +++---- include/linux/gpio/driver.h | 2 +- 16 files changed, 108 insertions(+), 108 deletions(-) (limited to 'include/linux/gpio') diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c index 8cfb353c3abb..07c6d090058d 100644 --- a/drivers/gpio/gpio-amdpt.c +++ b/drivers/gpio/gpio-amdpt.c @@ -36,19 +36,19 @@ static int pt_gpio_request(struct gpio_chip *gc, unsigned offset) dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset); - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); if (using_pins & BIT(offset)) { dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n", offset); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return -EINVAL; } writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; } @@ -59,13 +59,13 @@ static void pt_gpio_free(struct gpio_chip *gc, unsigned offset) unsigned long flags; u32 using_pins; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG); using_pins &= ~BIT(offset); writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset); } diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 74ef89248867..6b7439b44690 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -92,9 +92,9 @@ brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank) unsigned long status; unsigned long flags; - spin_lock_irqsave(&bank->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&bank->gc.bgpio_lock, flags); status = __brcmstb_gpio_get_active_irqs(bank); - spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags); return status; } @@ -114,14 +114,14 @@ static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank, u32 imask; unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); imask = gc->read_reg(priv->reg_base + GIO_MASK(bank->id)); if (enable) imask |= mask; else imask &= ~mask; gc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) @@ -204,7 +204,7 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - spin_lock_irqsave(&bank->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&bank->gc.bgpio_lock, flags); iedge_config = bank->gc.read_reg(priv->reg_base + GIO_EC(bank->id)) & ~mask; @@ -220,7 +220,7 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type) bank->gc.write_reg(priv->reg_base + GIO_LEVEL(bank->id), ilevel | level); - spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags); return 0; } diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c index 562f8f7e7d1f..137aea49ba02 100644 --- a/drivers/gpio/gpio-cadence.c +++ b/drivers/gpio/gpio-cadence.c @@ -41,12 +41,12 @@ static int cdns_gpio_request(struct gpio_chip *chip, unsigned int offset) struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip); unsigned long flags; - spin_lock_irqsave(&chip->bgpio_lock, flags); + raw_spin_lock_irqsave(&chip->bgpio_lock, flags); iowrite32(ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE) & ~BIT(offset), cgpio->regs + CDNS_GPIO_BYPASS_MODE); - spin_unlock_irqrestore(&chip->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags); return 0; } @@ -55,13 +55,13 @@ static void cdns_gpio_free(struct gpio_chip *chip, unsigned int offset) struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip); unsigned long flags; - spin_lock_irqsave(&chip->bgpio_lock, flags); + raw_spin_lock_irqsave(&chip->bgpio_lock, flags); iowrite32(ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE) | (BIT(offset) & cgpio->bypass_orig), cgpio->regs + CDNS_GPIO_BYPASS_MODE); - spin_unlock_irqrestore(&chip->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags); } static void cdns_gpio_irq_mask(struct irq_data *d) @@ -90,7 +90,7 @@ static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type) u32 mask = BIT(d->hwirq); int ret = 0; - spin_lock_irqsave(&chip->bgpio_lock, flags); + raw_spin_lock_irqsave(&chip->bgpio_lock, flags); int_value = ioread32(cgpio->regs + CDNS_GPIO_IRQ_VALUE) & ~mask; int_type = ioread32(cgpio->regs + CDNS_GPIO_IRQ_TYPE) & ~mask; @@ -115,7 +115,7 @@ static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type) iowrite32(int_type, cgpio->regs + CDNS_GPIO_IRQ_TYPE); err_irq_type: - spin_unlock_irqrestore(&chip->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags); return ret; } diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index b0f3aca61974..7130195da48d 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -243,9 +243,9 @@ static void dwapb_irq_ack(struct irq_data *d) u32 val = BIT(irqd_to_hwirq(d)); unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); dwapb_write(gpio, GPIO_PORTA_EOI, val); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void dwapb_irq_mask(struct irq_data *d) @@ -255,10 +255,10 @@ static void dwapb_irq_mask(struct irq_data *d) unsigned long flags; u32 val; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); val = dwapb_read(gpio, GPIO_INTMASK) | BIT(irqd_to_hwirq(d)); dwapb_write(gpio, GPIO_INTMASK, val); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void dwapb_irq_unmask(struct irq_data *d) @@ -268,10 +268,10 @@ static void dwapb_irq_unmask(struct irq_data *d) unsigned long flags; u32 val; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(irqd_to_hwirq(d)); dwapb_write(gpio, GPIO_INTMASK, val); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void dwapb_irq_enable(struct irq_data *d) @@ -281,11 +281,11 @@ static void dwapb_irq_enable(struct irq_data *d) unsigned long flags; u32 val; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); val = dwapb_read(gpio, GPIO_INTEN); val |= BIT(irqd_to_hwirq(d)); dwapb_write(gpio, GPIO_INTEN, val); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void dwapb_irq_disable(struct irq_data *d) @@ -295,11 +295,11 @@ static void dwapb_irq_disable(struct irq_data *d) unsigned long flags; u32 val; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); val = dwapb_read(gpio, GPIO_INTEN); val &= ~BIT(irqd_to_hwirq(d)); dwapb_write(gpio, GPIO_INTEN, val); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static int dwapb_irq_set_type(struct irq_data *d, u32 type) @@ -309,7 +309,7 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type) irq_hw_number_t bit = irqd_to_hwirq(d); unsigned long level, polarity, flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL); polarity = dwapb_read(gpio, GPIO_INT_POLARITY); @@ -344,7 +344,7 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type) dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level); if (type != IRQ_TYPE_EDGE_BOTH) dwapb_write(gpio, GPIO_INT_POLARITY, polarity); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; } @@ -374,7 +374,7 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc, unsigned long flags, val_deb; unsigned long mask = BIT(offset); - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE); if (debounce) @@ -383,7 +383,7 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc, val_deb &= ~mask; dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; } @@ -738,7 +738,7 @@ static int dwapb_gpio_suspend(struct device *dev) unsigned long flags; int i; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); for (i = 0; i < gpio->nr_ports; i++) { unsigned int offset; unsigned int idx = gpio->ports[i].idx; @@ -765,7 +765,7 @@ static int dwapb_gpio_suspend(struct device *dev) dwapb_write(gpio, GPIO_INTMASK, ~ctx->wake_en); } } - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks); @@ -785,7 +785,7 @@ static int dwapb_gpio_resume(struct device *dev) return err; } - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); for (i = 0; i < gpio->nr_ports; i++) { unsigned int offset; unsigned int idx = gpio->ports[i].idx; @@ -812,7 +812,7 @@ static int dwapb_gpio_resume(struct device *dev) dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff); } } - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; } diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 23d447e17a67..df563616f943 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -145,7 +145,7 @@ static int grgpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - spin_lock_irqsave(&priv->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags); ipol = priv->gc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask; iedge = priv->gc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask; @@ -153,7 +153,7 @@ static int grgpio_irq_set_type(struct irq_data *d, unsigned int type) priv->gc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol); priv->gc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge); - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); return 0; } @@ -164,11 +164,11 @@ static void grgpio_irq_mask(struct irq_data *d) int offset = d->hwirq; unsigned long flags; - spin_lock_irqsave(&priv->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags); grgpio_set_imask(priv, offset, 0); - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); } static void grgpio_irq_unmask(struct irq_data *d) @@ -177,11 +177,11 @@ static void grgpio_irq_unmask(struct irq_data *d) int offset = d->hwirq; unsigned long flags; - spin_lock_irqsave(&priv->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags); grgpio_set_imask(priv, offset, 1); - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); } static struct irq_chip grgpio_irq_chip = { @@ -199,7 +199,7 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev) int i; int match = 0; - spin_lock_irqsave(&priv->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags); /* * For each gpio line, call its interrupt handler if it its underlying @@ -215,7 +215,7 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev) } } - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); if (!match) dev_warn(priv->dev, "No gpio line matched irq %d\n", irq); @@ -247,13 +247,13 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, dev_dbg(priv->dev, "Mapping irq %d for gpio line %d\n", irq, offset); - spin_lock_irqsave(&priv->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags); /* Request underlying irq if not already requested */ lirq->irq = irq; uirq = &priv->uirqs[lirq->index]; if (uirq->refcnt == 0) { - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); ret = request_irq(uirq->uirq, grgpio_irq_handler, 0, dev_name(priv->dev), priv); if (ret) { @@ -262,11 +262,11 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, uirq->uirq); return ret; } - spin_lock_irqsave(&priv->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags); } uirq->refcnt++; - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); /* Setup irq */ irq_set_chip_data(irq, priv); @@ -290,7 +290,7 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_data(irq, NULL); - spin_lock_irqsave(&priv->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags); /* Free underlying irq if last user unmapped */ index = -1; @@ -309,13 +309,13 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) uirq = &priv->uirqs[lirq->index]; uirq->refcnt--; if (uirq->refcnt == 0) { - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); free_irq(uirq->uirq, priv); return; } } - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); } static const struct irq_domain_ops grgpio_irq_domain_ops = { diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c index 641719a96a1a..4e13e937f832 100644 --- a/drivers/gpio/gpio-hlwd.c +++ b/drivers/gpio/gpio-hlwd.c @@ -65,7 +65,7 @@ static void hlwd_gpio_irqhandler(struct irq_desc *desc) int hwirq; u32 emulated_pending; - spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); pending = ioread32be(hlwd->regs + HW_GPIOB_INTFLAG); pending &= ioread32be(hlwd->regs + HW_GPIOB_INTMASK); @@ -93,7 +93,7 @@ static void hlwd_gpio_irqhandler(struct irq_desc *desc) /* Mark emulated interrupts as pending */ pending |= rising | falling; } - spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); chained_irq_enter(chip, desc); @@ -118,11 +118,11 @@ static void hlwd_gpio_irq_mask(struct irq_data *data) unsigned long flags; u32 mask; - spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK); mask &= ~BIT(data->hwirq); iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK); - spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); } static void hlwd_gpio_irq_unmask(struct irq_data *data) @@ -132,11 +132,11 @@ static void hlwd_gpio_irq_unmask(struct irq_data *data) unsigned long flags; u32 mask; - spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK); mask |= BIT(data->hwirq); iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK); - spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); } static void hlwd_gpio_irq_enable(struct irq_data *data) @@ -173,7 +173,7 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) unsigned long flags; u32 level; - spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); hlwd->edge_emulation &= ~BIT(data->hwirq); @@ -194,11 +194,11 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) hlwd_gpio_irq_setup_emulation(hlwd, data->hwirq, flow_type); break; default: - spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); return -EINVAL; } - spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); return 0; } diff --git a/drivers/gpio/gpio-idt3243x.c b/drivers/gpio/gpio-idt3243x.c index 52b8b72ded77..1cafdf46f875 100644 --- a/drivers/gpio/gpio-idt3243x.c +++ b/drivers/gpio/gpio-idt3243x.c @@ -57,7 +57,7 @@ static int idt_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) if (sense == IRQ_TYPE_NONE || (sense & IRQ_TYPE_EDGE_BOTH)) return -EINVAL; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ilevel = readl(ctrl->gpio + IDT_GPIO_ILEVEL); if (sense & IRQ_TYPE_LEVEL_HIGH) @@ -68,7 +68,7 @@ static int idt_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) writel(ilevel, ctrl->gpio + IDT_GPIO_ILEVEL); irq_set_handler_locked(d, handle_level_irq); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; } @@ -86,12 +86,12 @@ static void idt_gpio_mask(struct irq_data *d) struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ctrl->mask_cache |= BIT(d->hwirq); writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void idt_gpio_unmask(struct irq_data *d) @@ -100,12 +100,12 @@ static void idt_gpio_unmask(struct irq_data *d) struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ctrl->mask_cache &= ~BIT(d->hwirq); writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static int idt_gpio_irq_init_hw(struct gpio_chip *gc) diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c index 1acda980d119..76ab9bd7d84b 100644 --- a/drivers/gpio/gpio-ixp4xx.c +++ b/drivers/gpio/gpio-ixp4xx.c @@ -126,7 +126,7 @@ static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type) int_reg = IXP4XX_REG_GPIT1; } - spin_lock_irqsave(&g->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&g->gc.bgpio_lock, flags); /* Clear the style for the appropriate pin */ val = __raw_readl(g->base + int_reg); @@ -145,7 +145,7 @@ static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type) val |= BIT(d->hwirq); __raw_writel(val, g->base + IXP4XX_REG_GPOE); - spin_unlock_irqrestore(&g->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&g->gc.bgpio_lock, flags); /* This parent only accept level high (asserted) */ return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH); diff --git a/drivers/gpio/gpio-loongson1.c b/drivers/gpio/gpio-loongson1.c index 1b1ee94eeab4..5d90b3bc5a25 100644 --- a/drivers/gpio/gpio-loongson1.c +++ b/drivers/gpio/gpio-loongson1.c @@ -25,10 +25,10 @@ static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset) { unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | BIT(offset), gpio_reg_base + GPIO_CFG); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; } @@ -37,10 +37,10 @@ static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset) { unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~BIT(offset), gpio_reg_base + GPIO_CFG); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static int ls1x_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c index 1e21c661d79d..a035a9bcb57c 100644 --- a/drivers/gpio/gpio-menz127.c +++ b/drivers/gpio/gpio-menz127.c @@ -64,7 +64,7 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio, debounce /= 50; } - spin_lock(&gc->bgpio_lock); + raw_spin_lock(&gc->bgpio_lock); db_en = readl(priv->reg_base + MEN_Z127_DBER); @@ -79,7 +79,7 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio, writel(db_en, priv->reg_base + MEN_Z127_DBER); writel(db_cnt, priv->reg_base + GPIO_TO_DBCNT_REG(gpio)); - spin_unlock(&gc->bgpio_lock); + raw_spin_unlock(&gc->bgpio_lock); return 0; } @@ -91,7 +91,7 @@ static int men_z127_set_single_ended(struct gpio_chip *gc, struct men_z127_gpio *priv = gpiochip_get_data(gc); u32 od_en; - spin_lock(&gc->bgpio_lock); + raw_spin_lock(&gc->bgpio_lock); od_en = readl(priv->reg_base + MEN_Z127_ODER); if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN) @@ -101,7 +101,7 @@ static int men_z127_set_single_ended(struct gpio_chip *gc, od_en &= ~BIT(offset); writel(od_en, priv->reg_base + MEN_Z127_ODER); - spin_unlock(&gc->bgpio_lock); + raw_spin_unlock(&gc->bgpio_lock); return 0; } diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index 3d89912a05b8..64cb060d9d75 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -131,7 +131,7 @@ static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs) u32 arm_gpio_lock_val; mutex_lock(yu_arm_gpio_lock_param.lock); - spin_lock(&gs->gc.bgpio_lock); + raw_spin_lock(&gs->gc.bgpio_lock); arm_gpio_lock_val = readl(yu_arm_gpio_lock_param.io); @@ -139,7 +139,7 @@ static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs) * When lock active bit[31] is set, ModeX is write enabled */ if (YU_LOCK_ACTIVE_BIT(arm_gpio_lock_val)) { - spin_unlock(&gs->gc.bgpio_lock); + raw_spin_unlock(&gs->gc.bgpio_lock); mutex_unlock(yu_arm_gpio_lock_param.lock); return -EINVAL; } @@ -157,7 +157,7 @@ static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs) __releases(yu_arm_gpio_lock_param.lock) { writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io); - spin_unlock(&gs->gc.bgpio_lock); + raw_spin_unlock(&gs->gc.bgpio_lock); mutex_unlock(yu_arm_gpio_lock_param.lock); } @@ -237,7 +237,7 @@ static void mlxbf2_gpio_irq_enable(struct irq_data *irqd) unsigned long flags; u32 val; - spin_lock_irqsave(&gs->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags); val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); val |= BIT(offset); writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); @@ -245,7 +245,7 @@ static void mlxbf2_gpio_irq_enable(struct irq_data *irqd) val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); val |= BIT(offset); writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); } static void mlxbf2_gpio_irq_disable(struct irq_data *irqd) @@ -256,11 +256,11 @@ static void mlxbf2_gpio_irq_disable(struct irq_data *irqd) unsigned long flags; u32 val; - spin_lock_irqsave(&gs->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags); val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); val &= ~BIT(offset); writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); } static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr) @@ -307,7 +307,7 @@ mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) return -EINVAL; } - spin_lock_irqsave(&gs->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags); if (fall) { val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); val |= BIT(offset); @@ -319,7 +319,7 @@ mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) val |= BIT(offset); writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); } - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); return 0; } diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index c335a0309ba3..d9dff3dc92ae 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -220,7 +220,7 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) unsigned long mask = bgpio_line2mask(gc, gpio); unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); if (val) gc->bgpio_data |= mask; @@ -229,7 +229,7 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) gc->write_reg(gc->reg_dat, gc->bgpio_data); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, @@ -248,7 +248,7 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) unsigned long mask = bgpio_line2mask(gc, gpio); unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); if (val) gc->bgpio_data |= mask; @@ -257,7 +257,7 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) gc->write_reg(gc->reg_set, gc->bgpio_data); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void bgpio_multiple_get_masks(struct gpio_chip *gc, @@ -286,7 +286,7 @@ static void bgpio_set_multiple_single_reg(struct gpio_chip *gc, unsigned long flags; unsigned long set_mask, clear_mask; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); @@ -295,7 +295,7 @@ static void bgpio_set_multiple_single_reg(struct gpio_chip *gc, gc->write_reg(reg, gc->bgpio_data); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, @@ -347,7 +347,7 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); @@ -356,7 +356,7 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) if (gc->reg_dir_out) gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; } @@ -387,7 +387,7 @@ static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); gc->bgpio_dir |= bgpio_line2mask(gc, gpio); @@ -396,7 +396,7 @@ static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) if (gc->reg_dir_out) gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, @@ -610,7 +610,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev, if (gc->bgpio_bits > BITS_PER_LONG) return -EINVAL; - spin_lock_init(&gc->bgpio_lock); + raw_spin_lock_init(&gc->bgpio_lock); gc->parent = dev; gc->label = dev_name(dev); gc->base = -1; diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c index 7d82388b4ab7..03b8c4de2e91 100644 --- a/drivers/gpio/gpio-sifive.c +++ b/drivers/gpio/gpio-sifive.c @@ -44,7 +44,7 @@ static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset) unsigned long flags; unsigned int trigger; - spin_lock_irqsave(&chip->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&chip->gc.bgpio_lock, flags); trigger = (chip->irq_state & BIT(offset)) ? chip->trigger[offset] : 0; regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset), (trigger & IRQ_TYPE_EDGE_RISING) ? BIT(offset) : 0); @@ -54,7 +54,7 @@ static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset) (trigger & IRQ_TYPE_LEVEL_HIGH) ? BIT(offset) : 0); regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset), (trigger & IRQ_TYPE_LEVEL_LOW) ? BIT(offset) : 0); - spin_unlock_irqrestore(&chip->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&chip->gc.bgpio_lock, flags); } static int sifive_gpio_irq_set_type(struct irq_data *d, unsigned int trigger) @@ -84,13 +84,13 @@ static void sifive_gpio_irq_enable(struct irq_data *d) /* Switch to input */ gc->direction_input(gc, offset); - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); /* Clear any sticky pending interrupts */ regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit); regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit); regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit); regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); /* Enable interrupts */ assign_bit(offset, &chip->irq_state, 1); @@ -116,13 +116,13 @@ static void sifive_gpio_irq_eoi(struct irq_data *d) u32 bit = BIT(offset); unsigned long flags; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); /* Clear all pending interrupts */ regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit); regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit); regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit); regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); irq_chip_eoi_parent(d); } diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index 718a508d3b2f..de6afa3f9716 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -62,14 +62,14 @@ static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs, u32 r; unsigned long flags; - spin_lock_irqsave(&gpio->gc.bgpio_lock, flags); + raw_spin_lock_irqsave(&gpio->gc.bgpio_lock, flags); r = tb10x_reg_read(gpio, offs); r = (r & ~mask) | (val & mask); tb10x_reg_write(gpio, offs, r); - spin_unlock_irqrestore(&gpio->gc.bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gpio->gc.bgpio_lock, flags); } static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index 9557fac5d11c..b2a0f11a658b 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -104,12 +104,12 @@ static void npcm_gpio_set(struct gpio_chip *gc, void __iomem *reg, unsigned long flags; unsigned long val; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); val = ioread32(reg) | pinmask; iowrite32(val, reg); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void npcm_gpio_clr(struct gpio_chip *gc, void __iomem *reg, @@ -118,12 +118,12 @@ static void npcm_gpio_clr(struct gpio_chip *gc, void __iomem *reg, unsigned long flags; unsigned long val; - spin_lock_irqsave(&gc->bgpio_lock, flags); + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); val = ioread32(reg) & ~pinmask; iowrite32(val, reg); - spin_unlock_irqrestore(&gc->bgpio_lock, flags); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void npcmgpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 98c93510640e..991d374dcf71 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -436,7 +436,7 @@ struct gpio_chip { void __iomem *reg_dir_in; bool bgpio_dir_unreadable; int bgpio_bits; - spinlock_t bgpio_lock; + raw_spinlock_t bgpio_lock; unsigned long bgpio_data; unsigned long bgpio_dir; #endif /* CONFIG_GPIO_GENERIC */ -- cgit v1.2.3 From 42112dd77b74220e6a1f4a71bb51ca3f583d3842 Mon Sep 17 00:00:00 2001 From: Dipen Patel Date: Fri, 22 Apr 2022 13:52:16 -0700 Subject: gpiolib: Add HTE support Some GPIO chip can provide hardware timestamp support on its GPIO lines , in order to support that, additional API needs to be added which can talk to both GPIO chip and HTE (hardware timestamping engine) providers if there is any dependencies. This patch introduces optional hooks to enable and disable hardware timestamping related features in the GPIO controller chip. Signed-off-by: Dipen Patel Reviewed-by: Linus Walleij Reported-by: kernel test robot Signed-off-by: Thierry Reding --- drivers/gpio/gpiolib.c | 58 +++++++++++++++++++++++++++++++++++++++++++ drivers/gpio/gpiolib.h | 1 + include/linux/gpio/consumer.h | 16 ++++++++++-- include/linux/gpio/driver.h | 10 ++++++++ 4 files changed, 83 insertions(+), 2 deletions(-) (limited to 'include/linux/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e59884cc12a7..60cd7cc33647 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2434,6 +2434,64 @@ set_output_flag: } EXPORT_SYMBOL_GPL(gpiod_direction_output); +/** + * gpiod_enable_hw_timestamp_ns - Enable hardware timestamp in nanoseconds. + * + * @desc: GPIO to enable. + * @flags: Flags related to GPIO edge. + * + * Return 0 in case of success, else negative error code. + */ +int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) +{ + int ret = 0; + struct gpio_chip *gc; + + VALIDATE_DESC(desc); + + gc = desc->gdev->chip; + if (!gc->en_hw_timestamp) { + gpiod_warn(desc, "%s: hw ts not supported\n", __func__); + return -ENOTSUPP; + } + + ret = gc->en_hw_timestamp(gc, gpio_chip_hwgpio(desc), flags); + if (ret) + gpiod_warn(desc, "%s: hw ts request failed\n", __func__); + + return ret; +} +EXPORT_SYMBOL_GPL(gpiod_enable_hw_timestamp_ns); + +/** + * gpiod_disable_hw_timestamp_ns - Disable hardware timestamp. + * + * @desc: GPIO to disable. + * @flags: Flags related to GPIO edge, same value as used during enable call. + * + * Return 0 in case of success, else negative error code. + */ +int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) +{ + int ret = 0; + struct gpio_chip *gc; + + VALIDATE_DESC(desc); + + gc = desc->gdev->chip; + if (!gc->dis_hw_timestamp) { + gpiod_warn(desc, "%s: hw ts not supported\n", __func__); + return -ENOTSUPP; + } + + ret = gc->dis_hw_timestamp(gc, gpio_chip_hwgpio(desc), flags); + if (ret) + gpiod_warn(desc, "%s: hw ts release failed\n", __func__); + + return ret; +} +EXPORT_SYMBOL_GPL(gpiod_disable_hw_timestamp_ns); + /** * gpiod_set_config - sets @config for a GPIO * @desc: descriptor of the GPIO for which to set the configuration diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 06f3faa9fbef..29a7d39062b3 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -158,6 +158,7 @@ struct gpio_desc { #define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */ #define FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */ #define FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */ +#define FLAG_EVENT_CLOCK_HTE 19 /* GPIO CDEV reports hardware timestamps in events */ /* Connection label */ const char *label; diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index c3aa8b330e1c..7eaec081ae6c 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -109,6 +109,8 @@ 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); +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); /* Value get/set from non-sleeping context */ int gpiod_get_value(const struct gpio_desc *desc); @@ -350,8 +352,18 @@ static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value) WARN_ON(desc); return -ENOSYS; } - - +static inline int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, + unsigned long flags) +{ + WARN_ON(desc); + return -ENOSYS; +} +static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, + unsigned long flags) +{ + WARN_ON(desc); + return -ENOSYS; +} static inline int gpiod_get_value(const struct gpio_desc *desc) { /* GPIO can never have been requested */ diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 98c93510640e..0ce96ebdaa36 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -323,6 +323,10 @@ struct gpio_irq_chip { * @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 @@ -419,6 +423,12 @@ struct gpio_chip { 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; -- cgit v1.2.3 From 813c2aee51dd7d7d9092251851e33f66719513cc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 7 May 2022 14:33:31 +0200 Subject: ARM/pxa/mfd/power/sound: Switch Tosa to GPIO descriptors The Tosa device (Sharp SL-6000) has a mishmash driver set-up for the Toshiba TC6393xb MFD that includes a battery charger and touchscreen and has some kind of relationship to the SoC sound driver for the AC97 codec. Other devices define a chip like this but seem only half-implemented, not really handling battery charging etc. This patch switches the Toshiba MFD device to provide GPIO descriptors to the battery charger and SoC codec. As a result some descriptors need to be moved out of the Tosa boardfile and new one added: all SoC GPIO resources to these drivers now comes from the main boardfile, while the MFD provide GPIOs for its portions. As a result we can request one GPIO from our own GPIO chip and drop two hairy callbacks into the board file. This platform badly needs to have its drivers split up and converted to device tree probing to handle this quite complex relationship in an orderly manner. I just do my best in solving the GPIO descriptor part of the puzzle. Please don't ask me to fix everything that is wrong with these driver to todays standards, I am just trying to fix one aspect. I do try to use modern devres resource management and handle deferred probe using new functions where appropriate. Cc: Dmitry Eremin-Solenikov Cc: Dirk Opfer Cc: Robert Jarzmik Cc: Daniel Mack Cc: Haojian Zhuang Cc: Lee Jones Cc: Liam Girdwood Reviewed-by: Dmitry Baryshkov Acked-by: Mark Brown Acked-by: Sebastian Reichel Signed-off-by: Linus Walleij Signed-off-by: Arnd Bergmann --- arch/arm/mach-pxa/eseries.c | 2 - arch/arm/mach-pxa/include/mach/tosa.h | 18 ---- arch/arm/mach-pxa/tosa.c | 68 ++++---------- drivers/mfd/tc6393xb.c | 130 ++++++++++++++++++------- drivers/power/supply/tosa_battery.c | 172 +++++++++++++++++++++------------- include/linux/gpio/machine.h | 12 +++ include/linux/mfd/tc6393xb.h | 3 - sound/soc/pxa/tosa.c | 23 ++--- 8 files changed, 241 insertions(+), 187 deletions(-) (limited to 'include/linux/gpio') diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c index a8b6483ff665..1e9d6bbf4555 100644 --- a/arch/arm/mach-pxa/eseries.c +++ b/arch/arm/mach-pxa/eseries.c @@ -699,7 +699,6 @@ static struct tc6393xb_platform_data e750_tc6393xb_info = { .irq_base = IRQ_BOARD_START, .scr_pll2cr = 0x0cc1, .scr_gper = 0, - .gpio_base = -1, .suspend = &eseries_tmio_suspend, .resume = &eseries_tmio_resume, .enable = &eseries_tmio_enable, @@ -918,7 +917,6 @@ static struct tc6393xb_platform_data e800_tc6393xb_info = { .irq_base = IRQ_BOARD_START, .scr_pll2cr = 0x0cc1, .scr_gper = 0, - .gpio_base = -1, .suspend = &eseries_tmio_suspend, .resume = &eseries_tmio_resume, .enable = &eseries_tmio_enable, diff --git a/arch/arm/mach-pxa/include/mach/tosa.h b/arch/arm/mach-pxa/include/mach/tosa.h index 8bfaca3a8b64..3b3efa0a0e22 100644 --- a/arch/arm/mach-pxa/include/mach/tosa.h +++ b/arch/arm/mach-pxa/include/mach/tosa.h @@ -54,24 +54,6 @@ /* GPIO Direction 1 : output mode / 0:input mode */ #define TOSA_SCOOP_JC_IO_DIR (TOSA_SCOOP_JC_CARD_LIMIT_SEL) -/* - * TC6393XB GPIOs - */ -#define TOSA_TC6393XB_GPIO_BASE (PXA_NR_BUILTIN_GPIO + 2 * 12) - -#define TOSA_GPIO_TG_ON (TOSA_TC6393XB_GPIO_BASE + 0) -#define TOSA_GPIO_L_MUTE (TOSA_TC6393XB_GPIO_BASE + 1) -#define TOSA_GPIO_BL_C20MA (TOSA_TC6393XB_GPIO_BASE + 3) -#define TOSA_GPIO_CARD_VCC_ON (TOSA_TC6393XB_GPIO_BASE + 4) -#define TOSA_GPIO_CHARGE_OFF (TOSA_TC6393XB_GPIO_BASE + 6) -#define TOSA_GPIO_CHARGE_OFF_JC (TOSA_TC6393XB_GPIO_BASE + 7) -#define TOSA_GPIO_BAT0_V_ON (TOSA_TC6393XB_GPIO_BASE + 9) -#define TOSA_GPIO_BAT1_V_ON (TOSA_TC6393XB_GPIO_BASE + 10) -#define TOSA_GPIO_BU_CHRG_ON (TOSA_TC6393XB_GPIO_BASE + 11) -#define TOSA_GPIO_BAT_SW_ON (TOSA_TC6393XB_GPIO_BASE + 12) -#define TOSA_GPIO_BAT0_TH_ON (TOSA_TC6393XB_GPIO_BASE + 14) -#define TOSA_GPIO_BAT1_TH_ON (TOSA_TC6393XB_GPIO_BASE + 15) - /* * PXA GPIOs */ diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 9476ed0f55e9..ee0e38a8f96e 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -616,6 +616,22 @@ static struct resource tc6393xb_resources[] = { }, }; +static struct gpiod_lookup_table tosa_battery_gpio_table = { + .dev_id = "wm97xx-battery", + .table = { + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_BAT0_CRG, + "main battery full", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_BAT1_CRG, + "jacket battery full", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_BAT0_LOW, + "main battery low", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_BAT1_LOW, + "jacket battery low", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_JACKET_DETECT, + "jacket detect", GPIO_ACTIVE_HIGH), + { }, + }, +}; static int tosa_tc6393xb_enable(struct platform_device *dev) { @@ -709,31 +725,6 @@ static struct tmio_nand_data tosa_tc6393xb_nand_config = { .part_parsers = probes, }; -static int tosa_tc6393xb_setup(struct platform_device *dev) -{ - int rc; - - rc = gpio_request(TOSA_GPIO_CARD_VCC_ON, "CARD_VCC_ON"); - if (rc) - goto err_req; - - rc = gpio_direction_output(TOSA_GPIO_CARD_VCC_ON, 1); - if (rc) - goto err_dir; - - return rc; - -err_dir: - gpio_free(TOSA_GPIO_CARD_VCC_ON); -err_req: - return rc; -} - -static void tosa_tc6393xb_teardown(struct platform_device *dev) -{ - gpio_free(TOSA_GPIO_CARD_VCC_ON); -} - #ifdef CONFIG_MFD_TC6393XB static struct fb_videomode tosa_tc6393xb_lcd_mode[] = { { @@ -778,9 +769,6 @@ static struct tc6393xb_platform_data tosa_tc6393xb_data = { .scr_gper = 0x3300, .irq_base = IRQ_BOARD_START, - .gpio_base = TOSA_TC6393XB_GPIO_BASE, - .setup = tosa_tc6393xb_setup, - .teardown = tosa_tc6393xb_teardown, .enable = tosa_tc6393xb_enable, .disable = tosa_tc6393xb_disable, @@ -821,26 +809,6 @@ static struct pxa2xx_spi_controller pxa_ssp_master_info = { .num_chipselect = 1, }; -static struct gpiod_lookup_table tosa_lcd_gpio_table = { - .dev_id = "spi2.0", - .table = { - GPIO_LOOKUP("tc6393xb", - TOSA_GPIO_TG_ON - TOSA_TC6393XB_GPIO_BASE, - "tg #pwr", GPIO_ACTIVE_HIGH), - { }, - }, -}; - -static struct gpiod_lookup_table tosa_lcd_bl_gpio_table = { - .dev_id = "i2c-tosa-bl", - .table = { - GPIO_LOOKUP("tc6393xb", - TOSA_GPIO_BL_C20MA - TOSA_TC6393XB_GPIO_BASE, - "backlight", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static struct spi_board_info spi_board_info[] __initdata = { { .modalias = "tosa-lcd", @@ -943,6 +911,8 @@ static void __init tosa_init(void) /* enable batt_fault */ PMCR = 0x01; + gpiod_add_lookup_table(&tosa_battery_gpio_table); + gpiod_add_lookup_table(&tosa_mci_gpio_table); pxa_set_mci_info(&tosa_mci_platform_data); pxa_set_ficp_info(&tosa_ficp_platform_data); @@ -951,8 +921,6 @@ static void __init tosa_init(void) platform_scoop_config = &tosa_pcmcia_config; pxa2xx_set_spi_info(2, &pxa_ssp_master_info); - gpiod_add_lookup_table(&tosa_lcd_gpio_table); - gpiod_add_lookup_table(&tosa_lcd_bl_gpio_table); spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); clk_add_alias("CLK_CK3P6MI", tc6393xb_device.name, "GPIO11_CLK", NULL); diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 3d5b14c60e20..0be5731685b4 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #define SCR_REVID 0x08 /* b Revision ID */ @@ -87,8 +89,10 @@ struct tc6393xb { void __iomem *scr; + struct device *dev; struct gpio_chip gpio; + struct gpio_desc *vcc_on; struct clk *clk; /* 3,6 Mhz */ @@ -497,17 +501,93 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, return 0; } -static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) +/* + * TC6393XB GPIOs as used on TOSA, are the only user of this chip. + * GPIOs 2, 5, 8 and 13 are not connected. + */ +#define TOSA_GPIO_TG_ON 0 +#define TOSA_GPIO_L_MUTE 1 +#define TOSA_GPIO_BL_C20MA 3 +#define TOSA_GPIO_CARD_VCC_ON 4 +#define TOSA_GPIO_CHARGE_OFF 6 +#define TOSA_GPIO_CHARGE_OFF_JC 7 +#define TOSA_GPIO_BAT0_V_ON 9 +#define TOSA_GPIO_BAT1_V_ON 10 +#define TOSA_GPIO_BU_CHRG_ON 11 +#define TOSA_GPIO_BAT_SW_ON 12 +#define TOSA_GPIO_BAT0_TH_ON 14 +#define TOSA_GPIO_BAT1_TH_ON 15 + + +GPIO_LOOKUP_SINGLE(tosa_lcd_gpio_lookup, "spi2.0", "tc6393xb", + TOSA_GPIO_TG_ON, "tg #pwr", GPIO_ACTIVE_HIGH); + +GPIO_LOOKUP_SINGLE(tosa_lcd_bl_gpio_lookup, "i2c-tos-bl", "tc6393xb", + TOSA_GPIO_BL_C20MA, "backlight", GPIO_ACTIVE_HIGH); + +GPIO_LOOKUP_SINGLE(tosa_audio_gpio_lookup, "tosa-audio", "tc6393xb", + TOSA_GPIO_L_MUTE, NULL, GPIO_ACTIVE_HIGH); + +static struct gpiod_lookup_table tosa_battery_gpio_lookup = { + .dev_id = "wm97xx-battery", + .table = { + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_CHARGE_OFF, + "main charge off", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_CHARGE_OFF_JC, + "jacket charge off", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT0_V_ON, + "main battery", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT1_V_ON, + "jacket battery", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BU_CHRG_ON, + "backup battery", GPIO_ACTIVE_HIGH), + /* BAT1 and BAT0 thermistors appear to be swapped */ + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT1_TH_ON, + "main battery temp", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT0_TH_ON, + "jacket battery temp", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT_SW_ON, + "battery switch", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table *tc6393xb_gpio_lookups[] = { + &tosa_lcd_gpio_lookup, + &tosa_lcd_bl_gpio_lookup, + &tosa_audio_gpio_lookup, + &tosa_battery_gpio_lookup, +}; + +static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb) { - tc6393xb->gpio.label = "tc6393xb"; - tc6393xb->gpio.base = gpio_base; - tc6393xb->gpio.ngpio = 16; - tc6393xb->gpio.set = tc6393xb_gpio_set; - tc6393xb->gpio.get = tc6393xb_gpio_get; - tc6393xb->gpio.direction_input = tc6393xb_gpio_direction_input; - tc6393xb->gpio.direction_output = tc6393xb_gpio_direction_output; - - return gpiochip_add_data(&tc6393xb->gpio, tc6393xb); + struct gpio_chip *gc = &tc6393xb->gpio; + struct device *dev = tc6393xb->dev; + int ret; + + gc->label = "tc6393xb"; + gc->base = -1; /* Dynamic allocation */ + gc->ngpio = 16; + gc->set = tc6393xb_gpio_set; + gc->get = tc6393xb_gpio_get; + gc->direction_input = tc6393xb_gpio_direction_input; + gc->direction_output = tc6393xb_gpio_direction_output; + + ret = devm_gpiochip_add_data(dev, gc, tc6393xb); + if (ret) + return dev_err_probe(dev, ret, "failed to add GPIO chip\n"); + + /* Register descriptor look-ups for consumers */ + gpiod_add_lookup_tables(tc6393xb_gpio_lookups, ARRAY_SIZE(tc6393xb_gpio_lookups)); + + /* Request some of our own GPIOs */ + tc6393xb->vcc_on = gpiochip_request_own_desc(gc, TOSA_GPIO_CARD_VCC_ON, "VCC ON", + GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH); + if (IS_ERR(tc6393xb->vcc_on)) + return dev_err_probe(dev, PTR_ERR(tc6393xb->vcc_on), + "failed to request VCC ON GPIO\n"); + + return 0; } /*--------------------------------------------------------------------------*/ @@ -617,6 +697,7 @@ static int tc6393xb_probe(struct platform_device *dev) ret = -ENOMEM; goto err_kzalloc; } + tc6393xb->dev = &dev->dev; raw_spin_lock_init(&tc6393xb->lock); @@ -676,22 +757,12 @@ static int tc6393xb_probe(struct platform_device *dev) tmio_ioread8(tc6393xb->scr + SCR_REVID), (unsigned long) iomem->start, tc6393xb->irq); - tc6393xb->gpio.base = -1; - - if (tcpd->gpio_base >= 0) { - ret = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); - if (ret) - goto err_gpio_add; - } + ret = tc6393xb_register_gpio(tc6393xb); + if (ret) + goto err_gpio_add; tc6393xb_attach_irq(dev); - if (tcpd->setup) { - ret = tcpd->setup(dev); - if (ret) - goto err_setup; - } - tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data; tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size = sizeof(*tcpd->nand_data); @@ -705,15 +776,8 @@ static int tc6393xb_probe(struct platform_device *dev) if (!ret) return 0; - if (tcpd->teardown) - tcpd->teardown(dev); - -err_setup: tc6393xb_detach_irq(dev); - err_gpio_add: - if (tc6393xb->gpio.base != -1) - gpiochip_remove(&tc6393xb->gpio); tcpd->disable(dev); err_enable: clk_disable_unprepare(tc6393xb->clk); @@ -738,14 +802,8 @@ static int tc6393xb_remove(struct platform_device *dev) mfd_remove_devices(&dev->dev); - if (tcpd->teardown) - tcpd->teardown(dev); - tc6393xb_detach_irq(dev); - if (tc6393xb->gpio.base != -1) - gpiochip_remove(&tc6393xb->gpio); - ret = tcpd->disable(dev); clk_disable_unprepare(tc6393xb->clk); iounmap(tc6393xb->scr); diff --git a/drivers/power/supply/tosa_battery.c b/drivers/power/supply/tosa_battery.c index 32cc31cd4761..73d4aca4c386 100644 --- a/drivers/power/supply/tosa_battery.c +++ b/drivers/power/supply/tosa_battery.c @@ -12,10 +12,9 @@ #include #include #include -#include +#include #include -#include static DEFINE_MUTEX(bat_lock); /* protects gpio pins */ static struct work_struct bat_work; @@ -28,22 +27,23 @@ struct tosa_bat { struct mutex work_lock; /* protects data */ bool (*is_present)(struct tosa_bat *bat); - int gpio_full; - int gpio_charge_off; + struct gpio_desc *gpiod_full; + struct gpio_desc *gpiod_charge_off; int technology; - int gpio_bat; + struct gpio_desc *gpiod_bat; int adc_bat; int adc_bat_divider; int bat_max; int bat_min; - int gpio_temp; + struct gpio_desc *gpiod_temp; int adc_temp; int adc_temp_divider; }; +static struct gpio_desc *jacket_detect; static struct tosa_bat tosa_bat_main; static struct tosa_bat tosa_bat_jacket; @@ -51,15 +51,15 @@ static unsigned long tosa_read_bat(struct tosa_bat *bat) { unsigned long value = 0; - if (bat->gpio_bat < 0 || bat->adc_bat < 0) + if (!bat->gpiod_bat || bat->adc_bat < 0) return 0; mutex_lock(&bat_lock); - gpio_set_value(bat->gpio_bat, 1); + gpiod_set_value(bat->gpiod_bat, 1); msleep(5); value = wm97xx_read_aux_adc(dev_get_drvdata(bat->psy->dev.parent), bat->adc_bat); - gpio_set_value(bat->gpio_bat, 0); + gpiod_set_value(bat->gpiod_bat, 0); mutex_unlock(&bat_lock); value = value * 1000000 / bat->adc_bat_divider; @@ -71,15 +71,15 @@ static unsigned long tosa_read_temp(struct tosa_bat *bat) { unsigned long value = 0; - if (bat->gpio_temp < 0 || bat->adc_temp < 0) + if (!bat->gpiod_temp || bat->adc_temp < 0) return 0; mutex_lock(&bat_lock); - gpio_set_value(bat->gpio_temp, 1); + gpiod_set_value(bat->gpiod_temp, 1); msleep(5); value = wm97xx_read_aux_adc(dev_get_drvdata(bat->psy->dev.parent), bat->adc_temp); - gpio_set_value(bat->gpio_temp, 0); + gpiod_set_value(bat->gpiod_temp, 0); mutex_unlock(&bat_lock); value = value * 10000 / bat->adc_temp_divider; @@ -136,7 +136,7 @@ static int tosa_bat_get_property(struct power_supply *psy, static bool tosa_jacket_bat_is_present(struct tosa_bat *bat) { - return gpio_get_value(TOSA_GPIO_JACKET_DETECT) == 0; + return gpiod_get_value(jacket_detect) == 0; } static void tosa_bat_external_power_changed(struct power_supply *psy) @@ -166,23 +166,23 @@ static void tosa_bat_update(struct tosa_bat *bat) bat->full_chrg = -1; } else if (power_supply_am_i_supplied(psy)) { if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) { - gpio_set_value(bat->gpio_charge_off, 0); + gpiod_set_value(bat->gpiod_charge_off, 0); mdelay(15); } - if (gpio_get_value(bat->gpio_full)) { + if (gpiod_get_value(bat->gpiod_full)) { if (old == POWER_SUPPLY_STATUS_CHARGING || bat->full_chrg == -1) bat->full_chrg = tosa_read_bat(bat); - gpio_set_value(bat->gpio_charge_off, 1); + gpiod_set_value(bat->gpiod_charge_off, 1); bat->status = POWER_SUPPLY_STATUS_FULL; } else { - gpio_set_value(bat->gpio_charge_off, 0); + gpiod_set_value(bat->gpiod_charge_off, 0); bat->status = POWER_SUPPLY_STATUS_CHARGING; } } else { - gpio_set_value(bat->gpio_charge_off, 1); + gpiod_set_value(bat->gpiod_charge_off, 1); bat->status = POWER_SUPPLY_STATUS_DISCHARGING; } @@ -251,18 +251,18 @@ static struct tosa_bat tosa_bat_main = { .full_chrg = -1, .psy = NULL, - .gpio_full = TOSA_GPIO_BAT0_CRG, - .gpio_charge_off = TOSA_GPIO_CHARGE_OFF, + .gpiod_full = NULL, + .gpiod_charge_off = NULL, .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, - .gpio_bat = TOSA_GPIO_BAT0_V_ON, + .gpiod_bat = NULL, .adc_bat = WM97XX_AUX_ID3, .adc_bat_divider = 414, .bat_max = 4310000, .bat_min = 1551 * 1000000 / 414, - .gpio_temp = TOSA_GPIO_BAT1_TH_ON, + .gpiod_temp = NULL, .adc_temp = WM97XX_AUX_ID2, .adc_temp_divider = 10000, }; @@ -273,18 +273,18 @@ static struct tosa_bat tosa_bat_jacket = { .psy = NULL, .is_present = tosa_jacket_bat_is_present, - .gpio_full = TOSA_GPIO_BAT1_CRG, - .gpio_charge_off = TOSA_GPIO_CHARGE_OFF_JC, + .gpiod_full = NULL, + .gpiod_charge_off = NULL, .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, - .gpio_bat = TOSA_GPIO_BAT1_V_ON, + .gpiod_bat = NULL, .adc_bat = WM97XX_AUX_ID3, .adc_bat_divider = 414, .bat_max = 4310000, .bat_min = 1551 * 1000000 / 414, - .gpio_temp = TOSA_GPIO_BAT0_TH_ON, + .gpiod_temp = NULL, .adc_temp = WM97XX_AUX_ID2, .adc_temp_divider = 10000, }; @@ -294,36 +294,20 @@ static struct tosa_bat tosa_bat_bu = { .full_chrg = -1, .psy = NULL, - .gpio_full = -1, - .gpio_charge_off = -1, + .gpiod_full = NULL, + .gpiod_charge_off = NULL, .technology = POWER_SUPPLY_TECHNOLOGY_LiMn, - .gpio_bat = TOSA_GPIO_BU_CHRG_ON, + .gpiod_bat = NULL, .adc_bat = WM97XX_AUX_ID4, .adc_bat_divider = 1266, - .gpio_temp = -1, + .gpiod_temp = NULL, .adc_temp = -1, .adc_temp_divider = -1, }; -static struct gpio tosa_bat_gpios[] = { - { TOSA_GPIO_CHARGE_OFF, GPIOF_OUT_INIT_HIGH, "main charge off" }, - { TOSA_GPIO_CHARGE_OFF_JC, GPIOF_OUT_INIT_HIGH, "jacket charge off" }, - { TOSA_GPIO_BAT_SW_ON, GPIOF_OUT_INIT_LOW, "battery switch" }, - { TOSA_GPIO_BAT0_V_ON, GPIOF_OUT_INIT_LOW, "main battery" }, - { TOSA_GPIO_BAT1_V_ON, GPIOF_OUT_INIT_LOW, "jacket battery" }, - { TOSA_GPIO_BAT1_TH_ON, GPIOF_OUT_INIT_LOW, "main battery temp" }, - { TOSA_GPIO_BAT0_TH_ON, GPIOF_OUT_INIT_LOW, "jacket battery temp" }, - { TOSA_GPIO_BU_CHRG_ON, GPIOF_OUT_INIT_LOW, "backup battery" }, - { TOSA_GPIO_BAT0_CRG, GPIOF_IN, "main battery full" }, - { TOSA_GPIO_BAT1_CRG, GPIOF_IN, "jacket battery full" }, - { TOSA_GPIO_BAT0_LOW, GPIOF_IN, "main battery low" }, - { TOSA_GPIO_BAT1_LOW, GPIOF_IN, "jacket battery low" }, - { TOSA_GPIO_JACKET_DETECT, GPIOF_IN, "jacket detect" }, -}; - #ifdef CONFIG_PM static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state) { @@ -343,19 +327,83 @@ static int tosa_bat_resume(struct platform_device *dev) #define tosa_bat_resume NULL #endif -static int tosa_bat_probe(struct platform_device *dev) +static int tosa_bat_probe(struct platform_device *pdev) { int ret; struct power_supply_config main_psy_cfg = {}, jacket_psy_cfg = {}, bu_psy_cfg = {}; + struct device *dev = &pdev->dev; + struct gpio_desc *dummy; if (!machine_is_tosa()) return -ENODEV; - ret = gpio_request_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios)); - if (ret) - return ret; + /* Main charging control GPIOs */ + tosa_bat_main.gpiod_charge_off = devm_gpiod_get(dev, "main charge off", GPIOD_OUT_HIGH); + if (IS_ERR(tosa_bat_main.gpiod_charge_off)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_main.gpiod_charge_off), + "no main charger GPIO\n"); + tosa_bat_jacket.gpiod_charge_off = devm_gpiod_get(dev, "jacket charge off", GPIOD_OUT_HIGH); + if (IS_ERR(tosa_bat_jacket.gpiod_charge_off)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_jacket.gpiod_charge_off), + "no jacket charger GPIO\n"); + + /* Per-battery output check (routes battery voltage to ADC) */ + tosa_bat_main.gpiod_bat = devm_gpiod_get(dev, "main battery", GPIOD_OUT_LOW); + if (IS_ERR(tosa_bat_main.gpiod_bat)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_main.gpiod_bat), + "no main battery GPIO\n"); + tosa_bat_jacket.gpiod_bat = devm_gpiod_get(dev, "jacket battery", GPIOD_OUT_LOW); + if (IS_ERR(tosa_bat_jacket.gpiod_bat)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_jacket.gpiod_bat), + "no jacket battery GPIO\n"); + tosa_bat_bu.gpiod_bat = devm_gpiod_get(dev, "backup battery", GPIOD_OUT_LOW); + if (IS_ERR(tosa_bat_bu.gpiod_bat)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_bu.gpiod_bat), + "no backup battery GPIO\n"); + + /* Battery full detect GPIOs (using PXA SoC GPIOs) */ + tosa_bat_main.gpiod_full = devm_gpiod_get(dev, "main battery full", GPIOD_IN); + if (IS_ERR(tosa_bat_main.gpiod_full)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_main.gpiod_full), + "no main battery full GPIO\n"); + tosa_bat_jacket.gpiod_full = devm_gpiod_get(dev, "jacket battery full", GPIOD_IN); + if (IS_ERR(tosa_bat_jacket.gpiod_full)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_jacket.gpiod_full), + "no jacket battery full GPIO\n"); + + /* Battery temperature GPIOs (routes thermistor voltage to ADC) */ + tosa_bat_main.gpiod_temp = devm_gpiod_get(dev, "main battery temp", GPIOD_OUT_LOW); + if (IS_ERR(tosa_bat_main.gpiod_temp)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_main.gpiod_temp), + "no main battery temp GPIO\n"); + tosa_bat_jacket.gpiod_temp = devm_gpiod_get(dev, "jacket battery temp", GPIOD_OUT_LOW); + if (IS_ERR(tosa_bat_jacket.gpiod_temp)) + return dev_err_probe(dev, PTR_ERR(tosa_bat_jacket.gpiod_temp), + "no jacket battery temp GPIO\n"); + + /* Jacket detect GPIO */ + jacket_detect = devm_gpiod_get(dev, "jacket detect", GPIOD_IN); + if (IS_ERR(jacket_detect)) + return dev_err_probe(dev, PTR_ERR(jacket_detect), + "no jacket detect GPIO\n"); + + /* Battery low indication GPIOs (not used, we just request them) */ + dummy = devm_gpiod_get(dev, "main battery low", GPIOD_IN); + if (IS_ERR(dummy)) + return dev_err_probe(dev, PTR_ERR(dummy), + "no main battery low GPIO\n"); + dummy = devm_gpiod_get(dev, "jacket battery low", GPIOD_IN); + if (IS_ERR(dummy)) + return dev_err_probe(dev, PTR_ERR(dummy), + "no jacket battery low GPIO\n"); + + /* Battery switch GPIO (not used just requested) */ + dummy = devm_gpiod_get(dev, "battery switch", GPIOD_OUT_LOW); + if (IS_ERR(dummy)) + return dev_err_probe(dev, PTR_ERR(dummy), + "no battery switch GPIO\n"); mutex_init(&tosa_bat_main.work_lock); mutex_init(&tosa_bat_jacket.work_lock); @@ -363,7 +411,7 @@ static int tosa_bat_probe(struct platform_device *dev) INIT_WORK(&bat_work, tosa_bat_work); main_psy_cfg.drv_data = &tosa_bat_main; - tosa_bat_main.psy = power_supply_register(&dev->dev, + tosa_bat_main.psy = power_supply_register(dev, &tosa_bat_main_desc, &main_psy_cfg); if (IS_ERR(tosa_bat_main.psy)) { @@ -372,7 +420,7 @@ static int tosa_bat_probe(struct platform_device *dev) } jacket_psy_cfg.drv_data = &tosa_bat_jacket; - tosa_bat_jacket.psy = power_supply_register(&dev->dev, + tosa_bat_jacket.psy = power_supply_register(dev, &tosa_bat_jacket_desc, &jacket_psy_cfg); if (IS_ERR(tosa_bat_jacket.psy)) { @@ -381,28 +429,28 @@ static int tosa_bat_probe(struct platform_device *dev) } bu_psy_cfg.drv_data = &tosa_bat_bu; - tosa_bat_bu.psy = power_supply_register(&dev->dev, &tosa_bat_bu_desc, + tosa_bat_bu.psy = power_supply_register(dev, &tosa_bat_bu_desc, &bu_psy_cfg); if (IS_ERR(tosa_bat_bu.psy)) { ret = PTR_ERR(tosa_bat_bu.psy); goto err_psy_reg_bu; } - ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), + ret = request_irq(gpiod_to_irq(tosa_bat_main.gpiod_full), tosa_bat_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "main full", &tosa_bat_main); if (ret) goto err_req_main; - ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), + ret = request_irq(gpiod_to_irq(tosa_bat_jacket.gpiod_full), tosa_bat_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "jacket full", &tosa_bat_jacket); if (ret) goto err_req_jacket; - ret = request_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), + ret = request_irq(gpiod_to_irq(jacket_detect), tosa_bat_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "jacket detect", &tosa_bat_jacket); @@ -411,9 +459,9 @@ static int tosa_bat_probe(struct platform_device *dev) return 0; } - free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket); + free_irq(gpiod_to_irq(tosa_bat_jacket.gpiod_full), &tosa_bat_jacket); err_req_jacket: - free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main); + free_irq(gpiod_to_irq(tosa_bat_main.gpiod_full), &tosa_bat_main); err_req_main: power_supply_unregister(tosa_bat_bu.psy); err_psy_reg_bu: @@ -425,15 +473,14 @@ err_psy_reg_main: /* see comment in tosa_bat_remove */ cancel_work_sync(&bat_work); - gpio_free_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios)); return ret; } static int tosa_bat_remove(struct platform_device *dev) { - free_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), &tosa_bat_jacket); - free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket); - free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main); + free_irq(gpiod_to_irq(jacket_detect), &tosa_bat_jacket); + free_irq(gpiod_to_irq(tosa_bat_jacket.gpiod_full), &tosa_bat_jacket); + free_irq(gpiod_to_irq(tosa_bat_main.gpiod_full), &tosa_bat_main); power_supply_unregister(tosa_bat_bu.psy); power_supply_unregister(tosa_bat_jacket.psy); @@ -445,7 +492,6 @@ static int tosa_bat_remove(struct platform_device *dev) * unregistered now. */ cancel_work_sync(&bat_work); - gpio_free_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios)); return 0; } diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h index 2647dd10b541..4d55da28e664 100644 --- a/include/linux/gpio/machine.h +++ b/include/linux/gpio/machine.h @@ -63,6 +63,18 @@ struct gpiod_hog { 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 */ diff --git a/include/linux/mfd/tc6393xb.h b/include/linux/mfd/tc6393xb.h index fcc8e74f0e8d..d336c541b7df 100644 --- a/include/linux/mfd/tc6393xb.h +++ b/include/linux/mfd/tc6393xb.h @@ -27,9 +27,6 @@ struct tc6393xb_platform_data { int (*resume)(struct platform_device *dev); int irq_base; /* base for subdevice irqs */ - int gpio_base; - int (*setup)(struct platform_device *dev); - void (*teardown)(struct platform_device *dev); struct tmio_nand_data *nand_data; struct tmio_fb_data *fb_data; diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 06226f9b863e..30f83cab0c32 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -16,14 +16,13 @@ #include #include #include -#include +#include #include #include #include #include -#include #include #define TOSA_HP 0 @@ -33,6 +32,7 @@ #define TOSA_SPK_ON 0 #define TOSA_SPK_OFF 1 +static struct gpio_desc *tosa_mute; static int tosa_jack_func; static int tosa_spk_func; @@ -128,7 +128,7 @@ static int tosa_set_spk(struct snd_kcontrol *kcontrol, static int tosa_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 : 0); + gpiod_set_value(tosa_mute, SND_SOC_DAPM_EVENT_ON(event) ? 1 : 0); return 0; } @@ -222,10 +222,11 @@ static int tosa_probe(struct platform_device *pdev) struct snd_soc_card *card = ⤩ int ret; - ret = gpio_request_one(TOSA_GPIO_L_MUTE, GPIOF_OUT_INIT_LOW, - "Headphone Jack"); - if (ret) - return ret; + tosa_mute = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW); + if (IS_ERR(tosa_mute)) + return dev_err_probe(&pdev->dev, PTR_ERR(tosa_mute), + "failed to get L_MUTE GPIO\n"); + gpiod_set_consumer_name(tosa_mute, "Headphone Jack"); card->dev = &pdev->dev; @@ -233,24 +234,16 @@ static int tosa_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - gpio_free(TOSA_GPIO_L_MUTE); } return ret; } -static int tosa_remove(struct platform_device *pdev) -{ - gpio_free(TOSA_GPIO_L_MUTE); - return 0; -} - static struct platform_driver tosa_driver = { .driver = { .name = "tosa-audio", .pm = &snd_soc_pm_ops, }, .probe = tosa_probe, - .remove = tosa_remove, }; module_platform_driver(tosa_driver); -- cgit v1.2.3 From c7e1c443584ddd7facffca00e9e23b0d084e5bb3 Mon Sep 17 00:00:00 2001 From: Akira Yokosawa Date: Mon, 6 Jun 2022 13:44:24 +0900 Subject: gpio: Fix kernel-doc comments to nested union Commit 48ec13d36d3f ("gpio: Properly document parent data union") is supposed to have fixed a warning from "make htmldocs" regarding kernel-doc comments to union members. However, the same warning still remains [1]. Fix the issue by following the example found in section "Nested structs/unions" of Documentation/doc-guide/kernel-doc.rst. Signed-off-by: Akira Yokosawa Reported-by: Stephen Rothwell Fixes: 48ec13d36d3f ("gpio: Properly document parent data union") Link: https://lore.kernel.org/r/20220606093302.21febee3@canb.auug.org.au/ [1] Cc: Linus Walleij Cc: Bartosz Golaszewski Cc: Joey Gouly Cc: Marc Zyngier Tested-by: Stephen Rothwell Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Bartosz Golaszewski --- include/linux/gpio/driver.h | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'include/linux/gpio') diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index b1e0f1f8ee2e..54c3c6506503 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -167,21 +167,24 @@ struct gpio_irq_chip { */ irq_flow_handler_t parent_handler; - /** - * @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. - * - * @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. - */ 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; }; -- cgit v1.2.3