summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig83
-rw-r--r--drivers/gpio/Makefile4
-rw-r--r--drivers/gpio/TODO15
-rw-r--r--drivers/gpio/gpio-104-dio-48e.c12
-rw-r--r--drivers/gpio/gpio-104-idi-48.c1
-rw-r--r--drivers/gpio/gpio-adnp.c9
-rw-r--r--drivers/gpio/gpio-aggregator.c9
-rw-r--r--drivers/gpio/gpio-altera.c29
-rw-r--r--drivers/gpio/gpio-aspeed-sgpio.c45
-rw-r--r--drivers/gpio/gpio-aspeed.c82
-rw-r--r--drivers/gpio/gpio-ath79.c8
-rw-r--r--drivers/gpio/gpio-cadence.c10
-rw-r--r--drivers/gpio/gpio-davinci.c7
-rw-r--r--drivers/gpio/gpio-elkhartlake.c90
-rw-r--r--drivers/gpio/gpio-ftgpio010.c2
-rw-r--r--drivers/gpio/gpio-fxl6408.c158
-rw-r--r--drivers/gpio/gpio-hisi.c25
-rw-r--r--drivers/gpio/gpio-hlwd.c33
-rw-r--r--drivers/gpio/gpio-ich.c10
-rw-r--r--drivers/gpio/gpio-idt3243x.c11
-rw-r--r--drivers/gpio/gpio-imx-scu.c1
-rw-r--r--drivers/gpio/gpio-loongson-64bit.c238
-rw-r--r--drivers/gpio/gpio-loongson1.c71
-rw-r--r--drivers/gpio/gpio-max732x.c8
-rw-r--r--drivers/gpio/gpio-merrifield.c453
-rw-r--r--drivers/gpio/gpio-mlxbf2.c32
-rw-r--r--drivers/gpio/gpio-mm-lantiq.c2
-rw-r--r--drivers/gpio/gpio-mpc5200.c2
-rw-r--r--drivers/gpio/gpio-msc313.c26
-rw-r--r--drivers/gpio/gpio-mxs.c1
-rw-r--r--drivers/gpio/gpio-omap.c83
-rw-r--r--drivers/gpio/gpio-pci-idio-16.c12
-rw-r--r--drivers/gpio/gpio-pcie-idio-24.c21
-rw-r--r--drivers/gpio/gpio-pxa.c5
-rw-r--r--drivers/gpio/gpio-raspberrypi-exp.c2
-rw-r--r--drivers/gpio/gpio-rcar.c2
-rw-r--r--drivers/gpio/gpio-rda.c23
-rw-r--r--drivers/gpio/gpio-reg.c12
-rw-r--r--drivers/gpio/gpio-regmap.c12
-rw-r--r--drivers/gpio/gpio-sama5d2-piobu.c2
-rw-r--r--drivers/gpio/gpio-sifive.c2
-rw-r--r--drivers/gpio/gpio-sim.c2
-rw-r--r--drivers/gpio/gpio-siox.c75
-rw-r--r--drivers/gpio/gpio-stmpe.c8
-rw-r--r--drivers/gpio/gpio-stp-xway.c2
-rw-r--r--drivers/gpio/gpio-tangier.c536
-rw-r--r--drivers/gpio/gpio-tangier.h117
-rw-r--r--drivers/gpio/gpio-tb10x.c2
-rw-r--r--drivers/gpio/gpio-thunderx.c26
-rw-r--r--drivers/gpio/gpio-tqmx86.c28
-rw-r--r--drivers/gpio/gpio-visconti.c52
-rw-r--r--drivers/gpio/gpio-xgs-iproc.c32
-rw-r--r--drivers/gpio/gpio-xilinx.c23
-rw-r--r--drivers/gpio/gpio-xlp.c14
-rw-r--r--drivers/gpio/gpio-xra1403.c2
-rw-r--r--drivers/gpio/gpiolib-acpi.c36
-rw-r--r--drivers/gpio/gpiolib-acpi.h1
-rw-r--r--drivers/gpio/gpiolib-of.c9
-rw-r--r--drivers/gpio/gpiolib-of.h1
-rw-r--r--drivers/gpio/gpiolib-swnode.c5
-rw-r--r--drivers/gpio/gpiolib-sysfs.c39
-rw-r--r--drivers/gpio/gpiolib.c173
62 files changed, 1960 insertions, 876 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8be697f9f621..5521f060d58e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -3,14 +3,6 @@
# GPIO infrastructure and drivers
#
-config ARCH_HAVE_CUSTOM_GPIO_H
- bool
- help
- Selecting this config option from the architecture Kconfig allows
- the architecture to provide a custom asm/gpio.h implementation
- overriding the default implementations. New uses of this are
- strongly discouraged.
-
menuconfig GPIOLIB
bool "GPIO Support"
help
@@ -47,6 +39,14 @@ config GPIOLIB_IRQCHIP
select IRQ_DOMAIN
bool
+config OF_GPIO_MM_GPIOCHIP
+ bool
+ help
+ This adds support for the legacy 'struct of_mm_gpio_chip' interface
+ from PowerPC. Existing drivers using this interface need to select
+ this symbol, but new drivers should use the generic gpio-regmap
+ infrastructure instead.
+
config DEBUG_GPIO
bool "Debug GPIO calls"
depends on DEBUG_KERNEL
@@ -100,7 +100,7 @@ config GPIO_GENERIC
tristate
config GPIO_REGMAP
- depends on REGMAP
+ select REGMAP
tristate
# put drivers in the right section, in alphabetical order
@@ -139,6 +139,7 @@ config GPIO_ALTERA
tristate "Altera GPIO"
depends on OF_GPIO
select GPIOLIB_IRQCHIP
+ select OF_GPIO_MM_GPIOCHIP
help
Say Y or M here to build support for the Altera PIO device.
@@ -380,6 +381,18 @@ config GPIO_LOONGSON
help
Driver for GPIO functionality on Loongson-2F/3A/3B processors.
+config GPIO_LOONGSON_64BIT
+ tristate "Loongson 64 bit GPIO support"
+ depends on LOONGARCH || COMPILE_TEST
+ depends on OF_GPIO
+ select GPIO_GENERIC
+ help
+ Say yes here to support the GPIO functionality of a number of
+ Loongson series of chips. The Loongson GPIO controller supports
+ up to 60 GPIOS in total, 4 of which are dedicated GPIO pins, and
+ the remaining 56 are reused with other functions, with edge or
+ level triggered interrupts.
+
config GPIO_LPC18XX
tristate "NXP LPC18XX/43XX GPIO support"
default y if ARCH_LPC18XX
@@ -411,6 +424,7 @@ config GPIO_MENZ127
config GPIO_MM_LANTIQ
bool "Lantiq Memory mapped GPIOs"
depends on LANTIQ && SOC_XWAY
+ select OF_GPIO_MM_GPIOCHIP
help
This enables support for memory mapped GPIOs on the External Bus Unit
(EBU) found on Lantiq SoCs. The GPIOs are output only as they are
@@ -419,6 +433,7 @@ config GPIO_MM_LANTIQ
config GPIO_MPC5200
def_bool y
depends on PPC_MPC52xx
+ select OF_GPIO_MM_GPIOCHIP
config GPIO_MPC8XXX
bool "MPC512x/MPC8xxx/QorIQ GPIO support"
@@ -485,14 +500,6 @@ config GPIO_PL061
help
Say yes here to support the PrimeCell PL061 GPIO device.
-config GPIO_PMIC_EIC_SPRD
- tristate "Spreadtrum PMIC EIC support"
- depends on MFD_SC27XX_PMIC || COMPILE_TEST
- depends on OF_GPIO
- select GPIOLIB_IRQCHIP
- help
- Say yes here to support Spreadtrum PMIC EIC device.
-
config GPIO_PXA
bool "PXA GPIO support"
depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST
@@ -616,6 +623,17 @@ config GPIO_SYSCON
help
Say yes here to support GPIO functionality though SYSCON driver.
+config GPIO_TANGIER
+ tristate
+ select GPIOLIB_IRQCHIP
+ help
+ GPIO support for Intel Tangier and compatible platforms.
+ Currently supported:
+ - Elkhart Lake
+ - Merrifield
+
+ If built as a module its name will be gpio-tangier.
+
config GPIO_TB10X
bool
select GPIO_GENERIC
@@ -1000,6 +1018,16 @@ config GPIO_ADNP
enough to represent all pins, but the driver will assume a
register layout for 64 pins (8 registers).
+config GPIO_FXL6408
+ tristate "FXL6408 I2C GPIO expander"
+ select GPIO_REGMAP
+ select REGMAP_I2C
+ help
+ GPIO driver for Fairchild Semiconductor FXL6408 GPIO expander.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gpio-fxl6408.
+
config GPIO_GW_PLD
tristate "Gateworks PLD GPIO Expander"
depends on OF_GPIO
@@ -1235,6 +1263,17 @@ config HTC_EGPIO
several HTC phones. It provides basic support for input
pins, output pins, and IRQs.
+config GPIO_ELKHARTLAKE
+ tristate "Intel Elkhart Lake PSE GPIO support"
+ depends on X86 || COMPILE_TEST
+ select GPIO_TANGIER
+ help
+ Select this option to enable GPIO support for Intel Elkhart Lake
+ PSE GPIO IP.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gpio-elkhartlake.
+
config GPIO_JANZ_TTL
tristate "Janz VMOD-TTL Digital IO Module"
depends on MFD_JANZ_CMODIO
@@ -1323,6 +1362,14 @@ config GPIO_PALMAS
Select this option to enable GPIO driver for the TI PALMAS
series chip family.
+config GPIO_PMIC_EIC_SPRD
+ tristate "Spreadtrum PMIC EIC support"
+ depends on MFD_SC27XX_PMIC || COMPILE_TEST
+ depends on OF_GPIO
+ select GPIOLIB_IRQCHIP
+ help
+ Say yes here to support Spreadtrum PMIC EIC device.
+
config GPIO_RC5T583
bool "RICOH RC5T583 GPIO"
depends on MFD_RC5T583
@@ -1517,7 +1564,7 @@ config GPIO_BT8XX
config GPIO_MERRIFIELD
tristate "Intel Merrifield GPIO support"
depends on X86_INTEL_MID
- select GPIOLIB_IRQCHIP
+ select GPIO_TANGIER
help
Say Y here to support Intel Merrifield GPIO.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index eb59524d18c0..20036af3acb1 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -54,12 +54,14 @@ obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
+obj-$(CONFIG_GPIO_ELKHARTLAKE) += gpio-elkhartlake.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EN7523) += gpio-en7523.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
+obj-$(CONFIG_GPIO_FXL6408) += gpio-fxl6408.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
@@ -81,6 +83,7 @@ obj-$(CONFIG_GPIO_LJCA) += gpio-ljca.o
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
+obj-$(CONFIG_GPIO_LOONGSON_64BIT) += gpio-loongson-64bit.o
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o
obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o
@@ -146,6 +149,7 @@ obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
+obj-$(CONFIG_GPIO_TANGIER) += gpio-tangier.o
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO
index 68ada1066941..189c3abe7e79 100644
--- a/drivers/gpio/TODO
+++ b/drivers/gpio/TODO
@@ -59,11 +59,6 @@ the device tree back-end. It is legacy and should not be used in new code.
Work items:
-- Get rid of struct of_mm_gpio_chip altogether: use the generic MMIO
- GPIO for all current users (see below). Delete struct of_mm_gpio_chip,
- to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_remove()
- from the kernel.
-
- Change all consumer drivers that #include <linux/of_gpio.h> to
#include <linux/gpio/consumer.h> and stop doing custom parsing of the
GPIO lines from the device tree. This can be tricky and often ivolves
@@ -81,6 +76,16 @@ Work items:
uses <linux/gpio/consumer.h> or <linux/gpio/driver.h> instead.
+Get rid of <linux/gpio/legacy-of-mm-gpiochip.h>
+
+Work items:
+
+- Get rid of struct of_mm_gpio_chip altogether: use the generic MMIO
+ GPIO for all current users (see below). Delete struct of_mm_gpio_chip,
+ to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_remove(),
+ CONFIG_OF_GPIO_MM_GPIOCHIP from the kernel.
+
+
Get rid of <linux/gpio.h>
This legacy header is a one stop shop for anything GPIO is closely tied
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index a3846faf3780..f2253fd5ab4b 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -86,6 +86,7 @@ static const struct regmap_config dio48e_regmap_config = {
.volatile_table = &dio48e_volatile_table,
.precious_table = &dio48e_precious_table,
.cache_type = REGCACHE_FLAT,
+ .use_raw_spinlock = true,
};
/* only bit 3 on each respective Port C supports interrupts */
@@ -106,7 +107,6 @@ static int dio48e_handle_mask_sync(struct regmap *const map, const int index,
{
unsigned int *const irq_mask = irq_drv_data;
const unsigned int prev_mask = *irq_mask;
- const unsigned int all_masked = GENMASK(1, 0);
int err;
unsigned int val;
@@ -118,7 +118,7 @@ static int dio48e_handle_mask_sync(struct regmap *const map, const int index,
*irq_mask = mask_buf;
/* if all previously masked, enable interrupts when unmasking */
- if (prev_mask == all_masked) {
+ if (prev_mask == mask_buf_def) {
err = regmap_write(map, DIO48E_CLEAR_INTERRUPT, 0x00);
if (err)
return err;
@@ -126,7 +126,7 @@ static int dio48e_handle_mask_sync(struct regmap *const map, const int index,
}
/* if all are currently masked, disable interrupts */
- if (mask_buf == all_masked)
+ if (mask_buf == mask_buf_def)
return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val);
return 0;
@@ -195,13 +195,9 @@ static int dio48e_probe(struct device *dev, unsigned int id)
return -ENOMEM;
chip->name = name;
- /* No IRQ status register so use CLEAR_INTERRUPT register instead */
- chip->status_base = DIO48E_CLEAR_INTERRUPT;
chip->mask_base = DIO48E_ENABLE_INTERRUPT;
chip->ack_base = DIO48E_CLEAR_INTERRUPT;
- /* CLEAR_INTERRUPT doubles as status register so we need it cleared */
- chip->clear_ack = true;
- chip->status_invert = true;
+ chip->no_status = true;
chip->num_regs = 1;
chip->irqs = dio48e_regmap_irqs;
chip->num_irqs = ARRAY_SIZE(dio48e_regmap_irqs);
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index ca2175b84e24..ba73ee9c0c29 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -81,6 +81,7 @@ static const struct regmap_config idi48_regmap_config = {
.wr_table = &idi_48_wr_table,
.rd_table = &idi_48_rd_table,
.precious_table = &idi_48_precious_table,
+ .use_raw_spinlock = true,
};
#define IDI48_NGPIO 48
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index a6439e3daff0..9b01c391efce 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -307,6 +307,7 @@ static void adnp_irq_mask(struct irq_data *d)
unsigned int pos = d->hwirq & 7;
adnp->irq_enable[reg] &= ~BIT(pos);
+ gpiochip_disable_irq(gc, irqd_to_hwirq(d));
}
static void adnp_irq_unmask(struct irq_data *d)
@@ -316,6 +317,7 @@ static void adnp_irq_unmask(struct irq_data *d)
unsigned int reg = d->hwirq >> adnp->reg_shift;
unsigned int pos = d->hwirq & 7;
+ gpiochip_enable_irq(gc, irqd_to_hwirq(d));
adnp->irq_enable[reg] |= BIT(pos);
}
@@ -372,13 +374,15 @@ static void adnp_irq_bus_unlock(struct irq_data *d)
mutex_unlock(&adnp->irq_lock);
}
-static struct irq_chip adnp_irq_chip = {
+static const struct irq_chip adnp_irq_chip = {
.name = "gpio-adnp",
.irq_mask = adnp_irq_mask,
.irq_unmask = adnp_irq_unmask,
.irq_set_type = adnp_irq_set_type,
.irq_bus_lock = adnp_irq_bus_lock,
.irq_bus_sync_unlock = adnp_irq_bus_unlock,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int adnp_irq_setup(struct adnp *adnp)
@@ -469,7 +473,8 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios,
return err;
girq = &chip->irq;
- girq->chip = &adnp_irq_chip;
+ gpio_irq_chip_set_chip(girq, &adnp_irq_chip);
+
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 6d17d262ad91..20a686f12df7 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -10,19 +10,20 @@
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/ctype.h>
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
-#include <linux/gpio/driver.h>
-#include <linux/gpio/machine.h>
#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/overflow.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+
#define AGGREGATOR_MAX_GPIOS 512
/*
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index b59fae993626..54d7c450c596 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -7,7 +7,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/gpio/driver.h>
-#include <linux/of_gpio.h> /* For of_mm_gpio_chip */
+#include <linux/gpio/legacy-of-mm-gpiochip.h>
#include <linux/platform_device.h>
#define ALTERA_GPIO_MAX_NGPIO 32
@@ -24,14 +24,12 @@
* @interrupt_trigger : specifies the hardware configured IRQ trigger type
* (rising, falling, both, high)
* @mapped_irq : kernel mapped irq number.
-* @irq_chip : IRQ chip configuration
*/
struct altera_gpio_chip {
struct of_mm_gpio_chip mmchip;
raw_spinlock_t gpio_lock;
int interrupt_trigger;
int mapped_irq;
- struct irq_chip irq_chip;
};
static void altera_gpio_irq_unmask(struct irq_data *d)
@@ -43,6 +41,7 @@ static void altera_gpio_irq_unmask(struct irq_data *d)
altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
mm_gc = &altera_gc->mmchip;
+ gpiochip_enable_irq(&mm_gc->gc, irqd_to_hwirq(d));
raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
@@ -68,6 +67,7 @@ static void altera_gpio_irq_mask(struct irq_data *d)
intmask &= ~BIT(irqd_to_hwirq(d));
writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
+ gpiochip_disable_irq(&mm_gc->gc, irqd_to_hwirq(d));
}
/*
@@ -233,6 +233,17 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+static const struct irq_chip altera_gpio_irq_chip = {
+ .name = "altera-gpio",
+ .irq_mask = altera_gpio_irq_mask,
+ .irq_unmask = altera_gpio_irq_unmask,
+ .irq_set_type = altera_gpio_irq_set_type,
+ .irq_startup = altera_gpio_irq_startup,
+ .irq_shutdown = altera_gpio_irq_mask,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int altera_gpio_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -278,15 +289,9 @@ static int altera_gpio_probe(struct platform_device *pdev)
}
altera_gc->interrupt_trigger = reg;
- altera_gc->irq_chip.name = "altera-gpio";
- altera_gc->irq_chip.irq_mask = altera_gpio_irq_mask;
- altera_gc->irq_chip.irq_unmask = altera_gpio_irq_unmask;
- altera_gc->irq_chip.irq_set_type = altera_gpio_irq_set_type;
- altera_gc->irq_chip.irq_startup = altera_gpio_irq_startup;
- altera_gc->irq_chip.irq_shutdown = altera_gpio_irq_mask;
-
girq = &altera_gc->mmchip.gc.irq;
- girq->chip = &altera_gc->irq_chip;
+ gpio_irq_chip_set_chip(girq, &altera_gpio_irq_chip);
+
if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
girq->parent_handler = altera_gpio_irq_leveL_high_handler;
else
@@ -330,7 +335,7 @@ MODULE_DEVICE_TABLE(of, altera_gpio_of_match);
static struct platform_driver altera_gpio_driver = {
.driver = {
.name = "altera_gpio",
- .of_match_table = of_match_ptr(altera_gpio_of_match),
+ .of_match_table = altera_gpio_of_match,
},
.probe = altera_gpio_probe,
.remove = altera_gpio_remove,
diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c
index 454cefbeecf0..72755fee6478 100644
--- a/drivers/gpio/gpio-aspeed-sgpio.c
+++ b/drivers/gpio/gpio-aspeed-sgpio.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -29,7 +30,7 @@ struct aspeed_sgpio_pdata {
struct aspeed_sgpio {
struct gpio_chip chip;
- struct irq_chip intc;
+ struct device *dev;
struct clk *pclk;
raw_spinlock_t lock;
void __iomem *base;
@@ -296,6 +297,10 @@ static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
addr = bank_reg(gpio, bank, reg_irq_enable);
+ /* Unmasking the IRQ */
+ if (set)
+ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d));
+
raw_spin_lock_irqsave(&gpio->lock, flags);
reg = ioread32(addr);
@@ -307,6 +312,12 @@ static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
iowrite32(reg, addr);
raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+ /* Masking the IRQ */
+ if (!set)
+ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d));
+
+
}
static void aspeed_sgpio_irq_mask(struct irq_data *d)
@@ -401,6 +412,27 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(ic, desc);
}
+static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+ const struct aspeed_sgpio_bank *bank;
+ struct aspeed_sgpio *gpio;
+ u32 bit;
+ int offset;
+
+ irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+ seq_printf(p, dev_name(gpio->dev));
+}
+
+static const struct irq_chip aspeed_sgpio_irq_chip = {
+ .irq_ack = aspeed_sgpio_irq_ack,
+ .irq_mask = aspeed_sgpio_irq_mask,
+ .irq_unmask = aspeed_sgpio_irq_unmask,
+ .irq_set_type = aspeed_sgpio_set_type,
+ .irq_print_chip = aspeed_sgpio_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
struct platform_device *pdev)
{
@@ -423,14 +455,8 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
}
- gpio->intc.name = dev_name(&pdev->dev);
- gpio->intc.irq_ack = aspeed_sgpio_irq_ack;
- gpio->intc.irq_mask = aspeed_sgpio_irq_mask;
- gpio->intc.irq_unmask = aspeed_sgpio_irq_unmask;
- gpio->intc.irq_set_type = aspeed_sgpio_set_type;
-
irq = &gpio->chip.irq;
- irq->chip = &gpio->intc;
+ gpio_irq_chip_set_chip(irq, &aspeed_sgpio_irq_chip);
irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
irq->handler = handle_bad_irq;
irq->default_type = IRQ_TYPE_NONE;
@@ -524,6 +550,8 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
if (IS_ERR(gpio->base))
return PTR_ERR(gpio->base);
+ gpio->dev = &pdev->dev;
+
pdata = device_get_match_data(&pdev->dev);
if (!pdata)
return -EINVAL;
@@ -609,4 +637,3 @@ static struct platform_driver aspeed_sgpio_driver = {
module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index a94da80d3a95..da33bbbdacb9 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -53,7 +54,7 @@ struct aspeed_gpio_config {
*/
struct aspeed_gpio {
struct gpio_chip chip;
- struct irq_chip irqc;
+ struct device *dev;
raw_spinlock_t lock;
void __iomem *base;
int irq;
@@ -566,6 +567,10 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)
addr = bank_reg(gpio, bank, reg_irq_enable);
+ /* Unmasking the IRQ */
+ if (set)
+ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d));
+
raw_spin_lock_irqsave(&gpio->lock, flags);
copro = aspeed_gpio_copro_request(gpio, offset);
@@ -579,6 +584,10 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)
if (copro)
aspeed_gpio_copro_release(gpio, offset);
raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+ /* Masking the IRQ */
+ if (!set)
+ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d));
}
static void aspeed_gpio_irq_mask(struct irq_data *d)
@@ -1080,6 +1089,30 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio);
+static void aspeed_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+ const struct aspeed_gpio_bank *bank;
+ struct aspeed_gpio *gpio;
+ u32 bit;
+ int rc, offset;
+
+ rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset);
+ if (rc)
+ return;
+
+ seq_printf(p, dev_name(gpio->dev));
+}
+
+static const struct irq_chip aspeed_gpio_irq_chip = {
+ .irq_ack = aspeed_gpio_irq_ack,
+ .irq_mask = aspeed_gpio_irq_mask,
+ .irq_unmask = aspeed_gpio_irq_unmask,
+ .irq_set_type = aspeed_gpio_set_type,
+ .irq_print_chip = aspeed_gpio_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
/*
* Any banks not specified in a struct aspeed_bank_props array are assumed to
* have the properties:
@@ -1137,8 +1170,9 @@ MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
static int __init aspeed_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *gpio_id;
+ struct gpio_irq_chip *girq;
struct aspeed_gpio *gpio;
- int rc, i, banks, err;
+ int rc, irq, i, banks, err;
u32 ngpio;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
@@ -1149,6 +1183,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
if (IS_ERR(gpio->base))
return PTR_ERR(gpio->base);
+ gpio->dev = &pdev->dev;
+
raw_spin_lock_init(&gpio->lock);
gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
@@ -1201,31 +1237,23 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM);
}
- /* Optionally set up an irqchip if there is an IRQ */
- rc = platform_get_irq(pdev, 0);
- if (rc > 0) {
- struct gpio_irq_chip *girq;
-
- gpio->irq = rc;
- girq = &gpio->chip.irq;
- girq->chip = &gpio->irqc;
- girq->chip->name = dev_name(&pdev->dev);
- girq->chip->irq_ack = aspeed_gpio_irq_ack;
- girq->chip->irq_mask = aspeed_gpio_irq_mask;
- girq->chip->irq_unmask = aspeed_gpio_irq_unmask;
- girq->chip->irq_set_type = aspeed_gpio_set_type;
- girq->parent_handler = aspeed_gpio_irq_handler;
- girq->num_parents = 1;
- girq->parents = devm_kcalloc(&pdev->dev, 1,
- sizeof(*girq->parents),
- GFP_KERNEL);
- if (!girq->parents)
- return -ENOMEM;
- girq->parents[0] = gpio->irq;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_bad_irq;
- girq->init_valid_mask = aspeed_init_irq_valid_mask;
- }
+ /* Set up an irqchip */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ gpio->irq = irq;
+ girq = &gpio->chip.irq;
+ gpio_irq_chip_set_chip(girq, &aspeed_gpio_irq_chip);
+
+ girq->parent_handler = aspeed_gpio_irq_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents), GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+ girq->parents[0] = gpio->irq;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+ girq->init_valid_mask = aspeed_init_irq_valid_mask;
gpio->offset_timer =
devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL);
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 3958c6d97639..aa0a954b8392 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -71,6 +71,7 @@ static void ath79_gpio_irq_unmask(struct irq_data *data)
u32 mask = BIT(irqd_to_hwirq(data));
unsigned long flags;
+ gpiochip_enable_irq(&ctrl->gc, irqd_to_hwirq(data));
raw_spin_lock_irqsave(&ctrl->lock, flags);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
@@ -85,6 +86,7 @@ static void ath79_gpio_irq_mask(struct irq_data *data)
raw_spin_lock_irqsave(&ctrl->lock, flags);
ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
+ gpiochip_disable_irq(&ctrl->gc, irqd_to_hwirq(data));
}
static void ath79_gpio_irq_enable(struct irq_data *data)
@@ -169,13 +171,15 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
return 0;
}
-static struct irq_chip ath79_gpio_irqchip = {
+static const struct irq_chip ath79_gpio_irqchip = {
.name = "gpio-ath79",
.irq_enable = ath79_gpio_irq_enable,
.irq_disable = ath79_gpio_irq_disable,
.irq_mask = ath79_gpio_irq_mask,
.irq_unmask = ath79_gpio_irq_unmask,
.irq_set_type = ath79_gpio_irq_set_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static void ath79_gpio_irq_handler(struct irq_desc *desc)
@@ -274,7 +278,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
/* Optional interrupt setup */
if (!np || of_property_read_bool(np, "interrupt-controller")) {
girq = &ctrl->gc.irq;
- girq->chip = &ath79_gpio_irqchip;
+ gpio_irq_chip_set_chip(girq, &ath79_gpio_irqchip);
girq->parent_handler = ath79_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c
index 137aea49ba02..3720b90cad10 100644
--- a/drivers/gpio/gpio-cadence.c
+++ b/drivers/gpio/gpio-cadence.c
@@ -70,6 +70,7 @@ static void cdns_gpio_irq_mask(struct irq_data *d)
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
iowrite32(BIT(d->hwirq), cgpio->regs + CDNS_GPIO_IRQ_DIS);
+ gpiochip_disable_irq(chip, irqd_to_hwirq(d));
}
static void cdns_gpio_irq_unmask(struct irq_data *d)
@@ -77,6 +78,7 @@ static void cdns_gpio_irq_unmask(struct irq_data *d)
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
+ gpiochip_enable_irq(chip, irqd_to_hwirq(d));
iowrite32(BIT(d->hwirq), cgpio->regs + CDNS_GPIO_IRQ_EN);
}
@@ -138,11 +140,13 @@ static void cdns_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(irqchip, desc);
}
-static struct irq_chip cdns_gpio_irqchip = {
+static const struct irq_chip cdns_gpio_irqchip = {
.name = "cdns-gpio",
.irq_mask = cdns_gpio_irq_mask,
.irq_unmask = cdns_gpio_irq_unmask,
- .irq_set_type = cdns_gpio_irq_set_type
+ .irq_set_type = cdns_gpio_irq_set_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int cdns_gpio_probe(struct platform_device *pdev)
@@ -222,7 +226,7 @@ static int cdns_gpio_probe(struct platform_device *pdev)
struct gpio_irq_chip *girq;
girq = &cgpio->gc.irq;
- girq->chip = &cdns_gpio_irqchip;
+ gpio_irq_chip_set_chip(girq, &cdns_gpio_irqchip);
girq->parent_handler = cdns_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1,
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 26b1f7465e09..aaaf61dc2632 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -24,8 +24,6 @@
#include <linux/spinlock.h>
#include <linux/pm_runtime.h>
-#include <asm-generic/gpio.h>
-
#define MAX_REGS_BANKS 5
#define MAX_INT_PER_BANK 32
@@ -324,7 +322,7 @@ static struct irq_chip gpio_irqchip = {
.irq_enable = gpio_irq_enable,
.irq_disable = gpio_irq_disable,
.irq_set_type = gpio_irq_type,
- .flags = IRQCHIP_SET_TYPE_MASKED,
+ .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE,
};
static void gpio_irq_handler(struct irq_desc *desc)
@@ -641,9 +639,6 @@ static void davinci_gpio_save_context(struct davinci_gpio_controller *chips,
context->set_falling = readl_relaxed(&g->set_falling);
}
- /* Clear Bank interrupt enable bit */
- writel_relaxed(0, base + BINTEN);
-
/* Clear all interrupt status registers */
writel_relaxed(GENMASK(31, 0), &g->intstat);
}
diff --git a/drivers/gpio/gpio-elkhartlake.c b/drivers/gpio/gpio-elkhartlake.c
new file mode 100644
index 000000000000..a9c8b16215be
--- /dev/null
+++ b/drivers/gpio/gpio-elkhartlake.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Elkhart Lake PSE GPIO driver
+ *
+ * Copyright (c) 2023 Intel Corporation.
+ *
+ * Authors: Pandith N <pandith.n@intel.com>
+ * Raag Jadav <raag.jadav@intel.com>
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#include "gpio-tangier.h"
+
+/* Each Intel EHL PSE GPIO Controller has 30 GPIO pins */
+#define EHL_PSE_NGPIO 30
+
+static int ehl_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct tng_gpio *priv;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->reg_base))
+ return PTR_ERR(priv->reg_base);
+
+ priv->dev = dev;
+ priv->irq = irq;
+
+ priv->info.base = -1;
+ priv->info.ngpio = EHL_PSE_NGPIO;
+
+ priv->wake_regs.gwmr = GWMR_EHL;
+ priv->wake_regs.gwsr = GWSR_EHL;
+ priv->wake_regs.gsir = GSIR_EHL;
+
+ ret = devm_tng_gpio_probe(dev, priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "tng_gpio_probe error\n");
+
+ platform_set_drvdata(pdev, priv);
+ return 0;
+}
+
+static int ehl_gpio_suspend(struct device *dev)
+{
+ return tng_gpio_suspend(dev);
+}
+
+static int ehl_gpio_resume(struct device *dev)
+{
+ return tng_gpio_resume(dev);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(ehl_gpio_pm_ops, ehl_gpio_suspend, ehl_gpio_resume);
+
+static const struct platform_device_id ehl_gpio_ids[] = {
+ { "gpio-elkhartlake" },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, ehl_gpio_ids);
+
+static struct platform_driver ehl_gpio_driver = {
+ .driver = {
+ .name = "gpio-elkhartlake",
+ .pm = pm_sleep_ptr(&ehl_gpio_pm_ops),
+ },
+ .probe = ehl_gpio_probe,
+ .id_table = ehl_gpio_ids,
+};
+module_platform_driver(ehl_gpio_driver);
+
+MODULE_AUTHOR("Pandith N <pandith.n@intel.com>");
+MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>");
+MODULE_DESCRIPTION("Intel Elkhart Lake PSE GPIO driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(GPIO_TANGIER);
diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
index 2728672ef9f8..31e26072f6ae 100644
--- a/drivers/gpio/gpio-ftgpio010.c
+++ b/drivers/gpio/gpio-ftgpio010.c
@@ -349,7 +349,7 @@ static const struct of_device_id ftgpio_gpio_of_match[] = {
static struct platform_driver ftgpio_gpio_driver = {
.driver = {
.name = "ftgpio010-gpio",
- .of_match_table = of_match_ptr(ftgpio_gpio_of_match),
+ .of_match_table = ftgpio_gpio_of_match,
},
.probe = ftgpio_gpio_probe,
.remove = ftgpio_gpio_remove,
diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c
new file mode 100644
index 000000000000..208fa851e82a
--- /dev/null
+++ b/drivers/gpio/gpio-fxl6408.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * FXL6408 GPIO driver
+ *
+ * Copyright 2023 Toradex
+ *
+ * Author: Emanuele Ghidoli <emanuele.ghidoli@toradex.com>
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/regmap.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define FXL6408_REG_DEVICE_ID 0x01
+#define FXL6408_MF_FAIRCHILD 0b101
+#define FXL6408_MF_SHIFT 5
+
+/* Bits set here indicate that the GPIO is an output. */
+#define FXL6408_REG_IO_DIR 0x03
+
+/*
+ * Bits set here, when the corresponding bit of IO_DIR is set, drive
+ * the output high instead of low.
+ */
+#define FXL6408_REG_OUTPUT 0x05
+
+/* Bits here make the output High-Z, instead of the OUTPUT value. */
+#define FXL6408_REG_OUTPUT_HIGH_Z 0x07
+
+/* Returns the current status (1 = HIGH) of the input pins. */
+#define FXL6408_REG_INPUT_STATUS 0x0f
+
+/*
+ * Return the current interrupt status
+ * This bit is HIGH if input GPIO != default state (register 09h).
+ * The flag is cleared after being read (bit returns to 0).
+ * The input must go back to default state and change again before this flag is raised again.
+ */
+#define FXL6408_REG_INT_STS 0x13
+
+#define FXL6408_NGPIO 8
+
+static const struct regmap_range rd_range[] = {
+ { FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID },
+ { FXL6408_REG_IO_DIR, FXL6408_REG_OUTPUT },
+ { FXL6408_REG_INPUT_STATUS, FXL6408_REG_INPUT_STATUS },
+};
+
+static const struct regmap_range wr_range[] = {
+ { FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID },
+ { FXL6408_REG_IO_DIR, FXL6408_REG_OUTPUT },
+ { FXL6408_REG_OUTPUT_HIGH_Z, FXL6408_REG_OUTPUT_HIGH_Z },
+};
+
+static const struct regmap_range volatile_range[] = {
+ { FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID },
+ { FXL6408_REG_INPUT_STATUS, FXL6408_REG_INPUT_STATUS },
+};
+
+static const struct regmap_access_table rd_table = {
+ .yes_ranges = rd_range,
+ .n_yes_ranges = ARRAY_SIZE(rd_range),
+};
+
+static const struct regmap_access_table wr_table = {
+ .yes_ranges = wr_range,
+ .n_yes_ranges = ARRAY_SIZE(wr_range),
+};
+
+static const struct regmap_access_table volatile_table = {
+ .yes_ranges = volatile_range,
+ .n_yes_ranges = ARRAY_SIZE(volatile_range),
+};
+
+static const struct regmap_config regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = FXL6408_REG_INT_STS,
+ .wr_table = &wr_table,
+ .rd_table = &rd_table,
+ .volatile_table = &volatile_table,
+
+ .cache_type = REGCACHE_RBTREE,
+ .num_reg_defaults_raw = FXL6408_REG_INT_STS + 1,
+};
+
+static int fxl6408_identify(struct device *dev, struct regmap *regmap)
+{
+ int val, ret;
+
+ ret = regmap_read(regmap, FXL6408_REG_DEVICE_ID, &val);
+ if (ret)
+ return dev_err_probe(dev, ret, "error reading DEVICE_ID\n");
+ if (val >> FXL6408_MF_SHIFT != FXL6408_MF_FAIRCHILD)
+ return dev_err_probe(dev, -ENODEV, "invalid device id 0x%02x\n", val);
+
+ return 0;
+}
+
+static int fxl6408_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ int ret;
+ struct gpio_regmap_config gpio_config = {
+ .parent = dev,
+ .ngpio = FXL6408_NGPIO,
+ .reg_dat_base = GPIO_REGMAP_ADDR(FXL6408_REG_INPUT_STATUS),
+ .reg_set_base = GPIO_REGMAP_ADDR(FXL6408_REG_OUTPUT),
+ .reg_dir_out_base = GPIO_REGMAP_ADDR(FXL6408_REG_IO_DIR),
+ .ngpio_per_reg = FXL6408_NGPIO,
+ };
+
+ gpio_config.regmap = devm_regmap_init_i2c(client, &regmap);
+ if (IS_ERR(gpio_config.regmap))
+ return dev_err_probe(dev, PTR_ERR(gpio_config.regmap),
+ "failed to allocate register map\n");
+
+ ret = fxl6408_identify(dev, gpio_config.regmap);
+ if (ret)
+ return ret;
+
+ /* Disable High-Z of outputs, so that our OUTPUT updates actually take effect. */
+ ret = regmap_write(gpio_config.regmap, FXL6408_REG_OUTPUT_HIGH_Z, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to write 'output high Z' register\n");
+
+ return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
+}
+
+static const __maybe_unused struct of_device_id fxl6408_dt_ids[] = {
+ { .compatible = "fcs,fxl6408" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, fxl6408_dt_ids);
+
+static const struct i2c_device_id fxl6408_id[] = {
+ { "fxl6408", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, fxl6408_id);
+
+static struct i2c_driver fxl6408_driver = {
+ .driver = {
+ .name = "fxl6408",
+ .of_match_table = fxl6408_dt_ids,
+ },
+ .probe_new = fxl6408_probe,
+ .id_table = fxl6408_id,
+};
+module_i2c_driver(fxl6408_driver);
+
+MODULE_AUTHOR("Emanuele Ghidoli <emanuele.ghidoli@toradex.com>");
+MODULE_DESCRIPTION("FXL6408 GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-hisi.c b/drivers/gpio/gpio-hisi.c
index 55bd69043bf4..29a03de37fd8 100644
--- a/drivers/gpio/gpio-hisi.c
+++ b/drivers/gpio/gpio-hisi.c
@@ -37,7 +37,6 @@ struct hisi_gpio {
struct device *dev;
void __iomem *reg_base;
unsigned int line_num;
- struct irq_chip irq_chip;
int irq;
};
@@ -100,12 +99,14 @@ static void hisi_gpio_irq_set_mask(struct irq_data *d)
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_SET_WX, BIT(irqd_to_hwirq(d)));
+ gpiochip_disable_irq(chip, irqd_to_hwirq(d));
}
static void hisi_gpio_irq_clr_mask(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ gpiochip_enable_irq(chip, irqd_to_hwirq(d));
hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_CLR_WX, BIT(irqd_to_hwirq(d)));
}
@@ -191,20 +192,24 @@ static void hisi_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(irq_c, desc);
}
+static const struct irq_chip hisi_gpio_irq_chip = {
+ .name = "HISI-GPIO",
+ .irq_ack = hisi_gpio_set_ack,
+ .irq_mask = hisi_gpio_irq_set_mask,
+ .irq_unmask = hisi_gpio_irq_clr_mask,
+ .irq_set_type = hisi_gpio_irq_set_type,
+ .irq_enable = hisi_gpio_irq_enable,
+ .irq_disable = hisi_gpio_irq_disable,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static void hisi_gpio_init_irq(struct hisi_gpio *hisi_gpio)
{
struct gpio_chip *chip = &hisi_gpio->chip;
struct gpio_irq_chip *girq_chip = &chip->irq;
- /* Set hooks for irq_chip */
- hisi_gpio->irq_chip.irq_ack = hisi_gpio_set_ack;
- hisi_gpio->irq_chip.irq_mask = hisi_gpio_irq_set_mask;
- hisi_gpio->irq_chip.irq_unmask = hisi_gpio_irq_clr_mask;
- hisi_gpio->irq_chip.irq_set_type = hisi_gpio_irq_set_type;
- hisi_gpio->irq_chip.irq_enable = hisi_gpio_irq_enable;
- hisi_gpio->irq_chip.irq_disable = hisi_gpio_irq_disable;
-
- girq_chip->chip = &hisi_gpio->irq_chip;
+ gpio_irq_chip_set_chip(girq_chip, &hisi_gpio_irq_chip);
girq_chip->default_type = IRQ_TYPE_NONE;
girq_chip->num_parents = 1;
girq_chip->parents = &hisi_gpio->irq;
diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c
index 4e13e937f832..c208ac1c54a6 100644
--- a/drivers/gpio/gpio-hlwd.c
+++ b/drivers/gpio/gpio-hlwd.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
/*
@@ -48,7 +49,7 @@
struct hlwd_gpio {
struct gpio_chip gpioc;
- struct irq_chip irqc;
+ struct device *dev;
void __iomem *regs;
int irq;
u32 edge_emulation;
@@ -123,6 +124,7 @@ static void hlwd_gpio_irq_mask(struct irq_data *data)
mask &= ~BIT(data->hwirq);
iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK);
raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
+ gpiochip_disable_irq(&hlwd->gpioc, irqd_to_hwirq(data));
}
static void hlwd_gpio_irq_unmask(struct irq_data *data)
@@ -132,6 +134,7 @@ static void hlwd_gpio_irq_unmask(struct irq_data *data)
unsigned long flags;
u32 mask;
+ gpiochip_enable_irq(&hlwd->gpioc, irqd_to_hwirq(data));
raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK);
mask |= BIT(data->hwirq);
@@ -202,6 +205,24 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
return 0;
}
+static void hlwd_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p)
+{
+ struct hlwd_gpio *hlwd =
+ gpiochip_get_data(irq_data_get_irq_chip_data(data));
+
+ seq_printf(p, dev_name(hlwd->dev));
+}
+
+static const struct irq_chip hlwd_gpio_irq_chip = {
+ .irq_mask = hlwd_gpio_irq_mask,
+ .irq_unmask = hlwd_gpio_irq_unmask,
+ .irq_enable = hlwd_gpio_irq_enable,
+ .irq_set_type = hlwd_gpio_irq_set_type,
+ .irq_print_chip = hlwd_gpio_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int hlwd_gpio_probe(struct platform_device *pdev)
{
struct hlwd_gpio *hlwd;
@@ -216,6 +237,8 @@ static int hlwd_gpio_probe(struct platform_device *pdev)
if (IS_ERR(hlwd->regs))
return PTR_ERR(hlwd->regs);
+ hlwd->dev = &pdev->dev;
+
/*
* Claim all GPIOs using the OWNER register. This will not work on
* systems where the AHBPROT memory firewall hasn't been configured to
@@ -259,14 +282,8 @@ static int hlwd_gpio_probe(struct platform_device *pdev)
return hlwd->irq;
}
- hlwd->irqc.name = dev_name(&pdev->dev);
- hlwd->irqc.irq_mask = hlwd_gpio_irq_mask;
- hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask;
- hlwd->irqc.irq_enable = hlwd_gpio_irq_enable;
- hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type;
-
girq = &hlwd->gpioc.irq;
- girq->chip = &hlwd->irqc;
+ gpio_irq_chip_set_chip(girq, &hlwd_gpio_irq_chip);
girq->parent_handler = hlwd_gpio_irqhandler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1,
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index 3b31f5e9bf40..0be9285efebc 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -457,7 +457,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
init:
ichx_gpiolib_setup(&ichx_priv.chip);
- err = gpiochip_add_data(&ichx_priv.chip, NULL);
+ err = devm_gpiochip_add_data(dev, &ichx_priv.chip, NULL);
if (err) {
dev_err(dev, "Failed to register GPIOs\n");
return err;
@@ -469,19 +469,11 @@ init:
return 0;
}
-static int ichx_gpio_remove(struct platform_device *pdev)
-{
- gpiochip_remove(&ichx_priv.chip);
-
- return 0;
-}
-
static struct platform_driver ichx_gpio_driver = {
.driver = {
.name = DRV_NAME,
},
.probe = ichx_gpio_probe,
- .remove = ichx_gpio_remove,
};
module_platform_driver(ichx_gpio_driver);
diff --git a/drivers/gpio/gpio-idt3243x.c b/drivers/gpio/gpio-idt3243x.c
index 1cafdf46f875..00f547d26254 100644
--- a/drivers/gpio/gpio-idt3243x.c
+++ b/drivers/gpio/gpio-idt3243x.c
@@ -92,6 +92,8 @@ static void idt_gpio_mask(struct irq_data *d)
writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK);
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+
+ gpiochip_disable_irq(gc, irqd_to_hwirq(d));
}
static void idt_gpio_unmask(struct irq_data *d)
@@ -100,6 +102,7 @@ static void idt_gpio_unmask(struct irq_data *d)
struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
unsigned long flags;
+ gpiochip_enable_irq(gc, irqd_to_hwirq(d));
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
ctrl->mask_cache &= ~BIT(d->hwirq);
@@ -119,12 +122,14 @@ static int idt_gpio_irq_init_hw(struct gpio_chip *gc)
return 0;
}
-static struct irq_chip idt_gpio_irqchip = {
+static const struct irq_chip idt_gpio_irqchip = {
.name = "IDTGPIO",
.irq_mask = idt_gpio_mask,
.irq_ack = idt_gpio_ack,
.irq_unmask = idt_gpio_unmask,
- .irq_set_type = idt_gpio_irq_set_type
+ .irq_set_type = idt_gpio_irq_set_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int idt_gpio_probe(struct platform_device *pdev)
@@ -168,7 +173,7 @@ static int idt_gpio_probe(struct platform_device *pdev)
return parent_irq;
girq = &ctrl->gc.irq;
- girq->chip = &idt_gpio_irqchip;
+ gpio_irq_chip_set_chip(girq, &idt_gpio_irqchip);
girq->init_hw = idt_gpio_irq_init_hw;
girq->parent_handler = idt_gpio_dispatch;
girq->num_parents = 1;
diff --git a/drivers/gpio/gpio-imx-scu.c b/drivers/gpio/gpio-imx-scu.c
index 17be21b8f3b7..e190bde5397d 100644
--- a/drivers/gpio/gpio-imx-scu.c
+++ b/drivers/gpio/gpio-imx-scu.c
@@ -136,4 +136,3 @@ subsys_initcall_sync(_imx_scu_gpio_init);
MODULE_AUTHOR("Shenwei Wang <shenwei.wang@nxp.com>");
MODULE_DESCRIPTION("NXP GPIO over IMX SCU API");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c
new file mode 100644
index 000000000000..06213bbfabdd
--- /dev/null
+++ b/drivers/gpio/gpio-loongson-64bit.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Loongson GPIO Support
+ *
+ * Copyright (C) 2022-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <asm/types.h>
+
+enum loongson_gpio_mode {
+ BIT_CTRL_MODE,
+ BYTE_CTRL_MODE,
+};
+
+struct loongson_gpio_chip_data {
+ const char *label;
+ enum loongson_gpio_mode mode;
+ unsigned int conf_offset;
+ unsigned int out_offset;
+ unsigned int in_offset;
+};
+
+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;
+};
+
+static inline struct loongson_gpio_chip *to_loongson_gpio_chip(struct gpio_chip *chip)
+{
+ return container_of(chip, struct loongson_gpio_chip, chip);
+}
+
+static inline void loongson_commit_direction(struct loongson_gpio_chip *lgpio, unsigned int pin,
+ int input)
+{
+ u8 bval = input ? 1 : 0;
+
+ writeb(bval, lgpio->reg_base + lgpio->chip_data->conf_offset + pin);
+}
+
+static void loongson_commit_level(struct loongson_gpio_chip *lgpio, unsigned int pin, int high)
+{
+ u8 bval = high ? 1 : 0;
+
+ writeb(bval, lgpio->reg_base + lgpio->chip_data->out_offset + pin);
+}
+
+static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
+{
+ unsigned long flags;
+ struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
+
+ spin_lock_irqsave(&lgpio->lock, flags);
+ loongson_commit_direction(lgpio, pin, 1);
+ spin_unlock_irqrestore(&lgpio->lock, flags);
+
+ return 0;
+}
+
+static int loongson_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, int value)
+{
+ unsigned long flags;
+ struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
+
+ spin_lock_irqsave(&lgpio->lock, flags);
+ loongson_commit_level(lgpio, pin, value);
+ loongson_commit_direction(lgpio, pin, 0);
+ spin_unlock_irqrestore(&lgpio->lock, flags);
+
+ return 0;
+}
+
+static int loongson_gpio_get(struct gpio_chip *chip, unsigned int pin)
+{
+ u8 bval;
+ int val;
+ struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
+
+ bval = readb(lgpio->reg_base + lgpio->chip_data->in_offset + pin);
+ val = bval & 1;
+
+ return val;
+}
+
+static int loongson_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
+{
+ u8 bval;
+ struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
+
+ bval = readb(lgpio->reg_base + lgpio->chip_data->conf_offset + pin);
+ if (bval & 1)
+ return GPIO_LINE_DIRECTION_IN;
+
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
+{
+ unsigned long flags;
+ struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
+
+ spin_lock_irqsave(&lgpio->lock, flags);
+ loongson_commit_level(lgpio, pin, value);
+ spin_unlock_irqrestore(&lgpio->lock, flags);
+}
+
+static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct platform_device *pdev = to_platform_device(chip->parent);
+
+ return platform_get_irq(pdev, offset);
+}
+
+static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgpio,
+ struct device_node *np, void __iomem *reg_base)
+{
+ int ret;
+ u32 ngpios;
+
+ lgpio->reg_base = reg_base;
+
+ if (lgpio->chip_data->mode == BIT_CTRL_MODE) {
+ ret = bgpio_init(&lgpio->chip, dev, 8,
+ lgpio->reg_base + lgpio->chip_data->in_offset,
+ lgpio->reg_base + lgpio->chip_data->out_offset,
+ NULL, NULL,
+ lgpio->reg_base + lgpio->chip_data->conf_offset,
+ 0);
+ if (ret) {
+ dev_err(dev, "unable to init generic GPIO\n");
+ return ret;
+ }
+ } else {
+ lgpio->chip.direction_input = loongson_gpio_direction_input;
+ lgpio->chip.get = loongson_gpio_get;
+ lgpio->chip.get_direction = loongson_gpio_get_direction;
+ lgpio->chip.direction_output = loongson_gpio_direction_output;
+ lgpio->chip.set = loongson_gpio_set;
+ lgpio->chip.parent = dev;
+ spin_lock_init(&lgpio->lock);
+ }
+
+ device_property_read_u32(dev, "ngpios", &ngpios);
+
+ lgpio->chip.can_sleep = 0;
+ lgpio->chip.ngpio = ngpios;
+ lgpio->chip.label = lgpio->chip_data->label;
+ lgpio->chip.to_irq = loongson_gpio_to_irq;
+
+ return devm_gpiochip_add_data(dev, &lgpio->chip, lgpio);
+}
+
+static int loongson_gpio_probe(struct platform_device *pdev)
+{
+ void __iomem *reg_base;
+ struct loongson_gpio_chip *lgpio;
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+
+ lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL);
+ if (!lgpio)
+ return -ENOMEM;
+
+ lgpio->chip_data = device_get_match_data(dev);
+
+ reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+
+ return loongson_gpio_init(dev, lgpio, np, reg_base);
+}
+
+static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = {
+ .label = "ls2k_gpio",
+ .mode = BIT_CTRL_MODE,
+ .conf_offset = 0x0,
+ .in_offset = 0x20,
+ .out_offset = 0x10,
+};
+
+static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = {
+ .label = "ls7a_gpio",
+ .mode = BYTE_CTRL_MODE,
+ .conf_offset = 0x800,
+ .in_offset = 0xa00,
+ .out_offset = 0x900,
+};
+
+static const struct of_device_id loongson_gpio_of_match[] = {
+ {
+ .compatible = "loongson,ls2k-gpio",
+ .data = &loongson_gpio_ls2k_data,
+ },
+ {
+ .compatible = "loongson,ls7a-gpio",
+ .data = &loongson_gpio_ls7a_data,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, loongson_gpio_of_match);
+
+static const struct acpi_device_id loongson_gpio_acpi_match[] = {
+ {
+ .id = "LOON0002",
+ .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match);
+
+static struct platform_driver loongson_gpio_driver = {
+ .driver = {
+ .name = "loongson-gpio",
+ .of_match_table = loongson_gpio_of_match,
+ .acpi_match_table = loongson_gpio_acpi_match,
+ },
+ .probe = loongson_gpio_probe,
+};
+
+static int __init loongson_gpio_setup(void)
+{
+ return platform_driver_register(&loongson_gpio_driver);
+}
+postcore_initcall(loongson_gpio_setup);
+
+MODULE_DESCRIPTION("Loongson gpio driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-loongson1.c b/drivers/gpio/gpio-loongson1.c
index 5d90b3bc5a25..6ca3b969db4d 100644
--- a/drivers/gpio/gpio-loongson1.c
+++ b/drivers/gpio/gpio-loongson1.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO Driver for Loongson 1 SoC
*
- * Copyright (C) 2015-2016 Zhang, Keguang <keguang.zhang@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
+ * Copyright (C) 2015-2023 Keguang Zhang <keguang.zhang@gmail.com>
*/
#include <linux/module.h>
@@ -19,15 +16,19 @@
#define GPIO_DATA 0x20
#define GPIO_OUTPUT 0x30
-static void __iomem *gpio_reg_base;
+struct ls1x_gpio_chip {
+ struct gpio_chip gc;
+ void __iomem *reg_base;
+};
static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
{
+ struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
- __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | BIT(offset),
- gpio_reg_base + GPIO_CFG);
+ __raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) | BIT(offset),
+ ls1x_gc->reg_base + GPIO_CFG);
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
@@ -35,61 +36,75 @@ static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset)
{
+ struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc);
unsigned long flags;
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
- __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~BIT(offset),
- gpio_reg_base + GPIO_CFG);
+ __raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) & ~BIT(offset),
+ ls1x_gc->reg_base + GPIO_CFG);
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static int ls1x_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct gpio_chip *gc;
+ struct ls1x_gpio_chip *ls1x_gc;
int ret;
- gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
- if (!gc)
+ ls1x_gc = devm_kzalloc(dev, sizeof(*ls1x_gc), GFP_KERNEL);
+ if (!ls1x_gc)
return -ENOMEM;
- gpio_reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(gpio_reg_base))
- return PTR_ERR(gpio_reg_base);
+ ls1x_gc->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ls1x_gc->reg_base))
+ return PTR_ERR(ls1x_gc->reg_base);
- ret = bgpio_init(gc, dev, 4, gpio_reg_base + GPIO_DATA,
- gpio_reg_base + GPIO_OUTPUT, NULL,
- NULL, gpio_reg_base + GPIO_DIR, 0);
+ ret = bgpio_init(&ls1x_gc->gc, dev, 4, ls1x_gc->reg_base + GPIO_DATA,
+ ls1x_gc->reg_base + GPIO_OUTPUT, NULL,
+ NULL, ls1x_gc->reg_base + GPIO_DIR, 0);
if (ret)
goto err;
- gc->owner = THIS_MODULE;
- gc->request = ls1x_gpio_request;
- gc->free = ls1x_gpio_free;
- gc->base = pdev->id * 32;
+ ls1x_gc->gc.owner = THIS_MODULE;
+ ls1x_gc->gc.request = ls1x_gpio_request;
+ ls1x_gc->gc.free = ls1x_gpio_free;
+ /*
+ * Clear ngpio to let gpiolib get the correct number
+ * by reading ngpios property
+ */
+ ls1x_gc->gc.ngpio = 0;
- ret = devm_gpiochip_add_data(dev, gc, NULL);
+ ret = devm_gpiochip_add_data(dev, &ls1x_gc->gc, ls1x_gc);
if (ret)
goto err;
- platform_set_drvdata(pdev, gc);
- dev_info(dev, "Loongson1 GPIO driver registered\n");
+ platform_set_drvdata(pdev, ls1x_gc);
+
+ dev_info(dev, "GPIO controller registered with %d pins\n",
+ ls1x_gc->gc.ngpio);
return 0;
err:
- dev_err(dev, "failed to register GPIO device\n");
+ dev_err(dev, "failed to register GPIO controller\n");
return ret;
}
+static const struct of_device_id ls1x_gpio_dt_ids[] = {
+ { .compatible = "loongson,ls1x-gpio" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ls1x_gpio_dt_ids);
+
static struct platform_driver ls1x_gpio_driver = {
.probe = ls1x_gpio_probe,
.driver = {
.name = "ls1x-gpio",
+ .of_match_table = ls1x_gpio_dt_ids,
},
};
module_platform_driver(ls1x_gpio_driver);
-MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>");
+MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>");
MODULE_DESCRIPTION("Loongson1 GPIO driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 68e982cdee73..7f2fde191755 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -351,6 +351,7 @@ static void max732x_irq_mask(struct irq_data *d)
struct max732x_chip *chip = gpiochip_get_data(gc);
chip->irq_mask_cur &= ~(1 << d->hwirq);
+ gpiochip_disable_irq(gc, irqd_to_hwirq(d));
}
static void max732x_irq_unmask(struct irq_data *d)
@@ -358,6 +359,7 @@ static void max732x_irq_unmask(struct irq_data *d)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct max732x_chip *chip = gpiochip_get_data(gc);
+ gpiochip_enable_irq(gc, irqd_to_hwirq(d));
chip->irq_mask_cur |= 1 << d->hwirq;
}
@@ -429,7 +431,7 @@ static int max732x_irq_set_wake(struct irq_data *data, unsigned int on)
return 0;
}
-static struct irq_chip max732x_irq_chip = {
+static const struct irq_chip max732x_irq_chip = {
.name = "max732x",
.irq_mask = max732x_irq_mask,
.irq_unmask = max732x_irq_unmask,
@@ -437,6 +439,8 @@ static struct irq_chip max732x_irq_chip = {
.irq_bus_sync_unlock = max732x_irq_bus_sync_unlock,
.irq_set_type = max732x_irq_set_type,
.irq_set_wake = max732x_irq_set_wake,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static uint8_t max732x_irq_pending(struct max732x_chip *chip)
@@ -517,7 +521,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
}
girq = &chip->gpio_chip.irq;
- girq->chip = &max732x_irq_chip;
+ gpio_irq_chip_set_chip(girq, &max732x_irq_chip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c
index 92ea8411050d..421d7e3a6c66 100644
--- a/drivers/gpio/gpio-merrifield.c
+++ b/drivers/gpio/gpio-merrifield.c
@@ -2,60 +2,25 @@
/*
* Intel Merrifield SoC GPIO driver
*
- * Copyright (c) 2016 Intel Corporation.
+ * Copyright (c) 2016, 2023 Intel Corporation.
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*/
#include <linux/acpi.h>
#include <linux/bitops.h>
-#include <linux/gpio/driver.h>
-#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/pinctrl/consumer.h>
-#include <linux/string_helpers.h>
+#include <linux/types.h>
-#define GCCR 0x000 /* controller configuration */
-#define GPLR 0x004 /* pin level r/o */
-#define GPDR 0x01c /* pin direction */
-#define GPSR 0x034 /* pin set w/o */
-#define GPCR 0x04c /* pin clear w/o */
-#define GRER 0x064 /* rising edge detect */
-#define GFER 0x07c /* falling edge detect */
-#define GFBR 0x094 /* glitch filter bypass */
-#define GIMR 0x0ac /* interrupt mask */
-#define GISR 0x0c4 /* interrupt source */
-#define GITR 0x300 /* input type */
-#define GLPR 0x318 /* level input polarity */
-#define GWMR 0x400 /* wake mask */
-#define GWSR 0x418 /* wake source */
-#define GSIR 0xc00 /* secure input */
+#include "gpio-tangier.h"
/* Intel Merrifield has 192 GPIO pins */
#define MRFLD_NGPIO 192
-struct mrfld_gpio_pinrange {
- unsigned int gpio_base;
- unsigned int pin_base;
- unsigned int npins;
-};
-
-#define GPIO_PINRANGE(gstart, gend, pstart) \
- { \
- .gpio_base = (gstart), \
- .pin_base = (pstart), \
- .npins = (gend) - (gstart) + 1, \
- }
-
-struct mrfld_gpio {
- struct gpio_chip chip;
- void __iomem *reg_base;
- raw_spinlock_t lock;
- struct device *dev;
-};
-
-static const struct mrfld_gpio_pinrange mrfld_gpio_ranges[] = {
+static const struct tng_gpio_pinrange mrfld_gpio_ranges[] = {
GPIO_PINRANGE(0, 11, 146),
GPIO_PINRANGE(12, 13, 144),
GPIO_PINRANGE(14, 15, 35),
@@ -84,323 +49,15 @@ static const struct mrfld_gpio_pinrange mrfld_gpio_ranges[] = {
GPIO_PINRANGE(190, 191, 178),
};
-static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset,
- unsigned int reg_type_offset)
-{
- struct mrfld_gpio *priv = gpiochip_get_data(chip);
- u8 reg = offset / 32;
-
- return priv->reg_base + reg_type_offset + reg * 4;
-}
-
-static int mrfld_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
- void __iomem *gplr = gpio_reg(chip, offset, GPLR);
-
- return !!(readl(gplr) & BIT(offset % 32));
-}
-
-static void mrfld_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
-{
- struct mrfld_gpio *priv = gpiochip_get_data(chip);
- void __iomem *gpsr, *gpcr;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&priv->lock, flags);
-
- if (value) {
- gpsr = gpio_reg(chip, offset, GPSR);
- writel(BIT(offset % 32), gpsr);
- } else {
- gpcr = gpio_reg(chip, offset, GPCR);
- writel(BIT(offset % 32), gpcr);
- }
-
- raw_spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int mrfld_gpio_direction_input(struct gpio_chip *chip,
- unsigned int offset)
-{
- struct mrfld_gpio *priv = gpiochip_get_data(chip);
- void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
- unsigned long flags;
- u32 value;
-
- raw_spin_lock_irqsave(&priv->lock, flags);
-
- value = readl(gpdr);
- value &= ~BIT(offset % 32);
- writel(value, gpdr);
-
- raw_spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int mrfld_gpio_direction_output(struct gpio_chip *chip,
- unsigned int offset, int value)
-{
- struct mrfld_gpio *priv = gpiochip_get_data(chip);
- void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
- unsigned long flags;
-
- mrfld_gpio_set(chip, offset, value);
-
- raw_spin_lock_irqsave(&priv->lock, flags);
-
- value = readl(gpdr);
- value |= BIT(offset % 32);
- writel(value, gpdr);
-
- raw_spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
-{
- void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
-
- if (readl(gpdr) & BIT(offset % 32))
- return GPIO_LINE_DIRECTION_OUT;
-
- return GPIO_LINE_DIRECTION_IN;
-}
-
-static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
- unsigned int debounce)
-{
- struct mrfld_gpio *priv = gpiochip_get_data(chip);
- void __iomem *gfbr = gpio_reg(chip, offset, GFBR);
- unsigned long flags;
- u32 value;
-
- raw_spin_lock_irqsave(&priv->lock, flags);
-
- if (debounce)
- value = readl(gfbr) & ~BIT(offset % 32);
- else
- value = readl(gfbr) | BIT(offset % 32);
- writel(value, gfbr);
-
- raw_spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
- unsigned long config)
-{
- u32 debounce;
-
- if ((pinconf_to_config_param(config) == PIN_CONFIG_BIAS_DISABLE) ||
- (pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_UP) ||
- (pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_DOWN))
- return gpiochip_generic_config(chip, offset, config);
-
- if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
- return -ENOTSUPP;
-
- debounce = pinconf_to_config_argument(config);
- return mrfld_gpio_set_debounce(chip, offset, debounce);
-}
-
-static void mrfld_irq_ack(struct irq_data *d)
-{
- struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
- u32 gpio = irqd_to_hwirq(d);
- void __iomem *gisr = gpio_reg(&priv->chip, gpio, GISR);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&priv->lock, flags);
-
- writel(BIT(gpio % 32), gisr);
-
- raw_spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void mrfld_irq_unmask_mask(struct mrfld_gpio *priv, u32 gpio, bool unmask)
-{
- void __iomem *gimr = gpio_reg(&priv->chip, gpio, GIMR);
- unsigned long flags;
- u32 value;
-
- raw_spin_lock_irqsave(&priv->lock, flags);
-
- if (unmask)
- value = readl(gimr) | BIT(gpio % 32);
- else
- value = readl(gimr) & ~BIT(gpio % 32);
- writel(value, gimr);
-
- raw_spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void mrfld_irq_mask(struct irq_data *d)
-{
- struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
- u32 gpio = irqd_to_hwirq(d);
-
- mrfld_irq_unmask_mask(priv, gpio, false);
- gpiochip_disable_irq(&priv->chip, gpio);
-}
-
-static void mrfld_irq_unmask(struct irq_data *d)
-{
- struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
- u32 gpio = irqd_to_hwirq(d);
-
- gpiochip_enable_irq(&priv->chip, gpio);
- mrfld_irq_unmask_mask(priv, gpio, true);
-}
-
-static int mrfld_irq_set_type(struct irq_data *d, unsigned int type)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct mrfld_gpio *priv = gpiochip_get_data(gc);
- u32 gpio = irqd_to_hwirq(d);
- void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER);
- void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER);
- void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR);
- void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR);
- unsigned long flags;
- u32 value;
-
- raw_spin_lock_irqsave(&priv->lock, flags);
-
- if (type & IRQ_TYPE_EDGE_RISING)
- value = readl(grer) | BIT(gpio % 32);
- else
- value = readl(grer) & ~BIT(gpio % 32);
- writel(value, grer);
-
- if (type & IRQ_TYPE_EDGE_FALLING)
- value = readl(gfer) | BIT(gpio % 32);
- else
- value = readl(gfer) & ~BIT(gpio % 32);
- writel(value, gfer);
-
- /*
- * To prevent glitches from triggering an unintended level interrupt,
- * configure GLPR register first and then configure GITR.
- */
- if (type & IRQ_TYPE_LEVEL_LOW)
- value = readl(glpr) | BIT(gpio % 32);
- else
- value = readl(glpr) & ~BIT(gpio % 32);
- writel(value, glpr);
-
- if (type & IRQ_TYPE_LEVEL_MASK) {
- value = readl(gitr) | BIT(gpio % 32);
- writel(value, gitr);
-
- irq_set_handler_locked(d, handle_level_irq);
- } else if (type & IRQ_TYPE_EDGE_BOTH) {
- value = readl(gitr) & ~BIT(gpio % 32);
- writel(value, gitr);
-
- irq_set_handler_locked(d, handle_edge_irq);
- }
-
- raw_spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct mrfld_gpio *priv = gpiochip_get_data(gc);
- u32 gpio = irqd_to_hwirq(d);
- void __iomem *gwmr = gpio_reg(&priv->chip, gpio, GWMR);
- void __iomem *gwsr = gpio_reg(&priv->chip, gpio, GWSR);
- unsigned long flags;
- u32 value;
-
- raw_spin_lock_irqsave(&priv->lock, flags);
-
- /* Clear the existing wake status */
- writel(BIT(gpio % 32), gwsr);
-
- if (on)
- value = readl(gwmr) | BIT(gpio % 32);
- else
- value = readl(gwmr) & ~BIT(gpio % 32);
- writel(value, gwmr);
-
- raw_spin_unlock_irqrestore(&priv->lock, flags);
-
- dev_dbg(priv->dev, "%s wake for gpio %u\n", str_enable_disable(on), gpio);
- return 0;
-}
-
-static const struct irq_chip mrfld_irqchip = {
- .name = "gpio-merrifield",
- .irq_ack = mrfld_irq_ack,
- .irq_mask = mrfld_irq_mask,
- .irq_unmask = mrfld_irq_unmask,
- .irq_set_type = mrfld_irq_set_type,
- .irq_set_wake = mrfld_irq_set_wake,
- .flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
-};
-
-static void mrfld_irq_handler(struct irq_desc *desc)
-{
- struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct mrfld_gpio *priv = gpiochip_get_data(gc);
- struct irq_chip *irqchip = irq_desc_get_chip(desc);
- unsigned long base, gpio;
-
- chained_irq_enter(irqchip, desc);
-
- /* Check GPIO controller to check which pin triggered the interrupt */
- for (base = 0; base < priv->chip.ngpio; base += 32) {
- void __iomem *gisr = gpio_reg(&priv->chip, base, GISR);
- void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR);
- unsigned long pending, enabled;
-
- pending = readl(gisr);
- enabled = readl(gimr);
-
- /* Only interrupts that are enabled */
- pending &= enabled;
-
- for_each_set_bit(gpio, &pending, 32)
- generic_handle_domain_irq(gc->irq.domain, base + gpio);
- }
-
- chained_irq_exit(irqchip, desc);
-}
-
-static int mrfld_irq_init_hw(struct gpio_chip *chip)
-{
- struct mrfld_gpio *priv = gpiochip_get_data(chip);
- void __iomem *reg;
- unsigned int base;
-
- for (base = 0; base < priv->chip.ngpio; base += 32) {
- /* Clear the rising-edge detect register */
- reg = gpio_reg(&priv->chip, base, GRER);
- writel(0, reg);
- /* Clear the falling-edge detect register */
- reg = gpio_reg(&priv->chip, base, GFER);
- writel(0, reg);
- }
-
- return 0;
-}
-
-static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv)
+static const char *mrfld_gpio_get_pinctrl_dev_name(struct tng_gpio *priv)
{
+ struct device *dev = priv->dev;
struct acpi_device *adev;
const char *name;
adev = acpi_dev_get_first_match_dev("INTC1002", NULL, -1);
if (adev) {
- name = devm_kstrdup(priv->dev, acpi_dev_name(adev), GFP_KERNEL);
+ name = devm_kstrdup(dev, acpi_dev_name(adev), GFP_KERNEL);
acpi_dev_put(adev);
} else {
name = "pinctrl-merrifield";
@@ -409,37 +66,10 @@ static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv)
return name;
}
-static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip)
-{
- struct mrfld_gpio *priv = gpiochip_get_data(chip);
- const struct mrfld_gpio_pinrange *range;
- const char *pinctrl_dev_name;
- unsigned int i;
- int retval;
-
- pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv);
- if (!pinctrl_dev_name)
- return -ENOMEM;
-
- for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
- range = &mrfld_gpio_ranges[i];
- retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name,
- range->gpio_base,
- range->pin_base,
- range->npins);
- if (retval) {
- dev_err(priv->dev, "failed to add GPIO pin range\n");
- return retval;
- }
- }
-
- return 0;
-}
-
static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- struct gpio_irq_chip *girq;
- struct mrfld_gpio *priv;
+ struct device *dev = &pdev->dev;
+ struct tng_gpio *priv;
u32 gpio_base, irq_base;
void __iomem *base;
int retval;
@@ -449,10 +79,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
return retval;
retval = pcim_iomap_regions(pdev, BIT(1) | BIT(0), pci_name(pdev));
- if (retval) {
- dev_err(&pdev->dev, "I/O memory mapping error\n");
- return retval;
- }
+ if (retval)
+ return dev_err_probe(dev, retval, "I/O memory mapping error\n");
base = pcim_iomap_table(pdev)[1];
@@ -462,53 +90,36 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
/* Release the IO mapping, since we already get the info from BAR1 */
pcim_iounmap_regions(pdev, BIT(1));
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->dev = &pdev->dev;
+ priv->dev = dev;
priv->reg_base = pcim_iomap_table(pdev)[0];
- priv->chip.label = dev_name(&pdev->dev);
- priv->chip.parent = &pdev->dev;
- priv->chip.request = gpiochip_generic_request;
- priv->chip.free = gpiochip_generic_free;
- priv->chip.direction_input = mrfld_gpio_direction_input;
- priv->chip.direction_output = mrfld_gpio_direction_output;
- priv->chip.get = mrfld_gpio_get;
- priv->chip.set = mrfld_gpio_set;
- priv->chip.get_direction = mrfld_gpio_get_direction;
- priv->chip.set_config = mrfld_gpio_set_config;
- priv->chip.base = gpio_base;
- priv->chip.ngpio = MRFLD_NGPIO;
- priv->chip.can_sleep = false;
- priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges;
+ priv->pin_info.pin_ranges = mrfld_gpio_ranges;
+ priv->pin_info.nranges = ARRAY_SIZE(mrfld_gpio_ranges);
+ priv->pin_info.name = mrfld_gpio_get_pinctrl_dev_name(priv);
+ if (!priv->pin_info.name)
+ return -ENOMEM;
- raw_spin_lock_init(&priv->lock);
+ priv->info.base = gpio_base;
+ priv->info.ngpio = MRFLD_NGPIO;
+ priv->info.first = irq_base;
retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
if (retval < 0)
return retval;
- girq = &priv->chip.irq;
- gpio_irq_chip_set_chip(girq, &mrfld_irqchip);
- girq->init_hw = mrfld_irq_init_hw;
- girq->parent_handler = mrfld_irq_handler;
- girq->num_parents = 1;
- girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
- sizeof(*girq->parents), GFP_KERNEL);
- if (!girq->parents)
- return -ENOMEM;
- girq->parents[0] = pci_irq_vector(pdev, 0);
- girq->first = irq_base;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_bad_irq;
+ priv->irq = pci_irq_vector(pdev, 0);
- retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
- if (retval) {
- dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
- return retval;
- }
+ priv->wake_regs.gwmr = GWMR_MRFLD;
+ priv->wake_regs.gwsr = GWSR_MRFLD;
+ priv->wake_regs.gsir = GSIR_MRFLD;
+
+ retval = devm_tng_gpio_probe(dev, priv);
+ if (retval)
+ return dev_err_probe(dev, retval, "tng_gpio_probe error\n");
pci_set_drvdata(pdev, priv);
return 0;
@@ -525,9 +136,9 @@ static struct pci_driver mrfld_gpio_driver = {
.id_table = mrfld_gpio_ids,
.probe = mrfld_gpio_probe,
};
-
module_pci_driver(mrfld_gpio_driver);
MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
MODULE_DESCRIPTION("Intel Merrifield SoC GPIO driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(GPIO_TANGIER);
diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c
index 77a41151c921..6abe01bc39c3 100644
--- a/drivers/gpio/gpio-mlxbf2.c
+++ b/drivers/gpio/gpio-mlxbf2.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/resource.h>
+#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -65,10 +66,10 @@ struct mlxbf2_gpio_context_save_regs {
/* BlueField-2 gpio block context structure. */
struct mlxbf2_gpio_context {
struct gpio_chip gc;
- struct irq_chip irq_chip;
/* YU GPIO blocks address */
void __iomem *gpio_io;
+ struct device *dev;
struct mlxbf2_gpio_context_save_regs *csave_regs;
};
@@ -237,6 +238,7 @@ static void mlxbf2_gpio_irq_enable(struct irq_data *irqd)
unsigned long flags;
u32 val;
+ gpiochip_enable_irq(gc, irqd_to_hwirq(irqd));
raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
val |= BIT(offset);
@@ -261,6 +263,7 @@ static void mlxbf2_gpio_irq_disable(struct irq_data *irqd)
val &= ~BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
+ gpiochip_disable_irq(gc, irqd_to_hwirq(irqd));
}
static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr)
@@ -322,6 +325,24 @@ mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
return 0;
}
+static void mlxbf2_gpio_irq_print_chip(struct irq_data *irqd,
+ struct seq_file *p)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc);
+
+ seq_printf(p, dev_name(gs->dev));
+}
+
+static const struct irq_chip mlxbf2_gpio_irq_chip = {
+ .irq_set_type = mlxbf2_gpio_irq_set_type,
+ .irq_enable = mlxbf2_gpio_irq_enable,
+ .irq_disable = mlxbf2_gpio_irq_disable,
+ .irq_print_chip = mlxbf2_gpio_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
/* BlueField-2 GPIO driver initialization routine. */
static int
mlxbf2_gpio_probe(struct platform_device *pdev)
@@ -340,6 +361,8 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
if (!gs)
return -ENOMEM;
+ gs->dev = dev;
+
/* YU GPIO block address */
gs->gpio_io = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(gs->gpio_io))
@@ -376,13 +399,8 @@ mlxbf2_gpio_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq >= 0) {
- gs->irq_chip.name = name;
- gs->irq_chip.irq_set_type = mlxbf2_gpio_irq_set_type;
- gs->irq_chip.irq_enable = mlxbf2_gpio_irq_enable;
- gs->irq_chip.irq_disable = mlxbf2_gpio_irq_disable;
-
girq = &gs->gc.irq;
- girq->chip = &gs->irq_chip;
+ gpio_irq_chip_set_chip(girq, &mlxbf2_gpio_irq_chip);
girq->handler = handle_simple_irq;
girq->default_type = IRQ_TYPE_NONE;
/* This will let us handle the parent IRQ in the driver */
diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c
index 538e31fe8903..f3c158259636 100644
--- a/drivers/gpio/gpio-mm-lantiq.c
+++ b/drivers/gpio/gpio-mm-lantiq.c
@@ -10,8 +10,8 @@
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/legacy-of-mm-gpiochip.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/slab.h>
diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c
index 000494e0c533..3b0bfff8c778 100644
--- a/drivers/gpio/gpio-mpc5200.c
+++ b/drivers/gpio/gpio-mpc5200.c
@@ -8,7 +8,7 @@
#include <linux/of.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/legacy-of-mm-gpiochip.h>
#include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/module.h>
diff --git a/drivers/gpio/gpio-msc313.c b/drivers/gpio/gpio-msc313.c
index b0773e5652fa..036ad2324892 100644
--- a/drivers/gpio/gpio-msc313.c
+++ b/drivers/gpio/gpio-msc313.c
@@ -532,17 +532,35 @@ static int msc313_gpio_direction_output(struct gpio_chip *chip, unsigned int off
return 0;
}
+static void msc313_gpio_irq_mask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ irq_chip_mask_parent(d);
+ gpiochip_disable_irq(gc, d->hwirq);
+}
+
+static void msc313_gpio_irq_unmask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ gpiochip_enable_irq(gc, d->hwirq);
+ irq_chip_unmask_parent(d);
+}
+
/*
* The interrupt handling happens in the parent interrupt controller,
* we don't do anything here.
*/
-static struct irq_chip msc313_gpio_irqchip = {
+static const struct irq_chip msc313_gpio_irqchip = {
.name = "GPIO",
.irq_eoi = irq_chip_eoi_parent,
- .irq_mask = irq_chip_mask_parent,
- .irq_unmask = irq_chip_unmask_parent,
+ .irq_mask = msc313_gpio_irq_mask,
+ .irq_unmask = msc313_gpio_irq_unmask,
.irq_set_type = irq_chip_set_type_parent,
.irq_set_affinity = irq_chip_set_affinity_parent,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
/*
@@ -644,7 +662,7 @@ static int msc313_gpio_probe(struct platform_device *pdev)
gpiochip->names = gpio->gpio_data->names;
gpioirqchip = &gpiochip->irq;
- gpioirqchip->chip = &msc313_gpio_irqchip;
+ gpio_irq_chip_set_chip(gpioirqchip, &msc313_gpio_irqchip);
gpioirqchip->fwnode = of_node_to_fwnode(dev->of_node);
gpioirqchip->parent_domain = parent_domain;
gpioirqchip->child_to_parent_hwirq = msc313e_gpio_child_to_parent_hwirq;
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index 7f59e5d936c2..390e619a2831 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -364,4 +364,3 @@ MODULE_AUTHOR("Freescale Semiconductor, "
"Daniel Mack <danielncaiaq.de>, "
"Juergen Beisert <kernel@pengutronix.de>");
MODULE_DESCRIPTION("Freescale MXS GPIO");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index f5f3d4b22452..a08be5bf6808 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/seq_file.h>
#include <linux/syscore_ops.h>
#include <linux/err.h>
#include <linux/clk.h>
@@ -47,6 +48,7 @@ struct gpio_regs {
struct gpio_bank {
void __iomem *base;
const struct omap_gpio_reg_offs *regs;
+ struct device *dev;
int irq;
u32 non_wakeup_gpios;
@@ -681,6 +683,7 @@ static void omap_gpio_mask_irq(struct irq_data *d)
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
omap_set_gpio_irqenable(bank, offset, 0);
raw_spin_unlock_irqrestore(&bank->lock, flags);
+ gpiochip_disable_irq(&bank->chip, offset);
}
static void omap_gpio_unmask_irq(struct irq_data *d)
@@ -690,6 +693,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
u32 trigger = irqd_get_trigger_type(d);
unsigned long flags;
+ gpiochip_enable_irq(&bank->chip, offset);
raw_spin_lock_irqsave(&bank->lock, flags);
omap_set_gpio_irqenable(bank, offset, 1);
@@ -708,6 +712,40 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
+static void omap_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
+
+ seq_printf(p, dev_name(bank->dev));
+}
+
+static const struct irq_chip omap_gpio_irq_chip = {
+ .irq_startup = omap_gpio_irq_startup,
+ .irq_shutdown = omap_gpio_irq_shutdown,
+ .irq_mask = omap_gpio_mask_irq,
+ .irq_unmask = omap_gpio_unmask_irq,
+ .irq_set_type = omap_gpio_irq_type,
+ .irq_set_wake = omap_gpio_wake_enable,
+ .irq_bus_lock = omap_gpio_irq_bus_lock,
+ .irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
+ .irq_print_chip = omap_gpio_irq_print_chip,
+ .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static const struct irq_chip omap_gpio_irq_chip_nowake = {
+ .irq_startup = omap_gpio_irq_startup,
+ .irq_shutdown = omap_gpio_irq_shutdown,
+ .irq_mask = omap_gpio_mask_irq,
+ .irq_unmask = omap_gpio_unmask_irq,
+ .irq_set_type = omap_gpio_irq_type,
+ .irq_bus_lock = omap_gpio_irq_bus_lock,
+ .irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
+ .irq_print_chip = omap_gpio_irq_print_chip,
+ .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
/*---------------------------------------------------------------------*/
static int omap_mpuio_suspend_noirq(struct device *dev)
@@ -986,13 +1024,11 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
writel_relaxed(0, base + bank->regs->ctrl);
}
-static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc,
- struct device *pm_dev)
+static int omap_gpio_chip_init(struct gpio_bank *bank, struct device *pm_dev)
{
struct gpio_irq_chip *irq;
static int gpio;
const char *label;
- int irq_base = 0;
int ret;
/*
@@ -1024,30 +1060,16 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc,
}
bank->chip.ngpio = bank->width;
-#ifdef CONFIG_ARCH_OMAP1
- /*
- * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
- * irq_alloc_descs() since a base IRQ offset will no longer be needed.
- */
- irq_base = devm_irq_alloc_descs(bank->chip.parent,
- -1, 0, bank->width, 0);
- if (irq_base < 0) {
- dev_err(bank->chip.parent, "Couldn't allocate IRQ numbers\n");
- return -ENODEV;
- }
-#endif
-
+ irq = &bank->chip.irq;
/* MPUIO is a bit different, reading IRQ status clears it */
if (bank->is_mpuio && !bank->regs->wkup_en)
- irqc->irq_set_wake = NULL;
-
- irq = &bank->chip.irq;
- irq->chip = irqc;
+ gpio_irq_chip_set_chip(irq, &omap_gpio_irq_chip_nowake);
+ else
+ gpio_irq_chip_set_chip(irq, &omap_gpio_irq_chip);
irq->handler = handle_bad_irq;
irq->default_type = IRQ_TYPE_NONE;
irq->num_parents = 1;
irq->parents = &bank->irq;
- irq->first = irq_base;
ret = gpiochip_add_data(&bank->chip, bank);
if (ret)
@@ -1376,7 +1398,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node;
const struct omap_gpio_platform_data *pdata;
struct gpio_bank *bank;
- struct irq_chip *irqc;
int ret;
pdata = device_get_match_data(dev);
@@ -1389,21 +1410,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
if (!bank)
return -ENOMEM;
- irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
- if (!irqc)
- return -ENOMEM;
-
- irqc->irq_startup = omap_gpio_irq_startup,
- irqc->irq_shutdown = omap_gpio_irq_shutdown,
- irqc->irq_ack = dummy_irq_chip.irq_ack,
- irqc->irq_mask = omap_gpio_mask_irq,
- irqc->irq_unmask = omap_gpio_unmask_irq,
- irqc->irq_set_type = omap_gpio_irq_type,
- irqc->irq_set_wake = omap_gpio_wake_enable,
- irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
- irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
- irqc->name = dev_name(&pdev->dev);
- irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
+ bank->dev = dev;
bank->irq = platform_get_irq(pdev, 0);
if (bank->irq <= 0) {
@@ -1467,7 +1474,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_gpio_mod_init(bank);
- ret = omap_gpio_chip_init(bank, irqc, dev);
+ ret = omap_gpio_chip_init(bank, dev);
if (ret) {
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c
index a86ce748384b..6726c32e31e6 100644
--- a/drivers/gpio/gpio-pci-idio-16.c
+++ b/drivers/gpio/gpio-pci-idio-16.c
@@ -107,6 +107,8 @@ static void idio_16_irq_mask(struct irq_data *data)
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
+
+ gpiochip_disable_irq(chip, irqd_to_hwirq(data));
}
static void idio_16_irq_unmask(struct irq_data *data)
@@ -117,6 +119,8 @@ static void idio_16_irq_unmask(struct irq_data *data)
const unsigned long prev_irq_mask = idio16gpio->irq_mask;
unsigned long flags;
+ gpiochip_enable_irq(chip, irqd_to_hwirq(data));
+
idio16gpio->irq_mask |= mask;
if (!prev_irq_mask) {
@@ -138,12 +142,14 @@ static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
return 0;
}
-static struct irq_chip idio_16_irqchip = {
+static const struct irq_chip idio_16_irqchip = {
.name = "pci-idio-16",
.irq_ack = idio_16_irq_ack,
.irq_mask = idio_16_irq_mask,
.irq_unmask = idio_16_irq_unmask,
- .irq_set_type = idio_16_irq_set_type
+ .irq_set_type = idio_16_irq_set_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
@@ -242,7 +248,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
idio_16_state_init(&idio16gpio->state);
girq = &idio16gpio->chip.irq;
- girq->chip = &idio_16_irqchip;
+ gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c
index 8a9b98fa418f..463c0613abb9 100644
--- a/drivers/gpio/gpio-pcie-idio-24.c
+++ b/drivers/gpio/gpio-pcie-idio-24.c
@@ -3,15 +3,6 @@
* GPIO driver for the ACCES PCIe-IDIO-24 family
* Copyright (C) 2018 William Breathitt Gray
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
* This driver supports the following ACCES devices: PCIe-IDIO-24,
* PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
*/
@@ -396,6 +387,8 @@ static void idio_24_irq_mask(struct irq_data *data)
}
raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+
+ gpiochip_disable_irq(chip, irqd_to_hwirq(data));
}
static void idio_24_irq_unmask(struct irq_data *data)
@@ -408,6 +401,8 @@ static void idio_24_irq_unmask(struct irq_data *data)
const unsigned long bank_offset = bit_offset / 8;
unsigned char cos_enable_state;
+ gpiochip_enable_irq(chip, irqd_to_hwirq(data));
+
raw_spin_lock_irqsave(&idio24gpio->lock, flags);
prev_irq_mask = idio24gpio->irq_mask >> bank_offset * 8;
@@ -437,12 +432,14 @@ static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
return 0;
}
-static struct irq_chip idio_24_irqchip = {
+static const struct irq_chip idio_24_irqchip = {
.name = "pcie-idio-24",
.irq_ack = idio_24_irq_ack,
.irq_mask = idio_24_irq_mask,
.irq_unmask = idio_24_irq_unmask,
- .irq_set_type = idio_24_irq_set_type
+ .irq_set_type = idio_24_irq_set_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
@@ -535,7 +532,7 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
girq = &idio24gpio->chip.irq;
- girq->chip = &idio_24_irqchip;
+ gpio_irq_chip_set_chip(girq, &idio_24_irqchip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 1198ab0305d0..a1630ed4b741 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -171,11 +171,6 @@ static inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c,
return chip_to_pxachip(c)->banks + gpio / 32;
}
-static inline int gpio_is_pxa_type(int type)
-{
- return (type & MMP_GPIO) == 0;
-}
-
static inline int gpio_is_mmp_type(int type)
{
return (type & MMP_GPIO) != 0;
diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c
index 3c414e0005fc..ecb0d3800dfe 100644
--- a/drivers/gpio/gpio-raspberrypi-exp.c
+++ b/drivers/gpio/gpio-raspberrypi-exp.c
@@ -234,7 +234,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev)
return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
}
-static const struct of_device_id rpi_exp_gpio_ids[] = {
+static const struct of_device_id rpi_exp_gpio_ids[] __maybe_unused = {
{ .compatible = "raspberrypi,firmware-gpio" },
{ }
};
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 5b117f3bd322..2525adb52f4f 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -663,7 +663,7 @@ static struct platform_driver gpio_rcar_device_driver = {
.driver = {
.name = "gpio_rcar",
.pm = &gpio_rcar_pm_ops,
- .of_match_table = of_match_ptr(gpio_rcar_of_table),
+ .of_match_table = gpio_rcar_of_table,
}
};
diff --git a/drivers/gpio/gpio-rda.c b/drivers/gpio/gpio-rda.c
index 62ba18b3a602..cb2f63eee2aa 100644
--- a/drivers/gpio/gpio-rda.c
+++ b/drivers/gpio/gpio-rda.c
@@ -38,7 +38,6 @@ struct rda_gpio {
struct gpio_chip chip;
void __iomem *base;
spinlock_t lock;
- struct irq_chip irq_chip;
int irq;
};
@@ -74,6 +73,7 @@ static void rda_gpio_irq_mask(struct irq_data *data)
value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
+ gpiochip_disable_irq(chip, offset);
}
static void rda_gpio_irq_ack(struct irq_data *data)
@@ -154,6 +154,7 @@ static void rda_gpio_irq_unmask(struct irq_data *data)
u32 offset = irqd_to_hwirq(data);
u32 trigger = irqd_get_trigger_type(data);
+ gpiochip_enable_irq(chip, offset);
rda_gpio_set_irq(chip, offset, trigger);
}
@@ -195,6 +196,16 @@ static void rda_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(ic, desc);
}
+static const struct irq_chip rda_gpio_irq_chip = {
+ .name = "rda-gpio",
+ .irq_ack = rda_gpio_irq_ack,
+ .irq_mask = rda_gpio_irq_mask,
+ .irq_unmask = rda_gpio_irq_unmask,
+ .irq_set_type = rda_gpio_irq_set_type,
+ .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int rda_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -241,15 +252,8 @@ static int rda_gpio_probe(struct platform_device *pdev)
rda_gpio->chip.base = -1;
if (rda_gpio->irq >= 0) {
- rda_gpio->irq_chip.name = "rda-gpio",
- rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack,
- rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask,
- rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask,
- rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type,
- rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE,
-
girq = &rda_gpio->chip.irq;
- girq->chip = &rda_gpio->irq_chip;
+ gpio_irq_chip_set_chip(girq, &rda_gpio_irq_chip);
girq->handler = handle_bad_irq;
girq->default_type = IRQ_TYPE_NONE;
girq->parent_handler = rda_gpio_irq_handler;
@@ -286,4 +290,3 @@ module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe);
MODULE_DESCRIPTION("RDA Micro GPIO driver");
MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-reg.c b/drivers/gpio/gpio-reg.c
index d35169bde25a..73c7260d89c0 100644
--- a/drivers/gpio/gpio-reg.c
+++ b/drivers/gpio/gpio-reg.c
@@ -4,11 +4,19 @@
*
* Copyright (C) 2016 Russell King
*/
-#include <linux/gpio/driver.h>
-#include <linux/gpio/gpio-reg.h>
+#include <linux/bits.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
#include <linux/io.h>
+#include <linux/irqdomain.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <linux/gpio/driver.h>
+#include <linux/gpio/gpio-reg.h>
struct gpio_reg {
struct gpio_chip gc;
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index fca17d478984..c08c8e528867 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -5,11 +5,17 @@
* Copyright 2020 Michael Walle <michael@walle.cc>
*/
-#include <linux/gpio/driver.h>
-#include <linux/gpio/regmap.h>
-#include <linux/kernel.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/gpio/driver.h>
+#include <linux/gpio/regmap.h>
struct gpio_regmap {
struct device *parent;
diff --git a/drivers/gpio/gpio-sama5d2-piobu.c b/drivers/gpio/gpio-sama5d2-piobu.c
index 3e95da717fc9..767c33ae3213 100644
--- a/drivers/gpio/gpio-sama5d2-piobu.c
+++ b/drivers/gpio/gpio-sama5d2-piobu.c
@@ -236,7 +236,7 @@ MODULE_DEVICE_TABLE(of, sama5d2_piobu_ids);
static struct platform_driver sama5d2_piobu_driver = {
.driver = {
.name = "sama5d2-piobu",
- .of_match_table = of_match_ptr(sama5d2_piobu_ids)
+ .of_match_table = sama5d2_piobu_ids,
},
.probe = sama5d2_piobu_probe,
};
diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
index bc5660f61c57..98939cd4a71e 100644
--- a/drivers/gpio/gpio-sifive.c
+++ b/drivers/gpio/gpio-sifive.c
@@ -270,7 +270,7 @@ static struct platform_driver sifive_gpio_driver = {
.probe = sifive_gpio_probe,
.driver = {
.name = "sifive_gpio",
- .of_match_table = of_match_ptr(sifive_gpio_match),
+ .of_match_table = sifive_gpio_match,
},
};
builtin_platform_driver(sifive_gpio_driver)
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index e5dfd636c63c..a1c8702f362c 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -953,9 +953,9 @@ static void gpio_sim_device_deactivate_unlocked(struct gpio_sim_device *dev)
swnode = dev_fwnode(&dev->pdev->dev);
platform_device_unregister(dev->pdev);
+ gpio_sim_remove_hogs(dev);
gpio_sim_remove_swnode_recursive(swnode);
dev->pdev = NULL;
- gpio_sim_remove_hogs(dev);
}
static ssize_t
diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c
index f8c5e9fc4bac..051bc99bdfb2 100644
--- a/drivers/gpio/gpio-siox.c
+++ b/drivers/gpio/gpio-siox.c
@@ -10,7 +10,6 @@
struct gpio_siox_ddata {
struct gpio_chip gchip;
- struct irq_chip ichip;
struct mutex lock;
u8 setdata[1];
u8 getdata[3];
@@ -97,9 +96,8 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
static void gpio_siox_irq_ack(struct irq_data *d)
{
- struct irq_chip *ic = irq_data_get_irq_chip(d);
- struct gpio_siox_ddata *ddata =
- container_of(ic, struct gpio_siox_ddata, ichip);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_siox_ddata *ddata = gpiochip_get_data(gc);
raw_spin_lock(&ddata->irqlock);
ddata->irq_status &= ~(1 << d->hwirq);
@@ -108,21 +106,21 @@ static void gpio_siox_irq_ack(struct irq_data *d)
static void gpio_siox_irq_mask(struct irq_data *d)
{
- struct irq_chip *ic = irq_data_get_irq_chip(d);
- struct gpio_siox_ddata *ddata =
- container_of(ic, struct gpio_siox_ddata, ichip);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_siox_ddata *ddata = gpiochip_get_data(gc);
raw_spin_lock(&ddata->irqlock);
ddata->irq_enable &= ~(1 << d->hwirq);
raw_spin_unlock(&ddata->irqlock);
+ gpiochip_disable_irq(gc, irqd_to_hwirq(d));
}
static void gpio_siox_irq_unmask(struct irq_data *d)
{
- struct irq_chip *ic = irq_data_get_irq_chip(d);
- struct gpio_siox_ddata *ddata =
- container_of(ic, struct gpio_siox_ddata, ichip);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_siox_ddata *ddata = gpiochip_get_data(gc);
+ gpiochip_enable_irq(gc, irqd_to_hwirq(d));
raw_spin_lock(&ddata->irqlock);
ddata->irq_enable |= 1 << d->hwirq;
raw_spin_unlock(&ddata->irqlock);
@@ -130,9 +128,8 @@ static void gpio_siox_irq_unmask(struct irq_data *d)
static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
{
- struct irq_chip *ic = irq_data_get_irq_chip(d);
- struct gpio_siox_ddata *ddata =
- container_of(ic, struct gpio_siox_ddata, ichip);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_siox_ddata *ddata = gpiochip_get_data(gc);
raw_spin_lock(&ddata->irqlock);
ddata->irq_type[d->hwirq] = type;
@@ -143,8 +140,7 @@ static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
{
- struct gpio_siox_ddata *ddata =
- container_of(chip, struct gpio_siox_ddata, gchip);
+ struct gpio_siox_ddata *ddata = gpiochip_get_data(chip);
int ret;
mutex_lock(&ddata->lock);
@@ -167,8 +163,7 @@ static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
static void gpio_siox_set(struct gpio_chip *chip,
unsigned int offset, int value)
{
- struct gpio_siox_ddata *ddata =
- container_of(chip, struct gpio_siox_ddata, gchip);
+ struct gpio_siox_ddata *ddata = gpiochip_get_data(chip);
u8 mask = 1 << (19 - offset);
mutex_lock(&ddata->lock);
@@ -208,11 +203,22 @@ static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
return GPIO_LINE_DIRECTION_OUT;
}
+static const struct irq_chip gpio_siox_irq_chip = {
+ .name = "siox-gpio",
+ .irq_ack = gpio_siox_irq_ack,
+ .irq_mask = gpio_siox_irq_mask,
+ .irq_unmask = gpio_siox_irq_unmask,
+ .irq_set_type = gpio_siox_irq_set_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int gpio_siox_probe(struct siox_device *sdevice)
{
struct gpio_siox_ddata *ddata;
struct gpio_irq_chip *girq;
struct device *dev = &sdevice->dev;
+ struct gpio_chip *gc;
int ret;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
@@ -224,30 +230,25 @@ static int gpio_siox_probe(struct siox_device *sdevice)
mutex_init(&ddata->lock);
raw_spin_lock_init(&ddata->irqlock);
- ddata->gchip.base = -1;
- ddata->gchip.can_sleep = 1;
- ddata->gchip.parent = dev;
- ddata->gchip.owner = THIS_MODULE;
- ddata->gchip.get = gpio_siox_get;
- ddata->gchip.set = gpio_siox_set;
- ddata->gchip.direction_input = gpio_siox_direction_input;
- ddata->gchip.direction_output = gpio_siox_direction_output;
- ddata->gchip.get_direction = gpio_siox_get_direction;
- ddata->gchip.ngpio = 20;
-
- ddata->ichip.name = "siox-gpio";
- ddata->ichip.irq_ack = gpio_siox_irq_ack;
- ddata->ichip.irq_mask = gpio_siox_irq_mask;
- ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
- ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
-
- girq = &ddata->gchip.irq;
- girq->chip = &ddata->ichip;
+ gc = &ddata->gchip;
+ gc->base = -1;
+ gc->can_sleep = 1;
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
+ gc->get = gpio_siox_get;
+ gc->set = gpio_siox_set;
+ gc->direction_input = gpio_siox_direction_input;
+ gc->direction_output = gpio_siox_direction_output;
+ gc->get_direction = gpio_siox_get_direction;
+ gc->ngpio = 20;
+
+ girq = &gc->irq;
+ gpio_irq_chip_set_chip(girq, &gpio_siox_irq_chip);
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
girq->threaded = true;
- ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL);
+ ret = devm_gpiochip_add_data(dev, gc, ddata);
if (ret)
dev_err(dev, "Failed to register gpio chip (%d)\n", ret);
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 0fa4f0a93378..27cc4da53565 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -234,6 +234,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d)
int mask = BIT(offset % 8);
stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
+ gpiochip_disable_irq(gc, offset);
}
static void stmpe_gpio_irq_unmask(struct irq_data *d)
@@ -244,6 +245,7 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d)
int regoffset = offset / 8;
int mask = BIT(offset % 8);
+ gpiochip_enable_irq(gc, offset);
stmpe_gpio->regs[REG_IE][regoffset] |= mask;
}
@@ -357,13 +359,15 @@ static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc)
}
}
-static struct irq_chip stmpe_gpio_irq_chip = {
+static const struct irq_chip stmpe_gpio_irq_chip = {
.name = "stmpe-gpio",
.irq_bus_lock = stmpe_gpio_irq_lock,
.irq_bus_sync_unlock = stmpe_gpio_irq_sync_unlock,
.irq_mask = stmpe_gpio_irq_mask,
.irq_unmask = stmpe_gpio_irq_unmask,
.irq_set_type = stmpe_gpio_irq_set_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
#define MAX_GPIOS 24
@@ -511,7 +515,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
}
girq = &stmpe_gpio->chip.irq;
- girq->chip = &stmpe_gpio_irq_chip;
+ gpio_irq_chip_set_chip(girq, &stmpe_gpio_irq_chip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 0ce1543426a4..4750ea34204c 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -292,7 +292,7 @@ static int xway_stp_probe(struct platform_device *pdev)
}
/* check which edge trigger we should use, default to a falling edge */
- if (!of_find_property(pdev->dev.of_node, "lantiq,rising", NULL))
+ if (!of_property_read_bool(pdev->dev.of_node, "lantiq,rising"))
chip->edge = XWAY_STP_FALLING;
clk = devm_clk_get(&pdev->dev, NULL);
diff --git a/drivers/gpio/gpio-tangier.c b/drivers/gpio/gpio-tangier.c
new file mode 100644
index 000000000000..e990781935ba
--- /dev/null
+++ b/drivers/gpio/gpio-tangier.c
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Tangier GPIO driver
+ *
+ * Copyright (c) 2016, 2021, 2023 Intel Corporation.
+ *
+ * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ * Pandith N <pandith.n@intel.com>
+ * Raag Jadav <raag.jadav@intel.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/spinlock.h>
+#include <linux/string_helpers.h>
+#include <linux/types.h>
+
+#include <linux/gpio/driver.h>
+
+#include "gpio-tangier.h"
+
+#define GCCR 0x000 /* Controller configuration */
+#define GPLR 0x004 /* Pin level r/o */
+#define GPDR 0x01c /* Pin direction */
+#define GPSR 0x034 /* Pin set w/o */
+#define GPCR 0x04c /* Pin clear w/o */
+#define GRER 0x064 /* Rising edge detect */
+#define GFER 0x07c /* Falling edge detect */
+#define GFBR 0x094 /* Glitch filter bypass */
+#define GIMR 0x0ac /* Interrupt mask */
+#define GISR 0x0c4 /* Interrupt source */
+#define GITR 0x300 /* Input type */
+#define GLPR 0x318 /* Level input polarity */
+
+/**
+ * struct tng_gpio_context - Context to be saved during suspend-resume
+ * @level: Pin level
+ * @gpdr: Pin direction
+ * @grer: Rising edge detect enable
+ * @gfer: Falling edge detect enable
+ * @gimr: Interrupt mask
+ * @gwmr: Wake mask
+ */
+struct tng_gpio_context {
+ u32 level;
+ u32 gpdr;
+ u32 grer;
+ u32 gfer;
+ u32 gimr;
+ u32 gwmr;
+};
+
+static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset,
+ unsigned int reg)
+{
+ struct tng_gpio *priv = gpiochip_get_data(chip);
+ u8 reg_offset = offset / 32;
+
+ return priv->reg_base + reg + reg_offset * 4;
+}
+
+static void __iomem *gpio_reg_and_bit(struct gpio_chip *chip, unsigned int offset,
+ unsigned int reg, u8 *bit)
+{
+ struct tng_gpio *priv = gpiochip_get_data(chip);
+ u8 reg_offset = offset / 32;
+ u8 shift = offset % 32;
+
+ *bit = shift;
+ return priv->reg_base + reg + reg_offset * 4;
+}
+
+static int tng_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ void __iomem *gplr;
+ u8 shift;
+
+ gplr = gpio_reg_and_bit(chip, offset, GPLR, &shift);
+
+ return !!(readl(gplr) & BIT(shift));
+}
+
+static void tng_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct tng_gpio *priv = gpiochip_get_data(chip);
+ unsigned long flags;
+ void __iomem *reg;
+ u8 shift;
+
+ reg = gpio_reg_and_bit(chip, offset, value ? GPSR : GPCR, &shift);
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ writel(BIT(shift), reg);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int tng_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ struct tng_gpio *priv = gpiochip_get_data(chip);
+ unsigned long flags;
+ void __iomem *gpdr;
+ u32 value;
+ u8 shift;
+
+ gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ value = readl(gpdr);
+ value &= ~BIT(shift);
+ writel(value, gpdr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int tng_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct tng_gpio *priv = gpiochip_get_data(chip);
+ unsigned long flags;
+ void __iomem *gpdr;
+ u8 shift;
+
+ gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);
+ tng_gpio_set(chip, offset, value);
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ value = readl(gpdr);
+ value |= BIT(shift);
+ writel(value, gpdr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int tng_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ void __iomem *gpdr;
+ u8 shift;
+
+ gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);
+
+ if (readl(gpdr) & BIT(shift))
+ return GPIO_LINE_DIRECTION_OUT;
+
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int tng_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
+ unsigned int debounce)
+{
+ struct tng_gpio *priv = gpiochip_get_data(chip);
+ unsigned long flags;
+ void __iomem *gfbr;
+ u32 value;
+ u8 shift;
+
+ gfbr = gpio_reg_and_bit(chip, offset, GFBR, &shift);
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ value = readl(gfbr);
+ if (debounce)
+ value &= ~BIT(shift);
+ else
+ value |= BIT(shift);
+ writel(value, gfbr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int tng_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ u32 debounce;
+
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ return gpiochip_generic_config(chip, offset, config);
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ debounce = pinconf_to_config_argument(config);
+ return tng_gpio_set_debounce(chip, offset, debounce);
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static void tng_irq_ack(struct irq_data *d)
+{
+ struct tng_gpio *priv = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ unsigned long flags;
+ void __iomem *gisr;
+ u8 shift;
+
+ gisr = gpio_reg_and_bit(&priv->chip, gpio, GISR, &shift);
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+ writel(BIT(shift), gisr);
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask)
+{
+ unsigned long flags;
+ void __iomem *gimr;
+ u32 value;
+ u8 shift;
+
+ gimr = gpio_reg_and_bit(&priv->chip, gpio, GIMR, &shift);
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ value = readl(gimr);
+ if (unmask)
+ value |= BIT(shift);
+ else
+ value &= ~BIT(shift);
+ writel(value, gimr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void tng_irq_mask(struct irq_data *d)
+{
+ struct tng_gpio *priv = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+
+ tng_irq_unmask_mask(priv, gpio, false);
+ gpiochip_disable_irq(&priv->chip, gpio);
+}
+
+static void tng_irq_unmask(struct irq_data *d)
+{
+ struct tng_gpio *priv = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+
+ gpiochip_enable_irq(&priv->chip, gpio);
+ tng_irq_unmask_mask(priv, gpio, true);
+}
+
+static int tng_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tng_gpio *priv = gpiochip_get_data(gc);
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER);
+ void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER);
+ void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR);
+ void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR);
+ u8 shift = gpio % 32;
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ value = readl(grer);
+ if (type & IRQ_TYPE_EDGE_RISING)
+ value |= BIT(shift);
+ else
+ value &= ~BIT(shift);
+ writel(value, grer);
+
+ value = readl(gfer);
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ value |= BIT(shift);
+ else
+ value &= ~BIT(shift);
+ writel(value, gfer);
+
+ /*
+ * To prevent glitches from triggering an unintended level interrupt,
+ * configure GLPR register first and then configure GITR.
+ */
+ value = readl(glpr);
+ if (type & IRQ_TYPE_LEVEL_LOW)
+ value |= BIT(shift);
+ else
+ value &= ~BIT(shift);
+ writel(value, glpr);
+
+ if (type & IRQ_TYPE_LEVEL_MASK) {
+ value = readl(gitr);
+ value |= BIT(shift);
+ writel(value, gitr);
+
+ irq_set_handler_locked(d, handle_level_irq);
+ } else if (type & IRQ_TYPE_EDGE_BOTH) {
+ value = readl(gitr);
+ value &= ~BIT(shift);
+ writel(value, gitr);
+
+ irq_set_handler_locked(d, handle_edge_irq);
+ }
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int tng_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tng_gpio *priv = gpiochip_get_data(gc);
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *gwmr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwmr);
+ void __iomem *gwsr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwsr);
+ u8 shift = gpio % 32;
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ /* Clear the existing wake status */
+ writel(BIT(shift), gwsr);
+
+ value = readl(gwmr);
+ if (on)
+ value |= BIT(shift);
+ else
+ value &= ~BIT(shift);
+ writel(value, gwmr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ dev_dbg(priv->dev, "%s wake for gpio %lu\n", str_enable_disable(on), gpio);
+ return 0;
+}
+
+static const struct irq_chip tng_irqchip = {
+ .name = "gpio-tangier",
+ .irq_ack = tng_irq_ack,
+ .irq_mask = tng_irq_mask,
+ .irq_unmask = tng_irq_unmask,
+ .irq_set_type = tng_irq_set_type,
+ .irq_set_wake = tng_irq_set_wake,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static void tng_irq_handler(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct tng_gpio *priv = gpiochip_get_data(gc);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ unsigned long base, gpio;
+
+ chained_irq_enter(irqchip, desc);
+
+ /* Check GPIO controller to check which pin triggered the interrupt */
+ for (base = 0; base < priv->chip.ngpio; base += 32) {
+ void __iomem *gisr = gpio_reg(&priv->chip, base, GISR);
+ void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR);
+ unsigned long pending, enabled;
+
+ pending = readl(gisr);
+ enabled = readl(gimr);
+
+ /* Only interrupts that are enabled */
+ pending &= enabled;
+
+ for_each_set_bit(gpio, &pending, 32)
+ generic_handle_domain_irq(gc->irq.domain, base + gpio);
+ }
+
+ chained_irq_exit(irqchip, desc);
+}
+
+static int tng_irq_init_hw(struct gpio_chip *chip)
+{
+ struct tng_gpio *priv = gpiochip_get_data(chip);
+ void __iomem *reg;
+ unsigned int base;
+
+ for (base = 0; base < priv->chip.ngpio; base += 32) {
+ /* Clear the rising-edge detect register */
+ reg = gpio_reg(&priv->chip, base, GRER);
+ writel(0, reg);
+
+ /* Clear the falling-edge detect register */
+ reg = gpio_reg(&priv->chip, base, GFER);
+ writel(0, reg);
+ }
+
+ return 0;
+}
+
+static int tng_gpio_add_pin_ranges(struct gpio_chip *chip)
+{
+ struct tng_gpio *priv = gpiochip_get_data(chip);
+ const struct tng_gpio_pinrange *range;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < priv->pin_info.nranges; i++) {
+ range = &priv->pin_info.pin_ranges[i];
+ ret = gpiochip_add_pin_range(&priv->chip,
+ priv->pin_info.name,
+ range->gpio_base,
+ range->pin_base,
+ range->npins);
+ if (ret) {
+ dev_err(priv->dev, "failed to add GPIO pin range\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio)
+{
+ const struct tng_gpio_info *info = &gpio->info;
+ struct gpio_irq_chip *girq;
+ int ret;
+
+ gpio->ctx = devm_kcalloc(dev, DIV_ROUND_UP(info->ngpio, 32), sizeof(*gpio->ctx), GFP_KERNEL);
+ if (!gpio->ctx)
+ return -ENOMEM;
+
+ gpio->chip.label = dev_name(dev);
+ gpio->chip.parent = dev;
+ gpio->chip.request = gpiochip_generic_request;
+ gpio->chip.free = gpiochip_generic_free;
+ gpio->chip.direction_input = tng_gpio_direction_input;
+ gpio->chip.direction_output = tng_gpio_direction_output;
+ gpio->chip.get = tng_gpio_get;
+ gpio->chip.set = tng_gpio_set;
+ gpio->chip.get_direction = tng_gpio_get_direction;
+ gpio->chip.set_config = tng_gpio_set_config;
+ gpio->chip.base = info->base;
+ gpio->chip.ngpio = info->ngpio;
+ gpio->chip.can_sleep = false;
+ gpio->chip.add_pin_ranges = tng_gpio_add_pin_ranges;
+
+ raw_spin_lock_init(&gpio->lock);
+
+ girq = &gpio->chip.irq;
+ gpio_irq_chip_set_chip(girq, &tng_irqchip);
+ girq->init_hw = tng_irq_init_hw;
+ girq->parent_handler = tng_irq_handler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(dev, girq->num_parents,
+ sizeof(*girq->parents), GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+
+ girq->parents[0] = gpio->irq;
+ girq->first = info->first;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+
+ ret = devm_gpiochip_add_data(dev, &gpio->chip, gpio);
+ if (ret)
+ return dev_err_probe(dev, ret, "gpiochip_add error\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(devm_tng_gpio_probe, GPIO_TANGIER);
+
+int tng_gpio_suspend(struct device *dev)
+{
+ struct tng_gpio *priv = dev_get_drvdata(dev);
+ struct tng_gpio_context *ctx = priv->ctx;
+ unsigned long flags;
+ unsigned int base;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) {
+ /* GPLR is RO, values read will be restored using GPSR */
+ ctx->level = readl(gpio_reg(&priv->chip, base, GPLR));
+
+ ctx->gpdr = readl(gpio_reg(&priv->chip, base, GPDR));
+ ctx->grer = readl(gpio_reg(&priv->chip, base, GRER));
+ ctx->gfer = readl(gpio_reg(&priv->chip, base, GFER));
+ ctx->gimr = readl(gpio_reg(&priv->chip, base, GIMR));
+
+ ctx->gwmr = readl(gpio_reg(&priv->chip, base, priv->wake_regs.gwmr));
+ }
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tng_gpio_suspend, GPIO_TANGIER);
+
+int tng_gpio_resume(struct device *dev)
+{
+ struct tng_gpio *priv = dev_get_drvdata(dev);
+ struct tng_gpio_context *ctx = priv->ctx;
+ unsigned long flags;
+ unsigned int base;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) {
+ /* GPLR is RO, values read will be restored using GPSR */
+ writel(ctx->level, gpio_reg(&priv->chip, base, GPSR));
+
+ writel(ctx->gpdr, gpio_reg(&priv->chip, base, GPDR));
+ writel(ctx->grer, gpio_reg(&priv->chip, base, GRER));
+ writel(ctx->gfer, gpio_reg(&priv->chip, base, GFER));
+ writel(ctx->gimr, gpio_reg(&priv->chip, base, GIMR));
+
+ writel(ctx->gwmr, gpio_reg(&priv->chip, base, priv->wake_regs.gwmr));
+ }
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tng_gpio_resume, GPIO_TANGIER);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_AUTHOR("Pandith N <pandith.n@intel.com>");
+MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>");
+MODULE_DESCRIPTION("Intel Tangier GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-tangier.h b/drivers/gpio/gpio-tangier.h
new file mode 100644
index 000000000000..16c4f22908fb
--- /dev/null
+++ b/drivers/gpio/gpio-tangier.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Intel Tangier GPIO functions
+ *
+ * Copyright (c) 2016, 2021, 2023 Intel Corporation.
+ *
+ * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ * Pandith N <pandith.n@intel.com>
+ * Raag Jadav <raag.jadav@intel.com>
+ */
+
+#ifndef _GPIO_TANGIER_H_
+#define _GPIO_TANGIER_H_
+
+#include <linux/gpio/driver.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+
+struct device;
+
+struct tng_gpio_context;
+
+/* Elkhart Lake specific wake registers */
+#define GWMR_EHL 0x100 /* Wake mask */
+#define GWSR_EHL 0x118 /* Wake source */
+#define GSIR_EHL 0x130 /* Secure input */
+
+/* Merrifield specific wake registers */
+#define GWMR_MRFLD 0x400 /* Wake mask */
+#define GWSR_MRFLD 0x418 /* Wake source */
+#define GSIR_MRFLD 0xc00 /* Secure input */
+
+/**
+ * struct tng_wake_regs - Platform specific wake registers
+ * @gwmr: Wake mask
+ * @gwsr: Wake source
+ * @gsir: Secure input
+ */
+struct tng_wake_regs {
+ u32 gwmr;
+ u32 gwsr;
+ u32 gsir;
+};
+
+/**
+ * struct tng_gpio_pinrange - Map pin numbers to gpio numbers
+ * @gpio_base: Starting GPIO number of this range
+ * @pin_base: Starting pin number of this range
+ * @npins: Number of pins in this range
+ */
+struct tng_gpio_pinrange {
+ unsigned int gpio_base;
+ unsigned int pin_base;
+ unsigned int npins;
+};
+
+#define GPIO_PINRANGE(gstart, gend, pstart) \
+(struct tng_gpio_pinrange) { \
+ .gpio_base = (gstart), \
+ .pin_base = (pstart), \
+ .npins = (gend) - (gstart) + 1, \
+ }
+
+/**
+ * struct tng_gpio_pin_info - Platform specific pinout information
+ * @pin_ranges: Pin to GPIO mapping
+ * @nranges: Number of pin ranges
+ * @name: Respective pinctrl device name
+ */
+struct tng_gpio_pin_info {
+ const struct tng_gpio_pinrange *pin_ranges;
+ unsigned int nranges;
+ const char *name;
+};
+
+/**
+ * struct tng_gpio_info - Platform specific GPIO and IRQ information
+ * @base: GPIO base to start numbering with
+ * @ngpio: Amount of GPIOs supported by the controller
+ * @first: First IRQ to start numbering with
+ */
+struct tng_gpio_info {
+ int base;
+ u16 ngpio;
+ unsigned int first;
+};
+
+/**
+ * struct tng_gpio - Platform specific private data
+ * @chip: Instance of the struct gpio_chip
+ * @reg_base: Base address of MMIO registers
+ * @irq: Interrupt for the GPIO device
+ * @lock: Synchronization lock to prevent I/O race conditions
+ * @dev: The GPIO device
+ * @ctx: Context to be saved during suspend-resume
+ * @wake_regs: Platform specific wake registers
+ * @pin_info: Platform specific pinout information
+ * @info: Platform specific GPIO and IRQ information
+ */
+struct tng_gpio {
+ struct gpio_chip chip;
+ void __iomem *reg_base;
+ int irq;
+ raw_spinlock_t lock;
+ struct device *dev;
+ struct tng_gpio_context *ctx;
+ struct tng_wake_regs wake_regs;
+ struct tng_gpio_pin_info pin_info;
+ struct tng_gpio_info info;
+};
+
+int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio);
+
+int tng_gpio_suspend(struct device *dev);
+int tng_gpio_resume(struct device *dev);
+
+#endif /* _GPIO_TANGIER_H_ */
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index de6afa3f9716..78f8790168ae 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -167,7 +167,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tb10x_gpio);
- if (of_find_property(np, "interrupt-controller", NULL)) {
+ if (of_property_read_bool(np, "interrupt-controller")) {
struct irq_chip_generic *gc;
ret = platform_get_irq(pdev, 0);
diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c
index cc62c6e64103..8521c6aacace 100644
--- a/drivers/gpio/gpio-thunderx.c
+++ b/drivers/gpio/gpio-thunderx.c
@@ -354,16 +354,22 @@ static int thunderx_gpio_irq_set_type(struct irq_data *d,
return IRQ_SET_MASK_OK;
}
-static void thunderx_gpio_irq_enable(struct irq_data *data)
+static void thunderx_gpio_irq_enable(struct irq_data *d)
{
- irq_chip_enable_parent(data);
- thunderx_gpio_irq_unmask(data);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ gpiochip_enable_irq(gc, irqd_to_hwirq(d));
+ irq_chip_enable_parent(d);
+ thunderx_gpio_irq_unmask(d);
}
-static void thunderx_gpio_irq_disable(struct irq_data *data)
+static void thunderx_gpio_irq_disable(struct irq_data *d)
{
- thunderx_gpio_irq_mask(data);
- irq_chip_disable_parent(data);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ thunderx_gpio_irq_mask(d);
+ irq_chip_disable_parent(d);
+ gpiochip_disable_irq(gc, irqd_to_hwirq(d));
}
/*
@@ -372,7 +378,7 @@ static void thunderx_gpio_irq_disable(struct irq_data *data)
* semantics and other acknowledgment tasks associated with the GPIO
* mechanism.
*/
-static struct irq_chip thunderx_gpio_irq_chip = {
+static const struct irq_chip thunderx_gpio_irq_chip = {
.name = "GPIO",
.irq_enable = thunderx_gpio_irq_enable,
.irq_disable = thunderx_gpio_irq_disable,
@@ -383,8 +389,8 @@ static struct irq_chip thunderx_gpio_irq_chip = {
.irq_eoi = irq_chip_eoi_parent,
.irq_set_affinity = irq_chip_set_affinity_parent,
.irq_set_type = thunderx_gpio_irq_set_type,
-
- .flags = IRQCHIP_SET_TYPE_MASKED
+ .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
@@ -526,7 +532,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
chip->set_multiple = thunderx_gpio_set_multiple;
chip->set_config = thunderx_gpio_set_config;
girq = &chip->irq;
- girq->chip = &thunderx_gpio_irq_chip;
+ gpio_irq_chip_set_chip(girq, &thunderx_gpio_irq_chip);
girq->fwnode = of_node_to_fwnode(dev->of_node);
girq->parent_domain =
irq_get_irq_data(txgpio->msix_entries[0].vector)->domain;
diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c
index e739dcea61b2..6f8bd1155db7 100644
--- a/drivers/gpio/gpio-tqmx86.c
+++ b/drivers/gpio/gpio-tqmx86.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
#define TQMX86_NGPIO 8
@@ -34,7 +35,6 @@
struct tqmx86_gpio_data {
struct gpio_chip chip;
- struct irq_chip irq_chip;
void __iomem *io_base;
int irq;
raw_spinlock_t spinlock;
@@ -122,6 +122,7 @@ static void tqmx86_gpio_irq_mask(struct irq_data *data)
gpiic &= ~mask;
tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);
raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
+ gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(data));
}
static void tqmx86_gpio_irq_unmask(struct irq_data *data)
@@ -134,6 +135,7 @@ static void tqmx86_gpio_irq_unmask(struct irq_data *data)
mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS);
+ gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(data));
raw_spin_lock_irqsave(&gpio->spinlock, flags);
gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
gpiic &= ~mask;
@@ -226,6 +228,22 @@ static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip,
clear_bit(3, valid_mask);
}
+static void tqmx86_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ seq_printf(p, gc->label);
+}
+
+static const struct irq_chip tqmx86_gpio_irq_chip = {
+ .irq_mask = tqmx86_gpio_irq_mask,
+ .irq_unmask = tqmx86_gpio_irq_unmask,
+ .irq_set_type = tqmx86_gpio_irq_set_type,
+ .irq_print_chip = tqmx86_gpio_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int tqmx86_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -277,14 +295,8 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
if (irq > 0) {
- struct irq_chip *irq_chip = &gpio->irq_chip;
u8 irq_status;
- irq_chip->name = chip->label;
- irq_chip->irq_mask = tqmx86_gpio_irq_mask;
- irq_chip->irq_unmask = tqmx86_gpio_irq_unmask;
- irq_chip->irq_set_type = tqmx86_gpio_irq_set_type;
-
/* Mask all interrupts */
tqmx86_gpio_write(gpio, 0, TQMX86_GPIIC);
@@ -293,7 +305,7 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);
girq = &chip->irq;
- girq->chip = irq_chip;
+ gpio_irq_chip_set_chip(girq, &tqmx86_gpio_irq_chip);
girq->parent_handler = tqmx86_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1,
diff --git a/drivers/gpio/gpio-visconti.c b/drivers/gpio/gpio-visconti.c
index 5e108ba9956a..6734e7e1e2a4 100644
--- a/drivers/gpio/gpio-visconti.c
+++ b/drivers/gpio/gpio-visconti.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
+#include <linux/seq_file.h>
#include <linux/bitops.h>
/* register offset */
@@ -31,7 +32,7 @@ struct visconti_gpio {
void __iomem *base;
spinlock_t lock; /* protect gpio register */
struct gpio_chip gpio_chip;
- struct irq_chip irq_chip;
+ struct device *dev;
};
static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type)
@@ -119,11 +120,45 @@ static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
return 0;
}
+static void visconti_gpio_mask_irq(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ irq_chip_mask_parent(d);
+ gpiochip_disable_irq(gc, irqd_to_hwirq(d));
+}
+
+static void visconti_gpio_unmask_irq(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ gpiochip_enable_irq(gc, irqd_to_hwirq(d));
+ irq_chip_unmask_parent(d);
+}
+
+static void visconti_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct visconti_gpio *priv = gpiochip_get_data(gc);
+
+ seq_printf(p, dev_name(priv->dev));
+}
+
+static const struct irq_chip visconti_gpio_irq_chip = {
+ .irq_mask = visconti_gpio_mask_irq,
+ .irq_unmask = visconti_gpio_unmask_irq,
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_set_type = visconti_gpio_irq_set_type,
+ .irq_print_chip = visconti_gpio_irq_print_chip,
+ .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND |
+ IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int visconti_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct visconti_gpio *priv;
- struct irq_chip *irq_chip;
struct gpio_irq_chip *girq;
struct irq_domain *parent;
struct device_node *irq_parent;
@@ -134,6 +169,7 @@ static int visconti_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
spin_lock_init(&priv->lock);
+ priv->dev = dev;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
@@ -164,16 +200,8 @@ static int visconti_gpio_probe(struct platform_device *pdev)
return ret;
}
- irq_chip = &priv->irq_chip;
- irq_chip->name = dev_name(dev);
- irq_chip->irq_mask = irq_chip_mask_parent;
- irq_chip->irq_unmask = irq_chip_unmask_parent;
- irq_chip->irq_eoi = irq_chip_eoi_parent;
- irq_chip->irq_set_type = visconti_gpio_irq_set_type;
- irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
-
girq = &priv->gpio_chip.irq;
- girq->chip = irq_chip;
+ gpio_irq_chip_set_chip(girq, &visconti_gpio_irq_chip);
girq->fwnode = of_node_to_fwnode(dev->of_node);
girq->parent_domain = parent;
girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq;
@@ -194,7 +222,7 @@ static struct platform_driver visconti_gpio_driver = {
.probe = visconti_gpio_probe,
.driver = {
.name = "visconti_gpio",
- .of_match_table = of_match_ptr(visconti_gpio_of_match),
+ .of_match_table = visconti_gpio_of_match,
}
};
module_platform_driver(visconti_gpio_driver);
diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c
index fd88500399c6..2d23b27d55af 100644
--- a/drivers/gpio/gpio-xgs-iproc.c
+++ b/drivers/gpio/gpio-xgs-iproc.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/seq_file.h>
#include <linux/spinlock.h>
#define IPROC_CCA_INT_F_GPIOINT BIT(0)
@@ -27,7 +28,6 @@
#define IPROC_GPIO_CCA_INT_EDGE 0x24
struct iproc_gpio_chip {
- struct irq_chip irqchip;
struct gpio_chip gc;
spinlock_t lock;
struct device *dev;
@@ -69,6 +69,7 @@ static void iproc_gpio_irq_unmask(struct irq_data *d)
u32 irq = d->irq;
u32 int_mask, irq_type, event_mask;
+ gpiochip_enable_irq(gc, pin);
spin_lock_irqsave(&chip->lock, flags);
irq_type = irq_get_trigger_type(irq);
event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
@@ -110,6 +111,7 @@ static void iproc_gpio_irq_mask(struct irq_data *d)
chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
}
spin_unlock_irqrestore(&chip->lock, flags);
+ gpiochip_disable_irq(gc, pin);
}
static int iproc_gpio_irq_set_type(struct irq_data *d, u32 type)
@@ -191,6 +193,24 @@ static irqreturn_t iproc_gpio_irq_handler(int irq, void *data)
return int_bits ? IRQ_HANDLED : IRQ_NONE;
}
+static void iproc_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
+
+ seq_printf(p, dev_name(chip->dev));
+}
+
+static const struct irq_chip iproc_gpio_irq_chip = {
+ .irq_ack = iproc_gpio_irq_ack,
+ .irq_mask = iproc_gpio_irq_mask,
+ .irq_unmask = iproc_gpio_irq_unmask,
+ .irq_set_type = iproc_gpio_irq_set_type,
+ .irq_print_chip = iproc_gpio_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int iproc_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -230,16 +250,8 @@ static int iproc_gpio_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
struct gpio_irq_chip *girq;
- struct irq_chip *irqc;
u32 val;
- irqc = &chip->irqchip;
- irqc->name = dev_name(dev);
- irqc->irq_ack = iproc_gpio_irq_ack;
- irqc->irq_mask = iproc_gpio_irq_mask;
- irqc->irq_unmask = iproc_gpio_irq_unmask;
- irqc->irq_set_type = iproc_gpio_irq_set_type;
-
chip->intr = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(chip->intr))
return PTR_ERR(chip->intr);
@@ -261,7 +273,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
}
girq = &chip->gc.irq;
- girq->chip = irqc;
+ gpio_irq_chip_set_chip(girq, &iproc_gpio_irq_chip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index e248809965ca..1fa66f2a667f 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -68,7 +68,6 @@ struct xgpio_instance {
DECLARE_BITMAP(dir, 64);
spinlock_t gpio_lock; /* For serializing operations */
int irq;
- struct irq_chip irqchip;
DECLARE_BITMAP(enable, 64);
DECLARE_BITMAP(rising_edge, 64);
DECLARE_BITMAP(falling_edge, 64);
@@ -416,6 +415,8 @@ static void xgpio_irq_mask(struct irq_data *irq_data)
xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp);
}
spin_unlock_irqrestore(&chip->gpio_lock, flags);
+
+ gpiochip_disable_irq(&chip->gc, irq_offset);
}
/**
@@ -431,6 +432,8 @@ static void xgpio_irq_unmask(struct irq_data *irq_data)
u32 old_enable = xgpio_get_value32(chip->enable, bit);
u32 mask = BIT(bit / 32), val;
+ gpiochip_enable_irq(&chip->gc, irq_offset);
+
spin_lock_irqsave(&chip->gpio_lock, flags);
__set_bit(bit, chip->enable);
@@ -544,6 +547,16 @@ static void xgpio_irqhandler(struct irq_desc *desc)
chained_irq_exit(irqchip, desc);
}
+static const struct irq_chip xgpio_irq_chip = {
+ .name = "gpio-xilinx",
+ .irq_ack = xgpio_irq_ack,
+ .irq_mask = xgpio_irq_mask,
+ .irq_unmask = xgpio_irq_unmask,
+ .irq_set_type = xgpio_set_irq_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
/**
* xgpio_probe - Probe method for the GPIO device.
* @pdev: pointer to the platform device
@@ -653,12 +666,6 @@ static int xgpio_probe(struct platform_device *pdev)
if (chip->irq <= 0)
goto skip_irq;
- chip->irqchip.name = "gpio-xilinx";
- chip->irqchip.irq_ack = xgpio_irq_ack;
- chip->irqchip.irq_mask = xgpio_irq_mask;
- chip->irqchip.irq_unmask = xgpio_irq_unmask;
- chip->irqchip.irq_set_type = xgpio_set_irq_type;
-
/* Disable per-channel interrupts */
xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, 0);
/* Clear any existing per-channel interrupts */
@@ -668,7 +675,7 @@ static int xgpio_probe(struct platform_device *pdev)
xgpio_writereg(chip->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE);
girq = &chip->gc.irq;
- girq->chip = &chip->irqchip;
+ gpio_irq_chip_set_chip(girq, &xgpio_irq_chip);
girq->parent_handler = xgpio_irqhandler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1,
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index 0199f545335f..b4b52213bcd9 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -90,6 +90,13 @@ static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state)
writel(value, addr + regset);
}
+static void xlp_gpio_irq_enable(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ gpiochip_enable_irq(gc, irqd_to_hwirq(d));
+}
+
static void xlp_gpio_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
@@ -100,6 +107,7 @@ static void xlp_gpio_irq_disable(struct irq_data *d)
xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
__clear_bit(d->hwirq, priv->gpio_enabled_mask);
spin_unlock_irqrestore(&priv->lock, flags);
+ gpiochip_disable_irq(gc, irqd_to_hwirq(d));
}
static void xlp_gpio_irq_mask_ack(struct irq_data *d)
@@ -163,10 +171,12 @@ static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type)
static struct irq_chip xlp_gpio_irq_chip = {
.name = "XLP-GPIO",
.irq_mask_ack = xlp_gpio_irq_mask_ack,
+ .irq_enable = xlp_gpio_irq_enable,
.irq_disable = xlp_gpio_irq_disable,
.irq_set_type = xlp_gpio_set_irq_type,
.irq_unmask = xlp_gpio_irq_unmask,
- .flags = IRQCHIP_ONESHOT_SAFE,
+ .flags = IRQCHIP_ONESHOT_SAFE | IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static void xlp_gpio_generic_handler(struct irq_desc *desc)
@@ -272,7 +282,7 @@ static int xlp_gpio_probe(struct platform_device *pdev)
spin_lock_init(&priv->lock);
girq = &gc->irq;
- girq->chip = &xlp_gpio_irq_chip;
+ gpio_irq_chip_set_chip(girq, &xlp_gpio_irq_chip);
girq->parent_handler = xlp_gpio_generic_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1,
diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c
index 49c878cfd5c6..51d6119e1bb4 100644
--- a/drivers/gpio/gpio-xra1403.c
+++ b/drivers/gpio/gpio-xra1403.c
@@ -195,7 +195,7 @@ static const struct spi_device_id xra1403_ids[] = {
};
MODULE_DEVICE_TABLE(spi, xra1403_ids);
-static const struct of_device_id xra1403_spi_of_match[] = {
+static const struct of_device_id xra1403_spi_of_match[] __maybe_unused = {
{ .compatible = "exar,xra1403" },
{},
};
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 31ae0adbb295..97496c0f9133 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -7,17 +7,19 @@
* Mika Westerberg <mika.westerberg@linux.intel.com>
*/
+#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/errno.h>
-#include <linux/gpio/consumer.h>
-#include <linux/gpio/driver.h>
-#include <linux/gpio/machine.h>
#include <linux/export.h>
-#include <linux/acpi.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/mutex.h>
#include <linux/pinctrl/pinctrl.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+
#include "gpiolib.h"
#include "gpiolib-acpi.h"
@@ -126,7 +128,7 @@ static bool acpi_gpio_deferred_req_irqs_done;
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{
- return gc->parent && device_match_acpi_handle(gc->parent, data);
+ return ACPI_HANDLE_FWNODE(gc->fwnode) == data;
}
/**
@@ -646,7 +648,7 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
{
const struct acpi_gpio_mapping *gm;
- if (!adev->driver_gpios)
+ if (!adev || !adev->driver_gpios)
return false;
for (gm = adev->driver_gpios; gm->name; gm++)
@@ -840,13 +842,10 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
ret = __acpi_node_get_property_reference(fwnode, propname, index, 3,
&args);
if (ret) {
- struct acpi_device *adev = to_acpi_device_node(fwnode);
+ struct acpi_device *adev;
- if (!adev)
- return ret;
-
- if (!acpi_get_driver_gpio_data(adev, propname, index, &args,
- &quirks))
+ adev = to_acpi_device_node(fwnode);
+ if (!acpi_get_driver_gpio_data(adev, propname, index, &args, &quirks))
return ret;
}
/*
@@ -1624,6 +1623,19 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
* https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
*/
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
+ },
+ .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+ .ignore_wake = "ELAN0415:00@9",
+ },
+ },
+ {
+ /*
+ * Spurious wakeups from TP_ATTN# pin
+ * Found in BIOS 1.7.8
+ * https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
+ */
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
},
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
index 90fd6b04f24d..0fcd7e14d7f9 100644
--- a/drivers/gpio/gpiolib-acpi.h
+++ b/drivers/gpio/gpiolib-acpi.h
@@ -9,7 +9,6 @@
#define GPIOLIB_ACPI_H
#include <linux/err.h>
-#include <linux/errno.h>
#include <linux/types.h>
#include <linux/gpio/consumer.h>
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 266352b1a966..1436cdb5fa26 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -10,14 +10,16 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/module.h>
#include <linux/io.h>
-#include <linux/gpio/consumer.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include "gpiolib.h"
@@ -892,6 +894,8 @@ static int of_gpio_simple_xlate(struct gpio_chip *gc,
return gpiospec->args[0];
}
+#if IS_ENABLED(CONFIG_OF_GPIO_MM_GPIOCHIP)
+#include <linux/gpio/legacy-of-mm-gpiochip.h>
/**
* of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
* @np: device node of the GPIO chip
@@ -964,6 +968,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
kfree(gc->label);
}
EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
+#endif
#ifdef CONFIG_PINCTRL
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h
index e5bb065d82ef..6b3a5347c5d9 100644
--- a/drivers/gpio/gpiolib-of.h
+++ b/drivers/gpio/gpiolib-of.h
@@ -4,7 +4,6 @@
#define GPIOLIB_OF_H
#include <linux/err.h>
-#include <linux/errno.h>
#include <linux/types.h>
#include <linux/notifier.h>
diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c
index dd9ccac214d1..b5a6eaf3729b 100644
--- a/drivers/gpio/gpiolib-swnode.c
+++ b/drivers/gpio/gpiolib-swnode.c
@@ -6,13 +6,14 @@
*/
#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/gpio/consumer.h>
-#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/property.h>
#include <linux/string.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+
#include "gpiolib.h"
#include "gpiolib-swnode.h"
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index cd27bf173dec..530dfd19d7b5 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -1,18 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bitops.h>
+#include <linux/device.h>
#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/kstrtox.h>
+#include <linux/list.h>
#include <linux/mutex.h>
-#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
#include <linux/sysfs.h>
+#include <linux/types.h>
+
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
-#include <linux/interrupt.h>
-#include <linux/kdev_t.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
#include "gpiolib.h"
#include "gpiolib-sysfs.h"
+struct kernfs_node;
+
#define GPIO_IRQF_TRIGGER_NONE 0
#define GPIO_IRQF_TRIGGER_FALLING BIT(0)
#define GPIO_IRQF_TRIGGER_RISING BIT(1)
@@ -426,8 +437,8 @@ ATTRIBUTE_GROUPS(gpiochip);
* /sys/class/gpio/unexport ... write-only
* integer N ... number of GPIO to unexport
*/
-static ssize_t export_store(struct class *class,
- struct class_attribute *attr,
+static ssize_t export_store(const struct class *class,
+ const struct class_attribute *attr,
const char *buf, size_t len)
{
long gpio;
@@ -478,8 +489,8 @@ done:
}
static CLASS_ATTR_WO(export);
-static ssize_t unexport_store(struct class *class,
- struct class_attribute *attr,
+static ssize_t unexport_store(const struct class *class,
+ const struct class_attribute *attr,
const char *buf, size_t len)
{
long gpio;
@@ -491,7 +502,7 @@ static ssize_t unexport_store(struct class *class,
goto done;
desc = gpio_to_desc(gpio);
- /* reject bogus commands (gpio_unexport ignores them) */
+ /* reject bogus commands (gpiod_unexport() ignores them) */
if (!desc) {
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
return -EINVAL;
@@ -523,8 +534,6 @@ ATTRIBUTE_GROUPS(gpio_class);
static struct class gpio_class = {
.name = "gpio",
- .owner = THIS_MODULE,
-
.class_groups = gpio_class_groups,
};
@@ -556,7 +565,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
int offset;
/* can't export until sysfs is available ... */
- if (!gpio_class.p) {
+ if (!class_is_registered(&gpio_class)) {
pr_debug("%s: called too early!\n", __func__);
return -ENOENT;
}
@@ -730,7 +739,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
* register later, in gpiolib_sysfs_init() ... here we just
* verify that _some_ field of gpio_class got initialized.
*/
- if (!gpio_class.p)
+ if (!class_is_registered(&gpio_class))
return 0;
/*
@@ -790,7 +799,7 @@ static int __init gpiolib_sysfs_init(void)
* early (e.g. before the class_register above was called).
*
* We run before arch_initcall() so chip->dev nodes can have
- * registered, and so arch_initcall() can always gpio_export().
+ * registered, and so arch_initcall() can always gpiod_export().
*/
spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(gdev, &gpio_devices, list) {
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 19bd23044b01..04fb05df805b 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -6,22 +6,25 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/errno.h>
#include <linux/file.h>
#include <linux/fs.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/gpio/machine.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+
#include <uapi/linux/gpio.h>
#include "gpiolib-acpi.h"
@@ -58,7 +61,20 @@
static DEFINE_IDA(gpio_ida);
static dev_t gpio_devt;
#define GPIO_DEV_MAX 256 /* 256 GPIO chip devices supported */
-static int gpio_bus_match(struct device *dev, struct device_driver *drv);
+
+static int gpio_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+
+ /*
+ * Only match if the fwnode doesn't already have a proper struct device
+ * created for it.
+ */
+ if (fwnode && fwnode->dev != dev)
+ return 0;
+ return 1;
+}
+
static struct bus_type gpio_bus_type = {
.name = "gpio",
.match = gpio_bus_match,
@@ -357,7 +373,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
}
/*
- * devprop_gpiochip_set_names - Set GPIO line names using device properties
+ * gpiochip_set_names - Set GPIO line names using device properties
* @chip: GPIO chip whose lines should be named, if possible
*
* Looks for device property "gpio-line-names" and if it exists assigns
@@ -365,7 +381,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
* names belong to the underlying firmware node and should not be released
* by the caller.
*/
-static int devprop_gpiochip_set_names(struct gpio_chip *chip)
+static int gpiochip_set_names(struct gpio_chip *chip)
{
struct gpio_device *gdev = chip->gpiodev;
struct device *dev = &gdev->dev;
@@ -556,7 +572,7 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc,
}
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
-static void gpiodevice_release(struct device *dev)
+static void gpiodev_release(struct device *dev)
{
struct gpio_device *gdev = to_gpio_device(dev);
unsigned long flags;
@@ -585,21 +601,22 @@ static void gpiodevice_release(struct device *dev)
static int gpiochip_setup_dev(struct gpio_device *gdev)
{
+ struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
int ret;
/*
* If fwnode doesn't belong to another device, it's safe to clear its
* initialized flag.
*/
- if (gdev->dev.fwnode && !gdev->dev.fwnode->dev)
- fwnode_dev_initialized(gdev->dev.fwnode, false);
+ if (fwnode && !fwnode->dev)
+ fwnode_dev_initialized(fwnode, false);
ret = gcdev_register(gdev, gpio_devt);
if (ret)
return ret;
/* From this point, the .release() function cleans up gpio_device */
- gdev->dev.release = gpiodevice_release;
+ gdev->dev.release = gpiodev_release;
ret = gpiochip_sysfs_register(gdev);
if (ret)
@@ -663,11 +680,28 @@ static void gpiochip_setup_devs(void)
}
}
+static void gpiochip_set_data(struct gpio_chip *gc, void *data)
+{
+ gc->gpiodev->data = data;
+}
+
+/**
+ * gpiochip_get_data() - get per-subdriver data for the chip
+ * @gc: GPIO chip
+ *
+ * Returns:
+ * The per-subdriver data for the chip.
+ */
+void *gpiochip_get_data(struct gpio_chip *gc)
+{
+ return gc->gpiodev->data;
+}
+EXPORT_SYMBOL_GPL(gpiochip_get_data);
+
int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
struct lock_class_key *lock_key,
struct lock_class_key *request_key)
{
- struct fwnode_handle *fwnode = NULL;
struct gpio_device *gdev;
unsigned long flags;
unsigned int i;
@@ -675,12 +709,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
int base = 0;
int ret = 0;
- /* If the calling driver did not initialize firmware node, do it here */
- if (gc->fwnode)
- fwnode = gc->fwnode;
- else if (gc->parent)
- fwnode = dev_fwnode(gc->parent);
- gc->fwnode = fwnode;
+ /*
+ * If the calling driver did not initialize firmware node, do it here
+ * using the parent device, if any.
+ */
+ if (!gc->fwnode && gc->parent)
+ gc->fwnode = dev_fwnode(gc->parent);
/*
* First: allocate and populate the internal stat container, and
@@ -692,7 +726,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
gdev->dev.bus = &gpio_bus_type;
gdev->dev.parent = gc->parent;
gdev->chip = gc;
+
gc->gpiodev = gdev;
+ gpiochip_set_data(gc, data);
device_set_node(&gdev->dev, gc->fwnode);
@@ -759,7 +795,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
}
gdev->ngpio = gc->ngpio;
- gdev->data = data;
spin_lock_irqsave(&gpio_lock, flags);
@@ -816,7 +851,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
if (ret)
goto err_remove_from_list;
}
- ret = devprop_gpiochip_set_names(gc);
+ ret = gpiochip_set_names(gc);
if (ret)
goto err_remove_from_list;
@@ -922,19 +957,6 @@ err_print_message:
EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);
/**
- * gpiochip_get_data() - get per-subdriver data for the chip
- * @gc: GPIO chip
- *
- * Returns:
- * The per-subdriver data for the chip.
- */
-void *gpiochip_get_data(struct gpio_chip *gc)
-{
- return gc->gpiodev->data;
-}
-EXPORT_SYMBOL_GPL(gpiochip_get_data);
-
-/**
* gpiochip_remove() - unregister a gpio_chip
* @gc: the chip to unregister
*
@@ -960,9 +982,9 @@ void gpiochip_remove(struct gpio_chip *gc)
gpiochip_free_valid_mask(gc);
/*
* We accept no more calls into the driver from this point, so
- * NULL the driver data pointer
+ * NULL the driver data pointer.
*/
- gdev->data = NULL;
+ gpiochip_set_data(gc, NULL);
spin_lock_irqsave(&gpio_lock, flags);
for (i = 0; i < gdev->ngpio; i++) {
@@ -1201,7 +1223,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
if (ret)
return ret;
- chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq);
+ chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq);
ret = girq->child_to_parent_hwirq(gc, hwirq, type,
&parent_hwirq, &parent_type);
@@ -1369,8 +1391,7 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
* gpiochip by assigning the gpiochip as chip data, and using the irqchip
* stored inside the gpiochip.
*/
-int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
+int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)
{
struct gpio_chip *gc = d->host_data;
int ret = 0;
@@ -1446,8 +1467,9 @@ int gpiochip_irq_domain_activate(struct irq_domain *domain,
struct irq_data *data, bool reserve)
{
struct gpio_chip *gc = domain->host_data;
+ unsigned int hwirq = irqd_to_hwirq(data);
- return gpiochip_lock_as_irq(gc, data->hwirq);
+ return gpiochip_lock_as_irq(gc, hwirq);
}
EXPORT_SYMBOL_GPL(gpiochip_irq_domain_activate);
@@ -1464,8 +1486,9 @@ void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
struct irq_data *data)
{
struct gpio_chip *gc = domain->host_data;
+ unsigned int hwirq = irqd_to_hwirq(data);
- return gpiochip_unlock_as_irq(gc, data->hwirq);
+ return gpiochip_unlock_as_irq(gc, hwirq);
}
EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
@@ -1505,33 +1528,37 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)
int gpiochip_irq_reqres(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
- return gpiochip_reqres_irq(gc, d->hwirq);
+ return gpiochip_reqres_irq(gc, hwirq);
}
EXPORT_SYMBOL(gpiochip_irq_reqres);
void gpiochip_irq_relres(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
- gpiochip_relres_irq(gc, d->hwirq);
+ gpiochip_relres_irq(gc, hwirq);
}
EXPORT_SYMBOL(gpiochip_irq_relres);
static void gpiochip_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
if (gc->irq.irq_mask)
gc->irq.irq_mask(d);
- gpiochip_disable_irq(gc, d->hwirq);
+ gpiochip_disable_irq(gc, hwirq);
}
static void gpiochip_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
- gpiochip_enable_irq(gc, d->hwirq);
+ gpiochip_enable_irq(gc, hwirq);
if (gc->irq.irq_unmask)
gc->irq.irq_unmask(d);
}
@@ -1539,17 +1566,19 @@ static void gpiochip_irq_unmask(struct irq_data *d)
static void gpiochip_irq_enable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
- gpiochip_enable_irq(gc, d->hwirq);
+ gpiochip_enable_irq(gc, hwirq);
gc->irq.irq_enable(d);
}
static void gpiochip_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
gc->irq.irq_disable(d);
- gpiochip_disable_irq(gc, d->hwirq);
+ gpiochip_disable_irq(gc, hwirq);
}
static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
@@ -3909,13 +3938,10 @@ static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
bool platform_lookup_allowed)
{
unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
- struct gpio_desc *desc = ERR_PTR(-ENOENT);
+ struct gpio_desc *desc;
int ret;
- if (!IS_ERR_OR_NULL(fwnode))
- desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx,
- &flags, &lookupflags);
-
+ desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx, &flags, &lookupflags);
if (gpiod_not_found(desc) && platform_lookup_allowed) {
/*
* Either we are not using DT or ACPI, or their lookup did not
@@ -4256,16 +4282,18 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
struct gpio_array *array_info = NULL;
struct gpio_chip *gc;
int count, bitmap_size;
+ size_t descs_size;
count = gpiod_count(dev, con_id);
if (count < 0)
return ERR_PTR(count);
- descs = kzalloc(struct_size(descs, desc, count), GFP_KERNEL);
+ descs_size = struct_size(descs, desc, count);
+ descs = kzalloc(descs_size, GFP_KERNEL);
if (!descs)
return ERR_PTR(-ENOMEM);
- for (descs->ndescs = 0; descs->ndescs < count; ) {
+ for (descs->ndescs = 0; descs->ndescs < count; descs->ndescs++) {
desc = gpiod_get_index(dev, con_id, descs->ndescs, flags);
if (IS_ERR(desc)) {
gpiod_put_array(descs);
@@ -4285,20 +4313,17 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
bitmap_size = BITS_TO_LONGS(gc->ngpio > count ?
gc->ngpio : count);
- array = kzalloc(struct_size(descs, desc, count) +
- struct_size(array_info, invert_mask,
- 3 * bitmap_size), GFP_KERNEL);
+ array = krealloc(descs, descs_size +
+ struct_size(array_info, invert_mask, 3 * bitmap_size),
+ GFP_KERNEL | __GFP_ZERO);
if (!array) {
gpiod_put_array(descs);
return ERR_PTR(-ENOMEM);
}
- memcpy(array, descs,
- struct_size(descs, desc, descs->ndescs + 1));
- kfree(descs);
-
descs = array;
- array_info = (void *)(descs->desc + count);
+
+ array_info = (void *)descs + descs_size;
array_info->get_mask = array_info->invert_mask +
bitmap_size;
array_info->set_mask = array_info->get_mask +
@@ -4313,8 +4338,13 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
count - descs->ndescs);
descs->info = array_info;
}
+
+ /* If there is no cache for fast bitmap processing path, continue */
+ if (!array_info)
+ continue;
+
/* Unmark array members which don't belong to the 'fast' chip */
- if (array_info && array_info->chip != gc) {
+ if (array_info->chip != gc) {
__clear_bit(descs->ndescs, array_info->get_mask);
__clear_bit(descs->ndescs, array_info->set_mask);
}
@@ -4322,8 +4352,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
* Detect array members which belong to the 'fast' chip
* but their pins are not in hardware order.
*/
- else if (array_info &&
- gpio_chip_hwgpio(desc) != descs->ndescs) {
+ else if (gpio_chip_hwgpio(desc) != descs->ndescs) {
/*
* Don't use fast path if all array members processed so
* far belong to the same chip as this one but its pin
@@ -4337,7 +4366,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
__clear_bit(descs->ndescs,
array_info->set_mask);
}
- } else if (array_info) {
+ } else {
/* Exclude open drain or open source from fast output */
if (gpiochip_line_is_open_drain(gc, descs->ndescs) ||
gpiochip_line_is_open_source(gc, descs->ndescs))
@@ -4348,8 +4377,6 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
__set_bit(descs->ndescs,
array_info->invert_mask);
}
-
- descs->ndescs++;
}
if (array_info)
dev_dbg(dev,
@@ -4413,20 +4440,6 @@ void gpiod_put_array(struct gpio_descs *descs)
}
EXPORT_SYMBOL_GPL(gpiod_put_array);
-
-static int gpio_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct fwnode_handle *fwnode = dev_fwnode(dev);
-
- /*
- * Only match if the fwnode doesn't already have a proper struct device
- * created for it.
- */
- if (fwnode && fwnode->dev != dev)
- return 0;
- return 1;
-}
-
static int gpio_stub_drv_probe(struct device *dev)
{
/*