summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml6
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml10
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-vf610.yaml1
-rw-r--r--Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml3
-rw-r--r--Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml37
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/dev-sync-probe.c97
-rw-r--r--drivers/gpio/dev-sync-probe.h25
-rw-r--r--drivers/gpio/gpio-74x164.c92
-rw-r--r--drivers/gpio/gpio-adnp.c138
-rw-r--r--drivers/gpio/gpio-adp5520.c12
-rw-r--r--drivers/gpio/gpio-adp5585.c10
-rw-r--r--drivers/gpio/gpio-aggregator.c38
-rw-r--r--drivers/gpio/gpio-altera-a10sr.c14
-rw-r--r--drivers/gpio/gpio-altera.c6
-rw-r--r--drivers/gpio/gpio-amd-fch.c7
-rw-r--r--drivers/gpio/gpio-amd8111.c6
-rw-r--r--drivers/gpio/gpio-arizona.c9
-rw-r--r--drivers/gpio/gpio-aspeed-sgpio.c86
-rw-r--r--drivers/gpio/gpio-aspeed.c108
-rw-r--r--drivers/gpio/gpio-brcmstb.c3
-rw-r--r--drivers/gpio/gpio-crystalcove.c3
-rw-r--r--drivers/gpio/gpio-davinci.c6
-rw-r--r--drivers/gpio/gpio-grgpio.c3
-rw-r--r--drivers/gpio/gpio-latch.c68
-rw-r--r--drivers/gpio/gpio-loongson-64bit.c55
-rw-r--r--drivers/gpio/gpio-max3191x.c18
-rw-r--r--drivers/gpio/gpio-max77650.c14
-rw-r--r--drivers/gpio/gpio-mmio.c37
-rw-r--r--drivers/gpio/gpio-mockup.c14
-rw-r--r--drivers/gpio/gpio-mvebu.c15
-rw-r--r--drivers/gpio/gpio-nomadik.c3
-rw-r--r--drivers/gpio/gpio-pca953x.c17
-rw-r--r--drivers/gpio/gpio-pcf857x.c29
-rw-r--r--drivers/gpio/gpio-rcar.c13
-rw-r--r--drivers/gpio/gpio-regmap.c73
-rw-r--r--drivers/gpio/gpio-sim.c98
-rw-r--r--drivers/gpio/gpio-stmpe.c6
-rw-r--r--drivers/gpio/gpio-vf610.c105
-rw-r--r--drivers/gpio/gpio-virtio.c29
-rw-r--r--drivers/gpio/gpio-virtuser.c73
-rw-r--r--drivers/gpio/gpio-wcove.c3
-rw-r--r--drivers/gpio/gpio-wm831x.c3
-rw-r--r--drivers/gpio/gpio-xilinx.c102
-rw-r--r--drivers/gpio/gpio-xra1403.c3
-rw-r--r--drivers/gpio/gpiolib-acpi.c2
-rw-r--r--drivers/gpio/gpiolib-of.c128
-rw-r--r--drivers/gpio/gpiolib.c365
-rw-r--r--drivers/gpio/gpiolib.h39
-rw-r--r--drivers/leds/leds-aw200xx.c2
-rw-r--r--drivers/mmc/core/pwrseq_simple.c3
-rw-r--r--drivers/mux/gpio.c4
-rw-r--r--drivers/phy/motorola/phy-mapphone-mdm6600.c4
-rw-r--r--include/drm/drm_util.h16
-rw-r--r--include/linux/gpio.h4
-rw-r--r--include/linux/gpio/consumer.h80
-rw-r--r--include/linux/gpio/driver.h92
-rw-r--r--include/linux/gpio/regmap.h4
-rw-r--r--include/linux/util_macros.h15
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, &reg, &mask);
+ if (ret)
+ return ret;
- gpio->reg_mask_xlate(gpio, base, offset, &reg, &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, &reg, &mask);
- regmap_write(gpio->regmap, reg, mask);
+ ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &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