diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-24 20:02:48 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-24 20:02:48 -1000 |
| commit | 9628ee0c2219daaa6374b0c5f5a5c0d55e0e263b (patch) | |
| tree | 43c5168bdacd79bd2f2356d2902b82db4e5e877e | |
| parent | 44388c8f3e22b578c9089df53301ef7e53e7fb01 (diff) | |
| parent | dae739137441667d67fbfcc4d303a0ecc6618662 (diff) | |
Merge tag 'gpio-fixes-for-v7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio fixes from Bartosz Golaszewski:
- add ACPI quirks for Thinkpad L13 Gen 2a and Acer Nitro 16S AI to
ignore a wrong GPIO interrupt declaration
- add missing return value check of devm_gpiochip_add_data() to
gpio-lpc32xx
- don't set GPIOD_FLAG_IS_OUT from character device code as GPIO core
already does it where needed and it can lead to providing invalid
info to user-space on request errors
- don't report a bogus -ENOMEM for a line requested without a label
- propagate errors occurring when setting line values for pins for
which we emulate open-drain or open-source drive settings
- fix interrupt handling bugs in gpio-pca953x and gpio-davinci
- fix more memory leaks in GPIO core
- clear event clock flags from pins on GPIO release
* tag 'gpio-fixes-for-v7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
gpiolib: don't report -ENOMEM for a requested line without a label
gpiolib: Propagate emulated drive errors when setting arrays
gpio: pca953x: Handle direction register read errors in IRQ paths
gpio: pca953x: Preserve wakeup accounting on parent IRQ failure
gpio: davinci: Clear interrupt status in every bank on suspend
gpiolib: Free chip resources when allocating the label fails
gpiolib: cdev: don't set GPIOD_FLAG_IS_OUT
gpiolib: clear the event clock flags when a line is released
gpiolib: fix memory leak in gpiod_set_array_value_complex() EPERM error path
gpiolib: acpi: Ignore GPIO 11 interrupt on Acer Nitro 16S AI
gpio: lpc32xx: check devm_gpiochip_add_data() return value
gpiolib: acpi: Ignore GPIO 11 interrupt on ThinkPad L13 Gen 2a
| -rw-r--r-- | drivers/gpio/gpio-davinci.c | 6 | ||||
| -rw-r--r-- | drivers/gpio/gpio-lpc32xx.c | 9 | ||||
| -rw-r--r-- | drivers/gpio/gpio-pca953x.c | 21 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib-acpi-quirks.c | 31 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib-cdev.c | 5 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib.c | 32 |
6 files changed, 81 insertions, 23 deletions
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index cccbaea1dec2..fc2b9bef7efc 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -611,10 +611,10 @@ static void davinci_gpio_save_context(struct davinci_gpio_controller *chips, context->set_data = readl_relaxed(&g->set_data); context->set_rising = readl_relaxed(&g->set_rising); context->set_falling = readl_relaxed(&g->set_falling); - } - /* Clear all interrupt status registers */ - writel_relaxed(GENMASK(31, 0), &g->intstat); + /* Clear stale interrupt status for this bank. */ + writel_relaxed(GENMASK(31, 0), &g->intstat); + } } static void davinci_gpio_restore_context(struct davinci_gpio_controller *chips, diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 37fc54fc7385..7fb46262e18c 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -510,7 +510,7 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc, static int lpc32xx_gpio_probe(struct platform_device *pdev) { - int i; + int i, ret; void __iomem *reg_base; reg_base = devm_platform_ioremap_resource(pdev, 0); @@ -524,8 +524,11 @@ static int lpc32xx_gpio_probe(struct platform_device *pdev) lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3; lpc32xx_gpiochip[i].reg_base = reg_base; } - devm_gpiochip_add_data(&pdev->dev, &lpc32xx_gpiochip[i].chip, - &lpc32xx_gpiochip[i]); + ret = devm_gpiochip_add_data(&pdev->dev, &lpc32xx_gpiochip[i].chip, + &lpc32xx_gpiochip[i]); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to register gpio chip %d\n", i); } return 0; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index aac9ea7520b6..afec5ec23696 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -838,13 +838,18 @@ static int pca953x_irq_set_wake(struct irq_data *d, unsigned int on) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = gpiochip_get_data(gc); + int ret; + + ret = irq_set_irq_wake(chip->client->irq, on); + if (ret) + return ret; if (on) atomic_inc(&chip->wakeup_path); else atomic_dec(&chip->wakeup_path); - return irq_set_irq_wake(chip->client->irq, on); + return 0; } static void pca953x_irq_bus_lock(struct irq_data *d) @@ -862,6 +867,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) DECLARE_BITMAP(irq_mask, MAX_LINE); DECLARE_BITMAP(reg_direction, MAX_LINE); int level; + int ret; guard(mutex)(&chip->i2c_lock); @@ -880,7 +886,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) } /* Switch direction to input if needed */ - pca953x_read_regs(chip, chip->regs->direction, reg_direction); + ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction); + if (ret) + goto out; bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio); bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_high, gc->ngpio); @@ -890,6 +898,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio) pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level); +out: mutex_unlock(&chip->irq_lock); } @@ -984,7 +993,9 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin } /* Remove output pins from the equation */ - pca953x_read_regs(chip, chip->regs->direction, reg_direction); + ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction); + if (ret) + return false; bitmap_copy(old_stat, chip->irq_stat, gc->ngpio); @@ -1084,7 +1095,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) * interrupt. We have to rely on the previous read for * this purpose. */ - pca953x_read_regs(chip, chip->regs->direction, reg_direction); + ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction); + if (ret) + return ret; bitmap_and(chip->irq_stat, irq_stat, reg_direction, gc->ngpio); mutex_init(&chip->irq_lock); diff --git a/drivers/gpio/gpiolib-acpi-quirks.c b/drivers/gpio/gpiolib-acpi-quirks.c index 9a523871800d..3f89a87601c1 100644 --- a/drivers/gpio/gpiolib-acpi-quirks.c +++ b/drivers/gpio/gpiolib-acpi-quirks.c @@ -361,6 +361,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { }, { /* + * Same camera power enable on GPIO 11 as the Acer Nitro V 16S AI + * above. It also powers the internal microphones. + * Found in BIOS V1.53 + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Acer Nitro 16S AI"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_interrupt = "AMDI0030:00@11", + }, + }, + { + /* * Wakeup only works when keyboard backlight is turned off * https://gitlab.freedesktop.org/drm/amd/-/issues/4169 */ @@ -374,6 +388,23 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { }, { /* + * ACPI incorrectly declares GPIO 11 as an interrupt in _AEI, + * although the EC uses the pin to control the Caps Lock LED. + * Requesting the interrupt configures the pin as an input and + * prevents the LED from working. + * Found in BIOS R1QET54W (1.40). + * https://lore.kernel.org/linux-gpio/CAAUQFRPW-rbcZV-=qV1NMjF_358sdJTiGvQuRxRqAsehY+J9Qg@mail.gmail.com/ + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21AB"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_interrupt = "AMDI0030:00@11", + }, + }, + { + /* * Spurious wakeups from TP_ATTN# pin * Found in BIOS 5.35 * https://gitlab.freedesktop.org/drm/amd/-/issues/4482 diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index a30564d1525a..3f1f8c9acfc3 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -1231,11 +1231,6 @@ static void gpio_v2_line_config_flags_to_desc_flags(u64 lflags, assign_bit(GPIOD_FLAG_ACTIVE_LOW, &flags, lflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW); - if (lflags & GPIO_V2_LINE_FLAG_OUTPUT) - set_bit(GPIOD_FLAG_IS_OUT, &flags); - else if (lflags & GPIO_V2_LINE_FLAG_INPUT) - clear_bit(GPIOD_FLAG_IS_OUT, &flags); - assign_bit(GPIOD_FLAG_EDGE_RISING, &flags, lflags & GPIO_V2_LINE_FLAG_EDGE_RISING); assign_bit(GPIOD_FLAG_EDGE_FALLING, &flags, diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c880686f5fd7..fbdeda2f2787 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2648,10 +2648,13 @@ int gpiod_request_commit(struct gpio_desc *desc, const char *label) ret = desc_set_label(desc, label ? : "?"); if (ret) - goto out_clear_bit; + goto out_free_gpio; return 0; +out_free_gpio: + if (guard.gc->free) + guard.gc->free(guard.gc, offset); out_clear_bit: clear_bit(GPIOD_FLAG_REQUESTED, &desc->flags); return ret; @@ -2700,6 +2703,8 @@ void gpiod_free_commit(struct gpio_desc *desc) clear_bit(GPIOD_FLAG_BIAS_DISABLE, &flags); clear_bit(GPIOD_FLAG_EDGE_RISING, &flags); clear_bit(GPIOD_FLAG_EDGE_FALLING, &flags); + clear_bit(GPIOD_FLAG_EVENT_CLOCK_REALTIME, &flags); + clear_bit(GPIOD_FLAG_EVENT_CLOCK_HTE, &flags); clear_bit(GPIOD_FLAG_IS_HOGGED, &flags); #ifdef CONFIG_OF_DYNAMIC WRITE_ONCE(desc->hog, NULL); @@ -2737,6 +2742,7 @@ void gpiod_free(struct gpio_desc *desc) char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset) { struct gpio_desc *desc; + const char *name; char *label; desc = gpiochip_get_desc(gc, offset); @@ -2748,7 +2754,11 @@ char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset) guard(srcu)(&desc->gdev->desc_srcu); - label = kstrdup(gpiod_get_label(desc), GFP_KERNEL); + name = gpiod_get_label(desc); + if (!name) + return NULL; + + label = kstrdup(name, GFP_KERNEL); if (!label) return ERR_PTR(-ENOMEM); @@ -3863,7 +3873,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, unsigned long *value_bitmap) { struct gpio_chip *gc; - int i = 0, ret; + int i = 0, ret = 0; /* * Validate array_info against desc_array and its size. @@ -3941,8 +3951,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, int hwgpio = gpiod_hwgpio(desc); int value = test_bit(i, value_bitmap); - if (unlikely(!test_bit(GPIOD_FLAG_IS_OUT, &desc->flags))) - return -EPERM; + if (unlikely(!test_bit(GPIOD_FLAG_IS_OUT, &desc->flags))) { + ret = -EPERM; + goto cleanup_bitmap; + } /* * Pins applicable for fast input but not for @@ -3959,9 +3971,13 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, * open drain and open source outputs are set individually */ if (test_bit(GPIOD_FLAG_OPEN_DRAIN, &desc->flags) && !raw) { - gpio_set_open_drain_value_commit(desc, value); + ret = gpio_set_open_drain_value_commit(desc, value); + if (ret) + goto cleanup_bitmap; } else if (test_bit(GPIOD_FLAG_OPEN_SOURCE, &desc->flags) && !raw) { - gpio_set_open_source_value_commit(desc, value); + ret = gpio_set_open_source_value_commit(desc, value); + if (ret) + goto cleanup_bitmap; } else { __set_bit(hwgpio, mask); __assign_bit(hwgpio, bits, value); @@ -3975,10 +3991,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, } while ((i < array_size) && gpio_device_chip_cmp(desc_array[i]->gdev, guard.gc)); /* push collected bits to outputs */ - ret = 0; if (count != 0) ret = gpiochip_set_multiple(guard.gc, mask, bits); +cleanup_bitmap: if (mask != fastpath_mask) bitmap_free(mask); if (bits != fastpath_bits) |
