diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-07-30 09:05:34 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-07-30 09:05:34 -0700 |
| commit | 110b5cdd5b72bcef01b8d4dfe45d922bdd16de0e (patch) | |
| tree | 4a3d727fa0a25b64e9ff957919cf9f819d6957af | |
| parent | b96890b3e5e0995a4bcf731bb9d6af2bbdf8ec42 (diff) | |
| parent | a02b8950d619123da64f69b70fe1dadef217dfe4 (diff) | |
Merge tag 'gpio-fixes-for-v7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio fixes from Bartosz Golaszewski:
- fix a memory leak in gpio-sloppy-logic-analyzer
- fix a regression in GPIO hog handling for hogs without direction
specified
- extend the critical section in IRQ handling in gpio-pca953x to cover
the reads from the direction register
- disable the interrupt on errors when restoring context in
gpio-pca953x
- apply the initial value when setting direction in gpio-by-pinctrl
- use raw spinlock for the register lock in gpio-pch to address locking
context issues
* tag 'gpio-fixes-for-v7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
gpio: pch: use raw_spinlock_t for the register lock
gpio: pca953x: fix cache_only and IRQ state on restore_context() failure
gpio: gpio-by-pinctrl: Apply initial value in direction output wrapper
gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock
gpiolib: tolerate gpio-hogs lacking a hogging state
gpio: sloppy-logic-analyzer: Fix memory leak in gpio_la_poll_probe()
| -rw-r--r-- | drivers/gpio/gpio-by-pinctrl.c | 18 | ||||
| -rw-r--r-- | drivers/gpio/gpio-pca953x.c | 34 | ||||
| -rw-r--r-- | drivers/gpio/gpio-pch.c | 28 | ||||
| -rw-r--r-- | drivers/gpio/gpio-sloppy-logic-analyzer.c | 10 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib.c | 13 |
5 files changed, 71 insertions, 32 deletions
diff --git a/drivers/gpio/gpio-by-pinctrl.c b/drivers/gpio/gpio-by-pinctrl.c index 7d7c48ce5163..fb8440acb31d 100644 --- a/drivers/gpio/gpio-by-pinctrl.c +++ b/drivers/gpio/gpio-by-pinctrl.c @@ -27,12 +27,6 @@ static int pin_control_gpio_get_direction(struct gpio_chip *gc, unsigned int off return GPIO_LINE_DIRECTION_IN; } -static int pin_control_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int val) -{ - return pinctrl_gpio_direction_output(chip, offset); -} - static int pin_control_gpio_get(struct gpio_chip *chip, unsigned int offset) { unsigned long config; @@ -55,6 +49,18 @@ static int pin_control_gpio_set(struct gpio_chip *chip, unsigned int offset, return pinctrl_gpio_set_config(chip, offset, config); } +static int pin_control_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int val) +{ + int ret; + + ret = pinctrl_gpio_direction_output(chip, offset); + if (ret) + return ret; + + return pin_control_gpio_set(chip, offset, val); +} + static int pin_control_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index f6b870b7b352..aac9ea7520b6 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -604,20 +604,28 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long * return 0; } -static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) +static int pca953x_gpio_direction_input_unlocked(struct gpio_chip *gc, + unsigned int off) { struct pca953x_chip *chip = gpiochip_get_data(gc); u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); u8 bit = pca953x_get_bit_mask(chip, off); - guard(mutex)(&chip->i2c_lock); - if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE) return regmap_update_bits(chip->regmap, dirreg, bit, 0); return regmap_update_bits(chip->regmap, dirreg, bit, bit); } +static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned int off) +{ + struct pca953x_chip *chip = gpiochip_get_data(gc); + + guard(mutex)(&chip->i2c_lock); + + return pca953x_gpio_direction_input_unlocked(gc, off); +} + static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { @@ -855,9 +863,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) DECLARE_BITMAP(reg_direction, MAX_LINE); int level; + guard(mutex)(&chip->i2c_lock); + if (chip->driver_data & PCA_PCAL) { DECLARE_BITMAP(latched_inputs, MAX_LINE); - guard(mutex)(&chip->i2c_lock); /* Enable latch on edge-triggered interrupt-enabled inputs */ bitmap_or(latched_inputs, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio); @@ -879,7 +888,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) /* Look for any newly setup interrupt */ for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio) - pca953x_gpio_direction_input(&chip->gpio_chip, level); + pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level); mutex_unlock(&chip->irq_lock); } @@ -1369,9 +1378,20 @@ static int pca953x_restore_context(struct pca953x_chip *chip) regcache_mark_dirty(chip->regmap); ret = pca953x_regcache_sync(chip); if (ret) - return ret; + goto err; + + ret = regcache_sync(chip->regmap); + if (ret) + goto err; + + return 0; - return regcache_sync(chip->regmap); +err: + if (chip->client->irq > 0) + disable_irq(chip->client->irq); + regcache_cache_only(chip->regmap, true); + + return ret; } static void pca953x_save_context(struct pca953x_chip *chip) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 4ffa0955a9e3..07a5617b314b 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -96,7 +96,7 @@ struct pch_gpio { struct pch_gpio_reg_data pch_gpio_reg; int irq_base; enum pch_type_t ioh; - spinlock_t spinlock; + raw_spinlock_t spinlock; }; static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) @@ -105,7 +105,7 @@ static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) struct pch_gpio *chip = gpiochip_get_data(gpio); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->po); if (val) reg_val |= BIT(nr); @@ -113,7 +113,7 @@ static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->po); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -133,7 +133,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, u32 reg_val; unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->po); if (val) @@ -147,7 +147,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, pm |= BIT(nr); iowrite32(pm, &chip->reg->pm); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -158,12 +158,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr) u32 pm; unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->pm); pm &= BIT(gpio_pins[chip->ioh]) - 1; pm &= ~BIT(nr); iowrite32(pm, &chip->reg->pm); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -265,7 +265,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) return 0; } - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); /* Set interrupt mode */ im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4)); @@ -277,7 +277,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) else if (type & IRQ_TYPE_EDGE_BOTH) irq_set_handler_locked(d, handle_edge_irq); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -374,7 +374,7 @@ static int pch_gpio_probe(struct pci_dev *pdev, chip->ioh = id->driver_data; chip->reg = chip->base; pci_set_drvdata(pdev, chip); - spin_lock_init(&chip->spinlock); + raw_spin_lock_init(&chip->spinlock); pch_gpio_setup(chip); ret = devm_gpiochip_add_data(dev, &chip->gpio, chip); @@ -407,9 +407,9 @@ static int pch_gpio_suspend(struct device *dev) struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); pch_gpio_save_reg_conf(chip); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -419,11 +419,11 @@ static int pch_gpio_resume(struct device *dev) struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); iowrite32(0x01, &chip->reg->reset); iowrite32(0x00, &chip->reg->reset); pch_gpio_restore_reg_conf(chip); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } diff --git a/drivers/gpio/gpio-sloppy-logic-analyzer.c b/drivers/gpio/gpio-sloppy-logic-analyzer.c index 2bbd308ca08e..aa23b5779802 100644 --- a/drivers/gpio/gpio-sloppy-logic-analyzer.c +++ b/drivers/gpio/gpio-sloppy-logic-analyzer.c @@ -160,6 +160,13 @@ static int fops_buf_size_get(void *data, u64 *val) return 0; } +static void fops_buf_release(void *data) +{ + struct gpio_la_poll_priv *priv = data; + + vfree(priv->blob.data); +} + static int fops_buf_size_set(void *data, u64 val) { struct gpio_la_poll_priv *priv = data; @@ -238,6 +245,9 @@ static int gpio_la_poll_probe(struct platform_device *pdev) return ret; fops_buf_size_set(priv, GPIO_LA_DEFAULT_BUF_SIZE); + ret = devm_add_action_or_reset(dev, fops_buf_release, priv); + if (ret) + return ret; priv->descs = devm_gpiod_get_array(dev, "probe", GPIOD_IN); if (IS_ERR(priv->descs)) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e5fb60111151..c433a095907f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -999,14 +999,17 @@ int gpiochip_add_hog(struct gpio_chip *gc, struct fwnode_handle *fwnode) if (ret < 0) return ret; - if (fwnode_property_present(fwnode, "input")) + if (fwnode_property_present(fwnode, "input")) { dflags |= GPIOD_IN; - else if (fwnode_property_present(fwnode, "output-low")) + } else if (fwnode_property_present(fwnode, "output-low")) { dflags |= GPIOD_OUT_LOW; - else if (fwnode_property_present(fwnode, "output-high")) + } else if (fwnode_property_present(fwnode, "output-high")) { dflags |= GPIOD_OUT_HIGH; - else - return -EINVAL; + } else { + gpiochip_warn(gc, "%pfwP: no hogging state specified, bailing out\n", + fwnode); + return 0; + } fwnode_property_read_string(fwnode, "line-name", &name); |
