Skip to content

Commit

Permalink
Merge tag 'gpio-fixes-for-v6.15-rc2' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/brgl/linux

Pull gpio fixes from Bartosz Golaszewski:

 - fix resource handling in gpio-tegra186

 - fix wakeup source leaks in gpio-mpc8xxx and gpio-zynq

 - fix minor issues with some GPIO OF quirks

 - deprecate GPIOD_FLAGS_BIT_NONEXCLUSIVE and devm_gpiod_unhinge()
   symbols and add a TODO task to track replacing them with a better
   solution

* tag 'gpio-fixes-for-v6.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpiolib: of: Move Atmel HSMCI quirk up out of the regulator comment
  gpiolib: of: Fix the choice for Ingenic NAND quirk
  gpio: zynq: Fix wakeup source leaks on device unbind
  gpio: mpc8xxx: Fix wakeup source leaks on device unbind
  gpio: TODO: track the removal of regulator-related workarounds
  MAINTAINERS: add more keywords for the GPIO subsystem entry
  gpio: deprecate devm_gpiod_unhinge()
  gpio: deprecate the GPIOD_FLAGS_BIT_NONEXCLUSIVE flag
  gpio: tegra186: fix resource handling in ACPI probe path
  • Loading branch information
Linus Torvalds committed Apr 10, 2025
2 parents b4991c0 + b8c7a1a commit 8f43640
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 18 deletions.
2 changes: 2 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -10151,6 +10151,8 @@ F: include/linux/gpio.h
F: include/linux/gpio/
F: include/linux/of_gpio.h
K: (devm_)?gpio_(request|free|direction|get|set)
K: GPIOD_FLAGS_BIT_NONEXCLUSIVE
K: devm_gpiod_unhinge

GPIO UAPI
M: Bartosz Golaszewski <brgl@bgdev.pl>
Expand Down
34 changes: 34 additions & 0 deletions drivers/gpio/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,37 @@ their hardware offsets within the chip.

Encourage users to switch to using them and eventually remove the existing
global export/unexport attribues.

-------------------------------------------------------------------------------

Remove GPIOD_FLAGS_BIT_NONEXCLUSIVE

GPIOs in the linux kernel are meant to be an exclusive resource. This means
that the GPIO descriptors (the software representation of the hardware concept)
are not reference counted and - in general - only one user at a time can
request a GPIO line and control its settings. The consumer API is designed
around full control of the line's state as evidenced by the fact that, for
instance, gpiod_set_value() does indeed drive the line as requested, instead
of bumping an enable counter of some sort.

A problematic use-case for GPIOs is when two consumers want to use the same
descriptor independently. An example of such a user is the regulator subsystem
which may instantiate several struct regulator_dev instances containing
a struct device but using the same enable GPIO line.

A workaround was introduced in the form of the GPIOD_FLAGS_BIT_NONEXCLUSIVE
flag but its implementation is problematic: it does not provide any
synchronization of usage nor did it introduce any enable count meaning the
non-exclusive users of the same descriptor will in fact "fight" for the
control over it. This flag should be removed and replaced with a better
solution, possibly based on the new power sequencing subsystem.

-------------------------------------------------------------------------------

Remove devm_gpiod_unhinge()

devm_gpiod_unhinge() is provided as a way to transfer the ownership of managed
enable GPIOs to the regulator core. Rather than doing that however, we should
make it possible for the regulator subsystem to deal with GPIO resources the
lifetime of which it doesn't control as logically, a GPIO obtained by a caller
should also be freed by it.
4 changes: 3 additions & 1 deletion drivers/gpio/gpio-mpc8xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,9 @@ static int mpc8xxx_probe(struct platform_device *pdev)
goto err;
}

