gpio fixes for v7.4-rc1

- 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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmrbHSMACgkQBZ0uy/82
 hMMEig//bCUhWF0A94cH7kCq4HBSm5to5wlBO8G08YRrwisca8sfV+RxwoT+uflW
 kgT4qvrip5PRxpA7V859fo9Fur+9Tfhf7euAPLsylF78bcnPynYVjxS9+ull6MOM
 UdHTn+kP8eVmRkD8btLD9GdU4UnTk4AZtVA8rr2a18YYxM1PvziAF5eP312tNqMm
 F/lks0qXLnSVkPiLyn4uCJ+Mn2I1lV4xRUBIIy67wOqDoWSh2eRMH11zBFBB0qUw
 Gw3mWo9b5utTd38tNtUj0r6kFmQ1J+WzwROwhF1AoQVKGveYHuhg1aaxmoNsHqF2
 HskMezPM4T3K3JZUOFFGDc1CUAQ43hQUvpEXi5JJ+U/OSN754zCuyrCE0hQwRevG
 8X53iCoUmqJBduE+m8BK6Hi1MWr3gf/kpeKqsWrcPuFegFuq3+i/wiA3gMsU8q3x
 EigbigPcfJoHqyMHAmJ7+OawHCoaP+lwp73rJmw7hb5a6gYeAX61Ppx0gc3jPmkE
 xrlnUo2zO7vtONlUHsvbf1Dqc4IbIV4PLXco/sG6dTTQ8AI+yuIl/BV7eSWdXPAh
 Nhv4IiBsNdKkyKTYrcco0V+X9o3XimqTgY5umGmznwI1DSl0QyNqy9Q3PIOP8WXN
 MFtijq48+6DuG6VXf4BHsabQDq+qBh0gn7io0v8zG1PQ9Fs1fJY=
 =UrAJ
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2026-10-24 20:02:48 -10:00
commit 9628ee0c22
6 changed files with 81 additions and 23 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -359,6 +359,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
.ignore_interrupt = "AMDI0030:00@11",
},
},
{
/*
* 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
@ -372,6 +386,23 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
.ignore_interrupt = "AMDI0030:00@8",
},
},
{
/*
* 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

View File

@ -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,

View File

@ -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)