diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-11-01 06:21:54 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-11-01 06:21:54 +0300 |
commit | b05ddad00903b24931cb4b45516f1bc1b5c288f2 (patch) | |
tree | c7473f0416eea8035c1beb348edc56c3053164f2 /drivers/gpio | |
parent | ad1871ad8d9b3d252390ade8e2bcab7b773173ad (diff) | |
parent | 9bc633117d6a8411c6912cb0194b3e0f83ef9d56 (diff) | |
download | linux-b05ddad00903b24931cb4b45516f1bc1b5c288f2.tar.xz |
Merge tag 'gpio-updates-for-v6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"We don't have any new drivers. The loongson driver is getting extended
with support for new models. There's a big refactor of gpio-pca953x
and many small improvements to others.
The GPIO code in the kernel has acquired a lot of cruft over the years
as well as many abusers of the API across the kernel tree. This
release cycle we have started a major cleanup and improvement effort
that will most likely span several releases. We have started by
converting external users of struct gpio_chip to accessing the wrapper
around it - struct gpio_device. This is because the latter is
reference counted while the former is removed when the provider is
unbound. We also removed several instances of drivers accessing
private GPIOLIB structures and including the private header from
drivers/gpio/.
To that end you'll see several commits aimed at different subsystems
(acked by relevant maintainers) as well as two merges from the
x86/platform tree.
We'll then rework the locking in GPIOLIB which currently uses a big
spinlock for many different things and could use becoming more
fine-grained, especially as it doesn't even get the locking right.
We'll also use SRCU for protecting the gpio_chip pointer against
in-kernel hot-unplug crashes similar to what we saw triggered from
user-space and fixed with semaphores in gpiolib-cdev. The core GPIOLIB
is still vulnerable to these use-cases. I'm just mentioning the plans
here, this is not part of this PR.
You'll see some new instances of using __free(). We've added a
gpio_device_put cleanup helper similar to the put_device one
introduced by Peter Zijlstra and used it according to the preferred
pattern except where it didn't make sense.
GPIOLIB core:
- provide interfaces allowing users to retrieve, manage and query the
reference counted GPIO device instead of accessing the private
gpio_chip structure
- replace gpiochip_find() with gpio_device_find()
- remove unused acpi_get_and_request_gpiod()
- improve the ignore_interrupt functionality in GPIO ACPI
- correct notifier return codes in gpiolib-of
- unexport gpiod_set_transitory() as it's unused outside of core GPIO
code
- while there are still external users accessing struct gpio_chip,
let's make gpiochip_get_desc() public so that they at least use the
preferred helper
- improve locking for lookup tables
- annotate struct linereq with __counted_by
- improve GPIOLIB docs
- add an OF quirk for LED trigger sources
Driver improvements:
- convert all GPIO drivers with .remove() callbacks to using the new
variant returning void instead of int
- stop accessing the GPIOLIB private structures in gpio-mockup,
i2c-mux-gpio, hte-tegra194, gpio-sim
- use the recommended pattern for autofree variables in gpio-sim
- add support for more models to gpio-loongson
- use a notifier chain to notify other blocks about interrupts in
gpio-eic-sprd instead of looking up GPIO devices on every interrupt
- convert gpio-pca953x and gpio-fx6408 to using the maple tree regmap
cache
- don't include GPIOLIB internal headers in drivers which don't need
them
- move the ingenic NAND quirk into gpiolib-of
- add an ignore interrupt quirk for Peaq C1010
- drop static GPIO base from gpio-omap, gpio-f7188x
- use the preferred device_get_match_data() function in drivers that
still don't
- refactor gpio-pca953x: switch to using DEFINE_SIMPLE_DEV_PM_OPS(),
use cleanup helpers, use dev_err_probe() where it makes sense,
fully convert to using devres and some other minor tweaks
DT bindings:
- add support for a new model to gpio-vf610 and update existing
properties
- add support for more loongson models
- add missing support for imx models that are used but undocumented
- convert bindings for Intel IXP4xx to schema
Minor stuff:
- deprecate gpio-mockup in favor of gpio-sim
- include missing headers here and there
- stop using gpiochip_find() in OMAP1 board files
- minor tweaks in gpio-vf610, gpio-hisi
- remove unneeded 'extern' specifiers from headers"
* tag 'gpio-updates-for-v6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (108 commits)
hte: tegra194: add GPIOLIB dependency
hte: tegra194: don't access struct gpio_chip
gpiolib: provide gpio_device_get_base()
i2c: mux: gpio: don't fiddle with GPIOLIB internals
gpiolib: provide gpiod_to_gpio_device()
gpiolib: provide gpio_device_to_device()
gpio: hisi: Fix format specifier
gpiolib: provide gpio_device_find_by_fwnode()
gpio: acpi: remove acpi_get_and_request_gpiod()
gpio: Use device_get_match_data()
gpio: vf610: update comment for i.MX8ULP and i.MX93 legacy compatibles
platform/x86: int3472: Switch to devm_get_gpiod()
platform/x86: int3472: Stop using gpiod_toggle_active_low()
platform/x86: int3472: Add new skl_int3472_gpiod_get_from_temp_lookup() helper
platform/x86: int3472: Add new skl_int3472_fill_gpiod_lookup() helper
gpio: vf610: simplify code by dropping data check
gpio: vf610: add i.MX8ULP of_device_id entry
dt-bindings: gpio: vf610: add i.MX95 compatible
dt-bindings: gpio: vf610: correct i.MX8ULP and i.MX93
dt-bindings: gpio: vf610: update gpio-ranges
...
Diffstat (limited to 'drivers/gpio')
44 files changed, 933 insertions, 603 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 673bafb8be58..913948876c93 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1790,9 +1790,11 @@ config GPIO_LATCH connected to other GPIOs. config GPIO_MOCKUP - tristate "GPIO Testing Driver" + tristate "GPIO Testing Driver (DEPRECATED)" select IRQ_SIM help + This module is DEPRECATED. Please consider using gpio-sim instead. + This enables GPIO Testing driver, which provides a way to test GPIO subsystem through sysfs (or char device) and debugfs. User could use it through the script in diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 54d7c450c596..c2edfbb231fc 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -317,13 +317,11 @@ skip_irq: return 0; } -static int altera_gpio_remove(struct platform_device *pdev) +static void altera_gpio_remove(struct platform_device *pdev) { struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev); of_mm_gpiochip_remove(&altera_gc->mmchip); - - return 0; } static const struct of_device_id altera_gpio_of_match[] = { @@ -338,7 +336,7 @@ static struct platform_driver altera_gpio_driver = { .of_match_table = altera_gpio_of_match, }, .probe = altera_gpio_probe, - .remove = altera_gpio_remove, + .remove_new = altera_gpio_remove, }; static int __init altera_gpio_init(void) diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c index 07c6d090058d..0a2ea9db4682 100644 --- a/drivers/gpio/gpio-amdpt.c +++ b/drivers/gpio/gpio-amdpt.c @@ -122,13 +122,11 @@ static int pt_gpio_probe(struct platform_device *pdev) return ret; } -static int pt_gpio_remove(struct platform_device *pdev) +static void pt_gpio_remove(struct platform_device *pdev) { struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev); gpiochip_remove(&pt_gpio->gc); - - return 0; } static const struct acpi_device_id pt_gpio_acpi_match[] = { @@ -145,7 +143,7 @@ static struct platform_driver pt_gpio_driver = { .acpi_match_table = ACPI_PTR(pt_gpio_acpi_match), }, .probe = pt_gpio_probe, - .remove = pt_gpio_remove, + .remove_new = pt_gpio_remove, }; module_platform_driver(pt_gpio_driver); diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index bccdbfd5ec80..a789af4a5c85 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -371,7 +371,7 @@ static int brcmstb_gpio_sanity_check_banks(struct device *dev, } } -static int brcmstb_gpio_remove(struct platform_device *pdev) +static void brcmstb_gpio_remove(struct platform_device *pdev) { struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev); struct brcmstb_gpio_bank *bank; @@ -395,8 +395,6 @@ static int brcmstb_gpio_remove(struct platform_device *pdev) */ list_for_each_entry(bank, &priv->bank_list, node) gpiochip_remove(&bank->gc); - - return 0; } static int brcmstb_gpio_of_xlate(struct gpio_chip *gc, @@ -757,7 +755,7 @@ static struct platform_driver brcmstb_gpio_driver = { .pm = &brcmstb_gpio_pm_ops, }, .probe = brcmstb_gpio_probe, - .remove = brcmstb_gpio_remove, + .remove_new = brcmstb_gpio_remove, .shutdown = brcmstb_gpio_shutdown, }; module_platform_driver(brcmstb_gpio_driver); diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c index 3720b90cad10..6a439cf78459 100644 --- a/drivers/gpio/gpio-cadence.c +++ b/drivers/gpio/gpio-cadence.c @@ -268,14 +268,12 @@ err_revert_dir: return ret; } -static int cdns_gpio_remove(struct platform_device *pdev) +static void cdns_gpio_remove(struct platform_device *pdev) { struct cdns_gpio_chip *cgpio = platform_get_drvdata(pdev); iowrite32(cgpio->bypass_orig, cgpio->regs + CDNS_GPIO_BYPASS_MODE); clk_disable_unprepare(cgpio->pclk); - - return 0; } static const struct of_device_id cdns_of_ids[] = { @@ -290,7 +288,7 @@ static struct platform_driver cdns_gpio_driver = { .of_match_table = cdns_of_ids, }, .probe = cdns_gpio_probe, - .remove = cdns_gpio_remove, + .remove_new = cdns_gpio_remove, }; module_platform_driver(cdns_gpio_driver); diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 8db5717bdabe..bb499e362912 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -16,10 +16,10 @@ #include <linux/irqdomain.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/platform_data/gpio-davinci.h> +#include <linux/property.h> #include <linux/irqchip/chained_irq.h> #include <linux/spinlock.h> #include <linux/pm_runtime.h> @@ -486,7 +486,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) struct davinci_gpio_platform_data *pdata = dev->platform_data; struct davinci_gpio_regs __iomem *g; struct irq_domain *irq_domain = NULL; - const struct of_device_id *match; struct irq_chip *irq_chip; struct davinci_gpio_irq_data *irqdata; gpio_get_irq_chip_cb_t gpio_get_irq_chip; @@ -495,10 +494,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * Use davinci_gpio_get_irq_chip by default to handle non DT cases */ gpio_get_irq_chip = davinci_gpio_get_irq_chip; - match = of_match_device(of_match_ptr(davinci_gpio_ids), - dev); - if (match) - gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data; + if (dev->of_node) + gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)device_get_match_data(dev); ngpio = pdata->ngpio; diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index 71fa437b491f..7ead1f51128a 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -504,17 +504,15 @@ static int dln2_gpio_probe(struct platform_device *pdev) return 0; } -static int dln2_gpio_remove(struct platform_device *pdev) +static void dln2_gpio_remove(struct platform_device *pdev) { dln2_unregister_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV); - - return 0; } static struct platform_driver dln2_gpio_driver = { .driver.name = "dln2-gpio", .probe = dln2_gpio_probe, - .remove = dln2_gpio_remove, + .remove_new = dln2_gpio_remove, }; module_platform_driver(dln2_gpio_driver); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index c22fcaa44a61..4a4f61bf6c58 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -21,7 +21,6 @@ #include <linux/slab.h> #include <linux/spinlock.h> -#include "gpiolib.h" #include "gpiolib-acpi.h" #define GPIO_SWPORTA_DR 0x00 diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c index 5320cf1de89c..be7f2fa5aa7b 100644 --- a/drivers/gpio/gpio-eic-sprd.c +++ b/drivers/gpio/gpio-eic-sprd.c @@ -9,6 +9,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/notifier.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/spinlock.h> @@ -91,12 +92,20 @@ enum sprd_eic_type { struct sprd_eic { struct gpio_chip chip; + struct notifier_block irq_nb; void __iomem *base[SPRD_EIC_MAX_BANK]; enum sprd_eic_type type; spinlock_t lock; int irq; }; +static ATOMIC_NOTIFIER_HEAD(sprd_eic_irq_notifier); + +static struct sprd_eic *to_sprd_eic(struct notifier_block *nb) +{ + return container_of(nb, struct sprd_eic, irq_nb); +} + struct sprd_eic_variant_data { enum sprd_eic_type type; u32 num_eics; @@ -494,13 +503,6 @@ retry: sprd_eic_irq_unmask(data); } -static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data) -{ - enum sprd_eic_type type = *(enum sprd_eic_type *)data; - - return !strcmp(chip->label, sprd_eic_label_name[type]); -} - static void sprd_eic_handle_one_type(struct gpio_chip *chip) { struct sprd_eic *sprd_eic = gpiochip_get_data(chip); @@ -546,27 +548,29 @@ static void sprd_eic_handle_one_type(struct gpio_chip *chip) static void sprd_eic_irq_handler(struct irq_desc *desc) { struct irq_chip *ic = irq_desc_get_chip(desc); - struct gpio_chip *chip; - enum sprd_eic_type type; chained_irq_enter(ic, desc); /* * Since the digital-chip EIC 4 sub-modules (debounce, latch, async - * and sync) share one same interrupt line, we should iterate each - * EIC module to check if there are EIC interrupts were triggered. + * and sync) share one same interrupt line, we should notify all of + * them to let them check if there are EIC interrupts were triggered. */ - for (type = SPRD_EIC_DEBOUNCE; type < SPRD_EIC_MAX; type++) { - chip = gpiochip_find(&type, sprd_eic_match_chip_by_type); - if (!chip) - continue; - - sprd_eic_handle_one_type(chip); - } + atomic_notifier_call_chain(&sprd_eic_irq_notifier, 0, NULL); chained_irq_exit(ic, desc); } +static int sprd_eic_irq_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct sprd_eic *sprd_eic = to_sprd_eic(nb); + + sprd_eic_handle_one_type(&sprd_eic->chip); + + return NOTIFY_OK; +} + static const struct irq_chip sprd_eic_irq = { .name = "sprd-eic", .irq_ack = sprd_eic_irq_ack, @@ -576,21 +580,30 @@ static const struct irq_chip sprd_eic_irq = { .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, GPIOCHIP_IRQ_RESOURCE_HELPERS, }; + +static void sprd_eic_unregister_notifier(void *data) +{ + struct notifier_block *nb = data; + + atomic_notifier_chain_unregister(&sprd_eic_irq_notifier, nb); +} + static int sprd_eic_probe(struct platform_device *pdev) { const struct sprd_eic_variant_data *pdata; + struct device *dev = &pdev->dev; struct gpio_irq_chip *irq; struct sprd_eic *sprd_eic; struct resource *res; int ret, i; - pdata = of_device_get_match_data(&pdev->dev); + pdata = of_device_get_match_data(dev); if (!pdata) { - dev_err(&pdev->dev, "No matching driver data found.\n"); + dev_err(dev, "No matching driver data found.\n"); return -EINVAL; } - sprd_eic = devm_kzalloc(&pdev->dev, sizeof(*sprd_eic), GFP_KERNEL); + sprd_eic = devm_kzalloc(dev, sizeof(*sprd_eic), GFP_KERNEL); if (!sprd_eic) return -ENOMEM; @@ -612,7 +625,7 @@ static int sprd_eic_probe(struct platform_device *pdev) if (!res) break; - sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res); + sprd_eic->base[i] = devm_ioremap_resource(dev, res); if (IS_ERR(sprd_eic->base[i])) return PTR_ERR(sprd_eic->base[i]); } @@ -620,7 +633,7 @@ static int sprd_eic_probe(struct platform_device *pdev) sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type]; sprd_eic->chip.ngpio = pdata->num_eics; sprd_eic->chip.base = -1; - sprd_eic->chip.parent = &pdev->dev; + sprd_eic->chip.parent = dev; sprd_eic->chip.direction_input = sprd_eic_direction_input; switch (sprd_eic->type) { case SPRD_EIC_DEBOUNCE: @@ -647,13 +660,21 @@ static int sprd_eic_probe(struct platform_device *pdev) irq->num_parents = 1; irq->parents = &sprd_eic->irq; - ret = devm_gpiochip_add_data(&pdev->dev, &sprd_eic->chip, sprd_eic); + ret = devm_gpiochip_add_data(dev, &sprd_eic->chip, sprd_eic); if (ret < 0) { - dev_err(&pdev->dev, "Could not register gpiochip %d.\n", ret); + dev_err(dev, "Could not register gpiochip %d.\n", ret); return ret; } - return 0; + sprd_eic->irq_nb.notifier_call = sprd_eic_irq_notify; + ret = atomic_notifier_chain_register(&sprd_eic_irq_notifier, + &sprd_eic->irq_nb); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register with the interrupt notifier"); + + return devm_add_action_or_reset(dev, sprd_eic_unregister_notifier, + &sprd_eic->irq_nb); } static const struct of_device_id sprd_eic_of_match[] = { diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index f54ca5a1775e..3875fd940ccb 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -163,7 +163,7 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value); static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset, unsigned long config); -#define F7188X_GPIO_BANK(_base, _ngpio, _regbase, _label) \ +#define F7188X_GPIO_BANK(_ngpio, _regbase, _label) \ { \ .chip = { \ .label = _label, \ @@ -174,7 +174,7 @@ static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset, .direction_output = f7188x_gpio_direction_out, \ .set = f7188x_gpio_set, \ .set_config = f7188x_gpio_set_config, \ - .base = _base, \ + .base = -1, \ .ngpio = _ngpio, \ .can_sleep = true, \ }, \ @@ -191,98 +191,98 @@ static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset, #define f7188x_gpio_data_single(type) ((type) == nct6126d) static struct f7188x_gpio_bank f71869_gpio_bank[] = { - F7188X_GPIO_BANK(0, 6, 0xF0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"), - F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"), - F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"), - F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"), - F7188X_GPIO_BANK(60, 6, 0x90, DRVNAME "-6"), + F7188X_GPIO_BANK(6, 0xF0, DRVNAME "-0"), + F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"), + F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"), + F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"), + F7188X_GPIO_BANK(5, 0xA0, DRVNAME "-5"), + F7188X_GPIO_BANK(6, 0x90, DRVNAME "-6"), }; static struct f7188x_gpio_bank f71869a_gpio_bank[] = { - F7188X_GPIO_BANK(0, 6, 0xF0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"), - F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"), - F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"), - F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"), - F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"), - F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"), + F7188X_GPIO_BANK(6, 0xF0, DRVNAME "-0"), + F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"), + F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"), + F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"), + F7188X_GPIO_BANK(5, 0xA0, DRVNAME "-5"), + F7188X_GPIO_BANK(8, 0x90, DRVNAME "-6"), + F7188X_GPIO_BANK(8, 0x80, DRVNAME "-7"), }; static struct f7188x_gpio_bank f71882_gpio_bank[] = { - F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"), - F7188X_GPIO_BANK(30, 4, 0xC0, DRVNAME "-3"), - F7188X_GPIO_BANK(40, 4, 0xB0, DRVNAME "-4"), + F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-0"), + F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"), + F7188X_GPIO_BANK(4, 0xC0, DRVNAME "-3"), + F7188X_GPIO_BANK(4, 0xB0, DRVNAME "-4"), }; static struct f7188x_gpio_bank f71889a_gpio_bank[] = { - F7188X_GPIO_BANK(0, 7, 0xF0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 7, 0xE0, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"), - F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"), - F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"), - F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"), - F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"), - F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"), + F7188X_GPIO_BANK(7, 0xF0, DRVNAME "-0"), + F7188X_GPIO_BANK(7, 0xE0, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"), + F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"), + F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"), + F7188X_GPIO_BANK(5, 0xA0, DRVNAME "-5"), + F7188X_GPIO_BANK(8, 0x90, DRVNAME "-6"), + F7188X_GPIO_BANK(8, 0x80, DRVNAME "-7"), }; static struct f7188x_gpio_bank f71889_gpio_bank[] = { - F7188X_GPIO_BANK(0, 7, 0xF0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 7, 0xE0, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"), - F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"), - F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"), - F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"), - F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"), - F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"), + F7188X_GPIO_BANK(7, 0xF0, DRVNAME "-0"), + F7188X_GPIO_BANK(7, 0xE0, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"), + F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"), + F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"), + F7188X_GPIO_BANK(5, 0xA0, DRVNAME "-5"), + F7188X_GPIO_BANK(8, 0x90, DRVNAME "-6"), + F7188X_GPIO_BANK(8, 0x80, DRVNAME "-7"), }; static struct f7188x_gpio_bank f81866_gpio_bank[] = { - F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"), - F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"), - F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"), - F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-5"), - F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"), - F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"), - F7188X_GPIO_BANK(80, 8, 0x88, DRVNAME "-8"), + F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-0"), + F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"), + F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"), + F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"), + F7188X_GPIO_BANK(8, 0xA0, DRVNAME "-5"), + F7188X_GPIO_BANK(8, 0x90, DRVNAME "-6"), + F7188X_GPIO_BANK(8, 0x80, DRVNAME "-7"), + F7188X_GPIO_BANK(8, 0x88, DRVNAME "-8"), }; static struct f7188x_gpio_bank f81804_gpio_bank[] = { - F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"), - F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-3"), - F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-4"), - F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-5"), - F7188X_GPIO_BANK(90, 8, 0x98, DRVNAME "-6"), + F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-0"), + F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"), + F7188X_GPIO_BANK(8, 0xA0, DRVNAME "-3"), + F7188X_GPIO_BANK(8, 0x90, DRVNAME "-4"), + F7188X_GPIO_BANK(8, 0x80, DRVNAME "-5"), + F7188X_GPIO_BANK(8, 0x98, DRVNAME "-6"), }; static struct f7188x_gpio_bank f81865_gpio_bank[] = { - F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"), - F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"), - F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"), - F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-5"), - F7188X_GPIO_BANK(60, 5, 0x90, DRVNAME "-6"), + F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-0"), + F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"), + F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"), + F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"), + F7188X_GPIO_BANK(8, 0xA0, DRVNAME "-5"), + F7188X_GPIO_BANK(5, 0x90, DRVNAME "-6"), }; static struct f7188x_gpio_bank nct6126d_gpio_bank[] = { - F7188X_GPIO_BANK(0, 8, 0xE0, DRVNAME "-0"), - F7188X_GPIO_BANK(10, 8, 0xE4, DRVNAME "-1"), - F7188X_GPIO_BANK(20, 8, 0xE8, DRVNAME "-2"), - F7188X_GPIO_BANK(30, 8, 0xEC, DRVNAME "-3"), - F7188X_GPIO_BANK(40, 8, 0xF0, DRVNAME "-4"), - F7188X_GPIO_BANK(50, 8, 0xF4, DRVNAME "-5"), - F7188X_GPIO_BANK(60, 8, 0xF8, DRVNAME "-6"), - F7188X_GPIO_BANK(70, 8, 0xFC, DRVNAME "-7"), + F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-0"), + F7188X_GPIO_BANK(8, 0xE4, DRVNAME "-1"), + F7188X_GPIO_BANK(8, 0xE8, DRVNAME "-2"), + F7188X_GPIO_BANK(8, 0xEC, DRVNAME "-3"), + F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-4"), + F7188X_GPIO_BANK(8, 0xF4, DRVNAME "-5"), + F7188X_GPIO_BANK(8, 0xF8, DRVNAME "-6"), + F7188X_GPIO_BANK(8, 0xFC, DRVNAME "-7"), }; static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index 5ce59dcf02e3..97d345b59352 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -324,13 +324,11 @@ dis_clk: return ret; } -static int ftgpio_gpio_remove(struct platform_device *pdev) +static void ftgpio_gpio_remove(struct platform_device *pdev) { struct ftgpio_gpio *g = platform_get_drvdata(pdev); clk_disable_unprepare(g->clk); - - return 0; } static const struct of_device_id ftgpio_gpio_of_match[] = { @@ -352,6 +350,6 @@ static struct platform_driver ftgpio_gpio_driver = { .of_match_table = ftgpio_gpio_of_match, }, .probe = ftgpio_gpio_probe, - .remove = ftgpio_gpio_remove, + .remove_new = ftgpio_gpio_remove, }; builtin_platform_driver(ftgpio_gpio_driver); diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c index c14b5cc5e519..991549888904 100644 --- a/drivers/gpio/gpio-fxl6408.c +++ b/drivers/gpio/gpio-fxl6408.c @@ -84,7 +84,7 @@ static const struct regmap_config regmap = { .rd_table = &rd_table, .volatile_table = &volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .num_reg_defaults_raw = FXL6408_REG_INT_STS + 1, }; diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 0163c95f6dd7..017c7170eb57 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -431,7 +431,7 @@ static int grgpio_probe(struct platform_device *ofdev) return 0; } -static int grgpio_remove(struct platform_device *ofdev) +static void grgpio_remove(struct platform_device *ofdev) { struct grgpio_priv *priv = platform_get_drvdata(ofdev); @@ -439,8 +439,6 @@ static int grgpio_remove(struct platform_device *ofdev) if (priv->domain) irq_domain_remove(priv->domain); - - return 0; } static const struct of_device_id grgpio_match[] = { @@ -457,7 +455,7 @@ static struct platform_driver grgpio_driver = { .of_match_table = grgpio_match, }, .probe = grgpio_probe, - .remove = grgpio_remove, + .remove_new = grgpio_remove, }; module_platform_driver(grgpio_driver); diff --git a/drivers/gpio/gpio-hisi.c b/drivers/gpio/gpio-hisi.c index 29a03de37fd8..ef5cc654a24e 100644 --- a/drivers/gpio/gpio-hisi.c +++ b/drivers/gpio/gpio-hisi.c @@ -255,7 +255,7 @@ static void hisi_gpio_get_pdata(struct device *dev, hisi_gpio->irq = platform_get_irq(pdev, idx); dev_info(dev, - "get hisi_gpio[%d] with %d lines\n", idx, + "get hisi_gpio[%d] with %u lines\n", idx, hisi_gpio->line_num); idx++; diff --git a/drivers/gpio/gpio-ljca.c b/drivers/gpio/gpio-ljca.c index 87863f0230f5..aca69329455f 100644 --- a/drivers/gpio/gpio-ljca.c +++ b/drivers/gpio/gpio-ljca.c @@ -421,7 +421,7 @@ static int ljca_gpio_probe(struct platform_device *pdev) return ret; } -static int ljca_gpio_remove(struct platform_device *pdev) +static void ljca_gpio_remove(struct platform_device *pdev) { struct ljca_gpio_dev *ljca_gpio = platform_get_drvdata(pdev); @@ -429,7 +429,6 @@ static int ljca_gpio_remove(struct platform_device *pdev) ljca_unregister_event_cb(ljca_gpio->gpio_info->ljca); mutex_destroy(&ljca_gpio->irq_lock); mutex_destroy(&ljca_gpio->trans_lock); - return 0; } #define LJCA_GPIO_DRV_NAME "ljca-gpio" @@ -442,7 +441,7 @@ MODULE_DEVICE_TABLE(platform, ljca_gpio_id); static struct platform_driver ljca_gpio_driver = { .driver.name = LJCA_GPIO_DRV_NAME, .probe = ljca_gpio_probe, - .remove = ljca_gpio_remove, + .remove_new = ljca_gpio_remove, }; module_platform_driver(ljca_gpio_driver); diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c index 06213bbfabdd..6749d4dd6d64 100644 --- a/drivers/gpio/gpio-loongson-64bit.c +++ b/drivers/gpio/gpio-loongson-64bit.c @@ -26,6 +26,7 @@ struct loongson_gpio_chip_data { unsigned int conf_offset; unsigned int out_offset; unsigned int in_offset; + unsigned int inten_offset; }; struct loongson_gpio_chip { @@ -117,19 +118,29 @@ static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int valu static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) { + unsigned int u; struct platform_device *pdev = to_platform_device(chip->parent); + struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); + + if (lgpio->chip_data->mode == BIT_CTRL_MODE) { + /* Get the register index from offset then multiply by bytes per register */ + u = readl(lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4); + u |= BIT(offset % 32); + writel(u, lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4); + } else { + writeb(1, lgpio->reg_base + lgpio->chip_data->inten_offset + offset); + } return platform_get_irq(pdev, offset); } static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgpio, - struct device_node *np, void __iomem *reg_base) + void __iomem *reg_base) { int ret; u32 ngpios; lgpio->reg_base = reg_base; - if (lgpio->chip_data->mode == BIT_CTRL_MODE) { ret = bgpio_init(&lgpio->chip, dev, 8, lgpio->reg_base + lgpio->chip_data->in_offset, @@ -148,15 +159,15 @@ static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgp lgpio->chip.direction_output = loongson_gpio_direction_output; lgpio->chip.set = loongson_gpio_set; lgpio->chip.parent = dev; + device_property_read_u32(dev, "ngpios", &ngpios); + lgpio->chip.ngpio = ngpios; spin_lock_init(&lgpio->lock); } - device_property_read_u32(dev, "ngpios", &ngpios); - - lgpio->chip.can_sleep = 0; - lgpio->chip.ngpio = ngpios; lgpio->chip.label = lgpio->chip_data->label; - lgpio->chip.to_irq = loongson_gpio_to_irq; + lgpio->chip.can_sleep = false; + if (lgpio->chip_data->inten_offset) + lgpio->chip.to_irq = loongson_gpio_to_irq; return devm_gpiochip_add_data(dev, &lgpio->chip, lgpio); } @@ -165,7 +176,6 @@ static int loongson_gpio_probe(struct platform_device *pdev) { void __iomem *reg_base; struct loongson_gpio_chip *lgpio; - struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL); @@ -178,7 +188,7 @@ static int loongson_gpio_probe(struct platform_device *pdev) if (IS_ERR(reg_base)) return PTR_ERR(reg_base); - return loongson_gpio_init(dev, lgpio, np, reg_base); + return loongson_gpio_init(dev, lgpio, reg_base); } static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { @@ -187,6 +197,57 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { .conf_offset = 0x0, .in_offset = 0x20, .out_offset = 0x10, + .inten_offset = 0x30, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data0 = { + .label = "ls2k0500_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0x8, + .out_offset = 0x10, + .inten_offset = 0xb0, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data1 = { + .label = "ls2k0500_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0x8, + .out_offset = 0x10, + .inten_offset = 0x98, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = { + .label = "ls2k2000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0xc, + .out_offset = 0x8, +}; + +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, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = { + .label = "ls2k2000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x84, + .in_offset = 0x88, + .out_offset = 0x80, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls3a5000_data = { + .label = "ls3a5000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0xc, + .out_offset = 0x8, }; static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { @@ -203,6 +264,30 @@ static const struct of_device_id loongson_gpio_of_match[] = { .data = &loongson_gpio_ls2k_data, }, { + .compatible = "loongson,ls2k0500-gpio0", + .data = &loongson_gpio_ls2k0500_data0, + }, + { + .compatible = "loongson,ls2k0500-gpio1", + .data = &loongson_gpio_ls2k0500_data1, + }, + { + .compatible = "loongson,ls2k2000-gpio0", + .data = &loongson_gpio_ls2k2000_data0, + }, + { + .compatible = "loongson,ls2k2000-gpio1", + .data = &loongson_gpio_ls2k2000_data1, + }, + { + .compatible = "loongson,ls2k2000-gpio2", + .data = &loongson_gpio_ls2k2000_data2, + }, + { + .compatible = "loongson,ls3a5000-gpio", + .data = &loongson_gpio_ls3a5000_data, + }, + { .compatible = "loongson,ls7a-gpio", .data = &loongson_gpio_ls7a_data, }, @@ -215,6 +300,22 @@ static const struct acpi_device_id loongson_gpio_acpi_match[] = { .id = "LOON0002", .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data, }, + { + .id = "LOON0007", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a5000_data, + }, + { + .id = "LOON000A", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data0, + }, + { + .id = "LOON000B", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data1, + }, + { + .id = "LOON000C", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data2, + }, {} }; MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match); diff --git a/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c index ed3f653a1dfc..5c6bb57a8c99 100644 --- a/drivers/gpio/gpio-lpc18xx.c +++ b/drivers/gpio/gpio-lpc18xx.c @@ -381,7 +381,7 @@ static int lpc18xx_gpio_probe(struct platform_device *pdev) return 0; } -static int lpc18xx_gpio_remove(struct platform_device *pdev) +static void lpc18xx_gpio_remove(struct platform_device *pdev) { struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev); @@ -389,8 +389,6 @@ static int lpc18xx_gpio_remove(struct platform_device *pdev) irq_domain_remove(gc->pin_ic->domain); clk_disable_unprepare(gc->clk); - - return 0; } static const struct of_device_id lpc18xx_gpio_match[] = { @@ -401,7 +399,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match); static struct platform_driver lpc18xx_gpio_driver = { .probe = lpc18xx_gpio_probe, - .remove = lpc18xx_gpio_remove, + .remove_new = lpc18xx_gpio_remove, .driver = { .name = "lpc18xx-gpio", .of_match_table = lpc18xx_gpio_match, diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index ca7eb5e8bfaa..7fb298b4571b 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -20,7 +20,6 @@ #include <linux/spinlock.h> #include <linux/slab.h> -#include "gpiolib.h" #include "gpiolib-acpi.h" /* @@ -205,15 +204,13 @@ static int mb86s70_gpio_probe(struct platform_device *pdev) return 0; } -static int mb86s70_gpio_remove(struct platform_device *pdev) +static void mb86s70_gpio_remove(struct platform_device *pdev) { struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); acpi_gpiochip_free_interrupts(&gchip->gc); gpiochip_remove(&gchip->gc); clk_disable_unprepare(gchip->clk); - - return 0; } static const struct of_device_id mb86s70_gpio_dt_ids[] = { @@ -237,7 +234,7 @@ static struct platform_driver mb86s70_gpio_driver = { .acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids), }, .probe = mb86s70_gpio_probe, - .remove = mb86s70_gpio_remove, + .remove_new = mb86s70_gpio_remove, }; module_platform_driver(mb86s70_gpio_driver); diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index f3c158259636..e855c68c981b 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -121,13 +121,11 @@ static int ltq_mm_probe(struct platform_device *pdev) return of_mm_gpiochip_add_data(pdev->dev.of_node, &chip->mmchip, chip); } -static int ltq_mm_remove(struct platform_device *pdev) +static void ltq_mm_remove(struct platform_device *pdev) { struct ltq_mm *chip = platform_get_drvdata(pdev); of_mm_gpiochip_remove(&chip->mmchip); - - return 0; } static const struct of_device_id ltq_mm_match[] = { @@ -138,7 +136,7 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match); static struct platform_driver ltq_mm_driver = { .probe = ltq_mm_probe, - .remove = ltq_mm_remove, + .remove_new = 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 74fdf0d87b2c..3ff0ea1e351c 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -56,9 +56,9 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` #include <linux/slab.h> #include <linux/bitops.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/mod_devicetable.h> #include <linux/of.h> -#include <linux/of_device.h> #include "gpiolib.h" @@ -702,7 +702,7 @@ static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, { struct bgpio_pdata *pdata; - if (!of_match_device(bgpio_of_match, &pdev->dev)) + if (!pdev->dev.of_node) return NULL; pdata = devm_kzalloc(&pdev->dev, sizeof(struct bgpio_pdata), diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index b32063ac845a..4870e267a402 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -9,7 +9,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/cleanup.h> #include <linux/debugfs.h> +#include <linux/device.h> #include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -24,8 +26,6 @@ #include <linux/string_helpers.h> #include <linux/uaccess.h> -#include "gpiolib.h" - #define GPIO_MOCKUP_MAX_GC 10 /* * We're storing two values per chip: the GPIO base and the number @@ -39,11 +39,15 @@ * struct gpio_pin_status - structure describing a GPIO status * @dir: Configures direction of gpio as "in" or "out" * @value: Configures status of the gpio as 0(low) or 1(high) + * @pull: Configures the current pull of the GPIO as 0 (pull-down) or + * 1 (pull-up) + * @requested: Request status of this GPIO */ struct gpio_mockup_line_status { int dir; int value; int pull; + bool requested; }; struct gpio_mockup_chip { @@ -56,7 +60,6 @@ struct gpio_mockup_chip { struct gpio_mockup_dbgfs_private { struct gpio_mockup_chip *chip; - struct gpio_desc *desc; unsigned int offset; }; @@ -91,9 +94,8 @@ static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset) struct gpio_mockup_chip *chip = gpiochip_get_data(gc); int val; - mutex_lock(&chip->lock); - val = __gpio_mockup_get(chip, offset); - mutex_unlock(&chip->lock); + scoped_guard(mutex, &chip->lock) + val = __gpio_mockup_get(chip, offset); return val; } @@ -104,12 +106,12 @@ static int gpio_mockup_get_multiple(struct gpio_chip *gc, struct gpio_mockup_chip *chip = gpiochip_get_data(gc); unsigned int bit, val; - mutex_lock(&chip->lock); - for_each_set_bit(bit, mask, gc->ngpio) { - val = __gpio_mockup_get(chip, bit); - __assign_bit(bit, bits, val); + scoped_guard(mutex, &chip->lock) { + for_each_set_bit(bit, mask, gc->ngpio) { + val = __gpio_mockup_get(chip, bit); + __assign_bit(bit, bits, val); + } } - mutex_unlock(&chip->lock); return 0; } @@ -125,9 +127,9 @@ static void gpio_mockup_set(struct gpio_chip *gc, { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); + __gpio_mockup_set(chip, offset, value); - mutex_unlock(&chip->lock); } static void gpio_mockup_set_multiple(struct gpio_chip *gc, @@ -136,23 +138,21 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc, struct gpio_mockup_chip *chip = gpiochip_get_data(gc); unsigned int bit; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); + for_each_set_bit(bit, mask, gc->ngpio) __gpio_mockup_set(chip, bit, test_bit(bit, bits)); - mutex_unlock(&chip->lock); } static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip, unsigned int offset, int value) { - struct gpio_chip *gc = &chip->gc; - struct gpio_desc *desc = gpiochip_get_desc(gc, offset); + struct gpio_mockup_line_status *line = &chip->lines[offset]; int curr, irq, irq_type, ret = 0; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); - if (test_bit(FLAG_REQUESTED, &desc->flags) && - !test_bit(FLAG_IS_OUT, &desc->flags)) { + if (line->requested && line->dir == GPIO_LINE_DIRECTION_IN) { curr = __gpio_mockup_get(chip, offset); if (curr == value) goto out; @@ -180,13 +180,11 @@ static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip, set_value: /* Change the value unless we're actively driving the line. */ - if (!test_bit(FLAG_REQUESTED, &desc->flags) || - !test_bit(FLAG_IS_OUT, &desc->flags)) + if (!line->requested || line->dir == GPIO_LINE_DIRECTION_IN) __gpio_mockup_set(chip, offset, value); out: chip->lines[offset].pull = value; - mutex_unlock(&chip->lock); return ret; } @@ -211,10 +209,10 @@ static int gpio_mockup_dirout(struct gpio_chip *gc, { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - mutex_lock(&chip->lock); - chip->lines[offset].dir = GPIO_LINE_DIRECTION_OUT; - __gpio_mockup_set(chip, offset, value); - mutex_unlock(&chip->lock); + scoped_guard(mutex, &chip->lock) { + chip->lines[offset].dir = GPIO_LINE_DIRECTION_OUT; + __gpio_mockup_set(chip, offset, value); + } return 0; } @@ -223,9 +221,8 @@ static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - mutex_lock(&chip->lock); - chip->lines[offset].dir = GPIO_LINE_DIRECTION_IN; - mutex_unlock(&chip->lock); + scoped_guard(mutex, &chip->lock) + chip->lines[offset].dir = GPIO_LINE_DIRECTION_IN; return 0; } @@ -235,9 +232,8 @@ static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset) struct gpio_mockup_chip *chip = gpiochip_get_data(gc); int direction; - mutex_lock(&chip->lock); - direction = chip->lines[offset].dir; - mutex_unlock(&chip->lock); + scoped_guard(mutex, &chip->lock) + direction = chip->lines[offset].dir; return direction; } @@ -249,10 +245,23 @@ static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset) return irq_create_mapping(chip->irq_sim_domain, offset); } +static int gpio_mockup_request(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); + + scoped_guard(mutex, &chip->lock) + chip->lines[offset].requested = true; + + return 0; +} + static void gpio_mockup_free(struct gpio_chip *gc, unsigned int offset) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); + guard(mutex)(&chip->lock); + + chip->lines[offset].requested = false; __gpio_mockup_set(chip, offset, chip->lines[offset].pull); } @@ -345,6 +354,7 @@ static const struct file_operations gpio_mockup_debugfs_ops = { static void gpio_mockup_debugfs_setup(struct device *dev, struct gpio_mockup_chip *chip) { + struct device *child __free(put_device) = NULL; struct gpio_mockup_dbgfs_private *priv; struct gpio_chip *gc; const char *devname; @@ -352,8 +362,16 @@ static void gpio_mockup_debugfs_setup(struct device *dev, int i; gc = &chip->gc; - devname = dev_name(&gc->gpiodev->dev); + /* + * There can only be a single GPIO device per platform device in + * gpio-mockup so using device_find_any_child() is OK. + */ + child = device_find_any_child(dev); + if (!child) + return; + + devname = dev_name(child); chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir); for (i = 0; i < gc->ngpio; i++) { @@ -367,7 +385,6 @@ static void gpio_mockup_debugfs_setup(struct device *dev, priv->chip = chip; priv->offset = i; - priv->desc = gpiochip_get_desc(gc, i); debugfs_create_file(name, 0600, chip->dbg_dir, priv, &gpio_mockup_debugfs_ops); @@ -438,6 +455,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) gc->get_direction = gpio_mockup_get_direction; gc->set_config = gpio_mockup_set_config; gc->to_irq = gpio_mockup_to_irq; + gc->request = gpio_mockup_request; gc->free = gpio_mockup_free; chip->lines = devm_kcalloc(dev, gc->ngpio, diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c index b49e3ca64015..a199dce3394a 100644 --- a/drivers/gpio/gpio-mpc5200.c +++ b/drivers/gpio/gpio-mpc5200.c @@ -165,13 +165,11 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) return 0; } -static int mpc52xx_gpiochip_remove(struct platform_device *ofdev) +static void mpc52xx_gpiochip_remove(struct platform_device *ofdev) { struct mpc52xx_gpiochip *chip = platform_get_drvdata(ofdev); of_mm_gpiochip_remove(&chip->mmchip); - - return 0; } static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = { @@ -185,7 +183,7 @@ static struct platform_driver mpc52xx_wkup_gpiochip_driver = { .of_match_table = mpc52xx_wkup_gpiochip_match, }, .probe = mpc52xx_wkup_gpiochip_probe, - .remove = mpc52xx_gpiochip_remove, + .remove_new = mpc52xx_gpiochip_remove, }; /* @@ -338,7 +336,7 @@ static struct platform_driver mpc52xx_simple_gpiochip_driver = { .of_match_table = mpc52xx_simple_gpiochip_match, }, .probe = mpc52xx_simple_gpiochip_probe, - .remove = mpc52xx_gpiochip_remove, + .remove_new = mpc52xx_gpiochip_remove, }; static struct platform_driver * const drivers[] = { diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index ebf2f511df59..c0125ac73906 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -419,7 +419,7 @@ err: return ret; } -static int mpc8xxx_remove(struct platform_device *pdev) +static void mpc8xxx_remove(struct platform_device *pdev) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev); @@ -427,8 +427,6 @@ static int mpc8xxx_remove(struct platform_device *pdev) irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, NULL, NULL); irq_domain_remove(mpc8xxx_gc->irq); } - - return 0; } #ifdef CONFIG_ACPI @@ -441,7 +439,7 @@ MODULE_DEVICE_TABLE(acpi, gpio_acpi_ids); static struct platform_driver mpc8xxx_plat_driver = { .probe = mpc8xxx_probe, - .remove = mpc8xxx_remove, + .remove_new = mpc8xxx_remove, .driver = { .name = "gpio-mpc8xxx", .of_match_table = mpc8xxx_gpio_ids, diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 67497116ce27..8f80ca8ec1ed 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -42,9 +42,10 @@ #include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> #include <linux/mfd/syscon.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/pwm.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -1122,7 +1123,6 @@ static void mvebu_gpio_remove_irq_domain(void *data) static int mvebu_gpio_probe(struct platform_device *pdev) { struct mvebu_gpio_chip *mvchip; - const struct of_device_id *match; struct device_node *np = pdev->dev.of_node; struct irq_chip_generic *gc; struct irq_chip_type *ct; @@ -1132,11 +1132,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) int i, cpu, id; int err; - match = of_match_device(mvebu_gpio_of_match, &pdev->dev); - if (match) - soc_variant = (unsigned long) match->data; - else - soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; + soc_variant = (unsigned long)device_get_match_data(&pdev->dev); /* Some gpio controllers do not provide irq support */ err = platform_irq_count(pdev); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index a927680c66f8..76d5d87e9681 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1048,15 +1048,14 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct device *pm_dev) bank->chip.label = "mpuio"; if (bank->regs->wkup_en) bank->chip.parent = &omap_mpuio_device.dev; - bank->chip.base = OMAP_MPUIO(0); } else { label = devm_kasprintf(bank->chip.parent, GFP_KERNEL, "gpio-%d-%d", gpio, gpio + bank->width - 1); if (!label) return -ENOMEM; bank->chip.label = label; - bank->chip.base = -1; } + bank->chip.base = -1; bank->chip.ngpio = bank->width; irq = &bank->chip.irq; @@ -1489,7 +1488,7 @@ static int omap_gpio_probe(struct platform_device *pdev) return 0; } -static int omap_gpio_remove(struct platform_device *pdev) +static void omap_gpio_remove(struct platform_device *pdev) { struct gpio_bank *bank = platform_get_drvdata(pdev); @@ -1498,8 +1497,6 @@ static int omap_gpio_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); if (bank->dbck_flag) clk_unprepare(bank->dbck); - - return 0; } static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev) @@ -1560,7 +1557,7 @@ static const struct dev_pm_ops gpio_pm_ops = { static struct platform_driver omap_gpio_driver = { .probe = omap_gpio_probe, - .remove = omap_gpio_remove, + .remove_new = omap_gpio_remove, .driver = { .name = "omap_gpio", .pm = &gpio_pm_ops, diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index bdd50a78e414..00ffa168e405 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -8,22 +8,30 @@ * Derived from drivers/i2c/chips/pca9539.c */ -#include <linux/acpi.h> +#include <linux/atomic.h> #include <linux/bitmap.h> -#include <linux/gpio/consumer.h> -#include <linux/gpio/driver.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/errno.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/platform_data/pca953x.h> +#include <linux/mutex.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/seq_file.h> #include <linux/slab.h> -#include <asm/unaligned.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> + +#include <linux/pinctrl/pinconf-generic.h> + +#include <linux/platform_data/pca953x.h> #define PCA953X_INPUT 0x00 #define PCA953X_OUTPUT 0x01 @@ -118,6 +126,7 @@ MODULE_DEVICE_TABLE(i2c, pca953x_id); #ifdef CONFIG_GPIO_PCA953X_IRQ +#include <linux/acpi.h> #include <linux/dmi.h> static const struct acpi_gpio_params pca953x_irq_gpios = { 0, 0, true }; @@ -211,7 +220,6 @@ struct pca953x_chip { struct i2c_client *client; struct gpio_chip gpio_chip; - const char *const *names; unsigned long driver_data; struct regulator *regulator; @@ -414,7 +422,7 @@ static const struct regmap_config pca953x_i2c_regmap = { .volatile_reg = pca953x_volatile_register, .disable_locking = true, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 0x7f, }; @@ -430,7 +438,7 @@ static const struct regmap_config pca953x_ai_i2c_regmap = { .volatile_reg = pca953x_volatile_register, .disable_locking = true, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 0x7f, }; @@ -520,12 +528,10 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) struct pca953x_chip *chip = gpiochip_get_data(gc); u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); u8 bit = BIT(off % BANK_SZ); - int ret; - mutex_lock(&chip->i2c_lock); - ret = regmap_write_bits(chip->regmap, dirreg, bit, bit); - mutex_unlock(&chip->i2c_lock); - return ret; + guard(mutex)(&chip->i2c_lock); + + return regmap_write_bits(chip->regmap, dirreg, bit, bit); } static int pca953x_gpio_direction_output(struct gpio_chip *gc, @@ -537,17 +543,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, u8 bit = BIT(off % BANK_SZ); int ret; - mutex_lock(&chip->i2c_lock); + guard(mutex)(&chip->i2c_lock); + /* set output level */ ret = regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0); if (ret) - goto exit; + return ret; /* then direction */ - ret = regmap_write_bits(chip->regmap, dirreg, bit, 0); -exit: - mutex_unlock(&chip->i2c_lock); - return ret; + return regmap_write_bits(chip->regmap, dirreg, bit, 0); } static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) @@ -558,9 +562,8 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) u32 reg_val; int ret; - mutex_lock(&chip->i2c_lock); - ret = regmap_read(chip->regmap, inreg, ®_val); - mutex_unlock(&chip->i2c_lock); + scoped_guard(mutex, &chip->i2c_lock) + ret = regmap_read(chip->regmap, inreg, ®_val); if (ret < 0) return ret; @@ -573,9 +576,9 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) u8 outreg = chip->recalc_addr(chip, chip->regs->output, off); u8 bit = BIT(off % BANK_SZ); - mutex_lock(&chip->i2c_lock); + guard(mutex)(&chip->i2c_lock); + regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0); - mutex_unlock(&chip->i2c_lock); } static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) @@ -586,9 +589,8 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) u32 reg_val; int ret; - mutex_lock(&chip->i2c_lock); - ret = regmap_read(chip->regmap, dirreg, ®_val); - mutex_unlock(&chip->i2c_lock); + scoped_guard(mutex, &chip->i2c_lock) + ret = regmap_read(chip->regmap, dirreg, ®_val); if (ret < 0) return ret; @@ -605,9 +607,8 @@ static int pca953x_gpio_get_multiple(struct gpio_chip *gc, DECLARE_BITMAP(reg_val, MAX_LINE); int ret; - mutex_lock(&chip->i2c_lock); - ret = pca953x_read_regs(chip, chip->regs->input, reg_val); - mutex_unlock(&chip->i2c_lock); + scoped_guard(mutex, &chip->i2c_lock) + ret = pca953x_read_regs(chip, chip->regs->input, reg_val); if (ret) return ret; @@ -622,16 +623,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc, DECLARE_BITMAP(reg_val, MAX_LINE); int ret; - mutex_lock(&chip->i2c_lock); + guard(mutex)(&chip->i2c_lock); + ret = pca953x_read_regs(chip, chip->regs->output, reg_val); if (ret) - goto exit; + return; bitmap_replace(reg_val, reg_val, bits, mask, gc->ngpio); pca953x_write_regs(chip, chip->regs->output, reg_val); -exit: - mutex_unlock(&chip->i2c_lock); } static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, @@ -639,7 +639,6 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, unsigned long config) { enum pin_config_param param = pinconf_to_config_param(config); - u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset); u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset); u8 bit = BIT(offset % BANK_SZ); @@ -652,7 +651,7 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, if (!(chip->driver_data & PCA_PCAL)) return -ENOTSUPP; - mutex_lock(&chip->i2c_lock); + guard(mutex)(&chip->i2c_lock); /* Configure pull-up/pull-down */ if (param == PIN_CONFIG_BIAS_PULL_UP) @@ -662,17 +661,13 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, else ret = 0; if (ret) - goto exit; + return ret; /* Disable/Enable pull-up/pull-down */ if (param == PIN_CONFIG_BIAS_DISABLE) - ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0); + return regmap_write_bits(chip->regmap, pull_en_reg, bit, 0); else - ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit); - -exit: - mutex_unlock(&chip->i2c_lock); - return ret; + return regmap_write_bits(chip->regmap, pull_en_reg, bit, bit); } static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset, @@ -693,9 +688,7 @@ static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset, static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) { - struct gpio_chip *gc; - - gc = &chip->gpio_chip; + struct gpio_chip *gc = &chip->gpio_chip; gc->direction_input = pca953x_gpio_direction_input; gc->direction_output = pca953x_gpio_direction_output; @@ -712,7 +705,6 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->label = dev_name(&chip->client->dev); gc->parent = &chip->client->dev; gc->owner = THIS_MODULE; - gc->names = chip->names; } #ifdef CONFIG_GPIO_PCA953X_IRQ @@ -793,11 +785,11 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = gpiochip_get_data(gc); + struct device *dev = &chip->client->dev; irq_hw_number_t hwirq = irqd_to_hwirq(d); if (!(type & IRQ_TYPE_EDGE_BOTH)) { - dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", - d->irq, type); + dev_err(dev, "irq %d: unsupported type %d\n", d->irq, type); return -EINVAL; } @@ -902,10 +894,8 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) bitmap_zero(pending, MAX_LINE); - mutex_lock(&chip->i2c_lock); - ret = pca953x_irq_pending(chip, pending); - mutex_unlock(&chip->i2c_lock); - + scoped_guard(mutex, &chip->i2c_lock) + ret = pca953x_irq_pending(chip, pending); if (ret) { ret = 0; @@ -928,13 +918,15 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) { struct i2c_client *client = chip->client; + struct device *dev = &client->dev; DECLARE_BITMAP(reg_direction, MAX_LINE); DECLARE_BITMAP(irq_stat, MAX_LINE); + struct gpio_chip *gc = &chip->gpio_chip; struct gpio_irq_chip *girq; int ret; if (dmi_first_match(pca953x_dmi_acpi_irq_info)) { - ret = pca953x_acpi_get_irq(&client->dev); + ret = pca953x_acpi_get_irq(dev); if (ret > 0) client->irq = ret; } @@ -958,7 +950,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) * this purpose. */ pca953x_read_regs(chip, chip->regs->direction, reg_direction); - bitmap_and(chip->irq_stat, irq_stat, reg_direction, chip->gpio_chip.ngpio); + bitmap_and(chip->irq_stat, irq_stat, reg_direction, gc->ngpio); mutex_init(&chip->irq_lock); girq = &chip->gpio_chip.irq; @@ -972,33 +964,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) girq->threaded = true; girq->first = irq_base; /* FIXME: get rid of this */ - ret = devm_request_threaded_irq(&client->dev, client->irq, - NULL, pca953x_irq_handler, - IRQF_ONESHOT | IRQF_SHARED, - dev_name(&client->dev), chip); - if (ret) { - dev_err(&client->dev, "failed to request irq %d\n", - client->irq); - return ret; - } + ret = devm_request_threaded_irq(dev, client->irq, NULL, pca953x_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), + chip); + if (ret) + return dev_err_probe(dev, client->irq, "failed to request irq\n"); return 0; } #else /* CONFIG_GPIO_PCA953X_IRQ */ -static int pca953x_irq_setup(struct pca953x_chip *chip, - int irq_base) +static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) { struct i2c_client *client = chip->client; + struct device *dev = &client->dev; if (client->irq && irq_base != -1 && (chip->driver_data & PCA_INT)) - dev_warn(&client->dev, "interrupt support not compiled in\n"); + dev_warn(dev, "interrupt support not compiled in\n"); return 0; } #endif -static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert) +static int device_pca95xx_init(struct pca953x_chip *chip) { DECLARE_BITMAP(val, MAX_LINE); u8 regaddr; @@ -1008,68 +996,81 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert) ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1); if (ret) - goto out; + return ret; regaddr = chip->recalc_addr(chip, chip->regs->direction, 0); ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1); if (ret) - goto out; + return ret; - /* set platform specific polarity inversion */ - if (invert) - bitmap_fill(val, MAX_LINE); - else - bitmap_zero(val, MAX_LINE); + /* clear polarity inversion */ + bitmap_zero(val, MAX_LINE); - ret = pca953x_write_regs(chip, chip->regs->invert, val); -out: - return ret; + return pca953x_write_regs(chip, chip->regs->invert, val); } -static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) +static int device_pca957x_init(struct pca953x_chip *chip) { DECLARE_BITMAP(val, MAX_LINE); unsigned int i; int ret; - ret = device_pca95xx_init(chip, invert); + ret = device_pca95xx_init(chip); if (ret) - goto out; + return ret; /* To enable register 6, 7 to control pull up and pull down */ for (i = 0; i < NBANK(chip); i++) bitmap_set_value8(val, 0x02, i * BANK_SZ); - ret = pca953x_write_regs(chip, PCA957X_BKEN, val); + return pca953x_write_regs(chip, PCA957X_BKEN, val); +} + +static void pca953x_disable_regulator(void *reg) +{ + regulator_disable(reg); +} + +static int pca953x_get_and_enable_regulator(struct pca953x_chip *chip) +{ + struct device *dev = &chip->client->dev; + struct regulator *reg = chip->regulator; + int ret; + + reg = devm_regulator_get(dev, "vcc"); + if (IS_ERR(reg)) + return dev_err_probe(dev, PTR_ERR(reg), "reg get err\n"); + + ret = regulator_enable(reg); if (ret) - goto out; + return dev_err_probe(dev, ret, "reg en err\n"); + ret = devm_add_action_or_reset(dev, pca953x_disable_regulator, reg); + if (ret) + return ret; + + chip->regulator = reg; return 0; -out: - return ret; } static int pca953x_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct pca953x_platform_data *pdata; struct pca953x_chip *chip; - int irq_base = 0; + int irq_base; int ret; - u32 invert = 0; - struct regulator *reg; const struct regmap_config *regmap_config; - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - pdata = dev_get_platdata(&client->dev); + pdata = dev_get_platdata(dev); if (pdata) { irq_base = pdata->irq_base; chip->gpio_start = pdata->gpio_base; - invert = pdata->invert; - chip->names = pdata->names; } else { struct gpio_desc *reset_gpio; @@ -1083,8 +1084,7 @@ static int pca953x_probe(struct i2c_client *client) * using "reset" GPIO. Otherwise any of those platform * must use _DSD method with corresponding property. */ - reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", - GPIOD_OUT_LOW); + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(reset_gpio)) return PTR_ERR(reset_gpio); } @@ -1094,26 +1094,19 @@ static int pca953x_probe(struct i2c_client *client) if (!chip->driver_data) return -ENODEV; - reg = devm_regulator_get(&client->dev, "vcc"); - if (IS_ERR(reg)) - return dev_err_probe(&client->dev, PTR_ERR(reg), "reg get err\n"); - - ret = regulator_enable(reg); - if (ret) { - dev_err(&client->dev, "reg en err: %d\n", ret); + ret = pca953x_get_and_enable_regulator(chip); + if (ret) return ret; - } - chip->regulator = reg; i2c_set_clientdata(client, chip); pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { - dev_info(&client->dev, "using AI\n"); + dev_info(dev, "using AI\n"); regmap_config = &pca953x_ai_i2c_regmap; } else { - dev_info(&client->dev, "using no AI\n"); + dev_info(dev, "using no AI\n"); regmap_config = &pca953x_i2c_regmap; } @@ -1126,10 +1119,8 @@ static int pca953x_probe(struct i2c_client *client) } chip->regmap = devm_regmap_init_i2c(client, regmap_config); - if (IS_ERR(chip->regmap)) { - ret = PTR_ERR(chip->regmap); - goto err_exit; - } + if (IS_ERR(chip->regmap)) + return PTR_ERR(chip->regmap); regcache_mark_dirty(chip->regmap); @@ -1158,53 +1149,24 @@ static int pca953x_probe(struct i2c_client *client) */ if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { chip->regs = &pca957x_regs; - ret = device_pca957x_init(chip, invert); + ret = device_pca957x_init(chip); } else { chip->regs = &pca953x_regs; - ret = device_pca95xx_init(chip, invert); + ret = device_pca95xx_init(chip); } if (ret) - goto err_exit; + return ret; ret = pca953x_irq_setup(chip, irq_base); if (ret) - goto err_exit; - - ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip); - if (ret) - goto err_exit; - - if (pdata && pdata->setup) { - ret = pdata->setup(client, chip->gpio_chip.base, - chip->gpio_chip.ngpio, pdata->context); - if (ret < 0) - dev_warn(&client->dev, "setup failed, %d\n", ret); - } - - return 0; - -err_exit: - regulator_disable(chip->regulator); - return ret; -} - -static void pca953x_remove(struct i2c_client *client) -{ - struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev); - struct pca953x_chip *chip = i2c_get_clientdata(client); - - if (pdata && pdata->teardown) { - pdata->teardown(client, chip->gpio_chip.base, - chip->gpio_chip.ngpio, pdata->context); - } + return ret; - regulator_disable(chip->regulator); + return devm_gpiochip_add_data(dev, &chip->gpio_chip, chip); } -#ifdef CONFIG_PM_SLEEP -static int pca953x_regcache_sync(struct device *dev) +static int pca953x_regcache_sync(struct pca953x_chip *chip) { - struct pca953x_chip *chip = dev_get_drvdata(dev); + struct device *dev = &chip->client->dev; int ret; u8 regaddr; @@ -1251,13 +1213,32 @@ static int pca953x_regcache_sync(struct device *dev) return 0; } +static int pca953x_restore_context(struct pca953x_chip *chip) +{ + int ret; + + guard(mutex)(&chip->i2c_lock); + + regcache_cache_only(chip->regmap, false); + regcache_mark_dirty(chip->regmap); + ret = pca953x_regcache_sync(chip); + if (ret) + return ret; + + return regcache_sync(chip->regmap); +} + +static void pca953x_save_context(struct pca953x_chip *chip) +{ + guard(mutex)(&chip->i2c_lock); + regcache_cache_only(chip->regmap, true); +} + static int pca953x_suspend(struct device *dev) { struct pca953x_chip *chip = dev_get_drvdata(dev); - mutex_lock(&chip->i2c_lock); - regcache_cache_only(chip->regmap, true); - mutex_unlock(&chip->i2c_lock); + pca953x_save_context(chip); if (atomic_read(&chip->wakeup_path)) device_set_wakeup_path(dev); @@ -1280,25 +1261,14 @@ static int pca953x_resume(struct device *dev) } } - mutex_lock(&chip->i2c_lock); - regcache_cache_only(chip->regmap, false); - regcache_mark_dirty(chip->regmap); - ret = pca953x_regcache_sync(dev); - if (ret) { - mutex_unlock(&chip->i2c_lock); - return ret; - } - - ret = regcache_sync(chip->regmap); - mutex_unlock(&chip->i2c_lock); - if (ret) { + ret = pca953x_restore_context(chip); + if (ret) dev_err(dev, "Failed to restore register map: %d\n", ret); - return ret; - } - return 0; + return ret; } -#endif + +static DEFINE_SIMPLE_DEV_PM_OPS(pca953x_pm_ops, pca953x_suspend, pca953x_resume); /* convenience to stop overlong match-table lines */ #define OF_653X(__nrgpio, __int) ((void *)(__nrgpio | PCAL653X_TYPE | __int)) @@ -1356,17 +1326,14 @@ static const struct of_device_id pca953x_dt_ids[] = { MODULE_DEVICE_TABLE(of, pca953x_dt_ids); -static SIMPLE_DEV_PM_OPS(pca953x_pm_ops, pca953x_suspend, pca953x_resume); - static struct i2c_driver pca953x_driver = { .driver = { .name = "pca953x", - .pm = &pca953x_pm_ops, + .pm = pm_sleep_ptr(&pca953x_pm_ops), .of_match_table = pca953x_dt_ids, .acpi_match_table = pca953x_acpi_ids, }, .probe = pca953x_probe, - .remove = pca953x_remove, .id_table = pca953x_id, }; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 86e69cde04da..d8b1baae6357 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -583,14 +583,13 @@ err0: return ret; } -static int gpio_rcar_remove(struct platform_device *pdev) +static void gpio_rcar_remove(struct platform_device *pdev) { struct gpio_rcar_priv *p = platform_get_drvdata(pdev); gpiochip_remove(&p->gpio_chip); pm_runtime_disable(&pdev->dev); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -658,7 +657,7 @@ static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume); static struct platform_driver gpio_rcar_device_driver = { .probe = gpio_rcar_probe, - .remove = gpio_rcar_remove, + .remove_new = gpio_rcar_remove, .driver = { .name = "gpio_rcar", .pm = &gpio_rcar_pm_ops, diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index b35b9604413f..23040a8cea34 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -778,14 +778,12 @@ static int rockchip_gpio_probe(struct platform_device *pdev) return 0; } -static int rockchip_gpio_remove(struct platform_device *pdev) +static void rockchip_gpio_remove(struct platform_device *pdev) { struct rockchip_pin_bank *bank = platform_get_drvdata(pdev); clk_disable_unprepare(bank->clk); gpiochip_remove(&bank->gpio_chip); - - return 0; } static const struct of_device_id rockchip_gpio_match[] = { @@ -796,7 +794,7 @@ static const struct of_device_id rockchip_gpio_match[] = { static struct platform_driver rockchip_gpio_driver = { .probe = rockchip_gpio_probe, - .remove = rockchip_gpio_remove, + .remove_new = rockchip_gpio_remove, .driver = { .name = "rockchip-gpio", .of_match_table = rockchip_gpio_match, diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 44bf1709a648..1928209491e1 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -12,6 +12,8 @@ #include <linux/completion.h> #include <linux/configfs.h> #include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> #include <linux/gpio/machine.h> #include <linux/idr.h> @@ -30,8 +32,7 @@ #include <linux/string.h> #include <linux/string_helpers.h> #include <linux/sysfs.h> - -#include "gpiolib.h" +#include <linux/types.h> #define GPIO_SIM_NGPIO_MAX 1024 #define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */ @@ -41,6 +42,8 @@ static DEFINE_IDA(gpio_sim_ida); struct gpio_sim_chip { struct gpio_chip gc; + struct device *dev; + unsigned long *request_map; unsigned long *direction_map; unsigned long *value_map; unsigned long *pull_map; @@ -64,16 +67,11 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip, unsigned int offset, int value) { int irq, irq_type, ret; - struct gpio_desc *desc; - struct gpio_chip *gc; - - gc = &chip->gc; - desc = &gc->gpiodev->descs[offset]; guard(mutex)(&chip->lock); - if (test_bit(FLAG_REQUESTED, &desc->flags) && - !test_bit(FLAG_IS_OUT, &desc->flags)) { + if (test_bit(offset, chip->request_map) && + test_bit(offset, chip->direction_map)) { if (value == !!test_bit(offset, chip->value_map)) goto set_pull; @@ -100,8 +98,8 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip, set_value: /* Change the value unless we're actively driving the line. */ - if (!test_bit(FLAG_REQUESTED, &desc->flags) || - !test_bit(FLAG_IS_OUT, &desc->flags)) + if (!test_bit(offset, chip->request_map) || + test_bit(offset, chip->direction_map)) __assign_bit(offset, chip->value_map, value); set_pull: @@ -181,8 +179,8 @@ static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset) return direction ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } -static int gpio_sim_set_config(struct gpio_chip *gc, - unsigned int offset, unsigned long config) +static int gpio_sim_set_config(struct gpio_chip *gc, unsigned int offset, + unsigned long config) { struct gpio_sim_chip *chip = gpiochip_get_data(gc); @@ -205,13 +203,25 @@ static int gpio_sim_to_irq(struct gpio_chip *gc, unsigned int offset) return irq_create_mapping(chip->irq_sim, offset); } -static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) +static int gpio_sim_request(struct gpio_chip *gc, unsigned int offset) { struct gpio_sim_chip *chip = gpiochip_get_data(gc); scoped_guard(mutex, &chip->lock) + __set_bit(offset, chip->request_map); + + return 0; +} + +static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + scoped_guard(mutex, &chip->lock) { __assign_bit(offset, chip->value_map, !!test_bit(offset, chip->pull_map)); + __clear_bit(offset, chip->request_map); + } } static ssize_t gpio_sim_sysfs_val_show(struct device *dev, @@ -283,6 +293,13 @@ static void gpio_sim_mutex_destroy(void *data) mutex_destroy(lock); } +static void gpio_sim_put_device(void *data) +{ + struct device *dev = data; + + put_device(dev); +} + static void gpio_sim_dispose_mappings(void *data) { struct gpio_sim_chip *chip = data; @@ -296,7 +313,7 @@ static void gpio_sim_sysfs_remove(void *data) { struct gpio_sim_chip *chip = data; - sysfs_remove_groups(&chip->gc.gpiodev->dev.kobj, chip->attr_groups); + sysfs_remove_groups(&chip->dev->kobj, chip->attr_groups); } static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip) @@ -353,14 +370,18 @@ static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip) chip->attr_groups[i] = attr_group; } - ret = sysfs_create_groups(&chip->gc.gpiodev->dev.kobj, - chip->attr_groups); + ret = sysfs_create_groups(&chip->dev->kobj, chip->attr_groups); if (ret) return ret; return devm_add_action_or_reset(dev, gpio_sim_sysfs_remove, chip); } +static int gpio_sim_dev_match_fwnode(struct device *dev, void *data) +{ + return device_match_fwnode(dev, data); +} + static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) { struct gpio_sim_chip *chip; @@ -388,6 +409,10 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) if (!chip) return -ENOMEM; + chip->request_map = devm_bitmap_zalloc(dev, num_lines, GFP_KERNEL); + if (!chip->request_map) + return -ENOMEM; + chip->direction_map = devm_bitmap_alloc(dev, num_lines, GFP_KERNEL); if (!chip->direction_map) return -ENOMEM; @@ -433,6 +458,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) gc->get_direction = gpio_sim_get_direction; gc->set_config = gpio_sim_set_config; gc->to_irq = gpio_sim_to_irq; + gc->request = gpio_sim_request; gc->free = gpio_sim_free; gc->can_sleep = true; @@ -440,8 +466,16 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) if (ret) return ret; - /* Used by sysfs and configfs callbacks. */ - dev_set_drvdata(&gc->gpiodev->dev, chip); + chip->dev = device_find_child(dev, swnode, gpio_sim_dev_match_fwnode); + if (!chip->dev) + return -ENODEV; + + ret = devm_add_action_or_reset(dev, gpio_sim_put_device, chip->dev); + if (ret) + return ret; + + /* Used by sysfs callbacks. */ + dev_set_drvdata(chip->dev, chip); return gpio_sim_setup_sysfs(chip); } @@ -1438,10 +1472,10 @@ static const struct config_item_type gpio_sim_device_config_group_type = { static struct config_group * gpio_sim_config_make_device_group(struct config_group *group, const char *name) { - struct gpio_sim_device *dev __free(kfree) = NULL; int id; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + struct gpio_sim_device *dev __free(kfree) = kzalloc(sizeof(*dev), + GFP_KERNEL); if (!dev) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index f96d260a4a19..e8c1485b9c73 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -215,7 +215,7 @@ err_remove_domain: return ret; } -static int tb10x_gpio_remove(struct platform_device *pdev) +static void tb10x_gpio_remove(struct platform_device *pdev) { struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev); @@ -225,8 +225,6 @@ static int tb10x_gpio_remove(struct platform_device *pdev) kfree(tb10x_gpio->domain->gc); irq_domain_remove(tb10x_gpio->domain); } - - return 0; } static const struct of_device_id tb10x_gpio_dt_ids[] = { @@ -237,7 +235,7 @@ MODULE_DEVICE_TABLE(of, tb10x_gpio_dt_ids); static struct platform_driver tb10x_gpio_driver = { .probe = tb10x_gpio_probe, - .remove = tb10x_gpio_remove, + .remove_new = tb10x_gpio_remove, .driver = { .name = "tb10x-gpio", .of_match_table = tb10x_gpio_dt_ids, diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c index 8e03614c7a24..90f8e9e9915e 100644 --- a/drivers/gpio/gpio-ts5500.c +++ b/drivers/gpio/gpio-ts5500.c @@ -412,13 +412,11 @@ static int ts5500_dio_probe(struct platform_device *pdev) return 0; } -static int ts5500_dio_remove(struct platform_device *pdev) +static void ts5500_dio_remove(struct platform_device *pdev) { struct ts5500_priv *priv = platform_get_drvdata(pdev); ts5500_disable_irq(priv); - - return 0; } static const struct platform_device_id ts5500_dio_ids[] = { @@ -435,7 +433,7 @@ static struct platform_driver ts5500_dio_driver = { .name = "ts5500-dio", }, .probe = ts5500_dio_probe, - .remove = ts5500_dio_remove, + .remove_new = ts5500_dio_remove, .id_table = ts5500_dio_ids, }; diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 9725b7aa18a7..1f440707f8f4 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -414,13 +414,11 @@ static int uniphier_gpio_probe(struct platform_device *pdev) return 0; } -static int uniphier_gpio_remove(struct platform_device *pdev) +static void uniphier_gpio_remove(struct platform_device *pdev) { struct uniphier_gpio_priv *priv = platform_get_drvdata(pdev); irq_domain_remove(priv->domain); - - return 0; } static int __maybe_unused uniphier_gpio_suspend(struct device *dev) @@ -482,7 +480,7 @@ MODULE_DEVICE_TABLE(of, uniphier_gpio_match); static struct platform_driver uniphier_gpio_driver = { .probe = uniphier_gpio_probe, - .remove = uniphier_gpio_remove, + .remove_new = uniphier_gpio_remove, .driver = { .name = "uniphier-gpio", .of_match_table = uniphier_gpio_match, diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 656d6b1dddb5..444501c56a3b 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -25,6 +25,7 @@ struct fsl_gpio_soc_data { /* SoCs has a Port Data Direction Register (PDDR) */ bool have_paddr; + bool have_dual_base; }; struct vf610_gpio_port { @@ -60,13 +61,26 @@ struct vf610_gpio_port { #define PORT_INT_EITHER_EDGE 0xb #define PORT_INT_LOGIC_ONE 0xc +#define IMX8ULP_GPIO_BASE_OFF 0x40 +#define IMX8ULP_BASE_OFF 0x80 + +static const struct fsl_gpio_soc_data vf610_data = { + .have_dual_base = true, +}; + static const struct fsl_gpio_soc_data imx_data = { .have_paddr = true, + .have_dual_base = true, +}; + +static const struct fsl_gpio_soc_data imx8ulp_data = { + .have_paddr = true, }; static const struct of_device_id vf610_gpio_dt_ids[] = { - { .compatible = "fsl,vf610-gpio", .data = NULL, }, + { .compatible = "fsl,vf610-gpio", .data = &vf610_data }, { .compatible = "fsl,imx7ulp-gpio", .data = &imx_data, }, + { .compatible = "fsl,imx8ulp-gpio", .data = &imx8ulp_data, }, { /* sentinel */ } }; @@ -86,7 +100,7 @@ static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio) unsigned long mask = BIT(gpio); unsigned long offset = GPIO_PDIR; - if (port->sdata && port->sdata->have_paddr) { + if (port->sdata->have_paddr) { mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR); if (mask) offset = GPIO_PDOR; @@ -110,7 +124,7 @@ static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) unsigned long mask = BIT(gpio); u32 val; - if (port->sdata && port->sdata->have_paddr) { + if (port->sdata->have_paddr) { val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR); val &= ~mask; vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR); @@ -128,7 +142,7 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, vf610_gpio_set(chip, gpio, value); - if (port->sdata && port->sdata->have_paddr) { + if (port->sdata->have_paddr) { val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR); val |= mask; vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR); @@ -264,19 +278,41 @@ static int vf610_gpio_probe(struct platform_device *pdev) struct gpio_irq_chip *girq; int i; int ret; + bool dual_base; port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; port->sdata = of_device_get_match_data(dev); - port->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(port->base)) - return PTR_ERR(port->base); - port->gpio_base = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(port->gpio_base)) - return PTR_ERR(port->gpio_base); + dual_base = port->sdata->have_dual_base; + + /* + * Handle legacy compatible combinations which used two reg values + * for the i.MX8ULP and i.MX93. + */ + if (device_is_compatible(dev, "fsl,imx7ulp-gpio") && + (device_is_compatible(dev, "fsl,imx93-gpio") || + (device_is_compatible(dev, "fsl,imx8ulp-gpio")))) + dual_base = true; + + if (dual_base) { + port->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(port->base)) + return PTR_ERR(port->base); + + port->gpio_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(port->gpio_base)) + return PTR_ERR(port->gpio_base); + } else { + port->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(port->base)) + return PTR_ERR(port->base); + + port->gpio_base = port->base + IMX8ULP_GPIO_BASE_OFF; + port->base = port->base + IMX8ULP_BASE_OFF; + } port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index a809609ee957..bd5befa807c3 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -15,7 +15,6 @@ #include <linux/gpio/driver.h> #include <linux/acpi.h> -#include "gpiolib.h" #include "gpiolib-acpi.h" /* Common property names */ @@ -296,15 +295,13 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) return ret; } -static int xgene_gpio_sb_remove(struct platform_device *pdev) +static void xgene_gpio_sb_remove(struct platform_device *pdev) { struct xgene_gpio_sb *priv = platform_get_drvdata(pdev); acpi_gpiochip_free_interrupts(&priv->gc); irq_domain_remove(priv->irq_domain); - - return 0; } static const struct of_device_id xgene_gpio_sb_of_match[] = { @@ -328,7 +325,7 @@ static struct platform_driver xgene_gpio_sb_driver = { .acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match), }, .probe = xgene_gpio_sb_probe, - .remove = xgene_gpio_sb_remove, + .remove_new = xgene_gpio_sb_remove, }; module_platform_driver(xgene_gpio_sb_driver); diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c index 2d23b27d55af..d445eea03687 100644 --- a/drivers/gpio/gpio-xgs-iproc.c +++ b/drivers/gpio/gpio-xgs-iproc.c @@ -291,7 +291,7 @@ static int iproc_gpio_probe(struct platform_device *pdev) return 0; } -static int iproc_gpio_remove(struct platform_device *pdev) +static void iproc_gpio_remove(struct platform_device *pdev) { struct iproc_gpio_chip *chip = platform_get_drvdata(pdev); @@ -302,8 +302,6 @@ static int iproc_gpio_remove(struct platform_device *pdev) val &= ~IPROC_CCA_INT_F_GPIOINT; writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK); } - - return 0; } static const struct of_device_id bcm_iproc_gpio_of_match[] = { @@ -318,7 +316,7 @@ static struct platform_driver bcm_iproc_gpio_driver = { .of_match_table = bcm_iproc_gpio_of_match, }, .probe = iproc_gpio_probe, - .remove = iproc_gpio_remove, + .remove_new = iproc_gpio_remove, }; module_platform_driver(bcm_iproc_gpio_driver); diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index a16945e8319e..823198368250 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -332,7 +332,7 @@ static int __maybe_unused xgpio_suspend(struct device *dev) * * Return: 0 always */ -static int xgpio_remove(struct platform_device *pdev) +static void xgpio_remove(struct platform_device *pdev) { struct xgpio_instance *gpio = platform_get_drvdata(pdev); @@ -340,8 +340,6 @@ static int xgpio_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); clk_disable_unprepare(gpio->clk); - - return 0; } /** @@ -715,7 +713,7 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match); static struct platform_driver xgpio_plat_driver = { .probe = xgpio_probe, - .remove = xgpio_remove, + .remove_new = xgpio_remove, .driver = { .name = "gpio-xilinx", .of_match_table = xgpio_of_match, diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 324e942c0650..466e23031afc 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -1010,7 +1010,7 @@ err_pm_dis: * * Return: 0 always */ -static int zynq_gpio_remove(struct platform_device *pdev) +static void zynq_gpio_remove(struct platform_device *pdev) { struct zynq_gpio *gpio = platform_get_drvdata(pdev); int ret; @@ -1022,7 +1022,6 @@ static int zynq_gpio_remove(struct platform_device *pdev) clk_disable_unprepare(gpio->clk); device_set_wakeup_capable(&pdev->dev, 0); pm_runtime_disable(&pdev->dev); - return 0; } static struct platform_driver zynq_gpio_driver = { @@ -1032,7 +1031,7 @@ static struct platform_driver zynq_gpio_driver = { .of_match_table = zynq_gpio_of_match, }, .probe = zynq_gpio_probe, - .remove = zynq_gpio_remove, + .remove_new = zynq_gpio_remove, }; module_platform_driver(zynq_gpio_driver); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 51e41676de0b..88066826d8e5 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -143,7 +143,6 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) */ static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin) { - struct gpio_chip *chip; acpi_handle handle; acpi_status status; @@ -151,40 +150,17 @@ static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin) if (ACPI_FAILURE(status)) return ERR_PTR(-ENODEV); - chip = gpiochip_find(handle, acpi_gpiochip_find); - if (!chip) + struct gpio_device *gdev __free(gpio_device_put) = + gpio_device_find(handle, acpi_gpiochip_find); + if (!gdev) return ERR_PTR(-EPROBE_DEFER); - return gpiochip_get_desc(chip, pin); -} - -/** - * acpi_get_and_request_gpiod - Translate ACPI GPIO pin to GPIO descriptor and - * hold a refcount to the GPIO device. - * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") - * @pin: ACPI GPIO pin number (0-based, controller-relative) - * @label: Label to pass to gpiod_request() - * - * This function is a simple pass-through to acpi_get_gpiod(), except that - * as it is intended for use outside of the GPIO layer (in a similar fashion to - * gpiod_get_index() for example) it also holds a reference to the GPIO device. - */ -struct gpio_desc *acpi_get_and_request_gpiod(char *path, unsigned int pin, char *label) -{ - struct gpio_desc *gpio; - int ret; - - gpio = acpi_get_gpiod(path, pin); - if (IS_ERR(gpio)) - return gpio; - - ret = gpiod_request(gpio, label); - if (ret) - return ERR_PTR(ret); - - return gpio; + /* + * FIXME: keep track of the reference to the GPIO device somehow + * instead of putting it here. + */ + return gpio_device_get_desc(gdev, pin); } -EXPORT_SYMBOL_GPL(acpi_get_and_request_gpiod); static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) { @@ -437,6 +413,11 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, if (!handler) return AE_OK; + if (acpi_gpio_in_ignore_list(ignore_interrupt, dev_name(chip->parent), pin)) { + dev_info(chip->parent, "Ignoring interrupt on pin %u\n", pin); + return AE_OK; + } + desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event"); if (IS_ERR(desc)) { dev_err(chip->parent, @@ -461,11 +442,6 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, goto fail_unlock_irq; } - if (acpi_gpio_in_ignore_list(ignore_interrupt, dev_name(chip->parent), pin)) { - dev_info(chip->parent, "Ignoring interrupt on pin %u\n", pin); - return AE_OK; - } - event = kzalloc(sizeof(*event), GFP_KERNEL); if (!event) goto fail_unlock_irq; @@ -1655,6 +1631,26 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_wake = "SYNA1202:00@16", }, }, + { + /* + * On the Peaq C1010 2-in-1 INT33FC:00 pin 3 is connected to + * a "dolby" button. At the ACPI level an _AEI event-handler + * is connected which sets an ACPI variable to 1 on both + * edges. This variable can be polled + cleared to 0 using + * WMI. But since the variable is set on both edges the WMI + * interface is pretty useless even when polling. + * So instead the x86-android-tablets code instantiates + * a gpio-keys platform device for it. + * Ignore the _AEI handler for the pin, so that it is not busy. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"), + DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_interrupt = "INT33FC:00@3", + }, + }, {} /* Terminating entry */ }; diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index e39d344feb28..31fc71a612c2 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -572,7 +572,7 @@ struct linereq { DECLARE_KFIFO_PTR(events, struct gpio_v2_line_event); atomic_t seqno; struct mutex config_mutex; - struct line lines[]; + struct line lines[] __counted_by(num_lines); }; #define GPIO_V2_LINE_BIAS_FLAGS \ @@ -1656,6 +1656,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) lr = kzalloc(struct_size(lr, lines, ulr.num_lines), GFP_KERNEL); if (!lr) return -ENOMEM; + lr->num_lines = ulr.num_lines; lr->gdev = gpio_device_get(gdev); @@ -1684,7 +1685,6 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) lr->event_buffer_size = GPIO_V2_LINES_MAX * 16; atomic_set(&lr->seqno, 0); - lr->num_lines = ulr.num_lines; /* Request each GPIO */ for (i = 0; i < ulr.num_lines; i++) { diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 531faabead0f..a4b48d53ab4d 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -127,10 +127,10 @@ static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data) chip->of_xlate(chip, gpiospec, NULL) >= 0; } -static struct gpio_chip *of_find_gpiochip_by_xlate( - struct of_phandle_args *gpiospec) +static struct gpio_device * +of_find_gpio_device_by_xlate(struct of_phandle_args *gpiospec) { - return gpiochip_find(gpiospec, of_gpiochip_match_node_and_xlate); + return gpio_device_find(gpiospec, of_gpiochip_match_node_and_xlate); } static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, @@ -192,6 +192,15 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np, */ { "himax,hx8357", "gpios-reset", false }, { "himax,hx8369", "gpios-reset", false }, + /* + * The rb-gpios semantics was undocumented and qi,lb60 (along with + * the ingenic driver) got it wrong. The active state encodes the + * NAND ready state, which is high level. Since there's no signal + * inverter on this board, it should be active-high. Let's fix that + * here for older DTs so we can re-use the generic nand_gpio_waitrdy() + * helper, and be consistent with what other drivers do. + */ + { "qi,lb60", "rb-gpios", true }, #endif }; unsigned int i; @@ -363,7 +372,6 @@ static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags) { struct of_phandle_args gpiospec; - struct gpio_chip *chip; struct gpio_desc *desc; int ret; @@ -375,13 +383,15 @@ static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np, return ERR_PTR(ret); } - chip = of_find_gpiochip_by_xlate(&gpiospec); - if (!chip) { + struct gpio_device *gdev __free(gpio_device_put) = + of_find_gpio_device_by_xlate(&gpiospec); + if (!gdev) { desc = ERR_PTR(-EPROBE_DEFER); goto out; } - desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags); + desc = of_xlate_and_get_gpiod_flags(gpio_device_get_chip(gdev), + &gpiospec, flags); if (IS_ERR(desc)) goto out; @@ -611,6 +621,33 @@ static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np, return desc; } +/* + * Trigger sources are special, they allow us to use any GPIO as a LED trigger + * and have the name "trigger-sources" no matter which kind of phandle it is + * pointing to, whether to a GPIO, a USB host, a network PHY etc. So in this case + * we allow looking something up that is not named "foo-gpios". + */ +static struct gpio_desc *of_find_trigger_gpio(struct device_node *np, + const char *con_id, + unsigned int idx, + enum of_gpio_flags *of_flags) +{ + struct gpio_desc *desc; + + if (!IS_ENABLED(CONFIG_LEDS_TRIGGER_GPIO)) + return ERR_PTR(-ENOENT); + + if (!con_id || strcmp(con_id, "trigger-sources")) + return ERR_PTR(-ENOENT); + + desc = of_get_named_gpiod_flags(np, con_id, idx, of_flags); + if (!gpiod_not_found(desc)) + pr_debug("%s is used as a trigger\n", of_node_full_name(np)); + + return desc; +} + + typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np, const char *con_id, unsigned int idx, @@ -618,6 +655,7 @@ typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np, static const of_find_gpio_quirk of_find_gpio_quirks[] = { of_find_gpio_rename, of_find_mt2701_gpio, + of_find_trigger_gpio, NULL }; @@ -813,16 +851,16 @@ static int of_gpiochip_match_node(struct gpio_chip *chip, void *data) return device_match_of_node(&chip->gpiodev->dev, data); } -static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np) +static struct gpio_device *of_find_gpio_device_by_node(struct device_node *np) { - return gpiochip_find(np, of_gpiochip_match_node); + return gpio_device_find(np, of_gpiochip_match_node); } static int of_gpio_notify(struct notifier_block *nb, unsigned long action, void *arg) { + struct gpio_device *gdev __free(gpio_device_put) = NULL; struct of_reconfig_data *rd = arg; - struct gpio_chip *chip; int ret; /* @@ -834,38 +872,38 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action, switch (of_reconfig_get_state_change(action, arg)) { case OF_RECONFIG_CHANGE_ADD: if (!of_property_read_bool(rd->dn, "gpio-hog")) - return NOTIFY_OK; /* not for us */ + return NOTIFY_DONE; /* not for us */ if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) - return NOTIFY_OK; + return NOTIFY_DONE; - chip = of_find_gpiochip_by_node(rd->dn->parent); - if (chip == NULL) - return NOTIFY_OK; /* not for us */ + gdev = of_find_gpio_device_by_node(rd->dn->parent); + if (!gdev) + return NOTIFY_DONE; /* not for us */ - ret = of_gpiochip_add_hog(chip, rd->dn); + ret = of_gpiochip_add_hog(gpio_device_get_chip(gdev), rd->dn); if (ret < 0) { pr_err("%s: failed to add hogs for %pOF\n", __func__, rd->dn); of_node_clear_flag(rd->dn, OF_POPULATED); return notifier_from_errno(ret); } - break; + return NOTIFY_OK; case OF_RECONFIG_CHANGE_REMOVE: if (!of_node_check_flag(rd->dn, OF_POPULATED)) - return NOTIFY_OK; /* already depopulated */ + return NOTIFY_DONE; /* already depopulated */ - chip = of_find_gpiochip_by_node(rd->dn->parent); - if (chip == NULL) - return NOTIFY_OK; /* not for us */ + gdev = of_find_gpio_device_by_node(rd->dn->parent); + if (!gdev) + return NOTIFY_DONE; /* not for us */ - of_gpiochip_remove_hog(chip, rd->dn); + of_gpiochip_remove_hog(gpio_device_get_chip(gdev), rd->dn); of_node_clear_flag(rd->dn, OF_POPULATED); - break; + return NOTIFY_OK; } - return NOTIFY_OK; + return NOTIFY_DONE; } struct notifier_block gpio_of_notifier = { diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c index b5a6eaf3729b..fa52bdb1a29a 100644 --- a/drivers/gpio/gpiolib-swnode.c +++ b/drivers/gpio/gpiolib-swnode.c @@ -31,22 +31,17 @@ static void swnode_format_propname(const char *con_id, char *propname, strscpy(propname, "gpios", max_size); } -static int swnode_gpiochip_match_name(struct gpio_chip *chip, void *data) +static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode) { - return !strcmp(chip->label, data); -} - -static struct gpio_chip *swnode_get_chip(struct fwnode_handle *fwnode) -{ - const struct software_node *chip_node; - struct gpio_chip *chip; + const struct software_node *gdev_node; + struct gpio_device *gdev; - chip_node = to_software_node(fwnode); - if (!chip_node || !chip_node->name) + gdev_node = to_software_node(fwnode); + if (!gdev_node || !gdev_node->name) return ERR_PTR(-EINVAL); - chip = gpiochip_find((void *)chip_node->name, swnode_gpiochip_match_name); - return chip ?: ERR_PTR(-EPROBE_DEFER); + gdev = gpio_device_find_by_label(gdev_node->name); + return gdev ?: ERR_PTR(-EPROBE_DEFER); } struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode, @@ -55,7 +50,6 @@ struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode, { const struct software_node *swnode; struct fwnode_reference_args args; - struct gpio_chip *chip; struct gpio_desc *desc; char propname[32]; /* 32 is max size of property name */ int error; @@ -77,12 +71,17 @@ struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode, return ERR_PTR(error); } - chip = swnode_get_chip(args.fwnode); + struct gpio_device *gdev __free(gpio_device_put) = + swnode_get_gpio_device(args.fwnode); fwnode_handle_put(args.fwnode); - if (IS_ERR(chip)) - return ERR_CAST(chip); + if (IS_ERR(gdev)) + return ERR_CAST(gdev); - desc = gpiochip_get_desc(chip, args.args[0]); + /* + * FIXME: The GPIO device reference is put at return but the descriptor + * is passed on. Find a proper solution. + */ + desc = gpio_device_get_desc(gdev, args.args[0]); *flags = args.args[1]; /* We expect native GPIO flags */ pr_debug("%s: parsed '%s' property of node '%pfwP[%d]' - status (%d)\n", diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 50503a4525eb..6f309a3b2d9a 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -814,7 +814,7 @@ static int __init gpiolib_sysfs_init(void) * gpiochip_sysfs_register() acquires a mutex. This is unsafe * and needs to be fixed. * - * Also it would be nice to use gpiochip_find() here so we + * Also it would be nice to use gpio_device_find() here so we * can keep gpio_chips local to gpiolib.c, but the yield of * gpio_lock prevents us from doing this. */ diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 40a0022ea719..cbafcd95243e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -20,6 +20,7 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/string.h> #include <linux/gpio.h> #include <linux/gpio/driver.h> @@ -146,27 +147,49 @@ struct gpio_desc *gpio_to_desc(unsigned gpio) } EXPORT_SYMBOL_GPL(gpio_to_desc); +/* This function is deprecated and will be removed soon, don't use. */ +struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, + unsigned int hwnum) +{ + return gpio_device_get_desc(gc->gpiodev, hwnum); +} +EXPORT_SYMBOL_GPL(gpiochip_get_desc); + /** - * gpiochip_get_desc - get the GPIO descriptor corresponding to the given - * hardware number for this chip - * @gc: GPIO chip + * gpio_device_get_desc() - get the GPIO descriptor corresponding to the given + * hardware number for this GPIO device + * @gdev: GPIO device to get the descriptor from * @hwnum: hardware number of the GPIO for this chip * * Returns: - * A pointer to the GPIO descriptor or ``ERR_PTR(-EINVAL)`` if no GPIO exists - * in the given chip for the specified hardware number. + * A pointer to the GPIO descriptor or %EINVAL if no GPIO exists in the given + * chip for the specified hardware number or %ENODEV if the underlying chip + * already vanished. + * + * The reference count of struct gpio_device is *NOT* increased like when the + * GPIO is being requested for exclusive usage. It's up to the caller to make + * sure the GPIO device will stay alive together with the descriptor returned + * by this function. */ -struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, - unsigned int hwnum) +struct gpio_desc * +gpio_device_get_desc(struct gpio_device *gdev, unsigned int hwnum) { - struct gpio_device *gdev = gc->gpiodev; + struct gpio_chip *gc; + + /* + * FIXME: This will be locked once we protect gdev->chip everywhere + * with SRCU. + */ + gc = gdev->chip; + if (!gc) + return ERR_PTR(-ENODEV); if (hwnum >= gdev->ngpio) return ERR_PTR(-EINVAL); return &gdev->descs[hwnum]; } -EXPORT_SYMBOL_GPL(gpiochip_get_desc); +EXPORT_SYMBOL_GPL(gpio_device_get_desc); /** * desc_to_gpio - convert a GPIO descriptor to the integer namespace @@ -197,6 +220,61 @@ struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_to_chip); +/** + * gpiod_to_gpio_device() - Return the GPIO device to which this descriptor + * belongs. + * @desc: Descriptor for which to return the GPIO device. + * + * This *DOES NOT* increase the reference count of the GPIO device as it's + * expected that the descriptor is requested and the users already holds a + * reference to the device. + * + * Returns: + * Address of the GPIO device owning this descriptor. + */ +struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc) +{ + if (!desc) + return NULL; + + return desc->gdev; +} +EXPORT_SYMBOL_GPL(gpiod_to_gpio_device); + +/** + * gpio_device_get_base() - Get the base GPIO number allocated by this device + * @gdev: GPIO device + * + * Returns: + * First GPIO number in the global GPIO numberspace for this device. + */ +int gpio_device_get_base(struct gpio_device *gdev) +{ + return gdev->base; +} +EXPORT_SYMBOL_GPL(gpio_device_get_base); + +/** + * gpio_device_get_chip() - Get the gpio_chip implementation of this GPIO device + * @gdev: GPIO device + * + * Returns: + * Address of the GPIO chip backing this device. + * + * Until we can get rid of all non-driver users of struct gpio_chip, we must + * provide a way of retrieving the pointer to it from struct gpio_device. This + * is *NOT* safe as the GPIO API is considered to be hot-unpluggable and the + * chip can dissapear at any moment (unlike reference-counted struct + * gpio_device). + * + * Use at your own risk. + */ +struct gpio_chip *gpio_device_get_chip(struct gpio_device *gdev) +{ + return gdev->chip; +} +EXPORT_SYMBOL_GPL(gpio_device_get_chip); + /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ static int gpiochip_find_base(int ngpio) { @@ -1014,16 +1092,10 @@ void gpiochip_remove(struct gpio_chip *gc) } EXPORT_SYMBOL_GPL(gpiochip_remove); -/** - * gpiochip_find() - iterator for locating a specific gpio_chip - * @data: data to pass to match function - * @match: Callback function to check gpio_chip +/* + * FIXME: This will be removed soon. * - * Similar to bus_find_device. It returns a reference to a gpio_chip as - * determined by a user supplied @match callback. The callback should return - * 0 if the device doesn't match and non-zero if it does. If the callback is - * non-zero, this function will return to the caller and not iterate over any - * more gpio_chips. + * This function is depracated, don't use. */ struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *gc, @@ -1031,32 +1103,142 @@ struct gpio_chip *gpiochip_find(void *data, { struct gpio_device *gdev; struct gpio_chip *gc = NULL; - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - list_for_each_entry(gdev, &gpio_devices, list) - if (gdev->chip && match(gdev->chip, data)) { - gc = gdev->chip; - break; - } - spin_unlock_irqrestore(&gpio_lock, flags); + gdev = gpio_device_find(data, match); + if (gdev) { + gc = gdev->chip; + gpio_device_put(gdev); + } return gc; } EXPORT_SYMBOL_GPL(gpiochip_find); -static int gpiochip_match_name(struct gpio_chip *gc, void *data) +/** + * gpio_device_find() - find a specific GPIO device + * @data: data to pass to match function + * @match: Callback function to check gpio_chip + * + * Returns: + * New reference to struct gpio_device. + * + * Similar to bus_find_device(). It returns a reference to a gpio_device as + * determined by a user supplied @match callback. The callback should return + * 0 if the device doesn't match and non-zero if it does. If the callback + * returns non-zero, this function will return to the caller and not iterate + * over any more gpio_devices. + * + * The callback takes the GPIO chip structure as argument. During the execution + * of the callback function the chip is protected from being freed. TODO: This + * actually has yet to be implemented. + * + * If the function returns non-NULL, the returned reference must be freed by + * the caller using gpio_device_put(). + */ +struct gpio_device *gpio_device_find(void *data, + int (*match)(struct gpio_chip *gc, + void *data)) +{ + struct gpio_device *gdev; + + /* + * Not yet but in the future the spinlock below will become a mutex. + * Annotate this function before anyone tries to use it in interrupt + * context like it happened with gpiochip_find(). + */ + might_sleep(); + + guard(spinlock_irqsave)(&gpio_lock); + + list_for_each_entry(gdev, &gpio_devices, list) { + if (gdev->chip && match(gdev->chip, data)) + return gpio_device_get(gdev); + } + + return NULL; +} +EXPORT_SYMBOL_GPL(gpio_device_find); + +static int gpio_chip_match_by_label(struct gpio_chip *gc, void *label) { - const char *name = data; + return gc->label && !strcmp(gc->label, label); +} - return !strcmp(gc->label, name); +/** + * gpio_device_find_by_label() - wrapper around gpio_device_find() finding the + * GPIO device by its backing chip's label + * @label: Label to lookup + * + * Returns: + * Reference to the GPIO device or NULL. Reference must be released with + * gpio_device_put(). + */ +struct gpio_device *gpio_device_find_by_label(const char *label) +{ + return gpio_device_find((void *)label, gpio_chip_match_by_label); +} +EXPORT_SYMBOL_GPL(gpio_device_find_by_label); + +static int gpio_chip_match_by_fwnode(struct gpio_chip *gc, void *fwnode) +{ + return device_match_fwnode(&gc->gpiodev->dev, fwnode); } -static struct gpio_chip *find_chip_by_name(const char *name) +/** + * gpio_device_find_by_fwnode() - wrapper around gpio_device_find() finding + * the GPIO device by its fwnode + * @fwnode: Firmware node to lookup + * + * Returns: + * Reference to the GPIO device or NULL. Reference must be released with + * gpio_device_put(). + */ +struct gpio_device *gpio_device_find_by_fwnode(const struct fwnode_handle *fwnode) { - return gpiochip_find((void *)name, gpiochip_match_name); + return gpio_device_find((void *)fwnode, gpio_chip_match_by_fwnode); } +EXPORT_SYMBOL_GPL(gpio_device_find_by_fwnode); + +/** + * gpio_device_get() - Increase the reference count of this GPIO device + * @gdev: GPIO device to increase the refcount for + * + * Returns: + * Pointer to @gdev. + */ +struct gpio_device *gpio_device_get(struct gpio_device *gdev) +{ + return to_gpio_device(get_device(&gdev->dev)); +} +EXPORT_SYMBOL_GPL(gpio_device_get); + +/** + * gpio_device_put() - Decrease the reference count of this GPIO device and + * possibly free all resources associated with it. + * @gdev: GPIO device to decrease the reference count for + */ +void gpio_device_put(struct gpio_device *gdev) +{ + put_device(&gdev->dev); +} +EXPORT_SYMBOL_GPL(gpio_device_put); + +/** + * gpio_device_to_device() - Retrieve the address of the underlying struct + * device. + * @gdev: GPIO device for which to return the address. + * + * This does not increase the reference count of the GPIO device nor the + * underlying struct device. + * + * Returns: + * Address of struct device backing this GPIO device. + */ +struct device *gpio_device_to_device(struct gpio_device *gdev) +{ + return &gdev->dev; +} +EXPORT_SYMBOL_GPL(gpio_device_to_device); #ifdef CONFIG_GPIOLIB_IRQCHIP @@ -2700,7 +2882,6 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) PIN_CONFIG_PERSIST_STATE, !transitory); } -EXPORT_SYMBOL_GPL(gpiod_set_transitory); /** * gpiod_is_active_low - test whether a GPIO is active-low or not @@ -3786,7 +3967,6 @@ EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table); */ void gpiod_add_hogs(struct gpiod_hog *hogs) { - struct gpio_chip *gc; struct gpiod_hog *hog; mutex_lock(&gpio_machine_hogs_mutex); @@ -3798,9 +3978,10 @@ void gpiod_add_hogs(struct gpiod_hog *hogs) * The chip may have been registered earlier, so check if it * exists and, if so, try to hog the line now. */ - gc = find_chip_by_name(hog->chip_label); - if (gc) - gpiochip_machine_hog(gc, hog); + struct gpio_device *gdev __free(gpio_device_put) = + gpio_device_find_by_label(hog->chip_label); + if (gdev) + gpiochip_machine_hog(gpio_device_get_chip(gdev), hog); } mutex_unlock(&gpio_machine_hogs_mutex); @@ -3823,8 +4004,6 @@ static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) const char *dev_id = dev ? dev_name(dev) : NULL; struct gpiod_lookup_table *table; - mutex_lock(&gpio_lookup_lock); - list_for_each_entry(table, &gpio_lookup_list, list) { if (table->dev_id && dev_id) { /* @@ -3832,21 +4011,18 @@ static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) * a match */ if (!strcmp(table->dev_id, dev_id)) - goto found; + return table; } else { /* * One of the pointers is NULL, so both must be to have * a match */ if (dev_id == table->dev_id) - goto found; + return table; } } - table = NULL; -found: - mutex_unlock(&gpio_lookup_lock); - return table; + return NULL; } static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, @@ -3855,14 +4031,15 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, struct gpio_desc *desc = ERR_PTR(-ENOENT); struct gpiod_lookup_table *table; struct gpiod_lookup *p; + struct gpio_chip *gc; + + guard(mutex)(&gpio_lookup_lock); table = gpiod_find_lookup_table(dev); if (!table) return desc; for (p = &table->table[0]; p->key; p++) { - struct gpio_chip *gc; - /* idx must always match exactly */ if (p->idx != idx) continue; @@ -3883,9 +4060,9 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return ERR_PTR(-EPROBE_DEFER); } - gc = find_chip_by_name(p->key); - - if (!gc) { + struct gpio_device *gdev __free(gpio_device_put) = + gpio_device_find_by_label(p->key); + if (!gdev) { /* * As the lookup table indicates a chip with * p->key should exist, assume it may @@ -3898,6 +4075,8 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return ERR_PTR(-EPROBE_DEFER); } + gc = gpio_device_get_chip(gdev); + if (gc->ngpio <= p->chip_hwnum) { dev_err(dev, "requested GPIO %u (%u) is out of range [0..%u] for chip %s\n", @@ -3906,7 +4085,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return ERR_PTR(-EINVAL); } - desc = gpiochip_get_desc(gc, p->chip_hwnum); + desc = gpio_device_get_desc(gdev, p->chip_hwnum); *flags = p->flags; return desc; @@ -3921,15 +4100,18 @@ static int platform_gpio_count(struct device *dev, const char *con_id) struct gpiod_lookup *p; unsigned int count = 0; - table = gpiod_find_lookup_table(dev); - if (!table) - return -ENOENT; + scoped_guard(mutex, &gpio_lookup_lock) { + table = gpiod_find_lookup_table(dev); + if (!table) + return -ENOENT; - for (p = &table->table[0]; p->key; p++) { - if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) || - (!con_id && !p->con_id)) - count++; + for (p = &table->table[0]; p->key; p++) { + if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) || + (!con_id && !p->con_id)) + count++; + } } + if (!count) return -ENOENT; diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index a0a67569300b..3ccacf3c1288 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -86,16 +86,6 @@ static inline struct gpio_device *to_gpio_device(struct device *dev) return container_of(dev, struct gpio_device, dev); } -static inline struct gpio_device *gpio_device_get(struct gpio_device *gdev) -{ - return to_gpio_device(get_device(&gdev->dev)); -} - -static inline void gpio_device_put(struct gpio_device *gdev) -{ - put_device(&gdev->dev); -} - /* gpio suffixes used for ACPI and device tree lookup */ static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; @@ -122,8 +112,6 @@ struct gpio_array { unsigned long invert_mask[]; }; -struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum); - #define for_each_gpio_desc(gc, desc) \ for (unsigned int __i = 0; \ __i < gc->ngpio && (desc = gpiochip_get_desc(gc, __i)); \ @@ -144,6 +132,8 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, struct gpio_array *array_info, unsigned long *value_bitmap); +int gpiod_set_transitory(struct gpio_desc *desc, bool transitory); + extern spinlock_t gpio_lock; extern struct list_head gpio_devices; |