diff options
| author | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
| commit | 1ac731c529cd4d6adbce134754b51ff7d822b145 (patch) | |
| tree | 143ab3f35ca5f3b69f583c84e6964b17139c2ec1 /drivers/gpio | |
| parent | 07b4c950f27bef0362dc6ad7ee713aab61d58149 (diff) | |
| parent | 54116d442e001e1b6bd482122043b1870998a1f3 (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.6 merge window.
Diffstat (limited to 'drivers/gpio')
66 files changed, 2481 insertions, 897 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 13be729710f2..f45c6a36551c 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 @@ -879,7 +897,7 @@ config GPIO_F7188X  	help  	  This option enables support for GPIOs found on Fintek Super-I/O  	  chips F71869, F71869A, F71882FG, F71889F and F81866. -	  As well as Nuvoton Super-I/O chip NCT6116D. +	  As well as Nuvoton Super-I/O chip NCT6126D.  	  To compile this driver as a module, choose M here: the module will  	  be called f7188x-gpio. @@ -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 @@ -1253,6 +1292,18 @@ config GPIO_KEMPLD  	  This driver can also be built as a module. If so, the module will be  	  called gpio-kempld. +config GPIO_LJCA +	tristate "INTEL La Jolla Cove Adapter GPIO support" +	depends on MFD_LJCA +	select GPIOLIB_IRQCHIP +	default MFD_LJCA +	help +	  Select this option to enable GPIO driver for the INTEL +	  La Jolla Cove Adapter (LJCA) board. + +	  This driver can also be built as a module. If so, the module +	  will be called gpio-ljca. +  config GPIO_LP3943  	tristate "TI/National Semiconductor LP3943 GPIO expander"  	depends on MFD_LP3943 @@ -1311,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 @@ -1505,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 c048ba003367..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 @@ -77,9 +79,11 @@ obj-$(CONFIG_GPIO_IXP4XX)		+= gpio-ixp4xx.o  obj-$(CONFIG_GPIO_JANZ_TTL)		+= gpio-janz-ttl.o  obj-$(CONFIG_GPIO_KEMPLD)		+= gpio-kempld.o  obj-$(CONFIG_GPIO_LATCH)		+= gpio-latch.o +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 @@ -145,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 <[email protected]> + *          Raag Jadav <[email protected]> + */ + +#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 <[email protected]>"); +MODULE_AUTHOR("Raag Jadav <[email protected]>"); +MODULE_DESCRIPTION("Intel Elkhart Lake PSE GPIO driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(GPIO_TANGIER); diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 9effa7769bef..f54ca5a1775e 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -48,7 +48,7 @@  /*   * Nuvoton devices.   */ -#define SIO_NCT6116D_ID		0xD283  /* NCT6116D chipset ID */ +#define SIO_NCT6126D_ID		0xD283  /* NCT6126D chipset ID */  #define SIO_LD_GPIO_NUVOTON	0x07	/* GPIO logical device */ @@ -62,7 +62,7 @@ enum chips {  	f81866,  	f81804,  	f81865, -	nct6116d, +	nct6126d,  };  static const char * const f7188x_names[] = { @@ -74,7 +74,7 @@ static const char * const f7188x_names[] = {  	"f81866",  	"f81804",  	"f81865", -	"nct6116d", +	"nct6126d",  };  struct f7188x_sio { @@ -187,8 +187,8 @@ static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,  /* Output mode register (0:open drain 1:push-pull). */  #define f7188x_gpio_out_mode(base) ((base) + 3) -#define f7188x_gpio_dir_invert(type)	((type) == nct6116d) -#define f7188x_gpio_data_single(type)	((type) == nct6116d) +#define f7188x_gpio_dir_invert(type)	((type) == nct6126d) +#define f7188x_gpio_data_single(type)	((type) == nct6126d)  static struct f7188x_gpio_bank f71869_gpio_bank[] = {  	F7188X_GPIO_BANK(0, 6, 0xF0, DRVNAME "-0"), @@ -274,7 +274,7 @@ static struct f7188x_gpio_bank f81865_gpio_bank[] = {  	F7188X_GPIO_BANK(60, 5, 0x90, DRVNAME "-6"),  }; -static struct f7188x_gpio_bank nct6116d_gpio_bank[] = { +static struct f7188x_gpio_bank nct6126d_gpio_bank[] = {  	F7188X_GPIO_BANK(0, 8, 0xE0, DRVNAME "-0"),  	F7188X_GPIO_BANK(10, 8, 0xE4, DRVNAME "-1"),  	F7188X_GPIO_BANK(20, 8, 0xE8, DRVNAME "-2"), @@ -282,7 +282,7 @@ static struct f7188x_gpio_bank nct6116d_gpio_bank[] = {  	F7188X_GPIO_BANK(40, 8, 0xF0, DRVNAME "-4"),  	F7188X_GPIO_BANK(50, 8, 0xF4, DRVNAME "-5"),  	F7188X_GPIO_BANK(60, 8, 0xF8, DRVNAME "-6"), -	F7188X_GPIO_BANK(70, 1, 0xFC, DRVNAME "-7"), +	F7188X_GPIO_BANK(70, 8, 0xFC, DRVNAME "-7"),  };  static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) @@ -490,9 +490,9 @@ static int f7188x_gpio_probe(struct platform_device *pdev)  		data->nr_bank = ARRAY_SIZE(f81865_gpio_bank);  		data->bank = f81865_gpio_bank;  		break; -	case nct6116d: -		data->nr_bank = ARRAY_SIZE(nct6116d_gpio_bank); -		data->bank = nct6116d_gpio_bank; +	case nct6126d: +		data->nr_bank = ARRAY_SIZE(nct6126d_gpio_bank); +		data->bank = nct6126d_gpio_bank;  		break;  	default:  		return -ENODEV; @@ -559,9 +559,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)  	case SIO_F81865_ID:  		sio->type = f81865;  		break; -	case SIO_NCT6116D_ID: +	case SIO_NCT6126D_ID:  		sio->device = SIO_LD_GPIO_NUVOTON; -		sio->type = nct6116d; +		sio->type = nct6126d;  		break;  	default:  		pr_info("Unsupported Fintek device 0x%04x\n", devid); @@ -569,7 +569,7 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)  	}  	/* double check manufacturer where possible */ -	if (sio->type != nct6116d) { +	if (sio->type != nct6126d) {  		manid = superio_inw(addr, SIO_FINTEK_MANID);  		if (manid != SIO_FINTEK_ID) {  			pr_debug("Not a Fintek device at 0x%08x\n", addr); @@ -581,7 +581,7 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)  	err = 0;  	pr_info("Found %s at %#x\n", f7188x_names[sio->type], (unsigned int)addr); -	if (sio->type != nct6116d) +	if (sio->type != nct6126d)  		pr_info("   revision %d\n", superio_inb(addr, SIO_FINTEK_DEVREV));  err: 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 <[email protected]> + */ + +#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, ®map); +	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 <[email protected]>"); +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 <[email protected]>");  MODULE_DESCRIPTION("NXP GPIO over IMX SCU API"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-ljca.c b/drivers/gpio/gpio-ljca.c new file mode 100644 index 000000000000..87863f0230f5 --- /dev/null +++ b/drivers/gpio/gpio-ljca.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel La Jolla Cove Adapter USB-GPIO driver + * + * Copyright (c) 2023, Intel Corporation. + */ + +#include <linux/acpi.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/dev_printk.h> +#include <linux/gpio/driver.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/kref.h> +#include <linux/mfd/ljca.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> + +/* GPIO commands */ +#define LJCA_GPIO_CONFIG	1 +#define LJCA_GPIO_READ		2 +#define LJCA_GPIO_WRITE		3 +#define LJCA_GPIO_INT_EVENT	4 +#define LJCA_GPIO_INT_MASK	5 +#define LJCA_GPIO_INT_UNMASK	6 + +#define LJCA_GPIO_CONF_DISABLE		BIT(0) +#define LJCA_GPIO_CONF_INPUT		BIT(1) +#define LJCA_GPIO_CONF_OUTPUT		BIT(2) +#define LJCA_GPIO_CONF_PULLUP		BIT(3) +#define LJCA_GPIO_CONF_PULLDOWN		BIT(4) +#define LJCA_GPIO_CONF_DEFAULT		BIT(5) +#define LJCA_GPIO_CONF_INTERRUPT	BIT(6) +#define LJCA_GPIO_INT_TYPE		BIT(7) + +#define LJCA_GPIO_CONF_EDGE	FIELD_PREP(LJCA_GPIO_INT_TYPE, 1) +#define LJCA_GPIO_CONF_LEVEL	FIELD_PREP(LJCA_GPIO_INT_TYPE, 0) + +/* Intentional overlap with PULLUP / PULLDOWN */ +#define LJCA_GPIO_CONF_SET	BIT(3) +#define LJCA_GPIO_CONF_CLR	BIT(4) + +struct gpio_op { +	u8 index; +	u8 value; +} __packed; + +struct gpio_packet { +	u8 num; +	struct gpio_op item[]; +} __packed; + +#define LJCA_GPIO_BUF_SIZE 60 +struct ljca_gpio_dev { +	struct platform_device *pdev; +	struct gpio_chip gc; +	struct ljca_gpio_info *gpio_info; +	DECLARE_BITMAP(unmasked_irqs, LJCA_MAX_GPIO_NUM); +	DECLARE_BITMAP(enabled_irqs, LJCA_MAX_GPIO_NUM); +	DECLARE_BITMAP(reenable_irqs, LJCA_MAX_GPIO_NUM); +	u8 *connect_mode; +	/* mutex to protect irq bus */ +	struct mutex irq_lock; +	struct work_struct work; +	/* lock to protect package transfer to Hardware */ +	struct mutex trans_lock; + +	u8 obuf[LJCA_GPIO_BUF_SIZE]; +	u8 ibuf[LJCA_GPIO_BUF_SIZE]; +}; + +static int gpio_config(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id, u8 config) +{ +	struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; +	int ret; + +	mutex_lock(&ljca_gpio->trans_lock); +	packet->item[0].index = gpio_id; +	packet->item[0].value = config | ljca_gpio->connect_mode[gpio_id]; +	packet->num = 1; + +	ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_CONFIG, packet, +			    struct_size(packet, item, packet->num), NULL, NULL); +	mutex_unlock(&ljca_gpio->trans_lock); +	return ret; +} + +static int ljca_gpio_read(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id) +{ +	struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; +	struct gpio_packet *ack_packet = (struct gpio_packet *)ljca_gpio->ibuf; +	unsigned int ibuf_len = LJCA_GPIO_BUF_SIZE; +	int ret; + +	mutex_lock(&ljca_gpio->trans_lock); +	packet->num = 1; +	packet->item[0].index = gpio_id; +	ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_READ, packet, +			    struct_size(packet, item, packet->num), ljca_gpio->ibuf, &ibuf_len); +	if (ret) +		goto out_unlock; + +	if (!ibuf_len || ack_packet->num != packet->num) { +		dev_err(&ljca_gpio->pdev->dev, "failed gpio_id:%u %u", gpio_id, ack_packet->num); +		ret = -EIO; +	} + +out_unlock: +	mutex_unlock(&ljca_gpio->trans_lock); +	if (ret) +		return ret; +	return ack_packet->item[0].value > 0; +} + +static int ljca_gpio_write(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id, +			   int value) +{ +	struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; +	int ret; + +	mutex_lock(&ljca_gpio->trans_lock); +	packet->num = 1; +	packet->item[0].index = gpio_id; +	packet->item[0].value = value & 1; + +	ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_WRITE, packet, +			    struct_size(packet, item, packet->num), NULL, NULL); +	mutex_unlock(&ljca_gpio->trans_lock); +	return ret; +} + +static int ljca_gpio_get_value(struct gpio_chip *chip, unsigned int offset) +{ +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + +	return ljca_gpio_read(ljca_gpio, offset); +} + +static void ljca_gpio_set_value(struct gpio_chip *chip, unsigned int offset, +				int val) +{ +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); +	int ret; + +	ret = ljca_gpio_write(ljca_gpio, offset, val); +	if (ret) +		dev_err(chip->parent, "offset:%u val:%d set value failed %d\n", offset, val, ret); +} + +static int ljca_gpio_direction_input(struct gpio_chip *chip, +				     unsigned int offset) +{ +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); +	u8 config = LJCA_GPIO_CONF_INPUT | LJCA_GPIO_CONF_CLR; + +	return gpio_config(ljca_gpio, offset, config); +} + +static int ljca_gpio_direction_output(struct gpio_chip *chip, +				      unsigned int offset, int val) +{ +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); +	u8 config = LJCA_GPIO_CONF_OUTPUT | LJCA_GPIO_CONF_CLR; +	int ret; + +	ret = gpio_config(ljca_gpio, offset, config); +	if (ret) +		return ret; + +	ljca_gpio_set_value(chip, offset, val); +	return 0; +} + +static int ljca_gpio_set_config(struct gpio_chip *chip, unsigned int offset, +				unsigned long config) +{ +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + +	ljca_gpio->connect_mode[offset] = 0; +	switch (pinconf_to_config_param(config)) { +	case PIN_CONFIG_BIAS_PULL_UP: +		ljca_gpio->connect_mode[offset] |= LJCA_GPIO_CONF_PULLUP; +		break; +	case PIN_CONFIG_BIAS_PULL_DOWN: +		ljca_gpio->connect_mode[offset] |= LJCA_GPIO_CONF_PULLDOWN; +		break; +	case PIN_CONFIG_DRIVE_PUSH_PULL: +	case PIN_CONFIG_PERSIST_STATE: +		break; +	default: +		return -ENOTSUPP; +	} + +	return 0; +} + +static int ljca_gpio_init_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, +				     unsigned int ngpios) +{ +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + +	WARN_ON_ONCE(ngpios != ljca_gpio->gpio_info->num); +	bitmap_copy(valid_mask, ljca_gpio->gpio_info->valid_pin_map, ngpios); + +	return 0; +} + +static void ljca_gpio_irq_init_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, +					  unsigned int ngpios) +{ +	ljca_gpio_init_valid_mask(chip, valid_mask, ngpios); +} + +static int ljca_enable_irq(struct ljca_gpio_dev *ljca_gpio, int gpio_id, bool enable) +{ +	struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; +	int ret; + +	mutex_lock(&ljca_gpio->trans_lock); +	packet->num = 1; +	packet->item[0].index = gpio_id; +	packet->item[0].value = 0; + +	ret = ljca_transfer(ljca_gpio->gpio_info->ljca, +			    enable ? LJCA_GPIO_INT_UNMASK : LJCA_GPIO_INT_MASK, packet, +			    struct_size(packet, item, packet->num), NULL, NULL); +	mutex_unlock(&ljca_gpio->trans_lock); +	return ret; +} + +static void ljca_gpio_async(struct work_struct *work) +{ +	struct ljca_gpio_dev *ljca_gpio = container_of(work, struct ljca_gpio_dev, work); +	int gpio_id; +	int unmasked; + +	for_each_set_bit(gpio_id, ljca_gpio->reenable_irqs, ljca_gpio->gc.ngpio) { +		clear_bit(gpio_id, ljca_gpio->reenable_irqs); +		unmasked = test_bit(gpio_id, ljca_gpio->unmasked_irqs); +		if (unmasked) +			ljca_enable_irq(ljca_gpio, gpio_id, true); +	} +} + +static void ljca_gpio_event_cb(void *context, u8 cmd, const void *evt_data, int len) +{ +	const struct gpio_packet *packet = evt_data; +	struct ljca_gpio_dev *ljca_gpio = context; +	int i; +	int irq; + +	if (cmd != LJCA_GPIO_INT_EVENT) +		return; + +	for (i = 0; i < packet->num; i++) { +		irq = irq_find_mapping(ljca_gpio->gc.irq.domain, packet->item[i].index); +		if (!irq) { +			dev_err(ljca_gpio->gc.parent, "gpio_id %u does not mapped to IRQ yet\n", +				packet->item[i].index); +			return; +		} + +		generic_handle_domain_irq(ljca_gpio->gc.irq.domain, irq); +		set_bit(packet->item[i].index, ljca_gpio->reenable_irqs); +	} + +	schedule_work(&ljca_gpio->work); +} + +static void ljca_irq_unmask(struct irq_data *irqd) +{ +	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); +	int gpio_id = irqd_to_hwirq(irqd); + +	gpiochip_enable_irq(gc, gpio_id); +	set_bit(gpio_id, ljca_gpio->unmasked_irqs); +} + +static void ljca_irq_mask(struct irq_data *irqd) +{ +	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); +	int gpio_id = irqd_to_hwirq(irqd); + +	clear_bit(gpio_id, ljca_gpio->unmasked_irqs); +	gpiochip_disable_irq(gc, gpio_id); +} + +static int ljca_irq_set_type(struct irq_data *irqd, unsigned int type) +{ +	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); +	int gpio_id = irqd_to_hwirq(irqd); + +	ljca_gpio->connect_mode[gpio_id] = LJCA_GPIO_CONF_INTERRUPT; +	switch (type) { +	case IRQ_TYPE_LEVEL_HIGH: +		ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_LEVEL | LJCA_GPIO_CONF_PULLUP); +		break; +	case IRQ_TYPE_LEVEL_LOW: +		ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_LEVEL | LJCA_GPIO_CONF_PULLDOWN); +		break; +	case IRQ_TYPE_EDGE_BOTH: +		break; +	case IRQ_TYPE_EDGE_RISING: +		ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_EDGE | LJCA_GPIO_CONF_PULLUP); +		break; +	case IRQ_TYPE_EDGE_FALLING: +		ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_EDGE | LJCA_GPIO_CONF_PULLDOWN); +		break; +	default: +		return -EINVAL; +	} + +	return 0; +} + +static void ljca_irq_bus_lock(struct irq_data *irqd) +{ +	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + +	mutex_lock(&ljca_gpio->irq_lock); +} + +static void ljca_irq_bus_unlock(struct irq_data *irqd) +{ +	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); +	struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); +	int gpio_id = irqd_to_hwirq(irqd); +	int enabled; +	int unmasked; + +	enabled = test_bit(gpio_id, ljca_gpio->enabled_irqs); +	unmasked = test_bit(gpio_id, ljca_gpio->unmasked_irqs); + +	if (enabled != unmasked) { +		if (unmasked) { +			gpio_config(ljca_gpio, gpio_id, 0); +			ljca_enable_irq(ljca_gpio, gpio_id, true); +			set_bit(gpio_id, ljca_gpio->enabled_irqs); +		} else { +			ljca_enable_irq(ljca_gpio, gpio_id, false); +			clear_bit(gpio_id, ljca_gpio->enabled_irqs); +		} +	} + +	mutex_unlock(&ljca_gpio->irq_lock); +} + +static const struct irq_chip ljca_gpio_irqchip = { +	.name = "ljca-irq", +	.irq_mask = ljca_irq_mask, +	.irq_unmask = ljca_irq_unmask, +	.irq_set_type = ljca_irq_set_type, +	.irq_bus_lock = ljca_irq_bus_lock, +	.irq_bus_sync_unlock = ljca_irq_bus_unlock, +	.flags = IRQCHIP_IMMUTABLE, +	GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static int ljca_gpio_probe(struct platform_device *pdev) +{ +	struct ljca_gpio_dev *ljca_gpio; +	struct gpio_irq_chip *girq; +	int ret; + +	ljca_gpio = devm_kzalloc(&pdev->dev, sizeof(*ljca_gpio), GFP_KERNEL); +	if (!ljca_gpio) +		return -ENOMEM; + +	ljca_gpio->gpio_info = dev_get_platdata(&pdev->dev); +	ljca_gpio->connect_mode = devm_kcalloc(&pdev->dev, ljca_gpio->gpio_info->num, +					       sizeof(*ljca_gpio->connect_mode), GFP_KERNEL); +	if (!ljca_gpio->connect_mode) +		return -ENOMEM; + +	mutex_init(&ljca_gpio->irq_lock); +	mutex_init(&ljca_gpio->trans_lock); +	ljca_gpio->pdev = pdev; +	ljca_gpio->gc.direction_input = ljca_gpio_direction_input; +	ljca_gpio->gc.direction_output = ljca_gpio_direction_output; +	ljca_gpio->gc.get = ljca_gpio_get_value; +	ljca_gpio->gc.set = ljca_gpio_set_value; +	ljca_gpio->gc.set_config = ljca_gpio_set_config; +	ljca_gpio->gc.init_valid_mask = ljca_gpio_init_valid_mask; +	ljca_gpio->gc.can_sleep = true; +	ljca_gpio->gc.parent = &pdev->dev; + +	ljca_gpio->gc.base = -1; +	ljca_gpio->gc.ngpio = ljca_gpio->gpio_info->num; +	ljca_gpio->gc.label = ACPI_COMPANION(&pdev->dev) ? +			      acpi_dev_name(ACPI_COMPANION(&pdev->dev)) : +			      dev_name(&pdev->dev); +	ljca_gpio->gc.owner = THIS_MODULE; + +	platform_set_drvdata(pdev, ljca_gpio); +	ljca_register_event_cb(ljca_gpio->gpio_info->ljca, ljca_gpio_event_cb, ljca_gpio); + +	girq = &ljca_gpio->gc.irq; +	gpio_irq_chip_set_chip(girq, &ljca_gpio_irqchip); +	girq->parent_handler = NULL; +	girq->num_parents = 0; +	girq->parents = NULL; +	girq->default_type = IRQ_TYPE_NONE; +	girq->handler = handle_simple_irq; +	girq->init_valid_mask = ljca_gpio_irq_init_valid_mask; + +	INIT_WORK(&ljca_gpio->work, ljca_gpio_async); +	ret = gpiochip_add_data(&ljca_gpio->gc, ljca_gpio); +	if (ret) { +		ljca_unregister_event_cb(ljca_gpio->gpio_info->ljca); +		mutex_destroy(&ljca_gpio->irq_lock); +		mutex_destroy(&ljca_gpio->trans_lock); +	} + +	return ret; +} + +static int ljca_gpio_remove(struct platform_device *pdev) +{ +	struct ljca_gpio_dev *ljca_gpio = platform_get_drvdata(pdev); + +	gpiochip_remove(&ljca_gpio->gc); +	ljca_unregister_event_cb(ljca_gpio->gpio_info->ljca); +	mutex_destroy(&ljca_gpio->irq_lock); +	mutex_destroy(&ljca_gpio->trans_lock); +	return 0; +} + +#define LJCA_GPIO_DRV_NAME "ljca-gpio" +static const struct platform_device_id ljca_gpio_id[] = { +	{ LJCA_GPIO_DRV_NAME, 0 }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, ljca_gpio_id); + +static struct platform_driver ljca_gpio_driver = { +	.driver.name = LJCA_GPIO_DRV_NAME, +	.probe = ljca_gpio_probe, +	.remove = ljca_gpio_remove, +}; +module_platform_driver(ljca_gpio_driver); + +MODULE_AUTHOR("Ye Xiang <[email protected]>"); +MODULE_AUTHOR("Wang Zhifeng <[email protected]>"); +MODULE_AUTHOR("Zhang Lixu <[email protected]>"); +MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-GPIO driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(LJCA); 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 <[email protected]> - * - * 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 <[email protected]>   */  #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 <[email protected]>"); +MODULE_AUTHOR("Keguang Zhang <[email protected]>");  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 <[email protected]>   */  #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 <[email protected]>");  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-mockup.c b/drivers/gpio/gpio-mockup.c index e6a7049bef64..b32063ac845a 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -369,7 +369,7 @@ static void gpio_mockup_debugfs_setup(struct device *dev,  		priv->offset = i;  		priv->desc = gpiochip_get_desc(gc, i); -		debugfs_create_file(name, 0200, chip->dbg_dir, priv, +		debugfs_create_file(name, 0600, chip->dbg_dir, priv,  				    &gpio_mockup_debugfs_ops);  	}  } 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 <[email protected]>");  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 <[email protected]>"); -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 <[email protected]>   */ -#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..745e5f67254e 100644 --- a/drivers/gpio/gpio-sifive.c +++ b/drivers/gpio/gpio-sifive.c @@ -221,8 +221,12 @@ static int sifive_gpio_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	for (i = 0; i < ngpio; i++) -		chip->irq_number[i] = platform_get_irq(pdev, i); +	for (i = 0; i < ngpio; i++) { +		ret = platform_get_irq(pdev, i); +		if (ret < 0) +			return ret; +		chip->irq_number[i] = ret; +	}  	ret = bgpio_init(&chip->gc, dev, 4,  			 chip->base + SIFIVE_GPIO_INPUT_VAL, @@ -270,7 +274,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..8b49b0abacd5 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -696,6 +696,9 @@ static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank,  	char **line_names;  	list_for_each_entry(line, &bank->line_list, siblings) { +		if (line->offset >= bank->num_lines) +			continue; +  		if (line->name) {  			if (line->offset > max_offset)  				max_offset = line->offset; @@ -721,8 +724,13 @@ static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank,  	if (!line_names)  		return ERR_PTR(-ENOMEM); -	list_for_each_entry(line, &bank->line_list, siblings) -		line_names[line->offset] = line->name; +	list_for_each_entry(line, &bank->line_list, siblings) { +		if (line->offset >= bank->num_lines) +			continue; + +		if (line->name && (line->offset <= max_offset)) +			line_names[line->offset] = line->name; +	}  	return line_names;  } @@ -754,6 +762,9 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)  	list_for_each_entry(bank, &dev->bank_list, siblings) {  		list_for_each_entry(line, &bank->line_list, siblings) { +			if (line->offset >= bank->num_lines) +				continue; +  			if (line->hog)  				num_hogs++;  		} @@ -769,6 +780,9 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)  	list_for_each_entry(bank, &dev->bank_list, siblings) {  		list_for_each_entry(line, &bank->line_list, siblings) { +			if (line->offset >= bank->num_lines) +				continue; +  			if (!line->hog)  				continue; @@ -953,9 +967,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 <[email protected]> + *          Pandith N <[email protected]> + *          Raag Jadav <[email protected]> + */ + +#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 <[email protected]>"); +MODULE_AUTHOR("Pandith N <[email protected]>"); +MODULE_AUTHOR("Raag Jadav <[email protected]>"); +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 <[email protected]> + *          Pandith N <[email protected]> + *          Raag Jadav <[email protected]> + */ + +#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-tegra186.c b/drivers/gpio/gpio-tegra186.c index 14c872b6ad05..b904de0b1784 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -1134,6 +1134,7 @@ static const struct tegra_gpio_soc tegra234_aon_soc = {  	.name = "tegra234-gpio-aon",  	.instance = 1,  	.num_irqs_per_bank = 8, +	.has_gte = true,  };  #define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins)	\ 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 d8a421ce26a8..97496c0f9133 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -7,17 +7,19 @@   *          Mika Westerberg <[email protected]>   */ +#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;  }  /** @@ -536,6 +538,9 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)  	if (ACPI_FAILURE(status))  		return; +	if (acpi_quirk_skip_gpio_event_handlers()) +		return; +  	acpi_walk_resources(handle, METHOD_NAME__AEI,  			    acpi_gpiochip_alloc_event, acpi_gpio); @@ -643,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++) @@ -837,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); - -		if (!adev) -			return ret; +		struct acpi_device *adev; -		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;  	}  	/* @@ -1621,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..5be8ad61523e 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, @@ -193,6 +209,8 @@ static int gpiochip_find_base(int ngpio)  			break;  		/* nope, check the space right after the chip */  		base = gdev->base + gdev->ngpio; +		if (base < GPIO_DYNAMIC_BASE) +			base = GPIO_DYNAMIC_BASE;  	}  	if (gpio_is_valid(base)) { @@ -357,7 +375,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 +383,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 +574,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 +603,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 +682,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 +711,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 +728,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 +797,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 +853,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 +959,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 +984,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 +1225,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 +1393,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 +1469,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 +1488,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 +1530,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 +1568,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) @@ -1714,7 +1745,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)  	}  	/* Remove all IRQ mappings and delete the domain */ -	if (gc->irq.domain) { +	if (!gc->irq.domain_is_allocated_externally && gc->irq.domain) {  		unsigned int irq;  		for (offset = 0; offset < gc->ngpio; offset++) { @@ -1760,6 +1791,15 @@ int gpiochip_irqchip_add_domain(struct gpio_chip *gc,  	gc->to_irq = gpiochip_to_irq;  	gc->irq.domain = domain; +	gc->irq.domain_is_allocated_externally = true; + +	/* +	 * Using barrier() here to prevent compiler from reordering +	 * gc->irq.initialized before adding irqdomain. +	 */ +	barrier(); + +	gc->irq.initialized = true;  	return 0;  } @@ -3909,13 +3949,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 +4293,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 +4324,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 +4349,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 +4363,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 +4377,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 +4388,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 +4451,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)  {  	/*  |