diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-04 12:33:38 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-04 12:33:38 -0800 |
| commit | 500920fa76819b4909a32081e153bce80ce74824 (patch) | |
| tree | 5a030b34c37f9ed942e01d2795dec543af279589 /drivers/gpio | |
| parent | 205f1a0d188658ff3043d91c988378d8a81344c2 (diff) | |
| parent | dae9750105cf93ac1e156ef91f4beeb53bd64777 (diff) | |
Merge tag 'gpio-updates-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"There's one new driver, lots of various updates to existing ones, some
refactoring support for new models and misc tweaks and fixes.
The biggest new feature in GPIO core is adding support for managed,
enable-counted sharing of GPIO pins, something that - until now - was
only hacked around with the GPIOD_FLAGS_BIT_NONEXCLUSIVE request flag
which basically allowed drivers to "fight it out" for the descriptor
and provided no synchronization. It was enabled on Qualcomm platforms
(and thus is enabled on arm64 defconfig) and I plan on removing
GPIOD_FLAGS_BIT_NONEXCLUSIVE once all drivers using it are switched to
the new mechanism.
GPIO core:
- add proper support for shared GPIOs that's aiming to replace the
current sharing mechanism (which provides no synchronization ot
enable counting) and enable it for Qualcomm platforms
- improve the software node GPIO lookup by using the fwnode
representation instead of the software node's name which was prone
to bugs (GPIO controllers don't have to use the software node's
name as their kernel label)
- remove the last user of legacy-of-mm-gpiochip.h and drop the header
- move closer to removing the legacy gpio_request_one() routine
- rename some symbols for consistency
- shrink GPIO printk() helpers by reusing existing code
- remove some redundant kernel messages
- use min() instead of min_t() in GPIO ACPI code
- use system_percpu_wq instead of system_wq in GPIO character device
code
New drivers:
- add a driver for the QIXIS FPGA GPIO controller
Driver improvements:
- use modernized variants of power management macros across a wide
array of drivers in order to avoid having to use the __maybe_unused
attribute
- convert gpio-elkhartlake and reset-gpio to using the auxiliary bus
instead of the platform bus as they are not really described in
firmware
- use lock guards and update symbol prefixes in gpio-mmio
- support the bryx radio interface kit in gpio-mpsse + refactor the
driver
- use software nodes for configuring the reset-gpio driver, including
setting up the reference to the shared "reset" pin
- check and propagate the return value of gpiod_set_value() to
user-space in gpio-virtuser (this was previously not possible as
this function returned void)
- extend the gpio-regmap helper with more features (bypass cache for
aliased inputs, force writes for aliased data registers, add a new
configuration parameter)
- remove unneeded includes from gpio-aspeed and gpio-latch
- add support for Tegra410 to gpio-tegra186
- replace PCI-specific PM with generic device-level PM in gpio-bt8xx
- use dynamic GPIO range allocation in gpio-loongson-64bit
- improve handling of level-triggered interrupts in gpio-pca953x
- add suspend/resume support to gpio-fxl6408
- add support for more models to gpio-menz127
- optimize gpio-mvebu interrupt handling by avoiding unnecessary
calls to mvebu_gpio_irq_handler()
- make locking more consistent in gpio-grgpio
Device-tree bindings:
- document new NXP and Microchip models
Documentation:
- add a comprehensive compatibility and feature list for
gpio-pca953x, which is a great addition as it's probably the most
commonly used GPIO expander driver
- kernel-doc tweaks
Late fixes:
- use BYTE_CTRL_MODE for 2K2000/3000 models in gpio-loongson"
* tag 'gpio-updates-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (80 commits)
gpio: loongson: Switch 2K2000/3000 GPIO to BYTE_CTRL_MODE
gpio: regmap: fix kernel-doc notation
gpio: shared: fix a deadlock
gpio: shared-proxy: set suppress_bind_attrs
gpio: shared: ignore GPIO hogs when traversing the device tree
gpio: shared: ignore special __symbols__ node when traversing device tree
gpio: shared: handle the reset-gpios corner case
gpio: zynq: Use modern PM macros
gpio: xilinx: Use modern PM macros
gpio: xgene: Use modern PM macros
gpio: uniphier: Use modern PM macros
gpio: tqmx86: Use modern PM macros
gpio: pch: Use modern PM macros
gpio: omap: Use modern PM macros
gpio: msc313: Use modern PM macros
gpio: mlxbf2: Use modern PM macros
gpio: ml-ioh: Use modern PM macros
gpio: pl061: Use modern PM macros
gpio: htc-egpio: Use modern PM macros
gpio: brcmstb: Use modern PM macros
...
Diffstat (limited to 'drivers/gpio')
44 files changed, 1074 insertions, 753 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b8b6537290b0..c74da29253e8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -45,14 +45,6 @@ config GPIOLIB_IRQCHIP select IRQ_DOMAIN bool -config OF_GPIO_MM_GPIOCHIP - bool - help - This adds support for the legacy 'struct of_mm_gpio_chip' interface - from PowerPC. Existing drivers using this interface need to select - this symbol, but new drivers should use the generic gpio-regmap - infrastructure instead. - config GPIO_SHARED def_bool y depends on HAVE_SHARED_GPIOS || COMPILE_TEST @@ -484,7 +476,6 @@ config GPIO_MENZ127 config GPIO_MM_LANTIQ bool "Lantiq Memory mapped GPIOs" depends on LANTIQ && SOC_XWAY - select OF_GPIO_MM_GPIOCHIP help This enables support for memory mapped GPIOs on the External Bus Unit (EBU) found on Lantiq SoCs. The GPIOs are output only as they are @@ -1421,7 +1412,7 @@ config HTC_EGPIO config GPIO_ELKHARTLAKE tristate "Intel Elkhart Lake PSE GPIO support" - depends on X86 || COMPILE_TEST + depends on INTEL_EHL_PSE_IO select GPIO_TANGIER help Select this option to enable GPIO support for Intel Elkhart Lake @@ -1573,6 +1564,15 @@ config GPIO_PMIC_EIC_SPRD help Say yes here to support Spreadtrum PMIC EIC device. +config GPIO_QIXIS_FPGA + tristate "NXP QIXIS FPGA GPIO support" + depends on MFD_SIMPLE_MFD_I2C || COMPILE_TEST + select GPIO_REGMAP + help + This enables support for the GPIOs found in the QIXIS FPGA which is + integrated on some NXP Layerscape boards such as LX2160ARDB and + LS1046AQDS. + config GPIO_RC5T583 bool "RICOH RC5T583 GPIO" depends on MFD_RC5T583 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index d0020bc70b84..2421a8fd3733 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -147,6 +147,7 @@ obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o obj-$(CONFIG_GPIO_POLARFIRE_SOC) += gpio-mpfs.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o +obj-$(CONFIG_GPIO_QIXIS_FPGA) += gpio-qixis-fpga.o obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 8ed74e05903a..5acaeab029ec 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -86,17 +86,6 @@ Work items: ------------------------------------------------------------------------------- -Get rid of <linux/gpio/legacy-of-mm-gpiochip.h> - -Work items: - -- Get rid of struct of_mm_gpio_chip altogether: use the generic MMIO - GPIO for all current users (see below). Delete struct of_mm_gpio_chip, - to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_remove(), - CONFIG_OF_GPIO_MM_GPIOCHIP from the kernel. - -------------------------------------------------------------------------------- - Collect drivers Collect GPIO drivers from arch/* and other places that should be placed diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 7953a9c4e36d..2e0ae953dd99 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -24,12 +24,11 @@ /* * These two headers aren't meant to be used by GPIO drivers. We need - * them in order to access gpio_chip_hwgpio() which we need to implement + * them in order to access gpiod_hwgpio() which we need to implement * the aspeed specific API which allows the coprocessor to request * access to some GPIOs and to arbitrate between coprocessor and ARM. */ #include <linux/gpio/consumer.h> -#include "gpiolib.h" /* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) @@ -942,7 +941,7 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, { struct gpio_chip *chip = gpiod_to_chip(desc); struct aspeed_gpio *gpio = gpiochip_get_data(chip); - int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); + int rc = 0, bindex, offset = gpiod_hwgpio(desc); const struct aspeed_gpio_bank *bank = to_bank(offset); if (!aspeed_gpio_support_copro(gpio)) @@ -987,7 +986,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) { struct gpio_chip *chip = gpiod_to_chip(desc); struct aspeed_gpio *gpio = gpiochip_get_data(chip); - int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); + int rc = 0, bindex, offset = gpiod_hwgpio(desc); if (!aspeed_gpio_support_copro(gpio)) return -EOPNOTSUPP; diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index f40c9472588b..af9287ff5dc4 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -533,7 +533,6 @@ static void brcmstb_gpio_shutdown(struct platform_device *pdev) brcmstb_gpio_quiesce(&pdev->dev, false); } -#ifdef CONFIG_PM_SLEEP static void brcmstb_gpio_bank_restore(struct brcmstb_gpio_priv *priv, struct brcmstb_gpio_bank *bank) { @@ -572,14 +571,9 @@ static int brcmstb_gpio_resume(struct device *dev) return 0; } -#else -#define brcmstb_gpio_suspend NULL -#define brcmstb_gpio_resume NULL -#endif /* CONFIG_PM_SLEEP */ - static const struct dev_pm_ops brcmstb_gpio_pm_ops = { - .suspend_noirq = brcmstb_gpio_suspend, - .resume_noirq = brcmstb_gpio_resume, + .suspend_noirq = pm_sleep_ptr(brcmstb_gpio_suspend), + .resume_noirq = pm_sleep_ptr(brcmstb_gpio_resume), }; static int brcmstb_gpio_probe(struct platform_device *pdev) @@ -755,7 +749,7 @@ static struct platform_driver brcmstb_gpio_driver = { .driver = { .name = "brcmstb-gpio", .of_match_table = brcmstb_gpio_of_match, - .pm = &brcmstb_gpio_pm_ops, + .pm = pm_sleep_ptr(&brcmstb_gpio_pm_ops), }, .probe = brcmstb_gpio_probe, .remove = brcmstb_gpio_remove, diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index 05401da03ca3..324eeb77dbd5 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -52,10 +52,8 @@ struct bt8xxgpio { struct pci_dev *pdev; struct gpio_chip gpio; -#ifdef CONFIG_PM u32 saved_outen; u32 saved_data; -#endif }; #define bgwrite(dat, adr) writel((dat), bg->mmio+(adr)) @@ -224,9 +222,10 @@ static void bt8xxgpio_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -#ifdef CONFIG_PM -static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state) + +static int bt8xxgpio_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct bt8xxgpio *bg = pci_get_drvdata(pdev); scoped_guard(spinlock_irqsave, &bg->lock) { @@ -238,23 +237,13 @@ static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state) bgwrite(0x0, BT848_GPIO_OUT_EN); } - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } -static int bt8xxgpio_resume(struct pci_dev *pdev) +static int bt8xxgpio_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct bt8xxgpio *bg = pci_get_drvdata(pdev); - int err; - - pci_set_power_state(pdev, PCI_D0); - err = pci_enable_device(pdev); - if (err) - return err; - pci_restore_state(pdev); guard(spinlock_irqsave)(&bg->lock); @@ -267,10 +256,8 @@ static int bt8xxgpio_resume(struct pci_dev *pdev) return 0; } -#else -#define bt8xxgpio_suspend NULL -#define bt8xxgpio_resume NULL -#endif /* CONFIG_PM */ + +static DEFINE_SIMPLE_DEV_PM_OPS(bt8xxgpio_pm_ops, bt8xxgpio_suspend, bt8xxgpio_resume); static const struct pci_device_id bt8xxgpio_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) }, @@ -286,8 +273,7 @@ static struct pci_driver bt8xxgpio_pci_driver = { .id_table = bt8xxgpio_pci_tbl, .probe = bt8xxgpio_probe, .remove = bt8xxgpio_remove, - .suspend = bt8xxgpio_suspend, - .resume = bt8xxgpio_resume, + .driver.pm = &bt8xxgpio_pm_ops, }; module_pci_driver(bt8xxgpio_pci_driver); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index b42ff46d292b..4986c465c9a8 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -79,7 +79,6 @@ struct dwapb_platform_data { unsigned int nports; }; -#ifdef CONFIG_PM_SLEEP /* Store GPIO context across system-wide suspend/resume transitions */ struct dwapb_context { u32 data; @@ -92,7 +91,6 @@ struct dwapb_context { u32 int_deb; u32 wake_en; }; -#endif struct dwapb_gpio_port_irqchip { unsigned int nr_irqs; @@ -103,9 +101,7 @@ struct dwapb_gpio_port { struct gpio_generic_chip chip; struct dwapb_gpio_port_irqchip *pirq; struct dwapb_gpio *gpio; -#ifdef CONFIG_PM_SLEEP struct dwapb_context *ctx; -#endif unsigned int idx; }; @@ -363,7 +359,6 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type) return 0; } -#ifdef CONFIG_PM_SLEEP static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); @@ -378,9 +373,6 @@ static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable) return 0; } -#else -#define dwapb_irq_set_wake NULL -#endif static const struct irq_chip dwapb_irq_chip = { .name = DWAPB_DRIVER_NAME, @@ -390,7 +382,7 @@ static const struct irq_chip dwapb_irq_chip = { .irq_set_type = dwapb_irq_set_type, .irq_enable = dwapb_irq_enable, .irq_disable = dwapb_irq_disable, - .irq_set_wake = dwapb_irq_set_wake, + .irq_set_wake = pm_sleep_ptr(dwapb_irq_set_wake), .flags = IRQCHIP_IMMUTABLE, GPIOCHIP_IRQ_RESOURCE_HELPERS, }; @@ -759,7 +751,6 @@ static int dwapb_gpio_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int dwapb_gpio_suspend(struct device *dev) { struct dwapb_gpio *gpio = dev_get_drvdata(dev); @@ -844,15 +835,14 @@ static int dwapb_gpio_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend, - dwapb_gpio_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, + dwapb_gpio_suspend, dwapb_gpio_resume); static struct platform_driver dwapb_gpio_driver = { .driver = { .name = DWAPB_DRIVER_NAME, - .pm = &dwapb_gpio_pm_ops, + .pm = pm_sleep_ptr(&dwapb_gpio_pm_ops), .of_match_table = dwapb_of_match, .acpi_match_table = dwapb_acpi_match, }, diff --git a/drivers/gpio/gpio-elkhartlake.c b/drivers/gpio/gpio-elkhartlake.c index 95de52d2cc63..b96e7928b6e5 100644 --- a/drivers/gpio/gpio-elkhartlake.c +++ b/drivers/gpio/gpio-elkhartlake.c @@ -2,43 +2,46 @@ /* * Intel Elkhart Lake PSE GPIO driver * - * Copyright (c) 2023 Intel Corporation. + * Copyright (c) 2023, 2025 Intel Corporation. * * Authors: Pandith N <pandith.n@intel.com> * Raag Jadav <raag.jadav@intel.com> */ +#include <linux/auxiliary_bus.h> #include <linux/device.h> #include <linux/err.h> #include <linux/module.h> -#include <linux/platform_device.h> #include <linux/pm.h> +#include <linux/ehl_pse_io_aux.h> + #include "gpio-tangier.h" /* Each Intel EHL PSE GPIO Controller has 30 GPIO pins */ #define EHL_PSE_NGPIO 30 -static int ehl_gpio_probe(struct platform_device *pdev) +static int ehl_gpio_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) { - struct device *dev = &pdev->dev; + struct device *dev = &adev->dev; + struct ehl_pse_io_data *data; struct tng_gpio *priv; - int irq, ret; + int ret; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + data = dev_get_platdata(dev); + if (!data) + return -ENODATA; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->reg_base = devm_platform_ioremap_resource(pdev, 0); + priv->reg_base = devm_ioremap_resource(dev, &data->mem); if (IS_ERR(priv->reg_base)) return PTR_ERR(priv->reg_base); priv->dev = dev; - priv->irq = irq; + priv->irq = data->irq; priv->info.base = -1; priv->info.ngpio = EHL_PSE_NGPIO; @@ -51,25 +54,24 @@ static int ehl_gpio_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "tng_gpio_probe error\n"); - platform_set_drvdata(pdev, priv); + auxiliary_set_drvdata(adev, priv); return 0; } -static const struct platform_device_id ehl_gpio_ids[] = { - { "gpio-elkhartlake" }, +static const struct auxiliary_device_id ehl_gpio_ids[] = { + { EHL_PSE_IO_NAME "." EHL_PSE_GPIO_NAME }, { } }; -MODULE_DEVICE_TABLE(platform, ehl_gpio_ids); +MODULE_DEVICE_TABLE(auxiliary, ehl_gpio_ids); -static struct platform_driver ehl_gpio_driver = { +static struct auxiliary_driver ehl_gpio_driver = { .driver = { - .name = "gpio-elkhartlake", .pm = pm_sleep_ptr(&tng_gpio_pm_ops), }, .probe = ehl_gpio_probe, .id_table = ehl_gpio_ids, }; -module_platform_driver(ehl_gpio_driver); +module_auxiliary_driver(ehl_gpio_driver); MODULE_AUTHOR("Pandith N <pandith.n@intel.com>"); MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>"); diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c index 86ebc66b1104..afc1b8461dab 100644 --- a/drivers/gpio/gpio-fxl6408.c +++ b/drivers/gpio/gpio-fxl6408.c @@ -123,6 +123,8 @@ static int fxl6408_probe(struct i2c_client *client) if (ret) return ret; + i2c_set_clientdata(client, gpio_config.regmap); + /* Disable High-Z of outputs, so that our OUTPUT updates actually take effect. */ ret = regmap_write(gpio_config.regmap, FXL6408_REG_OUTPUT_HIGH_Z, 0); if (ret) @@ -131,6 +133,16 @@ static int fxl6408_probe(struct i2c_client *client) return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); } +static int fxl6408_resume(struct device *dev) +{ + struct regmap *regmap = dev_get_drvdata(dev); + + regcache_mark_dirty(regmap); + return regcache_sync(regmap); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(fxl6408_pm_ops, NULL, fxl6408_resume); + static const __maybe_unused struct of_device_id fxl6408_dt_ids[] = { { .compatible = "fcs,fxl6408" }, { } @@ -146,6 +158,7 @@ MODULE_DEVICE_TABLE(i2c, fxl6408_id); static struct i2c_driver fxl6408_driver = { .driver = { .name = "fxl6408", + .pm = pm_sleep_ptr(&fxl6408_pm_ops), .of_match_table = fxl6408_dt_ids, }, .probe = fxl6408_probe, diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 0c0f97fa14fc..e4fa84e22726 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -46,7 +46,7 @@ /* Structure for an irq of the core - called an underlying irq */ struct grgpio_uirq { - u8 refcnt; /* Reference counter to manage requesting/freeing of uirq */ + atomic_t refcnt; /* Reference counter to manage requesting/freeing of uirq */ u8 uirq; /* Underlying irq of the gpio driver */ }; @@ -242,30 +242,22 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, irq, offset); gpio_generic_chip_lock_irqsave(&priv->chip, flags); - - /* Request underlying irq if not already requested */ lirq->irq = irq; uirq = &priv->uirqs[lirq->index]; - if (uirq->refcnt == 0) { - /* - * FIXME: This is not how locking works at all, you can't just - * release the lock for a moment to do something that can't - * sleep... - */ - gpio_generic_chip_unlock_irqrestore(&priv->chip, flags); + gpio_generic_chip_unlock_irqrestore(&priv->chip, flags); + + /* Request underlying irq if not already requested */ + if (atomic_fetch_add(1, &uirq->refcnt) == 0) { ret = request_irq(uirq->uirq, grgpio_irq_handler, 0, dev_name(priv->dev), priv); if (ret) { dev_err(priv->dev, "Could not request underlying irq %d\n", uirq->uirq); + atomic_dec(&uirq->refcnt); /* rollback */ return ret; } - gpio_generic_chip_lock_irqsave(&priv->chip, flags); } - uirq->refcnt++; - - gpio_generic_chip_unlock_irqrestore(&priv->chip, flags); /* Setup irq */ irq_set_chip_data(irq, priv); @@ -306,8 +298,7 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) if (index >= 0) { uirq = &priv->uirqs[lirq->index]; - uirq->refcnt--; - if (uirq->refcnt == 0) { + if (atomic_dec_and_test(&uirq->refcnt)) { gpio_generic_chip_unlock_irqrestore(&priv->chip, flags); free_irq(uirq->uirq, priv); return; @@ -434,6 +425,7 @@ static int grgpio_probe(struct platform_device *ofdev) continue; } priv->uirqs[lirq->index].uirq = ret; + atomic_set(&priv->uirqs[lirq->index].refcnt, 0); } } diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 2eaed83214d8..72935d6dbebf 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -364,21 +364,20 @@ static int __init egpio_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int egpio_suspend(struct platform_device *pdev, pm_message_t state) +static int egpio_suspend(struct device *dev) { - struct egpio_info *ei = platform_get_drvdata(pdev); + struct egpio_info *ei = dev_get_drvdata(dev); - if (ei->chained_irq && device_may_wakeup(&pdev->dev)) + if (ei->chained_irq && device_may_wakeup(dev)) enable_irq_wake(ei->chained_irq); return 0; } -static int egpio_resume(struct platform_device *pdev) +static int egpio_resume(struct device *dev) { - struct egpio_info *ei = platform_get_drvdata(pdev); + struct egpio_info *ei = dev_get_drvdata(dev); - if (ei->chained_irq && device_may_wakeup(&pdev->dev)) + if (ei->chained_irq && device_may_wakeup(dev)) disable_irq_wake(ei->chained_irq); /* Update registers from the cache, in case @@ -386,19 +385,15 @@ static int egpio_resume(struct platform_device *pdev) egpio_write_cache(ei); return 0; } -#else -#define egpio_suspend NULL -#define egpio_resume NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(egpio_pm_ops, egpio_suspend, egpio_resume); static struct platform_driver egpio_driver = { .driver = { .name = "htc-egpio", .suppress_bind_attrs = true, + .pm = pm_sleep_ptr(&egpio_pm_ops), }, - .suspend = egpio_suspend, - .resume = egpio_resume, }; static int __init egpio_init(void) diff --git a/drivers/gpio/gpio-latch.c b/drivers/gpio/gpio-latch.c index c64aaa896766..452a9ce61488 100644 --- a/drivers/gpio/gpio-latch.c +++ b/drivers/gpio/gpio-latch.c @@ -48,8 +48,6 @@ #include <linux/property.h> #include <linux/delay.h> -#include "gpiolib.h" - struct gpio_latch_priv { struct gpio_chip gc; struct gpio_descs *clk_gpios; diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c index 02f181cb219e..77d07e31366f 100644 --- a/drivers/gpio/gpio-loongson-64bit.c +++ b/drivers/gpio/gpio-loongson-64bit.c @@ -312,6 +312,7 @@ static int loongson_gpio_init(struct platform_device *pdev, struct loongson_gpio lgpio->chip.gc.direction_output = loongson_gpio_direction_output; lgpio->chip.gc.set = loongson_gpio_set; lgpio->chip.gc.parent = &pdev->dev; + lgpio->chip.gc.base = -1; spin_lock_init(&lgpio->lock); } @@ -407,11 +408,11 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = { static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = { .label = "ls2k2000_gpio", - .mode = BIT_CTRL_MODE, - .conf_offset = 0x0, - .in_offset = 0x20, - .out_offset = 0x10, - .inten_offset = 0x30, + .mode = BYTE_CTRL_MODE, + .conf_offset = 0x800, + .in_offset = 0xa00, + .out_offset = 0x900, + .inten_offset = 0xb00, }; static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = { diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c index da2bf9381cc4..52b13c6ae496 100644 --- a/drivers/gpio/gpio-menz127.c +++ b/drivers/gpio/gpio-menz127.c @@ -24,6 +24,11 @@ #define MEN_Z127_ODER 0x1C #define GPIO_TO_DBCNT_REG(gpio) ((gpio * 4) + 0x80) +/* MEN Z127 supported model ids*/ +#define MEN_Z127_ID 0x7f +#define MEN_Z034_ID 0x22 +#define MEN_Z037_ID 0x25 + #define MEN_Z127_DB_MIN_US 50 /* 16 bit compare register. Each bit represents 50us */ #define MEN_Z127_DB_MAX_US (0xffff * MEN_Z127_DB_MIN_US) @@ -140,6 +145,7 @@ static int men_z127_probe(struct mcb_device *mdev, struct men_z127_gpio *men_z127_gpio; struct device *dev = &mdev->dev; int ret; + unsigned long sz; men_z127_gpio = devm_kzalloc(dev, sizeof(struct men_z127_gpio), GFP_KERNEL); @@ -163,9 +169,21 @@ static int men_z127_probe(struct mcb_device *mdev, mcb_set_drvdata(mdev, men_z127_gpio); + switch (mdev->id) { + case MEN_Z127_ID: + sz = 4; + break; + case MEN_Z034_ID: + case MEN_Z037_ID: + sz = 1; + break; + default: + return dev_err_probe(&mdev->dev, -EINVAL, "no size found for id %d", mdev->id); + } + config = (struct gpio_generic_chip_config) { .dev = &mdev->dev, - .sz = 4, + .sz = sz, .dat = men_z127_gpio->reg_base + MEN_Z127_PSR, .set = men_z127_gpio->reg_base + MEN_Z127_CTRL, .dirout = men_z127_gpio->reg_base + MEN_Z127_GPIODR, @@ -186,7 +204,9 @@ static int men_z127_probe(struct mcb_device *mdev, } static const struct mcb_device_id men_z127_ids[] = { - { .device = 0x7f }, + { .device = MEN_Z127_ID }, + { .device = MEN_Z034_ID }, + { .device = MEN_Z037_ID }, { } }; MODULE_DEVICE_TABLE(mcb, men_z127_ids); @@ -201,7 +221,7 @@ static struct mcb_driver men_z127_driver = { module_mcb_driver(men_z127_driver); MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>"); -MODULE_DESCRIPTION("MEN 16z127 GPIO Controller"); +MODULE_DESCRIPTION("MEN GPIO Controller"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("mcb:16z127"); MODULE_IMPORT_NS("MCB"); diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index f6af81bf2b13..6576e5dcb0ee 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -160,7 +160,7 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) /* * Save register configuration and disable interrupts. */ -static void __maybe_unused ioh_gpio_save_reg_conf(struct ioh_gpio *chip) +static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip) { int i; @@ -186,7 +186,7 @@ static void __maybe_unused ioh_gpio_save_reg_conf(struct ioh_gpio *chip) /* * This function restores the register configuration of the GPIO device. */ -static void __maybe_unused ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) +static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) { int i; @@ -479,7 +479,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev, return 0; } -static int __maybe_unused ioh_gpio_suspend(struct device *dev) +static int ioh_gpio_suspend(struct device *dev) { struct ioh_gpio *chip = dev_get_drvdata(dev); unsigned long flags; @@ -491,7 +491,7 @@ static int __maybe_unused ioh_gpio_suspend(struct device *dev) return 0; } -static int __maybe_unused ioh_gpio_resume(struct device *dev) +static int ioh_gpio_resume(struct device *dev) { struct ioh_gpio *chip = dev_get_drvdata(dev); unsigned long flags; @@ -505,7 +505,7 @@ static int __maybe_unused ioh_gpio_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(ioh_gpio_pm_ops, ioh_gpio_suspend, ioh_gpio_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(ioh_gpio_pm_ops, ioh_gpio_suspend, ioh_gpio_resume); static const struct pci_device_id ioh_gpio_pcidev_id[] = { { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) }, @@ -518,7 +518,7 @@ static struct pci_driver ioh_gpio_driver = { .id_table = ioh_gpio_pcidev_id, .probe = ioh_gpio_probe, .driver = { - .pm = &ioh_gpio_pm_ops, + .pm = pm_sleep_ptr(&ioh_gpio_pm_ops), }, }; diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index abffce3894fc..6668686a28ff 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -424,7 +424,7 @@ mlxbf2_gpio_probe(struct platform_device *pdev) return 0; } -static int __maybe_unused mlxbf2_gpio_suspend(struct device *dev) +static int mlxbf2_gpio_suspend(struct device *dev) { struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev); @@ -436,7 +436,7 @@ static int __maybe_unused mlxbf2_gpio_suspend(struct device *dev) return 0; } -static int __maybe_unused mlxbf2_gpio_resume(struct device *dev) +static int mlxbf2_gpio_resume(struct device *dev) { struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev); @@ -447,7 +447,7 @@ static int __maybe_unused mlxbf2_gpio_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(mlxbf2_pm_ops, mlxbf2_gpio_suspend, mlxbf2_gpio_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(mlxbf2_pm_ops, mlxbf2_gpio_suspend, mlxbf2_gpio_resume); static const struct acpi_device_id __maybe_unused mlxbf2_gpio_acpi_match[] = { { "MLNXBF22", 0 }, @@ -459,7 +459,7 @@ static struct platform_driver mlxbf2_gpio_driver = { .driver = { .name = "mlxbf2_gpio", .acpi_match_table = mlxbf2_gpio_acpi_match, - .pm = &mlxbf2_pm_ops, + .pm = pm_sleep_ptr(&mlxbf2_pm_ops), }, .probe = mlxbf2_gpio_probe, }; diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index 8f1405733d98..1bd98c50a459 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -10,7 +10,6 @@ #include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/gpio/driver.h> -#include <linux/gpio/legacy-of-mm-gpiochip.h> #include <linux/of.h> #include <linux/io.h> #include <linux/slab.h> @@ -27,7 +26,8 @@ #define LTQ_EBU_WP 0x80000000 /* write protect bit */ struct ltq_mm { - struct of_mm_gpio_chip mmchip; + struct gpio_chip gc; + void __iomem *regs; u16 shadow; /* shadow the latches state */ }; @@ -44,7 +44,7 @@ static void ltq_mm_apply(struct ltq_mm *chip) spin_lock_irqsave(&ebu_lock, flags); ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1); - __raw_writew(chip->shadow, chip->mmchip.regs); + __raw_writew(chip->shadow, chip->regs); ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); spin_unlock_irqrestore(&ebu_lock, flags); } @@ -52,8 +52,8 @@ static void ltq_mm_apply(struct ltq_mm *chip) /** * ltq_mm_set() - gpio_chip->set - set gpios. * @gc: Pointer to gpio_chip device structure. - * @gpio: GPIO signal number. - * @val: Value to be written to specified signal. + * @offset: GPIO signal number. + * @value: Value to be written to specified signal. * * Set the shadow value and call ltq_mm_apply. Always returns 0. */ @@ -73,8 +73,8 @@ static int ltq_mm_set(struct gpio_chip *gc, unsigned int offset, int value) /** * ltq_mm_dir_out() - gpio_chip->dir_out - set gpio direction. * @gc: Pointer to gpio_chip device structure. - * @gpio: GPIO signal number. - * @val: Value to be written to specified signal. + * @offset: GPIO signal number. + * @value: Value to be written to specified signal. * * Same as ltq_mm_set, always returns 0. */ @@ -85,21 +85,21 @@ static int ltq_mm_dir_out(struct gpio_chip *gc, unsigned offset, int value) /** * ltq_mm_save_regs() - Set initial values of GPIO pins - * @mm_gc: pointer to memory mapped GPIO chip structure + * @chip: Pointer to our private data structure. */ -static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc) +static void ltq_mm_save_regs(struct ltq_mm *chip) { - struct ltq_mm *chip = - container_of(mm_gc, struct ltq_mm, mmchip); - /* tell the ebu controller which memory address we will be using */ - ltq_ebu_w32(CPHYSADDR(chip->mmchip.regs) | 0x1, LTQ_EBU_ADDRSEL1); + ltq_ebu_w32(CPHYSADDR((__force void *)chip->regs) | 0x1, LTQ_EBU_ADDRSEL1); ltq_mm_apply(chip); } static int ltq_mm_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct gpio_chip *gc; struct ltq_mm *chip; u32 shadow; @@ -107,25 +107,29 @@ static int ltq_mm_probe(struct platform_device *pdev) if (!chip) return -ENOMEM; - platform_set_drvdata(pdev, chip); + gc = &chip->gc; + + gc->base = -1; + gc->ngpio = 16; + gc->direction_output = ltq_mm_dir_out; + gc->set = ltq_mm_set; + gc->parent = dev; + gc->owner = THIS_MODULE; + gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); + if (!gc->label) + return -ENOMEM; + + chip->regs = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(chip->regs)) + return PTR_ERR(chip->regs); - chip->mmchip.gc.ngpio = 16; - chip->mmchip.gc.direction_output = ltq_mm_dir_out; - chip->mmchip.gc.set = ltq_mm_set; - chip->mmchip.save_regs = ltq_mm_save_regs; + ltq_mm_save_regs(chip); /* store the shadow value if one was passed by the devicetree */ if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow)) chip->shadow = shadow; - return of_mm_gpiochip_add_data(pdev->dev.of_node, &chip->mmchip, chip); -} - -static void ltq_mm_remove(struct platform_device *pdev) -{ - struct ltq_mm *chip = platform_get_drvdata(pdev); - - of_mm_gpiochip_remove(&chip->mmchip); + return devm_gpiochip_add_data(dev, gc, chip); } static const struct of_device_id ltq_mm_match[] = { @@ -136,7 +140,6 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match); static struct platform_driver ltq_mm_driver = { .probe = ltq_mm_probe, - .remove = ltq_mm_remove, .driver = { .name = "gpio-mm-ltq", .of_match_table = ltq_mm_match, diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 7d6dd36cf1ae..b3a26a06260b 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -41,6 +41,7 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` */ #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/compiler.h> #include <linux/err.h> #include <linux/init.h> @@ -61,69 +62,69 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` #include "gpiolib.h" -static void bgpio_write8(void __iomem *reg, unsigned long data) +static void gpio_mmio_write8(void __iomem *reg, unsigned long data) { writeb(data, reg); } -static unsigned long bgpio_read8(void __iomem *reg) +static unsigned long gpio_mmio_read8(void __iomem *reg) { return readb(reg); } -static void bgpio_write16(void __iomem *reg, unsigned long data) +static void gpio_mmio_write16(void __iomem *reg, unsigned long data) { writew(data, reg); } -static unsigned long bgpio_read16(void __iomem *reg) +static unsigned long gpio_mmio_read16(void __iomem *reg) { return readw(reg); } -static void bgpio_write32(void __iomem *reg, unsigned long data) +static void gpio_mmio_write32(void __iomem *reg, unsigned long data) { writel(data, reg); } -static unsigned long bgpio_read32(void __iomem *reg) +static unsigned long gpio_mmio_read32(void __iomem *reg) { return readl(reg); } #if BITS_PER_LONG >= 64 -static void bgpio_write64(void __iomem *reg, unsigned long data) +static void gpio_mmio_write64(void __iomem *reg, unsigned long data) { writeq(data, reg); } -static unsigned long bgpio_read64(void __iomem *reg) +static unsigned long gpio_mmio_read64(void __iomem *reg) { return readq(reg); } #endif /* BITS_PER_LONG >= 64 */ -static void bgpio_write16be(void __iomem *reg, unsigned long data) +static void gpio_mmio_write16be(void __iomem *reg, unsigned long data) { iowrite16be(data, reg); } -static unsigned long bgpio_read16be(void __iomem *reg) +static unsigned long gpio_mmio_read16be(void __iomem *reg) { return ioread16be(reg); } -static void bgpio_write32be(void __iomem *reg, unsigned long data) +static void gpio_mmio_write32be(void __iomem *reg, unsigned long data) { iowrite32be(data, reg); } -static unsigned long bgpio_read32be(void __iomem *reg) +static unsigned long gpio_mmio_read32be(void __iomem *reg) { return ioread32be(reg); } -static unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line) +static unsigned long gpio_mmio_line2mask(struct gpio_chip *gc, unsigned int line) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); @@ -132,10 +133,10 @@ static unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line) return BIT(line); } -static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio) +static int gpio_mmio_get_set(struct gpio_chip *gc, unsigned int gpio) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - unsigned long pinmask = bgpio_line2mask(gc, gpio); + unsigned long pinmask = gpio_mmio_line2mask(gc, gpio); bool dir = !!(chip->sdir & pinmask); if (dir) @@ -148,8 +149,8 @@ static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio) * This assumes that the bits in the GPIO register are in native endianness. * We only assign the function pointer if we have that. */ -static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask, - unsigned long *bits) +static int gpio_mmio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long get_mask = 0, set_mask = 0; @@ -168,18 +169,18 @@ static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask, return 0; } -static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) +static int gpio_mmio_get(struct gpio_chip *gc, unsigned int gpio) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - return !!(chip->read_reg(chip->reg_dat) & bgpio_line2mask(gc, gpio)); + return !!(chip->read_reg(chip->reg_dat) & gpio_mmio_line2mask(gc, gpio)); } /* * This only works if the bits in the GPIO register are in native endianness. */ -static int bgpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, - unsigned long *bits) +static int gpio_mmio_get_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); @@ -192,8 +193,8 @@ static int bgpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, /* * With big endian mirrored bit order it becomes more tedious. */ -static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask, - unsigned long *bits) +static int gpio_mmio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long readmask = 0; @@ -205,7 +206,7 @@ static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask, /* Create a mirrored mask */ for_each_set_bit(bit, mask, gc->ngpio) - readmask |= bgpio_line2mask(gc, bit); + readmask |= gpio_mmio_line2mask(gc, bit); /* Read the register */ val = chip->read_reg(chip->reg_dat) & readmask; @@ -215,23 +216,22 @@ static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask, * in bit 0 ... line 31 in bit 31 for a 32bit register. */ for_each_set_bit(bit, &val, gc->ngpio) - *bits |= bgpio_line2mask(gc, bit); + *bits |= gpio_mmio_line2mask(gc, bit); return 0; } -static int bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val) +static int gpio_mmio_set_none(struct gpio_chip *gc, unsigned int gpio, int val) { return 0; } -static int bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +static int gpio_mmio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - unsigned long mask = bgpio_line2mask(gc, gpio); - unsigned long flags; + unsigned long mask = gpio_mmio_line2mask(gc, gpio); - raw_spin_lock_irqsave(&chip->lock, flags); + guard(raw_spinlock)(&chip->lock); if (val) chip->sdata |= mask; @@ -240,16 +240,14 @@ static int bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) chip->write_reg(chip->reg_dat, chip->sdata); - raw_spin_unlock_irqrestore(&chip->lock, flags); - return 0; } -static int bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, - int val) +static int gpio_mmio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, + int val) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - unsigned long mask = bgpio_line2mask(gc, gpio); + unsigned long mask = gpio_mmio_line2mask(gc, gpio); if (val) chip->write_reg(chip->reg_set, mask); @@ -259,12 +257,12 @@ static int bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, return 0; } -static int bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) +static int gpio_mmio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - unsigned long mask = bgpio_line2mask(gc, gpio), flags; + unsigned long mask = gpio_mmio_line2mask(gc, gpio); - raw_spin_lock_irqsave(&chip->lock, flags); + guard(raw_spinlock)(&chip->lock); if (val) chip->sdata |= mask; @@ -273,15 +271,14 @@ static int bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) chip->write_reg(chip->reg_set, chip->sdata); - raw_spin_unlock_irqrestore(&chip->lock, flags); - return 0; } -static void bgpio_multiple_get_masks(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits, - unsigned long *set_mask, - unsigned long *clear_mask) +static void gpio_mmio_multiple_get_masks(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits, + unsigned long *set_mask, + unsigned long *clear_mask) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); int i; @@ -291,60 +288,58 @@ static void bgpio_multiple_get_masks(struct gpio_chip *gc, for_each_set_bit(i, mask, chip->bits) { if (test_bit(i, bits)) - *set_mask |= bgpio_line2mask(gc, i); + *set_mask |= gpio_mmio_line2mask(gc, i); else - *clear_mask |= bgpio_line2mask(gc, i); + *clear_mask |= gpio_mmio_line2mask(gc, i); } } -static void bgpio_set_multiple_single_reg(struct gpio_chip *gc, - unsigned long *mask, - unsigned long *bits, - void __iomem *reg) +static void gpio_mmio_set_multiple_single_reg(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits, + void __iomem *reg) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - unsigned long flags, set_mask, clear_mask; + unsigned long set_mask, clear_mask; - raw_spin_lock_irqsave(&chip->lock, flags); + guard(raw_spinlock)(&chip->lock); - bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); + gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); chip->sdata |= set_mask; chip->sdata &= ~clear_mask; chip->write_reg(reg, chip->sdata); - - raw_spin_unlock_irqrestore(&chip->lock, flags); } -static int bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, - unsigned long *bits) +static int gpio_mmio_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - bgpio_set_multiple_single_reg(gc, mask, bits, chip->reg_dat); + gpio_mmio_set_multiple_single_reg(gc, mask, bits, chip->reg_dat); return 0; } -static int bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask, - unsigned long *bits) +static int gpio_mmio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - bgpio_set_multiple_single_reg(gc, mask, bits, chip->reg_set); + gpio_mmio_set_multiple_single_reg(gc, mask, bits, chip->reg_set); return 0; } -static int bgpio_set_multiple_with_clear(struct gpio_chip *gc, - unsigned long *mask, - unsigned long *bits) +static int gpio_mmio_set_multiple_with_clear(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); unsigned long set_mask, clear_mask; - bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); + gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); if (set_mask) chip->write_reg(chip->reg_set, set_mask); @@ -354,7 +349,8 @@ static int bgpio_set_multiple_with_clear(struct gpio_chip *gc, return 0; } -static int bgpio_dir_return(struct gpio_chip *gc, unsigned int gpio, bool dir_out) +static int gpio_mmio_dir_return(struct gpio_chip *gc, unsigned int gpio, + bool dir_out) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); @@ -367,131 +363,125 @@ static int bgpio_dir_return(struct gpio_chip *gc, unsigned int gpio, bool dir_ou return pinctrl_gpio_direction_input(gc, gpio); } -static int bgpio_dir_in_err(struct gpio_chip *gc, unsigned int gpio) +static int gpio_mmio_dir_in_err(struct gpio_chip *gc, unsigned int gpio) { return -EINVAL; } -static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) +static int gpio_mmio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) { - return bgpio_dir_return(gc, gpio, false); + return gpio_mmio_dir_return(gc, gpio, false); } -static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio, - int val) +static int gpio_mmio_dir_out_err(struct gpio_chip *gc, unsigned int gpio, + int val) { return -EINVAL; } -static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, - int val) +static int gpio_mmio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, + int val) { gc->set(gc, gpio, val); - return bgpio_dir_return(gc, gpio, true); + return gpio_mmio_dir_return(gc, gpio, true); } -static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) +static int gpio_mmio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - unsigned long flags; - raw_spin_lock_irqsave(&chip->lock, flags); + scoped_guard(raw_spinlock, &chip->lock) { + chip->sdir &= ~gpio_mmio_line2mask(gc, gpio); - chip->sdir &= ~bgpio_line2mask(gc, gpio); - - if (chip->reg_dir_in) - chip->write_reg(chip->reg_dir_in, ~chip->sdir); - if (chip->reg_dir_out) - chip->write_reg(chip->reg_dir_out, chip->sdir); - - raw_spin_unlock_irqrestore(&chip->lock, flags); + if (chip->reg_dir_in) + chip->write_reg(chip->reg_dir_in, ~chip->sdir); + if (chip->reg_dir_out) + chip->write_reg(chip->reg_dir_out, chip->sdir); + } - return bgpio_dir_return(gc, gpio, false); + return gpio_mmio_dir_return(gc, gpio, false); } -static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) +static int gpio_mmio_get_dir(struct gpio_chip *gc, unsigned int gpio) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); /* Return 0 if output, 1 if input */ if (chip->dir_unreadable) { - if (chip->sdir & bgpio_line2mask(gc, gpio)) + if (chip->sdir & gpio_mmio_line2mask(gc, gpio)) return GPIO_LINE_DIRECTION_OUT; return GPIO_LINE_DIRECTION_IN; } if (chip->reg_dir_out) { - if (chip->read_reg(chip->reg_dir_out) & bgpio_line2mask(gc, gpio)) + if (chip->read_reg(chip->reg_dir_out) & gpio_mmio_line2mask(gc, gpio)) return GPIO_LINE_DIRECTION_OUT; return GPIO_LINE_DIRECTION_IN; } if (chip->reg_dir_in) - if (!(chip->read_reg(chip->reg_dir_in) & bgpio_line2mask(gc, gpio))) + if (!(chip->read_reg(chip->reg_dir_in) & gpio_mmio_line2mask(gc, gpio))) return GPIO_LINE_DIRECTION_OUT; return GPIO_LINE_DIRECTION_IN; } -static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +static void gpio_mmio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); - unsigned long flags; - raw_spin_lock_irqsave(&chip->lock, flags); + guard(raw_spinlock)(&chip->lock); - chip->sdir |= bgpio_line2mask(gc, gpio); + chip->sdir |= gpio_mmio_line2mask(gc, gpio); if (chip->reg_dir_in) chip->write_reg(chip->reg_dir_in, ~chip->sdir); if (chip->reg_dir_out) chip->write_reg(chip->reg_dir_out, chip->sdir); - - raw_spin_unlock_irqrestore(&chip->lock, flags); } -static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, - int val) +static int gpio_mmio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, + int val) { - bgpio_dir_out(gc, gpio, val); + gpio_mmio_dir_out(gc, gpio, val); gc->set(gc, gpio, val); - return bgpio_dir_return(gc, gpio, true); + return gpio_mmio_dir_return(gc, gpio, true); } -static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio, - int val) +static int gpio_mmio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio, + int val) { gc->set(gc, gpio, val); - bgpio_dir_out(gc, gpio, val); - return bgpio_dir_return(gc, gpio, true); + gpio_mmio_dir_out(gc, gpio, val); + return gpio_mmio_dir_return(gc, gpio, true); } -static int bgpio_setup_accessors(struct device *dev, - struct gpio_generic_chip *chip, - bool byte_be) +static int gpio_mmio_setup_accessors(struct device *dev, + struct gpio_generic_chip *chip, + bool byte_be) { switch (chip->bits) { case 8: - chip->read_reg = bgpio_read8; - chip->write_reg = bgpio_write8; + chip->read_reg = gpio_mmio_read8; + chip->write_reg = gpio_mmio_write8; break; case 16: if (byte_be) { - chip->read_reg = bgpio_read16be; - chip->write_reg = bgpio_write16be; + chip->read_reg = gpio_mmio_read16be; + chip->write_reg = gpio_mmio_write16be; } else { - chip->read_reg = bgpio_read16; - chip->write_reg = bgpio_write16; + chip->read_reg = gpio_mmio_read16; + chip->write_reg = gpio_mmio_write16; } break; case 32: if (byte_be) { - chip->read_reg = bgpio_read32be; - chip->write_reg = bgpio_write32be; + chip->read_reg = gpio_mmio_read32be; + chip->write_reg = gpio_mmio_write32be; } else { - chip->read_reg = bgpio_read32; - chip->write_reg = bgpio_write32; + chip->read_reg = gpio_mmio_read32; + chip->write_reg = gpio_mmio_write32; } break; #if BITS_PER_LONG >= 64 @@ -501,8 +491,8 @@ static int bgpio_setup_accessors(struct device *dev, "64 bit big endian byte order unsupported\n"); return -EINVAL; } else { - chip->read_reg = bgpio_read64; - chip->write_reg = bgpio_write64; + chip->read_reg = gpio_mmio_read64; + chip->write_reg = gpio_mmio_write64; } break; #endif /* BITS_PER_LONG >= 64 */ @@ -536,8 +526,8 @@ static int bgpio_setup_accessors(struct device *dev, * - an input direction register (named "dirin") where a 1 bit indicates * the GPIO is an input. */ -static int bgpio_setup_io(struct gpio_generic_chip *chip, - const struct gpio_generic_chip_config *cfg) +static int gpio_mmio_setup_io(struct gpio_generic_chip *chip, + const struct gpio_generic_chip_config *cfg) { struct gpio_chip *gc = &chip->gc; @@ -548,25 +538,25 @@ static int bgpio_setup_io(struct gpio_generic_chip *chip, if (cfg->set && cfg->clr) { chip->reg_set = cfg->set; chip->reg_clr = cfg->clr; - gc->set = bgpio_set_with_clear; - gc->set_multiple = bgpio_set_multiple_with_clear; + gc->set = gpio_mmio_set_with_clear; + gc->set_multiple = gpio_mmio_set_multiple_with_clear; } else if (cfg->set && !cfg->clr) { chip->reg_set = cfg->set; - gc->set = bgpio_set_set; - gc->set_multiple = bgpio_set_multiple_set; + gc->set = gpio_mmio_set_set; + gc->set_multiple = gpio_mmio_set_multiple_set; } else if (cfg->flags & GPIO_GENERIC_NO_OUTPUT) { - gc->set = bgpio_set_none; + gc->set = gpio_mmio_set_none; gc->set_multiple = NULL; } else { - gc->set = bgpio_set; - gc->set_multiple = bgpio_set_multiple; + gc->set = gpio_mmio_set; + gc->set_multiple = gpio_mmio_set_multiple; } if (!(cfg->flags & GPIO_GENERIC_UNREADABLE_REG_SET) && (cfg->flags & GPIO_GENERIC_READ_OUTPUT_REG_SET)) { - gc->get = bgpio_get_set; + gc->get = gpio_mmio_get_set; if (!chip->be_bits) - gc->get_multiple = bgpio_get_set_multiple; + gc->get_multiple = gpio_mmio_get_set_multiple; /* * We deliberately avoid assigning the ->get_multiple() call * for big endian mirrored registers which are ALSO reflecting @@ -575,18 +565,18 @@ static int bgpio_setup_io(struct gpio_generic_chip *chip, * reading each line individually in that fringe case. */ } else { - gc->get = bgpio_get; + gc->get = gpio_mmio_get; if (chip->be_bits) - gc->get_multiple = bgpio_get_multiple_be; + gc->get_multiple = gpio_mmio_get_multiple_be; else - gc->get_multiple = bgpio_get_multiple; + gc->get_multiple = gpio_mmio_get_multiple; } return 0; } -static int bgpio_setup_direction(struct gpio_generic_chip *chip, - const struct gpio_generic_chip_config *cfg) +static int gpio_mmio_setup_direction(struct gpio_generic_chip *chip, + const struct gpio_generic_chip_config *cfg) { struct gpio_chip *gc = &chip->gc; @@ -594,27 +584,27 @@ static int bgpio_setup_direction(struct gpio_generic_chip *chip, chip->reg_dir_out = cfg->dirout; chip->reg_dir_in = cfg->dirin; if (cfg->flags & GPIO_GENERIC_NO_SET_ON_INPUT) - gc->direction_output = bgpio_dir_out_dir_first; + gc->direction_output = gpio_mmio_dir_out_dir_first; else - gc->direction_output = bgpio_dir_out_val_first; - gc->direction_input = bgpio_dir_in; - gc->get_direction = bgpio_get_dir; + gc->direction_output = gpio_mmio_dir_out_val_first; + gc->direction_input = gpio_mmio_dir_in; + gc->get_direction = gpio_mmio_get_dir; } else { if (cfg->flags & GPIO_GENERIC_NO_OUTPUT) - gc->direction_output = bgpio_dir_out_err; + gc->direction_output = gpio_mmio_dir_out_err; else - gc->direction_output = bgpio_simple_dir_out; + gc->direction_output = gpio_mmio_simple_dir_out; if (cfg->flags & GPIO_GENERIC_NO_INPUT) - gc->direction_input = bgpio_dir_in_err; + gc->direction_input = gpio_mmio_dir_in_err; else - gc->direction_input = bgpio_simple_dir_in; + gc->direction_input = gpio_mmio_simple_dir_in; } return 0; } -static int bgpio_request(struct gpio_chip *gc, unsigned int gpio_pin) +static int gpio_mmio_request(struct gpio_chip *gc, unsigned int gpio_pin) { struct gpio_generic_chip *chip = to_gpio_generic_chip(gc); @@ -653,23 +643,23 @@ int gpio_generic_chip_init(struct gpio_generic_chip *chip, gc->parent = dev; gc->label = dev_name(dev); gc->base = -1; - gc->request = bgpio_request; + gc->request = gpio_mmio_request; chip->be_bits = !!(flags & GPIO_GENERIC_BIG_ENDIAN); ret = gpiochip_get_ngpios(gc, dev); if (ret) gc->ngpio = chip->bits; - ret = bgpio_setup_io(chip, cfg); + ret = gpio_mmio_setup_io(chip, cfg); if (ret) return ret; - ret = bgpio_setup_accessors(dev, chip, + ret = gpio_mmio_setup_accessors(dev, chip, flags & GPIO_GENERIC_BIG_ENDIAN_BYTE_ORDER); if (ret) return ret; - ret = bgpio_setup_direction(chip, cfg); + ret = gpio_mmio_setup_direction(chip, cfg); if (ret) return ret; @@ -680,7 +670,7 @@ int gpio_generic_chip_init(struct gpio_generic_chip *chip, } chip->sdata = chip->read_reg(chip->reg_dat); - if (gc->set == bgpio_set_set && + if (gc->set == gpio_mmio_set_set && !(flags & GPIO_GENERIC_UNREADABLE_REG_SET)) chip->sdata = chip->read_reg(chip->reg_set); @@ -712,9 +702,8 @@ EXPORT_SYMBOL_GPL(gpio_generic_chip_init); #if IS_ENABLED(CONFIG_GPIO_GENERIC_PLATFORM) -static void __iomem *bgpio_map(struct platform_device *pdev, - const char *name, - resource_size_t sane_sz) +static void __iomem *gpio_mmio_map(struct platform_device *pdev, + const char *name, resource_size_t sane_sz) { struct resource *r; resource_size_t sz; @@ -730,16 +719,16 @@ static void __iomem *bgpio_map(struct platform_device *pdev, return devm_ioremap_resource(&pdev->dev, r); } -static const struct of_device_id bgpio_of_match[] = { +static const struct of_device_id gpio_mmio_of_match[] = { { .compatible = "brcm,bcm6345-gpio" }, { .compatible = "wd,mbl-gpio" }, { .compatible = "ni,169445-nand-gpio" }, { .compatible = "intel,ixp4xx-expansion-bus-mmio-gpio" }, { } }; -MODULE_DEVICE_TABLE(of, bgpio_of_match); +MODULE_DEVICE_TABLE(of, gpio_mmio_of_match); -static int bgpio_pdev_probe(struct platform_device *pdev) +static int gpio_mmio_pdev_probe(struct platform_device *pdev) { struct gpio_generic_chip_config config; struct gpio_generic_chip *gen_gc; @@ -762,23 +751,23 @@ static int bgpio_pdev_probe(struct platform_device *pdev) sz = resource_size(r); - dat = bgpio_map(pdev, "dat", sz); + dat = gpio_mmio_map(pdev, "dat", sz); if (IS_ERR(dat)) return PTR_ERR(dat); - set = bgpio_map(pdev, "set", sz); + set = gpio_mmio_map(pdev, "set", sz); if (IS_ERR(set)) return PTR_ERR(set); - clr = bgpio_map(pdev, "clr", sz); + clr = gpio_mmio_map(pdev, "clr", sz); if (IS_ERR(clr)) return PTR_ERR(clr); - dirout = bgpio_map(pdev, "dirout", sz); + dirout = gpio_mmio_map(pdev, "dirout", sz); if (IS_ERR(dirout)) return PTR_ERR(dirout); - dirin = bgpio_map(pdev, "dirin", sz); + dirin = gpio_mmio_map(pdev, "dirin", sz); if (IS_ERR(dirin)) return PTR_ERR(dirin); @@ -824,25 +813,25 @@ static int bgpio_pdev_probe(struct platform_device *pdev) return devm_gpiochip_add_data(&pdev->dev, &gen_gc->gc, NULL); } -static const struct platform_device_id bgpio_id_table[] = { +static const struct platform_device_id gpio_mmio_id_table[] = { { .name = "basic-mmio-gpio", .driver_data = 0, }, { } }; -MODULE_DEVICE_TABLE(platform, bgpio_id_table); +MODULE_DEVICE_TABLE(platform, gpio_mmio_id_table); -static struct platform_driver bgpio_driver = { +static struct platform_driver gpio_mmio_driver = { .driver = { .name = "basic-mmio-gpio", - .of_match_table = bgpio_of_match, + .of_match_table = gpio_mmio_of_match, }, - .id_table = bgpio_id_table, - .probe = bgpio_pdev_probe, + .id_table = gpio_mmio_id_table, + .probe = gpio_mmio_pdev_probe, }; -module_platform_driver(bgpio_driver); +module_platform_driver(gpio_mmio_driver); #endif /* CONFIG_GPIO_GENERIC_PLATFORM */ diff --git a/drivers/gpio/gpio-mpsse.c b/drivers/gpio/gpio-mpsse.c index 9f42bb30b4ec..ace652ba4df1 100644 --- a/drivers/gpio/gpio-mpsse.c +++ b/drivers/gpio/gpio-mpsse.c @@ -10,6 +10,7 @@ #include <linux/cleanup.h> #include <linux/gpio/driver.h> #include <linux/mutex.h> +#include <linux/spinlock.h> #include <linux/usb.h> struct mpsse_priv { @@ -17,8 +18,10 @@ struct mpsse_priv { struct usb_device *udev; /* USB device encompassing all MPSSEs */ struct usb_interface *intf; /* USB interface for this MPSSE */ u8 intf_id; /* USB interface number for this MPSSE */ - struct work_struct irq_work; /* polling work thread */ + struct list_head workers; /* polling work threads */ struct mutex irq_mutex; /* lock over irq_data */ + struct mutex irq_race; /* race for polling worker teardown */ + raw_spinlock_t irq_spin; /* protects worker list */ atomic_t irq_type[16]; /* pin -> edge detection type */ atomic_t irq_enabled; int id; @@ -26,6 +29,9 @@ struct mpsse_priv { u8 gpio_outputs[2]; /* Output states for GPIOs [L, H] */ u8 gpio_dir[2]; /* Directions for GPIOs [L, H] */ + unsigned long dir_in; /* Bitmask of valid input pins */ + unsigned long dir_out; /* Bitmask of valid output pins */ + u8 *bulk_in_buf; /* Extra recv buffer to grab status bytes */ struct usb_endpoint_descriptor *bulk_in; @@ -34,6 +40,14 @@ struct mpsse_priv { struct mutex io_mutex; /* sync I/O with disconnect */ }; +struct mpsse_worker { + struct mpsse_priv *priv; + struct work_struct work; + atomic_t cancelled; + struct list_head list; /* linked list */ + struct list_head destroy; /* teardown linked list */ +}; + struct bulk_desc { bool tx; /* direction of bulk transfer */ u8 *data; /* input (tx) or output (rx) */ @@ -43,8 +57,27 @@ struct bulk_desc { int timeout; }; +#define MPSSE_NGPIO 16 + +struct mpsse_quirk { + const char *names[MPSSE_NGPIO]; /* Pin names, if applicable */ + unsigned long dir_in; /* Bitmask of valid input pins */ + unsigned long dir_out; /* Bitmask of valid output pins */ +}; + +static struct mpsse_quirk bryx_brik_quirk = { + .names = { + [3] = "Push to Talk", + [5] = "Channel Activity", + }, + .dir_out = BIT(3), /* Push to Talk */ + .dir_in = BIT(5), /* Channel Activity */ +}; + static const struct usb_device_id gpio_mpsse_table[] = { { USB_DEVICE(0x0c52, 0xa064) }, /* SeaLevel Systems, Inc. */ + { USB_DEVICE(0x0403, 0x6988), /* FTDI, assigned to Bryx */ + .driver_info = (kernel_ulong_t)&bryx_brik_quirk}, { } /* Terminating entry */ }; @@ -160,6 +193,32 @@ static int gpio_mpsse_get_bank(struct mpsse_priv *priv, u8 bank) return buf; } +static int mpsse_ensure_supported(struct gpio_chip *chip, + unsigned long mask, int direction) +{ + unsigned long supported, unsupported; + char *type = "input"; + struct mpsse_priv *priv = gpiochip_get_data(chip); + + supported = priv->dir_in; + if (direction == GPIO_LINE_DIRECTION_OUT) { + supported = priv->dir_out; + type = "output"; + } + + /* An invalid bit was in the provided mask */ + unsupported = mask & ~supported; + if (unsupported) { + dev_err(&priv->udev->dev, + "mpsse: GPIO %lu doesn't support %s\n", + find_first_bit(&unsupported, sizeof(unsupported) * 8), + type); + return -EOPNOTSUPP; + } + + return 0; +} + static int gpio_mpsse_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { @@ -167,6 +226,10 @@ static int gpio_mpsse_set_multiple(struct gpio_chip *chip, unsigned long *mask, int ret; struct mpsse_priv *priv = gpiochip_get_data(chip); + ret = mpsse_ensure_supported(chip, *mask, GPIO_LINE_DIRECTION_OUT); + if (ret) + return ret; + guard(mutex)(&priv->io_mutex); for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { bank = i / 8; @@ -194,6 +257,10 @@ static int gpio_mpsse_get_multiple(struct gpio_chip *chip, unsigned long *mask, int ret; struct mpsse_priv *priv = gpiochip_get_data(chip); + ret = mpsse_ensure_supported(chip, *mask, GPIO_LINE_DIRECTION_IN); + if (ret) + return ret; + guard(mutex)(&priv->io_mutex); for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { bank = i / 8; @@ -242,10 +309,15 @@ static int gpio_mpsse_gpio_set(struct gpio_chip *chip, unsigned int offset, static int gpio_mpsse_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { + int ret; struct mpsse_priv *priv = gpiochip_get_data(chip); int bank = (offset & 8) >> 3; int bank_offset = offset & 7; + ret = mpsse_ensure_supported(chip, BIT(offset), GPIO_LINE_DIRECTION_OUT); + if (ret) + return ret; + scoped_guard(mutex, &priv->io_mutex) priv->gpio_dir[bank] |= BIT(bank_offset); @@ -255,15 +327,19 @@ static int gpio_mpsse_direction_output(struct gpio_chip *chip, static int gpio_mpsse_direction_input(struct gpio_chip *chip, unsigned int offset) { + int ret; struct mpsse_priv *priv = gpiochip_get_data(chip); int bank = (offset & 8) >> 3; int bank_offset = offset & 7; + ret = mpsse_ensure_supported(chip, BIT(offset), GPIO_LINE_DIRECTION_IN); + if (ret) + return ret; + guard(mutex)(&priv->io_mutex); priv->gpio_dir[bank] &= ~BIT(bank_offset); - gpio_mpsse_set_bank(priv, bank); - return 0; + return gpio_mpsse_set_bank(priv, bank); } static int gpio_mpsse_get_direction(struct gpio_chip *chip, @@ -284,18 +360,62 @@ static int gpio_mpsse_get_direction(struct gpio_chip *chip, return ret; } -static void gpio_mpsse_poll(struct work_struct *work) +/* + * Stops all workers except `my_worker`. + * Safe to call only when `irq_race` is held. + */ +static void gpio_mpsse_stop_all_except(struct mpsse_priv *priv, + struct mpsse_worker *my_worker) +{ + struct mpsse_worker *worker, *worker_tmp; + struct list_head destructors = LIST_HEAD_INIT(destructors); + + scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) { + list_for_each_entry_safe(worker, worker_tmp, + &priv->workers, list) { + /* Don't stop ourselves */ + if (worker == my_worker) + continue; + + list_del(&worker->list); + + /* Give worker a chance to terminate itself */ + atomic_set(&worker->cancelled, 1); + /* Keep track of stuff to cancel */ + INIT_LIST_HEAD(&worker->destroy); + list_add(&worker->destroy, &destructors); + } + } + + list_for_each_entry_safe(worker, worker_tmp, + &destructors, destroy) { + list_del(&worker->destroy); + cancel_work_sync(&worker->work); + kfree(worker); + } +} + +static void gpio_mpsse_poll(struct work_struct *my_work) { unsigned long pin_mask, pin_states, flags; int irq_enabled, offset, err, value, fire_irq, irq, old_value[16], irq_type[16]; - struct mpsse_priv *priv = container_of(work, struct mpsse_priv, - irq_work); + struct mpsse_worker *my_worker = container_of(my_work, struct mpsse_worker, work); + struct mpsse_priv *priv = my_worker->priv; for (offset = 0; offset < priv->gpio.ngpio; ++offset) old_value[offset] = -1; - while ((irq_enabled = atomic_read(&priv->irq_enabled))) { + /* + * We only want one worker. Workers race to acquire irq_race and tear + * down all other workers. This is a cond guard so that we don't deadlock + * trying to cancel a worker. + */ + scoped_cond_guard(mutex_try, return, &priv->irq_race) + gpio_mpsse_stop_all_except(priv, my_worker); + + while ((irq_enabled = atomic_read(&priv->irq_enabled)) && + !atomic_read(&my_worker->cancelled)) { usleep_range(MPSSE_POLL_INTERVAL, MPSSE_POLL_INTERVAL + 1000); /* Cleanup will trigger at the end of the loop */ guard(mutex)(&priv->irq_mutex); @@ -370,21 +490,45 @@ static int gpio_mpsse_set_irq_type(struct irq_data *irqd, unsigned int type) static void gpio_mpsse_irq_disable(struct irq_data *irqd) { + struct mpsse_worker *worker; struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); atomic_and(~BIT(irqd->hwirq), &priv->irq_enabled); gpiochip_disable_irq(&priv->gpio, irqd->hwirq); + + /* + * Can't actually do teardown in IRQ context (it blocks). + * As a result, these workers will stick around until irq is reenabled + * or device gets disconnected + */ + scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) + list_for_each_entry(worker, &priv->workers, list) + atomic_set(&worker->cancelled, 1); } static void gpio_mpsse_irq_enable(struct irq_data *irqd) { + struct mpsse_worker *worker; struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); gpiochip_enable_irq(&priv->gpio, irqd->hwirq); /* If no-one else was using the IRQ, enable it */ if (!atomic_fetch_or(BIT(irqd->hwirq), &priv->irq_enabled)) { - INIT_WORK(&priv->irq_work, gpio_mpsse_poll); - schedule_work(&priv->irq_work); + /* + * Can't be devm because it uses a non-raw spinlock (illegal in + * this context, where a raw spinlock is held by our caller) + */ + worker = kzalloc(sizeof(*worker), GFP_NOWAIT); + if (!worker) + return; + + worker->priv = priv; + INIT_LIST_HEAD(&worker->list); + INIT_WORK(&worker->work, gpio_mpsse_poll); + schedule_work(&worker->work); + + scoped_guard(raw_spinlock_irqsave, &priv->irq_spin) + list_add(&worker->list, &priv->workers); } } @@ -404,18 +548,49 @@ static void gpio_mpsse_ida_remove(void *data) ida_free(&gpio_mpsse_ida, priv->id); } +static int mpsse_init_valid_mask(struct gpio_chip *chip, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct mpsse_priv *priv = gpiochip_get_data(chip); + + if (WARN_ON(priv == NULL)) + return -ENODEV; + + *valid_mask = priv->dir_in | priv->dir_out; + + return 0; +} + +static void mpsse_irq_init_valid_mask(struct gpio_chip *chip, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct mpsse_priv *priv = gpiochip_get_data(chip); + + if (WARN_ON(priv == NULL)) + return; + + /* Can only use IRQ on input capable pins */ + *valid_mask = priv->dir_in; +} + static int gpio_mpsse_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct mpsse_priv *priv; struct device *dev; + char *serial; int err; + struct mpsse_quirk *quirk = (void *)id->driver_info; dev = &interface->dev; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + INIT_LIST_HEAD(&priv->workers); + priv->udev = usb_get_dev(interface_to_usbdev(interface)); priv->intf = interface; priv->intf_id = interface->cur_altsetting->desc.bInterfaceNumber; @@ -436,9 +611,21 @@ static int gpio_mpsse_probe(struct usb_interface *interface, if (err) return err; + err = devm_mutex_init(dev, &priv->irq_race); + if (err) + return err; + + raw_spin_lock_init(&priv->irq_spin); + + serial = priv->udev->serial; + if (!serial) + serial = "NONE"; + priv->gpio.label = devm_kasprintf(dev, GFP_KERNEL, - "gpio-mpsse.%d.%d", - priv->id, priv->intf_id); + "MPSSE%04x:%04x.%d.%d.%s", + id->idVendor, id->idProduct, + priv->intf_id, priv->id, + serial); if (!priv->gpio.label) return -ENOMEM; @@ -452,10 +639,20 @@ static int gpio_mpsse_probe(struct usb_interface *interface, priv->gpio.get_multiple = gpio_mpsse_get_multiple; priv->gpio.set_multiple = gpio_mpsse_set_multiple; priv->gpio.base = -1; - priv->gpio.ngpio = 16; + priv->gpio.ngpio = MPSSE_NGPIO; priv->gpio.offset = priv->intf_id * priv->gpio.ngpio; priv->gpio.can_sleep = 1; + if (quirk) { + priv->dir_out = quirk->dir_out; + priv->dir_in = quirk->dir_in; + priv->gpio.names = quirk->names; + priv->gpio.init_valid_mask = mpsse_init_valid_mask; + } else { + priv->dir_in = U16_MAX; + priv->dir_out = U16_MAX; + } + err = usb_find_common_endpoints(interface->cur_altsetting, &priv->bulk_in, &priv->bulk_out, NULL, NULL); @@ -494,6 +691,7 @@ static int gpio_mpsse_probe(struct usb_interface *interface, priv->gpio.irq.parents = NULL; priv->gpio.irq.default_type = IRQ_TYPE_NONE; priv->gpio.irq.handler = handle_simple_irq; + priv->gpio.irq.init_valid_mask = mpsse_irq_init_valid_mask; err = devm_gpiochip_add_data(dev, &priv->gpio, priv); if (err) @@ -506,6 +704,13 @@ static void gpio_mpsse_disconnect(struct usb_interface *intf) { struct mpsse_priv *priv = usb_get_intfdata(intf); + /* + * Lock prevents double-free of worker from here and the teardown + * step at the beginning of gpio_mpsse_poll + */ + scoped_guard(mutex, &priv->irq_race) + gpio_mpsse_stop_all_except(priv, NULL); + priv->intf = NULL; usb_set_intfdata(intf, NULL); usb_put_dev(priv->udev); diff --git a/drivers/gpio/gpio-msc313.c b/drivers/gpio/gpio-msc313.c index b0cccd856840..7345afdc78de 100644 --- a/drivers/gpio/gpio-msc313.c +++ b/drivers/gpio/gpio-msc313.c @@ -694,7 +694,7 @@ static const struct of_device_id msc313_gpio_of_match[] = { * SoC goes into suspend to memory mode so we need to save some * of the register bits before suspending and put it back when resuming */ -static int __maybe_unused msc313_gpio_suspend(struct device *dev) +static int msc313_gpio_suspend(struct device *dev) { struct msc313_gpio *gpio = dev_get_drvdata(dev); int i; @@ -705,7 +705,7 @@ static int __maybe_unused msc313_gpio_suspend(struct device *dev) return 0; } -static int __maybe_unused msc313_gpio_resume(struct device *dev) +static int msc313_gpio_resume(struct device *dev) { struct msc313_gpio *gpio = dev_get_drvdata(dev); int i; @@ -716,13 +716,13 @@ static int __maybe_unused msc313_gpio_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(msc313_gpio_ops, msc313_gpio_suspend, msc313_gpio_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(msc313_gpio_ops, msc313_gpio_suspend, msc313_gpio_resume); static struct platform_driver msc313_gpio_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = msc313_gpio_of_match, - .pm = &msc313_gpio_ops, + .pm = pm_sleep_ptr(&msc313_gpio_ops), }, .probe = msc313_gpio_probe, }; diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index ac799fced950..22c36b79e249 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -573,11 +573,10 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) for (i = 0; i < mvchip->chip.ngpio; i++) { int irq; - irq = irq_find_mapping(mvchip->domain, i); - if (!(cause & BIT(i))) continue; + irq = irq_find_mapping(mvchip->domain, i); type = irq_get_trigger_type(irq); if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { /* Swap polarity (race with GPIO line) */ diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index a268c76bdca6..e136e81794df 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1503,7 +1503,7 @@ static void omap_gpio_remove(struct platform_device *pdev) clk_unprepare(bank->dbck); } -static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev) +static int omap_gpio_runtime_suspend(struct device *dev) { struct gpio_bank *bank = dev_get_drvdata(dev); unsigned long flags; @@ -1516,7 +1516,7 @@ static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused omap_gpio_runtime_resume(struct device *dev) +static int omap_gpio_runtime_resume(struct device *dev) { struct gpio_bank *bank = dev_get_drvdata(dev); unsigned long flags; @@ -1529,7 +1529,7 @@ static int __maybe_unused omap_gpio_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused omap_gpio_suspend(struct device *dev) +static int omap_gpio_suspend(struct device *dev) { struct gpio_bank *bank = dev_get_drvdata(dev); @@ -1541,7 +1541,7 @@ static int __maybe_unused omap_gpio_suspend(struct device *dev) return omap_gpio_runtime_suspend(dev); } -static int __maybe_unused omap_gpio_resume(struct device *dev) +static int omap_gpio_resume(struct device *dev) { struct gpio_bank *bank = dev_get_drvdata(dev); @@ -1554,9 +1554,8 @@ static int __maybe_unused omap_gpio_resume(struct device *dev) } static const struct dev_pm_ops gpio_pm_ops = { - SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, - NULL) - SET_LATE_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) + RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, NULL) + LATE_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) }; static struct platform_driver omap_gpio_driver = { @@ -1564,7 +1563,7 @@ static struct platform_driver omap_gpio_driver = { .remove = omap_gpio_remove, .driver = { .name = "omap_gpio", - .pm = &gpio_pm_ops, + .pm = pm_ptr(&gpio_pm_ops), .of_match_table = omap_gpio_match, }, }; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index b46927f55038..0a3916cc2772 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -306,7 +306,7 @@ static inline u8 pca953x_get_bit_mask(struct pca953x_chip *chip, unsigned int of * Interrupt mask register 0x40 + 5 * bank_size RW * Interrupt status register 0x40 + 6 * bank_size R * - * - Registers with bit 0x80 set, the AI bit + * - Registers with bit 0x80 set, the AI bit (auto increment) * The bit is cleared and the registers fall into one of the * categories above. */ @@ -854,10 +854,13 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) int level; if (chip->driver_data & PCA_PCAL) { + DECLARE_BITMAP(latched_inputs, MAX_LINE); guard(mutex)(&chip->i2c_lock); - /* Enable latch on interrupt-enabled inputs */ - pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask); + /* Enable latch on edge-triggered interrupt-enabled inputs */ + bitmap_or(latched_inputs, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio); + bitmap_and(latched_inputs, latched_inputs, chip->irq_mask, gc->ngpio); + pca953x_write_regs(chip, PCAL953X_IN_LATCH, latched_inputs); bitmap_complement(irq_mask, chip->irq_mask, gc->ngpio); @@ -1203,10 +1206,10 @@ static int pca953x_probe(struct i2c_client *client) pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { - dev_info(dev, "using AI\n"); + dev_info(dev, "using auto increment\n"); regmap_config = &pca953x_ai_i2c_regmap; } else { - dev_info(dev, "using no AI\n"); + dev_info(dev, "using no auto increment\n"); regmap_config = &pca953x_i2c_regmap; } diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 9925687e05fb..4ffa0955a9e3 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -171,7 +171,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr) /* * Save register configuration and disable interrupts. */ -static void __maybe_unused pch_gpio_save_reg_conf(struct pch_gpio *chip) +static void pch_gpio_save_reg_conf(struct pch_gpio *chip) { chip->pch_gpio_reg.ien_reg = ioread32(&chip->reg->ien); chip->pch_gpio_reg.imask_reg = ioread32(&chip->reg->imask); @@ -187,7 +187,7 @@ static void __maybe_unused pch_gpio_save_reg_conf(struct pch_gpio *chip) /* * This function restores the register configuration of the GPIO device. */ -static void __maybe_unused pch_gpio_restore_reg_conf(struct pch_gpio *chip) +static void pch_gpio_restore_reg_conf(struct pch_gpio *chip) { iowrite32(chip->pch_gpio_reg.ien_reg, &chip->reg->ien); iowrite32(chip->pch_gpio_reg.imask_reg, &chip->reg->imask); @@ -402,7 +402,7 @@ static int pch_gpio_probe(struct pci_dev *pdev, return pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]); } -static int __maybe_unused pch_gpio_suspend(struct device *dev) +static int pch_gpio_suspend(struct device *dev) { struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; @@ -414,7 +414,7 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev) return 0; } -static int __maybe_unused pch_gpio_resume(struct device *dev) +static int pch_gpio_resume(struct device *dev) { struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; @@ -428,7 +428,7 @@ static int __maybe_unused pch_gpio_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume); static const struct pci_device_id pch_gpio_pcidev_id[] = { { PCI_DEVICE_DATA(INTEL, EG20T_PCH, INTEL_EG20T_PCH) }, @@ -444,7 +444,7 @@ static struct pci_driver pch_gpio_driver = { .id_table = pch_gpio_pcidev_id, .probe = pch_gpio_probe, .driver = { - .pm = &pch_gpio_pm_ops, + .pm = pm_sleep_ptr(&pch_gpio_pm_ops), }, }; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 02e4ffcf5a6f..919cf86fd590 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -37,7 +37,6 @@ #define PL061_GPIO_NR 8 -#ifdef CONFIG_PM struct pl061_context_save_regs { u8 gpio_data; u8 gpio_dir; @@ -46,7 +45,6 @@ struct pl061_context_save_regs { u8 gpio_iev; u8 gpio_ie; }; -#endif struct pl061 { raw_spinlock_t lock; @@ -55,9 +53,7 @@ struct pl061 { struct gpio_chip gc; int parent_irq; -#ifdef CONFIG_PM struct pl061_context_save_regs csave_regs; -#endif }; static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) @@ -367,7 +363,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) return 0; } -#ifdef CONFIG_PM static int pl061_suspend(struct device *dev) { struct pl061 *pl061 = dev_get_drvdata(dev); @@ -411,13 +406,7 @@ static int pl061_resume(struct device *dev) return 0; } -static const struct dev_pm_ops pl061_dev_pm_ops = { - .suspend = pl061_suspend, - .resume = pl061_resume, - .freeze = pl061_suspend, - .restore = pl061_resume, -}; -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume); static const struct amba_id pl061_ids[] = { { @@ -431,9 +420,7 @@ MODULE_DEVICE_TABLE(amba, pl061_ids); static struct amba_driver pl061_gpio_driver = { .drv = { .name = "pl061_gpio", -#ifdef CONFIG_PM - .pm = &pl061_dev_pm_ops, -#endif + .pm = pm_sleep_ptr(&pl061_dev_pm_ops), }, .id_table = pl061_ids, .probe = pl061_probe, diff --git a/drivers/gpio/gpio-qixis-fpga.c b/drivers/gpio/gpio-qixis-fpga.c new file mode 100644 index 000000000000..6e67f43ac0bd --- /dev/null +++ b/drivers/gpio/gpio-qixis-fpga.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Layerscape GPIO QIXIS FPGA driver + * + * Copyright 2025 NXP + */ + +#include <linux/device.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/regmap.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +struct qixis_cpld_gpio_config { + u64 output_lines; +}; + +static const struct qixis_cpld_gpio_config lx2160ardb_sfp_cfg = { + .output_lines = BIT(0), +}; + +static const struct qixis_cpld_gpio_config ls1046aqds_stat_pres2_cfg = { + .output_lines = 0x0, +}; + +static const struct regmap_config regmap_config_8r_8v = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int qixis_cpld_gpio_probe(struct platform_device *pdev) +{ + DECLARE_BITMAP(fixed_direction_output, 8); + const struct qixis_cpld_gpio_config *cfg; + struct gpio_regmap_config config = {0}; + struct regmap *regmap; + void __iomem *reg; + u32 base; + int ret; + + if (!pdev->dev.parent) + return -ENODEV; + + cfg = device_get_match_data(&pdev->dev); + + ret = device_property_read_u32(&pdev->dev, "reg", &base); + if (ret) + return ret; + + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!regmap) { + /* In case there is no regmap configured by the parent device, + * create our own from the MMIO space. + */ + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + regmap = devm_regmap_init_mmio(&pdev->dev, reg, ®map_config_8r_8v); + if (!regmap) + return -ENODEV; + + /* In this case, the offset of our register is 0 inside the + * regmap area that we just created. + */ + base = 0; + } + config.reg_dat_base = GPIO_REGMAP_ADDR(base); + config.reg_set_base = GPIO_REGMAP_ADDR(base); + + config.drvdata = (void *)cfg; + config.regmap = regmap; + config.parent = &pdev->dev; + config.ngpio_per_reg = 8; + config.ngpio = 8; + + bitmap_from_u64(fixed_direction_output, cfg->output_lines); + config.fixed_direction_output = fixed_direction_output; + + return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(&pdev->dev, &config)); +} + +static const struct of_device_id qixis_cpld_gpio_of_match[] = { + { + .compatible = "fsl,lx2160ardb-fpga-gpio-sfp", + .data = &lx2160ardb_sfp_cfg, + }, + { + .compatible = "fsl,ls1046aqds-fpga-gpio-stat-pres2", + .data = &ls1046aqds_stat_pres2_cfg, + }, + + {} +}; +MODULE_DEVICE_TABLE(of, qixis_cpld_gpio_of_match); + +static struct platform_driver qixis_cpld_gpio_driver = { + .probe = qixis_cpld_gpio_probe, + .driver = { + .name = "gpio-qixis-cpld", + .of_match_table = qixis_cpld_gpio_of_match, + }, +}; +module_platform_driver(qixis_cpld_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>"); +MODULE_DESCRIPTION("Layerscape GPIO QIXIS FPGA driver"); diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index f4267af00027..e5ba38e65c10 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -82,7 +82,11 @@ static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - ret = regmap_read(gpio->regmap, reg, &val); + /* ensure we don't spoil any register cache with pin input values */ + if (gpio->reg_dat_base == gpio->reg_set_base) + ret = regmap_read_bypassed(gpio->regmap, reg, &val); + else + ret = regmap_read(gpio->regmap, reg, &val); if (ret) return ret; @@ -94,7 +98,7 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset, { struct gpio_regmap *gpio = gpiochip_get_data(chip); unsigned int base = gpio_regmap_addr(gpio->reg_set_base); - unsigned int reg, mask; + unsigned int reg, mask, mask_val; int ret; ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); @@ -102,9 +106,15 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset, return ret; if (val) - ret = regmap_update_bits(gpio->regmap, reg, mask, mask); + mask_val = mask; + else + mask_val = 0; + + /* ignore input values which shadow the old output value */ + if (gpio->reg_dat_base == gpio->reg_set_base) + ret = regmap_write_bits(gpio->regmap, reg, mask, mask_val); else - ret = regmap_update_bits(gpio->regmap, reg, mask, 0); + ret = regmap_update_bits(gpio->regmap, reg, mask, mask_val); return ret; } diff --git a/drivers/gpio/gpio-shared-proxy.c b/drivers/gpio/gpio-shared-proxy.c index 3ef2c40ed152..29d7d2e4dfc0 100644 --- a/drivers/gpio/gpio-shared-proxy.c +++ b/drivers/gpio/gpio-shared-proxy.c @@ -322,6 +322,7 @@ MODULE_DEVICE_TABLE(auxiliary, gpio_shared_proxy_id_table); static struct auxiliary_driver gpio_shared_proxy_driver = { .driver = { .name = "gpio-shared-proxy", + .suppress_bind_attrs = true, }, .probe = gpio_shared_proxy_probe, .id_table = gpio_shared_proxy_id_table, diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 4d3db6e06eeb..b1498b59a921 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2022 NVIDIA Corporation + * Copyright (c) 2016-2025 NVIDIA Corporation * * Author: Thierry Reding <treding@nvidia.com> * Dipen Patel <dpatel@nvidia.com> @@ -69,6 +69,30 @@ #define TEGRA186_GPIO_INTERRUPT_STATUS(x) (0x100 + (x) * 4) +/* Tegra410 GPIOs implemented by the COMPUTE GPIO controller */ +#define TEGRA410_COMPUTE_GPIO_PORT_A 0 +#define TEGRA410_COMPUTE_GPIO_PORT_B 1 +#define TEGRA410_COMPUTE_GPIO_PORT_C 2 +#define TEGRA410_COMPUTE_GPIO_PORT_D 3 +#define TEGRA410_COMPUTE_GPIO_PORT_E 4 + +/* Tegra410 GPIOs implemented by the SYSTEM GPIO controller */ +#define TEGRA410_SYSTEM_GPIO_PORT_A 0 +#define TEGRA410_SYSTEM_GPIO_PORT_B 1 +#define TEGRA410_SYSTEM_GPIO_PORT_C 2 +#define TEGRA410_SYSTEM_GPIO_PORT_D 3 +#define TEGRA410_SYSTEM_GPIO_PORT_E 4 +#define TEGRA410_SYSTEM_GPIO_PORT_I 5 +#define TEGRA410_SYSTEM_GPIO_PORT_J 6 +#define TEGRA410_SYSTEM_GPIO_PORT_K 7 +#define TEGRA410_SYSTEM_GPIO_PORT_L 8 +#define TEGRA410_SYSTEM_GPIO_PORT_M 9 +#define TEGRA410_SYSTEM_GPIO_PORT_N 10 +#define TEGRA410_SYSTEM_GPIO_PORT_P 11 +#define TEGRA410_SYSTEM_GPIO_PORT_Q 12 +#define TEGRA410_SYSTEM_GPIO_PORT_R 13 +#define TEGRA410_SYSTEM_GPIO_PORT_V 14 + struct tegra_gpio_port { const char *name; unsigned int bank; @@ -85,6 +109,7 @@ struct tegra_gpio_soc { const struct tegra_gpio_port *ports; unsigned int num_ports; const char *name; + const char *prefix; unsigned int instance; unsigned int num_irqs_per_bank; @@ -916,8 +941,12 @@ static int tegra186_gpio_probe(struct platform_device *pdev) char *name; for (j = 0; j < port->pins; j++) { - name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL, - "P%s.%02x", port->name, j); + if (gpio->soc->prefix) + name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL, "%s-P%s.%02x", + gpio->soc->prefix, port->name, j); + else + name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL, "P%s.%02x", + port->name, j); if (!name) return -ENOMEM; @@ -1002,14 +1031,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev) return devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio); } -#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA186_MAIN_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ +#define TEGRA_GPIO_PORT(_prefix, _name, _bank, _port, _pins) \ + [_prefix##_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } +#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA186_MAIN, _name, _bank, _port, _pins) + static const struct tegra_gpio_port tegra186_main_ports[] = { TEGRA186_MAIN_GPIO_PORT( A, 2, 0, 7), TEGRA186_MAIN_GPIO_PORT( B, 3, 0, 7), @@ -1045,13 +1077,8 @@ static const struct tegra_gpio_soc tegra186_main_soc = { .has_vm_support = false, }; -#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA186_AON_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ - } +#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA186_AON, _name, _bank, _port, _pins) static const struct tegra_gpio_port tegra186_aon_ports[] = { TEGRA186_AON_GPIO_PORT( S, 0, 1, 5), @@ -1073,13 +1100,8 @@ static const struct tegra_gpio_soc tegra186_aon_soc = { .has_vm_support = false, }; -#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA194_MAIN_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ - } +#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA194_MAIN, _name, _bank, _port, _pins) static const struct tegra_gpio_port tegra194_main_ports[] = { TEGRA194_MAIN_GPIO_PORT( A, 1, 2, 8), @@ -1129,13 +1151,8 @@ static const struct tegra_gpio_soc tegra194_main_soc = { .has_vm_support = true, }; -#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA194_AON_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ - } +#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA194_AON, _name, _bank, _port, _pins) static const struct tegra_gpio_port tegra194_aon_ports[] = { TEGRA194_AON_GPIO_PORT(AA, 0, 3, 8), @@ -1155,13 +1172,8 @@ static const struct tegra_gpio_soc tegra194_aon_soc = { .has_vm_support = false, }; -#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA234_MAIN_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ - } +#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA234_MAIN, _name, _bank, _port, _pins) static const struct tegra_gpio_port tegra234_main_ports[] = { TEGRA234_MAIN_GPIO_PORT( A, 0, 0, 8), @@ -1200,13 +1212,8 @@ static const struct tegra_gpio_soc tegra234_main_soc = { .has_vm_support = true, }; -#define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA234_AON_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ - } +#define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA234_AON, _name, _bank, _port, _pins) static const struct tegra_gpio_port tegra234_aon_ports[] = { TEGRA234_AON_GPIO_PORT(AA, 0, 4, 8), @@ -1227,13 +1234,8 @@ static const struct tegra_gpio_soc tegra234_aon_soc = { .has_vm_support = false, }; -#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA241_MAIN_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ - } +#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA241_MAIN, _name, _bank, _port, _pins) static const struct tegra_gpio_port tegra241_main_ports[] = { TEGRA241_MAIN_GPIO_PORT(A, 0, 0, 8), @@ -1258,13 +1260,8 @@ static const struct tegra_gpio_soc tegra241_main_soc = { .has_vm_support = false, }; -#define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA241_AON_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ - } +#define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA241_AON, _name, _bank, _port, _pins) static const struct tegra_gpio_port tegra241_aon_ports[] = { TEGRA241_AON_GPIO_PORT(AA, 0, 0, 8), @@ -1280,13 +1277,8 @@ static const struct tegra_gpio_soc tegra241_aon_soc = { .has_vm_support = false, }; -#define TEGRA256_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ - [TEGRA256_MAIN_GPIO_PORT_##_name] = { \ - .name = #_name, \ - .bank = _bank, \ - .port = _port, \ - .pins = _pins, \ - } +#define TEGRA256_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA256_MAIN, _name, _bank, _port, _pins) static const struct tegra_gpio_port tegra256_main_ports[] = { TEGRA256_MAIN_GPIO_PORT(A, 0, 0, 8), @@ -1304,6 +1296,56 @@ static const struct tegra_gpio_soc tegra256_main_soc = { .has_vm_support = true, }; +#define TEGRA410_COMPUTE_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA410_COMPUTE, _name, _bank, _port, _pins) + +static const struct tegra_gpio_port tegra410_compute_ports[] = { + TEGRA410_COMPUTE_GPIO_PORT(A, 0, 0, 3), + TEGRA410_COMPUTE_GPIO_PORT(B, 1, 0, 8), + TEGRA410_COMPUTE_GPIO_PORT(C, 1, 1, 3), + TEGRA410_COMPUTE_GPIO_PORT(D, 2, 0, 8), + TEGRA410_COMPUTE_GPIO_PORT(E, 2, 1, 8), +}; + +static const struct tegra_gpio_soc tegra410_compute_soc = { + .num_ports = ARRAY_SIZE(tegra410_compute_ports), + .ports = tegra410_compute_ports, + .name = "tegra410-gpio-compute", + .prefix = "COMPUTE", + .num_irqs_per_bank = 8, + .instance = 0, +}; + +#define TEGRA410_SYSTEM_GPIO_PORT(_name, _bank, _port, _pins) \ + TEGRA_GPIO_PORT(TEGRA410_SYSTEM, _name, _bank, _port, _pins) + +static const struct tegra_gpio_port tegra410_system_ports[] = { + TEGRA410_SYSTEM_GPIO_PORT(A, 0, 0, 7), + TEGRA410_SYSTEM_GPIO_PORT(B, 0, 1, 8), + TEGRA410_SYSTEM_GPIO_PORT(C, 0, 2, 8), + TEGRA410_SYSTEM_GPIO_PORT(D, 0, 3, 8), + TEGRA410_SYSTEM_GPIO_PORT(E, 0, 4, 6), + TEGRA410_SYSTEM_GPIO_PORT(I, 1, 0, 8), + TEGRA410_SYSTEM_GPIO_PORT(J, 1, 1, 7), + TEGRA410_SYSTEM_GPIO_PORT(K, 1, 2, 7), + TEGRA410_SYSTEM_GPIO_PORT(L, 1, 3, 7), + TEGRA410_SYSTEM_GPIO_PORT(M, 2, 0, 7), + TEGRA410_SYSTEM_GPIO_PORT(N, 2, 1, 6), + TEGRA410_SYSTEM_GPIO_PORT(P, 2, 2, 8), + TEGRA410_SYSTEM_GPIO_PORT(Q, 2, 3, 3), + TEGRA410_SYSTEM_GPIO_PORT(R, 2, 4, 2), + TEGRA410_SYSTEM_GPIO_PORT(V, 1, 4, 2), +}; + +static const struct tegra_gpio_soc tegra410_system_soc = { + .num_ports = ARRAY_SIZE(tegra410_system_ports), + .ports = tegra410_system_ports, + .name = "tegra410-gpio-system", + .prefix = "SYSTEM", + .num_irqs_per_bank = 8, + .instance = 0, +}; + static const struct of_device_id tegra186_gpio_of_match[] = { { .compatible = "nvidia,tegra186-gpio", @@ -1339,6 +1381,8 @@ static const struct acpi_device_id tegra186_gpio_acpi_match[] = { { .id = "NVDA0408", .driver_data = (kernel_ulong_t)&tegra194_aon_soc }, { .id = "NVDA0508", .driver_data = (kernel_ulong_t)&tegra241_main_soc }, { .id = "NVDA0608", .driver_data = (kernel_ulong_t)&tegra241_aon_soc }, + { .id = "NVDA0708", .driver_data = (kernel_ulong_t)&tegra410_compute_soc }, + { .id = "NVDA0808", .driver_data = (kernel_ulong_t)&tegra410_system_soc }, {} }; MODULE_DEVICE_TABLE(acpi, tegra186_gpio_acpi_match); diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c index 27dd09273292..eedfc0e371e3 100644 --- a/drivers/gpio/gpio-tqmx86.c +++ b/drivers/gpio/gpio-tqmx86.c @@ -279,19 +279,18 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc) } /* Minimal runtime PM is needed by the IRQ subsystem */ -static int __maybe_unused tqmx86_gpio_runtime_suspend(struct device *dev) +static int tqmx86_gpio_runtime_suspend(struct device *dev) { return 0; } -static int __maybe_unused tqmx86_gpio_runtime_resume(struct device *dev) +static int tqmx86_gpio_runtime_resume(struct device *dev) { return 0; } static const struct dev_pm_ops tqmx86_gpio_dev_pm_ops = { - SET_RUNTIME_PM_OPS(tqmx86_gpio_runtime_suspend, - tqmx86_gpio_runtime_resume, NULL) + RUNTIME_PM_OPS(tqmx86_gpio_runtime_suspend, tqmx86_gpio_runtime_resume, NULL) }; static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip, @@ -425,7 +424,7 @@ out_pm_dis: static struct platform_driver tqmx86_gpio_driver = { .driver = { .name = "tqmx86-gpio", - .pm = &tqmx86_gpio_dev_pm_ops, + .pm = pm_ptr(&tqmx86_gpio_dev_pm_ops), }, .probe = tqmx86_gpio_probe, }; diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 197bb1d22b3c..0574dde5b5bb 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -426,7 +426,7 @@ static void uniphier_gpio_remove(struct platform_device *pdev) irq_domain_remove(priv->domain); } -static int __maybe_unused uniphier_gpio_suspend(struct device *dev) +static int uniphier_gpio_suspend(struct device *dev) { struct uniphier_gpio_priv *priv = dev_get_drvdata(dev); unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio); @@ -448,7 +448,7 @@ static int __maybe_unused uniphier_gpio_suspend(struct device *dev) return 0; } -static int __maybe_unused uniphier_gpio_resume(struct device *dev) +static int uniphier_gpio_resume(struct device *dev) { struct uniphier_gpio_priv *priv = dev_get_drvdata(dev); unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio); @@ -473,8 +473,7 @@ static int __maybe_unused uniphier_gpio_resume(struct device *dev) } static const struct dev_pm_ops uniphier_gpio_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(uniphier_gpio_suspend, - uniphier_gpio_resume) + LATE_SYSTEM_SLEEP_PM_OPS(uniphier_gpio_suspend, uniphier_gpio_resume) }; static const struct of_device_id uniphier_gpio_match[] = { @@ -489,7 +488,7 @@ static struct platform_driver uniphier_gpio_driver = { .driver = { .name = "uniphier-gpio", .of_match_table = uniphier_gpio_match, - .pm = &uniphier_gpio_pm_ops, + .pm = pm_sleep_ptr(&uniphier_gpio_pm_ops), }, }; module_platform_driver(uniphier_gpio_driver); diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c index a10eab7d2617..37f2ce20f1ae 100644 --- a/drivers/gpio/gpio-virtuser.c +++ b/drivers/gpio/gpio-virtuser.c @@ -500,9 +500,7 @@ static int gpio_virtuser_value_set(void *data, u64 val) if (val > 1) return -EINVAL; - gpiod_set_value_cansleep(ld->ad.desc, (int)val); - - return 0; + return gpiod_set_value_cansleep(ld->ad.desc, (int)val); } DEFINE_DEBUGFS_ATTRIBUTE(gpio_virtuser_value_fops, @@ -543,7 +541,7 @@ static void gpio_virtuser_set_value_atomic(struct irq_work *work) struct gpio_virtuser_irq_work_context *ctx = to_gpio_virtuser_irq_work_context(work); - gpiod_set_value(ctx->desc, ctx->val); + ctx->ret = gpiod_set_value(ctx->desc, ctx->val); complete(&ctx->work_completion); } @@ -562,7 +560,7 @@ static int gpio_virtuser_value_atomic_set(void *data, u64 val) gpio_virtuser_irq_work_queue_sync(&ctx); - return 0; + return ctx.ret; } DEFINE_DEBUGFS_ATTRIBUTE(gpio_virtuser_value_atomic_fops, diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c index 4f627de3f56c..809668449dbe 100644 --- a/drivers/gpio/gpio-xgene.c +++ b/drivers/gpio/gpio-xgene.c @@ -130,7 +130,7 @@ static int xgene_gpio_dir_out(struct gpio_chip *gc, return 0; } -static __maybe_unused int xgene_gpio_suspend(struct device *dev) +static int xgene_gpio_suspend(struct device *dev) { struct xgene_gpio *gpio = dev_get_drvdata(dev); unsigned long bank_offset; @@ -143,7 +143,7 @@ static __maybe_unused int xgene_gpio_suspend(struct device *dev) return 0; } -static __maybe_unused int xgene_gpio_resume(struct device *dev) +static int xgene_gpio_resume(struct device *dev) { struct xgene_gpio *gpio = dev_get_drvdata(dev); unsigned long bank_offset; @@ -156,7 +156,7 @@ static __maybe_unused int xgene_gpio_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume); static int xgene_gpio_probe(struct platform_device *pdev) { @@ -204,7 +204,7 @@ static struct platform_driver xgene_gpio_driver = { .name = "xgene-gpio", .of_match_table = xgene_gpio_of_match, .acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match), - .pm = &xgene_gpio_pm, + .pm = pm_sleep_ptr(&xgene_gpio_pm), }, .probe = xgene_gpio_probe, }; diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 83675ac81077..be4b4d730547 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -286,7 +286,7 @@ static void xgpio_free(struct gpio_chip *chip, unsigned int offset) pm_runtime_put(chip->parent); } -static int __maybe_unused xgpio_suspend(struct device *dev) +static int xgpio_suspend(struct device *dev) { struct xgpio_instance *gpio = dev_get_drvdata(dev); struct irq_data *data = irq_get_irq_data(gpio->irq); @@ -327,7 +327,7 @@ static void xgpio_irq_ack(struct irq_data *irq_data) { } -static int __maybe_unused xgpio_resume(struct device *dev) +static int xgpio_resume(struct device *dev) { struct xgpio_instance *gpio = dev_get_drvdata(dev); struct irq_data *data = irq_get_irq_data(gpio->irq); @@ -343,7 +343,7 @@ static int __maybe_unused xgpio_resume(struct device *dev) return 0; } -static int __maybe_unused xgpio_runtime_suspend(struct device *dev) +static int xgpio_runtime_suspend(struct device *dev) { struct xgpio_instance *gpio = dev_get_drvdata(dev); @@ -352,7 +352,7 @@ static int __maybe_unused xgpio_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused xgpio_runtime_resume(struct device *dev) +static int xgpio_runtime_resume(struct device *dev) { struct xgpio_instance *gpio = dev_get_drvdata(dev); @@ -360,9 +360,8 @@ static int __maybe_unused xgpio_runtime_resume(struct device *dev) } static const struct dev_pm_ops xgpio_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(xgpio_suspend, xgpio_resume) - SET_RUNTIME_PM_OPS(xgpio_runtime_suspend, - xgpio_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(xgpio_suspend, xgpio_resume) + RUNTIME_PM_OPS(xgpio_runtime_suspend, xgpio_runtime_resume, NULL) }; /** @@ -682,7 +681,7 @@ static struct platform_driver xgpio_plat_driver = { .driver = { .name = "gpio-xilinx", .of_match_table = xgpio_of_match, - .pm = &xgpio_dev_pm_ops, + .pm = pm_ptr(&xgpio_dev_pm_ops), }, }; diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 0ffd76e8951f..97780c57ab56 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -735,7 +735,7 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio) } } -static int __maybe_unused zynq_gpio_suspend(struct device *dev) +static int zynq_gpio_suspend(struct device *dev) { struct zynq_gpio *gpio = dev_get_drvdata(dev); struct irq_data *data = irq_get_irq_data(gpio->irq); @@ -756,7 +756,7 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev) return 0; } -static int __maybe_unused zynq_gpio_resume(struct device *dev) +static int zynq_gpio_resume(struct device *dev) { struct zynq_gpio *gpio = dev_get_drvdata(dev); struct irq_data *data = irq_get_irq_data(gpio->irq); @@ -779,7 +779,7 @@ static int __maybe_unused zynq_gpio_resume(struct device *dev) return 0; } -static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev) +static int zynq_gpio_runtime_suspend(struct device *dev) { struct zynq_gpio *gpio = dev_get_drvdata(dev); @@ -788,7 +788,7 @@ static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev) +static int zynq_gpio_runtime_resume(struct device *dev) { struct zynq_gpio *gpio = dev_get_drvdata(dev); @@ -814,9 +814,8 @@ static void zynq_gpio_free(struct gpio_chip *chip, unsigned int offset) } static const struct dev_pm_ops zynq_gpio_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume) - SET_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, - zynq_gpio_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume) + RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, zynq_gpio_runtime_resume, NULL) }; static const struct zynq_platform_data versal_gpio_def = { @@ -1022,7 +1021,7 @@ static void zynq_gpio_remove(struct platform_device *pdev) static struct platform_driver zynq_gpio_driver = { .driver = { .name = DRIVER_NAME, - .pm = &zynq_gpio_dev_pm_ops, + .pm = pm_ptr(&zynq_gpio_dev_pm_ops), .of_match_table = zynq_gpio_of_match, }, .probe = zynq_gpio_probe, diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c index d441c1236d8c..83dd227dbbec 100644 --- a/drivers/gpio/gpiolib-acpi-core.c +++ b/drivers/gpio/gpiolib-acpi-core.c @@ -1099,7 +1099,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, return AE_BAD_PARAMETER; } - length = min_t(u16, agpio->pin_table_length, pin_index + bits); + length = min(agpio->pin_table_length, pin_index + bits); for (i = pin_index; i < length; ++i) { unsigned int pin = agpio->pin_table[i]; struct acpi_gpio_connection *conn; diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 084656564176..3735c9fe1502 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -652,7 +652,7 @@ static enum hte_return process_hw_ts_thread(void *p) } le.line_seqno = line->line_seqno; le.seqno = (lr->num_lines == 1) ? le.line_seqno : line->req_seqno; - le.offset = gpio_chip_hwgpio(line->desc); + le.offset = gpiod_hwgpio(line->desc); linereq_put_event(lr, &le); @@ -676,7 +676,7 @@ static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p) if (READ_ONCE(line->sw_debounced)) { line->total_discard_seq++; line->last_seqno = ts->seq; - mod_delayed_work(system_wq, &line->work, + mod_delayed_work(system_percpu_wq, &line->work, usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); } else { if (unlikely(ts->seq < line->line_seqno)) @@ -769,7 +769,7 @@ static irqreturn_t edge_irq_thread(int irq, void *p) line->line_seqno++; le.line_seqno = line->line_seqno; le.seqno = (lr->num_lines == 1) ? le.line_seqno : line->req_seqno; - le.offset = gpio_chip_hwgpio(line->desc); + le.offset = gpiod_hwgpio(line->desc); linereq_put_event(lr, &le); @@ -817,7 +817,7 @@ static irqreturn_t debounce_irq_handler(int irq, void *p) { struct line *line = p; - mod_delayed_work(system_wq, &line->work, + mod_delayed_work(system_percpu_wq, &line->work, usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); return IRQ_HANDLED; @@ -867,7 +867,7 @@ static void debounce_work_func(struct work_struct *work) lr = line->req; le.timestamp_ns = line_event_timestamp(line); - le.offset = gpio_chip_hwgpio(line->desc); + le.offset = gpiod_hwgpio(line->desc); #ifdef CONFIG_HTE if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) { /* discard events except the last one */ @@ -1567,7 +1567,7 @@ static void linereq_show_fdinfo(struct seq_file *out, struct file *file) for (i = 0; i < lr->num_lines; i++) seq_printf(out, "gpio-line:\t%d\n", - gpio_chip_hwgpio(lr->lines[i].desc)); + gpiod_hwgpio(lr->lines[i].desc)); } #endif @@ -2220,7 +2220,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, return; memset(info, 0, sizeof(*info)); - info->offset = gpio_chip_hwgpio(desc); + info->offset = gpiod_hwgpio(desc); if (desc->name) strscpy(info->name, desc->name, sizeof(info->name)); @@ -2526,7 +2526,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb, struct gpio_desc *desc = data; struct file *fp; - if (!test_bit(gpio_chip_hwgpio(desc), cdev->watched_lines)) + if (!test_bit(gpiod_hwgpio(desc), cdev->watched_lines)) return NOTIFY_DONE; /* Keep the file descriptor alive for the duration of the notification. */ @@ -2804,7 +2804,7 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt) if (!gc) return -ENODEV; - chip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id); + gpiochip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id); return 0; } diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c index 3bc93ccadb5b..ef3f2ef30cf2 100644 --- a/drivers/gpio/gpiolib-legacy.c +++ b/drivers/gpio/gpiolib-legacy.c @@ -34,30 +34,20 @@ EXPORT_SYMBOL_GPL(gpio_free); */ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) { - struct gpio_desc *desc; int err; - /* Compatibility: assume unavailable "valid" GPIOs will appear later */ - desc = gpio_to_desc(gpio); - if (!desc) - return -EPROBE_DEFER; - - err = gpiod_request(desc, label); + err = gpio_request(gpio, label); if (err) return err; if (flags & GPIOF_IN) - err = gpiod_direction_input(desc); + err = gpio_direction_input(gpio); else - err = gpiod_direction_output_raw(desc, !!(flags & GPIOF_OUT_INIT_HIGH)); + err = gpio_direction_output(gpio, !!(flags & GPIOF_OUT_INIT_HIGH)); if (err) - goto free_gpio; - - return 0; + gpio_free(gpio); - free_gpio: - gpiod_free(desc); return err; } EXPORT_SYMBOL_GPL(gpio_request_one); @@ -78,11 +68,9 @@ int gpio_request(unsigned gpio, const char *label) } EXPORT_SYMBOL_GPL(gpio_request); -static void devm_gpio_release(struct device *dev, void *res) +static void devm_gpio_release(void *gpio) { - unsigned *gpio = res; - - gpio_free(*gpio); + gpio_free((unsigned)(unsigned long)gpio); } /** @@ -100,22 +88,22 @@ static void devm_gpio_release(struct device *dev, void *res) int devm_gpio_request_one(struct device *dev, unsigned gpio, unsigned long flags, const char *label) { - unsigned *dr; int rc; - dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL); - if (!dr) - return -ENOMEM; + rc = gpio_request(gpio, label); + if (rc) + return rc; + + if (flags & GPIOF_IN) + rc = gpio_direction_input(gpio); + else + rc = gpio_direction_output(gpio, !!(flags & GPIOF_OUT_INIT_HIGH)); - rc = gpio_request_one(gpio, flags, label); if (rc) { - devres_free(dr); + gpio_free(gpio); return rc; } - *dr = gpio; - devres_add(dev, dr); - - return 0; + return devm_add_action_or_reset(dev, devm_gpio_release, (void *)(unsigned long)gpio); } EXPORT_SYMBOL_GPL(devm_gpio_request_one); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index fad4edf9cc5c..8657379e9165 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -1031,85 +1031,6 @@ static int of_gpio_threecell_xlate(struct gpio_chip *gc, return gpiospec->args[1]; } -#if IS_ENABLED(CONFIG_OF_GPIO_MM_GPIOCHIP) -#include <linux/gpio/legacy-of-mm-gpiochip.h> -/** - * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank) - * @np: device node of the GPIO chip - * @mm_gc: pointer to the of_mm_gpio_chip allocated structure - * @data: driver data to store in the struct gpio_chip - * - * To use this function you should allocate and fill mm_gc with: - * - * 1) In the gpio_chip structure: - * - all the callbacks - * - of_gpio_n_cells - * - of_xlate callback (optional) - * - * 3) In the of_mm_gpio_chip structure: - * - save_regs callback (optional) - * - * If succeeded, this function will map bank's memory and will - * do all necessary work for you. Then you'll able to use .regs - * to manage GPIOs from the callbacks. - * - * Returns: - * 0 on success, or negative errno on failure. - */ -int of_mm_gpiochip_add_data(struct device_node *np, - struct of_mm_gpio_chip *mm_gc, - void *data) -{ - int ret = -ENOMEM; - struct gpio_chip *gc = &mm_gc->gc; - - gc->label = kasprintf(GFP_KERNEL, "%pOF", np); - if (!gc->label) - goto err0; - - mm_gc->regs = of_iomap(np, 0); - if (!mm_gc->regs) - goto err1; - - gc->base = -1; - - if (mm_gc->save_regs) - mm_gc->save_regs(mm_gc); - - fwnode_handle_put(mm_gc->gc.fwnode); - mm_gc->gc.fwnode = fwnode_handle_get(of_fwnode_handle(np)); - - ret = gpiochip_add_data(gc, data); - if (ret) - goto err2; - - return 0; -err2: - of_node_put(np); - iounmap(mm_gc->regs); -err1: - kfree(gc->label); -err0: - pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret); - return ret; -} -EXPORT_SYMBOL_GPL(of_mm_gpiochip_add_data); - -/** - * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank) - * @mm_gc: pointer to the of_mm_gpio_chip allocated structure - */ -void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) -{ - struct gpio_chip *gc = &mm_gc->gc; - - gpiochip_remove(gc); - iounmap(mm_gc->regs); - kfree(gc->label); -} -EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove); -#endif - #ifdef CONFIG_PINCTRL static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index fa1d16635ea7..8bdd107b1ad1 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -49,6 +49,7 @@ struct gpio_shared_entry { unsigned int offset; /* Index in the property value array. */ size_t index; + struct mutex lock; struct gpio_shared_desc *shared_desc; struct kref ref; struct list_head refs; @@ -58,6 +59,7 @@ static LIST_HEAD(gpio_shared_list); static DEFINE_MUTEX(gpio_shared_lock); static DEFINE_IDA(gpio_shared_ida); +#if IS_ENABLED(CONFIG_OF) static struct gpio_shared_entry * gpio_shared_find_entry(struct fwnode_handle *controller_node, unsigned int offset) @@ -72,7 +74,26 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node, return NULL; } -#if IS_ENABLED(CONFIG_OF) +/* Handle all special nodes that we should ignore. */ +static bool gpio_shared_of_node_ignore(struct device_node *node) +{ + /* + * __symbols__ is a special, internal node and should not be considered + * when scanning for shared GPIOs. + */ + if (of_node_name_eq(node, "__symbols__")) + return true; + + /* + * GPIO hogs have a "gpios" property which is not a phandle and can't + * possibly refer to a shared GPIO. + */ + if (of_property_present(node, "gpio-hog")) + return true; + + return false; +} + static int gpio_shared_of_traverse(struct device_node *curr) { struct gpio_shared_entry *entry; @@ -84,6 +105,9 @@ static int gpio_shared_of_traverse(struct device_node *curr) const char *suffix; int ret, count, i; + if (gpio_shared_of_node_ignore(curr)) + return 0; + for_each_property_of_node(curr, prop) { /* * The standard name for a GPIO property is "foo-gpios" @@ -147,6 +171,7 @@ static int gpio_shared_of_traverse(struct device_node *curr) entry->offset = offset; entry->index = count; INIT_LIST_HEAD(&entry->refs); + mutex_init(&entry->lock); list_add_tail(&entry->list, &gpio_shared_list); } @@ -205,7 +230,10 @@ static int gpio_shared_of_traverse(struct device_node *curr) static int gpio_shared_of_scan(void) { - return gpio_shared_of_traverse(of_root); + if (of_root) + return gpio_shared_of_traverse(of_root); + + return 0; } #else static int gpio_shared_of_scan(void) @@ -220,6 +248,7 @@ static void gpio_shared_adev_release(struct device *dev) } static int gpio_shared_make_adev(struct gpio_device *gdev, + struct gpio_shared_entry *entry, struct gpio_shared_ref *ref) { struct auxiliary_device *adev = &ref->adev; @@ -232,6 +261,7 @@ static int gpio_shared_make_adev(struct gpio_device *gdev, adev->id = ref->dev_id; adev->name = "proxy"; adev->dev.parent = gdev->dev.parent; + adev->dev.platform_data = entry; adev->dev.release = gpio_shared_adev_release; ret = auxiliary_device_init(adev); @@ -250,6 +280,84 @@ static int gpio_shared_make_adev(struct gpio_device *gdev, return 0; } +#if IS_ENABLED(CONFIG_RESET_GPIO) +/* + * Special case: reset-gpio is an auxiliary device that's created dynamically + * and put in between the GPIO controller and consumers of shared GPIOs + * referred to by the "reset-gpios" property. + * + * If the supposed consumer of a shared GPIO didn't match any of the mappings + * we created when scanning the firmware nodes, it's still possible that it's + * the reset-gpio device which didn't exist at the time of the scan. + * + * This function verifies it an return true if it's the case. + */ +static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, + struct gpio_shared_entry *entry, + struct gpio_shared_ref *ref) +{ + struct fwnode_handle *reset_fwnode = dev_fwnode(consumer); + struct fwnode_reference_args ref_args, aux_args; + struct device *parent = consumer->parent; + bool match; + int ret; + + /* The reset-gpio device must have a parent AND a firmware node. */ + if (!parent || !reset_fwnode) + return false; + + /* + * FIXME: use device_is_compatible() once the reset-gpio drivers gains + * a compatible string which it currently does not have. + */ + if (!strstarts(dev_name(consumer), "reset.gpio.")) + return false; + + /* + * Parent of the reset-gpio auxiliary device is the GPIO chip whose + * fwnode we stored in the entry structure. + */ + if (!device_match_fwnode(parent, entry->fwnode)) + return false; + + /* + * The device associated with the shared reference's firmware node is + * the consumer of the reset control exposed by the reset-gpio device. + * It must have a "reset-gpios" property that's referencing the entry's + * firmware node. + * + * The reference args must agree between the real consumer and the + * auxiliary reset-gpio device. + */ + ret = fwnode_property_get_reference_args(ref->fwnode, "reset-gpios", + NULL, 2, 0, &ref_args); + if (ret) + return false; + + ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios", + NULL, 2, 0, &aux_args); + if (ret) { + fwnode_handle_put(ref_args.fwnode); + return false; + } + + match = ((ref_args.fwnode == entry->fwnode) && + (aux_args.fwnode == entry->fwnode) && + (ref_args.args[0] == aux_args.args[0])); + + fwnode_handle_put(ref_args.fwnode); + fwnode_handle_put(aux_args.fwnode); + return match; +} +#else +static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, + struct gpio_shared_entry *entry, + struct gpio_shared_ref *ref) +{ + return false; +} +#endif /* CONFIG_RESET_GPIO */ + int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) { const char *dev_id = dev_name(consumer); @@ -265,7 +373,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) list_for_each_entry(entry, &gpio_shared_list, list) { list_for_each_entry(ref, &entry->refs, list) { - if (!device_match_fwnode(consumer, ref->fwnode)) + if (!device_match_fwnode(consumer, ref->fwnode) && + !gpio_shared_dev_is_reset_gpio(consumer, entry, ref)) continue; /* We've already done that on a previous request. */ @@ -356,7 +465,7 @@ int gpio_device_setup_shared(struct gpio_device *gdev) pr_debug("Setting up a shared GPIO entry for %s\n", fwnode_get_name(ref->fwnode)); - ret = gpio_shared_make_adev(gdev, ref); + ret = gpio_shared_make_adev(gdev, entry, ref); if (ret) return ret; } @@ -390,10 +499,11 @@ static void gpio_shared_release(struct kref *kref) { struct gpio_shared_entry *entry = container_of(kref, struct gpio_shared_entry, ref); - struct gpio_shared_desc *shared_desc = entry->shared_desc; + struct gpio_shared_desc *shared_desc; - guard(mutex)(&gpio_shared_lock); + guard(mutex)(&entry->lock); + shared_desc = entry->shared_desc; gpio_device_put(shared_desc->desc->gdev); if (shared_desc->can_sleep) mutex_destroy(&shared_desc->mutex); @@ -416,6 +526,8 @@ gpiod_shared_desc_create(struct gpio_shared_entry *entry) struct gpio_shared_desc *shared_desc; struct gpio_device *gdev; + lockdep_assert_held(&entry->lock); + shared_desc = kzalloc(sizeof(*shared_desc), GFP_KERNEL); if (!shared_desc) return ERR_PTR(-ENOMEM); @@ -436,57 +548,42 @@ gpiod_shared_desc_create(struct gpio_shared_entry *entry) return shared_desc; } -static struct gpio_shared_entry *gpiod_shared_find(struct auxiliary_device *adev) +struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev) { struct gpio_shared_desc *shared_desc; struct gpio_shared_entry *entry; - struct gpio_shared_ref *ref; - - guard(mutex)(&gpio_shared_lock); + int ret; - list_for_each_entry(entry, &gpio_shared_list, list) { - list_for_each_entry(ref, &entry->refs, list) { - if (adev != &ref->adev) - continue; + lockdep_assert_not_held(&gpio_shared_lock); - if (entry->shared_desc) { - kref_get(&entry->ref); - return entry; - } + entry = dev_get_platdata(dev); + if (WARN_ON(!entry)) + /* Programmer bug */ + return ERR_PTR(-ENOENT); + scoped_guard(mutex, &entry->lock) { + if (entry->shared_desc) { + kref_get(&entry->ref); + shared_desc = entry->shared_desc; + } else { shared_desc = gpiod_shared_desc_create(entry); if (IS_ERR(shared_desc)) return ERR_CAST(shared_desc); kref_init(&entry->ref); entry->shared_desc = shared_desc; - - pr_debug("Device %s acquired a reference to the shared GPIO %u owned by %s\n", - dev_name(&adev->dev), gpio_chip_hwgpio(shared_desc->desc), - gpio_device_get_label(shared_desc->desc->gdev)); - - - return entry; } - } - - return ERR_PTR(-ENOENT); -} - -struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev) -{ - struct gpio_shared_entry *entry; - int ret; - entry = gpiod_shared_find(to_auxiliary_dev(dev)); - if (IS_ERR(entry)) - return ERR_CAST(entry); + pr_debug("Device %s acquired a reference to the shared GPIO %u owned by %s\n", + dev_name(dev), gpiod_hwgpio(shared_desc->desc), + gpio_device_get_label(shared_desc->desc->gdev)); + } ret = devm_add_action_or_reset(dev, gpiod_shared_put, entry); if (ret) return ERR_PTR(ret); - return entry->shared_desc; + return shared_desc; } EXPORT_SYMBOL_GPL(devm_gpiod_shared_get); @@ -502,6 +599,7 @@ static void gpio_shared_drop_ref(struct gpio_shared_ref *ref) static void gpio_shared_drop_entry(struct gpio_shared_entry *entry) { list_del(&entry->list); + mutex_destroy(&entry->lock); fwnode_handle_put(entry->fwnode); kfree(entry); } diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c index e3806db1c0e0..b44f35d68459 100644 --- a/drivers/gpio/gpiolib-swnode.c +++ b/drivers/gpio/gpiolib-swnode.c @@ -31,7 +31,7 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode) gdev_node = to_software_node(fwnode); if (!gdev_node || !gdev_node->name) - return ERR_PTR(-EINVAL); + goto fwnode_lookup; /* * Check for a special node that identifies undefined GPIOs, this is @@ -41,6 +41,7 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode) !strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME)) return ERR_PTR(-ENOENT); +fwnode_lookup: gdev = gpio_device_find_by_fwnode(fwnode); return gdev ?: ERR_PTR(-EPROBE_DEFER); } diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 9a849245b358..cd553acf3055 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -244,7 +244,7 @@ static int gpio_sysfs_request_irq(struct gpiod_data *data, unsigned char flags) * Remove this redundant call (along with the corresponding unlock) * when those drivers have been fixed. */ - ret = gpiochip_lock_as_irq(guard.gc, gpio_chip_hwgpio(desc)); + ret = gpiochip_lock_as_irq(guard.gc, gpiod_hwgpio(desc)); if (ret < 0) goto err_clr_bits; @@ -258,7 +258,7 @@ static int gpio_sysfs_request_irq(struct gpiod_data *data, unsigned char flags) return 0; err_unlock: - gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc)); + gpiochip_unlock_as_irq(guard.gc, gpiod_hwgpio(desc)); err_clr_bits: clear_bit(GPIOD_FLAG_EDGE_RISING, &desc->flags); clear_bit(GPIOD_FLAG_EDGE_FALLING, &desc->flags); @@ -280,7 +280,7 @@ static void gpio_sysfs_free_irq(struct gpiod_data *data) data->irq_flags = 0; free_irq(data->irq, data); - gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc)); + gpiochip_unlock_as_irq(guard.gc, gpiod_hwgpio(desc)); clear_bit(GPIOD_FLAG_EDGE_RISING, &desc->flags); clear_bit(GPIOD_FLAG_EDGE_FALLING, &desc->flags); } @@ -478,10 +478,10 @@ static int export_gpio_desc(struct gpio_desc *desc) if (!guard.gc) return -ENODEV; - offset = gpio_chip_hwgpio(desc); + offset = gpiod_hwgpio(desc); if (!gpiochip_line_is_valid(guard.gc, offset)) { pr_debug_ratelimited("%s: GPIO %d masked\n", __func__, - gpio_chip_hwgpio(desc)); + gpiod_hwgpio(desc)); return -EINVAL; } @@ -823,7 +823,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) } desc_data->chip_attr_group.name = kasprintf(GFP_KERNEL, "gpio%u", - gpio_chip_hwgpio(desc)); + gpiod_hwgpio(desc)); if (!desc_data->chip_attr_group.name) { status = -ENOMEM; goto err_put_dirent; @@ -843,7 +843,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) if (status) goto err_free_name; - path = kasprintf(GFP_KERNEL, "gpio%u/value", gpio_chip_hwgpio(desc)); + path = kasprintf(GFP_KERNEL, "gpio%u/value", gpiod_hwgpio(desc)); if (!path) { status = -ENOMEM; goto err_remove_groups; @@ -1091,7 +1091,7 @@ static int gpiofind_sysfs_register(struct gpio_chip *gc, const void *data) ret = gpiochip_sysfs_register(gdev); if (ret) - chip_err(gc, "failed to register the sysfs entry: %d\n", ret); + gpiochip_err(gc, "failed to register the sysfs entry: %d\n", ret); return 0; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 476fcc897d90..91e0c384f34a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -236,6 +236,19 @@ int desc_to_gpio(const struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(desc_to_gpio); +/** + * gpiod_hwgpio - Return the GPIO number of the passed descriptor relative to + * its chip. + * @desc: GPIO descriptor + * + * Returns: + * Hardware offset of the GPIO represented by the descriptor. + */ +int gpiod_hwgpio(const struct gpio_desc *desc) +{ + return desc - &desc->gdev->descs[0]; +} +EXPORT_SYMBOL_GPL(gpiod_hwgpio); /** * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs @@ -444,7 +457,7 @@ int gpiod_get_direction(struct gpio_desc *desc) if (!guard.gc) return -ENODEV; - offset = gpio_chip_hwgpio(desc); + offset = gpiod_hwgpio(desc); flags = READ_ONCE(desc->flags); /* @@ -922,8 +935,8 @@ static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog) desc = gpiochip_get_desc(gc, hog->chip_hwnum); if (IS_ERR(desc)) { - chip_err(gc, "%s: unable to get GPIO desc: %ld\n", __func__, - PTR_ERR(desc)); + gpiochip_err(gc, "%s: unable to get GPIO desc: %ld\n", + __func__, PTR_ERR(desc)); return; } @@ -1125,7 +1138,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, ret = gpiodev_add_to_list_unlocked(gdev); if (ret) { - chip_err(gc, "GPIO integer space overlap, cannot add chip\n"); + gpiochip_err(gc, "GPIO integer space overlap, cannot add chip\n"); goto err_free_label; } } @@ -1537,8 +1550,7 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc, &parent_hwirq, &parent_type); if (ret) { - chip_err(gc, "skip set-up on hwirq %d\n", - i); + gpiochip_err(gc, "skip set-up on hwirq %d\n", i); continue; } @@ -1551,15 +1563,14 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc, ret = irq_domain_alloc_irqs(gc->irq.domain, 1, NUMA_NO_NODE, &fwspec); if (ret < 0) { - chip_err(gc, - "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", - i, parent_hwirq, - ret); + gpiochip_err(gc, + "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", + i, parent_hwirq, ret); } } } - chip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__); + gpiochip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__); return; } @@ -1611,15 +1622,15 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, if (ret) return ret; - chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq); + gpiochip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq); ret = girq->child_to_parent_hwirq(gc, hwirq, type, &parent_hwirq, &parent_type); if (ret) { - chip_err(gc, "can't look up hwirq %lu\n", hwirq); + gpiochip_err(gc, "can't look up hwirq %lu\n", hwirq); return ret; } - chip_dbg(gc, "found parent hwirq %u\n", parent_hwirq); + gpiochip_dbg(gc, "found parent hwirq %u\n", parent_hwirq); /* * We set handle_bad_irq because the .set_type() should @@ -1640,8 +1651,8 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, if (ret) return ret; - chip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n", - irq, parent_hwirq); + gpiochip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n", + irq, parent_hwirq); irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key); ret = irq_domain_alloc_irqs_parent(d, irq, 1, &gpio_parent_fwspec); /* @@ -1651,9 +1662,9 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, if (irq_domain_is_msi(d->parent) && (ret == -EEXIST)) ret = 0; if (ret) - chip_err(gc, - "failed to allocate parent hwirq %d for hwirq %lu\n", - parent_hwirq, hwirq); + gpiochip_err(gc, + "failed to allocate parent hwirq %d for hwirq %lu\n", + parent_hwirq, hwirq); return ret; } @@ -1729,7 +1740,7 @@ static struct irq_domain *gpiochip_hierarchy_create_domain(struct gpio_chip *gc) if (!gc->irq.child_to_parent_hwirq || !gc->irq.fwnode) { - chip_err(gc, "missing irqdomain vital data\n"); + gpiochip_err(gc, "missing irqdomain vital data\n"); return ERR_PTR(-EINVAL); } @@ -2002,7 +2013,7 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc) if (irqchip->flags & IRQCHIP_IMMUTABLE) return; - chip_warn(gc, "not an immutable chip, please consider fixing it!\n"); + gpiochip_warn(gc, "not an immutable chip, please consider fixing it!\n"); if (!irqchip->irq_request_resources && !irqchip->irq_release_resources) { @@ -2018,8 +2029,8 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc) * ...and if so, give a gentle warning that this is bad * practice. */ - chip_info(gc, - "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n"); + gpiochip_info(gc, + "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n"); return; } @@ -2048,7 +2059,8 @@ static int gpiochip_irqchip_add_allocated_domain(struct gpio_chip *gc, return -EINVAL; if (gc->to_irq) - chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__); + gpiochip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", + __func__); gc->to_irq = gpiochip_to_irq; gc->irq.domain = domain; @@ -2089,7 +2101,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc, return 0; if (gc->irq.parent_handler && gc->can_sleep) { - chip_err(gc, "you cannot have chained interrupts on a chip that may sleep\n"); + gpiochip_err(gc, "you cannot have chained interrupts on a chip that may sleep\n"); return -EINVAL; } @@ -2325,10 +2337,8 @@ int gpiochip_add_pingroup_range(struct gpio_chip *gc, int ret; pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); - if (!pin_range) { - chip_err(gc, "failed to allocate pin ranges\n"); + if (!pin_range) return -ENOMEM; - } /* Use local offset as range ID */ pin_range->range.id = gpio_offset; @@ -2347,7 +2357,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *gc, pinctrl_add_gpio_range(pctldev, &pin_range->range); - chip_dbg(gc, "created GPIO range %d->%d ==> %s PINGRP %s\n", + gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s PINGRP %s\n", gpio_offset, gpio_offset + pin_range->range.npins - 1, pinctrl_dev_get_devname(pctldev), pin_group); @@ -2388,10 +2398,8 @@ int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, int ret; pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); - if (!pin_range) { - chip_err(gc, "failed to allocate pin ranges\n"); + if (!pin_range) return -ENOMEM; - } /* Use local offset as range ID */ pin_range->range.id = gpio_offset; @@ -2405,19 +2413,18 @@ int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc, &pin_range->range); if (IS_ERR(pin_range->pctldev)) { ret = PTR_ERR(pin_range->pctldev); - chip_err(gc, "could not create pin range\n"); + gpiochip_err(gc, "could not create pin range\n"); kfree(pin_range); return ret; } if (pin_range->range.pins) - chip_dbg(gc, "created GPIO range %d->%d ==> %s %d sparse PIN range { %d, ... }", - gpio_offset, gpio_offset + npins - 1, - pinctl_name, npins, pins[0]); + gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s %d sparse PIN range { %d, ... }", + gpio_offset, gpio_offset + npins - 1, + pinctl_name, npins, pins[0]); else - chip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n", - gpio_offset, gpio_offset + npins - 1, - pinctl_name, - pin_offset, pin_offset + npins - 1); + gpiochip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n", + gpio_offset, gpio_offset + npins - 1, pinctl_name, + pin_offset, pin_offset + npins - 1); list_add_tail(&pin_range->node, &gdev->pin_ranges); @@ -2461,7 +2468,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) if (test_and_set_bit(GPIOD_FLAG_REQUESTED, &desc->flags)) return -EBUSY; - offset = gpio_chip_hwgpio(desc); + offset = gpiod_hwgpio(desc); if (!gpiochip_line_is_valid(guard.gc, offset)) return -EINVAL; @@ -2523,7 +2530,7 @@ static void gpiod_free_commit(struct gpio_desc *desc) if (guard.gc && test_bit(GPIOD_FLAG_REQUESTED, &flags)) { if (guard.gc->free) - guard.gc->free(guard.gc, gpio_chip_hwgpio(desc)); + guard.gc->free(guard.gc, gpiod_hwgpio(desc)); clear_bit(GPIOD_FLAG_ACTIVE_LOW, &flags); clear_bit(GPIOD_FLAG_REQUESTED, &flags); @@ -2627,7 +2634,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc, int ret; if (IS_ERR(desc)) { - chip_err(gc, "failed to get GPIO %s descriptor\n", name); + gpiochip_err(gc, "failed to get GPIO %s descriptor\n", name); return desc; } @@ -2638,7 +2645,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc, ret = gpiod_configure_flags(desc, label, lflags, dflags); if (ret) { gpiod_free_commit(desc); - chip_err(gc, "setup of own GPIO %s failed\n", name); + gpiochip_err(gc, "setup of own GPIO %s failed\n", name); return ERR_PTR(ret); } @@ -2683,7 +2690,7 @@ int gpio_do_set_config(struct gpio_desc *desc, unsigned long config) if (!guard.gc->set_config) return -ENOTSUPP; - ret = guard.gc->set_config(guard.gc, gpio_chip_hwgpio(desc), config); + ret = guard.gc->set_config(guard.gc, gpiod_hwgpio(desc), config); if (ret > 0) ret = -EBADE; @@ -2714,7 +2721,7 @@ static int gpio_set_config_with_argument_optional(struct gpio_desc *desc, u32 argument) { struct device *dev = &desc->gdev->dev; - int gpio = gpio_chip_hwgpio(desc); + int gpio = gpiod_hwgpio(desc); int ret; ret = gpio_set_config_with_argument(desc, mode, argument); @@ -2877,9 +2884,9 @@ int gpiod_direction_input_nonotify(struct gpio_desc *desc) */ if (guard.gc->direction_input) { ret = gpiochip_direction_input(guard.gc, - gpio_chip_hwgpio(desc)); + gpiod_hwgpio(desc)); } else if (guard.gc->get_direction) { - dir = gpiochip_get_direction(guard.gc, gpio_chip_hwgpio(desc)); + dir = gpiochip_get_direction(guard.gc, gpiod_hwgpio(desc)); if (dir < 0) return dir; @@ -2938,12 +2945,12 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) if (guard.gc->direction_output) { ret = gpiochip_direction_output(guard.gc, - gpio_chip_hwgpio(desc), val); + gpiod_hwgpio(desc), val); } else { /* Check that we are in output mode if we can */ if (guard.gc->get_direction) { dir = gpiochip_get_direction(guard.gc, - gpio_chip_hwgpio(desc)); + gpiod_hwgpio(desc)); if (dir < 0) return dir; @@ -2958,7 +2965,7 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) * If we can't actively set the direction, we are some * output-only chip, so just drive the output as desired. */ - ret = gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), val); + ret = gpiochip_set(guard.gc, gpiod_hwgpio(desc), val); if (ret) return ret; } @@ -3109,7 +3116,7 @@ int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) } ret = guard.gc->en_hw_timestamp(guard.gc, - gpio_chip_hwgpio(desc), flags); + gpiod_hwgpio(desc), flags); if (ret) gpiod_warn(desc, "%s: hw ts request failed\n", __func__); @@ -3141,7 +3148,7 @@ int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) return -ENOTSUPP; } - ret = guard.gc->dis_hw_timestamp(guard.gc, gpio_chip_hwgpio(desc), + ret = guard.gc->dis_hw_timestamp(guard.gc, gpiod_hwgpio(desc), flags); if (ret) gpiod_warn(desc, "%s: hw ts release failed\n", __func__); @@ -3272,7 +3279,7 @@ static int gpiochip_get(struct gpio_chip *gc, unsigned int offset) static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *desc) { - return gc->get ? gpiochip_get(gc, gpio_chip_hwgpio(desc)) : -EIO; + return gc->get ? gpiochip_get(gc, gpiod_hwgpio(desc)) : -EIO; } /* I/O calls are only valid after configuration completed; the relevant @@ -3432,7 +3439,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, first = i; do { const struct gpio_desc *desc = desc_array[i]; - int hwgpio = gpio_chip_hwgpio(desc); + int hwgpio = gpiod_hwgpio(desc); __set_bit(hwgpio, mask); i++; @@ -3454,7 +3461,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, for (j = first; j < i; ) { const struct gpio_desc *desc = desc_array[j]; - int hwgpio = gpio_chip_hwgpio(desc); + int hwgpio = gpiod_hwgpio(desc); int value = test_bit(hwgpio, bits); if (!raw && test_bit(GPIOD_FLAG_ACTIVE_LOW, &desc->flags)) @@ -3591,7 +3598,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value); */ static int gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) { - int ret = 0, offset = gpio_chip_hwgpio(desc); + int ret = 0, offset = gpiod_hwgpio(desc); CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) @@ -3620,7 +3627,7 @@ static int gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) */ static int gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) { - int ret = 0, offset = gpio_chip_hwgpio(desc); + int ret = 0, offset = gpiod_hwgpio(desc); CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) @@ -3652,7 +3659,7 @@ static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) return -ENODEV; trace_gpio_value(desc_to_gpio(desc), 0, value); - return gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), value); + return gpiochip_set(guard.gc, gpiod_hwgpio(desc), value); } /* @@ -3775,7 +3782,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, do { struct gpio_desc *desc = desc_array[i]; - int hwgpio = gpio_chip_hwgpio(desc); + int hwgpio = gpiod_hwgpio(desc); int value = test_bit(i, value_bitmap); if (unlikely(!test_bit(GPIOD_FLAG_IS_OUT, &desc->flags))) @@ -4035,7 +4042,7 @@ int gpiod_to_irq(const struct gpio_desc *desc) if (!gc) return -ENODEV; - offset = gpio_chip_hwgpio(desc); + offset = gpiod_hwgpio(desc); if (gc->to_irq) { ret = gc->to_irq(gc, offset); if (ret) @@ -4085,8 +4092,8 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) int dir = gpiod_get_direction(desc); if (dir < 0) { - chip_err(gc, "%s: cannot get GPIO direction\n", - __func__); + gpiochip_err(gc, "%s: cannot get GPIO direction\n", + __func__); return dir; } } @@ -4094,9 +4101,9 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset) /* To be valid for IRQ the line needs to be input or open drain */ if (test_bit(GPIOD_FLAG_IS_OUT, &desc->flags) && !test_bit(GPIOD_FLAG_OPEN_DRAIN, &desc->flags)) { - chip_err(gc, - "%s: tried to flag a GPIO set as output for IRQ\n", - __func__); + gpiochip_err(gc, + "%s: tried to flag a GPIO set as output for IRQ\n", + __func__); return -EIO; } @@ -4173,7 +4180,7 @@ int gpiochip_reqres_irq(struct gpio_chip *gc, unsigned int offset) ret = gpiochip_lock_as_irq(gc, offset); if (ret) { - chip_err(gc, "unable to lock HW IRQ %u for IRQ\n", offset); + gpiochip_err(gc, "unable to lock HW IRQ %u for IRQ\n", offset); module_put(gc->gpiodev->owner); return ret; } @@ -5015,7 +5022,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, if (test_and_set_bit(GPIOD_FLAG_IS_HOGGED, &desc->flags)) return 0; - hwnum = gpio_chip_hwgpio(desc); + hwnum = gpiod_hwgpio(desc); local_desc = gpiochip_request_own_desc(guard.gc, hwnum, name, lflags, dflags); @@ -5096,7 +5103,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, * If pin hardware number of array member 0 is also 0, select * its chip as a candidate for fast bitmap processing path. */ - if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) { + if (descs->ndescs == 0 && gpiod_hwgpio(desc) == 0) { struct gpio_descs *array; bitmap_size = BITS_TO_LONGS(gdev->ngpio > count ? @@ -5141,7 +5148,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, * Detect array members which belong to the 'fast' chip * but their pins are not in hardware order. */ - else if (gpio_chip_hwgpio(desc) != descs->ndescs) { + else if (gpiod_hwgpio(desc) != descs->ndescs) { /* * Don't use fast path if all array members processed so * far belong to the same chip as this one but its pin diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index abd870fb4a3b..77f6f2936dc2 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -275,49 +275,30 @@ int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev); struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum); const char *gpiod_get_label(struct gpio_desc *desc); -/* - * Return the GPIO number of the passed descriptor relative to its chip - */ -static inline int gpio_chip_hwgpio(const struct gpio_desc *desc) -{ - return desc - &desc->gdev->descs[0]; -} - /* With descriptor prefix */ -#define gpiod_err(desc, fmt, ...) \ +#define __gpiod_pr(level, desc, fmt, ...) \ do { \ scoped_guard(srcu, &desc->gdev->desc_srcu) { \ - pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), \ - gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \ + pr_##level("gpio-%d (%s): " fmt, desc_to_gpio(desc), \ + gpiod_get_label(desc) ?: "?", ##__VA_ARGS__); \ } \ } while (0) -#define gpiod_warn(desc, fmt, ...) \ -do { \ - scoped_guard(srcu, &desc->gdev->desc_srcu) { \ - pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), \ - gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \ - } \ -} while (0) +#define gpiod_err(desc, fmt, ...) __gpiod_pr(err, desc, fmt, ##__VA_ARGS__) +#define gpiod_warn(desc, fmt, ...) __gpiod_pr(warn, desc, fmt, ##__VA_ARGS__) +#define gpiod_dbg(desc, fmt, ...) __gpiod_pr(debug, desc, fmt, ##__VA_ARGS__) + +/* With chip prefix */ -#define gpiod_dbg(desc, fmt, ...) \ +#define __gpiochip_pr(level, gc, fmt, ...) \ do { \ - scoped_guard(srcu, &desc->gdev->desc_srcu) { \ - pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), \ - gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \ - } \ + dev_##level(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__); \ } while (0) -/* With chip prefix */ - -#define chip_err(gc, fmt, ...) \ - dev_err(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) -#define chip_warn(gc, fmt, ...) \ - dev_warn(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) -#define chip_info(gc, fmt, ...) \ - dev_info(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) -#define chip_dbg(gc, fmt, ...) \ - dev_dbg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) +#define gpiochip_err(gc, fmt, ...) __gpiochip_pr(err, gc, fmt, ##__VA_ARGS__) +#define gpiochip_warn(gc, fmt, ...) __gpiochip_pr(warn, gc, fmt, ##__VA_ARGS__) +#define gpiochip_info(gc, fmt, ...) __gpiochip_pr(info, gc, fmt, ##__VA_ARGS__) +#define gpiochip_dbg(gc, fmt, ...) __gpiochip_pr(dbg, gc, fmt, ##__VA_ARGS__) #endif /* GPIOLIB_H */ |