device_init_wakeup(dev, true);
ret = devm_device_init_wakeup(dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to init wakeup\n");

return 0;
err:
Expand Down
27 changes: 14 additions & 13 deletions drivers/gpio/gpio-tegra186.c
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
struct gpio_irq_chip *irq;
struct tegra_gpio *gpio;
struct device_node *np;
struct resource *res;
char **names;
int err;

Expand All @@ -842,19 +843,19 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->num_banks++;

/* get register apertures */
gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
if (IS_ERR(gpio->secure)) {
gpio->secure = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(gpio->secure))
return PTR_ERR(gpio->secure);
}

gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
if (IS_ERR(gpio->base)) {
gpio->base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(gpio->base))
return PTR_ERR(gpio->base);
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "security");
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpio->secure = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gpio->secure))
return PTR_ERR(gpio->secure);

res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio");
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
gpio->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gpio->base))
return PTR_ERR(gpio->base);

err = platform_irq_count(pdev);
if (err < 0)
Expand Down
1 change: 1 addition & 0 deletions drivers/gpio/gpio-zynq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,7 @@ static void zynq_gpio_remove(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
dev_warn(&pdev->dev, "pm_runtime_get_sync() Failed\n");
device_init_wakeup(&pdev->dev, 0);
gpiochip_remove(&gpio->chip);
device_set_wakeup_capable(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
Expand Down
6 changes: 5 additions & 1 deletion drivers/gpio/gpiolib-devres.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,15 @@ EXPORT_SYMBOL_GPL(devm_gpiod_put);
* @dev: GPIO consumer
* @desc: GPIO descriptor to remove resource management from
*
* *DEPRECATED*
* This function should not be used. It's been provided as a workaround for
* resource ownership issues in the regulator framework and should be replaced
* with a better solution.
*
* Remove resource management from a GPIO descriptor. This is needed when
* you want to hand over lifecycle management of a descriptor to another
* mechanism.
*/

void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
{
int ret;
Expand Down
8 changes: 5 additions & 3 deletions drivers/gpio/gpiolib-of.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np,
*/
{ "himax,hx8357", "gpios-reset", false },
{ "himax,hx8369", "gpios-reset", false },
#endif
#if IS_ENABLED(CONFIG_MTD_NAND_JZ4780)
/*
* The rb-gpios semantics was undocumented and qi,lb60 (along with
* the ingenic driver) got it wrong. The active state encodes the
Expand Down Expand Up @@ -266,6 +268,9 @@ static void of_gpio_set_polarity_by_property(const struct device_node *np,
{ "fsl,imx8qm-fec", "phy-reset-gpios", "phy-reset-active-high" },
{ "fsl,s32v234-fec", "phy-reset-gpios", "phy-reset-active-high" },
#endif
#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
{ "atmel,hsmci", "cd-gpios", "cd-inverted" },
#endif
#if IS_ENABLED(CONFIG_PCI_IMX6)
{ "fsl,imx6q-pcie", "reset-gpio", "reset-gpio-active-high" },
{ "fsl,imx6sx-pcie", "reset-gpio", "reset-gpio-active-high" },
Expand All @@ -291,9 +296,6 @@ static void of_gpio_set_polarity_by_property(const struct device_node *np,
#if IS_ENABLED(CONFIG_REGULATOR_GPIO)
{ "regulator-gpio", "enable-gpio", "enable-active-high" },
{ "regulator-gpio", "enable-gpios", "enable-active-high" },
#endif
#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
{ "atmel,hsmci", "cd-gpios", "cd-inverted" },
#endif
};
unsigned int i;
Expand Down
1 change: 1 addition & 0 deletions include/linux/gpio/consumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct gpio_descs {
#define GPIOD_FLAGS_BIT_DIR_OUT BIT(1)
#define GPIOD_FLAGS_BIT_DIR_VAL BIT(2)
#define GPIOD_FLAGS_BIT_OPEN_DRAIN BIT(3)
/* GPIOD_FLAGS_BIT_NONEXCLUSIVE is DEPRECATED, don't use in new code. */
#define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4)

/**
Expand Down

0 comments on commit 8f43640

Please sign in to comment.