aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
authorMark Brown <broonie@kernel.org>2026-05-29 23:13:54 +0100
committerMark Brown <broonie@kernel.org>2026-05-29 23:13:54 +0100
commit72cd7b71160e5e201a1e9b941bbfacc7cd25003f (patch)
tree1e61b49504d13050958041ef5ae7fadce908543d /drivers
parent1ef9f7af25f6afae52decb8280285d2824d69c83 (diff)
parent9de94681ee48770ec7e2062451a572b557bf9298 (diff)
downloadlinux-next-history-72cd7b71160e5e201a1e9b941bbfacc7cd25003f.tar.gz
Merge branch 'gpio/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig39
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/gpio-74x164.c17
-rw-r--r--drivers/gpio/gpio-adnp.c4
-rw-r--r--drivers/gpio/gpio-adp5585.c4
-rw-r--r--drivers/gpio/gpio-altera.c124
-rw-r--r--drivers/gpio/gpio-amd8111.c4
-rw-r--r--drivers/gpio/gpio-bd72720.c4
-rw-r--r--drivers/gpio/gpio-bd9571mwv.c4
-rw-r--r--drivers/gpio/gpio-cros-ec.c4
-rw-r--r--drivers/gpio/gpio-ds4520.c2
-rw-r--r--drivers/gpio/gpio-dwapb.c1
-rw-r--r--drivers/gpio/gpio-ep93xx.c3
-rw-r--r--drivers/gpio/gpio-fxl6408.c2
-rw-r--r--drivers/gpio/gpio-gw-pld.c2
-rw-r--r--drivers/gpio/gpio-ixp4xx.c7
-rw-r--r--drivers/gpio/gpio-lp873x.c2
-rw-r--r--drivers/gpio/gpio-lp87565.c2
-rw-r--r--drivers/gpio/gpio-max7300.c2
-rw-r--r--drivers/gpio/gpio-max732x.c20
-rw-r--r--drivers/gpio/gpio-max77620.c2
-rw-r--r--drivers/gpio/gpio-max77759.c2
-rw-r--r--drivers/gpio/gpio-mxc.c4
-rw-r--r--drivers/gpio/gpio-pca953x.c87
-rw-r--r--drivers/gpio/gpio-pca9570.c6
-rw-r--r--drivers/gpio/gpio-pcf857x.c26
-rw-r--r--drivers/gpio/gpio-pxa.c18
-rw-r--r--drivers/gpio/gpio-realtek-otto.c6
-rw-r--r--drivers/gpio/gpio-regmap.c74
-rw-r--r--drivers/gpio/gpio-sim.c24
-rw-r--r--drivers/gpio/gpio-tegra186.c69
-rw-r--r--drivers/gpio/gpio-tpic2810.c2
-rw-r--r--drivers/gpio/gpio-tps65086.c2
-rw-r--r--drivers/gpio/gpio-tps65218.c2
-rw-r--r--drivers/gpio/gpio-tps65219.c4
-rw-r--r--drivers/gpio/gpio-tps65912.c2
-rw-r--r--drivers/gpio/gpio-ts4900.c2
-rw-r--r--drivers/gpio/gpio-ts5500.c446
-rw-r--r--drivers/gpio/gpio-usbio.c1
-rw-r--r--drivers/gpio/gpio-waveshare-dsi.c208
-rw-r--r--drivers/gpio/gpio-xilinx.c6
-rw-r--r--drivers/gpio/gpio-zevio.c4
-rw-r--r--drivers/gpio/gpio-zynq.c12
-rw-r--r--drivers/gpio/gpiolib-devres.c7
-rw-r--r--drivers/gpio/gpiolib-kunit.c358
-rw-r--r--drivers/gpio/gpiolib.c32
46 files changed, 960 insertions, 696 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 020e51e30317a..bbd0ebe2f1316 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -102,6 +102,14 @@ config GPIO_CDEV_V1
This ABI version is deprecated.
Please use the latest ABI for new developments.
+config GPIO_KUNIT
+ tristate "Build GPIO Kunit test cases"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Say Y here to build the module containing Kunit test cases verifying
+ the functionality of the GPIO subsystem.
+
config GPIO_GENERIC
depends on HAS_IOMEM # Only for IOMEM drivers
tristate
@@ -156,6 +164,7 @@ config GPIO_74XX_MMIO
config GPIO_ALTERA
tristate "Altera GPIO"
+ select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
Say Y or M here to build support for the Altera PIO device.
@@ -301,7 +310,7 @@ config GPIO_EM
config GPIO_EN7523
tristate "Airoha GPIO support"
- depends on ARCH_AIROHA
+ depends on ARCH_AIROHA || COMPILE_TEST
default ARCH_AIROHA
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
@@ -698,7 +707,7 @@ config GPIO_SPACEMIT_K1
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
- depends on PLAT_SPEAR
+ depends on PLAT_SPEAR || COMPILE_TEST
select GENERIC_IRQ_CHIP
help
Say yes here to support ST SPEAr SPI Chip Select as GPIO device.
@@ -805,8 +814,18 @@ config GPIO_VISCONTI
help
Say yes here to support GPIO on Tohisba Visconti.
+config GPIO_WAVESHARE_DSI_TOUCH
+ tristate "Waveshare GPIO controller for DSI panels"
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Enable support for the GPIO and PWM controller found on Waveshare DSI
+ TOUCH panel kits. It provides GPIOs (used for regulator control and
+ resets) and backlight support.
+
config GPIO_WCD934X
- tristate "Qualcomm Technologies Inc WCD9340/WCD9341 GPIO controller driver"
+ tristate "Qualcomm WCD9340/WCD9341 GPIO controller driver"
depends on MFD_WCD934X
help
This driver is to support GPIO block found on the Qualcomm Technologies
@@ -814,7 +833,7 @@ config GPIO_WCD934X
config GPIO_XGENE
bool "APM X-Gene GPIO controller support"
- depends on ARM64
+ depends on ARM64 || COMPILE_TEST
help
This driver is to support the GPIO block within the APM X-Gene SoC
platform's generic flash controller. The GPIO pins are muxed with
@@ -858,7 +877,7 @@ config GPIO_XTENSA
config GPIO_ZEVIO
bool "LSI ZEVIO SoC memory mapped GPIOs"
- depends on ARM
+ depends on ARM || COMPILE_TEST
help
Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
@@ -1093,15 +1112,6 @@ config GPIO_SCH311X
To compile this driver as a module, choose M here: the module will
be called gpio-sch311x.
-config GPIO_TS5500
- tristate "TS-5500 DIO blocks and compatibles"
- depends on TS5500 || COMPILE_TEST
- help
- This driver supports Digital I/O exposed by pin blocks found on some
- Technologic Systems platforms. It includes, but is not limited to, 3
- blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
- LCD port.
-
config GPIO_WINBOND
tristate "Winbond Super I/O GPIO support"
select ISA_BUS_API
@@ -2060,6 +2070,7 @@ config GPIO_VIRTIO
config GPIO_SIM
tristate "GPIO Simulator Module"
+ depends on SYSFS
select IRQ_SIM
select CONFIGFS_FS
help
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index b267598b517de..8ec03c9aec20d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
gpiolib-acpi-y := gpiolib-acpi-core.o gpiolib-acpi-quirks.o
obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
obj-$(CONFIG_GPIO_SHARED) += gpiolib-shared.o
+obj-$(CONFIG_GPIO_KUNIT) += gpiolib-kunit.o
# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o
@@ -194,7 +195,6 @@ obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o
obj-$(CONFIG_GPIO_TQMX86) += gpio-tqmx86.o
obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
-obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
@@ -205,6 +205,7 @@ obj-$(CONFIG_GPIO_VIRTUSER) += gpio-virtuser.o
obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o
obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
+obj-$(CONFIG_GPIO_WAVESHARE_DSI_TOUCH) += gpio-waveshare-dsi.o
obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index c226524efebab..5ca61cf5206aa 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -112,7 +112,7 @@ static int gen_74x164_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct gen_74x164_chip *chip;
- u32 nregs;
+ u32 nregs, init_state;
int ret;
/*
@@ -134,6 +134,21 @@ static int gen_74x164_probe(struct spi_device *spi)
chip->registers = nregs;
+ /*
+ * Optionally seed the chain with a board-specified pattern so the
+ * outputs come up in a known state on the first SPI write. The
+ * property follows the nxp,pcf8575 convention where bit N maps to
+ * GPIO line N. On this output-only device, bit=0 drives the line
+ * low and bit=1 drives it high. The bitmask covers up to 32 lines;
+ * any further outputs come up zeroed by devm_kzalloc().
+ */
+ if (!device_property_read_u32(dev, "lines-initial-states", &init_state)) {
+ unsigned int i;
+
+ for (i = 0; i < min(nregs, 4U); i++)
+ chip->buffer[nregs - 1 - i] = (init_state >> (i * 8)) & 0xff;
+ }
+
chip->gpiod_oe = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(chip->gpiod_oe))
return PTR_ERR(chip->gpiod_oe);
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index fe5bcaa90496a..350feea2afa3d 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -501,8 +501,8 @@ static int adnp_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adnp_i2c_id[] = {
- { "gpio-adnp" },
- { },
+ { .name = "gpio-adnp" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, adnp_i2c_id);
diff --git a/drivers/gpio/gpio-adp5585.c b/drivers/gpio/gpio-adp5585.c
index 0fd3cc26d017b..6f10fc6460080 100644
--- a/drivers/gpio/gpio-adp5585.c
+++ b/drivers/gpio/gpio-adp5585.c
@@ -507,8 +507,8 @@ static const struct adp5585_gpio_chip adp5589_gpio_chip_info = {
};
static const struct platform_device_id adp5585_gpio_id_table[] = {
- { "adp5585-gpio", (kernel_ulong_t)&adp5585_gpio_chip_info },
- { "adp5589-gpio", (kernel_ulong_t)&adp5589_gpio_chip_info },
+ { .name = "adp5585-gpio", .driver_data = (kernel_ulong_t)&adp5585_gpio_chip_info },
+ { .name = "adp5589-gpio", .driver_data = (kernel_ulong_t)&adp5589_gpio_chip_info },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(platform, adp5585_gpio_id_table);
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index 9508d764cce40..fe144360a88d8 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/generic.h>
#define ALTERA_GPIO_MAX_NGPIO 32
#define ALTERA_GPIO_DATA 0x0
@@ -26,7 +27,7 @@
/**
* struct altera_gpio_chip
-* @gc : GPIO chip structure.
+* @chip : Generic GPIO chip structure.
* @regs : memory mapped IO address for the controller registers.
* @gpio_lock : synchronization lock so that new irq/set/get requests
* will be blocked until the current one completes.
@@ -34,7 +35,7 @@
* (rising, falling, both, high)
*/
struct altera_gpio_chip {
- struct gpio_chip gc;
+ struct gpio_generic_chip chip;
void __iomem *regs;
raw_spinlock_t gpio_lock;
int interrupt_trigger;
@@ -106,72 +107,6 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d)
return 0;
}
-static int altera_gpio_get(struct gpio_chip *gc, unsigned offset)
-{
- struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
-
- return !!(readl(altera_gc->regs + ALTERA_GPIO_DATA) & BIT(offset));
-}
-
-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;
- unsigned int data_reg;
-
- raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
- data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA);
- if (value)
- data_reg |= BIT(offset);
- else
- 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)
-{
- struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
- unsigned long flags;
- unsigned int gpio_ddr;
-
- raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
- /* Set pin as input, assumes software controlled IP */
- gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR);
- gpio_ddr &= ~BIT(offset);
- writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR);
- raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
-
- return 0;
-}
-
-static int altera_gpio_direction_output(struct gpio_chip *gc,
- unsigned offset, int value)
-{
- struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
- unsigned long flags;
- unsigned int data_reg, gpio_ddr;
-
- raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
- /* Sets the GPIO value */
- data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA);
- if (value)
- data_reg |= BIT(offset);
- else
- data_reg &= ~BIT(offset);
- writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA);
-
- /* Set pin as output, assumes software controlled IP */
- gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR);
- gpio_ddr |= BIT(offset);
- writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR);
- raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
-
- return 0;
-}
-
static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
@@ -231,9 +166,12 @@ static const struct irq_chip altera_gpio_irq_chip = {
static int altera_gpio_probe(struct platform_device *pdev)
{
+ struct gpio_generic_chip_config config;
struct device *dev = &pdev->dev;
int reg, ret;
struct altera_gpio_chip *altera_gc;
+ struct gpio_generic_chip *chip;
+ struct gpio_chip *gc;
struct gpio_irq_chip *girq;
int mapped_irq;
@@ -243,35 +181,45 @@ static int altera_gpio_probe(struct platform_device *pdev)
raw_spin_lock_init(&altera_gc->gpio_lock);
+ altera_gc->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(altera_gc->regs))
+ return dev_err_probe(dev, PTR_ERR(altera_gc->regs),
+ "failed to ioremap memory resource\n");
+
+ chip = &altera_gc->chip;
+
+ config = (struct gpio_generic_chip_config) {
+ .dev = dev,
+ .sz = 4,
+ .dat = altera_gc->regs + ALTERA_GPIO_DATA,
+ .set = altera_gc->regs + ALTERA_GPIO_DATA,
+ .dirout = altera_gc->regs + ALTERA_GPIO_DIR,
+ };
+
+ ret = gpio_generic_chip_init(chip, &config);
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to init generic GPIO\n");
+
+ gc = &chip->gc;
+
if (device_property_read_u32(dev, "altr,ngpio", &reg))
/* By default assume maximum ngpio */
- altera_gc->gc.ngpio = ALTERA_GPIO_MAX_NGPIO;
+ gc->ngpio = ALTERA_GPIO_MAX_NGPIO;
else
- altera_gc->gc.ngpio = reg;
+ gc->ngpio = reg;
- if (altera_gc->gc.ngpio > ALTERA_GPIO_MAX_NGPIO) {
+ if (gc->ngpio > ALTERA_GPIO_MAX_NGPIO) {
dev_warn(&pdev->dev,
"ngpio is greater than %d, defaulting to %d\n",
ALTERA_GPIO_MAX_NGPIO, ALTERA_GPIO_MAX_NGPIO);
- altera_gc->gc.ngpio = ALTERA_GPIO_MAX_NGPIO;
+ gc->ngpio = ALTERA_GPIO_MAX_NGPIO;
}
- 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.owner = THIS_MODULE;
- altera_gc->gc.parent = &pdev->dev;
- altera_gc->gc.base = -1;
-
- altera_gc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev));
- if (!altera_gc->gc.label)
+ gc->base = -1;
+ gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev));
+ if (!gc->label)
return -ENOMEM;
- altera_gc->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(altera_gc->regs))
- return dev_err_probe(dev, PTR_ERR(altera_gc->regs), "failed to ioremap memory resource\n");
-
mapped_irq = platform_get_irq_optional(pdev, 0);
if (mapped_irq < 0)
goto skip_irq;
@@ -283,7 +231,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
}
altera_gc->interrupt_trigger = reg;
- girq = &altera_gc->gc.irq;
+ girq = &gc->irq;
gpio_irq_chip_set_chip(girq, &altera_gpio_irq_chip);
if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
@@ -300,7 +248,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
girq->parents[0] = mapped_irq;
skip_irq:
- ret = devm_gpiochip_add_data(dev, &altera_gc->gc, altera_gc);
+ ret = devm_gpiochip_add_data(dev, gc, altera_gc);
if (ret) {
dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
return ret;
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c
index 15fd5e210d747..8078b5d7b80c9 100644
--- a/drivers/gpio/gpio-amd8111.c
+++ b/drivers/gpio/gpio-amd8111.c
@@ -59,8 +59,8 @@
* want to register another driver on the same PCI id.
*/
static const struct pci_device_id pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 0 },
- { 0, }, /* terminate list */
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS) },
+ { }, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
diff --git a/drivers/gpio/gpio-bd72720.c b/drivers/gpio/gpio-bd72720.c
index d0f936ed80af3..306e234112090 100644
--- a/drivers/gpio/gpio-bd72720.c
+++ b/drivers/gpio/gpio-bd72720.c
@@ -263,8 +263,8 @@ static int gpo_bd72720_probe(struct platform_device *pdev)
}
static const struct platform_device_id bd72720_gpio_id[] = {
- { "bd72720-gpio" },
- { },
+ { .name = "bd72720-gpio" },
+ { }
};
MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c
index cc5b1746f2fe8..f829fc40c02be 100644
--- a/drivers/gpio/gpio-bd9571mwv.c
+++ b/drivers/gpio/gpio-bd9571mwv.c
@@ -110,8 +110,8 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id bd9571mwv_gpio_id_table[] = {
- { "bd9571mwv-gpio", ROHM_CHIP_TYPE_BD9571 },
- { "bd9574mwf-gpio", ROHM_CHIP_TYPE_BD9574 },
+ { .name = "bd9571mwv-gpio", .driver_data = ROHM_CHIP_TYPE_BD9571 },
+ { .name = "bd9574mwf-gpio", .driver_data = ROHM_CHIP_TYPE_BD9574 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table);
diff --git a/drivers/gpio/gpio-cros-ec.c b/drivers/gpio/gpio-cros-ec.c
index 435483826c6e5..9deda8a9d11aa 100644
--- a/drivers/gpio/gpio-cros-ec.c
+++ b/drivers/gpio/gpio-cros-ec.c
@@ -196,8 +196,8 @@ static int cros_ec_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id cros_ec_gpio_id[] = {
- { "cros-ec-gpio", 0 },
- {}
+ { .name = "cros-ec-gpio" },
+ { }
};
MODULE_DEVICE_TABLE(platform, cros_ec_gpio_id);
diff --git a/drivers/gpio/gpio-ds4520.c b/drivers/gpio/gpio-ds4520.c
index f52ecae382a45..5add662a7ef51 100644
--- a/drivers/gpio/gpio-ds4520.c
+++ b/drivers/gpio/gpio-ds4520.c
@@ -54,7 +54,7 @@ static const struct of_device_id ds4520_gpio_of_match_table[] = {
MODULE_DEVICE_TABLE(of, ds4520_gpio_of_match_table);
static const struct i2c_device_id ds4520_gpio_id_table[] = {
- { "ds4520-gpio" },
+ { .name = "ds4520-gpio" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds4520_gpio_id_table);
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 15cebc8b5d663..c1f3d83a67c10 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -694,6 +694,7 @@ static const struct acpi_device_id dwapb_acpi_match[] = {
{"APMC0D07", GPIO_REG_OFFSET_V1},
{"APMC0D81", GPIO_REG_OFFSET_V2},
{"FUJI200A", GPIO_REG_OFFSET_V1},
+ {"LECA0001", GPIO_REG_OFFSET_V1},
{ }
};
MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match);
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 1f56e44ffc9a3..8784e433e1ffb 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -323,8 +323,7 @@ static int ep93xx_setup_irqs(struct platform_device *pdev,
}
girq->default_type = IRQ_TYPE_NONE;
- /* TODO: replace with handle_bad_irq() once we are fully hierarchical */
- girq->handler = handle_simple_irq;
+ girq->handler = handle_bad_irq;
return 0;
}
diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c
index afc1b8461dabb..45b02d36e66ff 100644
--- a/drivers/gpio/gpio-fxl6408.c
+++ b/drivers/gpio/gpio-fxl6408.c
@@ -150,7 +150,7 @@ static const __maybe_unused struct of_device_id fxl6408_dt_ids[] = {
MODULE_DEVICE_TABLE(of, fxl6408_dt_ids);
static const struct i2c_device_id fxl6408_id[] = {
- { "fxl6408" },
+ { .name = "fxl6408" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxl6408_id);
diff --git a/drivers/gpio/gpio-gw-pld.c b/drivers/gpio/gpio-gw-pld.c
index 2e5d97b7363fd..bf1f91c3c4a8b 100644
--- a/drivers/gpio/gpio-gw-pld.c
+++ b/drivers/gpio/gpio-gw-pld.c
@@ -109,7 +109,7 @@ static int gw_pld_probe(struct i2c_client *client)
}
static const struct i2c_device_id gw_pld_id[] = {
- { "gw-pld", },
+ { .name = "gw-pld" },
{ }
};
MODULE_DEVICE_TABLE(i2c, gw_pld_id);
diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c
index f34d87869c8b0..669b139cd499b 100644
--- a/drivers/gpio/gpio-ixp4xx.c
+++ b/drivers/gpio/gpio-ixp4xx.c
@@ -311,12 +311,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
}
g->chip.gc.ngpio = 16;
g->chip.gc.label = "IXP4XX_GPIO_CHIP";
- /*
- * TODO: when we have migrated to device tree and all GPIOs
- * are fetched using phandles, set this to -1 to get rid of
- * the fixed gpiochip base.
- */
- g->chip.gc.base = 0;
+ g->chip.gc.base = -1;
g->chip.gc.parent = &pdev->dev;
g->chip.gc.owner = THIS_MODULE;
diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c
index f4413fa5a8110..0d1bd9df265a4 100644
--- a/drivers/gpio/gpio-lp873x.c
+++ b/drivers/gpio/gpio-lp873x.c
@@ -156,7 +156,7 @@ static int lp873x_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id lp873x_gpio_id_table[] = {
- { "lp873x-gpio", },
+ { .name = "lp873x-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, lp873x_gpio_id_table);
diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c
index 0f337c1283b22..3ac78f2b0fa70 100644
--- a/drivers/gpio/gpio-lp87565.c
+++ b/drivers/gpio/gpio-lp87565.c
@@ -171,7 +171,7 @@ static int lp87565_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id lp87565_gpio_id_table[] = {
- { "lp87565-q1-gpio", },
+ { .name = "lp87565-q1-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, lp87565_gpio_id_table);
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index 621d609ece904..62f2434c0d79b 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -53,7 +53,7 @@ static void max7300_remove(struct i2c_client *client)
}
static const struct i2c_device_id max7300_id[] = {
- { "max7300" },
+ { .name = "max7300" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max7300_id);
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 281ba1740a6a0..24c67c9129549 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -103,16 +103,16 @@ static uint64_t max732x_features[] = {
};
static const struct i2c_device_id max732x_id[] = {
- { "max7319", MAX7319 },
- { "max7320", MAX7320 },
- { "max7321", MAX7321 },
- { "max7322", MAX7322 },
- { "max7323", MAX7323 },
- { "max7324", MAX7324 },
- { "max7325", MAX7325 },
- { "max7326", MAX7326 },
- { "max7327", MAX7327 },
- { },
+ { .name = "max7319", .driver_data = MAX7319 },
+ { .name = "max7320", .driver_data = MAX7320 },
+ { .name = "max7321", .driver_data = MAX7321 },
+ { .name = "max7322", .driver_data = MAX7322 },
+ { .name = "max7323", .driver_data = MAX7323 },
+ { .name = "max7324", .driver_data = MAX7324 },
+ { .name = "max7325", .driver_data = MAX7325 },
+ { .name = "max7326", .driver_data = MAX7326 },
+ { .name = "max7327", .driver_data = MAX7327 },
+ { }
};
MODULE_DEVICE_TABLE(i2c, max732x_id);
diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c
index e6c85411c695e..2bf3b55a61b5e 100644
--- a/drivers/gpio/gpio-max77620.c
+++ b/drivers/gpio/gpio-max77620.c
@@ -367,7 +367,7 @@ static int max77620_gpio_probe(struct platform_device *pdev)
static const struct platform_device_id max77620_gpio_devtype[] = {
{ .name = "max77620-gpio", },
{ .name = "max20024-gpio", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype);
diff --git a/drivers/gpio/gpio-max77759.c b/drivers/gpio/gpio-max77759.c
index 3bf9f23d15328..c6bdac7fb44a6 100644
--- a/drivers/gpio/gpio-max77759.c
+++ b/drivers/gpio/gpio-max77759.c
@@ -502,7 +502,7 @@ static const struct of_device_id max77759_gpio_of_id[] = {
MODULE_DEVICE_TABLE(of, max77759_gpio_of_id);
static const struct platform_device_id max77759_gpio_platform_id[] = {
- { "max77759-gpio", },
+ { .name = "max77759-gpio" },
{ }
};
MODULE_DEVICE_TABLE(platform, max77759_gpio_platform_id);
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 12f11a6c96653..7e2690d92df6f 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -330,13 +330,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
ret = enable_irq_wake(port->irq_high);
else
ret = enable_irq_wake(port->irq);
- port->wakeup_pads |= (1 << gpio_idx);
+ port->wakeup_pads |= BIT(gpio_idx);
} else {
if (port->irq_high && (gpio_idx >= 16))
ret = disable_irq_wake(port->irq_high);
else
ret = disable_irq_wake(port->irq);
- port->wakeup_pads &= ~(1 << gpio_idx);
+ port->wakeup_pads &= ~BIT(gpio_idx);
}
return ret;
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index b9c905a0ffa90..2ee35e855e4da 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -86,49 +86,49 @@
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
static const struct i2c_device_id pca953x_id[] = {
- { "pca6408", 8 | PCA953X_TYPE | PCA_INT, },
- { "pca6416", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
- { "pca9506", 40 | PCA953X_TYPE | PCA_INT, },
- { "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
- { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca9536", 4 | PCA953X_TYPE, },
- { "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
- { "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
- { "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
- { "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca9556", 8 | PCA953X_TYPE, },
- { "pca9557", 8 | PCA953X_TYPE, },
- { "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
- { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
- { "pca9698", 40 | PCA953X_TYPE, },
+ { .name = "pca6408", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca6416", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9505", .driver_data = 40 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9506", .driver_data = 40 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9534", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9535", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9536", .driver_data = 4 | PCA953X_TYPE },
+ { .name = "pca9537", .driver_data = 4 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9538", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9539", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9554", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9555", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca9556", .driver_data = 8 | PCA953X_TYPE },
+ { .name = "pca9557", .driver_data = 8 | PCA953X_TYPE },
+ { .name = "pca9574", .driver_data = 8 | PCA957X_TYPE | PCA_INT },
+ { .name = "pca9575", .driver_data = 16 | PCA957X_TYPE | PCA_INT },
+ { .name = "pca9698", .driver_data = 40 | PCA953X_TYPE },
- { "pcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal6534", 34 | PCAL653X_TYPE | PCA_LATCH_INT, },
- { "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal9554b", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
+ { .name = "pcal6408", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal6416", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal6524", .driver_data = 24 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal6534", .driver_data = 34 | PCAL653X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal9535", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal9554b", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "pcal9555a", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
- { "max7310", 8 | PCA953X_TYPE, },
- { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
- { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
- { "max7315", 8 | PCA953X_TYPE | PCA_INT, },
- { "max7318", 16 | PCA953X_TYPE | PCA_INT, },
- { "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
- { "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
- { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
- { "tca6418", 18 | TCA6418_TYPE | PCA_INT, },
- { "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
- { "tca9538", 8 | PCA953X_TYPE | PCA_INT, },
- { "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
- { "tca9554", 8 | PCA953X_TYPE | PCA_INT, },
- { "xra1202", 8 | PCA953X_TYPE },
+ { .name = "max7310", .driver_data = 8 | PCA953X_TYPE },
+ { .name = "max7312", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "max7313", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "max7315", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "max7318", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "pca6107", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca6408", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca6416", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca6418", .driver_data = 18 | TCA6418_TYPE | PCA_INT },
+ { .name = "tca6424", .driver_data = 24 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca9538", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca9539", .driver_data = 16 | PCA953X_TYPE | PCA_INT },
+ { .name = "tca9554", .driver_data = 8 | PCA953X_TYPE | PCA_INT },
+ { .name = "xra1202", .driver_data = 8 | PCA953X_TYPE },
- { "tcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
- { "tcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
+ { .name = "tcal6408", .driver_data = 8 | PCA953X_TYPE | PCA_LATCH_INT },
+ { .name = "tcal6416", .driver_data = 16 | PCA953X_TYPE | PCA_LATCH_INT },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
@@ -877,11 +877,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_high, gc->ngpio);
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_low, gc->ngpio);
- bitmap_complement(reg_direction, reg_direction, gc->ngpio);
- bitmap_and(irq_mask, irq_mask, reg_direction, gc->ngpio);
/* Look for any newly setup interrupt */
- for_each_set_bit(level, irq_mask, gc->ngpio)
+ for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio)
pca953x_gpio_direction_input(&chip->gpio_chip, level);
mutex_unlock(&chip->irq_lock);
@@ -1005,8 +1003,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin
bitmap_and(cur_stat, cur_stat, chip->irq_mask, gc->ngpio);
bitmap_or(pending, pending, cur_stat, gc->ngpio);
- bitmap_complement(cur_stat, new_stat, gc->ngpio);
- bitmap_and(cur_stat, cur_stat, reg_direction, gc->ngpio);
+ bitmap_andnot(cur_stat, reg_direction, new_stat, gc->ngpio);
bitmap_and(old_stat, cur_stat, chip->irq_trig_level_low, gc->ngpio);
bitmap_and(old_stat, old_stat, chip->irq_mask, gc->ngpio);
bitmap_or(pending, pending, old_stat, gc->ngpio);
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c
index 4a368803fb038..7a47a9aa0414e 100644
--- a/drivers/gpio/gpio-pca9570.c
+++ b/drivers/gpio/gpio-pca9570.c
@@ -163,9 +163,9 @@ static const struct pca9570_chip_data slg7xl45106_gpio = {
};
static const struct i2c_device_id pca9570_id_table[] = {
- { "pca9570", (kernel_ulong_t)&pca9570_gpio},
- { "pca9571", (kernel_ulong_t)&pca9571_gpio },
- { "slg7xl45106", (kernel_ulong_t)&slg7xl45106_gpio },
+ { .name = "pca9570", .driver_data = (kernel_ulong_t)&pca9570_gpio },
+ { .name = "pca9571", .driver_data = (kernel_ulong_t)&pca9571_gpio },
+ { .name = "slg7xl45106", .driver_data = (kernel_ulong_t)&slg7xl45106_gpio },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 3b9de8c3d924c..c942b959571b2 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -20,19 +20,19 @@
#include <linux/spinlock.h>
static const struct i2c_device_id pcf857x_id[] = {
- { "pcf8574", 8 },
- { "pcf8574a", 8 },
- { "pca8574", 8 },
- { "pca9670", 8 },
- { "pca9672", 8 },
- { "pca9674", 8 },
- { "pcf8575", 16 },
- { "pca8575", 16 },
- { "pca9671", 16 },
- { "pca9673", 16 },
- { "pca9675", 16 },
- { "max7328", 8 },
- { "max7329", 8 },
+ { .name = "pcf8574", .driver_data = 8 },
+ { .name = "pcf8574a", .driver_data = 8 },
+ { .name = "pca8574", .driver_data = 8 },
+ { .name = "pca9670", .driver_data = 8 },
+ { .name = "pca9672", .driver_data = 8 },
+ { .name = "pca9674", .driver_data = 8 },
+ { .name = "pcf8575", .driver_data = 16 },
+ { .name = "pca8575", .driver_data = 16 },
+ { .name = "pca9671", .driver_data = 16 },
+ { .name = "pca9673", .driver_data = 16 },
+ { .name = "pca9675", .driver_data = 16 },
+ { .name = "max7328", .driver_data = 8 },
+ { .name = "max7329", .driver_data = 8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 664cf1eef494c..5d61053e0596a 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -708,15 +708,15 @@ static int pxa_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id gpio_id_table[] = {
- { "pxa25x-gpio", (unsigned long)&pxa25x_id },
- { "pxa26x-gpio", (unsigned long)&pxa26x_id },
- { "pxa27x-gpio", (unsigned long)&pxa27x_id },
- { "pxa3xx-gpio", (unsigned long)&pxa3xx_id },
- { "pxa93x-gpio", (unsigned long)&pxa93x_id },
- { "mmp-gpio", (unsigned long)&mmp_id },
- { "mmp2-gpio", (unsigned long)&mmp2_id },
- { "pxa1928-gpio", (unsigned long)&pxa1928_id },
- { },
+ { .name = "pxa25x-gpio", .driver_data = (unsigned long)&pxa25x_id },
+ { .name = "pxa26x-gpio", .driver_data = (unsigned long)&pxa26x_id },
+ { .name = "pxa27x-gpio", .driver_data = (unsigned long)&pxa27x_id },
+ { .name = "pxa3xx-gpio", .driver_data = (unsigned long)&pxa3xx_id },
+ { .name = "pxa93x-gpio", .driver_data = (unsigned long)&pxa93x_id },
+ { .name = "mmp-gpio", .driver_data = (unsigned long)&mmp_id },
+ { .name = "mmp2-gpio", .driver_data = (unsigned long)&mmp2_id },
+ { .name = "pxa1928-gpio", .driver_data = (unsigned long)&pxa1928_id },
+ { }
};
static struct platform_driver pxa_gpio_driver = {
diff --git a/drivers/gpio/gpio-realtek-otto.c b/drivers/gpio/gpio-realtek-otto.c
index 5e3152c2e51a8..37ef56f453187 100644
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -40,16 +40,18 @@
#define REALTEK_GPIO_PORTS_PER_BANK 4
/**
- * realtek_gpio_ctrl - Realtek Otto GPIO driver data
+ * struct realtek_gpio_ctrl - Realtek Otto GPIO driver data
*
* @chip: Associated gpio_generic_chip instance
* @base: Base address of the register block for a GPIO bank
+ * @cpumask_base: Base address of the per-CPU interrupt mask registers
+ * @cpu_irq_maskable: CPUs that can receive GPIO interrupts
* @lock: Lock for accessing the IRQ registers and values
* @intr_mask: Mask for interrupts lines
* @intr_type: Interrupt type selection
* @bank_read: Read a bank setting as a single 32-bit value
* @bank_write: Write a bank setting as a single 32-bit value
- * @imr_line_pos: Bit shift of an IRQ line's IMR value.
+ * @line_imr_pos: Bit shift of an IRQ line's IMR value.
*
* The DIR, DATA, and ISR registers consist of four 8-bit port values, packed
* into a single 32-bit register. Use @bank_read (@bank_write) to get (assign)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 9ae4a41a24277..51b4d69b87403 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -31,6 +31,7 @@ struct gpio_regmap {
unsigned int reg_clr_base;
unsigned int reg_dir_in_base;
unsigned int reg_dir_out_base;
+ unsigned long *fixed_direction_mask;
unsigned long *fixed_direction_output;
#ifdef CONFIG_REGMAP_IRQ
@@ -138,6 +139,20 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
return regmap_write(gpio->regmap, reg, mask);
}
+static bool gpio_regmap_fixed_direction(struct gpio_regmap *gpio,
+ unsigned int offset)
+{
+ if (!gpio->fixed_direction_output)
+ return false;
+
+ /* In this case only some GPIOs are fixed as input/output */
+ if (gpio->fixed_direction_mask &&
+ !test_bit(offset, gpio->fixed_direction_mask))
+ return false;
+
+ return true;
+}
+
static int gpio_regmap_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
@@ -145,7 +160,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
unsigned int base, val, reg, mask;
int invert, ret;
- if (gpio->fixed_direction_output) {
+ if (gpio_regmap_fixed_direction(gpio, offset)) {
if (test_bit(offset, gpio->fixed_direction_output))
return GPIO_LINE_DIRECTION_OUT;
else
@@ -181,6 +196,22 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
return GPIO_LINE_DIRECTION_IN;
}
+static int gpio_regmap_try_direction_fixed(struct gpio_regmap *gpio,
+ unsigned int offset, bool output)
+{
+ if (test_bit(offset, gpio->fixed_direction_output)) {
+ if (output)
+ return 0;
+ else
+ return -EINVAL;
+ } else {
+ if (output)
+ return -EINVAL;
+ else
+ return 0;
+ }
+}
+
static int gpio_regmap_set_direction(struct gpio_chip *chip,
unsigned int offset, bool output)
{
@@ -188,6 +219,13 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip,
unsigned int base, val, reg, mask;
int invert, ret;
+ /*
+ * If the direction is fixed, only accept the fixed
+ * direction in this call.
+ */
+ if (gpio_regmap_fixed_direction(gpio, offset))
+ return gpio_regmap_try_direction_fixed(gpio, offset, output);
+
if (gpio->reg_dir_out_base) {
base = gpio_regmap_addr(gpio->reg_dir_out_base);
invert = 0;
@@ -219,6 +257,20 @@ static int gpio_regmap_direction_input(struct gpio_chip *chip,
static int gpio_regmap_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
+ struct gpio_regmap *gpio = gpiochip_get_data(chip);
+ int ret;
+
+ /*
+ * First check if this is gonna work on a fixed direction line,
+ * if it doesn't (i.e. this is a fixed input line), then do not
+ * attempt to set the output value either and just bail out.
+ */
+ if (gpio_regmap_fixed_direction(gpio, offset)) {
+ ret = gpio_regmap_try_direction_fixed(gpio, offset, true);
+ if (ret)
+ return ret;
+ }
+
gpio_regmap_set(chip, offset, value);
return gpio_regmap_set_direction(chip, offset, true);
@@ -302,12 +354,23 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
goto err_free_gpio;
}
+ if (config->fixed_direction_mask) {
+ gpio->fixed_direction_mask = bitmap_alloc(chip->ngpio,
+ GFP_KERNEL);
+ if (!gpio->fixed_direction_mask) {
+ ret = -ENOMEM;
+ goto err_free_gpio;
+ }
+ bitmap_copy(gpio->fixed_direction_mask,
+ config->fixed_direction_mask, chip->ngpio);
+ }
+
if (config->fixed_direction_output) {
gpio->fixed_direction_output = bitmap_alloc(chip->ngpio,
GFP_KERNEL);
if (!gpio->fixed_direction_output) {
ret = -ENOMEM;
- goto err_free_gpio;
+ goto err_free_bitmap_dirmask;
}
bitmap_copy(gpio->fixed_direction_output,
config->fixed_direction_output, chip->ngpio);
@@ -329,7 +392,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
ret = gpiochip_add_data(chip, gpio);
if (ret < 0)
- goto err_free_bitmap;
+ goto err_free_bitmap_output;
#ifdef CONFIG_REGMAP_IRQ
if (config->regmap_irq_chip) {
@@ -355,8 +418,10 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
err_remove_gpiochip:
gpiochip_remove(chip);
-err_free_bitmap:
+err_free_bitmap_output:
bitmap_free(gpio->fixed_direction_output);
+err_free_bitmap_dirmask:
+ bitmap_free(gpio->fixed_direction_mask);
err_free_gpio:
kfree(gpio);
return ERR_PTR(ret);
@@ -376,6 +441,7 @@ void gpio_regmap_unregister(struct gpio_regmap *gpio)
gpiochip_remove(&gpio->gpio_chip);
bitmap_free(gpio->fixed_direction_output);
+ bitmap_free(gpio->fixed_direction_mask);
kfree(gpio);
}
EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index 0da2c5a45843e..f0f570527cf23 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -695,9 +695,9 @@ static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item,
pdev = dev->pdev;
if (pdev)
- return sprintf(page, "%s\n", dev_name(&pdev->dev));
+ return sysfs_emit(page, "%s\n", dev_name(&pdev->dev));
- return sprintf(page, "gpio-sim.%d\n", dev->id);
+ return sysfs_emit(page, "gpio-sim.%d\n", dev->id);
}
CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name);
@@ -711,7 +711,7 @@ gpio_sim_device_config_live_show(struct config_item *item, char *page)
scoped_guard(mutex, &dev->lock)
live = gpio_sim_device_is_live(dev);
- return sprintf(page, "%c\n", live ? '1' : '0');
+ return sysfs_emit(page, "%c\n", live ? '1' : '0');
}
static unsigned int gpio_sim_get_line_names_size(struct gpio_sim_bank *bank)
@@ -1059,7 +1059,7 @@ static int gpio_sim_emit_chip_name(struct device *dev, void *data)
return 0;
if (device_match_fwnode(dev, ctx->swnode))
- return sprintf(ctx->page, "%s\n", dev_name(dev));
+ return sysfs_emit(ctx->page, "%s\n", dev_name(dev));
return 0;
}
@@ -1077,7 +1077,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
return device_for_each_child(&dev->pdev->dev, &ctx,
gpio_sim_emit_chip_name);
- return sprintf(page, "none\n");
+ return sysfs_emit(page, "none\n");
}
CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name);
@@ -1090,7 +1090,7 @@ gpio_sim_bank_config_label_show(struct config_item *item, char *page)
guard(mutex)(&dev->lock);
- return sprintf(page, "%s\n", bank->label ?: "");
+ return sysfs_emit(page, "%s\n", bank->label ?: "");
}
static ssize_t gpio_sim_bank_config_label_store(struct config_item *item,
@@ -1125,7 +1125,7 @@ gpio_sim_bank_config_num_lines_show(struct config_item *item, char *page)
guard(mutex)(&dev->lock);
- return sprintf(page, "%u\n", bank->num_lines);
+ return sysfs_emit(page, "%u\n", bank->num_lines);
}
static ssize_t
@@ -1171,7 +1171,7 @@ gpio_sim_line_config_name_show(struct config_item *item, char *page)
guard(mutex)(&dev->lock);
- return sprintf(page, "%s\n", line->name ?: "");
+ return sysfs_emit(page, "%s\n", line->name ?: "");
}
static ssize_t gpio_sim_line_config_name_store(struct config_item *item,
@@ -1206,7 +1206,7 @@ gpio_sim_line_config_valid_show(struct config_item *item, char *page)
guard(mutex)(&dev->lock);
- return sprintf(page, "%c\n", line->valid ? '1' : '0');
+ return sysfs_emit(page, "%c\n", line->valid ? '1' : '0');
}
static ssize_t gpio_sim_line_config_valid_store(struct config_item *item,
@@ -1244,7 +1244,7 @@ static ssize_t gpio_sim_hog_config_name_show(struct config_item *item,
guard(mutex)(&dev->lock);
- return sprintf(page, "%s\n", hog->name ?: "");
+ return sysfs_emit(page, "%s\n", hog->name ?: "");
}
static ssize_t gpio_sim_hog_config_name_store(struct config_item *item,
@@ -1298,7 +1298,7 @@ static ssize_t gpio_sim_hog_config_direction_show(struct config_item *item,
return -EINVAL;
}
- return sprintf(page, "%s\n", repr);
+ return sysfs_emit(page, "%s\n", repr);
}
static ssize_t
@@ -1338,7 +1338,7 @@ static ssize_t gpio_sim_hog_config_active_low_show(struct config_item *item,
guard(mutex)(&dev->lock);
- return sprintf(page, "%c\n", hog->active_low ? '1' : '0');
+ return sysfs_emit(page, "%c\n", hog->active_low ? '1' : '0');
}
static ssize_t
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index aa7c3e44234f5..d9a2dedf50eae 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -19,6 +19,7 @@
#include <dt-bindings/gpio/tegra186-gpio.h>
#include <dt-bindings/gpio/tegra194-gpio.h>
#include <dt-bindings/gpio/tegra234-gpio.h>
+#include <dt-bindings/gpio/nvidia,tegra238-gpio.h>
#include <dt-bindings/gpio/tegra241-gpio.h>
#include <dt-bindings/gpio/tegra256-gpio.h>
#include <dt-bindings/gpio/nvidia,tegra264-gpio.h>
@@ -1239,6 +1240,67 @@ static const struct tegra_gpio_soc tegra234_aon_soc = {
.has_vm_support = false,
};
+#define TEGRA238_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
+ TEGRA_GPIO_PORT(TEGRA238_MAIN, _name, _bank, _port, _pins)
+
+static const struct tegra_gpio_port tegra238_main_ports[] = {
+ TEGRA238_MAIN_GPIO_PORT(A, 0, 0, 8),
+ TEGRA238_MAIN_GPIO_PORT(B, 0, 1, 5),
+ TEGRA238_MAIN_GPIO_PORT(C, 0, 2, 8),
+ TEGRA238_MAIN_GPIO_PORT(D, 0, 3, 8),
+ TEGRA238_MAIN_GPIO_PORT(E, 0, 4, 4),
+ TEGRA238_MAIN_GPIO_PORT(F, 0, 5, 8),
+ TEGRA238_MAIN_GPIO_PORT(G, 0, 6, 8),
+ TEGRA238_MAIN_GPIO_PORT(H, 0, 7, 6),
+ TEGRA238_MAIN_GPIO_PORT(J, 1, 0, 8),
+ TEGRA238_MAIN_GPIO_PORT(K, 1, 1, 4),
+ TEGRA238_MAIN_GPIO_PORT(L, 1, 2, 8),
+ TEGRA238_MAIN_GPIO_PORT(M, 1, 3, 8),
+ TEGRA238_MAIN_GPIO_PORT(N, 1, 4, 3),
+ TEGRA238_MAIN_GPIO_PORT(P, 1, 5, 8),
+ TEGRA238_MAIN_GPIO_PORT(Q, 1, 6, 3),
+ TEGRA238_MAIN_GPIO_PORT(R, 2, 0, 8),
+ TEGRA238_MAIN_GPIO_PORT(S, 2, 1, 8),
+ TEGRA238_MAIN_GPIO_PORT(T, 2, 2, 8),
+ TEGRA238_MAIN_GPIO_PORT(U, 2, 3, 6),
+ TEGRA238_MAIN_GPIO_PORT(V, 2, 4, 2),
+ TEGRA238_MAIN_GPIO_PORT(W, 3, 0, 8),
+ TEGRA238_MAIN_GPIO_PORT(X, 3, 1, 2)
+};
+
+static const struct tegra_gpio_soc tegra238_main_soc = {
+ .num_ports = ARRAY_SIZE(tegra238_main_ports),
+ .ports = tegra238_main_ports,
+ .name = "tegra238-gpio",
+ .instance = 0,
+ .num_irqs_per_bank = 8,
+ .has_vm_support = true,
+};
+
+#define TEGRA238_AON_GPIO_PORT(_name, _bank, _port, _pins) \
+ TEGRA_GPIO_PORT(TEGRA238_AON, _name, _bank, _port, _pins)
+
+static const struct tegra_gpio_port tegra238_aon_ports[] = {
+ TEGRA238_AON_GPIO_PORT(AA, 0, 0, 8),
+ TEGRA238_AON_GPIO_PORT(BB, 0, 1, 1),
+ TEGRA238_AON_GPIO_PORT(CC, 0, 2, 8),
+ TEGRA238_AON_GPIO_PORT(DD, 0, 3, 8),
+ TEGRA238_AON_GPIO_PORT(EE, 0, 4, 6),
+ TEGRA238_AON_GPIO_PORT(FF, 0, 5, 8),
+ TEGRA238_AON_GPIO_PORT(GG, 0, 6, 8),
+ TEGRA238_AON_GPIO_PORT(HH, 0, 7, 4)
+};
+
+static const struct tegra_gpio_soc tegra238_aon_soc = {
+ .num_ports = ARRAY_SIZE(tegra238_aon_ports),
+ .ports = tegra238_aon_ports,
+ .name = "tegra238-gpio-aon",
+ .instance = 1,
+ .num_irqs_per_bank = 8,
+ .has_gte = true,
+ .has_vm_support = false,
+};
+
#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
TEGRA_GPIO_PORT(TEGRA241_MAIN, _name, _bank, _port, _pins)
@@ -1333,6 +1395,7 @@ static const struct tegra_gpio_soc tegra264_aon_soc = {
.name = "tegra264-gpio-aon",
.instance = 1,
.num_irqs_per_bank = 8,
+ .has_gte = true,
.has_vm_support = true,
};
@@ -1448,6 +1511,12 @@ static const struct of_device_id tegra186_gpio_of_match[] = {
.compatible = "nvidia,tegra234-gpio-aon",
.data = &tegra234_aon_soc
}, {
+ .compatible = "nvidia,tegra238-gpio",
+ .data = &tegra238_main_soc
+ }, {
+ .compatible = "nvidia,tegra238-gpio-aon",
+ .data = &tegra238_aon_soc
+ }, {
.compatible = "nvidia,tegra256-gpio",
.data = &tegra256_main_soc
}, {
diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c
index 866ff2d436d53..c38538653e991 100644
--- a/drivers/gpio/gpio-tpic2810.c
+++ b/drivers/gpio/gpio-tpic2810.c
@@ -112,7 +112,7 @@ static int tpic2810_probe(struct i2c_client *client)
}
static const struct i2c_device_id tpic2810_id_table[] = {
- { "tpic2810", },
+ { .name = "tpic2810" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, tpic2810_id_table);
diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c
index df770ecf28bc4..f29d8485ab331 100644
--- a/drivers/gpio/gpio-tps65086.c
+++ b/drivers/gpio/gpio-tps65086.c
@@ -91,7 +91,7 @@ static int tps65086_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id tps65086_gpio_id_table[] = {
- { "tps65086-gpio", },
+ { .name = "tps65086-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65086_gpio_id_table);
diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c
index 3b4c41f5ef554..bf85663349fb5 100644
--- a/drivers/gpio/gpio-tps65218.c
+++ b/drivers/gpio/gpio-tps65218.c
@@ -201,7 +201,7 @@ static const struct of_device_id tps65218_dt_match[] = {
MODULE_DEVICE_TABLE(of, tps65218_dt_match);
static const struct platform_device_id tps65218_gpio_id_table[] = {
- { "tps65218-gpio", },
+ { .name = "tps65218-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table);
diff --git a/drivers/gpio/gpio-tps65219.c b/drivers/gpio/gpio-tps65219.c
index 158f63bcf10cd..457fd8a589e89 100644
--- a/drivers/gpio/gpio-tps65219.c
+++ b/drivers/gpio/gpio-tps65219.c
@@ -249,8 +249,8 @@ static int tps65219_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id tps6521x_gpio_id_table[] = {
- { "tps65214-gpio", TPS65214 },
- { "tps65219-gpio", TPS65219 },
+ { .name = "tps65214-gpio", .driver_data = TPS65214 },
+ { .name = "tps65219-gpio", .driver_data = TPS65219 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps6521x_gpio_id_table);
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
index 7a2c5685c2fdb..cf3fa49a70974 100644
--- a/drivers/gpio/gpio-tps65912.c
+++ b/drivers/gpio/gpio-tps65912.c
@@ -115,7 +115,7 @@ static int tps65912_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id tps65912_gpio_id_table[] = {
- { "tps65912-gpio", },
+ { .name = "tps65912-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65912_gpio_id_table);
diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c
index d9ee8fc77ccdf..b46b48e56c565 100644
--- a/drivers/gpio/gpio-ts4900.c
+++ b/drivers/gpio/gpio-ts4900.c
@@ -175,7 +175,7 @@ static int ts4900_gpio_probe(struct i2c_client *client)
}
static const struct i2c_device_id ts4900_gpio_id_table[] = {
- { "ts4900-gpio", },
+ { .name = "ts4900-gpio" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table);
diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c
deleted file mode 100644
index 3c7f2efe10fd7..0000000000000
--- a/drivers/gpio/gpio-ts5500.c
+++ /dev/null
@@ -1,446 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Digital I/O driver for Technologic Systems TS-5500
- *
- * Copyright (c) 2012 Savoir-faire Linux Inc.
- * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * Technologic Systems platforms have pin blocks, exposing several Digital
- * Input/Output lines (DIO). This driver aims to support single pin blocks.
- * In that sense, the support is not limited to the TS-5500 blocks.
- * Actually, the following platforms have DIO support:
- *
- * TS-5500:
- * Documentation: https://docs.embeddedts.com/TS-5500
- * Blocks: DIO1, DIO2 and LCD port.
- *
- * TS-5600:
- * Documentation: https://docs.embeddedts.com/TS-5600
- * Blocks: LCD port (identical to TS-5500 LCD).
- */
-
-#include <linux/bitops.h>
-#include <linux/gpio/driver.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-/* List of supported Technologic Systems platforms DIO blocks */
-enum ts5500_blocks { TS5500_DIO1, TS5500_DIO2, TS5500_LCD, TS5600_LCD };
-
-struct ts5500_priv {
- const struct ts5500_dio *pinout;
- struct gpio_chip gpio_chip;
- spinlock_t lock;
- bool strap;
- u8 hwirq;
-};
-
-/*
- * Hex 7D is used to control several blocks (e.g. DIO2 and LCD port).
- * This flag ensures that the region has been requested by this driver.
- */
-static bool hex7d_reserved;
-
-/*
- * This structure is used to describe capabilities of DIO lines,
- * such as available directions and connected interrupt (if any).
- */
-struct ts5500_dio {
- const u8 value_addr;
- const u8 value_mask;
- const u8 control_addr;
- const u8 control_mask;
- const bool no_input;
- const bool no_output;
- const u8 irq;
-};
-
-#define TS5500_DIO_IN_OUT(vaddr, vbit, caddr, cbit) \
- { \
- .value_addr = vaddr, \
- .value_mask = BIT(vbit), \
- .control_addr = caddr, \
- .control_mask = BIT(cbit), \
- }
-
-#define TS5500_DIO_IN(addr, bit) \
- { \
- .value_addr = addr, \
- .value_mask = BIT(bit), \
- .no_output = true, \
- }
-
-#define TS5500_DIO_IN_IRQ(addr, bit, _irq) \
- { \
- .value_addr = addr, \
- .value_mask = BIT(bit), \
- .no_output = true, \
- .irq = _irq, \
- }
-
-#define TS5500_DIO_OUT(addr, bit) \
- { \
- .value_addr = addr, \
- .value_mask = BIT(bit), \
- .no_input = true, \
- }
-
-/*
- * Input/Output DIO lines are programmed in groups of 4. Their values are
- * available through 4 consecutive bits in a value port, whereas the direction
- * of these 4 lines is driven by only 1 bit in a control port.
- */
-#define TS5500_DIO_GROUP(vaddr, vbitfrom, caddr, cbit) \
- TS5500_DIO_IN_OUT(vaddr, vbitfrom + 0, caddr, cbit), \
- TS5500_DIO_IN_OUT(vaddr, vbitfrom + 1, caddr, cbit), \
- TS5500_DIO_IN_OUT(vaddr, vbitfrom + 2, caddr, cbit), \
- TS5500_DIO_IN_OUT(vaddr, vbitfrom + 3, caddr, cbit)
-
-/*
- * TS-5500 DIO1 block
- *
- * value control dir hw
- * addr bit addr bit in out irq name pin offset
- *
- * 0x7b 0 0x7a 0 x x DIO1_0 1 0
- * 0x7b 1 0x7a 0 x x DIO1_1 3 1
- * 0x7b 2 0x7a 0 x x DIO1_2 5 2
- * 0x7b 3 0x7a 0 x x DIO1_3 7 3
- * 0x7b 4 0x7a 1 x x DIO1_4 9 4
- * 0x7b 5 0x7a 1 x x DIO1_5 11 5
- * 0x7b 6 0x7a 1 x x DIO1_6 13 6
- * 0x7b 7 0x7a 1 x x DIO1_7 15 7
- * 0x7c 0 0x7a 5 x x DIO1_8 4 8
- * 0x7c 1 0x7a 5 x x DIO1_9 6 9
- * 0x7c 2 0x7a 5 x x DIO1_10 8 10
- * 0x7c 3 0x7a 5 x x DIO1_11 10 11
- * 0x7c 4 x DIO1_12 12 12
- * 0x7c 5 x 7 DIO1_13 14 13
- */
-static const struct ts5500_dio ts5500_dio1[] = {
- TS5500_DIO_GROUP(0x7b, 0, 0x7a, 0),
- TS5500_DIO_GROUP(0x7b, 4, 0x7a, 1),
- TS5500_DIO_GROUP(0x7c, 0, 0x7a, 5),
- TS5500_DIO_IN(0x7c, 4),
- TS5500_DIO_IN_IRQ(0x7c, 5, 7),
-};
-
-/*
- * TS-5500 DIO2 block
- *
- * value control dir hw
- * addr bit addr bit in out irq name pin offset
- *
- * 0x7e 0 0x7d 0 x x DIO2_0 1 0
- * 0x7e 1 0x7d 0 x x DIO2_1 3 1
- * 0x7e 2 0x7d 0 x x DIO2_2 5 2
- * 0x7e 3 0x7d 0 x x DIO2_3 7 3
- * 0x7e 4 0x7d 1 x x DIO2_4 9 4
- * 0x7e 5 0x7d 1 x x DIO2_5 11 5
- * 0x7e 6 0x7d 1 x x DIO2_6 13 6
- * 0x7e 7 0x7d 1 x x DIO2_7 15 7
- * 0x7f 0 0x7d 5 x x DIO2_8 4 8
- * 0x7f 1 0x7d 5 x x DIO2_9 6 9
- * 0x7f 2 0x7d 5 x x DIO2_10 8 10
- * 0x7f 3 0x7d 5 x x DIO2_11 10 11
- * 0x7f 4 x 6 DIO2_13 14 12
- */
-static const struct ts5500_dio ts5500_dio2[] = {
- TS5500_DIO_GROUP(0x7e, 0, 0x7d, 0),
- TS5500_DIO_GROUP(0x7e, 4, 0x7d, 1),
- TS5500_DIO_GROUP(0x7f, 0, 0x7d, 5),
- TS5500_DIO_IN_IRQ(0x7f, 4, 6),
-};
-
-/*
- * TS-5500 LCD port used as DIO block
- * TS-5600 LCD port is identical
- *
- * value control dir hw
- * addr bit addr bit in out irq name pin offset
- *
- * 0x72 0 0x7d 2 x x LCD_0 8 0
- * 0x72 1 0x7d 2 x x LCD_1 7 1
- * 0x72 2 0x7d 2 x x LCD_2 10 2
- * 0x72 3 0x7d 2 x x LCD_3 9 3
- * 0x72 4 0x7d 3 x x LCD_4 12 4
- * 0x72 5 0x7d 3 x x LCD_5 11 5
- * 0x72 6 0x7d 3 x x LCD_6 14 6
- * 0x72 7 0x7d 3 x x LCD_7 13 7
- * 0x73 0 x LCD_EN 5 8
- * 0x73 6 x LCD_WR 6 9
- * 0x73 7 x 1 LCD_RS 3 10
- */
-static const struct ts5500_dio ts5500_lcd[] = {
- TS5500_DIO_GROUP(0x72, 0, 0x7d, 2),
- TS5500_DIO_GROUP(0x72, 4, 0x7d, 3),
- TS5500_DIO_OUT(0x73, 0),
- TS5500_DIO_IN(0x73, 6),
- TS5500_DIO_IN_IRQ(0x73, 7, 1),
-};
-
-static inline void ts5500_set_mask(u8 mask, u8 addr)
-{
- u8 val = inb(addr);
- val |= mask;
- outb(val, addr);
-}
-
-static inline void ts5500_clear_mask(u8 mask, u8 addr)
-{
- u8 val = inb(addr);
- val &= ~mask;
- outb(val, addr);
-}
-
-static int ts5500_gpio_input(struct gpio_chip *chip, unsigned offset)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio line = priv->pinout[offset];
- unsigned long flags;
-
- if (line.no_input)
- return -ENXIO;
-
- if (line.no_output)
- return 0;
-
- spin_lock_irqsave(&priv->lock, flags);
- ts5500_clear_mask(line.control_mask, line.control_addr);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int ts5500_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio line = priv->pinout[offset];
-
- return !!(inb(line.value_addr) & line.value_mask);
-}
-
-static int ts5500_gpio_output(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio line = priv->pinout[offset];
- unsigned long flags;
-
- if (line.no_output)
- return -ENXIO;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (!line.no_input)
- ts5500_set_mask(line.control_mask, line.control_addr);
-
- if (val)
- ts5500_set_mask(line.value_mask, line.value_addr);
- else
- ts5500_clear_mask(line.value_mask, line.value_addr);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int ts5500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio line = priv->pinout[offset];
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (val)
- ts5500_set_mask(line.value_mask, line.value_addr);
- else
- ts5500_clear_mask(line.value_mask, line.value_addr);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int ts5500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct ts5500_priv *priv = gpiochip_get_data(chip);
- const struct ts5500_dio *block = priv->pinout;
- const struct ts5500_dio line = block[offset];
-
- /* Only one pin is connected to an interrupt */
- if (line.irq)
- return line.irq;
-
- /* As this pin is input-only, we may strap it to another in/out pin */
- if (priv->strap)
- return priv->hwirq;
-
- return -ENXIO;
-}
-
-static int ts5500_enable_irq(struct ts5500_priv *priv)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->hwirq == 7)
- ts5500_set_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */
- else if (priv->hwirq == 6)
- ts5500_set_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */
- else if (priv->hwirq == 1)
- ts5500_set_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
- else
- ret = -EINVAL;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return ret;
-}
-
-static void ts5500_disable_irq(struct ts5500_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->hwirq == 7)
- ts5500_clear_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */
- else if (priv->hwirq == 6)
- ts5500_clear_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */
- else if (priv->hwirq == 1)
- ts5500_clear_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
- else
- dev_err(priv->gpio_chip.parent, "invalid hwirq %d\n",
- priv->hwirq);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int ts5500_dio_probe(struct platform_device *pdev)
-{
- enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
- struct device *dev = &pdev->dev;
- const char *name = dev_name(dev);
- struct ts5500_priv *priv;
- unsigned long flags;
- int ret;
-
- ret = platform_get_irq(pdev, 0);
- if (ret < 0)
- return ret;
-
- priv = devm_kzalloc(dev, sizeof(struct ts5500_priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, priv);
- priv->hwirq = ret;
- spin_lock_init(&priv->lock);
-
- priv->gpio_chip.owner = THIS_MODULE;
- priv->gpio_chip.label = name;
- priv->gpio_chip.parent = dev;
- priv->gpio_chip.direction_input = ts5500_gpio_input;
- priv->gpio_chip.direction_output = ts5500_gpio_output;
- priv->gpio_chip.get = ts5500_gpio_get;
- priv->gpio_chip.set = ts5500_gpio_set;
- priv->gpio_chip.to_irq = ts5500_gpio_to_irq;
- priv->gpio_chip.base = -1;
-
- switch (block) {
- case TS5500_DIO1:
- priv->pinout = ts5500_dio1;
- priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio1);
-
- if (!devm_request_region(dev, 0x7a, 3, name)) {
- dev_err(dev, "failed to request %s ports\n", name);
- return -EBUSY;
- }
- break;
- case TS5500_DIO2:
- priv->pinout = ts5500_dio2;
- priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio2);
-
- if (!devm_request_region(dev, 0x7e, 2, name)) {
- dev_err(dev, "failed to request %s ports\n", name);
- return -EBUSY;
- }
-
- if (hex7d_reserved)
- break;
-
- if (!devm_request_region(dev, 0x7d, 1, name)) {
- dev_err(dev, "failed to request %s 7D\n", name);
- return -EBUSY;
- }
-
- hex7d_reserved = true;
- break;
- case TS5500_LCD:
- case TS5600_LCD:
- priv->pinout = ts5500_lcd;
- priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_lcd);
-
- if (!devm_request_region(dev, 0x72, 2, name)) {
- dev_err(dev, "failed to request %s ports\n", name);
- return -EBUSY;
- }
-
- if (!hex7d_reserved) {
- if (!devm_request_region(dev, 0x7d, 1, name)) {
- dev_err(dev, "failed to request %s 7D\n", name);
- return -EBUSY;
- }
-
- hex7d_reserved = true;
- }
-
- /* Ensure usage of LCD port as DIO */
- spin_lock_irqsave(&priv->lock, flags);
- ts5500_clear_mask(BIT(4), 0x7d);
- spin_unlock_irqrestore(&priv->lock, flags);
- break;
- }
-
- ret = devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
- if (ret) {
- dev_err(dev, "failed to register the gpio chip\n");
- return ret;
- }
-
- ret = ts5500_enable_irq(priv);
- if (ret) {
- dev_err(dev, "invalid interrupt %d\n", priv->hwirq);
- return ret;
- }
-
- return 0;
-}
-
-static void ts5500_dio_remove(struct platform_device *pdev)
-{
- struct ts5500_priv *priv = platform_get_drvdata(pdev);
-
- ts5500_disable_irq(priv);
-}
-
-static const struct platform_device_id ts5500_dio_ids[] = {
- { "ts5500-dio1", TS5500_DIO1 },
- { "ts5500-dio2", TS5500_DIO2 },
- { "ts5500-dio-lcd", TS5500_LCD },
- { "ts5600-dio-lcd", TS5600_LCD },
- { }
-};
-MODULE_DEVICE_TABLE(platform, ts5500_dio_ids);
-
-static struct platform_driver ts5500_dio_driver = {
- .driver = {
- .name = "ts5500-dio",
- },
- .probe = ts5500_dio_probe,
- .remove = ts5500_dio_remove,
- .id_table = ts5500_dio_ids,
-};
-
-module_platform_driver(ts5500_dio_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
-MODULE_DESCRIPTION("Technologic Systems TS-5500 Digital I/O driver");
diff --git a/drivers/gpio/gpio-usbio.c b/drivers/gpio/gpio-usbio.c
index 34d42c743d5bc..489c8ac6299e1 100644
--- a/drivers/gpio/gpio-usbio.c
+++ b/drivers/gpio/gpio-usbio.c
@@ -31,6 +31,7 @@ static const struct acpi_device_id usbio_gpio_acpi_hids[] = {
{ "INTC10B5" }, /* LNL */
{ "INTC10D1" }, /* MTL-CVF */
{ "INTC10E2" }, /* PTL */
+ { "INTC1116" }, /* NVL */
{ }
};
diff --git a/drivers/gpio/gpio-waveshare-dsi.c b/drivers/gpio/gpio-waveshare-dsi.c
new file mode 100644
index 0000000000000..38f52351bb584
--- /dev/null
+++ b/drivers/gpio/gpio-waveshare-dsi.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 Waveshare International Limited
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+/* I2C registers of the microcontroller. */
+#define REG_TP 0x94
+#define REG_LCD 0x95
+#define REG_PWM 0x96
+#define REG_SIZE 0x97
+#define REG_ID 0x98
+#define REG_VERSION 0x99
+
+enum {
+ GPIO_AVDD = 0,
+ GPIO_PANEL_RESET = 1,
+ GPIO_BL_ENABLE = 2,
+ GPIO_IOVCC = 4,
+ GPIO_VCC = 8,
+ GPIO_TS_RESET = 9,
+};
+
+#define NUM_GPIO 16
+
+struct waveshare_gpio {
+ struct mutex dir_lock;
+ struct mutex pwr_lock;
+ struct regmap *regmap;
+ u16 poweron_state;
+
+ struct gpio_chip gc;
+};
+
+static const struct regmap_config waveshare_gpio_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_VERSION,
+};
+
+static int waveshare_gpio_get(struct waveshare_gpio *state, unsigned int offset)
+{
+ u16 pwr_state;
+
+ guard(mutex)(&state->pwr_lock);
+ pwr_state = state->poweron_state & BIT(offset);
+
+ return !!pwr_state;
+}
+
+static int waveshare_gpio_set(struct waveshare_gpio *state, unsigned int offset, int value)
+{
+ u16 last_val;
+ int err;
+
+ guard(mutex)(&state->pwr_lock);
+
+ last_val = state->poweron_state;
+ if (value)
+ last_val |= BIT(offset);
+ else
+ last_val &= ~BIT(offset);
+
+ state->poweron_state = last_val;
+
+ err = regmap_write(state->regmap, REG_TP, last_val >> 8);
+ if (!err)
+ err = regmap_write(state->regmap, REG_LCD, last_val & 0xff);
+
+ return err;
+}
+
+static int waveshare_gpio_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int waveshare_gpio_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct waveshare_gpio *state = gpiochip_get_data(gc);
+
+ return waveshare_gpio_get(state, offset);
+}
+
+static int waveshare_gpio_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct waveshare_gpio *state = gpiochip_get_data(gc);
+
+ return waveshare_gpio_set(state, offset, value);
+}
+
+static int waveshare_gpio_update_status(struct backlight_device *bl)
+{
+ struct waveshare_gpio *state = bl_get_data(bl);
+ int brightness = backlight_get_brightness(bl);
+
+ waveshare_gpio_set(state, GPIO_BL_ENABLE, brightness);
+
+ return regmap_write(state->regmap, REG_PWM, brightness);
+}
+
+static const struct backlight_ops waveshare_gpio_bl = {
+ .update_status = waveshare_gpio_update_status,
+};
+
+static int waveshare_gpio_probe(struct i2c_client *i2c)
+{
+ struct backlight_properties props = {};
+ struct waveshare_gpio *state;
+ struct device *dev = &i2c->dev;
+ struct backlight_device *bl;
+ struct regmap *regmap;
+ unsigned int data;
+ int ret;
+
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ ret = devm_mutex_init(dev, &state->dir_lock);
+ if (ret)
+ return ret;
+
+ ret = devm_mutex_init(dev, &state->pwr_lock);
+ if (ret)
+ return ret;
+
+ regmap = devm_regmap_init_i2c(i2c, &waveshare_gpio_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to allocate register map\n");
+
+ state->regmap = regmap;
+ i2c_set_clientdata(i2c, state);
+
+ ret = regmap_read(regmap, REG_ID, &data);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read register\n");
+
+ dev_dbg(dev, "waveshare panel hw id = 0x%x\n", data);
+
+ ret = regmap_read(regmap, REG_SIZE, &data);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read register\n");
+
+ dev_dbg(dev, "waveshare panel size = %d\n", data);
+
+ ret = regmap_read(regmap, REG_VERSION, &data);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read register\n");
+
+ dev_dbg(dev, "waveshare panel mcu version = 0x%x\n", data);
+
+ ret = waveshare_gpio_set(state, GPIO_TS_RESET, 1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to program GPIOs\n");
+
+ msleep(20);
+
+ state->gc.parent = dev;
+ state->gc.label = i2c->name;
+ state->gc.owner = THIS_MODULE;
+ state->gc.base = -1;
+ state->gc.ngpio = NUM_GPIO;
+
+ /* it is output only */
+ state->gc.get = waveshare_gpio_gpio_get;
+ state->gc.set = waveshare_gpio_gpio_set;
+ state->gc.get_direction = waveshare_gpio_gpio_get_direction;
+ state->gc.can_sleep = true;
+
+ ret = devm_gpiochip_add_data(dev, &state->gc, state);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to create gpiochip\n");
+
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = 255;
+ props.brightness = 255;
+ bl = devm_backlight_device_register(dev, dev_name(dev), dev, state,
+ &waveshare_gpio_bl, &props);
+ return PTR_ERR_OR_ZERO(bl);
+}
+
+static const struct of_device_id waveshare_gpio_dt_ids[] = {
+ { .compatible = "waveshare,dsi-touch-gpio" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, waveshare_gpio_dt_ids);
+
+static struct i2c_driver waveshare_gpio_regulator_driver = {
+ .driver = {
+ .name = "waveshare-regulator",
+ .of_match_table = of_match_ptr(waveshare_gpio_dt_ids),
+ },
+ .probe = waveshare_gpio_probe,
+};
+
+module_i2c_driver(waveshare_gpio_regulator_driver);
+
+MODULE_DESCRIPTION("GPIO controller driver for Waveshare DSI touch panels");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index be4b4d7305477..532205175827a 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -495,13 +495,11 @@ static void xgpio_irqhandler(struct irq_desc *desc)
xgpio_read_ch_all(chip, XGPIO_DATA_OFFSET, hw);
- bitmap_complement(rising, chip->last_irq_read, 64);
- bitmap_and(rising, rising, hw, 64);
+ bitmap_andnot(rising, hw, chip->last_irq_read, 64);
bitmap_and(rising, rising, chip->enable, 64);
bitmap_and(rising, rising, chip->rising_edge, 64);
- bitmap_complement(falling, hw, 64);
- bitmap_and(falling, falling, chip->last_irq_read, 64);
+ bitmap_andnot(falling, chip->last_irq_read, hw, 64);
bitmap_and(falling, falling, chip->enable, 64);
bitmap_and(falling, falling, chip->falling_edge, 64);
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index 29375bea2289b..af0158522ac5d 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -64,14 +64,14 @@ static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
unsigned port_offset)
{
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
- return readl(IOMEM(c->regs + section_offset + port_offset));
+ return readl(c->regs + section_offset + port_offset);
}
static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
unsigned port_offset, u32 val)
{
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
- writel(val, IOMEM(c->regs + section_offset + port_offset));
+ writel(val, c->regs + section_offset + port_offset);
}
/* Functions for struct gpio_chip */
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 571e366624d2a..8118ae3412c20 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -25,6 +25,7 @@
#define VERSAL_GPIO_MAX_BANK 4
#define PMC_GPIO_MAX_BANK 5
#define VERSAL_UNUSED_BANKS 2
+#define EIO_GPIO_MAX_BANK 2
#define ZYNQ_GPIO_BANK0_NGPIO 32
#define ZYNQ_GPIO_BANK1_NGPIO 22
@@ -818,6 +819,16 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, zynq_gpio_runtime_resume, NULL)
};
+static const struct zynq_platform_data eio_gpio_def = {
+ .label = "eio_gpio",
+ .ngpio = 52,
+ .max_bank = EIO_GPIO_MAX_BANK,
+ .bank_min[0] = 0,
+ .bank_max[0] = 25, /* 0 to 25 are connected to MIOs (26 pins) */
+ .bank_min[1] = 26,
+ .bank_max[1] = 51, /* Bank 1 are connected to MIOs (26 pins) */
+};
+
static const struct zynq_platform_data versal_gpio_def = {
.label = "versal_gpio",
.quirks = GPIO_QUIRK_VERSAL,
@@ -882,6 +893,7 @@ static const struct of_device_id zynq_gpio_of_match[] = {
{ .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def },
{ .compatible = "xlnx,versal-gpio-1.0", .data = &versal_gpio_def },
{ .compatible = "xlnx,pmc-gpio-1.0", .data = &pmc_gpio_def },
+ { .compatible = "xlnx,eio-gpio-1.0", .data = &eio_gpio_def },
{ /* end of table */ }
};
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c
index 72422c5db3641..2ec825ffab7da 100644
--- a/drivers/gpio/gpiolib-devres.c
+++ b/drivers/gpio/gpiolib-devres.c
@@ -353,6 +353,13 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, vo
{
int ret;
+ /*
+ * We are passing the devres device here so if the user did not pass
+ * another parent, it's this one.
+ */
+ if (!gc->parent)
+ gc->parent = dev;
+
ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key);
if (ret < 0)
return ret;
diff --git a/drivers/gpio/gpiolib-kunit.c b/drivers/gpio/gpiolib-kunit.c
new file mode 100644
index 0000000000000..380b68f879e55
--- /dev/null
+++ b/drivers/gpio/gpiolib-kunit.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries
+ */
+
+#include <linux/fwnode.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/property.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#include <kunit/platform_device.h>
+#include <kunit/test.h>
+
+#define GPIO_TEST_PROVIDER "gpio-test-provider"
+#define GPIO_SWNODE_TEST_CONSUMER "gpio-swnode-test-consumer"
+#define GPIO_UNBIND_TEST_CONSUMER "gpio-unbind-test-consumer"
+
+static int gpio_test_provider_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int gpio_test_provider_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ return 0;
+}
+
+static int gpio_test_provider_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_chip *gc;
+
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
+ return -ENOMEM;
+
+ gc->base = -1;
+ gc->ngpio = 4;
+ gc->label = "gpio-swnode-consumer-test-device";
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
+
+ gc->get_direction = gpio_test_provider_get_direction;
+ gc->set = gpio_test_provider_set;
+
+ return devm_gpiochip_add_data(dev, gc, NULL);
+}
+
+static struct platform_driver gpio_test_provider_driver = {
+ .probe = gpio_test_provider_probe,
+ .driver = {
+ .name = GPIO_TEST_PROVIDER,
+ },
+};
+
+static const struct software_node gpio_test_provider_swnode = {
+ .name = "gpio-test-provider-primary",
+};
+
+struct gpio_swnode_consumer_pdata {
+ bool gpio_ok;
+};
+
+static const struct gpio_swnode_consumer_pdata gpio_swnode_pdata_template = {
+ .gpio_ok = false,
+};
+
+static int gpio_swnode_consumer_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_swnode_consumer_pdata *pdata = dev_get_platdata(dev);
+ struct gpio_desc *desc;
+
+ desc = devm_gpiod_get(dev, "foo", GPIOD_OUT_HIGH);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ pdata->gpio_ok = true;
+
+ return 0;
+}
+
+static struct platform_driver gpio_swnode_consumer_driver = {
+ .probe = gpio_swnode_consumer_probe,
+ .driver = {
+ .name = GPIO_SWNODE_TEST_CONSUMER,
+ },
+};
+
+static void gpio_swnode_lookup_by_primary(struct kunit *test)
+{
+ struct gpio_swnode_consumer_pdata *pdata;
+ struct platform_device_info pdevinfo;
+ struct property_entry properties[2];
+ struct platform_device *pdev;
+ bool bound = false;
+ int ret;
+
+ ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = kunit_platform_driver_register(test, &gpio_swnode_consumer_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_TEST_PROVIDER,
+ .id = PLATFORM_DEVID_NONE,
+ .swnode = &gpio_test_provider_swnode,
+ };
+
+ pdev = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
+ &gpio_test_provider_swnode,
+ 0, GPIO_ACTIVE_HIGH);
+ properties[1] = (struct property_entry){ };
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_SWNODE_TEST_CONSUMER,
+ .id = PLATFORM_DEVID_NONE,
+ .data = &gpio_swnode_pdata_template,
+ .size_data = sizeof(gpio_swnode_pdata_template),
+ .properties = properties,
+ };
+
+ pdev = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ wait_for_device_probe();
+ scoped_guard(device, &pdev->dev)
+ bound = device_is_bound(&pdev->dev);
+
+ KUNIT_ASSERT_TRUE(test, bound);
+
+ pdata = dev_get_platdata(&pdev->dev);
+ KUNIT_ASSERT_TRUE(test, pdata->gpio_ok);
+}
+
+static void gpio_swnode_lookup_by_secondary(struct kunit *test)
+{
+ struct gpio_swnode_consumer_pdata *pdata;
+ struct platform_device_info pdevinfo;
+ struct property_entry properties[2];
+ struct fwnode_handle *primary;
+ struct platform_device *pdev;
+ bool bound = false;
+ int ret;
+
+ /*
+ * Can't live on the stack as it will still get referenced in cleanup
+ * path after this function returns.
+ */
+ primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+
+ ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = kunit_platform_driver_register(test, &gpio_swnode_consumer_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ fwnode_init(primary, NULL);
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_TEST_PROVIDER,
+ .id = PLATFORM_DEVID_NONE,
+ .fwnode = primary,
+ .swnode = &gpio_test_provider_swnode,
+ };
+
+ pdev = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
+ &gpio_test_provider_swnode,
+ 0, GPIO_ACTIVE_HIGH);
+ properties[1] = (struct property_entry){ };
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_SWNODE_TEST_CONSUMER,
+ .id = PLATFORM_DEVID_NONE,
+ .data = &gpio_swnode_pdata_template,
+ .size_data = sizeof(gpio_swnode_pdata_template),
+ .properties = properties,
+ };
+
+ pdev = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ wait_for_device_probe();
+ scoped_guard(device, &pdev->dev)
+ bound = device_is_bound(&pdev->dev);
+
+ KUNIT_ASSERT_TRUE(test, bound);
+
+ pdata = dev_get_platdata(&pdev->dev);
+ KUNIT_ASSERT_TRUE(test, pdata->gpio_ok);
+}
+
+static struct kunit_case gpio_swnode_lookup_tests[] = {
+ KUNIT_CASE(gpio_swnode_lookup_by_primary),
+ KUNIT_CASE(gpio_swnode_lookup_by_secondary),
+ { }
+};
+
+static struct kunit_suite gpio_swnode_lookup_test_suite = {
+ .name = "gpio-swnode-lookup",
+ .test_cases = gpio_swnode_lookup_tests,
+};
+
+static BLOCKING_NOTIFIER_HEAD(gpio_unbind_notifier);
+
+struct gpio_unbind_consumer_drvdata {
+ struct device *dev;
+ struct gpio_desc *desc;
+ struct notifier_block nb;
+ int set_retval;
+};
+
+static int gpio_unbind_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct gpio_unbind_consumer_drvdata *drvdata =
+ container_of(nb, struct gpio_unbind_consumer_drvdata, nb);
+ struct device *dev = data;
+
+ if (dev != drvdata->dev)
+ return NOTIFY_DONE;
+
+ drvdata->set_retval = gpiod_set_value_cansleep(drvdata->desc, 0);
+
+ return NOTIFY_OK;
+}
+
+static void gpio_unbind_unregister_notifier(void *data)
+{
+ struct notifier_block *nb = data;
+
+ blocking_notifier_chain_unregister(&gpio_unbind_notifier, nb);
+}
+
+static int gpio_unbind_consumer_probe(struct platform_device *pdev)
+{
+ struct gpio_unbind_consumer_drvdata *data;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->dev = dev;
+
+ data->desc = devm_gpiod_get(dev, "foo", GPIOD_OUT_HIGH);
+ if (IS_ERR(data->desc))
+ return PTR_ERR(data->desc);
+
+ data->nb.notifier_call = gpio_unbind_notify;
+ ret = blocking_notifier_chain_register(&gpio_unbind_notifier, &data->nb);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, gpio_unbind_unregister_notifier, &data->nb);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+}
+
+static struct platform_driver gpio_unbind_consumer_driver = {
+ .probe = gpio_unbind_consumer_probe,
+ .driver = {
+ .name = GPIO_UNBIND_TEST_CONSUMER,
+ },
+};
+
+static void gpio_unbind_with_consumers(struct kunit *test)
+{
+ struct gpio_unbind_consumer_drvdata *cons_data;
+ struct platform_device_info pdevinfo;
+ struct property_entry properties[2];
+ struct platform_device *prvd, *cons;
+ bool bound = false;
+ int ret;
+
+ ret = kunit_platform_driver_register(test, &gpio_test_provider_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = kunit_platform_driver_register(test, &gpio_unbind_consumer_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_TEST_PROVIDER,
+ .id = PLATFORM_DEVID_NONE,
+ .swnode = &gpio_test_provider_swnode,
+ };
+
+ prvd = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, prvd);
+
+ properties[0] = PROPERTY_ENTRY_GPIO("foo-gpios",
+ &gpio_test_provider_swnode,
+ 0, GPIO_ACTIVE_HIGH);
+ properties[1] = (struct property_entry){ };
+
+ pdevinfo = (struct platform_device_info){
+ .name = GPIO_UNBIND_TEST_CONSUMER,
+ .id = PLATFORM_DEVID_NONE,
+ .properties = properties,
+ };
+
+ cons = kunit_platform_device_register_full(test, &pdevinfo);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons);
+
+ wait_for_device_probe();
+ scoped_guard(device, &cons->dev)
+ bound = device_is_bound(&cons->dev);
+
+ KUNIT_ASSERT_TRUE(test, bound);
+
+ kunit_platform_device_unregister(test, prvd);
+
+ ret = blocking_notifier_call_chain(&gpio_unbind_notifier, 0, &cons->dev);
+ KUNIT_ASSERT_EQ(test, ret, NOTIFY_OK);
+
+ scoped_guard(device, &cons->dev) {
+ cons_data = platform_get_drvdata(cons);
+ ret = cons_data->set_retval;
+ }
+
+ KUNIT_ASSERT_EQ(test, ret, -ENODEV);
+}
+
+static struct kunit_case gpio_unbind_with_consumers_tests[] = {
+ KUNIT_CASE(gpio_unbind_with_consumers),
+ { }
+};
+
+static struct kunit_suite gpio_unbind_with_consumers_test_suite = {
+ .name = "gpio-unbind-with-consumers",
+ .test_cases = gpio_unbind_with_consumers_tests,
+};
+
+kunit_test_suites(
+ &gpio_swnode_lookup_test_suite,
+ &gpio_unbind_with_consumers_test_suite,
+);
+
+MODULE_DESCRIPTION("Test module for the GPIO subsystem");
+MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1e6dce430dca0..c72eec54cb196 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -55,7 +55,7 @@
/* Device and char device-related information */
static DEFINE_IDA(gpio_ida);
-static dev_t gpio_devt;
+static dev_t gpio_devt __ro_after_init;
#define GPIO_DEV_MAX 256 /* 256 GPIO chip devices supported */
static int gpio_bus_match(struct device *dev, const struct device_driver *drv)
@@ -114,7 +114,7 @@ static int gpiochip_irqchip_init_hw(struct gpio_chip *gc);
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc);
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc);
-static bool gpiolib_initialized;
+static bool gpiolib_initialized __ro_after_init;
const char *gpiod_get_label(struct gpio_desc *desc)
{
@@ -491,6 +491,28 @@ int gpiod_get_direction(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_get_direction);
+/**
+ * gpiod_is_single_ended - check if the GPIO is configured as single-ended
+ * @desc: the GPIO descriptor to check
+ *
+ * Returns true if the GPIO is configured as either Open Drain or Open Source.
+ * In these modes, the direction of the line cannot always be reliably
+ * determined by reading hardware registers, as the "off" state (High-Z)
+ * is physically indistinguishable from an input state.
+ */
+bool gpiod_is_single_ended(struct gpio_desc *desc)
+{
+ if (!desc)
+ return false;
+
+ if (test_bit(GPIOD_FLAG_OPEN_DRAIN, &desc->flags) ||
+ test_bit(GPIOD_FLAG_OPEN_SOURCE, &desc->flags))
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(gpiod_is_single_ended);
+
/*
* Add a new chip to the global chips list, keeping the list of chips sorted
* by range(means [base, base + ngpio - 1]) order.
@@ -5340,7 +5362,7 @@ EXPORT_SYMBOL_GPL(gpiod_put_array);
* gpio_device of the GPIO chip with the firmware node and then simply
* bind it to this stub driver.
*/
-static struct device_driver gpio_stub_drv = {
+static struct device_driver gpio_stub_drv __ro_after_init = {
.name = "gpio_stub_drv",
.bus = &gpio_bus_type,
};
@@ -5498,8 +5520,8 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
if (gc->label)
seq_printf(s, ", %s", gc->label);
if (gc->can_sleep)
- seq_printf(s, ", can sleep");
- seq_printf(s, ":\n");
+ seq_puts(s, ", can sleep");
+ seq_puts(s, ":\n");
if (gc->dbg_show)
gc->dbg_show(s, gc);