From 9b6d5690b543b8fbf3daf8fc2d7ec7b59b3a3467 Mon Sep 17 00:00:00 2001 From: sachin agarwal Date: Sun, 9 Feb 2020 16:46:20 +0530 Subject: gpio: ich: fix a typo We had written "Mangagment" rather than "Management". Signed-off-by: Sachin Agarwal Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-ich.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 2f086d0aa1f4..9960bb8b0f5b 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -89,7 +89,7 @@ static struct { struct device *dev; struct gpio_chip chip; struct resource *gpio_base; /* GPIO IO base */ - struct resource *pm_base; /* Power Mangagment IO base */ + struct resource *pm_base; /* Power Management IO base */ struct ichx_desc *desc; /* Pointer to chipset-specific description */ u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ u8 use_gpio; /* Which GPIO groups are usable */ -- cgit v1.2.3-59-g8ed1b From 7fc504b993cee79e38c0f018bf3c38940873bebd Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 1 Apr 2020 13:49:37 -0400 Subject: gpio: xgene-sb: set valid IRQ type in to_irq() xgene-sb is setup to be a hierarchical IRQ chip with the GIC as the parent chip. xgene_gpio_sb_to_irq() currently sets the default IRQ type to IRQ_TYPE_NONE, which the GIC loudly complains about with a WARN_ON(). Let's set the initial default to a sane value (IRQ_TYPE_EDGE_RISING) that was determined by decoding the ACPI tables on affected hardware: Device (_SB.GPSB) { Name (_HID, "APMC0D15") // _HID: Hardware ID Name (_CID, "APMC0D15") // _CID: Compatible ID Name (_UID, "GPIOSB") // _UID: Unique ID ... Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { ... Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, ) { 0x00000048, } ... } } This can be overridden later as needed with irq_set_irq_type(). Signed-off-by: Brian Masney Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xgene-sb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index 25d86441666e..b45bfa9baa26 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -122,7 +122,7 @@ static int xgene_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio) fwspec.fwnode = gc->parent->fwnode; fwspec.param_count = 2; fwspec.param[0] = GPIO_TO_HWIRQ(priv, gpio); - fwspec.param[1] = IRQ_TYPE_NONE; + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; return irq_create_fwspec_mapping(&fwspec); } -- cgit v1.2.3-59-g8ed1b From 85a94ff8fb14511c88b8d21f82937197d76b82a2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Apr 2020 22:21:45 +0300 Subject: gpio: Extend TODO to cover code duplication avoidance It appears at least two drivers has a lot of duplication code in GPIO subsystem. To avoid adding more and get rid of existing duplication extend TODO. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/TODO | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 3a44e6ae52bd..b989c9352da2 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -99,6 +99,10 @@ similar and probe a proper driver in the gpiolib subsystem. In some cases it makes sense to create a GPIO chip from the local driver for a few GPIOs. Those should stay where they are. +At the same time it makes sense to get rid of code duplication in existing or +new coming drivers. For example, gpio-ml-ioh should be incorporated into +gpio-pch. In similar way gpio-intel-mid into gpio-pxa. + Generic MMIO GPIO -- cgit v1.2.3-59-g8ed1b From 616844408de7f21546c3c2a71ea7f8d364f45e0d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 8 Apr 2020 19:41:10 -0600 Subject: gpio: pl061: Support building as module Enable building the PL061 GPIO driver as a module. This does change the initcall level when built-in. This shouldn't be a problem as any user should support deferred probe by now. A scan of DT based platforms at least didn't reveal any users that would be a problem. Cc: Linus Walleij Cc: Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org Signed-off-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-pl061.c | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1b96169d84f7..8ef2179fb999 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -422,7 +422,7 @@ config GPIO_OMAP Say yes here to enable GPIO support for TI OMAP SoCs. config GPIO_PL061 - bool "PrimeCell PL061 GPIO support" + tristate "PrimeCell PL061 GPIO support" depends on ARM_AMBA select IRQ_DOMAIN select GPIOLIB_IRQCHIP diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index e241fb884c12..f1b53dd1df1a 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -408,6 +409,7 @@ static const struct amba_id pl061_ids[] = { }, { 0, 0 }, }; +MODULE_DEVICE_TABLE(amba, pl061_ids); static struct amba_driver pl061_gpio_driver = { .drv = { @@ -419,9 +421,6 @@ static struct amba_driver pl061_gpio_driver = { .id_table = pl061_ids, .probe = pl061_probe, }; +module_amba_driver(pl061_gpio_driver); -static int __init pl061_gpio_init(void) -{ - return amba_driver_register(&pl061_gpio_driver); -} -device_initcall(pl061_gpio_init); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From ea06a482a47c41f5d04565dffbc21156bcfdd3e8 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Sat, 11 Apr 2020 20:33:51 -0500 Subject: gpiolib: of: improve gpiolib-of support of pull up/down on expanders When using GPIO expanders attached to I2C ports, their set_config function needs to be passed a config setting which contains options to enable pull up or pull down bias feature. In order to set this config properly, the gpio parser needs to handle GPIO_PULL_UP and GPIO_PULL_DOWN. This patch enables the flags corresponding to GPIO_PULL_UP and GPIO_PULL_DOWN. Signed-off-by: Adam Ford Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-of.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index ccc449df3792..2c5dd1349f16 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -344,6 +344,12 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, if (transitory) lflags |= GPIO_TRANSITORY; + if (flags & OF_GPIO_PULL_UP) + lflags |= GPIO_PULL_UP; + + if (flags & OF_GPIO_PULL_DOWN) + lflags |= GPIO_PULL_DOWN; + ret = gpiod_configure_flags(desc, propname, lflags, dflags); if (ret < 0) { gpiod_put(desc); @@ -585,6 +591,10 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, *lflags |= GPIO_ACTIVE_LOW; if (xlate_flags & OF_GPIO_TRANSITORY) *lflags |= GPIO_TRANSITORY; + if (xlate_flags & OF_GPIO_PULL_UP) + *lflags |= GPIO_PULL_UP; + if (xlate_flags & OF_GPIO_PULL_DOWN) + *lflags |= GPIO_PULL_DOWN; if (of_property_read_bool(np, "input")) *dflags |= GPIOD_IN; -- cgit v1.2.3-59-g8ed1b From 04fd1ca77918a2395d0dc73c9a68436fdfaa26de Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 25 Mar 2020 11:39:56 +0100 Subject: gpiolib: acpi: Add missing __init(const) markers to initcall-s The gpiolib ACPI code uses 2 initcall-s and the called function (and used DMI table) is missing __init(const) markers. This commit fixes this freeing up some extra memory once the kernel has completed booting. Acked-by: Mika Westerberg Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20200325103956.109284-2-hdegoede@redhat.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 0017367e94ee..9276051663da 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1353,7 +1353,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id) } /* Run deferred acpi_gpiochip_request_irqs() */ -static int acpi_gpio_handle_deferred_request_irqs(void) +static int __init acpi_gpio_handle_deferred_request_irqs(void) { struct acpi_gpio_chip *acpi_gpio, *tmp; @@ -1371,7 +1371,7 @@ static int acpi_gpio_handle_deferred_request_irqs(void) /* We must use _sync so that this runs after the first deferred_probe run */ late_initcall_sync(acpi_gpio_handle_deferred_request_irqs); -static const struct dmi_system_id gpiolib_acpi_quirks[] = { +static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { { /* * The Minix Neo Z83-4 has a micro-USB-B id-pin handler for @@ -1455,7 +1455,7 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = { {} /* Terminating entry */ }; -static int acpi_gpio_setup_params(void) +static int __init acpi_gpio_setup_params(void) { const struct acpi_gpiolib_dmi_quirk *quirk = NULL; const struct dmi_system_id *id; -- cgit v1.2.3-59-g8ed1b From 96d7c7b3e6545612c1d37944621fdd611afd6adf Mon Sep 17 00:00:00 2001 From: Paul Thomas Date: Tue, 14 Apr 2020 11:28:42 -0400 Subject: gpio: gpio-pca953x, Add get_multiple function Implement a get_multiple function for gpio-pca953x. If a driver leaves get_multiple unimplemented then gpio_chip_get_multiple() in gpiolib.c takes care of it by calling chip->get() as needed. For i2c chips this is very inefficient. For example if you do an 8-bit read then instead of a single i2c transaction there are 8 transactions reading the same byte! Signed-off-by: Paul Thomas Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5638b4e5355f..6317510b0dc3 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -115,6 +115,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids); #define MAX_BANK 5 #define BANK_SZ 8 +#define BANK_SFT 3 /* ilog2(BANK_SZ) */ #define MAX_LINE (MAX_BANK * BANK_SZ) #define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ) @@ -466,6 +467,41 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) return GPIO_LINE_DIRECTION_OUT; } +static int pca953x_gpio_get_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + struct pca953x_chip *chip = gpiochip_get_data(gc); + unsigned int reg_val; + int offset, value, i, ret = 0; + u8 inreg; + + /* Force offset outside the range of i so that + * at least the first relevant register is read + */ + offset = gc->ngpio; + for_each_set_bit(i, mask, gc->ngpio) { + /* whenever i goes into a new bank update inreg + * and read the register + */ + if ((offset >> BANK_SFT) != (i >> BANK_SFT)) { + offset = i; + inreg = pca953x_recalc_addr(chip, chip->regs->input, + offset, true, false); + mutex_lock(&chip->i2c_lock); + ret = regmap_read(chip->regmap, inreg, ®_val); + mutex_unlock(&chip->i2c_lock); + if (ret < 0) + return ret; + } + /* reg_val is relative to the last read byte, + * so only shift the relative bits + */ + value = (reg_val >> (i % 8)) & 0x01; + __assign_bit(i, bits, value); + } + return ret; +} + static void pca953x_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { @@ -551,6 +587,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->get = pca953x_gpio_get_value; gc->set = pca953x_gpio_set_value; gc->get_direction = pca953x_gpio_get_direction; + gc->get_multiple = pca953x_gpio_get_multiple; gc->set_multiple = pca953x_gpio_set_multiple; gc->set_config = pca953x_gpio_set_config; gc->can_sleep = true; -- cgit v1.2.3-59-g8ed1b From 5c85418ab35bc84d33947e45b2e0ffe55aa8a484 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 14 Apr 2020 20:48:57 +0300 Subject: gpio: pch: Use BIT() and GENMASK() where it's appropriate Use BIT() and GENMASK() where it's appropriate. At the same time drop it where it's not appropriate. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pch.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 3f3d9a94b709..03eeacdb04fb 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. */ +#include #include #include #include @@ -11,11 +12,11 @@ #include #define PCH_EDGE_FALLING 0 -#define PCH_EDGE_RISING BIT(0) -#define PCH_LEVEL_L BIT(1) -#define PCH_LEVEL_H (BIT(0) | BIT(1)) -#define PCH_EDGE_BOTH BIT(2) -#define PCH_IM_MASK (BIT(0) | BIT(1) | BIT(2)) +#define PCH_EDGE_RISING 1 +#define PCH_LEVEL_L 2 +#define PCH_LEVEL_H 3 +#define PCH_EDGE_BOTH 4 +#define PCH_IM_MASK GENMASK(2, 0) #define PCH_IRQ_BASE 24 @@ -103,9 +104,9 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->po); if (val) - reg_val |= (1 << nr); + reg_val |= BIT(nr); else - reg_val &= ~(1 << nr); + reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->po); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -115,7 +116,7 @@ static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr) { struct pch_gpio *chip = gpiochip_get_data(gpio); - return (ioread32(&chip->reg->pi) >> nr) & 1; + return !!(ioread32(&chip->reg->pi) & BIT(nr)); } static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, @@ -130,13 +131,14 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, reg_val = ioread32(&chip->reg->po); if (val) - reg_val |= (1 << nr); + reg_val |= BIT(nr); else - reg_val &= ~(1 << nr); + reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->po); - pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); - pm |= (1 << nr); + pm = ioread32(&chip->reg->pm); + pm &= BIT(gpio_pins[chip->ioh]) - 1; + pm |= BIT(nr); iowrite32(pm, &chip->reg->pm); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -151,8 +153,9 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); - pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); - pm &= ~(1 << nr); + pm = ioread32(&chip->reg->pm); + pm &= BIT(gpio_pins[chip->ioh]) - 1; + pm &= ~BIT(nr); iowrite32(pm, &chip->reg->pm); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -277,7 +280,7 @@ static void pch_irq_unmask(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct pch_gpio *chip = gc->private; - iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imaskclr); + iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->imaskclr); } static void pch_irq_mask(struct irq_data *d) @@ -285,7 +288,7 @@ static void pch_irq_mask(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct pch_gpio *chip = gc->private; - iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imask); + iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->imask); } static void pch_irq_ack(struct irq_data *d) @@ -293,7 +296,7 @@ static void pch_irq_ack(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct pch_gpio *chip = gc->private; - iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->iclr); + iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->iclr); } static irqreturn_t pch_gpio_handler(int irq, void *dev_id) @@ -344,7 +347,6 @@ static int pch_gpio_probe(struct pci_dev *pdev, s32 ret; struct pch_gpio *chip; int irq_base; - u32 msk; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -357,7 +359,7 @@ static int pch_gpio_probe(struct pci_dev *pdev, return ret; } - ret = pcim_iomap_regions(pdev, 1 << 1, KBUILD_MODNAME); + ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME); if (ret) { dev_err(&pdev->dev, "pci_request_regions FAILED-%d", ret); return ret; @@ -393,9 +395,8 @@ static int pch_gpio_probe(struct pci_dev *pdev, chip->irq_base = irq_base; /* Mask all interrupts, but enable them */ - msk = (1 << gpio_pins[chip->ioh]) - 1; - iowrite32(msk, &chip->reg->imask); - iowrite32(msk, &chip->reg->ien); + iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->imask); + iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->ien); ret = devm_request_irq(&pdev->dev, pdev->irq, pch_gpio_handler, IRQF_SHARED, KBUILD_MODNAME, chip); -- cgit v1.2.3-59-g8ed1b From 5a4245de48d87f9300c3cac7c62e1af18916fb22 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 14 Apr 2020 20:48:58 +0300 Subject: gpio: pch: Get rid of unneeded variable in IRQ handler There is no need to have an additional variable in IRQ handler. We may simple rely on the fact of having non-zero register value we read from the hardware. While here, drop repetitive messages in time critical function. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pch.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 03eeacdb04fb..708272db6baf 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -303,14 +303,15 @@ static irqreturn_t pch_gpio_handler(int irq, void *dev_id) { struct pch_gpio *chip = dev_id; unsigned long reg_val = ioread32(&chip->reg->istatus); - int i, ret = IRQ_NONE; + int i; - for_each_set_bit(i, ®_val, gpio_pins[chip->ioh]) { - dev_dbg(chip->dev, "[%d]:irq=%d status=0x%lx\n", i, irq, reg_val); + dev_dbg(chip->dev, "irq=%d status=0x%lx\n", irq, reg_val); + + reg_val &= BIT(gpio_pins[chip->ioh]) - 1; + for_each_set_bit(i, ®_val, gpio_pins[chip->ioh]) generic_handle_irq(chip->irq_base + i); - ret = IRQ_HANDLED; - } - return ret; + + return IRQ_RETVAL(reg_val); } static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip, -- cgit v1.2.3-59-g8ed1b From 368b8436011ac5138230b98bb34923b7f77ae533 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 14 Apr 2020 20:48:59 +0300 Subject: gpio: pch: Refactor pch_irq_type() to avoid unnecessary locking When type is not supported there is no need to lock and check. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pch.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 708272db6baf..9c34230f2e84 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -229,17 +229,15 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) int ch, irq = d->irq; ch = irq - chip->irq_base; - if (irq <= chip->irq_base + 7) { + if (irq < chip->irq_base + 8) { im_reg = &chip->reg->im0; - im_pos = ch; + im_pos = ch - 0; } else { im_reg = &chip->reg->im1; im_pos = ch - 8; } dev_dbg(chip->dev, "irq=%d type=%d ch=%d pos=%d\n", irq, type, ch, im_pos); - spin_lock_irqsave(&chip->spinlock, flags); - switch (type) { case IRQ_TYPE_EDGE_RISING: val = PCH_EDGE_RISING; @@ -257,9 +255,11 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) val = PCH_LEVEL_L; break; default: - goto unlock; + return 0; } + spin_lock_irqsave(&chip->spinlock, flags); + /* Set interrupt mode */ im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4)); iowrite32(im | (val << (im_pos * 4)), im_reg); @@ -270,7 +270,6 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) irq_set_handler_locked(d, handle_edge_irq); -unlock: spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } -- cgit v1.2.3-59-g8ed1b From 5376b0b31295364f3a166ee82f1a7d893bcbf8e9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 14 Apr 2020 20:49:00 +0300 Subject: gpio: pch: Use in pch_irq_type() macros provided by IRQ core Use in pch_irq_type() the macros provided by IRQ core for IRQ type. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 9c34230f2e84..e96d28bf43b4 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -265,9 +265,9 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) iowrite32(im | (val << (im_pos * 4)), im_reg); /* And the handler */ - if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + if (type & IRQ_TYPE_LEVEL_MASK) irq_set_handler_locked(d, handle_level_irq); - else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + else if (type & IRQ_TYPE_EDGE_BOTH) irq_set_handler_locked(d, handle_edge_irq); spin_unlock_irqrestore(&chip->spinlock, flags); -- cgit v1.2.3-59-g8ed1b From 6b1c7837af0e29ad630f0ae18634f6c58a3381ee Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 Apr 2020 18:41:54 +0300 Subject: gpio: merrifield: Switch over to MSI interrupts Some devices may support MSI interrupts. Let's at least try to use them in platforms that provide MSI capability. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-merrifield.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 48918a016cd8..11e6ea70568a 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -473,6 +473,10 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id raw_spin_lock_init(&priv->lock); + retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (retval < 0) + return retval; + girq = &priv->chip.irq; girq->chip = &mrfld_irqchip; girq->init_hw = mrfld_irq_init_hw; @@ -482,7 +486,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id sizeof(*girq->parents), GFP_KERNEL); if (!girq->parents) return -ENOMEM; - girq->parents[0] = pdev->irq; + girq->parents[0] = pci_irq_vector(pdev, 0); girq->first = irq_base; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; -- cgit v1.2.3-59-g8ed1b From 7e73aa90a38c8815acea7af71e285658bf5ab879 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 Apr 2020 18:41:55 +0300 Subject: gpio: merrifield: Better show how GPIO and IRQ bases are derived from hardware It's a bit hard to realize what the BAR1 is for and what is the layout of the data in it. Be slightly more verbose to better show how GPIO and IRQ bases are derived from the hardware. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-merrifield.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 11e6ea70568a..706687fab634 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -443,8 +443,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id base = pcim_iomap_table(pdev)[1]; - irq_base = readl(base); - gpio_base = readl(sizeof(u32) + base); + irq_base = readl(base + 0 * sizeof(u32)); + gpio_base = readl(base + 1 * sizeof(u32)); /* Release the IO mapping, since we already get the info from BAR1 */ pcim_iounmap_regions(pdev, BIT(1)); -- cgit v1.2.3-59-g8ed1b From aa58a21ae37894d456a2f91a37e9fd71ad4aa27e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 7 Apr 2020 17:42:45 +0200 Subject: gpio: pca953x: disable regmap locking This driver uses its own locking but regmap silently uses a mutex for all operations too. Add the option to disable locking to the regmap config struct. Signed-off-by: Bartosz Golaszewski Reviewed-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Acked-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 6317510b0dc3..60ae18e4b5f5 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -307,6 +307,7 @@ static const struct regmap_config pca953x_i2c_regmap = { .writeable_reg = pca953x_writeable_register, .volatile_reg = pca953x_volatile_register, + .disable_locking = true, .cache_type = REGCACHE_RBTREE, /* REVISIT: should be 0x7f but some 24 bit chips use REG_ADDR_AI */ .max_register = 0xff, -- cgit v1.2.3-59-g8ed1b From 3ea8094c3b45495a18b75afd27cfda9597bf0e7d Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 23 Mar 2020 22:53:59 +0300 Subject: gpio: dwapb: Use optional-clocks interface for APB ref-clock The common clocks kernel framework provides a generic way to use an optional reference clock sources. If it's utilized there is no need in checking whether the clock descriptor pointer is actually a negative error at the moment of the prepare/unprepare clocks method calling. So if the corresponding clock source is provided, then getting an error shall actually terminate the device probe procedure. If it isn't specified then the driver shall proceed with further initializations. We'll use the optional clocks getting method to handle the APB reference clock, which can be provided for instance in the device of-node with "bus" clock-name. Signed-off-by: Serge Semin Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Cc: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200323195401.30338-5-Sergey.Semin@baikalelectronics.ru Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 92e127e74813..0c5abfa361e6 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -690,13 +690,16 @@ static int dwapb_gpio_probe(struct platform_device *pdev) return PTR_ERR(gpio->regs); /* Optional bus clock */ - gpio->clk = devm_clk_get(&pdev->dev, "bus"); - if (!IS_ERR(gpio->clk)) { - err = clk_prepare_enable(gpio->clk); - if (err) { - dev_info(&pdev->dev, "Cannot enable clock\n"); - return err; - } + gpio->clk = devm_clk_get_optional(&pdev->dev, "bus"); + if (IS_ERR(gpio->clk)) { + dev_err(&pdev->dev, "Cannot get APB clock\n"); + return PTR_ERR(gpio->clk); + } + + err = clk_prepare_enable(gpio->clk); + if (err) { + dev_err(&pdev->dev, "Cannot enable APB clock\n"); + return err; } gpio->flags = 0; @@ -793,8 +796,7 @@ static int dwapb_gpio_resume(struct device *dev) unsigned long flags; int i; - if (!IS_ERR(gpio->clk)) - clk_prepare_enable(gpio->clk); + clk_prepare_enable(gpio->clk); spin_lock_irqsave(&gc->bgpio_lock, flags); for (i = 0; i < gpio->nr_ports; i++) { -- cgit v1.2.3-59-g8ed1b From 5c544c92d6cd058d2a95a49fe75265043264b942 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 23 Mar 2020 22:54:00 +0300 Subject: gpio: dwapb: Add debounce reference clock support Aside from the APB reference clock DW GPIO controller can have a dedicated clock connected to setup a debounce time interval for GPIO-based IRQs. Since this functionality is optional the corresponding clock source is also optional. Due to this lets handle the debounce clock in the same way as it has been developed for the APB reference clock, but using the bulk request/enable-disable methods. Signed-off-by: Serge Semin Reviewed-by: Linus Walleij Cc: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200323195401.30338-6-Sergey.Semin@baikalelectronics.ru Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 0c5abfa361e6..d2ed11510f3c 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -62,6 +62,8 @@ #define GPIO_INTSTATUS_V2 0x3c #define GPIO_PORTA_EOI_V2 0x40 +#define DWAPB_NR_CLOCKS 2 + struct dwapb_gpio; #ifdef CONFIG_PM_SLEEP @@ -97,7 +99,7 @@ struct dwapb_gpio { struct irq_domain *domain; unsigned int flags; struct reset_control *rst; - struct clk *clk; + struct clk_bulk_data clks[DWAPB_NR_CLOCKS]; }; static inline u32 gpio_reg_v2_convert(unsigned int offset) @@ -689,16 +691,19 @@ static int dwapb_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio->regs)) return PTR_ERR(gpio->regs); - /* Optional bus clock */ - gpio->clk = devm_clk_get_optional(&pdev->dev, "bus"); - if (IS_ERR(gpio->clk)) { - dev_err(&pdev->dev, "Cannot get APB clock\n"); - return PTR_ERR(gpio->clk); + /* Optional bus and debounce clocks */ + gpio->clks[0].id = "bus"; + gpio->clks[1].id = "db"; + err = devm_clk_bulk_get_optional(&pdev->dev, DWAPB_NR_CLOCKS, + gpio->clks); + if (err) { + dev_err(&pdev->dev, "Cannot get APB/Debounce clocks\n"); + return err; } - err = clk_prepare_enable(gpio->clk); + err = clk_bulk_prepare_enable(DWAPB_NR_CLOCKS, gpio->clks); if (err) { - dev_err(&pdev->dev, "Cannot enable APB clock\n"); + dev_err(&pdev->dev, "Cannot enable APB/Debounce clocks\n"); return err; } @@ -727,7 +732,7 @@ static int dwapb_gpio_probe(struct platform_device *pdev) out_unregister: dwapb_gpio_unregister(gpio); dwapb_irq_teardown(gpio); - clk_disable_unprepare(gpio->clk); + clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks); return err; } @@ -739,7 +744,7 @@ static int dwapb_gpio_remove(struct platform_device *pdev) dwapb_gpio_unregister(gpio); dwapb_irq_teardown(gpio); reset_control_assert(gpio->rst); - clk_disable_unprepare(gpio->clk); + clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks); return 0; } @@ -784,7 +789,7 @@ static int dwapb_gpio_suspend(struct device *dev) } spin_unlock_irqrestore(&gc->bgpio_lock, flags); - clk_disable_unprepare(gpio->clk); + clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks); return 0; } @@ -794,9 +799,13 @@ static int dwapb_gpio_resume(struct device *dev) struct dwapb_gpio *gpio = dev_get_drvdata(dev); struct gpio_chip *gc = &gpio->ports[0].gc; unsigned long flags; - int i; + int i, err; - clk_prepare_enable(gpio->clk); + err = clk_bulk_prepare_enable(DWAPB_NR_CLOCKS, gpio->clks); + if (err) { + dev_err(gpio->dev, "Cannot reenable APB/Debounce clocks\n"); + return err; + } spin_lock_irqsave(&gc->bgpio_lock, flags); for (i = 0; i < gpio->nr_ports; i++) { -- cgit v1.2.3-59-g8ed1b From c58220cba2e03618659fa7d5dfae31f5ad4ae9d0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:21 +0300 Subject: gpio: dwapb: Append MODULE_ALIAS for platform driver The commit 3d2613c4289f ("GPIO: gpio-dwapb: Enable platform driver binding to MFD driver") introduced a use of the platform driver but missed to add the following line to it: MODULE_ALIAS("platform:gpio-dwapb"); Add this to get driver loaded automatically if platform device is registered. Fixes: 3d2613c4289f ("GPIO: gpio-dwapb: Enable platform driver binding to MFD driver") Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-2-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index d2ed11510f3c..c1b6d4f7307e 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -49,7 +49,9 @@ #define GPIO_EXT_PORTC 0x58 #define GPIO_EXT_PORTD 0x5c +#define DWAPB_DRIVER_NAME "gpio-dwapb" #define DWAPB_MAX_PORTS 4 + #define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */ #define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */ #define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */ @@ -400,7 +402,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, return; err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2, - "gpio-dwapb", handle_level_irq, + DWAPB_DRIVER_NAME, handle_level_irq, IRQ_NOREQUEST, 0, IRQ_GC_INIT_NESTED_LOCK); if (err) { @@ -457,7 +459,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, */ err = devm_request_irq(gpio->dev, pp->irq[0], dwapb_irq_handler_mfd, - IRQF_SHARED, "gpio-dwapb-mfd", gpio); + IRQF_SHARED, DWAPB_DRIVER_NAME, gpio); if (err) { dev_err(gpio->dev, "error requesting IRQ\n"); irq_domain_remove(gpio->domain); @@ -847,7 +849,7 @@ static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend, static struct platform_driver dwapb_gpio_driver = { .driver = { - .name = "gpio-dwapb", + .name = DWAPB_DRIVER_NAME, .pm = &dwapb_gpio_pm_ops, .of_match_table = of_match_ptr(dwapb_of_match), .acpi_match_table = ACPI_PTR(dwapb_acpi_match), @@ -861,3 +863,4 @@ module_platform_driver(dwapb_gpio_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jamie Iles"); MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver"); +MODULE_ALIAS("platform:" DWAPB_DRIVER_NAME); -- cgit v1.2.3-59-g8ed1b From 038aa1f0aba9596639c8ec2057169fa8e77d60d1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:22 +0300 Subject: gpio: dwapb: Refactor IRQ handler to use bit operations Refactor IRQ handler in order to use for_each_set_bit() helper. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-3-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index c1b6d4f7307e..e89a3c6877aa 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -193,22 +193,21 @@ static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) static u32 dwapb_do_irq(struct dwapb_gpio *gpio) { - u32 irq_status = dwapb_read(gpio, GPIO_INTSTATUS); - u32 ret = irq_status; + unsigned long irq_status; + int hwirq; - while (irq_status) { - int hwirq = fls(irq_status) - 1; + irq_status = dwapb_read(gpio, GPIO_INTSTATUS); + for_each_set_bit(hwirq, &irq_status, 32) { int gpio_irq = irq_find_mapping(gpio->domain, hwirq); + u32 irq_type = irq_get_trigger_type(gpio_irq); generic_handle_irq(gpio_irq); - irq_status &= ~BIT(hwirq); - if ((irq_get_trigger_type(gpio_irq) & IRQ_TYPE_SENSE_MASK) - == IRQ_TYPE_EDGE_BOTH) + if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) dwapb_toggle_trigger(gpio, hwirq); } - return ret; + return irq_status; } static void dwapb_irq_handler(struct irq_desc *desc) -- cgit v1.2.3-59-g8ed1b From 9b0aef32c725d7ff92f4628c119867bc1a04d321 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:23 +0300 Subject: gpio: dwapb: Use chained IRQ prologue and epilogue Refactor IRQ handler in order to enter and exit chained IRQ by using respective prologue and epilogue calls. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-4-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index e89a3c6877aa..f61139f787d9 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -215,10 +215,9 @@ static void dwapb_irq_handler(struct irq_desc *desc) struct dwapb_gpio *gpio = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); + chained_irq_enter(chip, desc); dwapb_do_irq(gpio); - - if (chip->irq_eoi) - chip->irq_eoi(irq_desc_get_irq_data(desc)); + chained_irq_exit(chip, desc); } static void dwapb_irq_enable(struct irq_data *d) -- cgit v1.2.3-59-g8ed1b From f9754c79707fb71f51208ae8a0d00a30250b6d08 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:24 +0300 Subject: gpio: dwapb: set default handler to be handle_bad_irq() We switch the default handler to be handle_bad_irq() instead of handle_level_irq(), though for now apply it later in the code, to make the difference between IRQ chips more visible. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-5-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index f61139f787d9..588d5c61ae42 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -400,7 +400,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, return; err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2, - DWAPB_DRIVER_NAME, handle_level_irq, + DWAPB_DRIVER_NAME, handle_bad_irq, IRQ_NOREQUEST, 0, IRQ_GC_INIT_NESTED_LOCK); if (err) { @@ -439,6 +439,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, } irq_gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK; + irq_gc->chip_types[0].handler = handle_level_irq; irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; irq_gc->chip_types[1].handler = handle_edge_irq; -- cgit v1.2.3-59-g8ed1b From 43296bf22e16a044500870e6063fc33b17b4253c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:25 +0300 Subject: gpio: dwapb: Deduplicate IRQ resource management GPIO library provides default IRQ resource management hooks, there is no need to repeat this in the individual driver. Remove them for good. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-6-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 588d5c61ae42..c0c267cddd80 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -250,31 +250,6 @@ static void dwapb_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&gc->bgpio_lock, flags); } -static int dwapb_irq_reqres(struct irq_data *d) -{ - struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); - struct dwapb_gpio *gpio = igc->private; - struct gpio_chip *gc = &gpio->ports[0].gc; - int ret; - - ret = gpiochip_lock_as_irq(gc, irqd_to_hwirq(d)); - if (ret) { - dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", - irqd_to_hwirq(d)); - return ret; - } - return 0; -} - -static void dwapb_irq_relres(struct irq_data *d) -{ - struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); - struct dwapb_gpio *gpio = igc->private; - struct gpio_chip *gc = &gpio->ports[0].gc; - - gpiochip_unlock_as_irq(gc, irqd_to_hwirq(d)); -} - static int dwapb_irq_set_type(struct irq_data *d, u32 type) { struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); @@ -428,8 +403,6 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, ct->chip.irq_set_type = dwapb_irq_set_type; ct->chip.irq_enable = dwapb_irq_enable; ct->chip.irq_disable = dwapb_irq_disable; - ct->chip.irq_request_resources = dwapb_irq_reqres; - ct->chip.irq_release_resources = dwapb_irq_relres; #ifdef CONFIG_PM_SLEEP ct->chip.irq_set_wake = dwapb_irq_set_wake; #endif -- cgit v1.2.3-59-g8ed1b From e092bc5044ca8bb7acfa2930a96a5f1dba4148aa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:26 +0300 Subject: gpio: dwapb: Convert to use irqd_to_hwirq() Convert to use irqd_to_hwirq() instead of direct access to the hwirq member. Also amend the type of the hwirq holding variable to be irq_hw_number_t. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Cc: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-7-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index c0c267cddd80..2edccc5bbc25 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -194,7 +194,7 @@ static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) static u32 dwapb_do_irq(struct dwapb_gpio *gpio) { unsigned long irq_status; - int hwirq; + irq_hw_number_t hwirq; irq_status = dwapb_read(gpio, GPIO_INTSTATUS); for_each_set_bit(hwirq, &irq_status, 32) { @@ -230,7 +230,7 @@ static void dwapb_irq_enable(struct irq_data *d) spin_lock_irqsave(&gc->bgpio_lock, flags); val = dwapb_read(gpio, GPIO_INTEN); - val |= BIT(d->hwirq); + val |= BIT(irqd_to_hwirq(d)); dwapb_write(gpio, GPIO_INTEN, val); spin_unlock_irqrestore(&gc->bgpio_lock, flags); } @@ -245,7 +245,7 @@ static void dwapb_irq_disable(struct irq_data *d) spin_lock_irqsave(&gc->bgpio_lock, flags); val = dwapb_read(gpio, GPIO_INTEN); - val &= ~BIT(d->hwirq); + val &= ~BIT(irqd_to_hwirq(d)); dwapb_write(gpio, GPIO_INTEN, val); spin_unlock_irqrestore(&gc->bgpio_lock, flags); } @@ -255,7 +255,7 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type) struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); struct dwapb_gpio *gpio = igc->private; struct gpio_chip *gc = &gpio->ports[0].gc; - int bit = d->hwirq; + irq_hw_number_t bit = irqd_to_hwirq(d); unsigned long level, polarity, flags; if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | @@ -305,11 +305,12 @@ static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable) struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); struct dwapb_gpio *gpio = igc->private; struct dwapb_context *ctx = gpio->ports[0].ctx; + irq_hw_number_t bit = irqd_to_hwirq(d); if (enable) - ctx->wake_en |= BIT(d->hwirq); + ctx->wake_en |= BIT(bit); else - ctx->wake_en &= ~BIT(d->hwirq); + ctx->wake_en &= ~BIT(bit); return 0; } @@ -365,8 +366,9 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, struct gpio_chip *gc = &port->gc; struct fwnode_handle *fwnode = pp->fwnode; struct irq_chip_generic *irq_gc = NULL; - unsigned int hwirq, ngpio = gc->ngpio; + unsigned int ngpio = gc->ngpio; struct irq_chip_type *ct; + irq_hw_number_t hwirq; int err, i; gpio->domain = irq_domain_create_linear(fwnode, ngpio, -- cgit v1.2.3-59-g8ed1b From 9826bbe1fef0b5a2432acce0292562891b1feb57 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:27 +0300 Subject: gpio: dwapb: Use device_get_match_data() to simplify code Use device_get_match_data() here to simplify the code a bit. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-8-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 2edccc5bbc25..8b30ded9322a 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -683,18 +683,7 @@ static int dwapb_gpio_probe(struct platform_device *pdev) return err; } - gpio->flags = 0; - if (dev->of_node) { - gpio->flags = (uintptr_t)of_device_get_match_data(dev); - } else if (has_acpi_companion(dev)) { - const struct acpi_device_id *acpi_id; - - acpi_id = acpi_match_device(dwapb_acpi_match, dev); - if (acpi_id) { - if (acpi_id->driver_data) - gpio->flags = acpi_id->driver_data; - } - } + gpio->flags = (uintptr_t)device_get_match_data(dev); for (i = 0; i < gpio->nr_ports; i++) { err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i); -- cgit v1.2.3-59-g8ed1b From d31275a9dc0baa6b084917f8d42f1e197239fe6c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:28 +0300 Subject: gpio: dwapb: Convert to use IRQ core provided macros IRQ core provides macros such as IRQ_RETVAL(). Convert code to use them. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-9-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 8b30ded9322a..4edac592c253 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -258,8 +258,7 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type) irq_hw_number_t bit = irqd_to_hwirq(d); unsigned long level, polarity, flags; - if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | - IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) + if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; spin_lock_irqsave(&gc->bgpio_lock, flags); @@ -351,12 +350,7 @@ static int dwapb_gpio_set_config(struct gpio_chip *gc, unsigned offset, static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id) { - u32 worked; - struct dwapb_gpio *gpio = dev_id; - - worked = dwapb_do_irq(gpio); - - return worked ? IRQ_HANDLED : IRQ_NONE; + return IRQ_RETVAL(dwapb_do_irq(dev_id)); } static void dwapb_configure_irqs(struct dwapb_gpio *gpio, -- cgit v1.2.3-59-g8ed1b From 48ce805683461f0205e5b1baa2385a0cb425388e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:29 +0300 Subject: gpio: dwapb: Switch to more usual pattern of RMW in dwapb_gpio_set_debounce() More usual pattern is to prepare value and then write it in a single place. Switch code in dwapb_gpio_set_debounce() to it. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-10-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 4edac592c253..0b073cbc003b 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -327,9 +327,10 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc, val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE); if (debounce) - dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb | mask); + val_deb |= mask; else - dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb & ~mask); + val_deb &= ~mask; + dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb); spin_unlock_irqrestore(&gc->bgpio_lock, flags); -- cgit v1.2.3-59-g8ed1b From 4f344e86c7396015e83f31c08aef2eb73838f338 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:30 +0300 Subject: gpio: dwapb: Drop bogus BUG_ON()s There is no case when no context is provided in the ->suspend() and ->resume() hooks. Moreover, BUG_ON() is harmful to user and makes kernel inoperable after the crash. Drop the BUG_ON()s for good. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-11-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 0b073cbc003b..ae4c4db8b156 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -723,8 +723,6 @@ static int dwapb_gpio_suspend(struct device *dev) unsigned int idx = gpio->ports[i].idx; struct dwapb_context *ctx = gpio->ports[i].ctx; - BUG_ON(!ctx); - offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE; ctx->dir = dwapb_read(gpio, offset); @@ -773,8 +771,6 @@ static int dwapb_gpio_resume(struct device *dev) unsigned int idx = gpio->ports[i].idx; struct dwapb_context *ctx = gpio->ports[i].ctx; - BUG_ON(!ctx); - offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE; dwapb_write(gpio, offset, ctx->data); -- cgit v1.2.3-59-g8ed1b From c59042ed896592eba6a5f8baa9c12aec7e36db20 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:31 +0300 Subject: gpio: dwapb: Drop of_match_ptr() & ACPI_PTR() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we always have a table of IDs compiled in, there is no use for of_match_ptr() nor ACPI_PTR() call. Besides that it brings a warning (depending on configuration): .../gpio-dwapb.c:638:34: warning: ‘dwapb_of_match’ defined but not used [-Wunused-const-variable=] 638 | static const struct of_device_id dwapb_of_match[] = { | ^~~~~~~~~~~~~~ Get rid of them for good. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-12-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index ae4c4db8b156..98e1ffcd432b 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -805,8 +805,8 @@ static struct platform_driver dwapb_gpio_driver = { .driver = { .name = DWAPB_DRIVER_NAME, .pm = &dwapb_gpio_pm_ops, - .of_match_table = of_match_ptr(dwapb_of_match), - .acpi_match_table = ACPI_PTR(dwapb_acpi_match), + .of_match_table = dwapb_of_match, + .acpi_match_table = dwapb_acpi_match, }, .probe = dwapb_gpio_probe, .remove = dwapb_gpio_remove, -- cgit v1.2.3-59-g8ed1b From 4c2b54f73aba9c8428c1c8025f91d69ca77e1e6e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Apr 2020 17:15:32 +0300 Subject: gpio: dwapb: Split out dwapb_get_irq() helper Split out dwapb_get_irq() helper for better readability and maintenance. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20200415141534.31240-13-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 56 ++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 98e1ffcd432b..31d29ec6ab5c 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -528,14 +528,38 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) gpiochip_remove(&gpio->ports[m].gc); } -static struct dwapb_platform_data * -dwapb_gpio_get_pdata(struct device *dev) +static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode, + struct dwapb_port_property *pp) +{ + struct device_node *np = NULL; + int j; + + if (fwnode_property_read_bool(fwnode, "interrupt-controller")) + np = to_of_node(fwnode); + + for (j = 0; j < pp->ngpio; j++) { + pp->irq[j] = -ENXIO; + + if (np) + pp->irq[j] = of_irq_get(np, j); + else if (has_acpi_companion(dev)) + pp->irq[j] = platform_get_irq(to_platform_device(dev), j); + + if (pp->irq[j] >= 0) + pp->has_irq = true; + } + + if (!pp->has_irq) + dev_warn(dev, "no irq for port%d\n", pp->idx); +} + +static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev) { struct fwnode_handle *fwnode; struct dwapb_platform_data *pdata; struct dwapb_port_property *pp; int nports; - int i, j; + int i; nports = device_get_child_node_count(dev); if (nports == 0) @@ -553,8 +577,6 @@ dwapb_gpio_get_pdata(struct device *dev) i = 0; device_for_each_child_node(dev, fwnode) { - struct device_node *np = NULL; - pp = &pdata->properties[i++]; pp->fwnode = fwnode; @@ -581,28 +603,8 @@ dwapb_gpio_get_pdata(struct device *dev) * Only port A can provide interrupts in all configurations of * the IP. */ - if (pp->idx != 0) - continue; - - if (dev->of_node && fwnode_property_read_bool(fwnode, - "interrupt-controller")) { - np = to_of_node(fwnode); - } - - for (j = 0; j < pp->ngpio; j++) { - pp->irq[j] = -ENXIO; - - if (np) - pp->irq[j] = of_irq_get(np, j); - else if (has_acpi_companion(dev)) - pp->irq[j] = platform_get_irq(to_platform_device(dev), j); - - if (pp->irq[j] >= 0) - pp->has_irq = true; - } - - if (!pp->has_irq) - dev_warn(dev, "no irq for port%d\n", pp->idx); + if (pp->idx == 0) + dwapb_get_irq(dev, fwnode, pp); } return pdata; -- cgit v1.2.3-59-g8ed1b From 9f676e5313c1fb7070997bd652a4ed68c6fb9a8c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 8 Apr 2020 07:08:32 +0000 Subject: gpio: mlxbf2: remove unused including Remove including that don't need it. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20200408070832.137037-1-yuehaibing@huawei.com Acked-by: Asmaa Mnebhi Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mlxbf2.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index 7b7085050219..240b488609ac 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -14,7 +14,6 @@ #include #include #include -#include /* * There are 3 YU GPIO blocks: -- cgit v1.2.3-59-g8ed1b From 9784c9963feccd8dede924dbc0f8b1c64506e646 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 23 Apr 2020 13:34:16 -0700 Subject: gpiolib: devprop: Warn if gpio-line-names is too long Some DT authors (including myself) have messed up the length of gpio-line-names and made it longer than it should be. Add a warning here so that developers can figure out that they've messed up their DT and should fix it. Cc: Alexandru M Stan Signed-off-by: Stephen Boyd Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-devprop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-devprop.c b/drivers/gpio/gpiolib-devprop.c index 53781b253986..26741032fa9e 100644 --- a/drivers/gpio/gpiolib-devprop.c +++ b/drivers/gpio/gpiolib-devprop.c @@ -37,8 +37,11 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip, if (count < 0) return; - if (count > gdev->ngpio) + if (count > gdev->ngpio) { + dev_warn(&gdev->dev, "gpio-line-names is length %d but should be at most length %d", + count, gdev->ngpio); count = gdev->ngpio; + } names = kcalloc(count, sizeof(*names), GFP_KERNEL); if (!names) -- cgit v1.2.3-59-g8ed1b From 1afbc80c3d2b7831ec2027938876ebffbfd20abb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Apr 2020 14:06:53 +0300 Subject: gpio: dwapb: Get rid of unnecessary conjunction over 32-bit value When we mask interrupts before sleep, there is no need to have a conjunction with 0xffffffff since the accepted by dwapb_write() value is 32-bit. Signed-off-by: Andy Shevchenko Acked-by: Serge Semin Cc: Serge Semin Link: https://lore.kernel.org/r/20200422110654.23442-1-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 31d29ec6ab5c..9d8476afaba3 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -743,8 +743,7 @@ static int dwapb_gpio_suspend(struct device *dev) ctx->int_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE); /* Mask out interrupts */ - dwapb_write(gpio, GPIO_INTMASK, - 0xffffffff & ~ctx->wake_en); + dwapb_write(gpio, GPIO_INTMASK, ~ctx->wake_en); } } spin_unlock_irqrestore(&gc->bgpio_lock, flags); -- cgit v1.2.3-59-g8ed1b From 1475b6293af2e240294c09182872b18e47495f37 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Apr 2020 14:06:54 +0300 Subject: gpio: dwapb: Amend indentation in some cases In some cases indentation makes code harder to read. Amend indentation in those cases despite of lines go a bit over 80 character limit. Signed-off-by: Andy Shevchenko Acked-by: Serge Semin Cc: Serge Semin Link: https://lore.kernel.org/r/20200422110654.23442-2-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 9d8476afaba3..8639c4a7f469 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -437,7 +437,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, } } - for (hwirq = 0 ; hwirq < ngpio ; hwirq++) + for (hwirq = 0; hwirq < ngpio; hwirq++) irq_create_mapping(gpio->domain, hwirq); port->gc.to_irq = dwapb_gpio_to_irq; @@ -453,7 +453,7 @@ static void dwapb_irq_teardown(struct dwapb_gpio *gpio) if (!gpio->domain) return; - for (hwirq = 0 ; hwirq < ngpio ; hwirq++) + for (hwirq = 0; hwirq < ngpio; hwirq++) irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq)); irq_domain_remove(gpio->domain); @@ -478,10 +478,9 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, return -ENOMEM; #endif - dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_STRIDE); - set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_STRIDE); - dirout = gpio->regs + GPIO_SWPORTA_DDR + - (pp->idx * GPIO_SWPORT_DDR_STRIDE); + dat = gpio->regs + GPIO_EXT_PORTA + pp->idx * GPIO_EXT_PORT_STRIDE; + set = gpio->regs + GPIO_SWPORTA_DR + pp->idx * GPIO_SWPORT_DR_STRIDE; + dirout = gpio->regs + GPIO_SWPORTA_DDR + pp->idx * GPIO_SWPORT_DDR_STRIDE; /* This registers 32 GPIO lines per port */ err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout, @@ -588,8 +587,7 @@ static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev) return ERR_PTR(-EINVAL); } - if (fwnode_property_read_u32(fwnode, "snps,nr-gpios", - &pp->ngpio)) { + if (fwnode_property_read_u32(fwnode, "snps,nr-gpios", &pp->ngpio)) { dev_info(dev, "failed to get number of gpios for port%d\n", i); -- cgit v1.2.3-59-g8ed1b From 262b90116619ecab0734a3d931851e1fa1e89a7d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Apr 2020 16:14:32 +0200 Subject: gpiolib: Improve kernel messages Simplify the printing of kernel messages and make the messages more accurate by using the most appropriate {dev,chip,gpiod}_*() helpers. Sample impact: -gpiochip_setup_dev: registered GPIOs 496 to 511 on device: gpiochip0 (e6050000.gpio) +gpio gpiochip0: registered GPIOs 496 to 511 on e6050000.gpio -no flags found for gpios +gpio-953 (?): no flags found for gpios -GPIO line 355 (PCIE/SATA switch) hogged as output/low +gpio-355 (PCIE/SATA switch): hogged as output/low Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200424141432.11400-1-geert+renesas@glider.be Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 40f2d7f69be2..48b4f70e2898 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1508,9 +1508,8 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) /* From this point, the .release() function cleans up gpio_device */ gdev->dev.release = gpiodevice_release; - pr_debug("%s: registered GPIOs %d to %d on device: %s (%s)\n", - __func__, gdev->base, gdev->base + gdev->ngpio - 1, - dev_name(&gdev->dev), gdev->chip->label ? : "generic"); + dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base, + gdev->base + gdev->ngpio - 1, gdev->chip->label ? : "generic"); return 0; @@ -1526,8 +1525,8 @@ static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog) desc = gpiochip_get_desc(gc, hog->chip_hwnum); if (IS_ERR(desc)) { - pr_err("%s: unable to get GPIO desc: %ld\n", - __func__, PTR_ERR(desc)); + chip_err(gc, "%s: unable to get GPIO desc: %ld\n", __func__, + PTR_ERR(desc)); return; } @@ -1536,8 +1535,8 @@ static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog) rv = gpiod_hog(desc, hog->line_name, hog->lflags, hog->dflags); if (rv) - pr_err("%s: unable to hog GPIO line (%s:%u): %d\n", - __func__, gc->label, hog->chip_hwnum, rv); + gpiod_err(desc, "%s: unable to hog GPIO line (%s:%u): %d\n", + __func__, gc->label, hog->chip_hwnum, rv); } static void machine_gpiochip_add(struct gpio_chip *gc) @@ -1562,8 +1561,8 @@ static void gpiochip_setup_devs(void) list_for_each_entry(gdev, &gpio_devices, list) { ret = gpiochip_setup_dev(gdev); if (ret) - pr_err("%s: Failed to initialize gpio device (%d)\n", - dev_name(&gdev->dev), ret); + dev_err(&gdev->dev, + "Failed to initialize gpio device (%d)\n", ret); } } @@ -2672,7 +2671,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gc, return -EINVAL; if (!gc->parent) { - pr_err("missing gpiochip .dev parent pointer\n"); + chip_err(gc, "missing gpiochip .dev parent pointer\n"); return -EINVAL; } gc->irq.threaded = threaded; @@ -4842,7 +4841,7 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { - pr_debug("no flags found for %s\n", con_id); + gpiod_dbg(desc, "no flags found for %s\n", con_id); return 0; } @@ -5067,8 +5066,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, /* Mark GPIO as hogged so it can be identified and removed later */ set_bit(FLAG_IS_HOGGED, &desc->flags); - pr_info("GPIO line %d (%s) hogged as %s%s\n", - desc_to_gpio(desc), name, + gpiod_info(desc, "hogged as %s%s\n", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? (dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : ""); -- cgit v1.2.3-59-g8ed1b From a5e93436e18c8f05a4e777ab125e140335d0ade8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Apr 2020 16:15:17 +0200 Subject: gpiolib: Rename "chip" variables to "gc" in core header file Consistently use "gc" for "struct gpio *" variables. This follows the spirit of commit a0b66a73785ccc8f ("gpio: Rename variable in core APIs"). Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200424141517.11582-1-geert+renesas@glider.be Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.h | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 853ce681b4a4..9ed242316414 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -81,8 +81,7 @@ struct gpio_array { unsigned long invert_mask[]; }; -struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, - unsigned int hwnum); +struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum); int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, @@ -163,18 +162,18 @@ static inline int gpio_chip_hwgpio(const struct gpio_desc *desc) /* With chip prefix */ -#define chip_emerg(chip, fmt, ...) \ - dev_emerg(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__) -#define chip_crit(chip, fmt, ...) \ - dev_crit(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__) -#define chip_err(chip, fmt, ...) \ - dev_err(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__) -#define chip_warn(chip, fmt, ...) \ - dev_warn(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__) -#define chip_info(chip, fmt, ...) \ - dev_info(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__) -#define chip_dbg(chip, fmt, ...) \ - dev_dbg(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__) +#define chip_emerg(gc, fmt, ...) \ + dev_emerg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) +#define chip_crit(gc, fmt, ...) \ + dev_crit(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) +#define chip_err(gc, fmt, ...) \ + dev_err(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) +#define chip_warn(gc, fmt, ...) \ + dev_warn(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) +#define chip_info(gc, fmt, ...) \ + dev_info(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) +#define chip_dbg(gc, fmt, ...) \ + dev_dbg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__) #ifdef CONFIG_GPIO_SYSFS -- cgit v1.2.3-59-g8ed1b From 1c12857c6722579cd4aca67b21d3e80870a290b1 Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Fri, 24 Apr 2020 23:41:02 +0800 Subject: gpio: ftgpio010: Fix small typo Fix a spelling typo in gpio-ftgpio010.c by codespell s/desireable/desirable/ Cc: Andy Shevchenko Signed-off-by: Dejin Zheng Link: https://lore.kernel.org/r/20200424154103.10311-2-zhengdejin5@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ftgpio010.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index fbddb1662428..4031164780f7 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -193,7 +193,7 @@ static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset, if (val == deb_div) { /* * The debounce timer happens to already be set to the - * desireable value, what a coincidence! We can just enable + * desirable value, what a coincidence! We can just enable * debounce on this GPIO line and return. This happens more * often than you think, for example when all GPIO keys * on a system are requesting the same debounce interval. -- cgit v1.2.3-59-g8ed1b From 66d8ad67aab3bc6f55e7de81565cd0d4875bd851 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 27 Apr 2020 11:08:29 +0000 Subject: gpio: mlxbf2: fix return value check in mlxbf2_gpio_get_lock_res() In case of error, the function devm_ioremap() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20200427110829.154785-1-weiyongjun1@huawei.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mlxbf2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index 240b488609ac..fca6a50d9308 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -109,8 +109,8 @@ static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev) } yu_arm_gpio_lock_param.io = devm_ioremap(dev, res->start, size); - if (IS_ERR(yu_arm_gpio_lock_param.io)) - ret = PTR_ERR(yu_arm_gpio_lock_param.io); + if (!yu_arm_gpio_lock_param.io) + ret = -ENOMEM; exit: mutex_unlock(yu_arm_gpio_lock_param.lock); -- cgit v1.2.3-59-g8ed1b From dc5c1439376de8e107396ff5bdbc05af3b04ff0b Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Fri, 24 Apr 2020 23:41:03 +0800 Subject: gpio: mm-lantiq: Fix small typo Fix a spelling typo in gpio-mm-lantiq.c by codespell s/dont/don't/ Cc: Andy Shevchenko Signed-off-by: Dejin Zheng Link: https://lore.kernel.org/r/20200424154103.10311-3-zhengdejin5@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mm-lantiq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index f460d71b0c92..538e31fe8903 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -36,7 +36,7 @@ struct ltq_mm { * @chip: Pointer to our private data structure. * * Write the shadow value to the EBU to set the gpios. We need to set the - * global EBU lock to make sure that PCI/MTD dont break. + * global EBU lock to make sure that PCI/MTD don't break. */ static void ltq_mm_apply(struct ltq_mm *chip) { -- cgit v1.2.3-59-g8ed1b From 6f793485fc03fe832e1abcf0682efd7b4419ae2d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 20 Apr 2020 20:27:50 +0300 Subject: gpio: pca953x: Rewrite ->get_multiple() function The commit 96d7c7b3e654 ("gpio: gpio-pca953x, Add get_multiple function") basically did everything wrong from style and code reuse perspective, i.e. - it didn't utilize existing PCA953x internal helpers - it didn't utilize bitmap API - it misses the point that ilog2(), besides that BANK_SFT is useless, can be used in macros - it has indentation issues. Rewrite the function completely. Cc: Paul Thomas Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 60ae18e4b5f5..41be681ae77c 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -115,7 +115,6 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids); #define MAX_BANK 5 #define BANK_SZ 8 -#define BANK_SFT 3 /* ilog2(BANK_SZ) */ #define MAX_LINE (MAX_BANK * BANK_SZ) #define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ) @@ -469,38 +468,20 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) } static int pca953x_gpio_get_multiple(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits) + unsigned long *mask, unsigned long *bits) { struct pca953x_chip *chip = gpiochip_get_data(gc); - unsigned int reg_val; - int offset, value, i, ret = 0; - u8 inreg; + DECLARE_BITMAP(reg_val, MAX_LINE); + int ret; - /* Force offset outside the range of i so that - * at least the first relevant register is read - */ - offset = gc->ngpio; - for_each_set_bit(i, mask, gc->ngpio) { - /* whenever i goes into a new bank update inreg - * and read the register - */ - if ((offset >> BANK_SFT) != (i >> BANK_SFT)) { - offset = i; - inreg = pca953x_recalc_addr(chip, chip->regs->input, - offset, true, false); - mutex_lock(&chip->i2c_lock); - ret = regmap_read(chip->regmap, inreg, ®_val); - mutex_unlock(&chip->i2c_lock); - if (ret < 0) - return ret; - } - /* reg_val is relative to the last read byte, - * so only shift the relative bits - */ - value = (reg_val >> (i % 8)) & 0x01; - __assign_bit(i, bits, value); - } - return ret; + mutex_lock(&chip->i2c_lock); + ret = pca953x_read_regs(chip, chip->regs->input, reg_val); + mutex_unlock(&chip->i2c_lock); + if (ret) + return ret; + + bitmap_replace(bits, bits, reg_val, mask, gc->ngpio); + return 0; } static void pca953x_gpio_set_multiple(struct gpio_chip *gc, -- cgit v1.2.3-59-g8ed1b From bcf41dc480b179bfb669a232080a2e26dc7294b4 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 20 Apr 2020 20:27:51 +0300 Subject: gpio: pca953x: fix handling of automatic address incrementing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the chips supported by the pca953x driver need the most significant bit in the address word set to automatically increment the address pointer on subsequent reads and writes (example: PCA9505). With this bit unset the same register is read multiple times on a multi-byte read sequence. Other chips must not have this bit set and autoincrement always (example: PCA9555). Up to now this AI bit was interpreted to be part of the address, which resulted in inconsistent regmap caching when a register was written with AI set and then read without it. This happened for the PCA9505 in pca953x_gpio_set_multiple() where pca953x_read_regs() bulk read from the cache for registers 0x8-0xc and then wrote to registers 0x88-0x8c. (Side note: reading 5 values from offset 0x8 yiels OP0 5 times because AI must be set to get OP0-OP4, which is another bug that is resolved here as a by-product.) The same problem happens when calls to gpio_set_value() and gpio_set_array_value() were mixed. With this patch the AI bit is always set for chips that support it. This works as there are no code locations that make use of the behaviour with AI unset (for the chips that support it). Note that the call to pca953x_setup_gpio() had to be done a bit earlier to make the NBANK macro work. The history of this bug is a bit complicated. Commit b32cecb46bdc ("gpio: pca953x: Extract the register address mangling to single function") changed which chips and functions are affected. Commit 3b00691cc46a ("gpio: pca953x: hack to fix 24 bit gpio expanders") used some duct tape to make the driver at least appear to work. Commit 49427232764d ("gpio: pca953x: Perform basic regmap conversion") introduced the caching. Commit b4818afeacbd ("gpio: pca953x: Add set_multiple to allow multiple bits to be set in one write.") introduced the .set_multiple() callback which didn't work for chips that need the AI bit which was fixed later for some chips in 8958262af3fb ("gpio: pca953x: Repair multi-byte IO address increment on PCA9575"). So I'm sorry, I don't know which commit I should pick for a Fixes: line. Tested-by: Marcel Gudert Signed-off-by: Uwe Kleine-König Tested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 41be681ae77c..590b07236637 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -308,8 +308,22 @@ static const struct regmap_config pca953x_i2c_regmap = { .disable_locking = true, .cache_type = REGCACHE_RBTREE, - /* REVISIT: should be 0x7f but some 24 bit chips use REG_ADDR_AI */ - .max_register = 0xff, + .max_register = 0x7f, +}; + +static const struct regmap_config pca953x_ai_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .read_flag_mask = REG_ADDR_AI, + .write_flag_mask = REG_ADDR_AI, + + .readable_reg = pca953x_readable_register, + .writeable_reg = pca953x_writeable_register, + .volatile_reg = pca953x_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .max_register = 0x7f, }; static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, @@ -320,18 +334,6 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1; u8 regaddr = pinctrl | addr | (off / BANK_SZ); - /* Single byte read doesn't need AI bit set. */ - if (!addrinc) - return regaddr; - - /* Chips with 24 and more GPIOs always support Auto Increment */ - if (write && NBANK(chip) > 2) - regaddr |= REG_ADDR_AI; - - /* PCA9575 needs address-increment on multi-byte writes */ - if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) - regaddr |= REG_ADDR_AI; - return regaddr; } @@ -882,6 +884,7 @@ static int pca953x_probe(struct i2c_client *client, int ret; u32 invert = 0; struct regulator *reg; + const struct regmap_config *regmap_config; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -944,7 +947,17 @@ static int pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); - chip->regmap = devm_regmap_init_i2c(client, &pca953x_i2c_regmap); + pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); + + if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { + dev_info(&client->dev, "using AI\n"); + regmap_config = &pca953x_ai_i2c_regmap; + } else { + dev_info(&client->dev, "using no AI\n"); + regmap_config = &pca953x_i2c_regmap; + } + + chip->regmap = devm_regmap_init_i2c(client, regmap_config); if (IS_ERR(chip->regmap)) { ret = PTR_ERR(chip->regmap); goto err_exit; @@ -975,7 +988,6 @@ static int pca953x_probe(struct i2c_client *client, /* initialize cached registers from their original values. * we can't share this chip with another i2c master. */ - pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) { chip->regs = &pca953x_regs; -- cgit v1.2.3-59-g8ed1b From 6fdeb6cbe1ef3bccd2c5e2b3427a06e9cda1efc2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 20 Apr 2020 20:27:52 +0300 Subject: gpio: pca953x: drop unused parameters of pca953x_recalc_addr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the previous patch the two last parameters of pca953x_recalc_addr() are unused and so can be dropped. Tested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Uwe Kleine-König Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 590b07236637..06d6af60e6b7 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -326,8 +326,7 @@ static const struct regmap_config pca953x_ai_i2c_regmap = { .max_register = 0x7f, }; -static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, - bool write, bool addrinc) +static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off) { int bank_shift = pca953x_bank_shift(chip); int addr = (reg & PCAL_GPIO_MASK) << bank_shift; @@ -339,7 +338,7 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long *val) { - u8 regaddr = pca953x_recalc_addr(chip, reg, 0, true, true); + u8 regaddr = pca953x_recalc_addr(chip, reg, 0); u8 value[MAX_BANK]; int i, ret; @@ -357,7 +356,7 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *val) { - u8 regaddr = pca953x_recalc_addr(chip, reg, 0, false, true); + u8 regaddr = pca953x_recalc_addr(chip, reg, 0); u8 value[MAX_BANK]; int i, ret; @@ -376,8 +375,7 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long * static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip = gpiochip_get_data(gc); - u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off, - true, false); + u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off); u8 bit = BIT(off % BANK_SZ); int ret; @@ -391,10 +389,8 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip = gpiochip_get_data(gc); - u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off, - true, false); - u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off, - true, false); + u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off); + u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off); u8 bit = BIT(off % BANK_SZ); int ret; @@ -414,8 +410,7 @@ exit: static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip = gpiochip_get_data(gc); - u8 inreg = pca953x_recalc_addr(chip, chip->regs->input, off, - true, false); + u8 inreg = pca953x_recalc_addr(chip, chip->regs->input, off); u8 bit = BIT(off % BANK_SZ); u32 reg_val; int ret; @@ -439,8 +434,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip = gpiochip_get_data(gc); - u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off, - true, false); + u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off); u8 bit = BIT(off % BANK_SZ); mutex_lock(&chip->i2c_lock); @@ -451,8 +445,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip = gpiochip_get_data(gc); - u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off, - true, false); + u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off); u8 bit = BIT(off % BANK_SZ); u32 reg_val; int ret; @@ -509,10 +502,8 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip, unsigned int offset, unsigned long config) { - u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset, - true, false); - u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset, - true, false); + u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset); + u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset); u8 bit = BIT(offset % BANK_SZ); int ret; -- cgit v1.2.3-59-g8ed1b From fef2d3bb2db61d904e4016a181dd107d608fd055 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Tue, 5 May 2020 10:45:01 +0200 Subject: gpio: tegra186: export MODULE_DEVICE_TABLE Export MODULE_DEVICE_TABLE since the driver can be built as a module. Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 79b553dc39a3..178e9128ded0 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -894,6 +894,7 @@ static const struct of_device_id tegra186_gpio_of_match[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, tegra186_gpio_of_match); static struct platform_driver tegra186_gpio_driver = { .driver = { -- cgit v1.2.3-59-g8ed1b From 17f96ee2b9be9b65517fe167cfb13b86b33f3a1d Mon Sep 17 00:00:00 2001 From: Petteri Jokinen Date: Sat, 2 May 2020 20:22:39 +0300 Subject: gpio-f7188x: Add GPIO support for F81865 Add GPIO support for Fintek F81865 chip. Datasheet: http://www.hardwaresecrets.com/datasheets/F81865_V028P.pdf Signed-off-by: Petteri Jokinen Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-f7188x.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index cadd02993539..18a3147f5a42 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -36,9 +36,19 @@ #define SIO_F71889A_ID 0x1005 /* F71889A chipset ID */ #define SIO_F81866_ID 0x1010 /* F81866 chipset ID */ #define SIO_F81804_ID 0x1502 /* F81804 chipset ID, same for f81966 */ - - -enum chips { f71869, f71869a, f71882fg, f71889a, f71889f, f81866, f81804 }; +#define SIO_F81865_ID 0x0704 /* F81865 chipset ID */ + + +enum chips { + f71869, + f71869a, + f71882fg, + f71889a, + f71889f, + f81866, + f81804, + f81865, +}; static const char * const f7188x_names[] = { "f71869", @@ -48,6 +58,7 @@ static const char * const f7188x_names[] = { "f71889f", "f81866", "f81804", + "f81865", }; struct f7188x_sio { @@ -233,6 +244,15 @@ static struct f7188x_gpio_bank f81804_gpio_bank[] = { F7188X_GPIO_BANK(90, 8, 0x98), }; +static struct f7188x_gpio_bank f81865_gpio_bank[] = { + F7188X_GPIO_BANK(0, 8, 0xF0), + F7188X_GPIO_BANK(10, 8, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 8, 0xC0), + F7188X_GPIO_BANK(40, 8, 0xB0), + F7188X_GPIO_BANK(50, 8, 0xA0), + F7188X_GPIO_BANK(60, 5, 0x90), +}; static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { @@ -425,6 +445,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev) data->nr_bank = ARRAY_SIZE(f81804_gpio_bank); data->bank = f81804_gpio_bank; break; + case f81865: + data->nr_bank = ARRAY_SIZE(f81865_gpio_bank); + data->bank = f81865_gpio_bank; + break; default: return -ENODEV; } @@ -490,6 +514,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) case SIO_F81804_ID: sio->type = f81804; break; + case SIO_F81865_ID: + sio->type = f81865; + break; default: pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid); goto err; -- cgit v1.2.3-59-g8ed1b From 582838ea5bea41258d136c82a6c493a95cda652c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 11 May 2020 12:18:28 +0200 Subject: gpiolib: Document that GPIO line names are not globally unique gpiochip_set_desc_names() no longer rejects GPIO line name collisions. Hence GPIO line names are not guaranteed to be globally unique. In case of multiple GPIO lines with the same name, gpio_name_to_desc() will return the first match found. Update the comments for gpio_name_to_desc() and gpiochip_set_desc_names() to match reality. Fixes: f881bab038c9667d ("gpio: keep the GPIO line names internal") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200511101828.30046-1-geert+renesas@glider.be Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 48b4f70e2898..fe5f14a417bd 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -296,6 +296,9 @@ static int gpiodev_add_to_list(struct gpio_device *gdev) /* * Convert a GPIO name to its descriptor + * Note that there is no guarantee that GPIO names are globally unique! + * Hence this function will return, if it exists, a reference to the first GPIO + * line found that matches the given name. */ static struct gpio_desc *gpio_name_to_desc(const char * const name) { @@ -329,10 +332,12 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) } /* - * Takes the names from gc->names and checks if they are all unique. If they - * are, they are assigned to their gpio descriptors. + * Take the names from gc->names and assign them to their GPIO descriptors. + * Warn if a name is already used for a GPIO line on a different GPIO chip. * - * Warning if one of the names is already used for a different GPIO. + * Note that: + * 1. Non-unique names are still accepted, + * 2. Name collisions within the same GPIO chip are not reported. */ static int gpiochip_set_desc_names(struct gpio_chip *gc) { -- cgit v1.2.3-59-g8ed1b From 672de5274446fd41167953528da3426805652c1a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 May 2020 21:26:22 +0300 Subject: gpio: mb86s7x: Use devm_clk_get_optional() to get the input clock Simplify the code which fetches the input clock by using devm_clk_get_optional(). If no input clock is present devm_clk_get_optional() will return NULL instead of an error which matches the behavior of the old code. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200512182623.54990-1-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mb86s7x.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index 501e89548f53..3be2e56f7c43 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -168,15 +168,13 @@ static int mb86s70_gpio_probe(struct platform_device *pdev) if (IS_ERR(gchip->base)) return PTR_ERR(gchip->base); - if (!has_acpi_companion(&pdev->dev)) { - gchip->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(gchip->clk)) - return PTR_ERR(gchip->clk); - - ret = clk_prepare_enable(gchip->clk); - if (ret) - return ret; - } + gchip->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(gchip->clk)) + return PTR_ERR(gchip->clk); + + ret = clk_prepare_enable(gchip->clk); + if (ret) + return ret; spin_lock_init(&gchip->lock); -- cgit v1.2.3-59-g8ed1b From db67aa33d58d1497c1e025c7dc34de95e83de529 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 May 2020 21:26:23 +0300 Subject: gpio: mb86s7x: Remove superfluous test for ACPI companion acpi_gpiochip_request_interrupts() will check for ACPI handle of the GPIO chip parent device and bail out if there is none defined. Thus, has_acpi_companion() is effectively repeating above and is not needed in the individual driver. Assigning ->to_irq() unconditionally doesn't change anything, except an error code, but this we fix as well by propagating it from platform_get_irq(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200512182623.54990-2-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mb86s7x.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index 3be2e56f7c43..37c5363e391e 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -145,7 +145,9 @@ static int mb86s70_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) for (index = 0;; index++) { irq = platform_get_irq(to_platform_device(gc->parent), index); - if (irq <= 0) + if (irq < 0) + return irq; + if (irq == 0) break; if (irq_get_irq_data(irq)->hwirq == offset) return irq; @@ -184,15 +186,13 @@ static int mb86s70_gpio_probe(struct platform_device *pdev) gchip->gc.free = mb86s70_gpio_free; gchip->gc.get = mb86s70_gpio_get; gchip->gc.set = mb86s70_gpio_set; + gchip->gc.to_irq = mb86s70_gpio_to_irq; gchip->gc.label = dev_name(&pdev->dev); gchip->gc.ngpio = 32; gchip->gc.owner = THIS_MODULE; gchip->gc.parent = &pdev->dev; gchip->gc.base = -1; - if (has_acpi_companion(&pdev->dev)) - gchip->gc.to_irq = mb86s70_gpio_to_irq; - ret = gpiochip_add_data(&gchip->gc, gchip); if (ret) { dev_err(&pdev->dev, "couldn't register gpio driver\n"); @@ -200,8 +200,7 @@ static int mb86s70_gpio_probe(struct platform_device *pdev) return ret; } - if (has_acpi_companion(&pdev->dev)) - acpi_gpiochip_request_interrupts(&gchip->gc); + acpi_gpiochip_request_interrupts(&gchip->gc); return 0; } @@ -210,8 +209,7 @@ static int mb86s70_gpio_remove(struct platform_device *pdev) { struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); - if (has_acpi_companion(&pdev->dev)) - acpi_gpiochip_free_interrupts(&gchip->gc); + acpi_gpiochip_free_interrupts(&gchip->gc); gpiochip_remove(&gchip->gc); clk_disable_unprepare(gchip->clk); -- cgit v1.2.3-59-g8ed1b From 4d3a050039a98bf12a8b9aa106395ce0c2dd9219 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 May 2020 21:27:19 +0300 Subject: gpio: xgene-sb: Drop redundant OF_GPIO dependency There is nothing in the driver requires OF_GPIO. Moreover, driver supports ACPI and OF_GPIO may be a quite overhead on such configurations. Drop dependency for good and replace of_gpio.h to of.h since we have one function to be defined from there. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200512182721.55127-1-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-xgene-sb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8ef2179fb999..739f179e28b1 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -638,7 +638,7 @@ config GPIO_XGENE config GPIO_XGENE_SB tristate "APM X-Gene GPIO standby controller support" - depends on ARCH_XGENE && OF_GPIO + depends on ARCH_XGENE select GPIO_GENERIC select GPIOLIB_IRQCHIP select IRQ_DOMAIN_HIERARCHY diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index b45bfa9baa26..203a268dd09c 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include #include -- cgit v1.2.3-59-g8ed1b From b24bc583dea7e0cf2d5d68e3325e1689fa7c2275 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 May 2020 21:27:20 +0300 Subject: gpio: xgene-sb: Allow driver to be built with COMPILE_TEST Allow driver to be built with COMPILE_TEST for better test coverage. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200512182721.55127-2-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 739f179e28b1..8fc7893fba2b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -638,7 +638,7 @@ config GPIO_XGENE config GPIO_XGENE_SB tristate "APM X-Gene GPIO standby controller support" - depends on ARCH_XGENE + depends on (ARCH_XGENE || COMPILE_TEST) select GPIO_GENERIC select GPIOLIB_IRQCHIP select IRQ_DOMAIN_HIERARCHY -- cgit v1.2.3-59-g8ed1b From d850c6f42cd8edcb019cfae5f00b1432d0d1a3c5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 May 2020 21:27:21 +0300 Subject: gpio: xgene-sb: Drop extra check to call acpi_gpiochip_request_interrupts() There is no need to have an additional check to call acpi_gpiochip_request_interrupts(). Even without any interrupts available the registered ACPI Event handlers can be useful for debugging purposes. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200512182721.55127-3-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xgene-sb.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index 203a268dd09c..a809609ee957 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -290,10 +290,8 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n"); - if (priv->nirq > 0) { - /* Register interrupt handlers for gpio signaled acpi events */ - acpi_gpiochip_request_interrupts(&priv->gc); - } + /* Register interrupt handlers for GPIO signaled ACPI Events */ + acpi_gpiochip_request_interrupts(&priv->gc); return ret; } @@ -302,9 +300,7 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev) { struct xgene_gpio_sb *priv = platform_get_drvdata(pdev); - if (priv->nirq > 0) { - acpi_gpiochip_free_interrupts(&priv->gc); - } + acpi_gpiochip_free_interrupts(&priv->gc); irq_domain_remove(priv->irq_domain); -- cgit v1.2.3-59-g8ed1b From 22b3bc63da37dc3c24f877951ff7bf60737848cf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 11 May 2020 16:52:52 +0200 Subject: i2c: i801: Use GPIO_LOOKUP() helper macro i801_add_mux() fills in the GPIO lookup table by manually populating an array of gpiod_lookup structures. Use the existing GPIO_LOOKUP() helper macro instead, to relax a dependency on the gpiod_lookup structure's member names. Signed-off-by: Geert Uytterhoeven Reviewed-by: Jean Delvare Link: https://lore.kernel.org/r/20200511145257.22970-2-geert+renesas@glider.be Signed-off-by: Linus Walleij --- drivers/i2c/busses/i2c-i801.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index a9c03f5c3482..4f333889489c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1439,9 +1439,9 @@ static int i801_add_mux(struct i801_priv *priv) return -ENOMEM; lookup->dev_id = "i2c-mux-gpio"; for (i = 0; i < mux_config->n_gpios; i++) { - lookup->table[i].chip_label = mux_config->gpio_chip; - lookup->table[i].chip_hwnum = mux_config->gpios[i]; - lookup->table[i].con_id = "mux"; + lookup->table[i] = (struct gpiod_lookup) + GPIO_LOOKUP(mux_config->gpio_chip, + mux_config->gpios[i], "mux", 0); } gpiod_add_lookup_table(lookup); priv->lookup = lookup; -- cgit v1.2.3-59-g8ed1b From 7b67b836625d9b8350aaec7ecd8347b0336f3f92 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 11 May 2020 16:52:53 +0200 Subject: mfd: sm501: Use GPIO_LOOKUP_IDX() helper macro i801_add_mux() fills in the GPIO lookup table by manually populating an array of gpiod_lookup structures. Use the existing GPIO_LOOKUP_IDX() helper macro instead, to relax a dependency on the gpiod_lookup structure's member names. Signed-off-by: Geert Uytterhoeven Acked-by: Lee Jones Link: https://lore.kernel.org/r/20200511145257.22970-3-geert+renesas@glider.be Signed-off-by: Linus Walleij --- drivers/mfd/sm501.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index e49787e6bb93..ccd62b963952 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1145,22 +1145,14 @@ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, return -ENOMEM; lookup->dev_id = "i2c-gpio"; - if (iic->pin_sda < 32) - lookup->table[0].chip_label = "SM501-LOW"; - else - lookup->table[0].chip_label = "SM501-HIGH"; - lookup->table[0].chip_hwnum = iic->pin_sda % 32; - lookup->table[0].con_id = NULL; - lookup->table[0].idx = 0; - lookup->table[0].flags = GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN; - if (iic->pin_scl < 32) - lookup->table[1].chip_label = "SM501-LOW"; - else - lookup->table[1].chip_label = "SM501-HIGH"; - lookup->table[1].chip_hwnum = iic->pin_scl % 32; - lookup->table[1].con_id = NULL; - lookup->table[1].idx = 1; - lookup->table[1].flags = GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN; + lookup->table[0] = (struct gpiod_lookup) + GPIO_LOOKUP_IDX(iic->pin_sda < 32 ? "SM501-LOW" : "SM501-HIGH", + iic->pin_sda % 32, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN); + lookup->table[1] = (struct gpiod_lookup) + GPIO_LOOKUP_IDX(iic->pin_scl < 32 ? "SM501-LOW" : "SM501-HIGH", + iic->pin_scl % 32, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN); gpiod_add_lookup_table(lookup); icd = dev_get_platdata(&pdev->dev); -- cgit v1.2.3-59-g8ed1b From 4c033b549912bc301c5e2adfb7b6ca007c11bf31 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 11 May 2020 16:52:54 +0200 Subject: gpiolib: Add support for GPIO lookup by line name Currently a GPIO lookup table can only refer to a specific GPIO by a tuple, consisting of a GPIO controller label and a GPIO offset inside the controller. However, a GPIO may also carry a line name, defined by DT or ACPI. If present, the line name is the most use-centric way to refer to a GPIO. Hence add support for looking up GPIOs by line name. Note that there is no guarantee that GPIO line names are globally unique, so this will use the first match found. Implement this by reusing the existing gpiod_lookup infrastructure. Rename gpiod_lookup.chip_label to gpiod_lookup.key, to make it clear that this field can have two meanings, and update the kerneldoc and GPIO_LOOKUP*() macros. Signed-off-by: Geert Uytterhoeven Tested-by: Eugeniu Rosca Reviewed-by: Ulrich Hecht Reviewed-by: Eugeniu Rosca Link: https://lore.kernel.org/r/20200511145257.22970-4-geert+renesas@glider.be Signed-off-by: Linus Walleij --- Documentation/driver-api/gpio/board.rst | 15 ++++++++++----- drivers/gpio/gpiolib.c | 22 +++++++++++++++++----- include/linux/gpio/machine.h | 17 ++++++++++------- 3 files changed, 37 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/Documentation/driver-api/gpio/board.rst b/Documentation/driver-api/gpio/board.rst index ce91518bf9f4..191fa867826a 100644 --- a/Documentation/driver-api/gpio/board.rst +++ b/Documentation/driver-api/gpio/board.rst @@ -113,13 +113,15 @@ files that desire to do so need to include the following header:: GPIOs are mapped by the means of tables of lookups, containing instances of the gpiod_lookup structure. Two macros are defined to help declaring such mappings:: - GPIO_LOOKUP(chip_label, chip_hwnum, con_id, flags) - GPIO_LOOKUP_IDX(chip_label, chip_hwnum, con_id, idx, flags) + GPIO_LOOKUP(key, chip_hwnum, con_id, flags) + GPIO_LOOKUP_IDX(key, chip_hwnum, con_id, idx, flags) where - - chip_label is the label of the gpiod_chip instance providing the GPIO - - chip_hwnum is the hardware number of the GPIO within the chip + - key is either the label of the gpiod_chip instance providing the GPIO, or + the GPIO line name + - chip_hwnum is the hardware number of the GPIO within the chip, or U16_MAX + to indicate that key is a GPIO line name - con_id is the name of the GPIO function from the device point of view. It can be NULL, in which case it will match any function. - idx is the index of the GPIO within the function. @@ -135,7 +137,10 @@ where In the future, these flags might be extended to support more properties. -Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0. +Note that: + 1. GPIO line names are not guaranteed to be globally unique, so the first + match found will be used. + 2. GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0. A lookup table can then be defined as follows, with an empty entry defining its end. The 'dev_id' field of the table is the identifier of the device that will diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 40f2d7f69be2..3c1dcdfe8572 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4618,7 +4618,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, if (!table) return desc; - for (p = &table->table[0]; p->chip_label; p++) { + for (p = &table->table[0]; p->key; p++) { struct gpio_chip *gc; /* idx must always match exactly */ @@ -4629,18 +4629,30 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) continue; - gc = find_chip_by_name(p->chip_label); + if (p->chip_hwnum == U16_MAX) { + desc = gpio_name_to_desc(p->key); + if (desc) { + *flags = p->flags; + return desc; + } + + dev_warn(dev, "cannot find GPIO line %s, deferring\n", + p->key); + return ERR_PTR(-EPROBE_DEFER); + } + + gc = find_chip_by_name(p->key); if (!gc) { /* * As the lookup table indicates a chip with - * p->chip_label should exist, assume it may + * p->key should exist, assume it may * still appear later and let the interested * consumer be probed again or let the Deferred * Probe infrastructure handle the error. */ dev_warn(dev, "cannot find GPIO chip %s, deferring\n", - p->chip_label); + p->key); return ERR_PTR(-EPROBE_DEFER); } @@ -4671,7 +4683,7 @@ static int platform_gpio_count(struct device *dev, const char *con_id) if (!table) return -ENOENT; - for (p = &table->table[0]; p->chip_label; p++) { + for (p = &table->table[0]; p->key; p++) { if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) || (!con_id && !p->con_id)) count++; diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h index 1ebe5be05d5f..781a053abbb9 100644 --- a/include/linux/gpio/machine.h +++ b/include/linux/gpio/machine.h @@ -20,8 +20,11 @@ enum gpio_lookup_flags { /** * struct gpiod_lookup - lookup table - * @chip_label: name of the chip the GPIO belongs to - * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO + * @key: either the name of the chip the GPIO belongs to, or the GPIO line name + * Note that GPIO line names are not guaranteed to be globally unique, + * so this will use the first match found! + * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO, or + * U16_MAX to indicate that @key is a GPIO line name * @con_id: name of the GPIO from the device's point of view * @idx: index of the GPIO in case several GPIOs share the same name * @flags: bitmask of gpio_lookup_flags GPIO_* values @@ -30,7 +33,7 @@ enum gpio_lookup_flags { * functions using platform data. */ struct gpiod_lookup { - const char *chip_label; + const char *key; u16 chip_hwnum; const char *con_id; unsigned int idx; @@ -63,17 +66,17 @@ struct gpiod_hog { /* * Simple definition of a single GPIO under a con_id */ -#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \ - GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags) +#define GPIO_LOOKUP(_key, _chip_hwnum, _con_id, _flags) \ + GPIO_LOOKUP_IDX(_key, _chip_hwnum, _con_id, 0, _flags) /* * Use this macro if you need to have several GPIOs under the same con_id. * Each GPIO needs to use a different index and can be accessed using * gpiod_get_index() */ -#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags) \ +#define GPIO_LOOKUP_IDX(_key, _chip_hwnum, _con_id, _idx, _flags) \ { \ - .chip_label = _chip_label, \ + .key = _key, \ .chip_hwnum = _chip_hwnum, \ .con_id = _con_id, \ .idx = _idx, \ -- cgit v1.2.3-59-g8ed1b From 828546e24280f721350a7a0dcc92416e917b4382 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 11 May 2020 16:52:55 +0200 Subject: gpio: Add GPIO Aggregator GPIO controllers are exported to userspace using /dev/gpiochip* character devices. Access control to these devices is provided by standard UNIX file system permissions, on an all-or-nothing basis: either a GPIO controller is accessible for a user, or it is not. Currently no mechanism exists to control access to individual GPIOs. Hence add a GPIO driver to aggregate existing GPIOs, and expose them as a new gpiochip. This supports the following use cases: - Aggregating GPIOs using Sysfs This is useful for implementing access control, and assigning a set of GPIOs to a specific user or virtual machine. - Generic GPIO Driver This is useful for industrial control, where it can provide userspace access to a simple GPIO-operated device described in DT, cfr. e.g. spidev for SPI-operated devices. Signed-off-by: Geert Uytterhoeven Tested-by: Eugeniu Rosca Reviewed-by: Eugeniu Rosca Link: https://lore.kernel.org/r/20200511145257.22970-5-geert+renesas@glider.be Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 12 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-aggregator.c | 568 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 581 insertions(+) create mode 100644 drivers/gpio/gpio-aggregator.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1b96169d84f7..cf45dfa079ee 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1541,6 +1541,18 @@ config GPIO_VIPERBOARD endmenu +config GPIO_AGGREGATOR + tristate "GPIO Aggregator" + help + Say yes here to enable the GPIO Aggregator, which provides a way to + aggregate existing GPIO lines into a new virtual GPIO chip. + This can serve the following purposes: + - Assign permissions for a collection of GPIO lines to a user, + - Export a collection of GPIO lines to a virtual machine, + - Provide a generic driver for a GPIO-operated device in an + industrial control context, to be operated from userspace using + the GPIO chardev interface. + config GPIO_MOCKUP tristate "GPIO Testing Driver" select IRQ_SIM diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index b2cfc21a97f3..65bf3940e33c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o +obj-$(CONFIG_GPIO_AGGREGATOR) += gpio-aggregator.o obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c new file mode 100644 index 000000000000..9b0adbdddbfc --- /dev/null +++ b/drivers/gpio/gpio-aggregator.c @@ -0,0 +1,568 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// GPIO Aggregator +// +// Copyright (C) 2019-2020 Glider bv + +#define DRV_NAME "gpio-aggregator" +#define pr_fmt(fmt) DRV_NAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * GPIO Aggregator sysfs interface + */ + +struct gpio_aggregator { + struct gpiod_lookup_table *lookups; + struct platform_device *pdev; + char args[]; +}; + +static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */ +static DEFINE_IDR(gpio_aggregator_idr); + +static char *get_arg(char **args) +{ + char *start = *args, *end; + + start = skip_spaces(start); + if (!*start) + return NULL; + + if (*start == '"') { + /* Quoted arg */ + end = strchr(++start, '"'); + if (!end) + return ERR_PTR(-EINVAL); + } else { + /* Unquoted arg */ + for (end = start; *end && !isspace(*end); end++) ; + } + + if (*end) + *end++ = '\0'; + + *args = end; + return start; +} + +static bool isrange(const char *s) +{ + size_t n; + + if (IS_ERR_OR_NULL(s)) + return false; + + while (1) { + n = strspn(s, "0123456789"); + if (!n) + return false; + + s += n; + + switch (*s++) { + case '\0': + return true; + + case '-': + case ',': + break; + + default: + return false; + } + } +} + +static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, + int hwnum, unsigned int *n) +{ + struct gpiod_lookup_table *lookups; + + lookups = krealloc(aggr->lookups, struct_size(lookups, table, *n + 2), + GFP_KERNEL); + if (!lookups) + return -ENOMEM; + + lookups->table[*n] = + (struct gpiod_lookup)GPIO_LOOKUP_IDX(key, hwnum, NULL, *n, 0); + + (*n)++; + memset(&lookups->table[*n], 0, sizeof(lookups->table[*n])); + + aggr->lookups = lookups; + return 0; +} + +static int aggr_parse(struct gpio_aggregator *aggr) +{ + unsigned int first_index, last_index, i, n = 0; + char *name, *offsets, *first, *last, *next; + char *args = aggr->args; + int error; + + for (name = get_arg(&args), offsets = get_arg(&args); name; + offsets = get_arg(&args)) { + if (IS_ERR(name)) { + pr_err("Cannot get GPIO specifier: %pe\n", name); + return PTR_ERR(name); + } + + if (!isrange(offsets)) { + /* Named GPIO line */ + error = aggr_add_gpio(aggr, name, U16_MAX, &n); + if (error) + return error; + + name = offsets; + continue; + } + + /* GPIO chip + offset(s) */ + for (first = offsets; *first; first = next) { + next = strchrnul(first, ','); + if (*next) + *next++ = '\0'; + + last = strchr(first, '-'); + if (last) + *last++ = '\0'; + + if (kstrtouint(first, 10, &first_index)) { + pr_err("Cannot parse GPIO index %s\n", first); + return -EINVAL; + } + + if (!last) { + last_index = first_index; + } else if (kstrtouint(last, 10, &last_index)) { + pr_err("Cannot parse GPIO index %s\n", last); + return -EINVAL; + } + + for (i = first_index; i <= last_index; i++) { + error = aggr_add_gpio(aggr, name, i, &n); + if (error) + return error; + } + } + + name = get_arg(&args); + } + + if (!n) { + pr_err("No GPIOs specified\n"); + return -EINVAL; + } + + return 0; +} + +static ssize_t new_device_store(struct device_driver *driver, const char *buf, + size_t count) +{ + struct gpio_aggregator *aggr; + struct platform_device *pdev; + int res, id; + + /* kernfs guarantees string termination, so count + 1 is safe */ + aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); + if (!aggr) + return -ENOMEM; + + memcpy(aggr->args, buf, count + 1); + + aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), + GFP_KERNEL); + if (!aggr->lookups) { + res = -ENOMEM; + goto free_ga; + } + + mutex_lock(&gpio_aggregator_lock); + id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); + mutex_unlock(&gpio_aggregator_lock); + + if (id < 0) { + res = id; + goto free_table; + } + + aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); + if (!aggr->lookups->dev_id) { + res = -ENOMEM; + goto remove_idr; + } + + res = aggr_parse(aggr); + if (res) + goto free_dev_id; + + gpiod_add_lookup_table(aggr->lookups); + + pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0); + if (IS_ERR(pdev)) { + res = PTR_ERR(pdev); + goto remove_table; + } + + aggr->pdev = pdev; + return count; + +remove_table: + gpiod_remove_lookup_table(aggr->lookups); +free_dev_id: + kfree(aggr->lookups->dev_id); +remove_idr: + mutex_lock(&gpio_aggregator_lock); + idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); +free_table: + kfree(aggr->lookups); +free_ga: + kfree(aggr); + return res; +} + +static DRIVER_ATTR_WO(new_device); + +static void gpio_aggregator_free(struct gpio_aggregator *aggr) +{ + platform_device_unregister(aggr->pdev); + gpiod_remove_lookup_table(aggr->lookups); + kfree(aggr->lookups->dev_id); + kfree(aggr->lookups); + kfree(aggr); +} + +static ssize_t delete_device_store(struct device_driver *driver, + const char *buf, size_t count) +{ + struct gpio_aggregator *aggr; + unsigned int id; + int error; + + if (!str_has_prefix(buf, DRV_NAME ".")) + return -EINVAL; + + error = kstrtouint(buf + strlen(DRV_NAME "."), 10, &id); + if (error) + return error; + + mutex_lock(&gpio_aggregator_lock); + aggr = idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); + if (!aggr) + return -ENOENT; + + gpio_aggregator_free(aggr); + return count; +} +static DRIVER_ATTR_WO(delete_device); + +static struct attribute *gpio_aggregator_attrs[] = { + &driver_attr_new_device.attr, + &driver_attr_delete_device.attr, + NULL, +}; +ATTRIBUTE_GROUPS(gpio_aggregator); + +static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) +{ + gpio_aggregator_free(p); + return 0; +} + +static void __exit gpio_aggregator_remove_all(void) +{ + mutex_lock(&gpio_aggregator_lock); + idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL); + idr_destroy(&gpio_aggregator_idr); + mutex_unlock(&gpio_aggregator_lock); +} + + +/* + * GPIO Forwarder + */ + +struct gpiochip_fwd { + struct gpio_chip chip; + struct gpio_desc **descs; + union { + struct mutex mlock; /* protects tmp[] if can_sleep */ + spinlock_t slock; /* protects tmp[] if !can_sleep */ + }; + unsigned long tmp[]; /* values and descs for multiple ops */ +}; + +static int gpio_fwd_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + return gpiod_get_direction(fwd->descs[offset]); +} + +static int gpio_fwd_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + return gpiod_direction_input(fwd->descs[offset]); +} + +static int gpio_fwd_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + return gpiod_direction_output(fwd->descs[offset], value); +} + +static int gpio_fwd_get(struct gpio_chip *chip, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + return gpiod_get_value(fwd->descs[offset]); +} + +static int gpio_fwd_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + unsigned long *values, flags = 0; + struct gpio_desc **descs; + unsigned int i, j = 0; + int error; + + if (chip->can_sleep) + mutex_lock(&fwd->mlock); + else + spin_lock_irqsave(&fwd->slock, flags); + + /* Both values bitmap and desc pointers are stored in tmp[] */ + values = &fwd->tmp[0]; + descs = (void *)&fwd->tmp[BITS_TO_LONGS(fwd->chip.ngpio)]; + + bitmap_clear(values, 0, fwd->chip.ngpio); + for_each_set_bit(i, mask, fwd->chip.ngpio) + descs[j++] = fwd->descs[i]; + + error = gpiod_get_array_value(j, descs, NULL, values); + if (!error) { + j = 0; + for_each_set_bit(i, mask, fwd->chip.ngpio) + __assign_bit(i, bits, test_bit(j++, values)); + } + + if (chip->can_sleep) + mutex_unlock(&fwd->mlock); + else + spin_unlock_irqrestore(&fwd->slock, flags); + + return error; +} + +static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + gpiod_set_value(fwd->descs[offset], value); +} + +static void gpio_fwd_set_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + unsigned long *values, flags = 0; + struct gpio_desc **descs; + unsigned int i, j = 0; + + if (chip->can_sleep) + mutex_lock(&fwd->mlock); + else + spin_lock_irqsave(&fwd->slock, flags); + + /* Both values bitmap and desc pointers are stored in tmp[] */ + values = &fwd->tmp[0]; + descs = (void *)&fwd->tmp[BITS_TO_LONGS(fwd->chip.ngpio)]; + + for_each_set_bit(i, mask, fwd->chip.ngpio) { + __assign_bit(j, values, test_bit(i, bits)); + descs[j++] = fwd->descs[i]; + } + + gpiod_set_array_value(j, descs, NULL, values); + + if (chip->can_sleep) + mutex_unlock(&fwd->mlock); + else + spin_unlock_irqrestore(&fwd->slock, flags); +} + +static int gpio_fwd_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + return gpiod_set_config(fwd->descs[offset], config); +} + +/** + * gpiochip_fwd_create() - Create a new GPIO forwarder + * @dev: Parent device pointer + * @ngpios: Number of GPIOs in the forwarder. + * @descs: Array containing the GPIO descriptors to forward to. + * This array must contain @ngpios entries, and must not be deallocated + * before the forwarder has been destroyed again. + * + * This function creates a new gpiochip, which forwards all GPIO operations to + * the passed GPIO descriptors. + * + * Return: An opaque object pointer, or an ERR_PTR()-encoded negative error + * code on failure. + */ +static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, + unsigned int ngpios, + struct gpio_desc *descs[]) +{ + const char *label = dev_name(dev); + struct gpiochip_fwd *fwd; + struct gpio_chip *chip; + unsigned int i; + int error; + + fwd = devm_kzalloc(dev, struct_size(fwd, tmp, + BITS_TO_LONGS(ngpios) + ngpios), GFP_KERNEL); + if (!fwd) + return ERR_PTR(-ENOMEM); + + chip = &fwd->chip; + + /* + * If any of the GPIO lines are sleeping, then the entire forwarder + * will be sleeping. + * If any of the chips support .set_config(), then the forwarder will + * support setting configs. + */ + for (i = 0; i < ngpios; i++) { + struct gpio_chip *parent = gpiod_to_chip(descs[i]); + + dev_dbg(dev, "%u => gpio-%d\n", i, desc_to_gpio(descs[i])); + + if (gpiod_cansleep(descs[i])) + chip->can_sleep = true; + if (parent && parent->set_config) + chip->set_config = gpio_fwd_set_config; + } + + chip->label = label; + chip->parent = dev; + chip->owner = THIS_MODULE; + chip->get_direction = gpio_fwd_get_direction; + chip->direction_input = gpio_fwd_direction_input; + chip->direction_output = gpio_fwd_direction_output; + chip->get = gpio_fwd_get; + chip->get_multiple = gpio_fwd_get_multiple; + chip->set = gpio_fwd_set; + chip->set_multiple = gpio_fwd_set_multiple; + chip->base = -1; + chip->ngpio = ngpios; + fwd->descs = descs; + + if (chip->can_sleep) + mutex_init(&fwd->mlock); + else + spin_lock_init(&fwd->slock); + + error = devm_gpiochip_add_data(dev, chip, fwd); + if (error) + return ERR_PTR(error); + + return fwd; +} + + +/* + * GPIO Aggregator platform device + */ + +static int gpio_aggregator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gpio_desc **descs; + struct gpiochip_fwd *fwd; + int i, n; + + n = gpiod_count(dev, NULL); + if (n < 0) + return n; + + descs = devm_kmalloc_array(dev, n, sizeof(*descs), GFP_KERNEL); + if (!descs) + return -ENOMEM; + + for (i = 0; i < n; i++) { + descs[i] = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS); + if (IS_ERR(descs[i])) + return PTR_ERR(descs[i]); + } + + fwd = gpiochip_fwd_create(dev, n, descs); + if (IS_ERR(fwd)) + return PTR_ERR(fwd); + + platform_set_drvdata(pdev, fwd); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id gpio_aggregator_dt_ids[] = { + /* + * Add GPIO-operated devices controlled from userspace below, + * or use "driver_override" in sysfs + */ + {}, +}; +MODULE_DEVICE_TABLE(of, gpio_aggregator_dt_ids); +#endif + +static struct platform_driver gpio_aggregator_driver = { + .probe = gpio_aggregator_probe, + .driver = { + .name = DRV_NAME, + .groups = gpio_aggregator_groups, + .of_match_table = of_match_ptr(gpio_aggregator_dt_ids), + }, +}; + +static int __init gpio_aggregator_init(void) +{ + return platform_driver_register(&gpio_aggregator_driver); +} +module_init(gpio_aggregator_init); + +static void __exit gpio_aggregator_exit(void) +{ + gpio_aggregator_remove_all(); + platform_driver_unregister(&gpio_aggregator_driver); +} +module_exit(gpio_aggregator_exit); + +MODULE_AUTHOR("Geert Uytterhoeven "); +MODULE_DESCRIPTION("GPIO Aggregator"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 47a3734b03904bbccbba0c8f78cf2b0f0aa157e7 Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar <455.rodrigo.alencar@gmail.com> Date: Thu, 14 May 2020 10:00:12 -0300 Subject: gpio: max730x: bring gpiochip_add_data after port config gpiochip_add_data being called before might cause premature calls of the gpiochip operations before the port_config values are initialized, which would possibily write zeros to port configuration registers, an operation not allowed. For example, if there are gpio-hog nodes in a device-tree, the sequence of function calls are performed gpiochip_add_data of_gpiochip_add of_gpiochip_scan_gpios of_gpiochip_add_hog gpiod_hog gpiochip_request_own_desc gpiod_configure_flags gpiod_direction_output/gpiod_direction_input which would call later the gpiochip operation direction_output or direction_input prior the port_config[] initialization. Moreover, gpiochip_get_data is replaced by the container_of macro inside the gpiochip operations, which would allow the calling of max7301_direction_input prior to gpiochip_add_data Signed-off-by: Rodrigo Alencar <455.rodrigo.alencar@gmail.com> [Bartosz: tweaked the commit message] Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-max730x.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 1e1935c51096..b8c1fe20f49a 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -47,7 +47,7 @@ static int max7301_direction_input(struct gpio_chip *chip, unsigned offset) { - struct max7301 *ts = gpiochip_get_data(chip); + struct max7301 *ts = container_of(chip, struct max7301, chip); u8 *config; u8 offset_bits, pin_config; int ret; @@ -89,7 +89,7 @@ static int __max7301_set(struct max7301 *ts, unsigned offset, int value) static int max7301_direction_output(struct gpio_chip *chip, unsigned offset, int value) { - struct max7301 *ts = gpiochip_get_data(chip); + struct max7301 *ts = container_of(chip, struct max7301, chip); u8 *config; u8 offset_bits; int ret; @@ -189,10 +189,6 @@ int __max730x_probe(struct max7301 *ts) ts->chip.parent = dev; ts->chip.owner = THIS_MODULE; - ret = gpiochip_add_data(&ts->chip, ts); - if (ret) - goto exit_destroy; - /* * initialize pullups according to platform data and cache the * register values for later use. @@ -214,7 +210,9 @@ int __max730x_probe(struct max7301 *ts) } } - return ret; + ret = gpiochip_add_data(&ts->chip, ts); + if (!ret) + return ret; exit_destroy: mutex_destroy(&ts->lock); -- cgit v1.2.3-59-g8ed1b From 494a94e38dcf62543a32a4424d646ff80b4b28bd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 May 2020 16:12:30 +0300 Subject: gpio: dwapb: Call acpi_gpiochip_free_interrupts() on GPIO chip de-registration Add missed acpi_gpiochip_free_interrupts() call when unregistering ports. While at it, drop extra check to call acpi_gpiochip_request_interrupts(). There is no need to have an additional check to call acpi_gpiochip_request_interrupts(). Even without any interrupts available the registered ACPI Event handlers can be useful for debugging purposes. Fixes: e6cb3486f5a1 ("gpio: dwapb: add gpio-signaled acpi event support") Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Acked-by: Serge Semin Link: https://lore.kernel.org/r/20200519131233.59032-1-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 8639c4a7f469..e5d844304f8d 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -505,26 +505,33 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, dwapb_configure_irqs(gpio, port, pp); err = gpiochip_add_data(&port->gc, port); - if (err) + if (err) { dev_err(gpio->dev, "failed to register gpiochip for port%d\n", port->idx); - else - port->is_registered = true; + return err; + } /* Add GPIO-signaled ACPI event support */ - if (pp->has_irq) - acpi_gpiochip_request_interrupts(&port->gc); + acpi_gpiochip_request_interrupts(&port->gc); - return err; + port->is_registered = true; + + return 0; } static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) { unsigned int m; - for (m = 0; m < gpio->nr_ports; ++m) - if (gpio->ports[m].is_registered) - gpiochip_remove(&gpio->ports[m].gc); + for (m = 0; m < gpio->nr_ports; ++m) { + struct dwapb_gpio_port *port = &gpio->ports[m]; + + if (!port->is_registered) + continue; + + acpi_gpiochip_free_interrupts(&port->gc); + gpiochip_remove(&port->gc); + } } static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode, -- cgit v1.2.3-59-g8ed1b From d7cc23604f367c0d0f272f0af55e2032de50a053 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 May 2020 16:12:31 +0300 Subject: gpio: dwapb: avoid error message for optional IRQ platform_get_irq() will generate an error message if the requested IRQ is not present. Use platform_get_irq_optional() to avoid the error message being generated. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Reviewed-by: Serge Semin Acked-by: Serge Semin Link: https://lore.kernel.org/r/20200519131233.59032-2-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index e5d844304f8d..944dae80d687 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -549,7 +549,7 @@ static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode, if (np) pp->irq[j] = of_irq_get(np, j); else if (has_acpi_companion(dev)) - pp->irq[j] = platform_get_irq(to_platform_device(dev), j); + pp->irq[j] = platform_get_irq_optional(to_platform_device(dev), j); if (pp->irq[j] >= 0) pp->has_irq = true; -- cgit v1.2.3-59-g8ed1b From aa90939d22973765cc6318c6748c272b954e202f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 May 2020 16:12:32 +0300 Subject: gpio: dwapb: Don't use IRQ 0 as valid Linux interrupt IRQ 0 is not valid in Linux interrupt number space. Refactor the code with this kept in mind. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Acked-by: Serge Semin Link: https://lore.kernel.org/r/20200519131233.59032-3-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 944dae80d687..d3765672c42b 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -417,7 +417,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, int i; for (i = 0; i < pp->ngpio; i++) { - if (pp->irq[i] >= 0) + if (pp->irq[i]) irq_set_chained_handler_and_data(pp->irq[i], dwapb_irq_handler, gpio); } @@ -538,20 +538,20 @@ static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode, struct dwapb_port_property *pp) { struct device_node *np = NULL; - int j; + int irq = -ENXIO, j; if (fwnode_property_read_bool(fwnode, "interrupt-controller")) np = to_of_node(fwnode); for (j = 0; j < pp->ngpio; j++) { - pp->irq[j] = -ENXIO; - if (np) - pp->irq[j] = of_irq_get(np, j); + irq = of_irq_get(np, j); else if (has_acpi_companion(dev)) - pp->irq[j] = platform_get_irq_optional(to_platform_device(dev), j); + irq = platform_get_irq_optional(to_platform_device(dev), j); + if (irq > 0) + pp->irq[j] = irq; - if (pp->irq[j] >= 0) + if (pp->irq[j]) pp->has_irq = true; } -- cgit v1.2.3-59-g8ed1b From 551cb86cbb7d85a3d16d10f6fb4fb954f13a7556 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 May 2020 16:12:33 +0300 Subject: gpio: dwapb: Remove unneeded has_irq member in struct dwapb_port_property has_irq member of struct dwapb_port_property is used only in one place, so, make it local test instead and remove from the structure. This local test is using memchr_inv() which is quite efficient in comparison to the original loop and possible little overhead can be neglected. Signed-off-by: Andy Shevchenko Tested-by: Serge Semin Acked-by: Lee Jones Acked-by: Serge Semin Link: https://lore.kernel.org/r/20200519131233.59032-4-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 14 +++++++------- drivers/mfd/intel_quark_i2c_gpio.c | 1 - include/linux/platform_data/gpio-dwapb.h | 1 - 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index d3765672c42b..1d8d55bd63aa 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -366,6 +366,11 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, irq_hw_number_t hwirq; int err, i; + if (memchr_inv(pp->irq, 0, sizeof(pp->irq)) == NULL) { + dev_warn(gpio->dev, "no IRQ for port%d\n", pp->idx); + return; + } + gpio->domain = irq_domain_create_linear(fwnode, ngpio, &irq_generic_chip_ops, gpio); if (!gpio->domain) @@ -501,7 +506,8 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, if (pp->idx == 0) port->gc.set_config = dwapb_gpio_set_config; - if (pp->has_irq) + /* Only port A can provide interrupts in all configurations of the IP */ + if (pp->idx == 0) dwapb_configure_irqs(gpio, port, pp); err = gpiochip_add_data(&port->gc, port); @@ -550,13 +556,7 @@ static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode, irq = platform_get_irq_optional(to_platform_device(dev), j); if (irq > 0) pp->irq[j] = irq; - - if (pp->irq[j]) - pp->has_irq = true; } - - if (!pp->has_irq) - dev_warn(dev, "no irq for port%d\n", pp->idx); } static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev) diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 41326b48da55..84ca7902e1df 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -216,7 +216,6 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell) pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO; pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE; pdata->properties->irq[0] = pdev->irq; - pdata->properties->has_irq = true; pdata->properties->irq_shared = true; cell->platform_data = pdata; diff --git a/include/linux/platform_data/gpio-dwapb.h b/include/linux/platform_data/gpio-dwapb.h index 3c606c450d05..ff1be737bad6 100644 --- a/include/linux/platform_data/gpio-dwapb.h +++ b/include/linux/platform_data/gpio-dwapb.h @@ -12,7 +12,6 @@ struct dwapb_port_property { unsigned int ngpio; unsigned int gpio_base; int irq[32]; - bool has_irq; bool irq_shared; }; -- cgit v1.2.3-59-g8ed1b From 22e4ebd05890cf2d9423ed7a35f18b0937c0cb3b Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Fri, 22 May 2020 12:12:20 +0800 Subject: gpio: pxa: Add COMPILE_TEST support Add COMPILE_TEST support to the PXA GPIO driver for better compile testing coverage. Signed-off-by: Tiezhu Yang Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8ef2179fb999..beccdc1d0467 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -439,7 +439,7 @@ config GPIO_PMIC_EIC_SPRD config GPIO_PXA bool "PXA GPIO support" - depends on ARCH_PXA || ARCH_MMP + depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST help Say yes here to support the PXA GPIO device -- cgit v1.2.3-59-g8ed1b From e33a58a29c6ad6f844cdc184210aa1feb5e2fbe0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 21 May 2020 00:19:15 +0300 Subject: gpio: pca935x: Allow IRQ support for driver built as a module Perhaps by some historical reasons the IRQ support has been allowed only for built-in driver. However, there is nothing prevents us to build it as module an use as IRQ chip. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index beccdc1d0467..78958c8aaf92 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -952,7 +952,7 @@ config GPIO_PCA953X config GPIO_PCA953X_IRQ bool "Interrupt controller support for PCA953x" - depends on GPIO_PCA953X=y + depends on GPIO_PCA953X select GPIOLIB_IRQCHIP help Say yes here to enable the pca953x to be used as an interrupt -- cgit v1.2.3-59-g8ed1b From 6f8cd246411575703d9312888b70705c396b53a9 Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Fri, 22 May 2020 16:08:38 +0800 Subject: gpio: rcar: Fix runtime PM imbalance on error pm_runtime_get_sync() increments the runtime PM usage counter even when it returns an error code. Thus a pairing decrement is needed on the error handling path to keep the counter balanced. Signed-off-by: Dinghao Liu Link: https://lore.kernel.org/r/20200522080839.32612-1-dinghao.liu@zju.edu.cn Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 7284473c9fe3..eac1582c70da 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -250,8 +250,10 @@ static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset) int error; error = pm_runtime_get_sync(p->dev); - if (error < 0) + if (error < 0) { + pm_runtime_put(p->dev); return error; + } error = pinctrl_gpio_request(chip->base + offset); if (error) -- cgit v1.2.3-59-g8ed1b From a34d5e56315007519f6c748e3ca0cb367264bbda Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 May 2020 22:40:28 +0300 Subject: gpiolib: Separate GPIO_GET_LINEINFO_WATCH_IOCTL conditional We already have two conditionals inside the outer one to check if the command is GPIO_GET_LINEINFO_WATCH_IOCTL. I think it's time to actually do what I have proposed in the first place, i.e. to separate GPIO_GET_LINEINFO_WATCH_IOCTL from GPIO_GET_LINEINFO_IOCTL. It's +13 LOCs, and surprisingly only +13 bytes of binary on x86_32, but for the price of much better readability. Signed-off-by: Andy Shevchenko Acked-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20200525194028.74236-1-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2e4aacbad8fe..34259c1e78ca 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1265,8 +1265,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_to_user(ip, &chipinfo, sizeof(chipinfo))) return -EFAULT; return 0; - } else if (cmd == GPIO_GET_LINEINFO_IOCTL || - cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) { + } else if (cmd == GPIO_GET_LINEINFO_IOCTL) { struct gpioline_info lineinfo; if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) @@ -1278,23 +1277,37 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) hwgpio = gpio_chip_hwgpio(desc); - if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL && - test_bit(hwgpio, priv->watched_lines)) - return -EBUSY; - gpio_desc_to_lineinfo(desc, &lineinfo); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; - - if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) - set_bit(hwgpio, priv->watched_lines); - return 0; } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { return linehandle_create(gdev, ip); } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) { return lineevent_create(gdev, ip); + } else if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) { + struct gpioline_info lineinfo; + + if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) + return -EFAULT; + + desc = gpiochip_get_desc(gc, lineinfo.line_offset); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + hwgpio = gpio_chip_hwgpio(desc); + + if (test_bit(hwgpio, priv->watched_lines)) + return -EBUSY; + + gpio_desc_to_lineinfo(desc, &lineinfo); + + if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) + return -EFAULT; + + set_bit(hwgpio, priv->watched_lines); + return 0; } else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) { if (copy_from_user(&offset, ip, sizeof(offset))) return -EFAULT; -- cgit v1.2.3-59-g8ed1b From a8173820f441ab3e2a45c4bb66b70da9a57a349e Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Sat, 23 May 2020 22:41:10 +0530 Subject: gpio: gpiolib: Allow GPIO IRQs to lazy disable With 'commit 461c1a7d4733 ("gpiolib: override irq_enable/disable")' gpiolib overrides irqchip's irq_enable and irq_disable callbacks. If irq_disable callback is implemented then genirq takes unlazy path to disable irq. Underlying irqchip may not want to implement irq_disable callback to lazy disable irq when client drivers invokes disable_irq(). By overriding irq_disable callback, gpiolib ends up always unlazy disabling IRQ. Allow gpiolib to lazy disable IRQs by overriding irq_disable callback only if irqchip implemented irq_disable. In cases where irq_disable is not implemented irq_mask is overridden. Similarly override irq_enable callback only if irqchip implemented irq_enable otherwise irq_unmask is overridden. Fixes: 461c1a7d4733 ("gpiolib: override irq_enable/disable") Signed-off-by: Maulik Shah Tested-by: Hans Verkuil Link: https://lore.kernel.org/r/1590253873-11556-2-git-send-email-mkshah@codeaurora.org Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 55 +++++++++++++++++++++++++++++---------------- include/linux/gpio/driver.h | 13 +++++++++++ 2 files changed, 49 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 34259c1e78ca..167860684be6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2471,32 +2471,37 @@ static void gpiochip_irq_relres(struct irq_data *d) gpiochip_relres_irq(gc, d->hwirq); } +static void gpiochip_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + if (gc->irq.irq_mask) + gc->irq.irq_mask(d); + gpiochip_disable_irq(gc, d->hwirq); +} + +static void gpiochip_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, d->hwirq); + if (gc->irq.irq_unmask) + gc->irq.irq_unmask(d); +} + static void gpiochip_irq_enable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); gpiochip_enable_irq(gc, d->hwirq); - if (gc->irq.irq_enable) - gc->irq.irq_enable(d); - else - gc->irq.chip->irq_unmask(d); + 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); - /* - * Since we override .irq_disable() we need to mimic the - * behaviour of __irq_disable() in irq/chip.c. - * First call .irq_disable() if it exists, else mimic the - * behaviour of mask_irq() which calls .irq_mask() if - * it exists. - */ - if (gc->irq.irq_disable) - gc->irq.irq_disable(d); - else if (gc->irq.chip->irq_mask) - gc->irq.chip->irq_mask(d); + gc->irq.irq_disable(d); gpiochip_disable_irq(gc, d->hwirq); } @@ -2521,10 +2526,22 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc) "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n"); return; } - gc->irq.irq_enable = irqchip->irq_enable; - gc->irq.irq_disable = irqchip->irq_disable; - irqchip->irq_enable = gpiochip_irq_enable; - irqchip->irq_disable = gpiochip_irq_disable; + + if (irqchip->irq_disable) { + gc->irq.irq_disable = irqchip->irq_disable; + irqchip->irq_disable = gpiochip_irq_disable; + } else { + gc->irq.irq_mask = irqchip->irq_mask; + irqchip->irq_mask = gpiochip_irq_mask; + } + + if (irqchip->irq_enable) { + gc->irq.irq_enable = irqchip->irq_enable; + irqchip->irq_enable = gpiochip_irq_enable; + } else { + gc->irq.irq_unmask = irqchip->irq_unmask; + irqchip->irq_unmask = gpiochip_irq_unmask; + } } /** diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 8c41ae41b6bb..c8bcaf315d03 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -253,6 +253,19 @@ struct gpio_irq_chip { * Store old irq_chip irq_disable callback */ void (*irq_disable)(struct irq_data *data); + /** + * @irq_unmask: + * + * Store old irq_chip irq_unmask callback + */ + void (*irq_unmask)(struct irq_data *data); + + /** + * @irq_mask: + * + * Store old irq_chip irq_mask callback + */ + void (*irq_mask)(struct irq_data *data); }; /** -- cgit v1.2.3-59-g8ed1b From 6a45b0e2589fafd7fc501a5fbd0ab56689a08124 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 28 May 2020 16:58:43 +0200 Subject: gpiolib: Introduce gpiochip_irqchip_add_domain() The function connects an IRQ domain to a gpiochip and reuses gpiochip_to_irq() which is provided by gpiolib. gpiochip_irqchip_* and regmap_irq partially provide the same functionality. This function will help to connect just the minimal functionality of the gpiochip_irqchip which is needed to work together with regmap-irq. Signed-off-by: Michael Walle Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200528145845.31436-2-michael@walle.cc Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 20 ++++++++++++++++++++ include/linux/gpio/driver.h | 3 +++ 2 files changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 167860684be6..0a54a759dd40 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2779,6 +2779,26 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gc, } EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key); +/** + * gpiochip_irqchip_add_domain() - adds an irqdomain to a gpiochip + * @gc: the gpiochip to add the irqchip to + * @domain: the irqdomain to add to the gpiochip + * + * This function adds an IRQ domain to the gpiochip. + */ +int gpiochip_irqchip_add_domain(struct gpio_chip *gc, + struct irq_domain *domain) +{ + if (!domain) + return -EINVAL; + + gc->to_irq = gpiochip_to_irq; + gc->irq.domain = domain; + + return 0; +} +EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_domain); + #else /* CONFIG_GPIOLIB_IRQCHIP */ static inline int gpiochip_add_irqchip(struct gpio_chip *gc, diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index c8bcaf315d03..c4f272af7af5 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -612,6 +612,9 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gc, bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc, unsigned int offset); +int gpiochip_irqchip_add_domain(struct gpio_chip *gc, + struct irq_domain *domain); + #ifdef CONFIG_LOCKDEP /* -- cgit v1.2.3-59-g8ed1b From ebe363197e525ffbd279c729421f6f6c24d8d681 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 28 May 2020 16:58:44 +0200 Subject: gpio: add a reusable generic gpio_chip using regmap There are quite a lot simple GPIO controller which are using regmap to access the hardware. This driver tries to be a base to unify existing code into one place. This won't cover everything but it should be a good starting point. It does not implement its own irq_chip because there is already a generic one for regmap based devices. Instead, the irq_chip will be instantiated in the parent driver and its irq domain will be associate to this driver. For now it consists of the usual registers, like set (and an optional clear) data register, an input register and direction registers. Out-of-the-box, it supports consecutive register mappings and mappings where the registers have gaps between them with a linear mapping between GPIO offset and bit position. For weirder mappings the user can register its own .xlate(). Signed-off-by: Michael Walle Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200528145845.31436-3-michael@walle.cc Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 4 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-regmap.c | 349 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/gpio/regmap.h | 86 +++++++++++ 4 files changed, 440 insertions(+) create mode 100644 drivers/gpio/gpio-regmap.c create mode 100644 include/linux/gpio/regmap.h (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7d077be10a0f..bcacd9c74aa8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -73,6 +73,10 @@ config GPIO_GENERIC depends on HAS_IOMEM # Only for IOMEM drivers tristate +config GPIO_REGMAP + depends on REGMAP + tristate + # put drivers in the right section, in alphabetical order # This symbol is selected by both I2C and SPI expanders diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 65bf3940e33c..1e4894e0bf0f 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o # Device drivers. Generally keep list sorted alphabetically +obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o # directly supported by gpio-generic diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c new file mode 100644 index 000000000000..5412cb3b0b2a --- /dev/null +++ b/drivers/gpio/gpio-regmap.c @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * regmap based generic GPIO driver + * + * Copyright 2020 Michael Walle + */ + +#include +#include +#include +#include +#include + +struct gpio_regmap { + struct device *parent; + struct regmap *regmap; + struct gpio_chip gpio_chip; + + int reg_stride; + int ngpio_per_reg; + unsigned int reg_dat_base; + unsigned int reg_set_base; + unsigned int reg_clr_base; + unsigned int reg_dir_in_base; + unsigned int reg_dir_out_base; + + int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask); + + void *driver_data; +}; + +static unsigned int gpio_regmap_addr(unsigned int addr) +{ + if (addr == GPIO_REGMAP_ADDR_ZERO) + return 0; + + return addr; +} + +static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio, + unsigned int base, unsigned int offset, + unsigned int *reg, unsigned int *mask) +{ + unsigned int line = offset % gpio->ngpio_per_reg; + unsigned int stride = offset / gpio->ngpio_per_reg; + + *reg = base + stride * gpio->reg_stride; + *mask = BIT(line); + + return 0; +} + +static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset) +{ + struct gpio_regmap *gpio = gpiochip_get_data(chip); + unsigned int base, val, reg, mask; + int ret; + + /* we might not have an output register if we are input only */ + if (gpio->reg_dat_base) + base = gpio_regmap_addr(gpio->reg_dat_base); + else + base = gpio_regmap_addr(gpio->reg_set_base); + + ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + return ret; + + ret = regmap_read(gpio->regmap, reg, &val); + if (ret) + return ret; + + return !!(val & mask); +} + +static void gpio_regmap_set(struct gpio_chip *chip, unsigned int offset, + int val) +{ + struct gpio_regmap *gpio = gpiochip_get_data(chip); + unsigned int base = gpio_regmap_addr(gpio->reg_set_base); + unsigned int reg, mask; + + gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (val) + regmap_update_bits(gpio->regmap, reg, mask, mask); + else + regmap_update_bits(gpio->regmap, reg, mask, 0); +} + +static void gpio_regmap_set_with_clear(struct gpio_chip *chip, + unsigned int offset, int val) +{ + struct gpio_regmap *gpio = gpiochip_get_data(chip); + unsigned int base, reg, mask; + + if (val) + base = gpio_regmap_addr(gpio->reg_set_base); + else + base = gpio_regmap_addr(gpio->reg_clr_base); + + gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + regmap_write(gpio->regmap, reg, mask); +} + +static int gpio_regmap_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct gpio_regmap *gpio = gpiochip_get_data(chip); + unsigned int base, val, reg, mask; + int invert, ret; + + if (gpio->reg_dir_out_base) { + base = gpio_regmap_addr(gpio->reg_dir_out_base); + invert = 0; + } else if (gpio->reg_dir_in_base) { + base = gpio_regmap_addr(gpio->reg_dir_in_base); + invert = 1; + } else { + return -EOPNOTSUPP; + } + + ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + return ret; + + ret = regmap_read(gpio->regmap, reg, &val); + if (ret) + return ret; + + if (!!(val & mask) ^ invert) + return GPIO_LINE_DIRECTION_OUT; + else + return GPIO_LINE_DIRECTION_IN; +} + +static int gpio_regmap_set_direction(struct gpio_chip *chip, + unsigned int offset, bool output) +{ + struct gpio_regmap *gpio = gpiochip_get_data(chip); + unsigned int base, val, reg, mask; + int invert, ret; + + if (gpio->reg_dir_out_base) { + base = gpio_regmap_addr(gpio->reg_dir_out_base); + invert = 0; + } else if (gpio->reg_dir_in_base) { + base = gpio_regmap_addr(gpio->reg_dir_in_base); + invert = 1; + } else { + return -EOPNOTSUPP; + } + + ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + return ret; + + if (invert) + val = output ? 0 : mask; + else + val = output ? mask : 0; + + return regmap_update_bits(gpio->regmap, reg, mask, val); +} + +static int gpio_regmap_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + return gpio_regmap_set_direction(chip, offset, false); +} + +static int gpio_regmap_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + gpio_regmap_set(chip, offset, value); + + return gpio_regmap_set_direction(chip, offset, true); +} + +void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data) +{ + gpio->driver_data = data; +} +EXPORT_SYMBOL_GPL(gpio_regmap_set_drvdata); + +void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio) +{ + return gpio->driver_data; +} +EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata); + +/** + * gpio_regmap_register() - Register a generic regmap GPIO controller + * @config: configuration for gpio_regmap + * + * Return: A pointer to the registered gpio_regmap or ERR_PTR error value. + */ +struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config) +{ + struct gpio_regmap *gpio; + struct gpio_chip *chip; + int ret; + + if (!config->parent) + return ERR_PTR(-EINVAL); + + if (!config->ngpio) + return ERR_PTR(-EINVAL); + + /* we need at least one */ + if (!config->reg_dat_base && !config->reg_set_base) + return ERR_PTR(-EINVAL); + + /* if we have a direction register we need both input and output */ + if ((config->reg_dir_out_base || config->reg_dir_in_base) && + (!config->reg_dat_base || !config->reg_set_base)) + return ERR_PTR(-EINVAL); + + /* we don't support having both registers simultaneously for now */ + if (config->reg_dir_out_base && config->reg_dir_in_base) + return ERR_PTR(-EINVAL); + + gpio = kzalloc(sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return ERR_PTR(-ENOMEM); + + gpio->parent = config->parent; + gpio->regmap = config->regmap; + gpio->ngpio_per_reg = config->ngpio_per_reg; + gpio->reg_stride = config->reg_stride; + gpio->reg_mask_xlate = config->reg_mask_xlate; + gpio->reg_dat_base = config->reg_dat_base; + gpio->reg_set_base = config->reg_set_base; + gpio->reg_clr_base = config->reg_clr_base; + gpio->reg_dir_in_base = config->reg_dir_in_base; + gpio->reg_dir_out_base = config->reg_dir_out_base; + + /* if not set, assume there is only one register */ + if (!gpio->ngpio_per_reg) + gpio->ngpio_per_reg = config->ngpio; + + /* if not set, assume they are consecutive */ + if (!gpio->reg_stride) + gpio->reg_stride = 1; + + if (!gpio->reg_mask_xlate) + gpio->reg_mask_xlate = gpio_regmap_simple_xlate; + + chip = &gpio->gpio_chip; + chip->parent = config->parent; + chip->base = -1; + chip->ngpio = config->ngpio; + chip->names = config->names; + chip->label = config->label ?: dev_name(config->parent); + + /* + * If our regmap is fast_io we should probably set can_sleep to false. + * Right now, the regmap doesn't save this property, nor is there any + * access function for it. + * The only regmap type which uses fast_io is regmap-mmio. For now, + * assume a safe default of true here. + */ + chip->can_sleep = true; + + chip->get = gpio_regmap_get; + if (gpio->reg_set_base && gpio->reg_clr_base) + chip->set = gpio_regmap_set_with_clear; + else if (gpio->reg_set_base) + chip->set = gpio_regmap_set; + + if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) { + chip->get_direction = gpio_regmap_get_direction; + chip->direction_input = gpio_regmap_direction_input; + chip->direction_output = gpio_regmap_direction_output; + } + + ret = gpiochip_add_data(chip, gpio); + if (ret < 0) + goto err_free_gpio; + + if (config->irq_domain) { + ret = gpiochip_irqchip_add_domain(chip, config->irq_domain); + if (ret) + goto err_remove_gpiochip; + } + + return gpio; + +err_remove_gpiochip: + gpiochip_remove(chip); +err_free_gpio: + kfree(gpio); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(gpio_regmap_register); + +/** + * gpio_regmap_unregister() - Unregister a generic regmap GPIO controller + * @gpio: gpio_regmap device to unregister + */ +void gpio_regmap_unregister(struct gpio_regmap *gpio) +{ + gpiochip_remove(&gpio->gpio_chip); + kfree(gpio); +} +EXPORT_SYMBOL_GPL(gpio_regmap_unregister); + +static void devm_gpio_regmap_unregister(struct device *dev, void *res) +{ + gpio_regmap_unregister(*(struct gpio_regmap **)res); +} + +/** + * devm_gpio_regmap_register() - resource managed gpio_regmap_register() + * @dev: device that is registering this GPIO device + * @config: configuration for gpio_regmap + * + * Managed gpio_regmap_register(). For generic regmap GPIO device registered by + * this function, gpio_regmap_unregister() is automatically called on driver + * detach. See gpio_regmap_register() for more information. + * + * Return: A pointer to the registered gpio_regmap or ERR_PTR error value. + */ +struct gpio_regmap *devm_gpio_regmap_register(struct device *dev, + const struct gpio_regmap_config *config) +{ + struct gpio_regmap **ptr, *gpio; + + ptr = devres_alloc(devm_gpio_regmap_unregister, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + gpio = gpio_regmap_register(config); + if (!IS_ERR(gpio)) { + *ptr = gpio; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return gpio; +} +EXPORT_SYMBOL_GPL(devm_gpio_regmap_register); + +MODULE_AUTHOR("Michael Walle "); +MODULE_DESCRIPTION("GPIO generic regmap driver core"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h new file mode 100644 index 000000000000..4c1e6b34e824 --- /dev/null +++ b/include/linux/gpio/regmap.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _LINUX_GPIO_REGMAP_H +#define _LINUX_GPIO_REGMAP_H + +struct device; +struct gpio_regmap; +struct irq_domain; +struct regmap; + +#define GPIO_REGMAP_ADDR_ZERO ((unsigned long)(-1)) +#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO) + +/** + * struct gpio_regmap_config - Description of a generic regmap gpio_chip. + * @parent: The parent device + * @regmap: The regmap used to access the registers + * given, the name of the device is used + * @label: (Optional) Descriptive name for GPIO controller. + * If not given, the name of the device is used. + * @ngpio: Number of GPIOs + * @names: (Optional) Array of names for gpios + * @reg_dat_base: (Optional) (in) register base address + * @reg_set_base: (Optional) set register base address + * @reg_clr_base: (Optional) clear register base address + * @reg_dir_in_base: (Optional) in setting register base address + * @reg_dir_out_base: (Optional) out setting register base address + * @reg_stride: (Optional) May be set if the registers (of the + * same type, dat, set, etc) are not consecutive. + * @ngpio_per_reg: Number of GPIOs per register + * @irq_domain: (Optional) IRQ domain if the controller is + * interrupt-capable + * @reg_mask_xlate: (Optional) Translates base address and GPIO + * offset to a register/bitmask pair. If not + * given the default gpio_regmap_simple_xlate() + * is used. + * + * The ->reg_mask_xlate translates a given base address and GPIO offset to + * register and mask pair. The base address is one of the given register + * base addresses in this structure. + * + * Although all register base addresses are marked as optional, there are + * several rules: + * 1. if you only have @reg_dat_base set, then it is input-only + * 2. if you only have @reg_set_base set, then it is output-only + * 3. if you have either @reg_dir_in_base or @reg_dir_out_base set, then + * you have to set both @reg_dat_base and @reg_set_base + * 4. if you have @reg_set_base set, you may also set @reg_clr_base to have + * two different registers for setting and clearing the output. This is + * also valid for the output-only case. + * 5. @reg_dir_in_base and @reg_dir_out_base are exclusive; is there really + * hardware which has redundant registers? + * + * Note: All base addresses may have the special value %GPIO_REGMAP_ADDR_ZERO + * which forces the address to the value 0. + */ +struct gpio_regmap_config { + struct device *parent; + struct regmap *regmap; + + const char *label; + int ngpio; + const char *const *names; + + unsigned int reg_dat_base; + unsigned int reg_set_base; + unsigned int reg_clr_base; + unsigned int reg_dir_in_base; + unsigned int reg_dir_out_base; + int reg_stride; + int ngpio_per_reg; + struct irq_domain *irq_domain; + + int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask); +}; + +struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config); +void gpio_regmap_unregister(struct gpio_regmap *gpio); +struct gpio_regmap *devm_gpio_regmap_register(struct device *dev, + const struct gpio_regmap_config *config); +void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data); +void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio); + +#endif /* _LINUX_GPIO_REGMAP_H */ -- cgit v1.2.3-59-g8ed1b From 74910e15ab25f95f162bc4d4a634d029186543ce Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 21 May 2020 00:19:14 +0300 Subject: gpio: pca953x: Drop unneeded ACPI_PTR() ACPI_PTR() becomes a no-op when !CONFIG_ACPI. This is not needed since we always have ID table enabled. Moreover, in the mentioned case compiler will complain about defined but not used variable. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20200520211916.25727-3-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 4bb3d3524bc7..1fca8dd7824f 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -1176,7 +1176,7 @@ static struct i2c_driver pca953x_driver = { .name = "pca953x", .pm = &pca953x_pm_ops, .of_match_table = pca953x_dt_ids, - .acpi_match_table = ACPI_PTR(pca953x_acpi_ids), + .acpi_match_table = pca953x_acpi_ids, }, .probe = pca953x_probe, .remove = pca953x_remove, -- cgit v1.2.3-59-g8ed1b