diff options
60 files changed, 1316 insertions, 950 deletions
diff --git a/Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml b/Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml index b9afd07a9d24..b16273e69dfe 100644 --- a/Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml @@ -46,6 +46,12 @@ properties: minimum: 12 maximum: 232 +patternProperties: + "-hog(-[0-9]+)?$": + type: object + required: + - gpio-hog + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml b/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml index 33d4e4716516..7ed5f9c4dde9 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml @@ -72,6 +72,9 @@ properties: "#gpio-cells": const: 2 + gpio-ranges: + maxItems: 1 + marvell,pwm-offset: $ref: /schemas/types.yaml#/definitions/uint32 description: Offset in the register map for the pwm registers (in bytes) @@ -96,6 +99,13 @@ properties: - const: axi minItems: 1 +patternProperties: + "^(.+-hog(-[0-9]+)?)$": + type: object + + required: + - gpio-hog + required: - compatible - gpio-controller diff --git a/Documentation/devicetree/bindings/gpio/gpio-vf610.yaml b/Documentation/devicetree/bindings/gpio/gpio-vf610.yaml index cabda2eab4a2..4fb32e9aec0a 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-vf610.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-vf610.yaml @@ -28,6 +28,7 @@ properties: - items: - enum: - fsl,imx93-gpio + - fsl,imx94-gpio - fsl,imx95-gpio - const: fsl,imx8ulp-gpio diff --git a/Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml b/Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml index cf3b1b270aa8..b68159600e2b 100644 --- a/Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml @@ -20,7 +20,10 @@ properties: - loongson,ls2k2000-gpio1 - loongson,ls2k2000-gpio2 - loongson,ls3a5000-gpio + - loongson,ls3a6000-gpio # Loongson-3A6000 node GPIO - loongson,ls7a-gpio + - loongson,ls7a2000-gpio1 # LS7A2000 chipset GPIO + - loongson,ls7a2000-gpio2 # LS7A2000 ACPI GPIO - items: - const: loongson,ls2k1000-gpio - const: loongson,ls2k-gpio diff --git a/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml b/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml index 3718103e966a..8bca574bb66d 100644 --- a/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml +++ b/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml @@ -73,6 +73,43 @@ properties: wakeup-source: true + reset-gpios: + maxItems: 1 + description: + GPIO controlling the (reset active LOW) RESET# pin. + + The active polarity of the GPIO must translate to the low state of the + RESET# pin on the IC, i.e. if a GPIO is directly routed to the RESET# pin + without any inverter, GPIO_ACTIVE_LOW is expected. + + Performing a reset makes all lines initialized to their input (pulled-up) + state. + +allOf: + - if: + properties: + compatible: + not: + contains: + enum: + - nxp,pca9670 + - nxp,pca9671 + - nxp,pca9672 + - nxp,pca9673 + then: + properties: + reset-gpios: false + + # lines-initial-states XOR reset-gpios + # Performing a reset reinitializes all lines to a known state which + # may not match passed lines-initial-states + - if: + required: + - lines-initial-states + then: + properties: + reset-gpios: false + patternProperties: "^(.+-hog(-[0-9]+)?)$": type: object diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 98b4d1633b25..3e9b174fee84 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -757,6 +757,7 @@ config GPIO_VF610 default y if SOC_VF610 depends on ARCH_MXC || COMPILE_TEST select GPIOLIB_IRQCHIP + select GPIO_GENERIC help Say yes here to support i.MX or Vybrid vf610 GPIOs. @@ -1791,7 +1792,6 @@ menu "SPI GPIO expanders" config GPIO_74X164 tristate "74x164 serial-in/parallel-out 8-bits shift register" - depends on OF_GPIO help Driver for 74x164 compatible serial-in/parallel-out 8-outputs shift registers. This driver can be used to provide access @@ -1911,6 +1911,7 @@ config GPIO_SIM tristate "GPIO Simulator Module" select IRQ_SIM select CONFIGFS_FS + select DEV_SYNC_PROBE help This enables the GPIO simulator - a configfs-based GPIO testing driver. @@ -1939,6 +1940,7 @@ config GPIO_VIRTUSER select DEBUG_FS select CONFIGFS_FS select IRQ_WORK + select DEV_SYNC_PROBE help Say Y here to enable the configurable, configfs-based virtual GPIO consumer testing driver. @@ -1949,3 +1951,6 @@ config GPIO_VIRTUSER endmenu endif + +config DEV_SYNC_PROBE + tristate diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index af3ba4d81b58..af130882ffee 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -19,6 +19,9 @@ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o # directly supported by gpio-generic gpio-generic-$(CONFIG_GPIO_GENERIC) += gpio-mmio.o +# Utilities for drivers that need synchronous fake device creation +obj-$(CONFIG_DEV_SYNC_PROBE) += dev-sync-probe.o + obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o diff --git a/drivers/gpio/dev-sync-probe.c b/drivers/gpio/dev-sync-probe.c new file mode 100644 index 000000000000..9ea733b863b2 --- /dev/null +++ b/drivers/gpio/dev-sync-probe.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Common code for drivers creating fake platform devices. + * + * Provides synchronous device creation: waits for probe completion and + * returns the probe success or error status to the device creator. + * + * Copyright (C) 2021 Bartosz Golaszewski <brgl@bgdev.pl> + * Copyright (C) 2025 Koichiro Den <koichiro.den@canonical.com> + */ + +#include <linux/device.h> +#include <linux/slab.h> + +#include "dev-sync-probe.h" + +static int dev_sync_probe_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct dev_sync_probe_data *pdata; + struct device *dev = data; + + pdata = container_of(nb, struct dev_sync_probe_data, bus_notifier); + if (!device_match_name(dev, pdata->name)) + return NOTIFY_DONE; + + switch (action) { + case BUS_NOTIFY_BOUND_DRIVER: + pdata->driver_bound = true; + break; + case BUS_NOTIFY_DRIVER_NOT_BOUND: + pdata->driver_bound = false; + break; + default: + return NOTIFY_DONE; + } + + complete(&pdata->probe_completion); + return NOTIFY_OK; +} + +void dev_sync_probe_init(struct dev_sync_probe_data *data) +{ + memset(data, 0, sizeof(*data)); + init_completion(&data->probe_completion); + data->bus_notifier.notifier_call = dev_sync_probe_notifier_call; +} +EXPORT_SYMBOL_GPL(dev_sync_probe_init); + +int dev_sync_probe_register(struct dev_sync_probe_data *data, + struct platform_device_info *pdevinfo) +{ + struct platform_device *pdev; + char *name; + + name = kasprintf(GFP_KERNEL, "%s.%d", pdevinfo->name, pdevinfo->id); + if (!name) + return -ENOMEM; + + data->driver_bound = false; + data->name = name; + reinit_completion(&data->probe_completion); + bus_register_notifier(&platform_bus_type, &data->bus_notifier); + + pdev = platform_device_register_full(pdevinfo); + if (IS_ERR(pdev)) { + bus_unregister_notifier(&platform_bus_type, &data->bus_notifier); + kfree(data->name); + return PTR_ERR(pdev); + } + + wait_for_completion(&data->probe_completion); + bus_unregister_notifier(&platform_bus_type, &data->bus_notifier); + + if (!data->driver_bound) { + platform_device_unregister(pdev); + kfree(data->name); + return -ENXIO; + } + + data->pdev = pdev; + return 0; +} +EXPORT_SYMBOL_GPL(dev_sync_probe_register); + +void dev_sync_probe_unregister(struct dev_sync_probe_data *data) +{ + platform_device_unregister(data->pdev); + kfree(data->name); + data->pdev = NULL; +} +EXPORT_SYMBOL_GPL(dev_sync_probe_unregister); + +MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>"); +MODULE_AUTHOR("Koichiro Den <koichiro.den@canonical.com>"); +MODULE_DESCRIPTION("Utilities for synchronous fake device creation"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/dev-sync-probe.h b/drivers/gpio/dev-sync-probe.h new file mode 100644 index 000000000000..4b3d52b70519 --- /dev/null +++ b/drivers/gpio/dev-sync-probe.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef DEV_SYNC_PROBE_H +#define DEV_SYNC_PROBE_H + +#include <linux/completion.h> +#include <linux/notifier.h> +#include <linux/platform_device.h> + +struct dev_sync_probe_data { + struct platform_device *pdev; + const char *name; + + /* Synchronize with probe */ + struct notifier_block bus_notifier; + struct completion probe_completion; + bool driver_bound; +}; + +void dev_sync_probe_init(struct dev_sync_probe_data *data); +int dev_sync_probe_register(struct dev_sync_probe_data *data, + struct platform_device_info *pdevinfo); +void dev_sync_probe_unregister(struct dev_sync_probe_data *data); + +#endif /* DEV_SYNC_PROBE_H */ diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index fca6cd2eb1dd..4dd5c2c330bb 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -7,6 +7,7 @@ */ #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> #include <linux/module.h> @@ -29,7 +30,7 @@ struct gen_74x164_chip { * register at the end of the transfer. So, to have a logical * numbering, store the bytes in reverse order. */ - u8 buffer[]; + u8 buffer[] __counted_by(registers); }; static int __gen_74x164_write_config(struct gen_74x164_chip *chip) @@ -43,34 +44,31 @@ static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset) struct gen_74x164_chip *chip = gpiochip_get_data(gc); u8 bank = chip->registers - 1 - offset / 8; u8 pin = offset % 8; - int ret; - mutex_lock(&chip->lock); - ret = (chip->buffer[bank] >> pin) & 0x1; - mutex_unlock(&chip->lock); + guard(mutex)(&chip->lock); - return ret; + return !!(chip->buffer[bank] & BIT(pin)); } -static void gen_74x164_set_value(struct gpio_chip *gc, - unsigned offset, int val) +static int gen_74x164_set_value(struct gpio_chip *gc, + unsigned int offset, int val) { struct gen_74x164_chip *chip = gpiochip_get_data(gc); u8 bank = chip->registers - 1 - offset / 8; u8 pin = offset % 8; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); + if (val) - chip->buffer[bank] |= (1 << pin); + chip->buffer[bank] |= BIT(pin); else - chip->buffer[bank] &= ~(1 << pin); + chip->buffer[bank] &= ~BIT(pin); - __gen_74x164_write_config(chip); - mutex_unlock(&chip->lock); + return __gen_74x164_write_config(chip); } -static void gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask, - unsigned long *bits) +static int gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) { struct gen_74x164_chip *chip = gpiochip_get_data(gc); unsigned long offset; @@ -78,7 +76,8 @@ static void gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask, size_t bank; unsigned long bitmask; - mutex_lock(&chip->lock); + guard(mutex)(&chip->lock); + for_each_set_clump8(offset, bankmask, mask, chip->registers * 8) { bank = chip->registers - 1 - offset / 8; bitmask = bitmap_get_value8(bits, offset) & bankmask; @@ -86,8 +85,7 @@ static void gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask, chip->buffer[bank] &= ~bankmask; chip->buffer[bank] |= bitmask; } - __gen_74x164_write_config(chip); - mutex_unlock(&chip->lock); + return __gen_74x164_write_config(chip); } static int gen_74x164_direction_output(struct gpio_chip *gc, @@ -97,8 +95,22 @@ static int gen_74x164_direction_output(struct gpio_chip *gc, return 0; } +static void gen_74x164_deactivate(void *data) +{ + struct gen_74x164_chip *chip = data; + + gpiod_set_value_cansleep(chip->gpiod_oe, 0); +} + +static int gen_74x164_activate(struct device *dev, struct gen_74x164_chip *chip) +{ + gpiod_set_value_cansleep(chip->gpiod_oe, 1); + return devm_add_action_or_reset(dev, gen_74x164_deactivate, chip); +} + static int gen_74x164_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct gen_74x164_chip *chip; u32 nregs; int ret; @@ -112,55 +124,44 @@ static int gen_74x164_probe(struct spi_device *spi) if (ret < 0) return ret; - ret = device_property_read_u32(&spi->dev, "registers-number", &nregs); - if (ret) { - dev_err(&spi->dev, "Missing 'registers-number' property.\n"); - return -EINVAL; - } + ret = device_property_read_u32(dev, "registers-number", &nregs); + if (ret) + return dev_err_probe(dev, ret, "Missing 'registers-number' property.\n"); - chip = devm_kzalloc(&spi->dev, sizeof(*chip) + nregs, GFP_KERNEL); + chip = devm_kzalloc(dev, struct_size(chip, buffer, nregs), GFP_KERNEL); if (!chip) return -ENOMEM; - chip->gpiod_oe = devm_gpiod_get_optional(&spi->dev, "enable", - GPIOD_OUT_LOW); + chip->registers = nregs; + + chip->gpiod_oe = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(chip->gpiod_oe)) return PTR_ERR(chip->gpiod_oe); - spi_set_drvdata(spi, chip); - chip->gpio_chip.label = spi->modalias; chip->gpio_chip.direction_output = gen_74x164_direction_output; chip->gpio_chip.get = gen_74x164_get_value; - chip->gpio_chip.set = gen_74x164_set_value; - chip->gpio_chip.set_multiple = gen_74x164_set_multiple; + chip->gpio_chip.set_rv = gen_74x164_set_value; + chip->gpio_chip.set_multiple_rv = gen_74x164_set_multiple; chip->gpio_chip.base = -1; - - chip->registers = nregs; chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers; - chip->gpio_chip.can_sleep = true; - chip->gpio_chip.parent = &spi->dev; + chip->gpio_chip.parent = dev; chip->gpio_chip.owner = THIS_MODULE; - ret = devm_mutex_init(&spi->dev, &chip->lock); + ret = devm_mutex_init(dev, &chip->lock); if (ret) return ret; ret = __gen_74x164_write_config(chip); if (ret) - return dev_err_probe(&spi->dev, ret, "Config write failed\n"); - - gpiod_set_value_cansleep(chip->gpiod_oe, 1); - - return devm_gpiochip_add_data(&spi->dev, &chip->gpio_chip, chip); -} + return dev_err_probe(dev, ret, "Config write failed\n"); -static void gen_74x164_remove(struct spi_device *spi) -{ - struct gen_74x164_chip *chip = spi_get_drvdata(spi); + ret = gen_74x164_activate(dev, chip); + if (ret) + return ret; - gpiod_set_value_cansleep(chip->gpiod_oe, 0); + return devm_gpiochip_add_data(dev, &chip->gpio_chip, chip); } static const struct spi_device_id gen_74x164_spi_ids[] = { @@ -183,7 +184,6 @@ static struct spi_driver gen_74x164_driver = { .of_match_table = gen_74x164_dt_ids, }, .probe = gen_74x164_probe, - .remove = gen_74x164_remove, .id_table = gen_74x164_spi_ids, }; module_spi_driver(gen_74x164_driver); diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 6dafab0cf964..dc2b941c3726 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -3,11 +3,13 @@ * Copyright (C) 2011-2012 Avionic Design GmbH */ +#include <linux/cleanup.h> #include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/property.h> #include <linux/seq_file.h> #include <linux/slab.h> @@ -78,7 +80,7 @@ static int adnp_gpio_get(struct gpio_chip *chip, unsigned offset) return (value & BIT(pos)) ? 1 : 0; } -static void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value) +static int __adnp_gpio_set(struct adnp *adnp, unsigned int offset, int value) { unsigned int reg = offset >> adnp->reg_shift; unsigned int pos = offset & 7; @@ -87,23 +89,23 @@ static void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value) err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &val); if (err < 0) - return; + return err; if (value) val |= BIT(pos); else val &= ~BIT(pos); - adnp_write(adnp, GPIO_PLR(adnp) + reg, val); + return adnp_write(adnp, GPIO_PLR(adnp) + reg, val); } -static void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int adnp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct adnp *adnp = gpiochip_get_data(chip); - mutex_lock(&adnp->i2c_lock); - __adnp_gpio_set(adnp, offset, value); - mutex_unlock(&adnp->i2c_lock); + guard(mutex)(&adnp->i2c_lock); + + return __adnp_gpio_set(adnp, offset, value); } static int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -114,32 +116,26 @@ static int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) u8 value; int err; - mutex_lock(&adnp->i2c_lock); + guard(mutex)(&adnp->i2c_lock); err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); if (err < 0) - goto out; + return err; value &= ~BIT(pos); err = adnp_write(adnp, GPIO_DDR(adnp) + reg, value); if (err < 0) - goto out; + return err; err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); if (err < 0) - goto out; - - if (value & BIT(pos)) { - err = -EPERM; - goto out; - } + return err; - err = 0; + if (value & BIT(pos)) + return -EPERM; -out: - mutex_unlock(&adnp->i2c_lock); - return err; + return 0; } static int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset, @@ -151,33 +147,28 @@ static int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int err; u8 val; - mutex_lock(&adnp->i2c_lock); + guard(mutex)(&adnp->i2c_lock); err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); if (err < 0) - goto out; + return err; val |= BIT(pos); err = adnp_write(adnp, GPIO_DDR(adnp) + reg, val); if (err < 0) - goto out; + return err; err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); if (err < 0) - goto out; + return err; - if (!(val & BIT(pos))) { - err = -EPERM; - goto out; - } + if (!(val & BIT(pos))) + return -EPERM; __adnp_gpio_set(adnp, offset, value); - err = 0; -out: - mutex_unlock(&adnp->i2c_lock); - return err; + return 0; } static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) @@ -187,27 +178,26 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) int err; for (i = 0; i < num_regs; i++) { - u8 ddr, plr, ier, isr; + u8 ddr = 0, plr = 0, ier = 0, isr = 0; - mutex_lock(&adnp->i2c_lock); + scoped_guard(mutex, &adnp->i2c_lock) { + err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr); + if (err < 0) + return; - err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr); - if (err < 0) - goto unlock; + err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr); + if (err < 0) + return; - err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr); - if (err < 0) - goto unlock; + err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); + if (err < 0) + return; - err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); - if (err < 0) - goto unlock; - - err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); - if (err < 0) - goto unlock; + err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); + if (err < 0) + return; - mutex_unlock(&adnp->i2c_lock); + } for (j = 0; j < 8; j++) { unsigned int bit = (i << adnp->reg_shift) + j; @@ -232,11 +222,6 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) direction, level, interrupt, pending); } } - - return; - -unlock: - mutex_unlock(&adnp->i2c_lock); } static irqreturn_t adnp_irq(int irq, void *data) @@ -248,32 +233,24 @@ static irqreturn_t adnp_irq(int irq, void *data) for (i = 0; i < num_regs; i++) { unsigned int base = i << adnp->reg_shift, bit; - u8 changed, level, isr, ier; + u8 changed, level = 0, isr = 0, ier = 0; unsigned long pending; int err; - mutex_lock(&adnp->i2c_lock); + scoped_guard(mutex, &adnp->i2c_lock) { + err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); + if (err < 0) + continue; - err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); - if (err < 0) { - mutex_unlock(&adnp->i2c_lock); - continue; - } + err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); + if (err < 0) + continue; - err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); - if (err < 0) { - mutex_unlock(&adnp->i2c_lock); - continue; + err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); + if (err < 0) + continue; } - err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); - if (err < 0) { - mutex_unlock(&adnp->i2c_lock); - continue; - } - - mutex_unlock(&adnp->i2c_lock); - /* determine pins that changed levels */ changed = level ^ adnp->irq_level[i]; @@ -365,12 +342,12 @@ static void adnp_irq_bus_unlock(struct irq_data *d) struct adnp *adnp = gpiochip_get_data(gc); unsigned int num_regs = 1 << adnp->reg_shift, i; - mutex_lock(&adnp->i2c_lock); - - for (i = 0; i < num_regs; i++) - adnp_write(adnp, GPIO_IER(adnp) + i, adnp->irq_enable[i]); + scoped_guard(mutex, &adnp->i2c_lock) { + for (i = 0; i < num_regs; i++) + adnp_write(adnp, GPIO_IER(adnp) + i, + adnp->irq_enable[i]); + } - mutex_unlock(&adnp->i2c_lock); mutex_unlock(&adnp->irq_lock); } @@ -453,7 +430,7 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios, chip->direction_input = adnp_gpio_direction_input; chip->direction_output = adnp_gpio_direction_output; chip->get = adnp_gpio_get; - chip->set = adnp_gpio_set; + chip->set_rv = adnp_gpio_set; chip->can_sleep = true; if (IS_ENABLED(CONFIG_DEBUG_FS)) @@ -506,7 +483,10 @@ static int adnp_i2c_probe(struct i2c_client *client) if (!adnp) return -ENOMEM; - mutex_init(&adnp->i2c_lock); + err = devm_mutex_init(&client->dev, &adnp->i2c_lock); + if (err) + return err; + adnp->client = client; err = adnp_gpio_setup(adnp, num_gpios, device_property_read_bool(dev, "interrupt-controller")); diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index c55e821c63b6..57d12c10cbda 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -40,16 +40,18 @@ static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off) return !!(reg_val & dev->lut[off]); } -static void adp5520_gpio_set_value(struct gpio_chip *chip, - unsigned off, int val) +static int adp5520_gpio_set_value(struct gpio_chip *chip, + unsigned int off, int val) { struct adp5520_gpio *dev; dev = gpiochip_get_data(chip); if (val) - adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]); + return adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, + dev->lut[off]); else - adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]); + return adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, + dev->lut[off]); } static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off) @@ -120,7 +122,7 @@ static int adp5520_gpio_probe(struct platform_device *pdev) gc->direction_input = adp5520_gpio_direction_input; gc->direction_output = adp5520_gpio_direction_output; gc->get = adp5520_gpio_get_value; - gc->set = adp5520_gpio_set_value; + gc->set_rv = adp5520_gpio_set_value; gc->can_sleep = true; gc->base = pdata->gpio_start; diff --git a/drivers/gpio/gpio-adp5585.c b/drivers/gpio/gpio-adp5585.c index 000d31f09671..d5c0f1b267c8 100644 --- a/drivers/gpio/gpio-adp5585.c +++ b/drivers/gpio/gpio-adp5585.c @@ -86,14 +86,16 @@ static int adp5585_gpio_get_value(struct gpio_chip *chip, unsigned int off) return !!(val & bit); } -static void adp5585_gpio_set_value(struct gpio_chip *chip, unsigned int off, int val) +static int adp5585_gpio_set_value(struct gpio_chip *chip, unsigned int off, + int val) { struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); unsigned int bank = ADP5585_BANK(off); unsigned int bit = ADP5585_BIT(off); - regmap_update_bits(adp5585_gpio->regmap, ADP5585_GPO_DATA_OUT_A + bank, - bit, val ? bit : 0); + return regmap_update_bits(adp5585_gpio->regmap, + ADP5585_GPO_DATA_OUT_A + bank, + bit, val ? bit : 0); } static int adp5585_gpio_set_bias(struct adp5585_gpio_dev *adp5585_gpio, @@ -192,7 +194,7 @@ static int adp5585_gpio_probe(struct platform_device *pdev) gc->direction_input = adp5585_gpio_direction_input; gc->direction_output = adp5585_gpio_direction_output; gc->get = adp5585_gpio_get_value; - gc->set = adp5585_gpio_set_value; + gc->set_rv = adp5585_gpio_set_value; gc->set_config = adp5585_gpio_set_config; gc->can_sleep = true; diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index d668ddb2e81d..d232ea865356 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -372,25 +372,30 @@ static void gpio_fwd_delay(struct gpio_chip *chip, unsigned int offset, int valu udelay(delay_us); } -static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value) +static int gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value) { struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + int ret; if (chip->can_sleep) - gpiod_set_value_cansleep(fwd->descs[offset], value); + ret = gpiod_set_value_cansleep(fwd->descs[offset], value); else - gpiod_set_value(fwd->descs[offset], value); + ret = gpiod_set_value(fwd->descs[offset], value); + if (ret) + return ret; if (fwd->delay_timings) gpio_fwd_delay(chip, offset, value); + + return ret; } -static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, - unsigned long *bits) +static int gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, + unsigned long *bits) { struct gpio_desc **descs = fwd_tmp_descs(fwd); unsigned long *values = fwd_tmp_values(fwd); - unsigned int i, j = 0; + unsigned int i, j = 0, ret; for_each_set_bit(i, mask, fwd->chip.ngpio) { __assign_bit(j, values, test_bit(i, bits)); @@ -398,26 +403,31 @@ static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, } if (fwd->chip.can_sleep) - gpiod_set_array_value_cansleep(j, descs, NULL, values); + ret = gpiod_set_array_value_cansleep(j, descs, NULL, values); else - gpiod_set_array_value(j, descs, NULL, values); + ret = gpiod_set_array_value(j, descs, NULL, values); + + return ret; } -static void gpio_fwd_set_multiple_locked(struct gpio_chip *chip, - unsigned long *mask, unsigned long *bits) +static int gpio_fwd_set_multiple_locked(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) { struct gpiochip_fwd *fwd = gpiochip_get_data(chip); unsigned long flags; + int ret; if (chip->can_sleep) { mutex_lock(&fwd->mlock); - gpio_fwd_set_multiple(fwd, mask, bits); + ret = gpio_fwd_set_multiple(fwd, mask, bits); mutex_unlock(&fwd->mlock); } else { spin_lock_irqsave(&fwd->slock, flags); - gpio_fwd_set_multiple(fwd, mask, bits); + ret = gpio_fwd_set_multiple(fwd, mask, bits); spin_unlock_irqrestore(&fwd->slock, flags); } + + return ret; } static int gpio_fwd_set_config(struct gpio_chip *chip, unsigned int offset, @@ -547,8 +557,8 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, chip->direction_output = gpio_fwd_direction_output; chip->get = gpio_fwd_get; chip->get_multiple = gpio_fwd_get_multiple_locked; - chip->set = gpio_fwd_set; - chip->set_multiple = gpio_fwd_set_multiple_locked; + chip->set_rv = gpio_fwd_set; + chip->set_multiple_rv = gpio_fwd_set_multiple_locked; chip->to_irq = gpio_fwd_to_irq; chip->base = -1; chip->ngpio = ngpios; diff --git a/drivers/gpio/gpio-altera-a10sr.c b/drivers/gpio/gpio-altera-a10sr.c index 11edf1fe6c90..77a674cf99e4 100644 --- a/drivers/gpio/gpio-altera-a10sr.c +++ b/drivers/gpio/gpio-altera-a10sr.c @@ -35,15 +35,15 @@ static int altr_a10sr_gpio_get(struct gpio_chip *chip, unsigned int offset) return !!(val & BIT(offset - ALTR_A10SR_LED_VALID_SHIFT)); } -static void altr_a10sr_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) +static int altr_a10sr_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip); - regmap_update_bits(gpio->regmap, ALTR_A10SR_LED_REG, - BIT(ALTR_A10SR_LED_VALID_SHIFT + offset), - value ? BIT(ALTR_A10SR_LED_VALID_SHIFT + offset) - : 0); + return regmap_update_bits(gpio->regmap, ALTR_A10SR_LED_REG, + BIT(ALTR_A10SR_LED_VALID_SHIFT + offset), + value ? + BIT(ALTR_A10SR_LED_VALID_SHIFT + offset) : 0); } static int altr_a10sr_gpio_direction_input(struct gpio_chip *gc, @@ -69,7 +69,7 @@ static const struct gpio_chip altr_a10sr_gc = { .label = "altr_a10sr_gpio", .owner = THIS_MODULE, .get = altr_a10sr_gpio_get, - .set = altr_a10sr_gpio_set, + .set_rv = altr_a10sr_gpio_set, .direction_input = altr_a10sr_gpio_direction_input, .direction_output = altr_a10sr_gpio_direction_output, .can_sleep = true, diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 17ab039c7413..1b28525726d7 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -113,7 +113,7 @@ static int altera_gpio_get(struct gpio_chip *gc, unsigned offset) return !!(readl(altera_gc->regs + ALTERA_GPIO_DATA) & BIT(offset)); } -static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +static int altera_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) { struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); unsigned long flags; @@ -127,6 +127,8 @@ static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value) data_reg &= ~BIT(offset); writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA); raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); + + return 0; } static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset) @@ -257,7 +259,7 @@ static int altera_gpio_probe(struct platform_device *pdev) altera_gc->gc.direction_input = altera_gpio_direction_input; altera_gc->gc.direction_output = altera_gpio_direction_output; altera_gc->gc.get = altera_gpio_get; - altera_gc->gc.set = altera_gpio_set; + altera_gc->gc.set_rv = altera_gpio_set; altera_gc->gc.owner = THIS_MODULE; altera_gc->gc.parent = &pdev->dev; altera_gc->gc.base = -1; diff --git a/drivers/gpio/gpio-amd-fch.c b/drivers/gpio/gpio-amd-fch.c index 2a21354ed6a0..f8d0cea46049 100644 --- a/drivers/gpio/gpio-amd-fch.c +++ b/drivers/gpio/gpio-amd-fch.c @@ -95,8 +95,7 @@ static int amd_fch_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; } -static void amd_fch_gpio_set(struct gpio_chip *gc, - unsigned int gpio, int value) +static int amd_fch_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) { unsigned long flags; struct amd_fch_gpio_priv *priv = gpiochip_get_data(gc); @@ -113,6 +112,8 @@ static void amd_fch_gpio_set(struct gpio_chip *gc, writel_relaxed(mask, ptr); spin_unlock_irqrestore(&priv->lock, flags); + + return 0; } static int amd_fch_gpio_get(struct gpio_chip *gc, @@ -164,7 +165,7 @@ static int amd_fch_gpio_probe(struct platform_device *pdev) priv->gc.direction_output = amd_fch_gpio_direction_output; priv->gc.get_direction = amd_fch_gpio_get_direction; priv->gc.get = amd_fch_gpio_get; - priv->gc.set = amd_fch_gpio_set; + priv->gc.set_rv = amd_fch_gpio_set; spin_lock_init(&priv->lock); diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index 3377667a28de..425d8472f744 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -94,7 +94,7 @@ static void amd_gpio_free(struct gpio_chip *chip, unsigned offset) iowrite8(agp->orig[offset], agp->pm + AMD_REG_GPIO(offset)); } -static void amd_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int amd_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct amd_gpio *agp = gpiochip_get_data(chip); u8 temp; @@ -107,6 +107,8 @@ static void amd_gpio_set(struct gpio_chip *chip, unsigned offset, int value) spin_unlock_irqrestore(&agp->lock, flags); dev_dbg(&agp->pdev->dev, "Setting gpio %d, value %d, reg=%02x\n", offset, !!value, temp); + + return 0; } static int amd_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -163,7 +165,7 @@ static struct amd_gpio gp = { .ngpio = 32, .request = amd_gpio_request, .free = amd_gpio_free, - .set = amd_gpio_set, + .set_rv = amd_gpio_set, .get = amd_gpio_get, .direction_output = amd_gpio_dirout, .direction_input = amd_gpio_dirin, diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index c15fda99120a..e530c94dcce8 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -121,7 +121,8 @@ static int arizona_gpio_direction_out(struct gpio_chip *chip, ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value); } -static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int arizona_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip); struct arizona *arizona = arizona_gpio->arizona; @@ -129,8 +130,8 @@ static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value) if (value) value = ARIZONA_GPN_LVL; - regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, - ARIZONA_GPN_LVL, value); + return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, + ARIZONA_GPN_LVL, value); } static const struct gpio_chip template_chip = { @@ -139,7 +140,7 @@ static const struct gpio_chip template_chip = { .direction_input = arizona_gpio_direction_in, .get = arizona_gpio_get, .direction_output = arizona_gpio_direction_out, - .set = arizona_gpio_set, + .set_rv = arizona_gpio_set, .can_sleep = true, }; diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c index 34eb26298e32..00b31497ecff 100644 --- a/drivers/gpio/gpio-aspeed-sgpio.c +++ b/drivers/gpio/gpio-aspeed-sgpio.c @@ -6,6 +6,7 @@ */ #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/gpio/driver.h> #include <linux/hashtable.h> @@ -170,17 +171,14 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) { struct aspeed_sgpio *gpio = gpiochip_get_data(gc); const struct aspeed_sgpio_bank *bank = to_bank(offset); - unsigned long flags; enum aspeed_sgpio_reg reg; int rc = 0; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); - raw_spin_unlock_irqrestore(&gpio->lock, flags); - return rc; } @@ -211,16 +209,13 @@ static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) return 0; } -static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) +static int aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) { struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - unsigned long flags; - - raw_spin_lock_irqsave(&gpio->lock, flags); - sgpio_set_value(gc, offset, val); + guard(raw_spinlock_irqsave)(&gpio->lock); - raw_spin_unlock_irqrestore(&gpio->lock, flags); + return sgpio_set_value(gc, offset, val); } static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) @@ -231,15 +226,14 @@ static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) { struct aspeed_sgpio *gpio = gpiochip_get_data(gc); - unsigned long flags; int rc; /* No special action is required for setting the direction; we'll * error-out in sgpio_set_value if this isn't an output GPIO */ - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); + rc = sgpio_set_value(gc, offset, val); - raw_spin_unlock_irqrestore(&gpio->lock, flags); return rc; } @@ -269,7 +263,6 @@ static void aspeed_sgpio_irq_ack(struct irq_data *d) { const struct aspeed_sgpio_bank *bank; struct aspeed_sgpio *gpio; - unsigned long flags; void __iomem *status_addr; int offset; u32 bit; @@ -278,18 +271,15 @@ static void aspeed_sgpio_irq_ack(struct irq_data *d) status_addr = bank_reg(gpio, bank, reg_irq_status); - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); iowrite32(bit, status_addr); - - raw_spin_unlock_irqrestore(&gpio->lock, flags); } static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) { const struct aspeed_sgpio_bank *bank; struct aspeed_sgpio *gpio; - unsigned long flags; u32 reg, bit; void __iomem *addr; int offset; @@ -301,17 +291,15 @@ static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) if (set) gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); - raw_spin_lock_irqsave(&gpio->lock, flags); - - reg = ioread32(addr); - if (set) - reg |= bit; - else - reg &= ~bit; - - iowrite32(reg, addr); + scoped_guard(raw_spinlock_irqsave, &gpio->lock) { + reg = ioread32(addr); + if (set) + reg |= bit; + else + reg &= ~bit; - raw_spin_unlock_irqrestore(&gpio->lock, flags); + iowrite32(reg, addr); + } /* Masking the IRQ */ if (!set) @@ -339,7 +327,6 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) const struct aspeed_sgpio_bank *bank; irq_flow_handler_t handler; struct aspeed_sgpio *gpio; - unsigned long flags; void __iomem *addr; int offset; @@ -366,24 +353,22 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - raw_spin_lock_irqsave(&gpio->lock, flags); - - addr = bank_reg(gpio, bank, reg_irq_type0); - reg = ioread32(addr); - reg = (reg & ~bit) | type0; - iowrite32(reg, addr); - - addr = bank_reg(gpio, bank, reg_irq_type1); - reg = ioread32(addr); - reg = (reg & ~bit) | type1; - iowrite32(reg, addr); - - addr = bank_reg(gpio, bank, reg_irq_type2); - reg = ioread32(addr); - reg = (reg & ~bit) | type2; - iowrite32(reg, addr); - - raw_spin_unlock_irqrestore(&gpio->lock, flags); + scoped_guard(raw_spinlock_irqsave, &gpio->lock) { + addr = bank_reg(gpio, bank, reg_irq_type0); + reg = ioread32(addr); + reg = (reg & ~bit) | type0; + iowrite32(reg, addr); + + addr = bank_reg(gpio, bank, reg_irq_type1); + reg = ioread32(addr); + reg = (reg & ~bit) | type1; + iowrite32(reg, addr); + + addr = bank_reg(gpio, bank, reg_irq_type2); + reg = ioread32(addr); + reg = (reg & ~bit) | type2; + iowrite32(reg, addr); + } irq_set_handler_locked(d, handler); @@ -487,13 +472,12 @@ static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, unsigned int offset, bool enable) { struct aspeed_sgpio *gpio = gpiochip_get_data(chip); - unsigned long flags; void __iomem *reg; u32 val; reg = bank_reg(gpio, to_bank(offset), reg_tolerance); - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); val = readl(reg); @@ -504,8 +488,6 @@ static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, writel(val, reg); - raw_spin_unlock_irqrestore(&gpio->lock, flags); - return 0; } @@ -614,7 +596,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) gpio->chip.request = NULL; gpio->chip.free = NULL; gpio->chip.get = aspeed_sgpio_get; - gpio->chip.set = aspeed_sgpio_set; + gpio->chip.set_rv = aspeed_sgpio_set; gpio->chip.set_config = aspeed_sgpio_set_config; gpio->chip.label = dev_name(&pdev->dev); gpio->chip.base = -1; diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 40c1bd80f8b0..2d340a343a17 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -5,6 +5,7 @@ * Joel Stanley <joel@jms.id.au> */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/gpio/aspeed.h> #include <linux/gpio/driver.h> @@ -423,41 +424,38 @@ static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, gpio->config->llops->reg_bit_get(gpio, offset, reg_val); } -static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, - int val) +static int aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - unsigned long flags; bool copro = false; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); + copro = aspeed_gpio_copro_request(gpio, offset); __aspeed_gpio_set(gc, offset, val); if (copro) aspeed_gpio_copro_release(gpio, offset); - raw_spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; } static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - unsigned long flags; bool copro = false; if (!have_input(gpio, offset)) return -ENOTSUPP; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); copro = aspeed_gpio_copro_request(gpio, offset); gpio->config->llops->reg_bit_set(gpio, offset, reg_dir, 0); if (copro) aspeed_gpio_copro_release(gpio, offset); - raw_spin_unlock_irqrestore(&gpio->lock, flags); - return 0; } @@ -465,13 +463,12 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - unsigned long flags; bool copro = false; if (!have_output(gpio, offset)) return -ENOTSUPP; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); copro = aspeed_gpio_copro_request(gpio, offset); __aspeed_gpio_set(gc, offset, val); @@ -479,7 +476,6 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, if (copro) aspeed_gpio_copro_release(gpio, offset); - raw_spin_unlock_irqrestore(&gpio->lock, flags); return 0; } @@ -487,7 +483,6 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - unsigned long flags; u32 val; if (!have_input(gpio, offset)) @@ -496,12 +491,10 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) if (!have_output(gpio, offset)) return GPIO_LINE_DIRECTION_IN; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); val = gpio->config->llops->reg_bit_get(gpio, offset, reg_dir); - raw_spin_unlock_irqrestore(&gpio->lock, flags); - return val ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; } @@ -527,7 +520,6 @@ static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, static void aspeed_gpio_irq_ack(struct irq_data *d) { struct aspeed_gpio *gpio; - unsigned long flags; int rc, offset; bool copro = false; @@ -535,20 +527,19 @@ static void aspeed_gpio_irq_ack(struct irq_data *d) if (rc) return; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); + copro = aspeed_gpio_copro_request(gpio, offset); gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_status, 1); if (copro) aspeed_gpio_copro_release(gpio, offset); - raw_spin_unlock_irqrestore(&gpio->lock, flags); } static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) { struct aspeed_gpio *gpio; - unsigned long flags; int rc, offset; bool copro = false; @@ -560,14 +551,14 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) if (set) gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); + copro = aspeed_gpio_copro_request(gpio, offset); gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_enable, set); if (copro) aspeed_gpio_copro_release(gpio, offset); - raw_spin_unlock_irqrestore(&gpio->lock, flags); /* Masking the IRQ */ if (!set) @@ -591,7 +582,6 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) u32 type2 = 0; irq_flow_handler_t handler; struct aspeed_gpio *gpio; - unsigned long flags; int rc, offset; bool copro = false; @@ -620,16 +610,19 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - raw_spin_lock_irqsave(&gpio->lock, flags); - copro = aspeed_gpio_copro_request(gpio, offset); + scoped_guard(raw_spinlock_irqsave, &gpio->lock) { + copro = aspeed_gpio_copro_request(gpio, offset); - gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0); - gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1); - gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2); + gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type0, + type0); + gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type1, + type1); + gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type2, + type2); - if (copro) - aspeed_gpio_copro_release(gpio, offset); - raw_spin_unlock_irqrestore(&gpio->lock, flags); + if (copro) + aspeed_gpio_copro_release(gpio, offset); + } irq_set_handler_locked(d, handler); @@ -686,17 +679,16 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, unsigned int offset, bool enable) { struct aspeed_gpio *gpio = gpiochip_get_data(chip); - unsigned long flags; bool copro = false; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); + copro = aspeed_gpio_copro_request(gpio, offset); gpio->config->llops->reg_bit_set(gpio, offset, reg_tolerance, enable); if (copro) aspeed_gpio_copro_release(gpio, offset); - raw_spin_unlock_irqrestore(&gpio->lock, flags); return 0; } @@ -798,7 +790,6 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, { struct aspeed_gpio *gpio = gpiochip_get_data(chip); u32 requested_cycles; - unsigned long flags; int rc; int i; @@ -812,12 +803,12 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, return rc; } - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); if (timer_allocation_registered(gpio, offset)) { rc = unregister_allocated_timer(gpio, offset); if (rc < 0) - goto out; + return rc; } /* Try to find a timer already configured for the debounce period */ @@ -855,7 +846,7 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, * consistency. */ configure_timer(gpio, offset, 0); - goto out; + return rc; } i = j; @@ -863,34 +854,26 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, iowrite32(requested_cycles, gpio->base + gpio->config->debounce_timers_array[i]); } - if (WARN(i == 0, "Cannot register index of disabled timer\n")) { - rc = -EINVAL; - goto out; - } + if (WARN(i == 0, "Cannot register index of disabled timer\n")) + return -EINVAL; register_allocated_timer(gpio, offset, i); configure_timer(gpio, offset, i); -out: - raw_spin_unlock_irqrestore(&gpio->lock, flags); - return rc; } static int disable_debounce(struct gpio_chip *chip, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(chip); - unsigned long flags; int rc; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); rc = unregister_allocated_timer(gpio, offset); if (!rc) configure_timer(gpio, offset, 0); - raw_spin_unlock_irqrestore(&gpio->lock, flags); - return rc; } @@ -961,7 +944,6 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, struct aspeed_gpio *gpio = gpiochip_get_data(chip); int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); const struct aspeed_gpio_bank *bank = to_bank(offset); - unsigned long flags; if (!aspeed_gpio_support_copro(gpio)) return -EOPNOTSUPP; @@ -974,13 +956,12 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, return -EINVAL; bindex = offset >> 3; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); /* Sanity check, this shouldn't happen */ - if (gpio->cf_copro_bankmap[bindex] == 0xff) { - rc = -EIO; - goto bail; - } + if (gpio->cf_copro_bankmap[bindex] == 0xff) + return -EIO; + gpio->cf_copro_bankmap[bindex]++; /* Switch command source */ @@ -994,8 +975,6 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, *dreg_offset = bank->rdata_reg; if (bit) *bit = GPIO_OFFSET(offset); - bail: - raw_spin_unlock_irqrestore(&gpio->lock, flags); return rc; } EXPORT_SYMBOL_GPL(aspeed_gpio_copro_grab_gpio); @@ -1009,7 +988,6 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) struct gpio_chip *chip = gpiod_to_chip(desc); struct aspeed_gpio *gpio = gpiochip_get_data(chip); int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); - unsigned long flags; if (!aspeed_gpio_support_copro(gpio)) return -EOPNOTSUPP; @@ -1021,21 +999,19 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) return -EINVAL; bindex = offset >> 3; - raw_spin_lock_irqsave(&gpio->lock, flags); + guard(raw_spinlock_irqsave)(&gpio->lock); /* Sanity check, this shouldn't happen */ - if (gpio->cf_copro_bankmap[bindex] == 0) { - rc = -EIO; - goto bail; - } + if (gpio->cf_copro_bankmap[bindex] == 0) + return -EIO; + gpio->cf_copro_bankmap[bindex]--; /* Switch command source */ if (gpio->cf_copro_bankmap[bindex] == 0) aspeed_gpio_change_cmd_source(gpio, offset, GPIO_CMDSRC_ARM); - bail: - raw_spin_unlock_irqrestore(&gpio->lock, flags); + return rc; } EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio); @@ -1376,7 +1352,7 @@ static int aspeed_gpio_probe(struct platform_device *pdev) gpio->chip.request = aspeed_gpio_request; gpio->chip.free = aspeed_gpio_free; gpio->chip.get = aspeed_gpio_get; - gpio->chip.set = aspeed_gpio_set; + gpio->chip.set_rv = aspeed_gpio_set; gpio->chip.set_config = aspeed_gpio_set_config; gpio->chip.label = dev_name(&pdev->dev); gpio->chip.base = -1; diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 491b529d25f8..ca3472977431 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -9,6 +9,7 @@ #include <linux/irqchip/chained_irq.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/string_choices.h> enum gio_reg_index { GIO_REG_ODEN = 0, @@ -224,7 +225,7 @@ static int brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv, ret = disable_irq_wake(priv->parent_wake_irq); if (ret) dev_err(&priv->pdev->dev, "failed to %s wake-up interrupt\n", - enable ? "enable" : "disable"); + str_enable_disable(enable)); return ret; } diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index 25db014494a4..56effd0f50c7 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/seq_file.h> +#include <linux/string_choices.h> #include <linux/types.h> #define CRYSTALCOVE_GPIO_NUM 16 @@ -317,7 +318,7 @@ static void crystalcove_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip offset = gpio % 8; seq_printf(s, " gpio-%-2d %s %s %s %s ctlo=%2x,%s %s %s\n", gpio, ctlo & CTLO_DIR_OUT ? "out" : "in ", - ctli & 0x1 ? "hi" : "lo", + str_hi_lo(ctli & 0x1), ctli & CTLI_INTCNT_NE ? "fall" : " ", ctli & CTLI_INTCNT_PE ? "rise" : " ", ctlo, diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 8c033e8cf3c9..63fc7888c1d4 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -139,7 +139,7 @@ static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) /* * Assuming the pin is muxed as a gpio output, set its output value. */ -static void +static int davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct davinci_gpio_controller *d = gpiochip_get_data(chip); @@ -150,6 +150,8 @@ davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) writel_relaxed(__gpio_mask(offset), value ? &g->set_data : &g->clr_data); + + return 0; } static int davinci_gpio_probe(struct platform_device *pdev) @@ -209,7 +211,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips->chip.direction_input = davinci_direction_in; chips->chip.get = davinci_gpio_get; chips->chip.direction_output = davinci_direction_out; - chips->chip.set = davinci_gpio_set; + chips->chip.set_rv = davinci_gpio_set; chips->chip.ngpio = ngpio; chips->chip.base = -1; diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 169f33c41c59..30a0522ae735 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/string_choices.h> #define GRGPIO_MAX_NGPIO 32 @@ -438,7 +439,7 @@ static int grgpio_probe(struct platform_device *ofdev) } dev_info(dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n", - priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off"); + priv->regs, gc->base, gc->ngpio, str_on_off(priv->domain)); return 0; } diff --git a/drivers/gpio/gpio-latch.c b/drivers/gpio/gpio-latch.c index d7c3b20c8482..3d0ff09284fb 100644 --- a/drivers/gpio/gpio-latch.c +++ b/drivers/gpio/gpio-latch.c @@ -38,12 +38,14 @@ * in the corresponding device tree properties. */ +#include <linux/cleanup.h> #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/delay.h> #include "gpiolib.h" @@ -71,46 +73,46 @@ static int gpio_latch_get_direction(struct gpio_chip *gc, unsigned int offset) return GPIO_LINE_DIRECTION_OUT; } -static void gpio_latch_set_unlocked(struct gpio_latch_priv *priv, - void (*set)(struct gpio_desc *desc, int value), - unsigned int offset, bool val) +static int gpio_latch_set_unlocked(struct gpio_latch_priv *priv, + int (*set)(struct gpio_desc *desc, int value), + unsigned int offset, bool val) { - int latch = offset / priv->n_latched_gpios; - int i; + int latch = offset / priv->n_latched_gpios, i, ret; assign_bit(offset, priv->shadow, val); - for (i = 0; i < priv->n_latched_gpios; i++) - set(priv->latched_gpios->desc[i], - test_bit(latch * priv->n_latched_gpios + i, priv->shadow)); + for (i = 0; i < priv->n_latched_gpios; i++) { + ret = set(priv->latched_gpios->desc[i], + test_bit(latch * priv->n_latched_gpios + i, + priv->shadow)); + if (ret) + return ret; + } ndelay(priv->setup_duration_ns); set(priv->clk_gpios->desc[latch], 1); ndelay(priv->clock_duration_ns); set(priv->clk_gpios->desc[latch], 0); + + return 0; } -static void gpio_latch_set(struct gpio_chip *gc, unsigned int offset, int val) +static int gpio_latch_set(struct gpio_chip *gc, unsigned int offset, int val) { struct gpio_latch_priv *priv = gpiochip_get_data(gc); - unsigned long flags; - - spin_lock_irqsave(&priv->spinlock, flags); - gpio_latch_set_unlocked(priv, gpiod_set_value, offset, val); + guard(spinlock_irqsave)(&priv->spinlock); - spin_unlock_irqrestore(&priv->spinlock, flags); + return gpio_latch_set_unlocked(priv, gpiod_set_value, offset, val); } -static void gpio_latch_set_can_sleep(struct gpio_chip *gc, unsigned int offset, int val) +static int gpio_latch_set_can_sleep(struct gpio_chip *gc, unsigned int offset, int val) { struct gpio_latch_priv *priv = gpiochip_get_data(gc); - mutex_lock(&priv->mutex); - - gpio_latch_set_unlocked(priv, gpiod_set_value_cansleep, offset, val); + guard(mutex)(&priv->mutex); - mutex_unlock(&priv->mutex); + return gpio_latch_set_unlocked(priv, gpiod_set_value_cansleep, offset, val); } static bool gpio_latch_can_sleep(struct gpio_latch_priv *priv, unsigned int n_latches) @@ -138,50 +140,52 @@ static bool gpio_latch_can_sleep(struct gpio_latch_priv *priv, unsigned int n_la static int gpio_latch_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct gpio_latch_priv *priv; unsigned int n_latches; - struct device_node *np = pdev->dev.of_node; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->clk_gpios = devm_gpiod_get_array(&pdev->dev, "clk", GPIOD_OUT_LOW); + priv->clk_gpios = devm_gpiod_get_array(dev, "clk", GPIOD_OUT_LOW); if (IS_ERR(priv->clk_gpios)) return PTR_ERR(priv->clk_gpios); - priv->latched_gpios = devm_gpiod_get_array(&pdev->dev, "latched", GPIOD_OUT_LOW); + priv->latched_gpios = devm_gpiod_get_array(dev, "latched", GPIOD_OUT_LOW); if (IS_ERR(priv->latched_gpios)) return PTR_ERR(priv->latched_gpios); n_latches = priv->clk_gpios->ndescs; priv->n_latched_gpios = priv->latched_gpios->ndescs; - priv->shadow = devm_bitmap_zalloc(&pdev->dev, n_latches * priv->n_latched_gpios, + priv->shadow = devm_bitmap_zalloc(dev, n_latches * priv->n_latched_gpios, GFP_KERNEL); if (!priv->shadow) return -ENOMEM; if (gpio_latch_can_sleep(priv, n_latches)) { priv->gc.can_sleep = true; - priv->gc.set = gpio_latch_set_can_sleep; + priv->gc.set_rv = gpio_latch_set_can_sleep; mutex_init(&priv->mutex); } else { priv->gc.can_sleep = false; - priv->gc.set = gpio_latch_set; + priv->gc.set_rv = gpio_latch_set; spin_lock_init(&priv->spinlock); } - of_property_read_u32(np, "setup-duration-ns", &priv->setup_duration_ns); + device_property_read_u32(dev, "setup-duration-ns", + &priv->setup_duration_ns); if (priv->setup_duration_ns > DURATION_NS_MAX) { - dev_warn(&pdev->dev, "setup-duration-ns too high, limit to %d\n", + dev_warn(dev, "setup-duration-ns too high, limit to %d\n", DURATION_NS_MAX); priv->setup_duration_ns = DURATION_NS_MAX; } - of_property_read_u32(np, "clock-duration-ns", &priv->clock_duration_ns); + device_property_read_u32(dev, "clock-duration-ns", + &priv->clock_duration_ns); if (priv->clock_duration_ns > DURATION_NS_MAX) { - dev_warn(&pdev->dev, "clock-duration-ns too high, limit to %d\n", + dev_warn(dev, "clock-duration-ns too high, limit to %d\n", DURATION_NS_MAX); priv->clock_duration_ns = DURATION_NS_MAX; } @@ -190,11 +194,11 @@ static int gpio_latch_probe(struct platform_device *pdev) priv->gc.ngpio = n_latches * priv->n_latched_gpios; priv->gc.owner = THIS_MODULE; priv->gc.base = -1; - priv->gc.parent = &pdev->dev; + priv->gc.parent = dev; platform_set_drvdata(pdev, priv); - return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv); + return devm_gpiochip_add_data(dev, &priv->gc, priv); } static const struct of_device_id gpio_latch_ids[] = { diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c index 7f4d78fd800e..a9a93036f08f 100644 --- a/drivers/gpio/gpio-loongson-64bit.c +++ b/drivers/gpio/gpio-loongson-64bit.c @@ -31,7 +31,6 @@ struct loongson_gpio_chip_data { struct loongson_gpio_chip { struct gpio_chip chip; - struct fwnode_handle *fwnode; spinlock_t lock; void __iomem *reg_base; const struct loongson_gpio_chip_data *chip_data; @@ -138,7 +137,6 @@ static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgp void __iomem *reg_base) { int ret; - u32 ngpios; lgpio->reg_base = reg_base; if (lgpio->chip_data->mode == BIT_CTRL_MODE) { @@ -159,8 +157,6 @@ 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); } @@ -258,6 +254,33 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { .out_offset = 0x900, }; +/* LS7A2000 chipset GPIO */ +static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data0 = { + .label = "ls7a2000_gpio", + .mode = BYTE_CTRL_MODE, + .conf_offset = 0x800, + .in_offset = 0xa00, + .out_offset = 0x900, +}; + +/* LS7A2000 ACPI GPIO */ +static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data1 = { + .label = "ls7a2000_gpio", + .mode = BYTE_CTRL_MODE, + .conf_offset = 0x4, + .in_offset = 0x8, + .out_offset = 0x0, +}; + +/* Loongson-3A6000 node GPIO */ +static const struct loongson_gpio_chip_data loongson_gpio_ls3a6000_data = { + .label = "ls3a6000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0xc, + .out_offset = 0x8, +}; + static const struct of_device_id loongson_gpio_of_match[] = { { .compatible = "loongson,ls2k-gpio", @@ -291,6 +314,18 @@ static const struct of_device_id loongson_gpio_of_match[] = { .compatible = "loongson,ls7a-gpio", .data = &loongson_gpio_ls7a_data, }, + { + .compatible = "loongson,ls7a2000-gpio1", + .data = &loongson_gpio_ls7a2000_data0, + }, + { + .compatible = "loongson,ls7a2000-gpio2", + .data = &loongson_gpio_ls7a2000_data1, + }, + { + .compatible = "loongson,ls3a6000-gpio", + .data = &loongson_gpio_ls3a6000_data, + }, {} }; MODULE_DEVICE_TABLE(of, loongson_gpio_of_match); @@ -316,6 +351,18 @@ static const struct acpi_device_id loongson_gpio_acpi_match[] = { .id = "LOON000C", .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data2, }, + { + .id = "LOON000D", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data0, + }, + { + .id = "LOON000E", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data1, + }, + { + .id = "LOON000F", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a6000_data, + }, {} }; MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match); diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index bbacc714632b..fc0708ab5192 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -309,23 +309,21 @@ static int max3191x_set_config(struct gpio_chip *gpio, unsigned int offset, return 0; } -static void gpiod_set_array_single_value_cansleep(unsigned int ndescs, - struct gpio_desc **desc, - struct gpio_array *info, +static void max3191x_gpiod_multi_set_single_value(struct gpio_descs *descs, int value) { unsigned long *values; - values = bitmap_alloc(ndescs, GFP_KERNEL); + values = bitmap_alloc(descs->ndescs, GFP_KERNEL); if (!values) return; if (value) - bitmap_fill(values, ndescs); + bitmap_fill(values, descs->ndescs); else - bitmap_zero(values, ndescs); + bitmap_zero(values, descs->ndescs); - gpiod_set_array_value_cansleep(ndescs, desc, info, values); + gpiod_multi_set_value_cansleep(descs, values); bitmap_free(values); } @@ -396,10 +394,8 @@ static int max3191x_probe(struct spi_device *spi) max3191x->mode = device_property_read_bool(dev, "maxim,modesel-8bit") ? STATUS_BYTE_DISABLED : STATUS_BYTE_ENABLED; if (max3191x->modesel_pins) - gpiod_set_array_single_value_cansleep( - max3191x->modesel_pins->ndescs, - max3191x->modesel_pins->desc, - max3191x->modesel_pins->info, max3191x->mode); + max3191x_gpiod_multi_set_single_value(max3191x->modesel_pins, + max3191x->mode); max3191x->ignore_uv = device_property_read_bool(dev, "maxim,ignore-undervoltage"); diff --git a/drivers/gpio/gpio-max77650.c b/drivers/gpio/gpio-max77650.c index 3075f2513c6f..a553e141059f 100644 --- a/drivers/gpio/gpio-max77650.c +++ b/drivers/gpio/gpio-max77650.c @@ -62,18 +62,16 @@ static int max77650_gpio_direction_output(struct gpio_chip *gc, MAX77650_REG_CNFG_GPIO, mask, regval); } -static void max77650_gpio_set_value(struct gpio_chip *gc, - unsigned int offset, int value) +static int max77650_gpio_set_value(struct gpio_chip *gc, + unsigned int offset, int value) { struct max77650_gpio_chip *chip = gpiochip_get_data(gc); - int rv, regval; + int regval; regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW; - rv = regmap_update_bits(chip->map, MAX77650_REG_CNFG_GPIO, - MAX77650_GPIO_OUTVAL_MASK, regval); - if (rv) - dev_err(gc->parent, "cannot set GPIO value: %d\n", rv); + return regmap_update_bits(chip->map, MAX77650_REG_CNFG_GPIO, + MAX77650_GPIO_OUTVAL_MASK, regval); } static int max77650_gpio_get_value(struct gpio_chip *gc, @@ -168,7 +166,7 @@ static int max77650_gpio_probe(struct platform_device *pdev) chip->gc.direction_input = max77650_gpio_direction_input; chip->gc.direction_output = max77650_gpio_direction_output; - chip->gc.set = max77650_gpio_set_value; + chip->gc.set_rv = max77650_gpio_set_value; chip->gc.get = max77650_gpio_get_value; chip->gc.get_direction = max77650_gpio_get_direction; chip->gc.set_config = max77650_gpio_set_config; diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index d89e78f0ead3..4841e4ebe7a6 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -49,6 +49,7 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` #include <linux/log2.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/slab.h> @@ -323,9 +324,20 @@ static void bgpio_set_multiple_with_clear(struct gpio_chip *gc, gc->write_reg(gc->reg_clr, clear_mask); } +static int bgpio_dir_return(struct gpio_chip *gc, unsigned int gpio, bool dir_out) +{ + if (!gc->bgpio_pinctrl) + return 0; + + if (dir_out) + return pinctrl_gpio_direction_output(gc, gpio); + else + return pinctrl_gpio_direction_input(gc, gpio); +} + static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) { - return 0; + return bgpio_dir_return(gc, gpio, false); } static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio, @@ -339,7 +351,7 @@ static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, { gc->set(gc, gpio, val); - return 0; + return bgpio_dir_return(gc, gpio, true); } static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) @@ -357,7 +369,7 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); - return 0; + return bgpio_dir_return(gc, gpio, false); } static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) @@ -403,7 +415,7 @@ static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, { bgpio_dir_out(gc, gpio, val); gc->set(gc, gpio, val); - return 0; + return bgpio_dir_return(gc, gpio, true); } static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio, @@ -411,7 +423,7 @@ static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio, { gc->set(gc, gpio, val); bgpio_dir_out(gc, gpio, val); - return 0; + return bgpio_dir_return(gc, gpio, true); } static int bgpio_setup_accessors(struct device *dev, @@ -562,10 +574,13 @@ static int bgpio_setup_direction(struct gpio_chip *gc, static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) { - if (gpio_pin < chip->ngpio) - return 0; + if (gpio_pin >= chip->ngpio) + return -EINVAL; - return -EINVAL; + if (chip->bgpio_pinctrl) + return gpiochip_generic_request(chip, gpio_pin); + + return 0; } /** @@ -632,6 +647,12 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev, if (ret) return ret; + if (flags & BGPIOF_PINCTRL_BACKEND) { + gc->bgpio_pinctrl = true; + /* Currently this callback is only used for pincontrol */ + gc->free = gpiochip_generic_free; + } + gc->bgpio_data = gc->read_reg(gc->reg_dat); if (gc->set == bgpio_set_set && !(flags & BGPIOF_UNREADABLE_REG_SET)) diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index d39c6618bade..266c0953d914 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -122,7 +122,7 @@ static void __gpio_mockup_set(struct gpio_mockup_chip *chip, chip->lines[offset].value = !!value; } -static void gpio_mockup_set(struct gpio_chip *gc, +static int gpio_mockup_set(struct gpio_chip *gc, unsigned int offset, int value) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); @@ -130,10 +130,12 @@ static void gpio_mockup_set(struct gpio_chip *gc, guard(mutex)(&chip->lock); __gpio_mockup_set(chip, offset, value); + + return 0; } -static void gpio_mockup_set_multiple(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits) +static int gpio_mockup_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); unsigned int bit; @@ -142,6 +144,8 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc, for_each_set_bit(bit, mask, gc->ngpio) __gpio_mockup_set(chip, bit, test_bit(bit, bits)); + + return 0; } static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip, @@ -445,9 +449,9 @@ static int gpio_mockup_probe(struct platform_device *pdev) gc->owner = THIS_MODULE; gc->parent = dev; gc->get = gpio_mockup_get; - gc->set = gpio_mockup_set; + gc->set_rv = gpio_mockup_set; gc->get_multiple = gpio_mockup_get_multiple; - gc->set_multiple = gpio_mockup_set_multiple; + gc->set_multiple_rv = gpio_mockup_set_multiple; gc->direction_output = gpio_mockup_dirout; gc->direction_input = gpio_mockup_dirin; gc->get_direction = gpio_mockup_get_direction; diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 5ffb332e9849..3604abcb6fec 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -49,6 +49,7 @@ #include <linux/pwm.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/string_choices.h> /* * GPIO unit register offsets. @@ -297,12 +298,12 @@ static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) /* * Functions implementing the gpio_chip methods */ -static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) +static int mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); - regmap_update_bits(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, - BIT(pin), value ? BIT(pin) : 0); + return regmap_update_bits(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, + BIT(pin), value ? BIT(pin) : 0); } static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin) @@ -907,14 +908,14 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) if (is_out) { seq_printf(s, " out %s %s\n", - out & msk ? "hi" : "lo", + str_hi_lo(out & msk), blink & msk ? "(blink )" : ""); continue; } seq_printf(s, " in %s (act %s) - IRQ", - (data_in ^ in_pol) & msk ? "hi" : "lo", - in_pol & msk ? "lo" : "hi"); + str_hi_lo((data_in ^ in_pol) & msk), + str_lo_hi(in_pol & msk)); if (!((edg_msk | lvl_msk) & msk)) { seq_puts(s, " disabled\n"); continue; @@ -1172,7 +1173,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.direction_input = mvebu_gpio_direction_input; mvchip->chip.get = mvebu_gpio_get; mvchip->chip.direction_output = mvebu_gpio_direction_output; - mvchip->chip.set = mvebu_gpio_set; + mvchip->chip.set_rv = mvebu_gpio_set; if (have_irqs) mvchip->chip.to_irq = mvebu_gpio_to_irq; mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK; diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/gpio/gpio-nomadik.c index 836f1cc760c2..fa19a44943fd 100644 --- a/drivers/gpio/gpio-nomadik.c +++ b/drivers/gpio/gpio-nomadik.c @@ -30,6 +30,7 @@ #include <linux/reset.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/string_choices.h> #include <linux/types.h> #include <linux/gpio/gpio-nomadik.h> @@ -430,7 +431,7 @@ void nmk_gpio_dbg_show_one(struct seq_file *s, struct pinctrl_dev *pctldev, seq_printf(s, " gpio-%-3d (%-20.20s) out %s %s", gpio, label ?: "(none)", - data_out ? "hi" : "lo", + str_hi_lo(data_out), (mode < 0) ? "unknown" : modes[mode]); } else { int irq = chip->to_irq(chip, offset); diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index d63c1030e6ac..442435ded020 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -570,7 +570,8 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) return !!(reg_val & bit); } -static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +static int pca953x_gpio_set_value(struct gpio_chip *gc, unsigned int off, + int val) { struct pca953x_chip *chip = gpiochip_get_data(gc); u8 outreg = chip->recalc_addr(chip, chip->regs->output, off); @@ -578,7 +579,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) guard(mutex)(&chip->i2c_lock); - regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0); + return regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0); } static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) @@ -616,8 +617,8 @@ static int pca953x_gpio_get_multiple(struct gpio_chip *gc, return 0; } -static void pca953x_gpio_set_multiple(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits) +static int pca953x_gpio_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) { struct pca953x_chip *chip = gpiochip_get_data(gc); DECLARE_BITMAP(reg_val, MAX_LINE); @@ -627,11 +628,11 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc, ret = pca953x_read_regs(chip, chip->regs->output, reg_val); if (ret) - return; + return ret; bitmap_replace(reg_val, reg_val, bits, mask, gc->ngpio); - pca953x_write_regs(chip, chip->regs->output, reg_val); + return pca953x_write_regs(chip, chip->regs->output, reg_val); } static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, @@ -693,10 +694,10 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->direction_input = pca953x_gpio_direction_input; gc->direction_output = pca953x_gpio_direction_output; gc->get = pca953x_gpio_get_value; - gc->set = pca953x_gpio_set_value; + gc->set_rv = pca953x_gpio_set_value; gc->get_direction = pca953x_gpio_get_direction; gc->get_multiple = pca953x_gpio_get_multiple; - gc->set_multiple = pca953x_gpio_set_multiple; + gc->set_multiple_rv = pca953x_gpio_set_multiple; gc->set_config = pca953x_gpio_set_config; gc->can_sleep = true; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 7c57eaeb0afe..2e5f5d7f8865 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -5,6 +5,8 @@ * Copyright (C) 2007 David Brownell */ +#include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -272,12 +274,11 @@ static const struct irq_chip pcf857x_irq_chip = { static int pcf857x_probe(struct i2c_client *client) { + struct gpio_desc *reset_gpio; struct pcf857x *gpio; unsigned int n_latch = 0; int status; - device_property_read_u32(&client->dev, "lines-initial-states", &n_latch); - /* Allocate, initialize, and register this gpio_chip. */ gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); if (!gpio) @@ -297,6 +298,30 @@ static int pcf857x_probe(struct i2c_client *client) gpio->chip.direction_output = pcf857x_output; gpio->chip.ngpio = (uintptr_t)i2c_get_match_data(client); + reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(reset_gpio), + "failed to get reset GPIO\n"); + + if (reset_gpio) { + /* Reset already held with devm_gpiod_get_optional with GPIOD_OUT_HIGH */ + fsleep(4); /* tw(rst) > 4us */ + gpiod_set_value_cansleep(reset_gpio, 0); + fsleep(100); /* trst > 100uS */ + + /* + * Performing a reset means "The PCA9670 registers and I2C-bus + * state machine will be held in their default state until the + * RESET input is once again HIGH". + * + * This is the same as writing 1 for all pins, which is the same + * as n_latch=0, the default value of the variable. + */ + } else { + device_property_read_u32(&client->dev, "lines-initial-states", + &n_latch); + } + /* NOTE: the OnSemi jlc1562b is also largely compatible with * these parts, notably for output. It has a low-resolution * DAC instead of pin change IRQs; and its inputs can be the diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index a7a1cdf7ac66..18c965ee02c8 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -336,9 +336,6 @@ static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long flags; bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0); - if (chip->valid_mask) - bankmask &= chip->valid_mask[0]; - if (!bankmask) return 0; @@ -380,9 +377,6 @@ static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask, u32 val, bankmask; bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0); - if (chip->valid_mask) - bankmask &= chip->valid_mask[0]; - if (!bankmask) return; @@ -487,10 +481,13 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins) static void gpio_rcar_enable_inputs(struct gpio_rcar_priv *p) { u32 mask = GENMASK(p->gpio_chip.ngpio - 1, 0); + const unsigned long *valid_mask; + + valid_mask = gpiochip_query_valid_mask(&p->gpio_chip); /* Select "Input Enable" in INEN */ - if (p->gpio_chip.valid_mask) - mask &= p->gpio_chip.valid_mask[0]; + if (valid_mask) + mask &= valid_mask[0]; if (mask) gpio_rcar_write(p, INEN, gpio_rcar_read(p, INEN) | mask); } diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 05f8781b5204..87c4225784cf 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -17,6 +17,8 @@ #include <linux/gpio/driver.h> #include <linux/gpio/regmap.h> +#include "gpiolib.h" + struct gpio_regmap { struct device *parent; struct regmap *regmap; @@ -81,33 +83,43 @@ static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset) return !!(val & mask); } -static void gpio_regmap_set(struct gpio_chip *chip, unsigned int offset, - int val) +static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset, + int val) { struct gpio_regmap *gpio = gpiochip_get_data(chip); unsigned int base = gpio_regmap_addr(gpio->reg_set_base); unsigned int reg, mask; + int ret; + + ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + return ret; - gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); if (val) - regmap_update_bits(gpio->regmap, reg, mask, mask); + ret = regmap_update_bits(gpio->regmap, reg, mask, mask); else - regmap_update_bits(gpio->regmap, reg, mask, 0); + ret = regmap_update_bits(gpio->regmap, reg, mask, 0); + + return ret; } -static void gpio_regmap_set_with_clear(struct gpio_chip *chip, - unsigned int offset, int val) +static int gpio_regmap_set_with_clear(struct gpio_chip *chip, + unsigned int offset, int val) { struct gpio_regmap *gpio = gpiochip_get_data(chip); unsigned int base, reg, mask; + int ret; if (val) base = gpio_regmap_addr(gpio->reg_set_base); else base = gpio_regmap_addr(gpio->reg_clr_base); - gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); - regmap_write(gpio->regmap, reg, mask); + ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + return ret; + + return regmap_write(gpio->regmap, reg, mask); } static int gpio_regmap_get_direction(struct gpio_chip *chip, @@ -210,9 +222,6 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config if (!config->parent) return ERR_PTR(-EINVAL); - if (!config->ngpio) - return ERR_PTR(-EINVAL); - /* we need at least one */ if (!config->reg_dat_base && !config->reg_set_base) return ERR_PTR(-EINVAL); @@ -233,31 +242,16 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config gpio->parent = config->parent; gpio->driver_data = config->drvdata; gpio->regmap = config->regmap; - gpio->ngpio_per_reg = config->ngpio_per_reg; - gpio->reg_stride = config->reg_stride; - gpio->reg_mask_xlate = config->reg_mask_xlate; gpio->reg_dat_base = config->reg_dat_base; gpio->reg_set_base = config->reg_set_base; gpio->reg_clr_base = config->reg_clr_base; gpio->reg_dir_in_base = config->reg_dir_in_base; gpio->reg_dir_out_base = config->reg_dir_out_base; - /* if not set, assume there is only one register */ - if (!gpio->ngpio_per_reg) - gpio->ngpio_per_reg = config->ngpio; - - /* if not set, assume they are consecutive */ - if (!gpio->reg_stride) - gpio->reg_stride = 1; - - if (!gpio->reg_mask_xlate) - gpio->reg_mask_xlate = gpio_regmap_simple_xlate; - chip = &gpio->gpio_chip; chip->parent = config->parent; chip->fwnode = config->fwnode; chip->base = -1; - chip->ngpio = config->ngpio; chip->names = config->names; chip->label = config->label ?: dev_name(config->parent); chip->can_sleep = regmap_might_sleep(config->regmap); @@ -266,9 +260,9 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config chip->free = gpiochip_generic_free; chip->get = gpio_regmap_get; if (gpio->reg_set_base && gpio->reg_clr_base) - chip->set = gpio_regmap_set_with_clear; + chip->set_rv = gpio_regmap_set_with_clear; else if (gpio->reg_set_base) - chip->set = gpio_regmap_set; + chip->set_rv = gpio_regmap_set; chip->get_direction = gpio_regmap_get_direction; if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) { @@ -276,6 +270,27 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config chip->direction_output = gpio_regmap_direction_output; } + chip->ngpio = config->ngpio; + if (!chip->ngpio) { + ret = gpiochip_get_ngpios(chip, chip->parent); + if (ret) + return ERR_PTR(ret); + } + + /* if not set, assume there is only one register */ + gpio->ngpio_per_reg = config->ngpio_per_reg; + if (!gpio->ngpio_per_reg) + gpio->ngpio_per_reg = config->ngpio; + + /* if not set, assume they are consecutive */ + gpio->reg_stride = config->reg_stride; + if (!gpio->reg_stride) + gpio->reg_stride = 1; + + gpio->reg_mask_xlate = config->reg_mask_xlate; + if (!gpio->reg_mask_xlate) + gpio->reg_mask_xlate = gpio_regmap_simple_xlate; + ret = gpiochip_add_data(chip, gpio); if (ret < 0) goto err_free_gpio; diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index b6c230fab840..f638219a7c4f 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -10,7 +10,6 @@ #include <linux/array_size.h> #include <linux/bitmap.h> #include <linux/cleanup.h> -#include <linux/completion.h> #include <linux/configfs.h> #include <linux/device.h> #include <linux/err.h> @@ -37,6 +36,8 @@ #include <linux/sysfs.h> #include <linux/types.h> +#include "dev-sync-probe.h" + #define GPIO_SIM_NGPIO_MAX 1024 #define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */ #define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */ @@ -119,12 +120,14 @@ static int gpio_sim_get(struct gpio_chip *gc, unsigned int offset) return !!test_bit(offset, chip->value_map); } -static void gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value) +static int gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value) { struct gpio_sim_chip *chip = gpiochip_get_data(gc); scoped_guard(mutex, &chip->lock) __assign_bit(offset, chip->value_map, value); + + return 0; } static int gpio_sim_get_multiple(struct gpio_chip *gc, @@ -138,14 +141,16 @@ static int gpio_sim_get_multiple(struct gpio_chip *gc, return 0; } -static void gpio_sim_set_multiple(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits) +static int gpio_sim_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) { struct gpio_sim_chip *chip = gpiochip_get_data(gc); scoped_guard(mutex, &chip->lock) bitmap_replace(chip->value_map, chip->value_map, bits, mask, gc->ngpio); + + return 0; } static int gpio_sim_direction_output(struct gpio_chip *gc, @@ -481,9 +486,9 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) gc->parent = dev; gc->fwnode = swnode; gc->get = gpio_sim_get; - gc->set = gpio_sim_set; + gc->set_rv = gpio_sim_set; gc->get_multiple = gpio_sim_get_multiple; - gc->set_multiple = gpio_sim_set_multiple; + gc->set_multiple_rv = gpio_sim_set_multiple; gc->direction_output = gpio_sim_direction_output; gc->direction_input = gpio_sim_direction_input; gc->get_direction = gpio_sim_get_direction; @@ -541,14 +546,9 @@ static struct platform_driver gpio_sim_driver = { }; struct gpio_sim_device { + struct dev_sync_probe_data probe_data; struct config_group group; - /* - * If pdev is NULL, the device is 'pending' (waiting for configuration). - * Once the pointer is assigned, the device has been created and the - * item is 'live'. - */ - struct platform_device *pdev; int id; /* @@ -562,46 +562,11 @@ struct gpio_sim_device { */ struct mutex lock; - /* - * This is used to synchronously wait for the driver's probe to complete - * and notify the user-space about any errors. - */ - struct notifier_block bus_notifier; - struct completion probe_completion; - bool driver_bound; - struct gpiod_hog *hogs; struct list_head bank_list; }; -/* This is called with dev->lock already taken. */ -static int gpio_sim_bus_notifier_call(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct gpio_sim_device *simdev = container_of(nb, - struct gpio_sim_device, - bus_notifier); - struct device *dev = data; - char devname[32]; - - snprintf(devname, sizeof(devname), "gpio-sim.%u", simdev->id); - - if (!device_match_name(dev, devname)) - return NOTIFY_DONE; - - if (action == BUS_NOTIFY_BOUND_DRIVER) - simdev->driver_bound = true; - else if (action == BUS_NOTIFY_DRIVER_NOT_BOUND) - simdev->driver_bound = false; - else - return NOTIFY_DONE; - - complete(&simdev->probe_completion); - - return NOTIFY_OK; -} - static struct gpio_sim_device *to_gpio_sim_device(struct config_item *item) { struct config_group *group = to_config_group(item); @@ -708,7 +673,7 @@ static bool gpio_sim_device_is_live(struct gpio_sim_device *dev) { lockdep_assert_held(&dev->lock); - return !!dev->pdev; + return !!dev->probe_data.pdev; } static char *gpio_sim_strdup_trimmed(const char *str, size_t count) @@ -730,7 +695,7 @@ static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item, guard(mutex)(&dev->lock); - pdev = dev->pdev; + pdev = dev->probe_data.pdev; if (pdev) return sprintf(page, "%s\n", dev_name(&pdev->dev)); @@ -939,7 +904,6 @@ static int gpio_sim_device_activate(struct gpio_sim_device *dev) { struct platform_device_info pdevinfo; struct fwnode_handle *swnode; - struct platform_device *pdev; struct gpio_sim_bank *bank; int ret; @@ -981,31 +945,13 @@ static int gpio_sim_device_activate(struct gpio_sim_device *dev) pdevinfo.fwnode = swnode; pdevinfo.id = dev->id; - reinit_completion(&dev->probe_completion); - dev->driver_bound = false; - bus_register_notifier(&platform_bus_type, &dev->bus_notifier); - - pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(pdev)) { - bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); - gpio_sim_remove_hogs(dev); - gpio_sim_remove_swnode_recursive(swnode); - return PTR_ERR(pdev); - } - - wait_for_completion(&dev->probe_completion); - bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); - - if (!dev->driver_bound) { - /* Probe failed, check kernel log. */ - platform_device_unregister(pdev); + ret = dev_sync_probe_register(&dev->probe_data, &pdevinfo); + if (ret) { gpio_sim_remove_hogs(dev); gpio_sim_remove_swnode_recursive(swnode); - return -ENXIO; + return ret; } - dev->pdev = pdev; - return 0; } @@ -1015,11 +961,10 @@ static void gpio_sim_device_deactivate(struct gpio_sim_device *dev) lockdep_assert_held(&dev->lock); - swnode = dev_fwnode(&dev->pdev->dev); - platform_device_unregister(dev->pdev); + swnode = dev_fwnode(&dev->probe_data.pdev->dev); + dev_sync_probe_unregister(&dev->probe_data); gpio_sim_remove_hogs(dev); gpio_sim_remove_swnode_recursive(swnode); - dev->pdev = NULL; } static void @@ -1120,7 +1065,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item, guard(mutex)(&dev->lock); if (gpio_sim_device_is_live(dev)) - return device_for_each_child(&dev->pdev->dev, &ctx, + return device_for_each_child(&dev->probe_data.pdev->dev, &ctx, gpio_sim_emit_chip_name); return sprintf(page, "none\n"); @@ -1561,8 +1506,7 @@ gpio_sim_config_make_device_group(struct config_group *group, const char *name) mutex_init(&dev->lock); INIT_LIST_HEAD(&dev->bank_list); - dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call; - init_completion(&dev->probe_completion); + dev_sync_probe_init(&dev->probe_data); return &no_free_ptr(dev)->group; } diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 222279a9d82b..dce8ff322e47 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/string_choices.h> /* * These registers are modified under the irq bus lock and cached to avoid @@ -282,8 +283,7 @@ static void stmpe_dbg_show_one(struct seq_file *s, if (dir) { seq_printf(s, " gpio-%-3d (%-20.20s) out %s", - gpio, label ?: "(none)", - val ? "hi" : "lo"); + gpio, label ?: "(none)", str_hi_lo(val)); } else { u8 edge_det_reg; u8 rise_reg; @@ -352,7 +352,7 @@ static void stmpe_dbg_show_one(struct seq_file *s, seq_printf(s, " gpio-%-3d (%-20.20s) in %s %13s %13s %25s %25s", gpio, label ?: "(none)", - val ? "hi" : "lo", + str_hi_lo(val), edge_det_values[edge_det], irqen ? "IRQ-enabled" : "IRQ-disabled", rise_values[rise], diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index c36a9dbccd4d..4dad7ce0c4dc 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -36,7 +36,6 @@ struct vf610_gpio_port { struct clk *clk_port; struct clk *clk_gpio; int irq; - spinlock_t lock; /* protect gpio direction registers */ }; #define GPIO_PDOR 0x00 @@ -94,78 +93,6 @@ static inline u32 vf610_gpio_readl(void __iomem *reg) return readl_relaxed(reg); } -static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio) -{ - struct vf610_gpio_port *port = gpiochip_get_data(gc); - u32 mask = BIT(gpio); - unsigned long offset = GPIO_PDIR; - - if (port->sdata->have_paddr) { - mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR); - if (mask) - offset = GPIO_PDOR; - } - - return !!(vf610_gpio_readl(port->gpio_base + offset) & BIT(gpio)); -} - -static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct vf610_gpio_port *port = gpiochip_get_data(gc); - u32 mask = BIT(gpio); - unsigned long offset = val ? GPIO_PSOR : GPIO_PCOR; - - vf610_gpio_writel(mask, port->gpio_base + offset); -} - -static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) -{ - struct vf610_gpio_port *port = gpiochip_get_data(chip); - u32 mask = BIT(gpio); - u32 val; - - if (port->sdata->have_paddr) { - guard(spinlock_irqsave)(&port->lock); - val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR); - val &= ~mask; - vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR); - } - - return pinctrl_gpio_direction_input(chip, gpio); -} - -static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, - int value) -{ - struct vf610_gpio_port *port = gpiochip_get_data(chip); - u32 mask = BIT(gpio); - u32 val; - - vf610_gpio_set(chip, gpio, value); - - if (port->sdata->have_paddr) { - guard(spinlock_irqsave)(&port->lock); - val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR); - val |= mask; - vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR); - } - - return pinctrl_gpio_direction_output(chip, gpio); -} - -static int vf610_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) -{ - struct vf610_gpio_port *port = gpiochip_get_data(gc); - u32 mask = BIT(gpio); - - mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR); - - if (mask) - return GPIO_LINE_DIRECTION_OUT; - - return GPIO_LINE_DIRECTION_IN; -} - static void vf610_gpio_irq_handler(struct irq_desc *desc) { struct vf610_gpio_port *port = @@ -291,6 +218,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) struct vf610_gpio_port *port; struct gpio_chip *gc; struct gpio_irq_chip *girq; + unsigned long flags; int i; int ret; bool dual_base; @@ -300,7 +228,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) return -ENOMEM; port->sdata = device_get_match_data(dev); - spin_lock_init(&port->lock); dual_base = port->sdata->have_dual_base; @@ -367,23 +294,25 @@ static int vf610_gpio_probe(struct platform_device *pdev) } gc = &port->gc; - gc->parent = dev; - gc->label = dev_name(dev); - gc->ngpio = VF610_GPIO_PER_PORT; - gc->base = -1; - - gc->request = gpiochip_generic_request; - gc->free = gpiochip_generic_free; - gc->direction_input = vf610_gpio_direction_input; - gc->get = vf610_gpio_get; - gc->direction_output = vf610_gpio_direction_output; - gc->set = vf610_gpio_set; + flags = BGPIOF_PINCTRL_BACKEND; /* - * only IP has Port Data Direction Register(PDDR) can - * support get direction + * We only read the output register for current value on output + * lines if the direction register is available so we can switch + * direction. */ if (port->sdata->have_paddr) - gc->get_direction = vf610_gpio_get_direction; + flags |= BGPIOF_READ_OUTPUT_REG_SET; + ret = bgpio_init(gc, dev, 4, + port->gpio_base + GPIO_PDIR, + port->gpio_base + GPIO_PDOR, + NULL, + port->sdata->have_paddr ? port->gpio_base + GPIO_PDDR : NULL, + NULL, + flags); + if (ret) + return dev_err_probe(dev, ret, "unable to init generic GPIO\n"); + gc->label = dev_name(dev); + gc->base = -1; /* Mask all GPIO interrupts */ for (i = 0; i < gc->ngpio; i++) diff --git a/drivers/gpio/gpio-virtio.c b/drivers/gpio/gpio-virtio.c index 93544ff62513..ac39da17a29b 100644 --- a/drivers/gpio/gpio-virtio.c +++ b/drivers/gpio/gpio-virtio.c @@ -350,19 +350,6 @@ static void virtio_gpio_irq_bus_sync_unlock(struct irq_data *d) mutex_unlock(&vgpio->irq_lock); } -static struct irq_chip vgpio_irq_chip = { - .name = "virtio-gpio", - .irq_enable = virtio_gpio_irq_enable, - .irq_disable = virtio_gpio_irq_disable, - .irq_mask = virtio_gpio_irq_mask, - .irq_unmask = virtio_gpio_irq_unmask, - .irq_set_type = virtio_gpio_irq_set_type, - - /* These are required to implement irqchip for slow busses */ - .irq_bus_lock = virtio_gpio_irq_bus_lock, - .irq_bus_sync_unlock = virtio_gpio_irq_bus_sync_unlock, -}; - static bool ignore_irq(struct virtio_gpio *vgpio, int gpio, struct vgpio_irq_line *irq_line) { @@ -542,6 +529,7 @@ static int virtio_gpio_probe(struct virtio_device *vdev) struct virtio_gpio_config config; struct device *dev = &vdev->dev; struct virtio_gpio *vgpio; + struct irq_chip *gpio_irq_chip; u32 gpio_names_size; u16 ngpio; int ret, i; @@ -591,13 +579,26 @@ static int virtio_gpio_probe(struct virtio_device *vdev) if (!vgpio->irq_lines) return -ENOMEM; + gpio_irq_chip = devm_kzalloc(dev, sizeof(*gpio_irq_chip), GFP_KERNEL); + if (!gpio_irq_chip) + return -ENOMEM; + + gpio_irq_chip->name = dev_name(dev); + gpio_irq_chip->irq_enable = virtio_gpio_irq_enable; + gpio_irq_chip->irq_disable = virtio_gpio_irq_disable; + gpio_irq_chip->irq_mask = virtio_gpio_irq_mask; + gpio_irq_chip->irq_unmask = virtio_gpio_irq_unmask; + gpio_irq_chip->irq_set_type = virtio_gpio_irq_set_type; + gpio_irq_chip->irq_bus_lock = virtio_gpio_irq_bus_lock; + gpio_irq_chip->irq_bus_sync_unlock = virtio_gpio_irq_bus_sync_unlock; + /* The event comes from the outside so no parent handler */ vgpio->gc.irq.parent_handler = NULL; vgpio->gc.irq.num_parents = 0; vgpio->gc.irq.parents = NULL; vgpio->gc.irq.default_type = IRQ_TYPE_NONE; vgpio->gc.irq.handler = handle_level_irq; - vgpio->gc.irq.chip = &vgpio_irq_chip; + vgpio->gc.irq.chip = gpio_irq_chip; for (i = 0; i < ngpio; i++) { vgpio->irq_lines[i].type = VIRTIO_GPIO_IRQ_TYPE_NONE; diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c index e89f299f2140..13407fd4f0eb 100644 --- a/drivers/gpio/gpio-virtuser.c +++ b/drivers/gpio/gpio-virtuser.c @@ -11,7 +11,6 @@ #include <linux/atomic.h> #include <linux/bitmap.h> #include <linux/cleanup.h> -#include <linux/completion.h> #include <linux/configfs.h> #include <linux/debugfs.h> #include <linux/device.h> @@ -37,6 +36,8 @@ #include <linux/string_helpers.h> #include <linux/types.h> +#include "dev-sync-probe.h" + #define GPIO_VIRTUSER_NAME_BUF_LEN 32 static DEFINE_IDA(gpio_virtuser_ida); @@ -973,49 +974,17 @@ static struct platform_driver gpio_virtuser_driver = { }; struct gpio_virtuser_device { + struct dev_sync_probe_data probe_data; struct config_group group; - struct platform_device *pdev; int id; struct mutex lock; - struct notifier_block bus_notifier; - struct completion probe_completion; - bool driver_bound; - struct gpiod_lookup_table *lookup_table; struct list_head lookup_list; }; -static int gpio_virtuser_bus_notifier_call(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct gpio_virtuser_device *vdev; - struct device *dev = data; - char devname[32]; - - vdev = container_of(nb, struct gpio_virtuser_device, bus_notifier); - snprintf(devname, sizeof(devname), "gpio-virtuser.%d", vdev->id); - - if (!device_match_name(dev, devname)) - return NOTIFY_DONE; - - switch (action) { - case BUS_NOTIFY_BOUND_DRIVER: - vdev->driver_bound = true; - break; - case BUS_NOTIFY_DRIVER_NOT_BOUND: - vdev->driver_bound = false; - break; - default: - return NOTIFY_DONE; - } - - complete(&vdev->probe_completion); - return NOTIFY_OK; -} - static struct gpio_virtuser_device * to_gpio_virtuser_device(struct config_item *item) { @@ -1029,7 +998,7 @@ gpio_virtuser_device_is_live(struct gpio_virtuser_device *dev) { lockdep_assert_held(&dev->lock); - return !!dev->pdev; + return !!dev->probe_data.pdev; } struct gpio_virtuser_lookup { @@ -1369,7 +1338,7 @@ gpio_virtuser_device_config_dev_name_show(struct config_item *item, guard(mutex)(&dev->lock); - pdev = dev->pdev; + pdev = dev->probe_data.pdev; if (pdev) return sprintf(page, "%s\n", dev_name(&pdev->dev)); @@ -1478,7 +1447,6 @@ gpio_virtuser_device_activate(struct gpio_virtuser_device *dev) { struct platform_device_info pdevinfo; struct fwnode_handle *swnode; - struct platform_device *pdev; int ret; lockdep_assert_held(&dev->lock); @@ -1499,31 +1467,12 @@ gpio_virtuser_device_activate(struct gpio_virtuser_device *dev) if (ret) goto err_remove_swnode; - reinit_completion(&dev->probe_completion); - dev->driver_bound = false; - bus_register_notifier(&platform_bus_type, &dev->bus_notifier); - - pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(pdev)) { - ret = PTR_ERR(pdev); - bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); + ret = dev_sync_probe_register(&dev->probe_data, &pdevinfo); + if (ret) goto err_remove_lookup_table; - } - - wait_for_completion(&dev->probe_completion); - bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); - - if (!dev->driver_bound) { - ret = -ENXIO; - goto err_unregister_pdev; - } - - dev->pdev = pdev; return 0; -err_unregister_pdev: - platform_device_unregister(pdev); err_remove_lookup_table: gpio_virtuser_remove_lookup_table(dev); err_remove_swnode: @@ -1539,11 +1488,10 @@ gpio_virtuser_device_deactivate(struct gpio_virtuser_device *dev) lockdep_assert_held(&dev->lock); - swnode = dev_fwnode(&dev->pdev->dev); - platform_device_unregister(dev->pdev); + swnode = dev_fwnode(&dev->probe_data.pdev->dev); + dev_sync_probe_unregister(&dev->probe_data); gpio_virtuser_remove_lookup_table(dev); fwnode_remove_software_node(swnode); - dev->pdev = NULL; } static void @@ -1772,8 +1720,7 @@ gpio_virtuser_config_make_device_group(struct config_group *group, &gpio_virtuser_device_config_group_type); mutex_init(&dev->lock); INIT_LIST_HEAD(&dev->lookup_list); - dev->bus_notifier.notifier_call = gpio_virtuser_bus_notifier_call; - init_completion(&dev->probe_completion); + dev_sync_probe_init(&dev->probe_data); return &no_free_ptr(dev)->group; } diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 94ca9d03c094..1ec24f6f9300 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/seq_file.h> +#include <linux/string_choices.h> /* * Whiskey Cove PMIC has 13 physical GPIO pins divided into 3 banks: @@ -393,7 +394,7 @@ static void wcove_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_printf(s, " gpio-%-2d %s %s %s %s ctlo=%2x,%s %s\n", gpio, ctlo & CTLO_DIR_OUT ? "out" : "in ", - ctli & 0x1 ? "hi" : "lo", + str_hi_lo(ctli & 0x1), ctli & CTLI_INTCNT_NE ? "fall" : " ", ctli & CTLI_INTCNT_PE ? "rise" : " ", ctlo, diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index f7d5120ff8f1..61bb83a1e8ae 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -16,6 +16,7 @@ #include <linux/mfd/core.h> #include <linux/platform_device.h> #include <linux/seq_file.h> +#include <linux/string_choices.h> #include <linux/mfd/wm831x/core.h> #include <linux/mfd/wm831x/pdata.h> @@ -234,7 +235,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_printf(s, " %s %s %s %s%s\n" " %s%s (0x%4x)\n", reg & WM831X_GPN_DIR ? "in" : "out", - wm831x_gpio_get(chip, i) ? "high" : "low", + str_high_low(wm831x_gpio_get(chip, i)), pull, powerdomain, reg & WM831X_GPN_POL ? "" : " inverted", diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 792d94c49077..c58a7e1349b4 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -45,8 +45,7 @@ * struct xgpio_instance - Stores information about GPIO device * @gc: GPIO chip * @regs: register block - * @hw_map: GPIO pin mapping on hardware side - * @sw_map: GPIO pin mapping on software side + * @map: GPIO pin mapping on hardware side * @state: GPIO write state shadow register * @last_irq_read: GPIO read state register from last interrupt * @dir: GPIO direction shadow register @@ -60,8 +59,7 @@ struct xgpio_instance { struct gpio_chip gc; void __iomem *regs; - DECLARE_BITMAP(hw_map, 64); - DECLARE_BITMAP(sw_map, 64); + DECLARE_BITMAP(map, 64); DECLARE_BITMAP(state, 64); DECLARE_BITMAP(last_irq_read, 64); DECLARE_BITMAP(dir, 64); @@ -73,33 +71,6 @@ struct xgpio_instance { struct clk *clk; }; -static inline int xgpio_from_bit(struct xgpio_instance *chip, int bit) -{ - return bitmap_bitremap(bit, chip->hw_map, chip->sw_map, 64); -} - -static inline int xgpio_to_bit(struct xgpio_instance *chip, int gpio) -{ - return bitmap_bitremap(gpio, chip->sw_map, chip->hw_map, 64); -} - -static inline u32 xgpio_get_value32(const unsigned long *map, int bit) -{ - const size_t index = BIT_WORD(bit); - const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5); - - return (map[index] >> offset) & 0xFFFFFFFFul; -} - -static inline void xgpio_set_value32(unsigned long *map, int bit, u32 v) -{ - const size_t index = BIT_WORD(bit); - const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5); - - map[index] &= ~(0xFFFFFFFFul << offset); - map[index] |= (unsigned long)v << offset; -} - static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch) { switch (ch) { @@ -115,20 +86,23 @@ static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch) static void xgpio_read_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a) { void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32); + unsigned long value = xgpio_readreg(addr); - xgpio_set_value32(a, bit, xgpio_readreg(addr)); + bitmap_write(a, value, round_down(bit, 32), 32); } static void xgpio_write_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a) { void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32); + unsigned long value = bitmap_read(a, round_down(bit, 32), 32); - xgpio_writereg(addr, xgpio_get_value32(a, bit)); + xgpio_writereg(addr, value); } static void xgpio_read_ch_all(struct xgpio_instance *chip, int reg, unsigned long *a) { - int bit, lastbit = xgpio_to_bit(chip, chip->gc.ngpio - 1); + unsigned long lastbit = find_nth_bit(chip->map, 64, chip->gc.ngpio - 1); + int bit; for (bit = 0; bit <= lastbit ; bit += 32) xgpio_read_ch(chip, reg, bit, a); @@ -136,7 +110,8 @@ static void xgpio_read_ch_all(struct xgpio_instance *chip, int reg, unsigned lon static void xgpio_write_ch_all(struct xgpio_instance *chip, int reg, unsigned long *a) { - int bit, lastbit = xgpio_to_bit(chip, chip->gc.ngpio - 1); + unsigned long lastbit = find_nth_bit(chip->map, 64, chip->gc.ngpio - 1); + int bit; for (bit = 0; bit <= lastbit ; bit += 32) xgpio_write_ch(chip, reg, bit, a); @@ -156,7 +131,7 @@ static void xgpio_write_ch_all(struct xgpio_instance *chip, int reg, unsigned lo static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct xgpio_instance *chip = gpiochip_get_data(gc); - int bit = xgpio_to_bit(chip, gpio); + unsigned long bit = find_nth_bit(chip->map, 64, gpio); DECLARE_BITMAP(state, 64); xgpio_read_ch(chip, XGPIO_DATA_OFFSET, bit, state); @@ -177,7 +152,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; struct xgpio_instance *chip = gpiochip_get_data(gc); - int bit = xgpio_to_bit(chip, gpio); + unsigned long bit = find_nth_bit(chip->map, 64, gpio); raw_spin_lock_irqsave(&chip->gpio_lock, flags); @@ -207,8 +182,8 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long flags; struct xgpio_instance *chip = gpiochip_get_data(gc); - bitmap_remap(hw_mask, mask, chip->sw_map, chip->hw_map, 64); - bitmap_remap(hw_bits, bits, chip->sw_map, chip->hw_map, 64); + bitmap_scatter(hw_mask, mask, chip->map, 64); + bitmap_scatter(hw_bits, bits, chip->map, 64); raw_spin_lock_irqsave(&chip->gpio_lock, flags); @@ -234,7 +209,7 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { unsigned long flags; struct xgpio_instance *chip = gpiochip_get_data(gc); - int bit = xgpio_to_bit(chip, gpio); + unsigned long bit = find_nth_bit(chip->map, 64, gpio); raw_spin_lock_irqsave(&chip->gpio_lock, flags); @@ -263,7 +238,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; struct xgpio_instance *chip = gpiochip_get_data(gc); - int bit = xgpio_to_bit(chip, gpio); + unsigned long bit = find_nth_bit(chip->map, 64, gpio); raw_spin_lock_irqsave(&chip->gpio_lock, flags); @@ -395,14 +370,15 @@ static void xgpio_irq_mask(struct irq_data *irq_data) unsigned long flags; struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); int irq_offset = irqd_to_hwirq(irq_data); - int bit = xgpio_to_bit(chip, irq_offset); + unsigned long bit = find_nth_bit(chip->map, 64, irq_offset), enable; u32 mask = BIT(bit / 32), temp; raw_spin_lock_irqsave(&chip->gpio_lock, flags); __clear_bit(bit, chip->enable); - if (xgpio_get_value32(chip->enable, bit) == 0) { + enable = bitmap_read(chip->enable, round_down(bit, 32), 32); + if (enable == 0) { /* Disable per channel interrupt */ temp = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET); temp &= ~mask; @@ -422,17 +398,15 @@ static void xgpio_irq_unmask(struct irq_data *irq_data) unsigned long flags; struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); int irq_offset = irqd_to_hwirq(irq_data); - int bit = xgpio_to_bit(chip, irq_offset); - u32 old_enable = xgpio_get_value32(chip->enable, bit); + unsigned long bit = find_nth_bit(chip->map, 64, irq_offset), enable; u32 mask = BIT(bit / 32), val; gpiochip_enable_irq(&chip->gc, irq_offset); raw_spin_lock_irqsave(&chip->gpio_lock, flags); - __set_bit(bit, chip->enable); - - if (old_enable == 0) { + enable = bitmap_read(chip->enable, round_down(bit, 32), 32); + if (enable == 0) { /* Clear any existing per-channel interrupts */ val = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); val &= mask; @@ -447,6 +421,8 @@ static void xgpio_irq_unmask(struct irq_data *irq_data) xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, val); } + __set_bit(bit, chip->enable); + raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); } @@ -462,7 +438,7 @@ static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type) { struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); int irq_offset = irqd_to_hwirq(irq_data); - int bit = xgpio_to_bit(chip, irq_offset); + unsigned long bit = find_nth_bit(chip->map, 64, irq_offset); /* * The Xilinx GPIO hardware provides a single interrupt status @@ -502,10 +478,10 @@ static void xgpio_irqhandler(struct irq_desc *desc) struct irq_chip *irqchip = irq_desc_get_chip(desc); DECLARE_BITMAP(rising, 64); DECLARE_BITMAP(falling, 64); - DECLARE_BITMAP(all, 64); + DECLARE_BITMAP(hw, 64); + DECLARE_BITMAP(sw, 64); int irq_offset; u32 status; - u32 bit; status = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, status); @@ -514,29 +490,28 @@ static void xgpio_irqhandler(struct irq_desc *desc) raw_spin_lock(&chip->gpio_lock); - xgpio_read_ch_all(chip, XGPIO_DATA_OFFSET, all); + xgpio_read_ch_all(chip, XGPIO_DATA_OFFSET, hw); bitmap_complement(rising, chip->last_irq_read, 64); - bitmap_and(rising, rising, all, 64); + bitmap_and(rising, rising, hw, 64); bitmap_and(rising, rising, chip->enable, 64); bitmap_and(rising, rising, chip->rising_edge, 64); - bitmap_complement(falling, all, 64); + bitmap_complement(falling, hw, 64); bitmap_and(falling, falling, chip->last_irq_read, 64); bitmap_and(falling, falling, chip->enable, 64); bitmap_and(falling, falling, chip->falling_edge, 64); - bitmap_copy(chip->last_irq_read, all, 64); - bitmap_or(all, rising, falling, 64); + bitmap_copy(chip->last_irq_read, hw, 64); + bitmap_or(hw, rising, falling, 64); raw_spin_unlock(&chip->gpio_lock); dev_dbg(gc->parent, "IRQ rising %*pb falling %*pb\n", 64, rising, 64, falling); - for_each_set_bit(bit, all, 64) { - irq_offset = xgpio_from_bit(chip, bit); + bitmap_gather(sw, hw, chip->map, 64); + for_each_set_bit(irq_offset, sw, 64) generic_handle_domain_irq(gc->irq.domain, irq_offset); - } chained_irq_exit(irqchip, desc); } @@ -613,17 +588,14 @@ static int xgpio_probe(struct platform_device *pdev) if (width[1] > 32) return -EINVAL; - /* Setup software pin mapping */ - bitmap_set(chip->sw_map, 0, width[0] + width[1]); - /* Setup hardware pin mapping */ - bitmap_set(chip->hw_map, 0, width[0]); - bitmap_set(chip->hw_map, 32, width[1]); + bitmap_set(chip->map, 0, width[0]); + bitmap_set(chip->map, 32, width[1]); raw_spin_lock_init(&chip->gpio_lock); chip->gc.base = -1; - chip->gc.ngpio = bitmap_weight(chip->hw_map, 64); + chip->gc.ngpio = bitmap_weight(chip->map, 64); chip->gc.parent = dev; chip->gc.direction_input = xgpio_dir_in; chip->gc.direction_output = xgpio_dir_out; diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c index dc2710c21c50..842cf875bb92 100644 --- a/drivers/gpio/gpio-xra1403.c +++ b/drivers/gpio/gpio-xra1403.c @@ -13,6 +13,7 @@ #include <linux/mutex.h> #include <linux/seq_file.h> #include <linux/spi/spi.h> +#include <linux/string_choices.h> #include <linux/regmap.h> /* XRA1403 registers */ @@ -140,7 +141,7 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_printf(s, " gpio-%-3d (%-12s) %s %s\n", chip->base + i, label, (gcr & BIT(i)) ? "in" : "out", - (gsr & BIT(i)) ? "hi" : "lo"); + str_hi_lo(gsr & BIT(i))); } } #else diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index f7746c57ba76..69caa35c58df 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -994,7 +994,7 @@ __acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, unsigned int desc = acpi_get_gpiod_from_data(fwnode, propname, idx, info); if (PTR_ERR(desc) == -EPROBE_DEFER) - return ERR_CAST(desc); + return desc; if (!IS_ERR(desc)) return desc; diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 2e537ee979f3..6e0eb67dcbf0 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -929,7 +929,7 @@ struct notifier_block gpio_of_notifier = { #endif /* CONFIG_OF_DYNAMIC */ /** - * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags + * of_gpio_twocell_xlate - translate twocell gpiospec to the GPIO number and flags * @gc: pointer to the gpio_chip structure * @gpiospec: GPIO specifier as found in the device tree * @flags: a flags pointer to fill in @@ -941,9 +941,9 @@ struct notifier_block gpio_of_notifier = { * Returns: * GPIO number (>= 0) on success, negative errno on failure. */ -static int of_gpio_simple_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, - u32 *flags) +static int of_gpio_twocell_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) { /* * We're discouraging gpio_cells < 2, since that way you'll have to @@ -951,7 +951,7 @@ static int of_gpio_simple_xlate(struct gpio_chip *gc, * number and the flags from a single gpio cell -- this is possible, * but not recommended). */ - if (gc->of_gpio_n_cells < 2) { + if (gc->of_gpio_n_cells != 2) { WARN_ON(1); return -EINVAL; } @@ -968,6 +968,49 @@ static int of_gpio_simple_xlate(struct gpio_chip *gc, return gpiospec->args[0]; } +/** + * of_gpio_threecell_xlate - translate threecell gpiospec to the GPIO number and flags + * @gc: pointer to the gpio_chip structure + * @gpiospec: GPIO specifier as found in the device tree + * @flags: a flags pointer to fill in + * + * This is simple translation function, suitable for the most 1:n mapped + * GPIO chips, i.e. several GPIO chip instances from one device tree node. + * In this case the following binding is implied: + * + * foo-gpios = <&gpio instance offset flags>; + * + * Returns: + * GPIO number (>= 0) on success, negative errno on failure. + */ +static int of_gpio_threecell_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + if (gc->of_gpio_n_cells != 3) { + WARN_ON(1); + return -EINVAL; + } + + if (WARN_ON(gpiospec->args_count != 3)) + return -EINVAL; + + /* + * Check chip instance number, the driver responds with true if + * this is the chip we are looking for. + */ + if (!gc->of_node_instance_match(gc, gpiospec->args[0])) + return -EINVAL; + + if (gpiospec->args[1] >= gc->ngpio) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[2]; + + return gpiospec->args[1]; +} + #if IS_ENABLED(CONFIG_OF_GPIO_MM_GPIOCHIP) #include <linux/gpio/legacy-of-mm-gpiochip.h> /** @@ -1057,6 +1100,9 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) const char *name; static const char group_names_propname[] = "gpio-ranges-group-names"; bool has_group_names; + int offset; /* Offset of the first GPIO line on the chip */ + int pin; /* Pin base number in the range */ + int count; /* Number of pins/GPIO lines to map */ np = dev_of_node(&chip->gpiodev->dev); if (!np) @@ -1065,7 +1111,15 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) has_group_names = of_property_present(np, group_names_propname); for (;; index++) { - ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, + /* + * Ordinary phandles contain 2-3 cells: + * gpios = <&gpio [instance] offset flags>; + * Ranges always contain one more cell: + * gpio-ranges <&pinctrl [gpio_instance] gpio_offet pin_offet count>; + * This is why we parse chip->of_gpio_n_cells + 1 cells + */ + ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", + chip->of_gpio_n_cells + 1, index, &pinspec); if (ret) break; @@ -1075,13 +1129,33 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) if (!pctldev) return -EPROBE_DEFER; + if (chip->of_gpio_n_cells == 3) { + /* First cell is the gpiochip instance number */ + offset = pinspec.args[1]; + pin = pinspec.args[2]; + count = pinspec.args[3]; + } else { + offset = pinspec.args[0]; + pin = pinspec.args[1]; + count = pinspec.args[2]; + } + + /* + * With multiple GPIO chips per node, check that this chip is the + * right instance. + */ + if (chip->of_node_instance_match && + (chip->of_gpio_n_cells == 3) && + !chip->of_node_instance_match(chip, pinspec.args[0])) + continue; + /* Ignore ranges outside of this GPIO chip */ - if (pinspec.args[0] >= (chip->offset + chip->ngpio)) + if (offset >= (chip->offset + chip->ngpio)) continue; - if (pinspec.args[0] + pinspec.args[2] <= chip->offset) + if (offset + count <= chip->offset) continue; - if (pinspec.args[2]) { + if (count) { /* npins != 0: linear range */ if (has_group_names) { of_property_read_string_index(np, @@ -1095,27 +1169,27 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) } /* Trim the range to fit this GPIO chip */ - if (chip->offset > pinspec.args[0]) { - trim = chip->offset - pinspec.args[0]; - pinspec.args[2] -= trim; - pinspec.args[1] += trim; - pinspec.args[0] = 0; + if (chip->offset > offset) { + trim = chip->offset - offset; + count -= trim; + pin += trim; + offset = 0; } else { - pinspec.args[0] -= chip->offset; + offset -= chip->offset; } - if ((pinspec.args[0] + pinspec.args[2]) > chip->ngpio) - pinspec.args[2] = chip->ngpio - pinspec.args[0]; + if ((offset + count) > chip->ngpio) + count = chip->ngpio - offset; ret = gpiochip_add_pin_range(chip, pinctrl_dev_get_devname(pctldev), - pinspec.args[0], - pinspec.args[1], - pinspec.args[2]); + offset, + pin, + count); if (ret) return ret; } else { /* npins == 0: special range */ - if (pinspec.args[1]) { + if (pin) { pr_err("%pOF: Illegal gpio-range format.\n", np); break; @@ -1140,7 +1214,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) } ret = gpiochip_add_pingroup_range(chip, pctldev, - pinspec.args[0], name); + offset, name); if (ret) return ret; } @@ -1163,8 +1237,14 @@ int of_gpiochip_add(struct gpio_chip *chip) return 0; if (!chip->of_xlate) { - chip->of_gpio_n_cells = 2; - chip->of_xlate = of_gpio_simple_xlate; + if (chip->of_gpio_n_cells == 3) { + if (!chip->of_node_instance_match) + return -EINVAL; + chip->of_xlate = of_gpio_threecell_xlate; + } else { + chip->of_gpio_n_cells = 2; + chip->of_xlate = of_gpio_twocell_xlate; + } } if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 0c00ed2ab431..b8197502a5ac 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/srcu.h> #include <linux/string.h> +#include <linux/string_choices.h> #include <linux/gpio.h> #include <linux/gpio/driver.h> @@ -341,6 +342,25 @@ static int gpiochip_find_base_unlocked(u16 ngpio) } } +static int gpiochip_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + if (WARN_ON(!gc->get_direction)) + return -EOPNOTSUPP; + + ret = gc->get_direction(gc, offset); + if (ret < 0) + return ret; + + if (ret != GPIO_LINE_DIRECTION_OUT && ret != GPIO_LINE_DIRECTION_IN) + ret = -EBADE; + + return ret; +} + /** * gpiod_get_direction - return the current direction of a GPIO * @desc: GPIO to get the direction of @@ -381,7 +401,7 @@ int gpiod_get_direction(struct gpio_desc *desc) if (!guard.gc->get_direction) return -ENOTSUPP; - ret = guard.gc->get_direction(guard.gc, offset); + ret = gpiochip_get_direction(guard.gc, offset); if (ret < 0) return ret; @@ -652,7 +672,7 @@ static int gpiochip_apply_reserved_ranges(struct gpio_chip *gc) if (start >= gc->ngpio || start + count > gc->ngpio) continue; - bitmap_clear(gc->valid_mask, start, count); + bitmap_clear(gc->gpiodev->valid_mask, start, count); } kfree(ranges); @@ -666,8 +686,8 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask)) return 0; - gc->valid_mask = gpiochip_allocate_mask(gc); - if (!gc->valid_mask) + gc->gpiodev->valid_mask = gpiochip_allocate_mask(gc); + if (!gc->gpiodev->valid_mask) return -ENOMEM; ret = gpiochip_apply_reserved_ranges(gc); @@ -676,7 +696,7 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) if (gc->init_valid_mask) return gc->init_valid_mask(gc, - gc->valid_mask, + gc->gpiodev->valid_mask, gc->ngpio); return 0; @@ -684,7 +704,7 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) static void gpiochip_free_valid_mask(struct gpio_chip *gc) { - gpiochip_free_mask(&gc->valid_mask); + gpiochip_free_mask(&gc->gpiodev->valid_mask); } static int gpiochip_add_pin_ranges(struct gpio_chip *gc) @@ -703,13 +723,29 @@ static int gpiochip_add_pin_ranges(struct gpio_chip *gc) return 0; } +/** + * gpiochip_query_valid_mask - return the GPIO validity information + * @gc: gpio chip which validity information is queried + * + * Returns: bitmap representing valid GPIOs or NULL if all GPIOs are valid + * + * Some GPIO chips may support configurations where some of the pins aren't + * available. These chips can have valid_mask set to represent the valid + * GPIOs. This function can be used to retrieve this information. + */ +const unsigned long *gpiochip_query_valid_mask(const struct gpio_chip *gc) +{ + return gc->gpiodev->valid_mask; +} +EXPORT_SYMBOL_GPL(gpiochip_query_valid_mask); + bool gpiochip_line_is_valid(const struct gpio_chip *gc, unsigned int offset) { /* No mask means all valid */ - if (likely(!gc->valid_mask)) + if (likely(!gc->gpiodev->valid_mask)) return true; - return test_bit(offset, gc->valid_mask); + return test_bit(offset, gc->gpiodev->valid_mask); } EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); @@ -882,13 +918,29 @@ void *gpiochip_get_data(struct gpio_chip *gc) } EXPORT_SYMBOL_GPL(gpiochip_get_data); +/* + * If the calling driver provides the specific firmware node, + * use it. Otherwise use the one from the parent device, if any. + */ +static struct fwnode_handle *gpiochip_choose_fwnode(struct gpio_chip *gc) +{ + if (gc->fwnode) + return gc->fwnode; + + if (gc->parent) + return dev_fwnode(gc->parent); + + return NULL; +} + int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev) { + struct fwnode_handle *fwnode = gpiochip_choose_fwnode(gc); u32 ngpios = gc->ngpio; int ret; if (ngpios == 0) { - ret = device_property_read_u32(dev, "ngpios", &ngpios); + ret = fwnode_property_read_u32(fwnode, "ngpios", &ngpios); if (ret == -ENODATA) /* * -ENODATA means that there is no property found and @@ -925,6 +977,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, int base = 0; int ret = 0; + /* Only allow one set() and one set_multiple(). */ + if ((gc->set && gc->set_rv) || + (gc->set_multiple && gc->set_multiple_rv)) + return -EINVAL; + /* * First: allocate and populate the internal stat container, and * set up the struct device. @@ -941,14 +998,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, gc->gpiodev = gdev; gpiochip_set_data(gc, data); - /* - * If the calling driver did not initialize firmware node, - * do it here using the parent device, if any. - */ - if (gc->fwnode) - device_set_node(&gdev->dev, gc->fwnode); - else if (gc->parent) - device_set_node(&gdev->dev, dev_fwnode(gc->parent)); + device_set_node(&gdev->dev, gpiochip_choose_fwnode(gc)); gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL); if (gdev->id < 0) { @@ -1058,11 +1108,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, desc->gdev = gdev; /* - * We would typically want to check the return value of - * get_direction() here but we must not check the return value - * and bail-out as pin controllers can have pins configured to - * alternate functions and return -EINVAL. Also: there's no - * need to take the SRCU lock here. + * We would typically want to use gpiochip_get_direction() here + * but we must not check the return value and bail-out as pin + * controllers can have pins configured to alternate functions + * and return -EINVAL. Also: there's no need to take the SRCU + * lock here. */ if (gc->get_direction && gpiochip_line_is_valid(gc, desc_index)) assign_bit(FLAG_IS_OUT, &desc->flags, @@ -2325,16 +2375,18 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags)) return -EBUSY; + offset = gpio_chip_hwgpio(desc); + if (!gpiochip_line_is_valid(guard.gc, offset)) + return -EINVAL; + /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled, for non-sleeping (SOC) GPIOs. */ if (guard.gc->request) { - offset = gpio_chip_hwgpio(desc); - if (gpiochip_line_is_valid(guard.gc, offset)) - ret = guard.gc->request(guard.gc, offset); - else - ret = -EINVAL; + ret = guard.gc->request(guard.gc, offset); + if (ret > 0) + ret = -EBADE; if (ret) goto out_clear_bit; } @@ -2577,6 +2629,9 @@ int gpio_do_set_config(struct gpio_desc *desc, unsigned long config) return -ENOTSUPP; ret = guard.gc->set_config(guard.gc, gpio_chip_hwgpio(desc), config); + if (ret > 0) + ret = -EBADE; + #ifdef CONFIG_GPIO_CDEV /* * Special case - if we're setting debounce period, we need to store @@ -2682,6 +2737,39 @@ int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce) return ret; } +static int gpiochip_direction_input(struct gpio_chip *gc, unsigned int offset) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + if (WARN_ON(!gc->direction_input)) + return -EOPNOTSUPP; + + ret = gc->direction_input(gc, offset); + if (ret > 0) + ret = -EBADE; + + return ret; +} + +static int gpiochip_direction_output(struct gpio_chip *gc, unsigned int offset, + int value) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + if (WARN_ON(!gc->direction_output)) + return -EOPNOTSUPP; + + ret = gc->direction_output(gc, offset, value); + if (ret > 0) + ret = -EBADE; + + return ret; +} + /** * gpiod_direction_input - set the GPIO direction to input * @desc: GPIO to set to input @@ -2733,11 +2821,10 @@ int gpiod_direction_input_nonotify(struct gpio_desc *desc) * assume we are in input mode after this. */ if (guard.gc->direction_input) { - ret = guard.gc->direction_input(guard.gc, - gpio_chip_hwgpio(desc)); + ret = gpiochip_direction_input(guard.gc, + gpio_chip_hwgpio(desc)); } else if (guard.gc->get_direction) { - dir = guard.gc->get_direction(guard.gc, - gpio_chip_hwgpio(desc)); + dir = gpiochip_get_direction(guard.gc, gpio_chip_hwgpio(desc)); if (dir < 0) return dir; @@ -2758,6 +2845,27 @@ int gpiod_direction_input_nonotify(struct gpio_desc *desc) return ret; } +static int gpiochip_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + if (WARN_ON(unlikely(!gc->set && !gc->set_rv))) + return -EOPNOTSUPP; + + if (gc->set_rv) { + ret = gc->set_rv(gc, offset, value); + if (ret > 0) + ret = -EBADE; + + return ret; + } + + gc->set(gc, offset, value); + return 0; +} + static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) { int val = !!value, ret = 0, dir; @@ -2779,13 +2887,13 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) } if (guard.gc->direction_output) { - ret = guard.gc->direction_output(guard.gc, - gpio_chip_hwgpio(desc), val); + ret = gpiochip_direction_output(guard.gc, + gpio_chip_hwgpio(desc), val); } else { /* Check that we are in output mode if we can */ if (guard.gc->get_direction) { - dir = guard.gc->get_direction(guard.gc, - gpio_chip_hwgpio(desc)); + dir = gpiochip_get_direction(guard.gc, + gpio_chip_hwgpio(desc)); if (dir < 0) return dir; @@ -2800,7 +2908,9 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) * If we can't actively set the direction, we are some * output-only chip, so just drive the output as desired. */ - guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), val); + ret = gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), val); + if (ret) + return ret; } if (!ret) @@ -2890,19 +3000,15 @@ int gpiod_direction_output_nonotify(struct gpio_desc *desc, int value) if (!ret) goto set_output_value; /* Emulate open drain by not actively driving the line high */ - if (value) { - ret = gpiod_direction_input_nonotify(desc); + if (value) goto set_output_flag; - } } else if (test_bit(FLAG_OPEN_SOURCE, &flags)) { ret = gpio_set_config(desc, PIN_CONFIG_DRIVE_OPEN_SOURCE); if (!ret) goto set_output_value; /* Emulate open source by not actively driving the line low */ - if (!value) { - ret = gpiod_direction_input_nonotify(desc); + if (!value) goto set_output_flag; - } } else { gpio_set_config(desc, PIN_CONFIG_DRIVE_PUSH_PULL); } @@ -2914,17 +3020,20 @@ set_output_value: return gpiod_direction_output_raw_commit(desc, value); set_output_flag: + ret = gpiod_direction_input_nonotify(desc); + if (ret) + return ret; /* * When emulating open-source or open-drain functionalities by not * actively driving the line (setting mode to input) we still need to * set the IS_OUT flag or otherwise we won't be able to set the line * value anymore. */ - if (ret == 0) - set_bit(FLAG_IS_OUT, &desc->flags); - return ret; + set_bit(FLAG_IS_OUT, &desc->flags); + return 0; } +#if IS_ENABLED(CONFIG_HTE) /** * gpiod_enable_hw_timestamp_ns - Enable hardware timestamp in nanoseconds. * @@ -2990,6 +3099,7 @@ int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) return ret; } EXPORT_SYMBOL_GPL(gpiod_disable_hw_timestamp_ns); +#endif /* CONFIG_HTE */ /** * gpiod_set_config - sets @config for a GPIO @@ -3096,9 +3206,23 @@ void gpiod_toggle_active_low(struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_toggle_active_low); +static int gpiochip_get(struct gpio_chip *gc, unsigned int offset) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + /* Make sure this is called after checking for gc->get(). */ + ret = gc->get(gc, offset); + if (ret > 1) + ret = -EBADE; + + return ret; +} + static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *desc) { - return gc->get ? gc->get(gc, gpio_chip_hwgpio(desc)) : -EIO; + return gc->get ? gpiochip_get(gc, gpio_chip_hwgpio(desc)) : -EIO; } /* I/O calls are only valid after configuration completed; the relevant @@ -3147,15 +3271,21 @@ static int gpiod_get_raw_value_commit(const struct gpio_desc *desc) static int gpio_chip_get_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { + int ret; + lockdep_assert_held(&gc->gpiodev->srcu); - if (gc->get_multiple) - return gc->get_multiple(gc, mask, bits); + if (gc->get_multiple) { + ret = gc->get_multiple(gc, mask, bits); + if (ret > 0) + return -EBADE; + } + if (gc->get) { int i, value; for_each_set_bit(i, mask, gc->ngpio) { - value = gc->get(gc, i); + value = gpiochip_get(gc, i); if (value < 0) return value; __assign_bit(i, bits, value); @@ -3408,18 +3538,18 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value); * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherwise it will set to LOW. */ -static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) +static int gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) { int ret = 0, offset = gpio_chip_hwgpio(desc); CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) - return; + return -ENODEV; if (value) { - ret = guard.gc->direction_input(guard.gc, offset); + ret = gpiochip_direction_input(guard.gc, offset); } else { - ret = guard.gc->direction_output(guard.gc, offset, 0); + ret = gpiochip_direction_output(guard.gc, offset, 0); if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); } @@ -3428,6 +3558,8 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) gpiod_err(desc, "%s: Error in set_value for open drain err %d\n", __func__, ret); + + return ret; } /* @@ -3435,36 +3567,38 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherwise it will set to LOW. */ -static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) +static int gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) { int ret = 0, offset = gpio_chip_hwgpio(desc); CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) - return; + return -ENODEV; if (value) { - ret = guard.gc->direction_output(guard.gc, offset, 1); + ret = gpiochip_direction_output(guard.gc, offset, 1); if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); } else { - ret = guard.gc->direction_input(guard.gc, offset); + ret = gpiochip_direction_input(guard.gc, offset); } trace_gpio_direction(desc_to_gpio(desc), !value, ret); if (ret < 0) gpiod_err(desc, "%s: Error in set_value for open source err %d\n", __func__, ret); + + return ret; } -static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) +static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) { CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) - return; + return -ENODEV; trace_gpio_value(desc_to_gpio(desc), 0, value); - guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), value); + return gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), value); } /* @@ -3476,21 +3610,38 @@ static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) * defines which outputs are to be changed * @bits: bit value array; one bit per output; BITS_PER_LONG bits per word * defines the values the outputs specified by mask are to be set to + * + * Returns: 0 on success, negative error number on failure. */ -static void gpio_chip_set_multiple(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits) +static int gpiochip_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) { + unsigned int i; + int ret; + lockdep_assert_held(&gc->gpiodev->srcu); + if (gc->set_multiple_rv) { + ret = gc->set_multiple_rv(gc, mask, bits); + if (ret > 0) + ret = -EBADE; + + return ret; + } + if (gc->set_multiple) { gc->set_multiple(gc, mask, bits); - } else { - unsigned int i; + return 0; + } - /* set outputs if the corresponding mask bit is set */ - for_each_set_bit(i, mask, gc->ngpio) - gc->set(gc, i, test_bit(i, bits)); + /* set outputs if the corresponding mask bit is set */ + for_each_set_bit(i, mask, gc->ngpio) { + ret = gpiochip_set(gc, i, test_bit(i, bits)); + if (ret) + break; } + + return ret; } int gpiod_set_array_value_complex(bool raw, bool can_sleep, @@ -3500,7 +3651,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, unsigned long *value_bitmap) { struct gpio_chip *gc; - int i = 0; + int i = 0, ret; /* * Validate array_info against desc_array and its size. @@ -3523,7 +3674,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, bitmap_xor(value_bitmap, value_bitmap, array_info->invert_mask, array_size); - gpio_chip_set_multiple(gc, array_info->set_mask, value_bitmap); + ret = gpiochip_set_multiple(gc, array_info->set_mask, + value_bitmap); + if (ret) + return ret; i = find_first_zero_bit(array_info->set_mask, array_size); if (i == array_size) @@ -3600,8 +3754,11 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, } while ((i < array_size) && gpio_device_chip_cmp(desc_array[i]->gdev, guard.gc)); /* push collected bits to outputs */ - if (count != 0) - gpio_chip_set_multiple(guard.gc, mask, bits); + if (count != 0) { + ret = gpiochip_set_multiple(guard.gc, mask, bits); + if (ret) + return ret; + } if (mask != fastpath_mask) bitmap_free(mask); @@ -3621,13 +3778,16 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, * * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. + * + * Returns: + * 0 on success, negative error number on failure. */ -void gpiod_set_raw_value(struct gpio_desc *desc, int value) +int gpiod_set_raw_value(struct gpio_desc *desc, int value) { - VALIDATE_DESC_VOID(desc); + VALIDATE_DESC(desc); /* Should be using gpiod_set_raw_value_cansleep() */ WARN_ON(desc->gdev->can_sleep); - gpiod_set_raw_value_commit(desc, value); + return gpiod_set_raw_value_commit(desc, value); } EXPORT_SYMBOL_GPL(gpiod_set_raw_value); @@ -3639,17 +3799,21 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value); * This sets the value of a GPIO line backing a descriptor, applying * different semantic quirks like active low and open drain/source * handling. + * + * Returns: + * 0 on success, negative error number on failure. */ -static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value) +static int gpiod_set_value_nocheck(struct gpio_desc *desc, int value) { if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - gpio_set_open_drain_value_commit(desc, value); + return gpio_set_open_drain_value_commit(desc, value); else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - gpio_set_open_source_value_commit(desc, value); - else - gpiod_set_raw_value_commit(desc, value); + return gpio_set_open_source_value_commit(desc, value); + + return gpiod_set_raw_value_commit(desc, value); } /** @@ -3662,13 +3826,16 @@ static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value) * * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. + * + * Returns: + * 0 on success, negative error number on failure. */ -void gpiod_set_value(struct gpio_desc *desc, int value) +int gpiod_set_value(struct gpio_desc *desc, int value) { - VALIDATE_DESC_VOID(desc); + VALIDATE_DESC(desc); /* Should be using gpiod_set_value_cansleep() */ WARN_ON(desc->gdev->can_sleep); - gpiod_set_value_nocheck(desc, value); + return gpiod_set_value_nocheck(desc, value); } EXPORT_SYMBOL_GPL(gpiod_set_value); @@ -4086,12 +4253,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep); * regard for its ACTIVE_LOW status. * * This function is to be called from contexts that can sleep. + * + * Returns: + * 0 on success, negative error number on failure. */ -void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) +int gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) { might_sleep(); - VALIDATE_DESC_VOID(desc); - gpiod_set_raw_value_commit(desc, value); + VALIDATE_DESC(desc); + return gpiod_set_raw_value_commit(desc, value); } EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); @@ -4104,12 +4274,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); * account * * This function is to be called from contexts that can sleep. + * + * Returns: + * 0 on success, negative error number on failure. */ -void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) +int gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { might_sleep(); - VALIDATE_DESC_VOID(desc); - gpiod_set_value_nocheck(desc, value); + VALIDATE_DESC(desc); + return gpiod_set_value_nocheck(desc, value); } EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); @@ -4746,10 +4919,10 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, return ret; } - gpiod_dbg(desc, "hogged as %s%s\n", + gpiod_dbg(desc, "hogged as %s/%s\n", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? - (dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : ""); + str_high_low(dflags & GPIOD_FLAGS_BIT_DIR_VAL) : "?"); return 0; } @@ -5023,6 +5196,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) unsigned int gpio = gdev->base; struct gpio_desc *desc; struct gpio_chip *gc; + unsigned long flags; int value; guard(srcu)(&gdev->srcu); @@ -5035,16 +5209,17 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) for_each_gpio_desc(gc, desc) { guard(srcu)(&desc->gdev->desc_srcu); - is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags); - if (is_irq || test_bit(FLAG_REQUESTED, &desc->flags)) { + flags = READ_ONCE(desc->flags); + is_irq = test_bit(FLAG_USED_AS_IRQ, &flags); + if (is_irq || test_bit(FLAG_REQUESTED, &flags)) { gpiod_get_direction(desc); - is_out = test_bit(FLAG_IS_OUT, &desc->flags); + is_out = test_bit(FLAG_IS_OUT, &flags); value = gpio_chip_get_value(gc, desc); - active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags); + active_low = test_bit(FLAG_ACTIVE_LOW, &flags); seq_printf(s, " gpio-%-3u (%-20.20s|%-20.20s) %s %s %s%s\n", gpio, desc->name ?: "", gpiod_get_label(desc), is_out ? "out" : "in ", - value >= 0 ? (value ? "hi" : "lo") : "? ", + value >= 0 ? str_hi_lo(value) : "? ", is_irq ? "IRQ " : "", active_low ? "ACTIVE LOW" : ""); } else if (desc->name) { diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index c129a03e2040..58f64056de77 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -33,6 +33,8 @@ * @chip: pointer to the corresponding gpiochip, holding static * data for this device * @descs: array of ngpio descriptors. + * @valid_mask: If not %NULL, holds bitmask of GPIOs which are valid to be + * used from the chip. * @desc_srcu: ensures consistent state of GPIO descriptors exposed to users * @ngpio: the number of GPIO lines on this GPIO device, equal to the size * of the @descs array. @@ -67,6 +69,7 @@ struct gpio_device { struct module *owner; struct gpio_chip __rcu *chip; struct gpio_desc *descs; + unsigned long *valid_mask; struct srcu_struct desc_srcu; unsigned int base; u16 ngpio; @@ -186,24 +189,24 @@ struct gpio_desc { struct gpio_device *gdev; unsigned long flags; /* flag symbols are bit numbers */ -#define FLAG_REQUESTED 0 -#define FLAG_IS_OUT 1 -#define FLAG_EXPORT 2 /* protected by sysfs_lock */ -#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ -#define FLAG_ACTIVE_LOW 6 /* value has active low */ -#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ -#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ -#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ -#define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */ -#define FLAG_IS_HOGGED 11 /* GPIO is hogged */ -#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ -#define FLAG_PULL_UP 13 /* GPIO has pull up enabled */ -#define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */ -#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */ -#define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */ -#define FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */ -#define FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */ -#define FLAG_EVENT_CLOCK_HTE 19 /* GPIO CDEV reports hardware timestamps in events */ +#define FLAG_REQUESTED 0 +#define FLAG_IS_OUT 1 +#define FLAG_EXPORT 2 /* protected by sysfs_lock */ +#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ +#define FLAG_ACTIVE_LOW 6 /* value has active low */ +#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ +#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ +#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ +#define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */ +#define FLAG_IS_HOGGED 11 /* GPIO is hogged */ +#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ +#define FLAG_PULL_UP 13 /* GPIO has pull up enabled */ +#define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */ +#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */ +#define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */ +#define FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */ +#define FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */ +#define FLAG_EVENT_CLOCK_HTE 19 /* GPIO CDEV reports hardware timestamps in events */ /* Connection label */ struct gpio_desc_label __rcu *label; diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c index 08cca128458c..fe223d363a5d 100644 --- a/drivers/leds/leds-aw200xx.c +++ b/drivers/leds/leds-aw200xx.c @@ -379,7 +379,7 @@ static void aw200xx_enable(const struct aw200xx *const chip) static void aw200xx_disable(const struct aw200xx *const chip) { - return gpiod_set_value_cansleep(chip->hwen, 0); + gpiod_set_value_cansleep(chip->hwen, 0); } static int aw200xx_probe_get_display_rows(struct device *dev, diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index 37cd858df0f4..4b47e6c3b04b 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -54,8 +54,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, else bitmap_zero(values, nvalues); - gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, - reset_gpios->info, values); + gpiod_multi_set_value_cansleep(reset_gpios, values); bitmap_free(values); } diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index cc5f2c1861d4..5710879cd47f 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -28,9 +28,7 @@ static int mux_gpio_set(struct mux_control *mux, int state) bitmap_from_arr32(values, &value, BITS_PER_TYPE(value)); - gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, - mux_gpio->gpios->desc, - mux_gpio->gpios->info, values); + gpiod_multi_set_value_cansleep(mux_gpio->gpios, values); return 0; } diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c index 152344e4f7e4..fd0e0cd1c1cf 100644 --- a/drivers/phy/motorola/phy-mapphone-mdm6600.c +++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c @@ -177,9 +177,7 @@ static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val) values[0] = val; - gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES, - ddata->cmd_gpios->desc, - ddata->cmd_gpios->info, values); + gpiod_multi_set_value_cansleep(ddata->cmd_gpios, values); } /** diff --git a/include/drm/drm_util.h b/include/drm/drm_util.h index 79952d8c4bba..440199618620 100644 --- a/include/drm/drm_util.h +++ b/include/drm/drm_util.h @@ -36,6 +36,7 @@ #include <linux/kgdb.h> #include <linux/preempt.h> #include <linux/smp.h> +#include <linux/util_macros.h> /* * Use EXPORT_SYMBOL_FOR_TESTS_ONLY() for functions that shall @@ -48,21 +49,6 @@ #endif /** - * for_each_if - helper for handling conditionals in various for_each macros - * @condition: The condition to check - * - * Typical use:: - * - * #define for_each_foo_bar(x, y) \' - * list_for_each_entry(x, y->list, head) \' - * for_each_if(x->something == SOMETHING) - * - * The for_each_if() macro makes the use of for_each_foo_bar() less error - * prone. - */ -#define for_each_if(condition) if (!(condition)) {} else - -/** * drm_can_sleep - returns true if currently okay to sleep * * This function shall not be used in new code. diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 6270150f4e29..c1ec62c11ed3 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -91,7 +91,7 @@ static inline int gpio_get_value_cansleep(unsigned gpio) } static inline void gpio_set_value_cansleep(unsigned gpio, int value) { - return gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value); + gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value); } static inline int gpio_get_value(unsigned gpio) @@ -100,7 +100,7 @@ static inline int gpio_get_value(unsigned gpio) } static inline void gpio_set_value(unsigned gpio, int value) { - return gpiod_set_raw_value(gpio_to_desc(gpio), value); + gpiod_set_raw_value(gpio_to_desc(gpio), value); } static inline int gpio_to_irq(unsigned gpio) diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index db2dfbae8edb..45b651c05b9c 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -3,6 +3,7 @@ #define __LINUX_GPIO_CONSUMER_H #include <linux/bits.h> +#include <linux/err.h> #include <linux/types.h> struct acpi_device; @@ -110,8 +111,6 @@ int gpiod_get_direction(struct gpio_desc *desc); int gpiod_direction_input(struct gpio_desc *desc); int gpiod_direction_output(struct gpio_desc *desc, int value); int gpiod_direction_output_raw(struct gpio_desc *desc, int value); -int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags); -int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags); /* Value get/set from non-sleeping context */ int gpiod_get_value(const struct gpio_desc *desc); @@ -119,7 +118,7 @@ int gpiod_get_array_value(unsigned int array_size, struct gpio_desc **desc_array, struct gpio_array *array_info, unsigned long *value_bitmap); -void gpiod_set_value(struct gpio_desc *desc, int value); +int gpiod_set_value(struct gpio_desc *desc, int value); int gpiod_set_array_value(unsigned int array_size, struct gpio_desc **desc_array, struct gpio_array *array_info, @@ -129,7 +128,7 @@ int gpiod_get_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, struct gpio_array *array_info, unsigned long *value_bitmap); -void gpiod_set_raw_value(struct gpio_desc *desc, int value); +int gpiod_set_raw_value(struct gpio_desc *desc, int value); int gpiod_set_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, struct gpio_array *array_info, @@ -141,7 +140,7 @@ int gpiod_get_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, struct gpio_array *array_info, unsigned long *value_bitmap); -void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); +int gpiod_set_value_cansleep(struct gpio_desc *desc, int value); int gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, struct gpio_array *array_info, @@ -151,7 +150,7 @@ int gpiod_get_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, struct gpio_array *array_info, unsigned long *value_bitmap); -void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value); +int gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value); int gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, struct gpio_array *array_info, @@ -183,11 +182,9 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, #else /* CONFIG_GPIOLIB */ -#include <linux/err.h> +#include <linux/bug.h> #include <linux/kernel.h> -#include <asm/bug.h> - static inline int gpiod_count(struct device *dev, const char *con_id) { return 0; @@ -348,18 +345,6 @@ static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value) WARN_ON(desc); return -ENOSYS; } -static inline int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, - unsigned long flags) -{ - WARN_ON(desc); - return -ENOSYS; -} -static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, - unsigned long flags) -{ - WARN_ON(desc); - return -ENOSYS; -} static inline int gpiod_get_value(const struct gpio_desc *desc) { /* GPIO can never have been requested */ @@ -375,10 +360,11 @@ static inline int gpiod_get_array_value(unsigned int array_size, WARN_ON(desc_array); return 0; } -static inline void gpiod_set_value(struct gpio_desc *desc, int value) +static inline int gpiod_set_value(struct gpio_desc *desc, int value) { /* GPIO can never have been requested */ WARN_ON(desc); + return 0; } static inline int gpiod_set_array_value(unsigned int array_size, struct gpio_desc **desc_array, @@ -404,10 +390,11 @@ static inline int gpiod_get_raw_array_value(unsigned int array_size, WARN_ON(desc_array); return 0; } -static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value) +static inline int gpiod_set_raw_value(struct gpio_desc *desc, int value) { /* GPIO can never have been requested */ WARN_ON(desc); + return 0; } static inline int gpiod_set_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, @@ -434,10 +421,11 @@ static inline int gpiod_get_array_value_cansleep(unsigned int array_size, WARN_ON(desc_array); return 0; } -static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) +static inline int gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { /* GPIO can never have been requested */ WARN_ON(desc); + return 0; } static inline int gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, @@ -463,11 +451,12 @@ static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size, WARN_ON(desc_array); return 0; } -static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, - int value) +static inline int gpiod_set_raw_value_cansleep(struct gpio_desc *desc, + int value) { /* GPIO can never have been requested */ WARN_ON(desc); + return 0; } static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, @@ -560,6 +549,31 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, #endif /* CONFIG_GPIOLIB */ +#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_HTE) +int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags); +int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags); +#else + +#include <linux/bug.h> + +static inline int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, + unsigned long flags) +{ + if (!IS_ENABLED(CONFIG_GPIOLIB)) + WARN_ON(desc); + + return -ENOSYS; +} +static inline int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, + unsigned long flags) +{ + if (!IS_ENABLED(CONFIG_GPIOLIB)) + WARN_ON(desc); + + return -ENOSYS; +} +#endif /* CONFIG_GPIOLIB && CONFIG_HTE */ + static inline struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev, struct fwnode_handle *fwnode, @@ -608,8 +622,6 @@ int devm_acpi_dev_add_driver_gpios(struct device *dev, #else /* CONFIG_GPIOLIB && CONFIG_ACPI */ -#include <linux/err.h> - static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev, const struct acpi_gpio_mapping *gpios) { @@ -635,8 +647,6 @@ void gpiod_unexport(struct gpio_desc *desc); #else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ -#include <asm/errno.h> - static inline int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { @@ -655,4 +665,14 @@ static inline void gpiod_unexport(struct gpio_desc *desc) #endif /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ +static inline int gpiod_multi_set_value_cansleep(struct gpio_descs *descs, + unsigned long *value_bitmap) +{ + if (IS_ERR_OR_NULL(descs)) + return PTR_ERR_OR_ZERO(descs); + + return gpiod_set_array_value_cansleep(descs->ndescs, descs->desc, + descs->info, value_bitmap); +} + #endif diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 2dd7cb9cc270..4c0294a9104d 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -14,6 +14,7 @@ #include <linux/property.h> #include <linux/spinlock_types.h> #include <linux/types.h> +#include <linux/util_macros.h> #ifdef CONFIG_GENERIC_MSI_IRQ #include <asm/msi.h> @@ -328,7 +329,8 @@ struct gpio_irq_chip { * @fwnode: optional fwnode providing this controller's properties * @owner: helps prevent removal of modules exporting active GPIOs * @request: optional hook for chip-specific activation, such as - * enabling module power and clock; may sleep + * enabling module power and clock; may sleep; must return 0 on success + * or negative error number on failure * @free: optional hook for chip-specific deactivation, such as * disabling module power and clock; may sleep * @get_direction: returns direction for signal "offset", 0=out, 1=in, @@ -344,10 +346,15 @@ struct gpio_irq_chip { * @get: returns value for signal "offset", 0=low, 1=high, or negative error * @get_multiple: reads values for multiple signals defined by "mask" and * stores them in "bits", returns 0 on success or negative error - * @set: assigns output value for signal "offset" - * @set_multiple: assigns output values for multiple signals defined by "mask" + * @set: **DEPRECATED** - please use set_rv() instead + * @set_multiple: **DEPRECATED** - please use set_multiple_rv() instead + * @set_rv: assigns output value for signal "offset", returns 0 on success or + * negative error value + * @set_multiple_rv: assigns output values for multiple signals defined by + * "mask", returns 0 on success or negative error value * @set_config: optional hook for all kinds of settings. Uses the same - * packed config format as generic pinconf. + * packed config format as generic pinconf. Must return 0 on success and + * a negative error number on failure. * @to_irq: optional hook supporting non-static gpiod_to_irq() mappings; * implementation may not sleep * @dbg_show: optional routine to show contents in debugfs; default code @@ -394,6 +401,7 @@ struct gpio_irq_chip { * @reg_dir_in: direction in setting register for generic GPIO * @bgpio_dir_unreadable: indicates that the direction register(s) cannot * be read and we need to rely on out internal state tracking. + * @bgpio_pinctrl: the generic GPIO uses a pin control backend. * @bgpio_bits: number of register bits used for a generic GPIO i.e. * <register width> * 8 * @bgpio_lock: used to lock chip->bgpio_data. Also, this is needed to keep @@ -441,6 +449,12 @@ struct gpio_chip { void (*set_multiple)(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits); + int (*set_rv)(struct gpio_chip *gc, + unsigned int offset, + int value); + int (*set_multiple_rv)(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits); int (*set_config)(struct gpio_chip *gc, unsigned int offset, unsigned long config); @@ -478,6 +492,7 @@ struct gpio_chip { void __iomem *reg_dir_out; void __iomem *reg_dir_in; bool bgpio_dir_unreadable; + bool bgpio_pinctrl; int bgpio_bits; raw_spinlock_t bgpio_lock; unsigned long bgpio_data; @@ -499,14 +514,6 @@ struct gpio_chip { struct gpio_irq_chip irq; #endif /* CONFIG_GPIOLIB_IRQCHIP */ - /** - * @valid_mask: - * - * If not %NULL, holds bitmask of GPIOs which are valid to be used - * from the chip. - */ - unsigned long *valid_mask; - #if defined(CONFIG_OF_GPIO) /* * If CONFIG_OF_GPIO is enabled, then all GPIO controllers described in @@ -516,11 +523,33 @@ struct gpio_chip { /** * @of_gpio_n_cells: * - * Number of cells used to form the GPIO specifier. + * Number of cells used to form the GPIO specifier. The standard is 2 + * cells: + * + * gpios = <&gpio offset flags>; + * + * some complex GPIO controllers instantiate more than one chip per + * device tree node and have 3 cells: + * + * gpios = <&gpio instance offset flags>; + * + * Legacy GPIO controllers may even have 1 cell: + * + * gpios = <&gpio offset>; */ unsigned int of_gpio_n_cells; /** + * @of_node_instance_match: + * + * Determine if a chip is the right instance. Must be implemented by + * any driver using more than one gpio_chip per device tree node. + * Returns true if gc is the instance indicated by i (which is the + * first cell in the phandles for GPIO lines and gpio-ranges). + */ + bool (*of_node_instance_match)(struct gpio_chip *gc, unsigned int i); + + /** * @of_xlate: * * Callback to translate a device tree GPIO specifier into a chip- @@ -550,19 +579,29 @@ DEFINE_CLASS(_gpiochip_for_each_data, const char **label, int *i) /** + * for_each_hwgpio_in_range - Iterates over all GPIOs in a given range + * @_chip: Chip to iterate over. + * @_i: Loop counter. + * @_base: First GPIO in the ranger. + * @_size: Amount of GPIOs to check starting from @base. + * @_label: Place to store the address of the label if the GPIO is requested. + * Set to NULL for unused GPIOs. + */ +#define for_each_hwgpio_in_range(_chip, _i, _base, _size, _label) \ + for (CLASS(_gpiochip_for_each_data, _data)(&_label, &_i); \ + _i < _size; \ + _i++, kfree(_label), _label = NULL) \ + for_each_if(!IS_ERR(_label = gpiochip_dup_line_label(_chip, _base + _i))) + +/** * for_each_hwgpio - Iterates over all GPIOs for given chip. * @_chip: Chip to iterate over. * @_i: Loop counter. * @_label: Place to store the address of the label if the GPIO is requested. * Set to NULL for unused GPIOs. */ -#define for_each_hwgpio(_chip, _i, _label) \ - for (CLASS(_gpiochip_for_each_data, _data)(&_label, &_i); \ - *_data.i < _chip->ngpio; \ - (*_data.i)++, kfree(*(_data.label)), *_data.label = NULL) \ - if (IS_ERR(*_data.label = \ - gpiochip_dup_line_label(_chip, *_data.i))) {} \ - else +#define for_each_hwgpio(_chip, _i, _label) \ + for_each_hwgpio_in_range(_chip, _i, 0, _chip->ngpio, _label) /** * for_each_requested_gpio_in_range - iterates over requested GPIOs in a given range @@ -573,13 +612,8 @@ DEFINE_CLASS(_gpiochip_for_each_data, * @_label: label of current GPIO */ #define for_each_requested_gpio_in_range(_chip, _i, _base, _size, _label) \ - for (CLASS(_gpiochip_for_each_data, _data)(&_label, &_i); \ - *_data.i < _size; \ - (*_data.i)++, kfree(*(_data.label)), *_data.label = NULL) \ - if ((*_data.label = \ - gpiochip_dup_line_label(_chip, _base + *_data.i)) == NULL) {} \ - else if (IS_ERR(*_data.label)) {} \ - else + for_each_hwgpio_in_range(_chip, _i, _base, _size, _label) \ + for_each_if(_label) /* Iterates over all requested GPIO of the given @chip */ #define for_each_requested_gpio(chip, i, label) \ @@ -678,6 +712,7 @@ bool gpiochip_line_is_open_source(struct gpio_chip *gc, unsigned int offset); /* Sleep persistence inquiry for drivers */ bool gpiochip_line_is_persistent(struct gpio_chip *gc, unsigned int offset); bool gpiochip_line_is_valid(const struct gpio_chip *gc, unsigned int offset); +const unsigned long *gpiochip_query_valid_mask(const struct gpio_chip *gc); /* get driver data */ void *gpiochip_get_data(struct gpio_chip *gc); @@ -713,6 +748,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev, #define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ #define BGPIOF_NO_OUTPUT BIT(5) /* only input */ #define BGPIOF_NO_SET_ON_INPUT BIT(6) +#define BGPIOF_PINCTRL_BACKEND BIT(7) /* Call pinctrl direction setters */ #ifdef CONFIG_GPIOLIB_IRQCHIP int gpiochip_irqchip_add_domain(struct gpio_chip *gc, @@ -865,7 +901,7 @@ static inline void gpiochip_unlock_as_irq(struct gpio_chip *gc, #define for_each_gpiochip_node(dev, child) \ device_for_each_child_node(dev, child) \ - if (!fwnode_property_present(child, "gpio-controller")) {} else + for_each_if(fwnode_property_present(child, "gpio-controller")) static inline unsigned int gpiochip_node_count(struct device *dev) { diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h index a9f7b7faf57b..c722c67668c6 100644 --- a/include/linux/gpio/regmap.h +++ b/include/linux/gpio/regmap.h @@ -21,7 +21,7 @@ struct regmap; * If not given, the fwnode of the parent is used. * @label: (Optional) Descriptive name for GPIO controller. * If not given, the name of the device is used. - * @ngpio: Number of GPIOs + * @ngpio: (Optional) Number of GPIOs * @names: (Optional) Array of names for gpios * @reg_dat_base: (Optional) (in) register base address * @reg_set_base: (Optional) set register base address @@ -30,7 +30,7 @@ struct regmap; * @reg_dir_out_base: (Optional) out setting register base address * @reg_stride: (Optional) May be set if the registers (of the * same type, dat, set, etc) are not consecutive. - * @ngpio_per_reg: Number of GPIOs per register + * @ngpio_per_reg: (Optional) Number of GPIOs per register * @irq_domain: (Optional) IRQ domain if the controller is * interrupt-capable * @reg_mask_xlate: (Optional) Translates base address and GPIO diff --git a/include/linux/util_macros.h b/include/linux/util_macros.h index 825487fb66fa..3b570b765b75 100644 --- a/include/linux/util_macros.h +++ b/include/linux/util_macros.h @@ -5,6 +5,21 @@ #include <linux/math.h> /** + * for_each_if - helper for handling conditionals in various for_each macros + * @condition: The condition to check + * + * Typical use:: + * + * #define for_each_foo_bar(x, y) \' + * list_for_each_entry(x, y->list, head) \' + * for_each_if(x->something == SOMETHING) + * + * The for_each_if() macro makes the use of for_each_foo_bar() less error + * prone. + */ +#define for_each_if(condition) if (!(condition)) {} else + +/** * find_closest - locate the closest element in a sorted array * @x: The reference value. * @a: The array in which to look for the closest element. Must be sorted |