diff options
Diffstat (limited to 'drivers/gpio')
43 files changed, 1037 insertions, 370 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8f442ed4a322..d171e3055b5d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -381,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 @@ -488,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 @@ -1014,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 @@ -1336,6 +1350,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 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 594a443eba60..8309b4ff128b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o +obj-$(CONFIG_GPIO_FXL6408) += gpio-fxl6408.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o @@ -81,6 +82,7 @@ obj-$(CONFIG_GPIO_LATCH) += gpio-latch.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 diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index a3846faf3780..4ec4719bf942 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -106,7 +106,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 +117,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 +125,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 +194,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-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-altera.c b/drivers/gpio/gpio-altera.c index 99e137f8097e..54d7c450c596 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -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-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index 2728672ef9f8..31e26072f6ae 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -349,7 +349,7 @@ static const struct of_device_id ftgpio_gpio_of_match[] = { static struct platform_driver ftgpio_gpio_driver = { .driver = { .name = "ftgpio010-gpio", - .of_match_table = of_match_ptr(ftgpio_gpio_of_match), + .of_match_table = ftgpio_gpio_of_match, }, .probe = ftgpio_gpio_probe, .remove = ftgpio_gpio_remove, diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c new file mode 100644 index 000000000000..208fa851e82a --- /dev/null +++ b/drivers/gpio/gpio-fxl6408.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * FXL6408 GPIO driver + * + * Copyright 2023 Toradex + * + * Author: Emanuele Ghidoli <emanuele.ghidoli@toradex.com> + */ + +#include <linux/err.h> +#include <linux/gpio/regmap.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#define FXL6408_REG_DEVICE_ID 0x01 +#define FXL6408_MF_FAIRCHILD 0b101 +#define FXL6408_MF_SHIFT 5 + +/* Bits set here indicate that the GPIO is an output. */ +#define FXL6408_REG_IO_DIR 0x03 + +/* + * Bits set here, when the corresponding bit of IO_DIR is set, drive + * the output high instead of low. + */ +#define FXL6408_REG_OUTPUT 0x05 + +/* Bits here make the output High-Z, instead of the OUTPUT value. */ +#define FXL6408_REG_OUTPUT_HIGH_Z 0x07 + +/* Returns the current status (1 = HIGH) of the input pins. */ +#define FXL6408_REG_INPUT_STATUS 0x0f + +/* + * Return the current interrupt status + * This bit is HIGH if input GPIO != default state (register 09h). + * The flag is cleared after being read (bit returns to 0). + * The input must go back to default state and change again before this flag is raised again. + */ +#define FXL6408_REG_INT_STS 0x13 + +#define FXL6408_NGPIO 8 + +static const struct regmap_range rd_range[] = { + { FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID }, + { FXL6408_REG_IO_DIR, FXL6408_REG_OUTPUT }, + { FXL6408_REG_INPUT_STATUS, FXL6408_REG_INPUT_STATUS }, +}; + +static const struct regmap_range wr_range[] = { + { FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID }, + { FXL6408_REG_IO_DIR, FXL6408_REG_OUTPUT }, + { FXL6408_REG_OUTPUT_HIGH_Z, FXL6408_REG_OUTPUT_HIGH_Z }, +}; + +static const struct regmap_range volatile_range[] = { + { FXL6408_REG_DEVICE_ID, FXL6408_REG_DEVICE_ID }, + { FXL6408_REG_INPUT_STATUS, FXL6408_REG_INPUT_STATUS }, +}; + +static const struct regmap_access_table rd_table = { + .yes_ranges = rd_range, + .n_yes_ranges = ARRAY_SIZE(rd_range), +}; + +static const struct regmap_access_table wr_table = { + .yes_ranges = wr_range, + .n_yes_ranges = ARRAY_SIZE(wr_range), +}; + +static const struct regmap_access_table volatile_table = { + .yes_ranges = volatile_range, + .n_yes_ranges = ARRAY_SIZE(volatile_range), +}; + +static const struct regmap_config regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = FXL6408_REG_INT_STS, + .wr_table = &wr_table, + .rd_table = &rd_table, + .volatile_table = &volatile_table, + + .cache_type = REGCACHE_RBTREE, + .num_reg_defaults_raw = FXL6408_REG_INT_STS + 1, +}; + +static int fxl6408_identify(struct device *dev, struct regmap *regmap) +{ + int val, ret; + + ret = regmap_read(regmap, FXL6408_REG_DEVICE_ID, &val); + if (ret) + return dev_err_probe(dev, ret, "error reading DEVICE_ID\n"); + if (val >> FXL6408_MF_SHIFT != FXL6408_MF_FAIRCHILD) + return dev_err_probe(dev, -ENODEV, "invalid device id 0x%02x\n", val); + + return 0; +} + +static int fxl6408_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + int ret; + struct gpio_regmap_config gpio_config = { + .parent = dev, + .ngpio = FXL6408_NGPIO, + .reg_dat_base = GPIO_REGMAP_ADDR(FXL6408_REG_INPUT_STATUS), + .reg_set_base = GPIO_REGMAP_ADDR(FXL6408_REG_OUTPUT), + .reg_dir_out_base = GPIO_REGMAP_ADDR(FXL6408_REG_IO_DIR), + .ngpio_per_reg = FXL6408_NGPIO, + }; + + gpio_config.regmap = devm_regmap_init_i2c(client, ®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 <emanuele.ghidoli@toradex.com>"); +MODULE_DESCRIPTION("FXL6408 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-hisi.c b/drivers/gpio/gpio-hisi.c index 55bd69043bf4..29a03de37fd8 100644 --- a/drivers/gpio/gpio-hisi.c +++ b/drivers/gpio/gpio-hisi.c @@ -37,7 +37,6 @@ struct hisi_gpio { struct device *dev; void __iomem *reg_base; unsigned int line_num; - struct irq_chip irq_chip; int irq; }; @@ -100,12 +99,14 @@ static void hisi_gpio_irq_set_mask(struct irq_data *d) struct gpio_chip *chip = irq_data_get_irq_chip_data(d); hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_SET_WX, BIT(irqd_to_hwirq(d))); + gpiochip_disable_irq(chip, irqd_to_hwirq(d)); } static void hisi_gpio_irq_clr_mask(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + gpiochip_enable_irq(chip, irqd_to_hwirq(d)); hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_CLR_WX, BIT(irqd_to_hwirq(d))); } @@ -191,20 +192,24 @@ static void hisi_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(irq_c, desc); } +static const struct irq_chip hisi_gpio_irq_chip = { + .name = "HISI-GPIO", + .irq_ack = hisi_gpio_set_ack, + .irq_mask = hisi_gpio_irq_set_mask, + .irq_unmask = hisi_gpio_irq_clr_mask, + .irq_set_type = hisi_gpio_irq_set_type, + .irq_enable = hisi_gpio_irq_enable, + .irq_disable = hisi_gpio_irq_disable, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static void hisi_gpio_init_irq(struct hisi_gpio *hisi_gpio) { struct gpio_chip *chip = &hisi_gpio->chip; struct gpio_irq_chip *girq_chip = &chip->irq; - /* Set hooks for irq_chip */ - hisi_gpio->irq_chip.irq_ack = hisi_gpio_set_ack; - hisi_gpio->irq_chip.irq_mask = hisi_gpio_irq_set_mask; - hisi_gpio->irq_chip.irq_unmask = hisi_gpio_irq_clr_mask; - hisi_gpio->irq_chip.irq_set_type = hisi_gpio_irq_set_type; - hisi_gpio->irq_chip.irq_enable = hisi_gpio_irq_enable; - hisi_gpio->irq_chip.irq_disable = hisi_gpio_irq_disable; - - girq_chip->chip = &hisi_gpio->irq_chip; + gpio_irq_chip_set_chip(girq_chip, &hisi_gpio_irq_chip); girq_chip->default_type = IRQ_TYPE_NONE; girq_chip->num_parents = 1; girq_chip->parents = &hisi_gpio->irq; diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c index 4e13e937f832..c208ac1c54a6 100644 --- a/drivers/gpio/gpio-hlwd.c +++ b/drivers/gpio/gpio-hlwd.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/seq_file.h> #include <linux/slab.h> /* @@ -48,7 +49,7 @@ struct hlwd_gpio { struct gpio_chip gpioc; - struct irq_chip irqc; + struct device *dev; void __iomem *regs; int irq; u32 edge_emulation; @@ -123,6 +124,7 @@ static void hlwd_gpio_irq_mask(struct irq_data *data) mask &= ~BIT(data->hwirq); iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK); raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); + gpiochip_disable_irq(&hlwd->gpioc, irqd_to_hwirq(data)); } static void hlwd_gpio_irq_unmask(struct irq_data *data) @@ -132,6 +134,7 @@ static void hlwd_gpio_irq_unmask(struct irq_data *data) unsigned long flags; u32 mask; + gpiochip_enable_irq(&hlwd->gpioc, irqd_to_hwirq(data)); raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK); mask |= BIT(data->hwirq); @@ -202,6 +205,24 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) return 0; } +static void hlwd_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p) +{ + struct hlwd_gpio *hlwd = + gpiochip_get_data(irq_data_get_irq_chip_data(data)); + + seq_printf(p, dev_name(hlwd->dev)); +} + +static const struct irq_chip hlwd_gpio_irq_chip = { + .irq_mask = hlwd_gpio_irq_mask, + .irq_unmask = hlwd_gpio_irq_unmask, + .irq_enable = hlwd_gpio_irq_enable, + .irq_set_type = hlwd_gpio_irq_set_type, + .irq_print_chip = hlwd_gpio_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int hlwd_gpio_probe(struct platform_device *pdev) { struct hlwd_gpio *hlwd; @@ -216,6 +237,8 @@ static int hlwd_gpio_probe(struct platform_device *pdev) if (IS_ERR(hlwd->regs)) return PTR_ERR(hlwd->regs); + hlwd->dev = &pdev->dev; + /* * Claim all GPIOs using the OWNER register. This will not work on * systems where the AHBPROT memory firewall hasn't been configured to @@ -259,14 +282,8 @@ static int hlwd_gpio_probe(struct platform_device *pdev) return hlwd->irq; } - hlwd->irqc.name = dev_name(&pdev->dev); - hlwd->irqc.irq_mask = hlwd_gpio_irq_mask; - hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask; - hlwd->irqc.irq_enable = hlwd_gpio_irq_enable; - hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type; - girq = &hlwd->gpioc.irq; - girq->chip = &hlwd->irqc; + gpio_irq_chip_set_chip(girq, &hlwd_gpio_irq_chip); girq->parent_handler = hlwd_gpio_irqhandler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, 1, diff --git a/drivers/gpio/gpio-idt3243x.c b/drivers/gpio/gpio-idt3243x.c index 1cafdf46f875..00f547d26254 100644 --- a/drivers/gpio/gpio-idt3243x.c +++ b/drivers/gpio/gpio-idt3243x.c @@ -92,6 +92,8 @@ static void idt_gpio_mask(struct irq_data *d) writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK); raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void idt_gpio_unmask(struct irq_data *d) @@ -100,6 +102,7 @@ static void idt_gpio_unmask(struct irq_data *d) struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); unsigned long flags; + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); raw_spin_lock_irqsave(&gc->bgpio_lock, flags); ctrl->mask_cache &= ~BIT(d->hwirq); @@ -119,12 +122,14 @@ static int idt_gpio_irq_init_hw(struct gpio_chip *gc) return 0; } -static struct irq_chip idt_gpio_irqchip = { +static const struct irq_chip idt_gpio_irqchip = { .name = "IDTGPIO", .irq_mask = idt_gpio_mask, .irq_ack = idt_gpio_ack, .irq_unmask = idt_gpio_unmask, - .irq_set_type = idt_gpio_irq_set_type + .irq_set_type = idt_gpio_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static int idt_gpio_probe(struct platform_device *pdev) @@ -168,7 +173,7 @@ static int idt_gpio_probe(struct platform_device *pdev) return parent_irq; girq = &ctrl->gc.irq; - girq->chip = &idt_gpio_irqchip; + gpio_irq_chip_set_chip(girq, &idt_gpio_irqchip); girq->init_hw = idt_gpio_irq_init_hw; girq->parent_handler = idt_gpio_dispatch; girq->num_parents = 1; diff --git a/drivers/gpio/gpio-imx-scu.c b/drivers/gpio/gpio-imx-scu.c index 17be21b8f3b7..e190bde5397d 100644 --- a/drivers/gpio/gpio-imx-scu.c +++ b/drivers/gpio/gpio-imx-scu.c @@ -136,4 +136,3 @@ subsys_initcall_sync(_imx_scu_gpio_init); MODULE_AUTHOR("Shenwei Wang <shenwei.wang@nxp.com>"); MODULE_DESCRIPTION("NXP GPIO over IMX SCU API"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c new file mode 100644 index 000000000000..06213bbfabdd --- /dev/null +++ b/drivers/gpio/gpio-loongson-64bit.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Loongson GPIO Support + * + * Copyright (C) 2022-2023 Loongson Technology Corporation Limited + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <linux/gpio/driver.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> +#include <asm/types.h> + +enum loongson_gpio_mode { + BIT_CTRL_MODE, + BYTE_CTRL_MODE, +}; + +struct loongson_gpio_chip_data { + const char *label; + enum loongson_gpio_mode mode; + unsigned int conf_offset; + unsigned int out_offset; + unsigned int in_offset; +}; + +struct loongson_gpio_chip { + struct gpio_chip chip; + struct fwnode_handle *fwnode; + spinlock_t lock; + void __iomem *reg_base; + const struct loongson_gpio_chip_data *chip_data; +}; + +static inline struct loongson_gpio_chip *to_loongson_gpio_chip(struct gpio_chip *chip) +{ + return container_of(chip, struct loongson_gpio_chip, chip); +} + +static inline void loongson_commit_direction(struct loongson_gpio_chip *lgpio, unsigned int pin, + int input) +{ + u8 bval = input ? 1 : 0; + + writeb(bval, lgpio->reg_base + lgpio->chip_data->conf_offset + pin); +} + +static void loongson_commit_level(struct loongson_gpio_chip *lgpio, unsigned int pin, int high) +{ + u8 bval = high ? 1 : 0; + + writeb(bval, lgpio->reg_base + lgpio->chip_data->out_offset + pin); +} + +static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) +{ + unsigned long flags; + struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); + + spin_lock_irqsave(&lgpio->lock, flags); + loongson_commit_direction(lgpio, pin, 1); + spin_unlock_irqrestore(&lgpio->lock, flags); + + return 0; +} + +static int loongson_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, int value) +{ + unsigned long flags; + struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); + + spin_lock_irqsave(&lgpio->lock, flags); + loongson_commit_level(lgpio, pin, value); + loongson_commit_direction(lgpio, pin, 0); + spin_unlock_irqrestore(&lgpio->lock, flags); + + return 0; +} + +static int loongson_gpio_get(struct gpio_chip *chip, unsigned int pin) +{ + u8 bval; + int val; + struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); + + bval = readb(lgpio->reg_base + lgpio->chip_data->in_offset + pin); + val = bval & 1; + + return val; +} + +static int loongson_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) +{ + u8 bval; + struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); + + bval = readb(lgpio->reg_base + lgpio->chip_data->conf_offset + pin); + if (bval & 1) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + +static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) +{ + unsigned long flags; + struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); + + spin_lock_irqsave(&lgpio->lock, flags); + loongson_commit_level(lgpio, pin, value); + spin_unlock_irqrestore(&lgpio->lock, flags); +} + +static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct platform_device *pdev = to_platform_device(chip->parent); + + return platform_get_irq(pdev, offset); +} + +static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgpio, + struct device_node *np, void __iomem *reg_base) +{ + int ret; + u32 ngpios; + + lgpio->reg_base = reg_base; + + if (lgpio->chip_data->mode == BIT_CTRL_MODE) { + ret = bgpio_init(&lgpio->chip, dev, 8, + lgpio->reg_base + lgpio->chip_data->in_offset, + lgpio->reg_base + lgpio->chip_data->out_offset, + NULL, NULL, + lgpio->reg_base + lgpio->chip_data->conf_offset, + 0); + if (ret) { + dev_err(dev, "unable to init generic GPIO\n"); + return ret; + } + } else { + lgpio->chip.direction_input = loongson_gpio_direction_input; + lgpio->chip.get = loongson_gpio_get; + lgpio->chip.get_direction = loongson_gpio_get_direction; + lgpio->chip.direction_output = loongson_gpio_direction_output; + lgpio->chip.set = loongson_gpio_set; + lgpio->chip.parent = dev; + spin_lock_init(&lgpio->lock); + } + + device_property_read_u32(dev, "ngpios", &ngpios); + + lgpio->chip.can_sleep = 0; + lgpio->chip.ngpio = ngpios; + lgpio->chip.label = lgpio->chip_data->label; + lgpio->chip.to_irq = loongson_gpio_to_irq; + + return devm_gpiochip_add_data(dev, &lgpio->chip, lgpio); +} + +static int loongson_gpio_probe(struct platform_device *pdev) +{ + void __iomem *reg_base; + struct loongson_gpio_chip *lgpio; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + + lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL); + if (!lgpio) + return -ENOMEM; + + lgpio->chip_data = device_get_match_data(dev); + + reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + + return loongson_gpio_init(dev, lgpio, np, reg_base); +} + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { + .label = "ls2k_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0x20, + .out_offset = 0x10, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { + .label = "ls7a_gpio", + .mode = BYTE_CTRL_MODE, + .conf_offset = 0x800, + .in_offset = 0xa00, + .out_offset = 0x900, +}; + +static const struct of_device_id loongson_gpio_of_match[] = { + { + .compatible = "loongson,ls2k-gpio", + .data = &loongson_gpio_ls2k_data, + }, + { + .compatible = "loongson,ls7a-gpio", + .data = &loongson_gpio_ls7a_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, loongson_gpio_of_match); + +static const struct acpi_device_id loongson_gpio_acpi_match[] = { + { + .id = "LOON0002", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data, + }, + {} +}; +MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match); + +static struct platform_driver loongson_gpio_driver = { + .driver = { + .name = "loongson-gpio", + .of_match_table = loongson_gpio_of_match, + .acpi_match_table = loongson_gpio_acpi_match, + }, + .probe = loongson_gpio_probe, +}; + +static int __init loongson_gpio_setup(void) +{ + return platform_driver_register(&loongson_gpio_driver); +} +postcore_initcall(loongson_gpio_setup); + +MODULE_DESCRIPTION("Loongson gpio driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-loongson1.c b/drivers/gpio/gpio-loongson1.c index 5d90b3bc5a25..6ca3b969db4d 100644 --- a/drivers/gpio/gpio-loongson1.c +++ b/drivers/gpio/gpio-loongson1.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO Driver for Loongson 1 SoC * - * Copyright (C) 2015-2016 Zhang, Keguang <keguang.zhang@gmail.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. + * Copyright (C) 2015-2023 Keguang Zhang <keguang.zhang@gmail.com> */ #include <linux/module.h> @@ -19,15 +16,19 @@ #define GPIO_DATA 0x20 #define GPIO_OUTPUT 0x30 -static void __iomem *gpio_reg_base; +struct ls1x_gpio_chip { + struct gpio_chip gc; + void __iomem *reg_base; +}; static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset) { + struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc); unsigned long flags; raw_spin_lock_irqsave(&gc->bgpio_lock, flags); - __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | BIT(offset), - gpio_reg_base + GPIO_CFG); + __raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) | BIT(offset), + ls1x_gc->reg_base + GPIO_CFG); raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); return 0; @@ -35,61 +36,75 @@ static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset) static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset) { + struct ls1x_gpio_chip *ls1x_gc = gpiochip_get_data(gc); unsigned long flags; raw_spin_lock_irqsave(&gc->bgpio_lock, flags); - __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~BIT(offset), - gpio_reg_base + GPIO_CFG); + __raw_writel(__raw_readl(ls1x_gc->reg_base + GPIO_CFG) & ~BIT(offset), + ls1x_gc->reg_base + GPIO_CFG); raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static int ls1x_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct gpio_chip *gc; + struct ls1x_gpio_chip *ls1x_gc; int ret; - gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); - if (!gc) + ls1x_gc = devm_kzalloc(dev, sizeof(*ls1x_gc), GFP_KERNEL); + if (!ls1x_gc) return -ENOMEM; - gpio_reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(gpio_reg_base)) - return PTR_ERR(gpio_reg_base); + ls1x_gc->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ls1x_gc->reg_base)) + return PTR_ERR(ls1x_gc->reg_base); - ret = bgpio_init(gc, dev, 4, gpio_reg_base + GPIO_DATA, - gpio_reg_base + GPIO_OUTPUT, NULL, - NULL, gpio_reg_base + GPIO_DIR, 0); + ret = bgpio_init(&ls1x_gc->gc, dev, 4, ls1x_gc->reg_base + GPIO_DATA, + ls1x_gc->reg_base + GPIO_OUTPUT, NULL, + NULL, ls1x_gc->reg_base + GPIO_DIR, 0); if (ret) goto err; - gc->owner = THIS_MODULE; - gc->request = ls1x_gpio_request; - gc->free = ls1x_gpio_free; - gc->base = pdev->id * 32; + ls1x_gc->gc.owner = THIS_MODULE; + ls1x_gc->gc.request = ls1x_gpio_request; + ls1x_gc->gc.free = ls1x_gpio_free; + /* + * Clear ngpio to let gpiolib get the correct number + * by reading ngpios property + */ + ls1x_gc->gc.ngpio = 0; - ret = devm_gpiochip_add_data(dev, gc, NULL); + ret = devm_gpiochip_add_data(dev, &ls1x_gc->gc, ls1x_gc); if (ret) goto err; - platform_set_drvdata(pdev, gc); - dev_info(dev, "Loongson1 GPIO driver registered\n"); + platform_set_drvdata(pdev, ls1x_gc); + + dev_info(dev, "GPIO controller registered with %d pins\n", + ls1x_gc->gc.ngpio); return 0; err: - dev_err(dev, "failed to register GPIO device\n"); + dev_err(dev, "failed to register GPIO controller\n"); return ret; } +static const struct of_device_id ls1x_gpio_dt_ids[] = { + { .compatible = "loongson,ls1x-gpio" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ls1x_gpio_dt_ids); + static struct platform_driver ls1x_gpio_driver = { .probe = ls1x_gpio_probe, .driver = { .name = "ls1x-gpio", + .of_match_table = ls1x_gpio_dt_ids, }, }; module_platform_driver(ls1x_gpio_driver); -MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>"); +MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>"); MODULE_DESCRIPTION("Loongson1 GPIO driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 68e982cdee73..7f2fde191755 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -351,6 +351,7 @@ static void max732x_irq_mask(struct irq_data *d) struct max732x_chip *chip = gpiochip_get_data(gc); chip->irq_mask_cur &= ~(1 << d->hwirq); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void max732x_irq_unmask(struct irq_data *d) @@ -358,6 +359,7 @@ static void max732x_irq_unmask(struct irq_data *d) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct max732x_chip *chip = gpiochip_get_data(gc); + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); chip->irq_mask_cur |= 1 << d->hwirq; } @@ -429,7 +431,7 @@ static int max732x_irq_set_wake(struct irq_data *data, unsigned int on) return 0; } -static struct irq_chip max732x_irq_chip = { +static const struct irq_chip max732x_irq_chip = { .name = "max732x", .irq_mask = max732x_irq_mask, .irq_unmask = max732x_irq_unmask, @@ -437,6 +439,8 @@ static struct irq_chip max732x_irq_chip = { .irq_bus_sync_unlock = max732x_irq_bus_sync_unlock, .irq_set_type = max732x_irq_set_type, .irq_set_wake = max732x_irq_set_wake, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static uint8_t max732x_irq_pending(struct max732x_chip *chip) @@ -517,7 +521,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, } girq = &chip->gpio_chip.irq; - girq->chip = &max732x_irq_chip; + gpio_irq_chip_set_chip(girq, &max732x_irq_chip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; diff --git a/drivers/gpio/gpio-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-msc313.c b/drivers/gpio/gpio-msc313.c index b0773e5652fa..036ad2324892 100644 --- a/drivers/gpio/gpio-msc313.c +++ b/drivers/gpio/gpio-msc313.c @@ -532,17 +532,35 @@ static int msc313_gpio_direction_output(struct gpio_chip *chip, unsigned int off return 0; } +static void msc313_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + irq_chip_mask_parent(d); + gpiochip_disable_irq(gc, d->hwirq); +} + +static void msc313_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, d->hwirq); + irq_chip_unmask_parent(d); +} + /* * The interrupt handling happens in the parent interrupt controller, * we don't do anything here. */ -static struct irq_chip msc313_gpio_irqchip = { +static const struct irq_chip msc313_gpio_irqchip = { .name = "GPIO", .irq_eoi = irq_chip_eoi_parent, - .irq_mask = irq_chip_mask_parent, - .irq_unmask = irq_chip_unmask_parent, + .irq_mask = msc313_gpio_irq_mask, + .irq_unmask = msc313_gpio_irq_unmask, .irq_set_type = irq_chip_set_type_parent, .irq_set_affinity = irq_chip_set_affinity_parent, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; /* @@ -644,7 +662,7 @@ static int msc313_gpio_probe(struct platform_device *pdev) gpiochip->names = gpio->gpio_data->names; gpioirqchip = &gpiochip->irq; - gpioirqchip->chip = &msc313_gpio_irqchip; + gpio_irq_chip_set_chip(gpioirqchip, &msc313_gpio_irqchip); gpioirqchip->fwnode = of_node_to_fwnode(dev->of_node); gpioirqchip->parent_domain = parent_domain; gpioirqchip->child_to_parent_hwirq = msc313e_gpio_child_to_parent_hwirq; diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 7f59e5d936c2..390e619a2831 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -364,4 +364,3 @@ MODULE_AUTHOR("Freescale Semiconductor, " "Daniel Mack <danielncaiaq.de>, " "Juergen Beisert <kernel@pengutronix.de>"); MODULE_DESCRIPTION("Freescale MXS GPIO"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f5f3d4b22452..a08be5bf6808 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/seq_file.h> #include <linux/syscore_ops.h> #include <linux/err.h> #include <linux/clk.h> @@ -47,6 +48,7 @@ struct gpio_regs { struct gpio_bank { void __iomem *base; const struct omap_gpio_reg_offs *regs; + struct device *dev; int irq; u32 non_wakeup_gpios; @@ -681,6 +683,7 @@ static void omap_gpio_mask_irq(struct irq_data *d) omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); omap_set_gpio_irqenable(bank, offset, 0); raw_spin_unlock_irqrestore(&bank->lock, flags); + gpiochip_disable_irq(&bank->chip, offset); } static void omap_gpio_unmask_irq(struct irq_data *d) @@ -690,6 +693,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d) u32 trigger = irqd_get_trigger_type(d); unsigned long flags; + gpiochip_enable_irq(&bank->chip, offset); raw_spin_lock_irqsave(&bank->lock, flags); omap_set_gpio_irqenable(bank, offset, 1); @@ -708,6 +712,40 @@ static void omap_gpio_unmask_irq(struct irq_data *d) raw_spin_unlock_irqrestore(&bank->lock, flags); } +static void omap_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_bank *bank = omap_irq_data_get_bank(d); + + seq_printf(p, dev_name(bank->dev)); +} + +static const struct irq_chip omap_gpio_irq_chip = { + .irq_startup = omap_gpio_irq_startup, + .irq_shutdown = omap_gpio_irq_shutdown, + .irq_mask = omap_gpio_mask_irq, + .irq_unmask = omap_gpio_unmask_irq, + .irq_set_type = omap_gpio_irq_type, + .irq_set_wake = omap_gpio_wake_enable, + .irq_bus_lock = omap_gpio_irq_bus_lock, + .irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, + .irq_print_chip = omap_gpio_irq_print_chip, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static const struct irq_chip omap_gpio_irq_chip_nowake = { + .irq_startup = omap_gpio_irq_startup, + .irq_shutdown = omap_gpio_irq_shutdown, + .irq_mask = omap_gpio_mask_irq, + .irq_unmask = omap_gpio_unmask_irq, + .irq_set_type = omap_gpio_irq_type, + .irq_bus_lock = omap_gpio_irq_bus_lock, + .irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, + .irq_print_chip = omap_gpio_irq_print_chip, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + /*---------------------------------------------------------------------*/ static int omap_mpuio_suspend_noirq(struct device *dev) @@ -986,13 +1024,11 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) writel_relaxed(0, base + bank->regs->ctrl); } -static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc, - struct device *pm_dev) +static int omap_gpio_chip_init(struct gpio_bank *bank, struct device *pm_dev) { struct gpio_irq_chip *irq; static int gpio; const char *label; - int irq_base = 0; int ret; /* @@ -1024,30 +1060,16 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc, } bank->chip.ngpio = bank->width; -#ifdef CONFIG_ARCH_OMAP1 - /* - * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop - * irq_alloc_descs() since a base IRQ offset will no longer be needed. - */ - irq_base = devm_irq_alloc_descs(bank->chip.parent, - -1, 0, bank->width, 0); - if (irq_base < 0) { - dev_err(bank->chip.parent, "Couldn't allocate IRQ numbers\n"); - return -ENODEV; - } -#endif - + irq = &bank->chip.irq; /* MPUIO is a bit different, reading IRQ status clears it */ if (bank->is_mpuio && !bank->regs->wkup_en) - irqc->irq_set_wake = NULL; - - irq = &bank->chip.irq; - irq->chip = irqc; + gpio_irq_chip_set_chip(irq, &omap_gpio_irq_chip_nowake); + else + gpio_irq_chip_set_chip(irq, &omap_gpio_irq_chip); irq->handler = handle_bad_irq; irq->default_type = IRQ_TYPE_NONE; irq->num_parents = 1; irq->parents = &bank->irq; - irq->first = irq_base; ret = gpiochip_add_data(&bank->chip, bank); if (ret) @@ -1376,7 +1398,6 @@ static int omap_gpio_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; const struct omap_gpio_platform_data *pdata; struct gpio_bank *bank; - struct irq_chip *irqc; int ret; pdata = device_get_match_data(dev); @@ -1389,21 +1410,7 @@ static int omap_gpio_probe(struct platform_device *pdev) if (!bank) return -ENOMEM; - irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL); - if (!irqc) - return -ENOMEM; - - irqc->irq_startup = omap_gpio_irq_startup, - irqc->irq_shutdown = omap_gpio_irq_shutdown, - irqc->irq_ack = dummy_irq_chip.irq_ack, - irqc->irq_mask = omap_gpio_mask_irq, - irqc->irq_unmask = omap_gpio_unmask_irq, - irqc->irq_set_type = omap_gpio_irq_type, - irqc->irq_set_wake = omap_gpio_wake_enable, - irqc->irq_bus_lock = omap_gpio_irq_bus_lock, - irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, - irqc->name = dev_name(&pdev->dev); - irqc->flags = IRQCHIP_MASK_ON_SUSPEND; + bank->dev = dev; bank->irq = platform_get_irq(pdev, 0); if (bank->irq <= 0) { @@ -1467,7 +1474,7 @@ static int omap_gpio_probe(struct platform_device *pdev) omap_gpio_mod_init(bank); - ret = omap_gpio_chip_init(bank, irqc, dev); + ret = omap_gpio_chip_init(bank, dev); if (ret) { pm_runtime_put_sync(dev); pm_runtime_disable(dev); diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c index a86ce748384b..6726c32e31e6 100644 --- a/drivers/gpio/gpio-pci-idio-16.c +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -107,6 +107,8 @@ static void idio_16_irq_mask(struct irq_data *data) raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } + + gpiochip_disable_irq(chip, irqd_to_hwirq(data)); } static void idio_16_irq_unmask(struct irq_data *data) @@ -117,6 +119,8 @@ static void idio_16_irq_unmask(struct irq_data *data) const unsigned long prev_irq_mask = idio16gpio->irq_mask; unsigned long flags; + gpiochip_enable_irq(chip, irqd_to_hwirq(data)); + idio16gpio->irq_mask |= mask; if (!prev_irq_mask) { @@ -138,12 +142,14 @@ static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type) return 0; } -static struct irq_chip idio_16_irqchip = { +static const struct irq_chip idio_16_irqchip = { .name = "pci-idio-16", .irq_ack = idio_16_irq_ack, .irq_mask = idio_16_irq_mask, .irq_unmask = idio_16_irq_unmask, - .irq_set_type = idio_16_irq_set_type + .irq_set_type = idio_16_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) @@ -242,7 +248,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) idio_16_state_init(&idio16gpio->state); girq = &idio16gpio->chip.irq; - girq->chip = &idio_16_irqchip; + gpio_irq_chip_set_chip(girq, &idio_16_irqchip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c index 8a9b98fa418f..463c0613abb9 100644 --- a/drivers/gpio/gpio-pcie-idio-24.c +++ b/drivers/gpio/gpio-pcie-idio-24.c @@ -3,15 +3,6 @@ * GPIO driver for the ACCES PCIe-IDIO-24 family * Copyright (C) 2018 William Breathitt Gray * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * * This driver supports the following ACCES devices: PCIe-IDIO-24, * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12. */ @@ -396,6 +387,8 @@ static void idio_24_irq_mask(struct irq_data *data) } raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); + + gpiochip_disable_irq(chip, irqd_to_hwirq(data)); } static void idio_24_irq_unmask(struct irq_data *data) @@ -408,6 +401,8 @@ static void idio_24_irq_unmask(struct irq_data *data) const unsigned long bank_offset = bit_offset / 8; unsigned char cos_enable_state; + gpiochip_enable_irq(chip, irqd_to_hwirq(data)); + raw_spin_lock_irqsave(&idio24gpio->lock, flags); prev_irq_mask = idio24gpio->irq_mask >> bank_offset * 8; @@ -437,12 +432,14 @@ static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type) return 0; } -static struct irq_chip idio_24_irqchip = { +static const struct irq_chip idio_24_irqchip = { .name = "pcie-idio-24", .irq_ack = idio_24_irq_ack, .irq_mask = idio_24_irq_mask, .irq_unmask = idio_24_irq_unmask, - .irq_set_type = idio_24_irq_set_type + .irq_set_type = idio_24_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static irqreturn_t idio_24_irq_handler(int irq, void *dev_id) @@ -535,7 +532,7 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple; girq = &idio24gpio->chip.irq; - girq->chip = &idio_24_irqchip; + gpio_irq_chip_set_chip(girq, &idio_24_irqchip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 1198ab0305d0..a1630ed4b741 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -171,11 +171,6 @@ static inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c, return chip_to_pxachip(c)->banks + gpio / 32; } -static inline int gpio_is_pxa_type(int type) -{ - return (type & MMP_GPIO) == 0; -} - static inline int gpio_is_mmp_type(int type) { return (type & MMP_GPIO) != 0; diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c index 3c414e0005fc..ecb0d3800dfe 100644 --- a/drivers/gpio/gpio-raspberrypi-exp.c +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -234,7 +234,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev) return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio); } -static const struct of_device_id rpi_exp_gpio_ids[] = { +static const struct of_device_id rpi_exp_gpio_ids[] __maybe_unused = { { .compatible = "raspberrypi,firmware-gpio" }, { } }; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 5b117f3bd322..2525adb52f4f 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -663,7 +663,7 @@ static struct platform_driver gpio_rcar_device_driver = { .driver = { .name = "gpio_rcar", .pm = &gpio_rcar_pm_ops, - .of_match_table = of_match_ptr(gpio_rcar_of_table), + .of_match_table = gpio_rcar_of_table, } }; diff --git a/drivers/gpio/gpio-rda.c b/drivers/gpio/gpio-rda.c index 62ba18b3a602..cb2f63eee2aa 100644 --- a/drivers/gpio/gpio-rda.c +++ b/drivers/gpio/gpio-rda.c @@ -38,7 +38,6 @@ struct rda_gpio { struct gpio_chip chip; void __iomem *base; spinlock_t lock; - struct irq_chip irq_chip; int irq; }; @@ -74,6 +73,7 @@ static void rda_gpio_irq_mask(struct irq_data *data) value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); + gpiochip_disable_irq(chip, offset); } static void rda_gpio_irq_ack(struct irq_data *data) @@ -154,6 +154,7 @@ static void rda_gpio_irq_unmask(struct irq_data *data) u32 offset = irqd_to_hwirq(data); u32 trigger = irqd_get_trigger_type(data); + gpiochip_enable_irq(chip, offset); rda_gpio_set_irq(chip, offset, trigger); } @@ -195,6 +196,16 @@ static void rda_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(ic, desc); } +static const struct irq_chip rda_gpio_irq_chip = { + .name = "rda-gpio", + .irq_ack = rda_gpio_irq_ack, + .irq_mask = rda_gpio_irq_mask, + .irq_unmask = rda_gpio_irq_unmask, + .irq_set_type = rda_gpio_irq_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int rda_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -241,15 +252,8 @@ static int rda_gpio_probe(struct platform_device *pdev) rda_gpio->chip.base = -1; if (rda_gpio->irq >= 0) { - rda_gpio->irq_chip.name = "rda-gpio", - rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack, - rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask, - rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask, - rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type, - rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE, - girq = &rda_gpio->chip.irq; - girq->chip = &rda_gpio->irq_chip; + gpio_irq_chip_set_chip(girq, &rda_gpio_irq_chip); girq->handler = handle_bad_irq; girq->default_type = IRQ_TYPE_NONE; girq->parent_handler = rda_gpio_irq_handler; @@ -286,4 +290,3 @@ module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe); MODULE_DESCRIPTION("RDA Micro GPIO driver"); MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-sama5d2-piobu.c b/drivers/gpio/gpio-sama5d2-piobu.c index 3e95da717fc9..767c33ae3213 100644 --- a/drivers/gpio/gpio-sama5d2-piobu.c +++ b/drivers/gpio/gpio-sama5d2-piobu.c @@ -236,7 +236,7 @@ MODULE_DEVICE_TABLE(of, sama5d2_piobu_ids); static struct platform_driver sama5d2_piobu_driver = { .driver = { .name = "sama5d2-piobu", - .of_match_table = of_match_ptr(sama5d2_piobu_ids) + .of_match_table = sama5d2_piobu_ids, }, .probe = sama5d2_piobu_probe, }; diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c index bc5660f61c57..98939cd4a71e 100644 --- a/drivers/gpio/gpio-sifive.c +++ b/drivers/gpio/gpio-sifive.c @@ -270,7 +270,7 @@ static struct platform_driver sifive_gpio_driver = { .probe = sifive_gpio_probe, .driver = { .name = "sifive_gpio", - .of_match_table = of_match_ptr(sifive_gpio_match), + .of_match_table = sifive_gpio_match, }, }; builtin_platform_driver(sifive_gpio_driver) diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index e5dfd636c63c..a1c8702f362c 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -953,9 +953,9 @@ static void gpio_sim_device_deactivate_unlocked(struct gpio_sim_device *dev) swnode = dev_fwnode(&dev->pdev->dev); platform_device_unregister(dev->pdev); + gpio_sim_remove_hogs(dev); gpio_sim_remove_swnode_recursive(swnode); dev->pdev = NULL; - gpio_sim_remove_hogs(dev); } static ssize_t diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c index f8c5e9fc4bac..051bc99bdfb2 100644 --- a/drivers/gpio/gpio-siox.c +++ b/drivers/gpio/gpio-siox.c @@ -10,7 +10,6 @@ struct gpio_siox_ddata { struct gpio_chip gchip; - struct irq_chip ichip; struct mutex lock; u8 setdata[1]; u8 getdata[3]; @@ -97,9 +96,8 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[]) static void gpio_siox_irq_ack(struct irq_data *d) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct gpio_siox_ddata *ddata = - container_of(ic, struct gpio_siox_ddata, ichip); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_siox_ddata *ddata = gpiochip_get_data(gc); raw_spin_lock(&ddata->irqlock); ddata->irq_status &= ~(1 << d->hwirq); @@ -108,21 +106,21 @@ static void gpio_siox_irq_ack(struct irq_data *d) static void gpio_siox_irq_mask(struct irq_data *d) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct gpio_siox_ddata *ddata = - container_of(ic, struct gpio_siox_ddata, ichip); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_siox_ddata *ddata = gpiochip_get_data(gc); raw_spin_lock(&ddata->irqlock); ddata->irq_enable &= ~(1 << d->hwirq); raw_spin_unlock(&ddata->irqlock); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void gpio_siox_irq_unmask(struct irq_data *d) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct gpio_siox_ddata *ddata = - container_of(ic, struct gpio_siox_ddata, ichip); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_siox_ddata *ddata = gpiochip_get_data(gc); + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); raw_spin_lock(&ddata->irqlock); ddata->irq_enable |= 1 << d->hwirq; raw_spin_unlock(&ddata->irqlock); @@ -130,9 +128,8 @@ static void gpio_siox_irq_unmask(struct irq_data *d) static int gpio_siox_irq_set_type(struct irq_data *d, u32 type) { - struct irq_chip *ic = irq_data_get_irq_chip(d); - struct gpio_siox_ddata *ddata = - container_of(ic, struct gpio_siox_ddata, ichip); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_siox_ddata *ddata = gpiochip_get_data(gc); raw_spin_lock(&ddata->irqlock); ddata->irq_type[d->hwirq] = type; @@ -143,8 +140,7 @@ static int gpio_siox_irq_set_type(struct irq_data *d, u32 type) static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset) { - struct gpio_siox_ddata *ddata = - container_of(chip, struct gpio_siox_ddata, gchip); + struct gpio_siox_ddata *ddata = gpiochip_get_data(chip); int ret; mutex_lock(&ddata->lock); @@ -167,8 +163,7 @@ static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset) static void gpio_siox_set(struct gpio_chip *chip, unsigned int offset, int value) { - struct gpio_siox_ddata *ddata = - container_of(chip, struct gpio_siox_ddata, gchip); + struct gpio_siox_ddata *ddata = gpiochip_get_data(chip); u8 mask = 1 << (19 - offset); mutex_lock(&ddata->lock); @@ -208,11 +203,22 @@ static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset) return GPIO_LINE_DIRECTION_OUT; } +static const struct irq_chip gpio_siox_irq_chip = { + .name = "siox-gpio", + .irq_ack = gpio_siox_irq_ack, + .irq_mask = gpio_siox_irq_mask, + .irq_unmask = gpio_siox_irq_unmask, + .irq_set_type = gpio_siox_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int gpio_siox_probe(struct siox_device *sdevice) { struct gpio_siox_ddata *ddata; struct gpio_irq_chip *girq; struct device *dev = &sdevice->dev; + struct gpio_chip *gc; int ret; ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); @@ -224,30 +230,25 @@ static int gpio_siox_probe(struct siox_device *sdevice) mutex_init(&ddata->lock); raw_spin_lock_init(&ddata->irqlock); - ddata->gchip.base = -1; - ddata->gchip.can_sleep = 1; - ddata->gchip.parent = dev; - ddata->gchip.owner = THIS_MODULE; - ddata->gchip.get = gpio_siox_get; - ddata->gchip.set = gpio_siox_set; - ddata->gchip.direction_input = gpio_siox_direction_input; - ddata->gchip.direction_output = gpio_siox_direction_output; - ddata->gchip.get_direction = gpio_siox_get_direction; - ddata->gchip.ngpio = 20; - - ddata->ichip.name = "siox-gpio"; - ddata->ichip.irq_ack = gpio_siox_irq_ack; - ddata->ichip.irq_mask = gpio_siox_irq_mask; - ddata->ichip.irq_unmask = gpio_siox_irq_unmask; - ddata->ichip.irq_set_type = gpio_siox_irq_set_type; - - girq = &ddata->gchip.irq; - girq->chip = &ddata->ichip; + gc = &ddata->gchip; + gc->base = -1; + gc->can_sleep = 1; + gc->parent = dev; + gc->owner = THIS_MODULE; + gc->get = gpio_siox_get; + gc->set = gpio_siox_set; + gc->direction_input = gpio_siox_direction_input; + gc->direction_output = gpio_siox_direction_output; + gc->get_direction = gpio_siox_get_direction; + gc->ngpio = 20; + + girq = &gc->irq; + gpio_irq_chip_set_chip(girq, &gpio_siox_irq_chip); girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; girq->threaded = true; - ret = devm_gpiochip_add_data(dev, &ddata->gchip, NULL); + ret = devm_gpiochip_add_data(dev, gc, ddata); if (ret) dev_err(dev, "Failed to register gpio chip (%d)\n", ret); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 0fa4f0a93378..27cc4da53565 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -234,6 +234,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d) int mask = BIT(offset % 8); stmpe_gpio->regs[REG_IE][regoffset] &= ~mask; + gpiochip_disable_irq(gc, offset); } static void stmpe_gpio_irq_unmask(struct irq_data *d) @@ -244,6 +245,7 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d) int regoffset = offset / 8; int mask = BIT(offset % 8); + gpiochip_enable_irq(gc, offset); stmpe_gpio->regs[REG_IE][regoffset] |= mask; } @@ -357,13 +359,15 @@ static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc) } } -static struct irq_chip stmpe_gpio_irq_chip = { +static const struct irq_chip stmpe_gpio_irq_chip = { .name = "stmpe-gpio", .irq_bus_lock = stmpe_gpio_irq_lock, .irq_bus_sync_unlock = stmpe_gpio_irq_sync_unlock, .irq_mask = stmpe_gpio_irq_mask, .irq_unmask = stmpe_gpio_irq_unmask, .irq_set_type = stmpe_gpio_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; #define MAX_GPIOS 24 @@ -511,7 +515,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) } girq = &stmpe_gpio->chip.irq; - girq->chip = &stmpe_gpio_irq_chip; + gpio_irq_chip_set_chip(girq, &stmpe_gpio_irq_chip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index 0ce1543426a4..4750ea34204c 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -292,7 +292,7 @@ static int xway_stp_probe(struct platform_device *pdev) } /* check which edge trigger we should use, default to a falling edge */ - if (!of_find_property(pdev->dev.of_node, "lantiq,rising", NULL)) + if (!of_property_read_bool(pdev->dev.of_node, "lantiq,rising")) chip->edge = XWAY_STP_FALLING; clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index de6afa3f9716..78f8790168ae 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -167,7 +167,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tb10x_gpio); - if (of_find_property(np, "interrupt-controller", NULL)) { + if (of_property_read_bool(np, "interrupt-controller")) { struct irq_chip_generic *gc; ret = platform_get_irq(pdev, 0); diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index cc62c6e64103..8521c6aacace 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -354,16 +354,22 @@ static int thunderx_gpio_irq_set_type(struct irq_data *d, return IRQ_SET_MASK_OK; } -static void thunderx_gpio_irq_enable(struct irq_data *data) +static void thunderx_gpio_irq_enable(struct irq_data *d) { - irq_chip_enable_parent(data); - thunderx_gpio_irq_unmask(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); + irq_chip_enable_parent(d); + thunderx_gpio_irq_unmask(d); } -static void thunderx_gpio_irq_disable(struct irq_data *data) +static void thunderx_gpio_irq_disable(struct irq_data *d) { - thunderx_gpio_irq_mask(data); - irq_chip_disable_parent(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + thunderx_gpio_irq_mask(d); + irq_chip_disable_parent(d); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } /* @@ -372,7 +378,7 @@ static void thunderx_gpio_irq_disable(struct irq_data *data) * semantics and other acknowledgment tasks associated with the GPIO * mechanism. */ -static struct irq_chip thunderx_gpio_irq_chip = { +static const struct irq_chip thunderx_gpio_irq_chip = { .name = "GPIO", .irq_enable = thunderx_gpio_irq_enable, .irq_disable = thunderx_gpio_irq_disable, @@ -383,8 +389,8 @@ static struct irq_chip thunderx_gpio_irq_chip = { .irq_eoi = irq_chip_eoi_parent, .irq_set_affinity = irq_chip_set_affinity_parent, .irq_set_type = thunderx_gpio_irq_set_type, - - .flags = IRQCHIP_SET_TYPE_MASKED + .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc, @@ -526,7 +532,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, chip->set_multiple = thunderx_gpio_set_multiple; chip->set_config = thunderx_gpio_set_config; girq = &chip->irq; - girq->chip = &thunderx_gpio_irq_chip; + gpio_irq_chip_set_chip(girq, &thunderx_gpio_irq_chip); girq->fwnode = of_node_to_fwnode(dev->of_node); girq->parent_domain = irq_get_irq_data(txgpio->msix_entries[0].vector)->domain; diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c index e739dcea61b2..6f8bd1155db7 100644 --- a/drivers/gpio/gpio-tqmx86.c +++ b/drivers/gpio/gpio-tqmx86.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/seq_file.h> #include <linux/slab.h> #define TQMX86_NGPIO 8 @@ -34,7 +35,6 @@ struct tqmx86_gpio_data { struct gpio_chip chip; - struct irq_chip irq_chip; void __iomem *io_base; int irq; raw_spinlock_t spinlock; @@ -122,6 +122,7 @@ static void tqmx86_gpio_irq_mask(struct irq_data *data) gpiic &= ~mask; tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC); raw_spin_unlock_irqrestore(&gpio->spinlock, flags); + gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(data)); } static void tqmx86_gpio_irq_unmask(struct irq_data *data) @@ -134,6 +135,7 @@ static void tqmx86_gpio_irq_unmask(struct irq_data *data) mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS); + gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(data)); raw_spin_lock_irqsave(&gpio->spinlock, flags); gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC); gpiic &= ~mask; @@ -226,6 +228,22 @@ static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip, clear_bit(3, valid_mask); } +static void tqmx86_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + seq_printf(p, gc->label); +} + +static const struct irq_chip tqmx86_gpio_irq_chip = { + .irq_mask = tqmx86_gpio_irq_mask, + .irq_unmask = tqmx86_gpio_irq_unmask, + .irq_set_type = tqmx86_gpio_irq_set_type, + .irq_print_chip = tqmx86_gpio_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int tqmx86_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -277,14 +295,8 @@ static int tqmx86_gpio_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); if (irq > 0) { - struct irq_chip *irq_chip = &gpio->irq_chip; u8 irq_status; - irq_chip->name = chip->label; - irq_chip->irq_mask = tqmx86_gpio_irq_mask; - irq_chip->irq_unmask = tqmx86_gpio_irq_unmask; - irq_chip->irq_set_type = tqmx86_gpio_irq_set_type; - /* Mask all interrupts */ tqmx86_gpio_write(gpio, 0, TQMX86_GPIIC); @@ -293,7 +305,7 @@ static int tqmx86_gpio_probe(struct platform_device *pdev) tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS); girq = &chip->irq; - girq->chip = irq_chip; + gpio_irq_chip_set_chip(girq, &tqmx86_gpio_irq_chip); girq->parent_handler = tqmx86_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, 1, diff --git a/drivers/gpio/gpio-visconti.c b/drivers/gpio/gpio-visconti.c index 5e108ba9956a..6734e7e1e2a4 100644 --- a/drivers/gpio/gpio-visconti.c +++ b/drivers/gpio/gpio-visconti.c @@ -15,6 +15,7 @@ #include <linux/io.h> #include <linux/of_irq.h> #include <linux/platform_device.h> +#include <linux/seq_file.h> #include <linux/bitops.h> /* register offset */ @@ -31,7 +32,7 @@ struct visconti_gpio { void __iomem *base; spinlock_t lock; /* protect gpio register */ struct gpio_chip gpio_chip; - struct irq_chip irq_chip; + struct device *dev; }; static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type) @@ -119,11 +120,45 @@ static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip, return 0; } +static void visconti_gpio_mask_irq(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + irq_chip_mask_parent(d); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); +} + +static void visconti_gpio_unmask_irq(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); + irq_chip_unmask_parent(d); +} + +static void visconti_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct visconti_gpio *priv = gpiochip_get_data(gc); + + seq_printf(p, dev_name(priv->dev)); +} + +static const struct irq_chip visconti_gpio_irq_chip = { + .irq_mask = visconti_gpio_mask_irq, + .irq_unmask = visconti_gpio_unmask_irq, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_type = visconti_gpio_irq_set_type, + .irq_print_chip = visconti_gpio_irq_print_chip, + .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int visconti_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct visconti_gpio *priv; - struct irq_chip *irq_chip; struct gpio_irq_chip *girq; struct irq_domain *parent; struct device_node *irq_parent; @@ -134,6 +169,7 @@ static int visconti_gpio_probe(struct platform_device *pdev) return -ENOMEM; spin_lock_init(&priv->lock); + priv->dev = dev; priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) @@ -164,16 +200,8 @@ static int visconti_gpio_probe(struct platform_device *pdev) return ret; } - irq_chip = &priv->irq_chip; - irq_chip->name = dev_name(dev); - irq_chip->irq_mask = irq_chip_mask_parent; - irq_chip->irq_unmask = irq_chip_unmask_parent; - irq_chip->irq_eoi = irq_chip_eoi_parent; - irq_chip->irq_set_type = visconti_gpio_irq_set_type; - irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; - girq = &priv->gpio_chip.irq; - girq->chip = irq_chip; + gpio_irq_chip_set_chip(girq, &visconti_gpio_irq_chip); girq->fwnode = of_node_to_fwnode(dev->of_node); girq->parent_domain = parent; girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq; @@ -194,7 +222,7 @@ static struct platform_driver visconti_gpio_driver = { .probe = visconti_gpio_probe, .driver = { .name = "visconti_gpio", - .of_match_table = of_match_ptr(visconti_gpio_of_match), + .of_match_table = visconti_gpio_of_match, } }; module_platform_driver(visconti_gpio_driver); diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c index fd88500399c6..2d23b27d55af 100644 --- a/drivers/gpio/gpio-xgs-iproc.c +++ b/drivers/gpio/gpio-xgs-iproc.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/seq_file.h> #include <linux/spinlock.h> #define IPROC_CCA_INT_F_GPIOINT BIT(0) @@ -27,7 +28,6 @@ #define IPROC_GPIO_CCA_INT_EDGE 0x24 struct iproc_gpio_chip { - struct irq_chip irqchip; struct gpio_chip gc; spinlock_t lock; struct device *dev; @@ -69,6 +69,7 @@ static void iproc_gpio_irq_unmask(struct irq_data *d) u32 irq = d->irq; u32 int_mask, irq_type, event_mask; + gpiochip_enable_irq(gc, pin); spin_lock_irqsave(&chip->lock, flags); irq_type = irq_get_trigger_type(irq); event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); @@ -110,6 +111,7 @@ static void iproc_gpio_irq_mask(struct irq_data *d) chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); } spin_unlock_irqrestore(&chip->lock, flags); + gpiochip_disable_irq(gc, pin); } static int iproc_gpio_irq_set_type(struct irq_data *d, u32 type) @@ -191,6 +193,24 @@ static irqreturn_t iproc_gpio_irq_handler(int irq, void *data) return int_bits ? IRQ_HANDLED : IRQ_NONE; } +static void iproc_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + + seq_printf(p, dev_name(chip->dev)); +} + +static const struct irq_chip iproc_gpio_irq_chip = { + .irq_ack = iproc_gpio_irq_ack, + .irq_mask = iproc_gpio_irq_mask, + .irq_unmask = iproc_gpio_irq_unmask, + .irq_set_type = iproc_gpio_irq_set_type, + .irq_print_chip = iproc_gpio_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int iproc_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -230,16 +250,8 @@ static int iproc_gpio_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq > 0) { struct gpio_irq_chip *girq; - struct irq_chip *irqc; u32 val; - irqc = &chip->irqchip; - irqc->name = dev_name(dev); - irqc->irq_ack = iproc_gpio_irq_ack; - irqc->irq_mask = iproc_gpio_irq_mask; - irqc->irq_unmask = iproc_gpio_irq_unmask; - irqc->irq_set_type = iproc_gpio_irq_set_type; - chip->intr = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(chip->intr)) return PTR_ERR(chip->intr); @@ -261,7 +273,7 @@ static int iproc_gpio_probe(struct platform_device *pdev) } girq = &chip->gc.irq; - girq->chip = irqc; + gpio_irq_chip_set_chip(girq, &iproc_gpio_irq_chip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index e248809965ca..1fa66f2a667f 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -68,7 +68,6 @@ struct xgpio_instance { DECLARE_BITMAP(dir, 64); spinlock_t gpio_lock; /* For serializing operations */ int irq; - struct irq_chip irqchip; DECLARE_BITMAP(enable, 64); DECLARE_BITMAP(rising_edge, 64); DECLARE_BITMAP(falling_edge, 64); @@ -416,6 +415,8 @@ static void xgpio_irq_mask(struct irq_data *irq_data) xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp); } spin_unlock_irqrestore(&chip->gpio_lock, flags); + + gpiochip_disable_irq(&chip->gc, irq_offset); } /** @@ -431,6 +432,8 @@ static void xgpio_irq_unmask(struct irq_data *irq_data) u32 old_enable = xgpio_get_value32(chip->enable, bit); u32 mask = BIT(bit / 32), val; + gpiochip_enable_irq(&chip->gc, irq_offset); + spin_lock_irqsave(&chip->gpio_lock, flags); __set_bit(bit, chip->enable); @@ -544,6 +547,16 @@ static void xgpio_irqhandler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } +static const struct irq_chip xgpio_irq_chip = { + .name = "gpio-xilinx", + .irq_ack = xgpio_irq_ack, + .irq_mask = xgpio_irq_mask, + .irq_unmask = xgpio_irq_unmask, + .irq_set_type = xgpio_set_irq_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + /** * xgpio_probe - Probe method for the GPIO device. * @pdev: pointer to the platform device @@ -653,12 +666,6 @@ static int xgpio_probe(struct platform_device *pdev) if (chip->irq <= 0) goto skip_irq; - chip->irqchip.name = "gpio-xilinx"; - chip->irqchip.irq_ack = xgpio_irq_ack; - chip->irqchip.irq_mask = xgpio_irq_mask; - chip->irqchip.irq_unmask = xgpio_irq_unmask; - chip->irqchip.irq_set_type = xgpio_set_irq_type; - /* Disable per-channel interrupts */ xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, 0); /* Clear any existing per-channel interrupts */ @@ -668,7 +675,7 @@ static int xgpio_probe(struct platform_device *pdev) xgpio_writereg(chip->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE); girq = &chip->gc.irq; - girq->chip = &chip->irqchip; + gpio_irq_chip_set_chip(girq, &xgpio_irq_chip); girq->parent_handler = xgpio_irqhandler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, 1, diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 0199f545335f..b4b52213bcd9 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -90,6 +90,13 @@ static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state) writel(value, addr + regset); } +static void xlp_gpio_irq_enable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); +} + static void xlp_gpio_irq_disable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); @@ -100,6 +107,7 @@ static void xlp_gpio_irq_disable(struct irq_data *d) xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0); __clear_bit(d->hwirq, priv->gpio_enabled_mask); spin_unlock_irqrestore(&priv->lock, flags); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void xlp_gpio_irq_mask_ack(struct irq_data *d) @@ -163,10 +171,12 @@ static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type) static struct irq_chip xlp_gpio_irq_chip = { .name = "XLP-GPIO", .irq_mask_ack = xlp_gpio_irq_mask_ack, + .irq_enable = xlp_gpio_irq_enable, .irq_disable = xlp_gpio_irq_disable, .irq_set_type = xlp_gpio_set_irq_type, .irq_unmask = xlp_gpio_irq_unmask, - .flags = IRQCHIP_ONESHOT_SAFE, + .flags = IRQCHIP_ONESHOT_SAFE | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static void xlp_gpio_generic_handler(struct irq_desc *desc) @@ -272,7 +282,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) spin_lock_init(&priv->lock); girq = &gc->irq; - girq->chip = &xlp_gpio_irq_chip; + gpio_irq_chip_set_chip(girq, &xlp_gpio_irq_chip); girq->parent_handler = xlp_gpio_generic_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, 1, diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c index 49c878cfd5c6..51d6119e1bb4 100644 --- a/drivers/gpio/gpio-xra1403.c +++ b/drivers/gpio/gpio-xra1403.c @@ -195,7 +195,7 @@ static const struct spi_device_id xra1403_ids[] = { }; MODULE_DEVICE_TABLE(spi, xra1403_ids); -static const struct of_device_id xra1403_spi_of_match[] = { +static const struct of_device_id xra1403_spi_of_match[] __maybe_unused = { { .compatible = "exar,xra1403" }, {}, }; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 700195a1faae..88dcf40aca90 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -61,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, @@ -360,7 +373,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc) } /* - * devprop_gpiochip_set_names - Set GPIO line names using device properties + * gpiochip_set_names - Set GPIO line names using device properties * @chip: GPIO chip whose lines should be named, if possible * * Looks for device property "gpio-line-names" and if it exists assigns @@ -368,7 +381,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc) * names belong to the underlying firmware node and should not be released * by the caller. */ -static int devprop_gpiochip_set_names(struct gpio_chip *chip) +static int gpiochip_set_names(struct gpio_chip *chip) { struct gpio_device *gdev = chip->gpiodev; struct device *dev = &gdev->dev; @@ -559,7 +572,7 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc, } EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); -static void gpiodevice_release(struct device *dev) +static void gpiodev_release(struct device *dev) { struct gpio_device *gdev = to_gpio_device(dev); unsigned long flags; @@ -588,21 +601,22 @@ static void gpiodevice_release(struct device *dev) static int gpiochip_setup_dev(struct gpio_device *gdev) { + struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev); int ret; /* * If fwnode doesn't belong to another device, it's safe to clear its * initialized flag. */ - if (gdev->dev.fwnode && !gdev->dev.fwnode->dev) - fwnode_dev_initialized(gdev->dev.fwnode, false); + if (fwnode && !fwnode->dev) + fwnode_dev_initialized(fwnode, false); ret = gcdev_register(gdev, gpio_devt); if (ret) return ret; /* From this point, the .release() function cleans up gpio_device */ - gdev->dev.release = gpiodevice_release; + gdev->dev.release = gpiodev_release; ret = gpiochip_sysfs_register(gdev); if (ret) @@ -666,6 +680,24 @@ 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) @@ -695,7 +727,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); @@ -762,7 +796,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); @@ -819,7 +852,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; @@ -925,19 +958,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 * @@ -963,9 +983,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++) { @@ -1204,7 +1224,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); @@ -1372,8 +1392,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; @@ -1449,8 +1468,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); @@ -1467,8 +1487,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); @@ -1508,33 +1529,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); } @@ -1542,17 +1567,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) @@ -3912,13 +3939,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 @@ -4259,16 +4283,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); @@ -4288,20 +4314,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 + @@ -4316,8 +4339,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); } @@ -4325,8 +4353,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 @@ -4340,7 +4367,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)) @@ -4351,8 +4378,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, @@ -4416,20 +4441,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) { /* |