diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-05 11:49:48 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-05 11:49:48 -0700 |
commit | 70b8e9eb3b50d8bded63f808b09c4844ef63c3b8 (patch) | |
tree | 42b5b22becc9e9542923be3bc78525e0d9f5c67c /drivers/gpio | |
parent | d16605c9128a498f9b8575b5c43be95c45dbcfab (diff) | |
parent | 02b6bddb0b0a4e27fad6623d82579f2a1e35d3d3 (diff) | |
download | linux-stable-70b8e9eb3b50d8bded63f808b09c4844ef63c3b8.tar.gz linux-stable-70b8e9eb3b50d8bded63f808b09c4844ef63c3b8.tar.bz2 linux-stable-70b8e9eb3b50d8bded63f808b09c4844ef63c3b8.zip |
Merge tag 'gpio-v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij:
"This is the bulk of the GPIO changes for the v4.14 cycle.
Not so much changes this time, phew. David Daney and Bartosz
Golaszewski did all the really interesting work in infrastructure
improvement across GPIO and IRQ core, hats off for them and to tglx
and Marc Z for general help with these patch sets.
Core changes:
- Allow the GPIO irqchip to allocate IRQs dynamically. This is an
important change on systems where only a restricted number of IRQs,
lesser than the number of GPIO lines, can be utilized. Now we can
allocate these on a first-come-first-served basis instead of
hogging up valuable IRQ lines.
- Serious fix-up of the kerneldoc documentation and inclusion into
the kerneldoc builds.
- Pulled in the IRQ simulator from the IRQ core tree and use this in
the GPIO mockup driver for exhaustive testing of interrupt
abilities.
New drivers:
- New driver for ThunderX and OCTEON-TX. This is especially
interesting as it picks up improvements from the IRQ core that
allow us to handle fasteoi ACKs upwards in a hierarchy when there
are IRQ flag latches on several levels in a hierarchy. Very
interesting work here.
- New subdriver for Renesas R-Car r8a7745 (RZ/G1E).
Misc:
- Several fixes and improvements for Xilinx Zynq GPIO.
- Support an enablement GPIO for the 74x164 GPIO.
- Switch a bunch of chips to use devres to allocate irq descriptors.
- A bunch of constification fixes"
* tag 'gpio-v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (63 commits)
gpio: mockup: remove unused variable gc
gpio: pl061: constify amba_id
Revert "gpiolib: request the gpio before querying its direction"
gpio: twl6040: remove unneeded forward declaration
gpio: zevio: make gpio_chip const
gpio: add gpio_add_lookup_tables() to add several tables at once
gpio: rcar: Add r8a7745 (RZ/G1E) support
gpio: brcmstb: check return value of gpiochip_irqchip_add()
MAINTAINERS: Add entry for THUNDERX GPIO Driver.
gpio: Add gpio driver support for ThunderX and OCTEON-TX
gpio: mockup: use irq_sim
gpio: mxs: use devres for irq generic chip
gpio: mxc: use devres for irq generic chip
gpio: pch: use devres for irq generic chip
gpio: ml-ioh: use devres for irq generic chip
gpio: sta2x11: use devres for irq generic chip
gpio: sta2x11: disallow unbinding the driver
gpio: mxs: disallow unbinding the driver
gpio: mxc: disallow unbinding the driver
gpio: aspeed: Remove reference to clock name in debounce warning message
...
Diffstat (limited to 'drivers/gpio')
42 files changed, 1333 insertions, 315 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 461d6fc3688b..3388d54ba114 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -311,7 +311,7 @@ config GPIO_MOCKUP depends on GPIOLIB && SYSFS select GPIO_SYSFS select GPIOLIB_IRQCHIP - select IRQ_WORK + select IRQ_SIM help This enables GPIO Testing driver, which provides a way to test GPIO subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS @@ -450,6 +450,15 @@ config GPIO_TS4800 help This driver support TS-4800 FPGA GPIO controllers. +config GPIO_THUNDERX + tristate "Cavium ThunderX/OCTEON-TX GPIO" + depends on ARCH_THUNDER || (64BIT && COMPILE_TEST) + depends on PCI_MSI && IRQ_DOMAIN_HIERARCHY + select IRQ_FASTEOI_HIERARCHY_HANDLERS + help + Say yes here to support the on-chip GPIO lines on the ThunderX + and OCTEON-TX families of SoCs. + config GPIO_TZ1090 bool "Toumaz Xenif TZ1090 GPIO support" depends on SOC_TZ1090 @@ -1065,6 +1074,21 @@ config GPIO_TPS65912 help This driver supports TPS65912 gpio chip +config GPIO_TPS68470 + bool "TPS68470 GPIO" + depends on MFD_TPS68470 + help + Select this option to enable GPIO driver for the TPS68470 + chip family. + There are 7 GPIOs and few sensor related GPIOs supported + by the TPS68470. While the 7 GPIOs can be configured as + input or output as appropriate, the sensor related GPIOs + are "output only" GPIOs. + + This driver config is bool, as the GPIO functionality + of the TPS68470 must be available before dependent + drivers are loaded. + config GPIO_TWL4030 tristate "TWL4030, TWL5030, and TPS659x0 GPIOs" depends on TWL4030_CORE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a9fda6c55113..aeb70e9de6f2 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -113,6 +113,7 @@ obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o +obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o @@ -121,6 +122,7 @@ obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o +obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index a75511d1ea5d..afbff155a0ba 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -132,6 +132,7 @@ EXPORT_SYMBOL(devm_gpiod_get_index); * @index: index of the GPIO to obtain in the consumer * @child: firmware node (child of @dev) * @flags: GPIO initialization flags + * @label: label to attach to the requested GPIO * * GPIO descriptors returned from this function are automatically disposed on * driver detach. @@ -271,6 +272,7 @@ EXPORT_SYMBOL(devm_gpiod_get_array_optional); /** * devm_gpiod_put - Resource-managed gpiod_put() + * @dev: GPIO consumer * @desc: GPIO descriptor to dispose of * * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or @@ -286,6 +288,7 @@ EXPORT_SYMBOL(devm_gpiod_put); /** * devm_gpiod_put_array - Resource-managed gpiod_put_array() + * @dev: GPIO consumer * @descs: GPIO descriptor array to dispose of * * Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array(). diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index a6607faf2fdf..6b535ec858cc 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/mutex.h> #include <linux/spi/spi.h> @@ -31,6 +32,7 @@ struct gen_74x164_chip { * numbering, store the bytes in reverse order. */ u8 buffer[0]; + struct gpio_desc *gpiod_oe; }; static int __gen_74x164_write_config(struct gen_74x164_chip *chip) @@ -126,6 +128,13 @@ static int gen_74x164_probe(struct spi_device *spi) if (!chip) return -ENOMEM; + chip->gpiod_oe = devm_gpiod_get_optional(&spi->dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(chip->gpiod_oe)) + return PTR_ERR(chip->gpiod_oe); + + gpiod_set_value_cansleep(chip->gpiod_oe, 1); + spi_set_drvdata(spi, chip); chip->gpio_chip.label = spi->modalias; @@ -164,6 +173,7 @@ static int gen_74x164_remove(struct spi_device *spi) { struct gen_74x164_chip *chip = spi_get_drvdata(spi); + gpiod_set_value_cansleep(chip->gpiod_oe, 0); gpiochip_remove(&chip->gpio_chip); mutex_destroy(&chip->lock); diff --git a/drivers/gpio/gpio-altera-a10sr.c b/drivers/gpio/gpio-altera-a10sr.c index 16a8951b2bed..6b11f1314248 100644 --- a/drivers/gpio/gpio-altera-a10sr.c +++ b/drivers/gpio/gpio-altera-a10sr.c @@ -71,7 +71,7 @@ static int altr_a10sr_gpio_direction_output(struct gpio_chip *gc, return -EINVAL; } -static struct gpio_chip altr_a10sr_gc = { +static const struct gpio_chip altr_a10sr_gc = { .label = "altr_a10sr_gpio", .owner = THIS_MODULE, .get = altr_a10sr_gpio_get, diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 17485dc20384..ccc02ed65b3c 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -324,8 +324,8 @@ skip_irq: return 0; teardown: of_mm_gpiochip_remove(&altera_gc->mmchip); - pr_err("%s: registration failed with status %d\n", - node->full_name, ret); + pr_err("%pOF: registration failed with status %d\n", + node, ret); return ret; } diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 4ca436e66bdb..bfc53995064a 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -834,7 +834,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->clk = of_clk_get(pdev->dev.of_node, 0); if (IS_ERR(gpio->clk)) { dev_warn(&pdev->dev, - "No HPLL clock phandle provided, debouncing disabled\n"); + "Failed to get clock from devicetree, debouncing disabled\n"); gpio->clk = NULL; } diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index e6489143721a..dd0308cc8bb0 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -339,6 +339,7 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev, struct brcmstb_gpio_priv *priv = bank->parent_priv; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; + int err; bank->irq_chip.name = dev_name(dev); bank->irq_chip.irq_mask = brcmstb_gpio_irq_mask; @@ -355,8 +356,6 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev, dev_warn(dev, "Couldn't get wake IRQ - GPIOs will not be able to wake from sleep"); } else { - int err; - /* * Set wakeup capability before requesting wakeup * interrupt, so we can process boot-time "wakeups" @@ -383,8 +382,10 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev, if (priv->can_wake) bank->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake; - gpiochip_irqchip_add(&bank->gc, &bank->irq_chip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + err = gpiochip_irqchip_add(&bank->gc, &bank->irq_chip, 0, + handle_simple_irq, IRQ_TYPE_NONE); + if (err) + return err; gpiochip_set_chained_irqchip(&bank->gc, &bank->irq_chip, priv->parent_irq, brcmstb_gpio_irq_handler); @@ -483,7 +484,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) gc->of_node = np; gc->owner = THIS_MODULE; - gc->label = np->full_name; + gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", dev->of_node); gc->base = gpio_base; gc->of_gpio_n_cells = 2; gc->of_xlate = brcmstb_gpio_of_xlate; diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 65cb359308e3..f75d8443ecaf 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -166,7 +166,7 @@ of_err: static int davinci_gpio_probe(struct platform_device *pdev) { static int ctrl_num, bank_base; - int gpio, bank; + int gpio, bank, ret = 0; unsigned ngpio, nbank; struct davinci_gpio_controller *chips; struct davinci_gpio_platform_data *pdata; @@ -232,10 +232,23 @@ static int davinci_gpio_probe(struct platform_device *pdev) for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++) chips->regs[bank] = gpio_base + offset_array[bank]; - gpiochip_add_data(&chips->chip, chips); + ret = devm_gpiochip_add_data(dev, &chips->chip, chips); + if (ret) + goto err; + platform_set_drvdata(pdev, chips); - davinci_gpio_irq_setup(pdev); + ret = davinci_gpio_irq_setup(pdev); + if (ret) + goto err; + return 0; + +err: + /* Revert the static variable increments */ + ctrl_num--; + bank_base -= ngpio; + + return ret; } /*--------------------------------------------------------------------------*/ @@ -477,8 +490,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) clk = devm_clk_get(dev, "gpio"); if (IS_ERR(clk)) { - printk(KERN_ERR "Error %ld getting gpio clock?\n", - PTR_ERR(clk)); + dev_err(dev, "Error %ld getting gpio clock\n", PTR_ERR(clk)); return PTR_ERR(clk); } ret = clk_prepare_enable(clk); diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 8650b2916f87..6f5a7fe9787d 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -76,8 +76,7 @@ static int __init gef_gpio_probe(struct platform_device *pdev) } /* Setup pointers to chip functions */ - gc->label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name, - GFP_KERNEL); + gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node); if (!gc->label) { ret = -ENOMEM; goto err0; @@ -96,8 +95,7 @@ static int __init gef_gpio_probe(struct platform_device *pdev) return 0; err0: iounmap(regs); - pr_err("%s: GPIO chip registration failed\n", - pdev->dev.of_node->full_name); + pr_err("%pOF: GPIO chip registration failed\n", pdev->dev.of_node); return ret; }; diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 7847dd34f86f..6544a16ab02e 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -367,7 +367,7 @@ static int grgpio_probe(struct platform_device *ofdev) gc->of_node = np; gc->owner = THIS_MODULE; gc->to_irq = grgpio_to_irq; - gc->label = np->full_name; + gc->label = devm_kasprintf(&ofdev->dev, GFP_KERNEL, "%pOF", np); gc->base = -1; err = of_property_read_u32(np, "nbits", &prop); diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index 45d29e488dbb..d43d0a2cc4c5 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -2,6 +2,7 @@ * GPIO interface for IT87xx Super I/O chips * * Author: Diego Elio Pettenò <flameeyes@flameeyes.eu> + * Copyright (c) 2017 Google, Inc. * * Based on it87_wdt.c by Oliver Schuster * gpio-it8761e.c by Denis Turischev @@ -39,6 +40,7 @@ #define IT8728_ID 0x8728 #define IT8732_ID 0x8732 #define IT8761_ID 0x8761 +#define IT8772_ID 0x8772 /* IO Ports */ #define REG 0x2e @@ -314,6 +316,7 @@ static int __init it87_gpio_init(void) break; case IT8728_ID: case IT8732_ID: + case IT8772_ID: gpio_ba_reg = 0x62; it87_gpio->io_size = 8; it87_gpio->output_base = 0xc8; diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index 743459d9477d..538bce4b5b42 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -82,7 +82,7 @@ static const struct regmap_irq max77620_gpio_irqs[] = { }, }; -static struct regmap_irq_chip max77620_gpio_irq_chip = { +static const struct regmap_irq_chip max77620_gpio_irq_chip = { .name = "max77620-gpio", .irqs = max77620_gpio_irqs, .num_irqs = ARRAY_SIZE(max77620_gpio_irqs), diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index ffb73f688ae1..94d772677ed6 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -168,7 +168,9 @@ static int mb86s70_gpio_probe(struct platform_device *pdev) if (IS_ERR(gchip->clk)) return PTR_ERR(gchip->clk); - clk_prepare_enable(gchip->clk); + ret = clk_prepare_enable(gchip->clk); + if (ret) + return ret; spin_lock_init(&gchip->lock); diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 74fdce096c26..4b80e996d976 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -391,9 +391,10 @@ static int ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, { struct irq_chip_generic *gc; struct irq_chip_type *ct; + int rv; - gc = irq_alloc_generic_chip("ioh_gpio", 1, irq_start, chip->base, - handle_simple_irq); + gc = devm_irq_alloc_generic_chip(chip->dev, "ioh_gpio", 1, irq_start, + chip->base, handle_simple_irq); if (!gc) return -ENOMEM; @@ -406,10 +407,11 @@ static int ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, ct->chip.irq_disable = ioh_irq_disable; ct->chip.irq_enable = ioh_irq_enable; - irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, - IRQ_NOREQUEST | IRQ_NOPROBE, 0); + rv = devm_irq_setup_generic_chip(chip->dev, gc, IRQ_MSK(num), + IRQ_GC_INIT_MASK_CACHE, + IRQ_NOREQUEST | IRQ_NOPROBE, 0); - return 0; + return rv; } static int ioh_gpio_probe(struct pci_dev *pdev, diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index a6565e128f9e..9532d86a82f7 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -20,7 +20,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/irq_work.h> +#include <linux/irq_sim.h> #include <linux/debugfs.h> #include <linux/uaccess.h> @@ -47,18 +47,12 @@ enum { struct gpio_mockup_line_status { int dir; bool value; - bool irq_enabled; -}; - -struct gpio_mockup_irq_context { - struct irq_work work; - int irq; }; struct gpio_mockup_chip { struct gpio_chip gc; struct gpio_mockup_line_status *lines; - struct gpio_mockup_irq_context irq_ctx; + struct irq_sim irqsim; struct dentry *dbg_dir; }; @@ -144,65 +138,11 @@ static int gpio_mockup_name_lines(struct device *dev, return 0; } -static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - return chip->irq_base + offset; -} - -static void gpio_mockup_irqmask(struct irq_data *data) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(data); - struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - - chip->lines[data->irq - gc->irq_base].irq_enabled = false; -} - -static void gpio_mockup_irqunmask(struct irq_data *data) +static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset) { - struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct gpio_mockup_chip *chip = gpiochip_get_data(gc); - chip->lines[data->irq - gc->irq_base].irq_enabled = true; -} - -static struct irq_chip gpio_mockup_irqchip = { - .name = GPIO_MOCKUP_NAME, - .irq_mask = gpio_mockup_irqmask, - .irq_unmask = gpio_mockup_irqunmask, -}; - -static void gpio_mockup_handle_irq(struct irq_work *work) -{ - struct gpio_mockup_irq_context *irq_ctx; - - irq_ctx = container_of(work, struct gpio_mockup_irq_context, work); - handle_simple_irq(irq_to_desc(irq_ctx->irq)); -} - -static int gpio_mockup_irqchip_setup(struct device *dev, - struct gpio_mockup_chip *chip) -{ - struct gpio_chip *gc = &chip->gc; - int irq_base, i; - - irq_base = devm_irq_alloc_descs(dev, -1, 0, gc->ngpio, 0); - if (irq_base < 0) - return irq_base; - - gc->irq_base = irq_base; - gc->irqchip = &gpio_mockup_irqchip; - - for (i = 0; i < gc->ngpio; i++) { - irq_set_chip(irq_base + i, gc->irqchip); - irq_set_chip_data(irq_base + i, gc); - irq_set_handler(irq_base + i, &handle_simple_irq); - irq_modify_status(irq_base + i, - IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE); - } - - init_irq_work(&chip->irq_ctx.work, gpio_mockup_handle_irq); - - return 0; + return irq_sim_irqnum(&chip->irqsim, offset); } static ssize_t gpio_mockup_event_write(struct file *file, @@ -213,7 +153,6 @@ static ssize_t gpio_mockup_event_write(struct file *file, struct gpio_mockup_chip *chip; struct seq_file *sfile; struct gpio_desc *desc; - struct gpio_chip *gc; int rv, val; rv = kstrtoint_from_user(usr_buf, size, 0, &val); @@ -226,13 +165,9 @@ static ssize_t gpio_mockup_event_write(struct file *file, priv = sfile->private; desc = priv->desc; chip = priv->chip; - gc = &chip->gc; - if (chip->lines[priv->offset].irq_enabled) { - gpiod_set_value_cansleep(desc, val); - priv->chip->irq_ctx.irq = gc->irq_base + priv->offset; - irq_work_queue(&priv->chip->irq_ctx.work); - } + gpiod_set_value_cansleep(desc, val); + irq_sim_fire(&chip->irqsim, priv->offset); return size; } @@ -319,7 +254,7 @@ static int gpio_mockup_add(struct device *dev, return ret; } - ret = gpio_mockup_irqchip_setup(dev, chip); + ret = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio); if (ret) return ret; diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 793518a30afe..8c93dec498fa 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -348,8 +348,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) ret = gpiochip_add_data(gc, mpc8xxx_gc); if (ret) { - pr_err("%s: GPIO chip registration failed with status %d\n", - np->full_name, ret); + pr_err("%pOF: GPIO chip registration failed with status %d\n", + np, ret); goto err; } diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c index 1b7ce7f85886..6cb67595d15f 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -265,8 +265,8 @@ static int platform_msic_gpio_probe(struct platform_device *pdev) int i; if (irq < 0) { - dev_err(dev, "no IRQ line\n"); - return -EINVAL; + dev_err(dev, "no IRQ line: %d\n", irq); + return irq; } if (!pdata || !pdata->gpio_base) { diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 92692251ade1..5245a2fe62ae 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -66,6 +66,7 @@ struct mxc_gpio_port { int irq_high; struct irq_domain *domain; struct gpio_chip gc; + struct device *dev; u32 both_edges; }; @@ -324,29 +325,31 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxc_gpio_port *port = gc->private; u32 gpio_idx = d->hwirq; + int ret; if (enable) { if (port->irq_high && (gpio_idx >= 16)) - enable_irq_wake(port->irq_high); + ret = enable_irq_wake(port->irq_high); else - enable_irq_wake(port->irq); + ret = enable_irq_wake(port->irq); } else { if (port->irq_high && (gpio_idx >= 16)) - disable_irq_wake(port->irq_high); + ret = disable_irq_wake(port->irq_high); else - disable_irq_wake(port->irq); + ret = disable_irq_wake(port->irq); } - return 0; + return ret; } static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) { struct irq_chip_generic *gc; struct irq_chip_type *ct; + int rv; - gc = irq_alloc_generic_chip("gpio-mxc", 1, irq_base, - port->base, handle_level_irq); + gc = devm_irq_alloc_generic_chip(port->dev, "gpio-mxc", 1, irq_base, + port->base, handle_level_irq); if (!gc) return -ENOMEM; gc->private = port; @@ -361,10 +364,11 @@ static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) ct->regs.ack = GPIO_ISR; ct->regs.mask = GPIO_IMR; - irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, - IRQ_NOREQUEST, 0); + rv = devm_irq_setup_generic_chip(port->dev, gc, IRQ_MSK(32), + IRQ_GC_INIT_NESTED_LOCK, + IRQ_NOREQUEST, 0); - return 0; + return rv; } static void mxc_gpio_get_hw(struct platform_device *pdev) @@ -418,6 +422,8 @@ static int mxc_gpio_probe(struct platform_device *pdev) if (!port) return -ENOMEM; + port->dev = &pdev->dev; + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); port->base = devm_ioremap_resource(&pdev->dev, iores); if (IS_ERR(port->base)) @@ -507,6 +513,7 @@ static struct platform_driver mxc_gpio_driver = { .driver = { .name = "gpio-mxc", .of_match_table = mxc_gpio_dt_ids, + .suppress_bind_attrs = true, }, .probe = mxc_gpio_probe, .id_table = mxc_gpio_devtype, diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 6ae583f36733..435def22445d 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -66,6 +66,7 @@ struct mxs_gpio_port { int irq; struct irq_domain *domain; struct gpio_chip gc; + struct device *dev; enum mxs_gpio_id devid; u32 both_edges; }; @@ -209,9 +210,10 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) { struct irq_chip_generic *gc; struct irq_chip_type *ct; + int rv; - gc = irq_alloc_generic_chip("gpio-mxs", 2, irq_base, - port->base, handle_level_irq); + gc = devm_irq_alloc_generic_chip(port->dev, "gpio-mxs", 2, irq_base, + port->base, handle_level_irq); if (!gc) return -ENOMEM; @@ -242,10 +244,11 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) ct->regs.disable = PINCTRL_IRQEN(port) + MXS_CLR; ct->handler = handle_level_irq; - irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, - IRQ_NOREQUEST, 0); + rv = devm_irq_setup_generic_chip(port->dev, gc, IRQ_MSK(32), + IRQ_GC_INIT_NESTED_LOCK, + IRQ_NOREQUEST, 0); - return 0; + return rv; } static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset) @@ -304,6 +307,7 @@ static int mxs_gpio_probe(struct platform_device *pdev) if (port->id < 0) return port->id; port->devid = (enum mxs_gpio_id) of_id->data; + port->dev = &pdev->dev; port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) return port->irq; @@ -379,6 +383,7 @@ static struct platform_driver mxs_gpio_driver = { .driver = { .name = "gpio-mxs", .of_match_table = mxs_gpio_dt_ids, + .suppress_bind_attrs = true, }, .probe = mxs_gpio_probe, .id_table = mxs_gpio_ids, diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f8c550de6c72..dbf869fb63ce 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1247,6 +1247,8 @@ static int omap_gpio_probe(struct platform_device *pdev) if (ret) { pm_runtime_put_sync(dev); pm_runtime_disable(dev); + if (bank->dbck_flag) + clk_unprepare(bank->dbck); return ret; } diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 4c9e21300a26..1b9dbf691ae7 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -187,10 +187,9 @@ static int pca953x_write_regs_8(struct pca953x_chip *chip, int reg, u8 *val) static int pca953x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val) { - __le16 word = cpu_to_le16(get_unaligned((u16 *)val)); + u16 word = get_unaligned((u16 *)val); - return i2c_smbus_write_word_data(chip->client, - reg << 1, (__force u16)word); + return i2c_smbus_write_word_data(chip->client, reg << 1, word); } static int pca957x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val) @@ -241,8 +240,7 @@ static int pca953x_read_regs_16(struct pca953x_chip *chip, int reg, u8 *val) int ret; ret = i2c_smbus_read_word_data(chip->client, reg << 1); - val[0] = (u16)ret & 0xFF; - val[1] = (u16)ret >> 8; + put_unaligned(ret, (u16 *)val); return ret; } diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index f6600f8ada52..68c6d0c5a6d1 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -337,9 +337,10 @@ static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip, { struct irq_chip_generic *gc; struct irq_chip_type *ct; + int rv; - gc = irq_alloc_generic_chip("pch_gpio", 1, irq_start, chip->base, - handle_simple_irq); + gc = devm_irq_alloc_generic_chip(chip->dev, "pch_gpio", 1, irq_start, + chip->base, handle_simple_irq); if (!gc) return -ENOMEM; @@ -351,10 +352,11 @@ static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip, ct->chip.irq_unmask = pch_irq_unmask; ct->chip.irq_set_type = pch_irq_type; - irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, - IRQ_NOREQUEST | IRQ_NOPROBE, 0); + rv = devm_irq_setup_generic_chip(chip->dev, gc, IRQ_MSK(num), + IRQ_GC_INIT_MASK_CACHE, + IRQ_NOREQUEST | IRQ_NOPROBE, 0); - return 0; + return rv; } static int pch_gpio_probe(struct pci_dev *pdev, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 3d3d6b6645a7..6aaaab79c205 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -405,7 +405,7 @@ static const struct dev_pm_ops pl061_dev_pm_ops = { }; #endif -static struct amba_id pl061_ids[] = { +static const struct amba_id pl061_ids[] = { { .id = 0x00041061, .mask = 0x000fffff, diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 832f3e46ba9f..6029899789f3 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -451,7 +451,9 @@ static irqreturn_t pxa_gpio_demux_handler(int in_irq, void *d) for_each_set_bit(n, &gedr, BITS_PER_LONG) { loop = 1; - generic_handle_irq(gpio_to_irq(gpio + n)); + generic_handle_irq( + irq_find_mapping(pchip->irqdomain, + gpio + n)); } } handled += loop; @@ -465,9 +467,9 @@ static irqreturn_t pxa_gpio_direct_handler(int in_irq, void *d) struct pxa_gpio_chip *pchip = d; if (in_irq == pchip->irq0) { - generic_handle_irq(gpio_to_irq(0)); + generic_handle_irq(irq_find_mapping(pchip->irqdomain, 0)); } else if (in_irq == pchip->irq1) { - generic_handle_irq(gpio_to_irq(1)); + generic_handle_irq(irq_find_mapping(pchip->irqdomain, 1)); } else { pr_err("%s() unknown irq %d\n", __func__, in_irq); return IRQ_NONE; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 4a1536a050bc..1f0871553fd2 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -371,6 +371,16 @@ static const struct of_device_id gpio_rcar_of_table[] = { /* Gen3 GPIO is identical to Gen2. */ .data = &gpio_rcar_info_gen2, }, { + .compatible = "renesas,rcar-gen1-gpio", + .data = &gpio_rcar_info_gen1, + }, { + .compatible = "renesas,rcar-gen2-gpio", + .data = &gpio_rcar_info_gen2, + }, { + .compatible = "renesas,rcar-gen3-gpio", + /* Gen3 GPIO is identical to Gen2. */ + .data = &gpio_rcar_info_gen2, + }, { .compatible = "renesas,gpio-rcar", .data = &gpio_rcar_info_gen1, }, { diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 9e705162da8d..407359da08f9 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -324,9 +324,11 @@ static int gsta_alloc_irq_chip(struct gsta_gpio *chip) { struct irq_chip_generic *gc; struct irq_chip_type *ct; + int rv; - gc = irq_alloc_generic_chip(KBUILD_MODNAME, 1, chip->irq_base, - chip->reg_base, handle_simple_irq); + gc = devm_irq_alloc_generic_chip(chip->dev, KBUILD_MODNAME, 1, + chip->irq_base, + chip->reg_base, handle_simple_irq); if (!gc) return -ENOMEM; @@ -338,8 +340,11 @@ static int gsta_alloc_irq_chip(struct gsta_gpio *chip) ct->chip.irq_enable = gsta_irq_enable; /* FIXME: this makes at most 32 interrupts. Request 0 by now */ - irq_setup_generic_chip(gc, 0 /* IRQ_MSK(GSTA_GPIO_PER_BLOCK) */, 0, - IRQ_NOREQUEST | IRQ_NOPROBE, 0); + rv = devm_irq_setup_generic_chip(chip->dev, gc, + 0 /* IRQ_MSK(GSTA_GPIO_PER_BLOCK) */, + 0, IRQ_NOREQUEST | IRQ_NOPROBE, 0); + if (rv) + return rv; /* Set up all all 128 interrupts: code from setup_generic_chip */ { @@ -432,6 +437,7 @@ static int gsta_probe(struct platform_device *dev) static struct platform_driver sta2x11_gpio_platform_driver = { .driver = { .name = "sta2x11-gpio", + .suppress_bind_attrs = true, }, .probe = gsta_probe, }; diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index 80b6959ae995..091ffaaec635 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -191,7 +191,8 @@ static int tb10x_gpio_probe(struct platform_device *pdev) if (IS_ERR(tb10x_gpio->base)) return PTR_ERR(tb10x_gpio->base); - tb10x_gpio->gc.label = of_node_full_name(dn); + tb10x_gpio->gc.label = + devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node); tb10x_gpio->gc.parent = &pdev->dev; tb10x_gpio->gc.owner = THIS_MODULE; tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in; diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 506c6a67c5fc..fbaf974277df 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -67,8 +67,8 @@ struct tegra_gpio_info; struct tegra_gpio_bank { - int bank; - int irq; + unsigned int bank; + unsigned int irq; spinlock_t lvl_lock[4]; spinlock_t dbc_lock[4]; /* Lock for updating debounce count register */ #ifdef CONFIG_PM_SLEEP @@ -112,13 +112,14 @@ static inline u32 tegra_gpio_readl(struct tegra_gpio_info *tgi, u32 reg) return __raw_readl(tgi->regs + reg); } -static int tegra_gpio_compose(int bank, int port, int bit) +static unsigned int tegra_gpio_compose(unsigned int bank, unsigned int port, + unsigned int bit) { return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7); } static void tegra_gpio_mask_write(struct tegra_gpio_info *tgi, u32 reg, - int gpio, int value) + unsigned int gpio, u32 value) { u32 val; @@ -128,22 +129,22 @@ static void tegra_gpio_mask_write(struct tegra_gpio_info *tgi, u32 reg, tegra_gpio_writel(tgi, val, reg); } -static void tegra_gpio_enable(struct tegra_gpio_info *tgi, int gpio) +static void tegra_gpio_enable(struct tegra_gpio_info *tgi, unsigned int gpio) { tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 1); } -static void tegra_gpio_disable(struct tegra_gpio_info *tgi, int gpio) +static void tegra_gpio_disable(struct tegra_gpio_info *tgi, unsigned int gpio) { tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 0); } -static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_request(struct gpio_chip *chip, unsigned int offset) { return pinctrl_request_gpio(offset); } -static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) +static void tegra_gpio_free(struct gpio_chip *chip, unsigned int offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); @@ -151,17 +152,18 @@ static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) tegra_gpio_disable(tgi, offset); } -static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static void tegra_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); tegra_gpio_mask_write(tgi, GPIO_MSK_OUT(tgi, offset), offset, value); } -static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); - int bval = BIT(GPIO_BIT(offset)); + unsigned int bval = BIT(GPIO_BIT(offset)); /* If gpio is in output mode then read from the out value */ if (tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)) & bval) @@ -170,7 +172,8 @@ static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(tegra_gpio_readl(tgi, GPIO_IN(tgi, offset)) & bval); } -static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); @@ -179,8 +182,9 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) return 0; } -static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) +static int tegra_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, + int value) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); @@ -190,7 +194,8 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int tegra_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); u32 pin_mask = BIT(GPIO_BIT(offset)); @@ -212,7 +217,7 @@ static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, struct tegra_gpio_bank *bank = &tgi->bank_info[GPIO_BANK(offset)]; unsigned int debounce_ms = DIV_ROUND_UP(debounce, 1000); unsigned long flags; - int port; + unsigned int port; if (!debounce_ms) { tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset), @@ -250,7 +255,7 @@ static int tegra_gpio_set_config(struct gpio_chip *chip, unsigned int offset, return tegra_gpio_set_debounce(chip, offset, debounce); } -static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) { struct tegra_gpio_info *tgi = gpiochip_get_data(chip); @@ -261,7 +266,7 @@ static void tegra_gpio_irq_ack(struct irq_data *d) { struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); struct tegra_gpio_info *tgi = bank->tgi; - int gpio = d->hwirq; + unsigned int gpio = d->hwirq; tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio)); } @@ -270,7 +275,7 @@ static void tegra_gpio_irq_mask(struct irq_data *d) { struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); struct tegra_gpio_info *tgi = bank->tgi; - int gpio = d->hwirq; + unsigned int gpio = d->hwirq; tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0); } @@ -279,20 +284,18 @@ static void tegra_gpio_irq_unmask(struct irq_data *d) { struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); struct tegra_gpio_info *tgi = bank->tgi; - int gpio = d->hwirq; + unsigned int gpio = d->hwirq; tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1); } static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - int gpio = d->hwirq; + unsigned int gpio = d->hwirq, port = GPIO_PORT(gpio), lvl_type; struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); struct tegra_gpio_info *tgi = bank->tgi; - int port = GPIO_PORT(gpio); - int lvl_type; - int val; unsigned long flags; + u32 val; int ret; switch (type & IRQ_TYPE_SENSE_MASK) { @@ -323,7 +326,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) ret = gpiochip_lock_as_irq(&tgi->gc, gpio); if (ret) { dev_err(tgi->dev, - "unable to lock Tegra GPIO %d as IRQ\n", gpio); + "unable to lock Tegra GPIO %u as IRQ\n", gpio); return ret; } @@ -351,17 +354,15 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d) { struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); struct tegra_gpio_info *tgi = bank->tgi; - int gpio = d->hwirq; + unsigned int gpio = d->hwirq; gpiochip_unlock_as_irq(&tgi->gc, gpio); } static void tegra_gpio_irq_handler(struct irq_desc *desc) { - int port; - int pin; + unsigned int port, pin, gpio; bool unmasked = false; - int gpio; u32 lvl; unsigned long sta; struct irq_chip *chip = irq_desc_get_chip(desc); @@ -389,7 +390,8 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } - generic_handle_irq(gpio_to_irq(gpio + pin)); + generic_handle_irq(irq_find_mapping(tgi->irq_domain, + gpio + pin)); } } @@ -404,8 +406,7 @@ static int tegra_gpio_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct tegra_gpio_info *tgi = platform_get_drvdata(pdev); unsigned long flags; - int b; - int p; + unsigned int b, p; local_irq_save(flags); @@ -413,7 +414,8 @@ static int tegra_gpio_resume(struct device *dev) struct tegra_gpio_bank *bank = &tgi->bank_info[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { - unsigned int gpio = (b<<5) | (p<<3); + unsigned int gpio = (b << 5) | (p << 3); + tegra_gpio_writel(tgi, bank->cnf[p], GPIO_CNF(tgi, gpio)); @@ -444,15 +446,15 @@ static int tegra_gpio_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct tegra_gpio_info *tgi = platform_get_drvdata(pdev); unsigned long flags; - int b; - int p; + unsigned int b, p; local_irq_save(flags); for (b = 0; b < tgi->bank_count; b++) { struct tegra_gpio_bank *bank = &tgi->bank_info[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { - unsigned int gpio = (b<<5) | (p<<3); + unsigned int gpio = (b << 5) | (p << 3); + bank->cnf[p] = tegra_gpio_readl(tgi, GPIO_CNF(tgi, gpio)); bank->out[p] = tegra_gpio_readl(tgi, @@ -483,7 +485,7 @@ static int tegra_gpio_suspend(struct device *dev) static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) { struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - int gpio = d->hwirq; + unsigned int gpio = d->hwirq; u32 port, bit, mask; port = GPIO_PORT(gpio); @@ -507,14 +509,14 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) static int dbg_gpio_show(struct seq_file *s, void *unused) { struct tegra_gpio_info *tgi = s->private; - int i; - int j; + unsigned int i, j; for (i = 0; i < tgi->bank_count; i++) { for (j = 0; j < 4; j++) { - int gpio = tegra_gpio_compose(i, j, 0); + unsigned int gpio = tegra_gpio_compose(i, j, 0); + seq_printf(s, - "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", + "%u:%u %02x %02x %02x %02x %02x %02x %06x\n", i, j, tegra_gpio_readl(tgi, GPIO_CNF(tgi, gpio)), tegra_gpio_readl(tgi, GPIO_OE(tgi, gpio)), @@ -542,7 +544,7 @@ static const struct file_operations debug_fops = { static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi) { - (void) debugfs_create_file("tegra_gpio", S_IRUGO, + (void) debugfs_create_file("tegra_gpio", 0444, NULL, tgi, &debug_fops); } @@ -566,35 +568,25 @@ static struct lock_class_key gpio_lock_class; static int tegra_gpio_probe(struct platform_device *pdev) { - const struct tegra_gpio_soc_config *config; struct tegra_gpio_info *tgi; struct resource *res; struct tegra_gpio_bank *bank; + unsigned int gpio, i, j; int ret; - int gpio; - int i; - int j; - - config = of_device_get_match_data(&pdev->dev); - if (!config) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL); if (!tgi) return -ENODEV; - tgi->soc = config; + tgi->soc = of_device_get_match_data(&pdev->dev); tgi->dev = &pdev->dev; - for (;;) { - res = platform_get_resource(pdev, IORESOURCE_IRQ, - tgi->bank_count); - if (!res) - break; - tgi->bank_count++; - } + ret = platform_irq_count(pdev); + if (ret < 0) + return ret; + + tgi->bank_count = ret; + if (!tgi->bank_count) { dev_err(&pdev->dev, "Missing IRQ resource\n"); return -ENODEV; @@ -626,13 +618,13 @@ static int tegra_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tgi); - if (config->debounce_supported) + if (tgi->soc->debounce_supported) tgi->gc.set_config = tegra_gpio_set_config; - tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count * + tgi->bank_info = devm_kcalloc(&pdev->dev, tgi->bank_count, sizeof(*tgi->bank_info), GFP_KERNEL); if (!tgi->bank_info) - return -ENODEV; + return -ENOMEM; tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node, tgi->gc.ngpio, @@ -641,15 +633,15 @@ static int tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; for (i = 0; i < tgi->bank_count; i++) { - res = platform_get_resource(pdev, IORESOURCE_IRQ, i); - if (!res) { - dev_err(&pdev->dev, "Missing IRQ resource\n"); - return -ENODEV; + ret = platform_get_irq(pdev, i); + if (ret < 0) { + dev_err(&pdev->dev, "Missing IRQ resource: %d\n", ret); + return ret; } bank = &tgi->bank_info[i]; bank->bank = i; - bank->irq = res->start; + bank->irq = ret; bank->tgi = tgi; } @@ -661,6 +653,7 @@ static int tegra_gpio_probe(struct platform_device *pdev) for (i = 0; i < tgi->bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); + tegra_gpio_writel(tgi, 0x00, GPIO_INT_ENB(tgi, gpio)); } } diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c new file mode 100644 index 000000000000..57efb251f9c4 --- /dev/null +++ b/drivers/gpio/gpio-thunderx.c @@ -0,0 +1,639 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2016, 2017 Cavium Inc. + */ + +#include <linux/bitops.h> +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/spinlock.h> + + +#define GPIO_RX_DAT 0x0 +#define GPIO_TX_SET 0x8 +#define GPIO_TX_CLR 0x10 +#define GPIO_CONST 0x90 +#define GPIO_CONST_GPIOS_MASK 0xff +#define GPIO_BIT_CFG 0x400 +#define GPIO_BIT_CFG_TX_OE BIT(0) +#define GPIO_BIT_CFG_PIN_XOR BIT(1) +#define GPIO_BIT_CFG_INT_EN BIT(2) +#define GPIO_BIT_CFG_INT_TYPE BIT(3) +#define GPIO_BIT_CFG_FIL_MASK GENMASK(11, 4) +#define GPIO_BIT_CFG_FIL_CNT_SHIFT 4 +#define GPIO_BIT_CFG_FIL_SEL_SHIFT 8 +#define GPIO_BIT_CFG_TX_OD BIT(12) +#define GPIO_BIT_CFG_PIN_SEL_MASK GENMASK(25, 16) +#define GPIO_INTR 0x800 +#define GPIO_INTR_INTR BIT(0) +#define GPIO_INTR_INTR_W1S BIT(1) +#define GPIO_INTR_ENA_W1C BIT(2) +#define GPIO_INTR_ENA_W1S BIT(3) +#define GPIO_2ND_BANK 0x1400 + +#define GLITCH_FILTER_400NS ((4u << GPIO_BIT_CFG_FIL_SEL_SHIFT) | \ + (9u << GPIO_BIT_CFG_FIL_CNT_SHIFT)) + +struct thunderx_gpio; + +struct thunderx_line { + struct thunderx_gpio *txgpio; + unsigned int line; + unsigned int fil_bits; +}; + +struct thunderx_gpio { + struct gpio_chip chip; + u8 __iomem *register_base; + struct irq_domain *irqd; + struct msix_entry *msix_entries; /* per line MSI-X */ + struct thunderx_line *line_entries; /* per line irq info */ + raw_spinlock_t lock; + unsigned long invert_mask[2]; + unsigned long od_mask[2]; + int base_msi; +}; + +static unsigned int bit_cfg_reg(unsigned int line) +{ + return 8 * line + GPIO_BIT_CFG; +} + +static unsigned int intr_reg(unsigned int line) +{ + return 8 * line + GPIO_INTR; +} + +static bool thunderx_gpio_is_gpio_nowarn(struct thunderx_gpio *txgpio, + unsigned int line) +{ + u64 bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line)); + + return (bit_cfg & GPIO_BIT_CFG_PIN_SEL_MASK) == 0; +} + +/* + * Check (and WARN) that the pin is available for GPIO. We will not + * allow modification of the state of non-GPIO pins from this driver. + */ +static bool thunderx_gpio_is_gpio(struct thunderx_gpio *txgpio, + unsigned int line) +{ + bool rv = thunderx_gpio_is_gpio_nowarn(txgpio, line); + + WARN_RATELIMIT(!rv, "Pin %d not available for GPIO\n", line); + + return rv; +} + +static int thunderx_gpio_request(struct gpio_chip *chip, unsigned int line) +{ + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + + return thunderx_gpio_is_gpio(txgpio, line) ? 0 : -EIO; +} + +static int thunderx_gpio_dir_in(struct gpio_chip *chip, unsigned int line) +{ + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + + if (!thunderx_gpio_is_gpio(txgpio, line)) + return -EIO; + + raw_spin_lock(&txgpio->lock); + clear_bit(line, txgpio->invert_mask); + clear_bit(line, txgpio->od_mask); + writeq(txgpio->line_entries[line].fil_bits, + txgpio->register_base + bit_cfg_reg(line)); + raw_spin_unlock(&txgpio->lock); + return 0; +} + +static void thunderx_gpio_set(struct gpio_chip *chip, unsigned int line, + int value) +{ + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + int bank = line / 64; + int bank_bit = line % 64; + + void __iomem *reg = txgpio->register_base + + (bank * GPIO_2ND_BANK) + (value ? GPIO_TX_SET : GPIO_TX_CLR); + + writeq(BIT_ULL(bank_bit), reg); +} + +static int thunderx_gpio_dir_out(struct gpio_chip *chip, unsigned int line, + int value) +{ + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + u64 bit_cfg = txgpio->line_entries[line].fil_bits | GPIO_BIT_CFG_TX_OE; + + if (!thunderx_gpio_is_gpio(txgpio, line)) + return -EIO; + + raw_spin_lock(&txgpio->lock); + + thunderx_gpio_set(chip, line, value); + + if (test_bit(line, txgpio->invert_mask)) + bit_cfg |= GPIO_BIT_CFG_PIN_XOR; + + if (test_bit(line, txgpio->od_mask)) + bit_cfg |= GPIO_BIT_CFG_TX_OD; + + writeq(bit_cfg, txgpio->register_base + bit_cfg_reg(line)); + + raw_spin_unlock(&txgpio->lock); + return 0; +} + +static int thunderx_gpio_get_direction(struct gpio_chip *chip, unsigned int line) +{ + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + u64 bit_cfg; + + if (!thunderx_gpio_is_gpio_nowarn(txgpio, line)) + /* + * Say it is input for now to avoid WARNing on + * gpiochip_add_data(). We will WARN if someone + * requests it or tries to use it. + */ + return 1; + + bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line)); + + return !(bit_cfg & GPIO_BIT_CFG_TX_OE); +} + +static int thunderx_gpio_set_config(struct gpio_chip *chip, + unsigned int line, + unsigned long cfg) +{ + bool orig_invert, orig_od, orig_dat, new_invert, new_od; + u32 arg, sel; + u64 bit_cfg; + int bank = line / 64; + int bank_bit = line % 64; + int ret = -ENOTSUPP; + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + void __iomem *reg = txgpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_TX_SET; + + if (!thunderx_gpio_is_gpio(txgpio, line)) + return -EIO; + + raw_spin_lock(&txgpio->lock); + orig_invert = test_bit(line, txgpio->invert_mask); + new_invert = orig_invert; + orig_od = test_bit(line, txgpio->od_mask); + new_od = orig_od; + orig_dat = ((readq(reg) >> bank_bit) & 1) ^ orig_invert; + bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line)); + switch (pinconf_to_config_param(cfg)) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + /* + * Weird, setting open-drain mode causes signal + * inversion. Note this so we can compensate in the + * dir_out function. + */ + set_bit(line, txgpio->invert_mask); + new_invert = true; + set_bit(line, txgpio->od_mask); + new_od = true; + ret = 0; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + clear_bit(line, txgpio->invert_mask); + new_invert = false; + clear_bit(line, txgpio->od_mask); + new_od = false; + ret = 0; + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + arg = pinconf_to_config_argument(cfg); + if (arg > 1228) { /* 15 * 2^15 * 2.5nS maximum */ + ret = -EINVAL; + break; + } + arg *= 400; /* scale to 2.5nS clocks. */ + sel = 0; + while (arg > 15) { + sel++; + arg++; /* always round up */ + arg >>= 1; + } + txgpio->line_entries[line].fil_bits = + (sel << GPIO_BIT_CFG_FIL_SEL_SHIFT) | + (arg << GPIO_BIT_CFG_FIL_CNT_SHIFT); + bit_cfg &= ~GPIO_BIT_CFG_FIL_MASK; + bit_cfg |= txgpio->line_entries[line].fil_bits; + writeq(bit_cfg, txgpio->register_base + bit_cfg_reg(line)); + ret = 0; + break; + default: + break; + } + raw_spin_unlock(&txgpio->lock); + + /* + * If currently output and OPEN_DRAIN changed, install the new + * settings + */ + if ((new_invert != orig_invert || new_od != orig_od) && + (bit_cfg & GPIO_BIT_CFG_TX_OE)) + ret = thunderx_gpio_dir_out(chip, line, orig_dat ^ new_invert); + + return ret; +} + +static int thunderx_gpio_get(struct gpio_chip *chip, unsigned int line) +{ + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + int bank = line / 64; + int bank_bit = line % 64; + u64 read_bits = readq(txgpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_RX_DAT); + u64 masked_bits = read_bits & BIT_ULL(bank_bit); + + if (test_bit(line, txgpio->invert_mask)) + return masked_bits == 0; + else + return masked_bits != 0; +} + +static void thunderx_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, + unsigned long *bits) +{ + int bank; + u64 set_bits, clear_bits; + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + + for (bank = 0; bank <= chip->ngpio / 64; bank++) { + set_bits = bits[bank] & mask[bank]; + clear_bits = ~bits[bank] & mask[bank]; + writeq(set_bits, txgpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_TX_SET); + writeq(clear_bits, txgpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_TX_CLR); + } +} + +static void thunderx_gpio_irq_ack(struct irq_data *data) +{ + struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + + writeq(GPIO_INTR_INTR, + txline->txgpio->register_base + intr_reg(txline->line)); +} + +static void thunderx_gpio_irq_mask(struct irq_data *data) +{ + struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + + writeq(GPIO_INTR_ENA_W1C, + txline->txgpio->register_base + intr_reg(txline->line)); +} + +static void thunderx_gpio_irq_mask_ack(struct irq_data *data) +{ + struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + + writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR, + txline->txgpio->register_base + intr_reg(txline->line)); +} + +static void thunderx_gpio_irq_unmask(struct irq_data *data) +{ + struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + + writeq(GPIO_INTR_ENA_W1S, + txline->txgpio->register_base + intr_reg(txline->line)); +} + +static int thunderx_gpio_irq_set_type(struct irq_data *data, + unsigned int flow_type) +{ + struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct thunderx_gpio *txgpio = txline->txgpio; + u64 bit_cfg; + + irqd_set_trigger_type(data, flow_type); + + bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN; + + if (flow_type & IRQ_TYPE_EDGE_BOTH) { + irq_set_handler_locked(data, handle_fasteoi_ack_irq); + bit_cfg |= GPIO_BIT_CFG_INT_TYPE; + } else { + irq_set_handler_locked(data, handle_fasteoi_mask_irq); + } + + raw_spin_lock(&txgpio->lock); + if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)) { + bit_cfg |= GPIO_BIT_CFG_PIN_XOR; + set_bit(txline->line, txgpio->invert_mask); + } else { + clear_bit(txline->line, txgpio->invert_mask); + } + clear_bit(txline->line, txgpio->od_mask); + writeq(bit_cfg, txgpio->register_base + bit_cfg_reg(txline->line)); + raw_spin_unlock(&txgpio->lock); + + return IRQ_SET_MASK_OK; +} + +static void thunderx_gpio_irq_enable(struct irq_data *data) +{ + irq_chip_enable_parent(data); + thunderx_gpio_irq_unmask(data); +} + +static void thunderx_gpio_irq_disable(struct irq_data *data) +{ + thunderx_gpio_irq_mask(data); + irq_chip_disable_parent(data); +} + +static int thunderx_gpio_irq_request_resources(struct irq_data *data) +{ + struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct thunderx_gpio *txgpio = txline->txgpio; + struct irq_data *parent_data = data->parent_data; + int r; + + r = gpiochip_lock_as_irq(&txgpio->chip, txline->line); + if (r) + return r; + + if (parent_data && parent_data->chip->irq_request_resources) { + r = parent_data->chip->irq_request_resources(parent_data); + if (r) + goto error; + } + + return 0; +error: + gpiochip_unlock_as_irq(&txgpio->chip, txline->line); + return r; +} + +static void thunderx_gpio_irq_release_resources(struct irq_data *data) +{ + struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct thunderx_gpio *txgpio = txline->txgpio; + struct irq_data *parent_data = data->parent_data; + + if (parent_data && parent_data->chip->irq_release_resources) + parent_data->chip->irq_release_resources(parent_data); + + gpiochip_unlock_as_irq(&txgpio->chip, txline->line); +} + +/* + * Interrupts are chained from underlying MSI-X vectors. We have + * these irq_chip functions to be able to handle level triggering + * semantics and other acknowledgment tasks associated with the GPIO + * mechanism. + */ +static struct irq_chip thunderx_gpio_irq_chip = { + .name = "GPIO", + .irq_enable = thunderx_gpio_irq_enable, + .irq_disable = thunderx_gpio_irq_disable, + .irq_ack = thunderx_gpio_irq_ack, + .irq_mask = thunderx_gpio_irq_mask, + .irq_mask_ack = thunderx_gpio_irq_mask_ack, + .irq_unmask = thunderx_gpio_irq_unmask, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_affinity = irq_chip_set_affinity_parent, + .irq_request_resources = thunderx_gpio_irq_request_resources, + .irq_release_resources = thunderx_gpio_irq_release_resources, + .irq_set_type = thunderx_gpio_irq_set_type, + + .flags = IRQCHIP_SET_TYPE_MASKED +}; + +static int thunderx_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct thunderx_gpio *txgpio = d->host_data; + + if (hwirq >= txgpio->chip.ngpio) + return -EINVAL; + if (!thunderx_gpio_is_gpio_nowarn(txgpio, hwirq)) + return -EPERM; + return 0; +} + +static int thunderx_gpio_irq_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + irq_hw_number_t *hwirq, + unsigned int *type) +{ + struct thunderx_gpio *txgpio = d->host_data; + + if (WARN_ON(fwspec->param_count < 2)) + return -EINVAL; + if (fwspec->param[0] >= txgpio->chip.ngpio) + return -EINVAL; + *hwirq = fwspec->param[0]; + *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + return 0; +} + +static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + struct thunderx_line *txline = arg; + + return irq_domain_set_hwirq_and_chip(d, virq, txline->line, + &thunderx_gpio_irq_chip, txline); +} + +static const struct irq_domain_ops thunderx_gpio_irqd_ops = { + .map = thunderx_gpio_irq_map, + .alloc = thunderx_gpio_irq_alloc, + .translate = thunderx_gpio_irq_translate +}; + +static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct thunderx_gpio *txgpio = gpiochip_get_data(chip); + + return irq_find_mapping(txgpio->irqd, offset); +} + +static int thunderx_gpio_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem * const *tbl; + struct device *dev = &pdev->dev; + struct thunderx_gpio *txgpio; + struct gpio_chip *chip; + int ngpio, i; + int err = 0; + + txgpio = devm_kzalloc(dev, sizeof(*txgpio), GFP_KERNEL); + if (!txgpio) + return -ENOMEM; + + raw_spin_lock_init(&txgpio->lock); + chip = &txgpio->chip; + + pci_set_drvdata(pdev, txgpio); + + err = pcim_enable_device(pdev); + if (err) { + dev_err(dev, "Failed to enable PCI device: err %d\n", err); + goto out; + } + + err = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME); + if (err) { + dev_err(dev, "Failed to iomap PCI device: err %d\n", err); + goto out; + } + + tbl = pcim_iomap_table(pdev); + txgpio->register_base = tbl[0]; + if (!txgpio->register_base) { + dev_err(dev, "Cannot map PCI resource\n"); + err = -ENOMEM; + goto out; + } + + if (pdev->subsystem_device == 0xa10a) { + /* CN88XX has no GPIO_CONST register*/ + ngpio = 50; + txgpio->base_msi = 48; + } else { + u64 c = readq(txgpio->register_base + GPIO_CONST); + + ngpio = c & GPIO_CONST_GPIOS_MASK; + txgpio->base_msi = (c >> 8) & 0xff; + } + + txgpio->msix_entries = devm_kzalloc(dev, + sizeof(struct msix_entry) * ngpio, + GFP_KERNEL); + if (!txgpio->msix_entries) { + err = -ENOMEM; + goto out; + } + + txgpio->line_entries = devm_kzalloc(dev, + sizeof(struct thunderx_line) * ngpio, + GFP_KERNEL); + if (!txgpio->line_entries) { + err = -ENOMEM; + goto out; + } + + for (i = 0; i < ngpio; i++) { + u64 bit_cfg = readq(txgpio->register_base + bit_cfg_reg(i)); + + txgpio->msix_entries[i].entry = txgpio->base_msi + (2 * i); + txgpio->line_entries[i].line = i; + txgpio->line_entries[i].txgpio = txgpio; + /* + * If something has already programmed the pin, use + * the existing glitch filter settings, otherwise go + * to 400nS. + */ + txgpio->line_entries[i].fil_bits = bit_cfg ? + (bit_cfg & GPIO_BIT_CFG_FIL_MASK) : GLITCH_FILTER_400NS; + + if ((bit_cfg & GPIO_BIT_CFG_TX_OE) && (bit_cfg & GPIO_BIT_CFG_TX_OD)) + set_bit(i, txgpio->od_mask); + if (bit_cfg & GPIO_BIT_CFG_PIN_XOR) + set_bit(i, txgpio->invert_mask); + } + + + /* Enable all MSI-X for interrupts on all possible lines. */ + err = pci_enable_msix_range(pdev, txgpio->msix_entries, ngpio, ngpio); + if (err < 0) + goto out; + + /* + * Push GPIO specific irqdomain on hierarchy created as a side + * effect of the pci_enable_msix() + */ + txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain, + 0, 0, of_node_to_fwnode(dev->of_node), + &thunderx_gpio_irqd_ops, txgpio); + if (!txgpio->irqd) + goto out; + + /* Push on irq_data and the domain for each line. */ + for (i = 0; i < ngpio; i++) { + err = irq_domain_push_irq(txgpio->irqd, + txgpio->msix_entries[i].vector, + &txgpio->line_entries[i]); + if (err < 0) + dev_err(dev, "irq_domain_push_irq: %d\n", err); + } + + chip->label = KBUILD_MODNAME; + chip->parent = dev; + chip->owner = THIS_MODULE; + chip->request = thunderx_gpio_request; + chip->base = -1; /* System allocated */ + chip->can_sleep = false; + chip->ngpio = ngpio; + chip->get_direction = thunderx_gpio_get_direction; + chip->direction_input = thunderx_gpio_dir_in; + chip->get = thunderx_gpio_get; + chip->direction_output = thunderx_gpio_dir_out; + chip->set = thunderx_gpio_set; + chip->set_multiple = thunderx_gpio_set_multiple; + chip->set_config = thunderx_gpio_set_config; + chip->to_irq = thunderx_gpio_to_irq; + err = devm_gpiochip_add_data(dev, chip, txgpio); + if (err) + goto out; + + dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n", + ngpio, chip->base); + return 0; +out: + pci_set_drvdata(pdev, NULL); + return err; +} + +static void thunderx_gpio_remove(struct pci_dev *pdev) +{ + int i; + struct thunderx_gpio *txgpio = pci_get_drvdata(pdev); + + for (i = 0; i < txgpio->chip.ngpio; i++) + irq_domain_pop_irq(txgpio->irqd, + txgpio->msix_entries[i].vector); + + irq_domain_remove(txgpio->irqd); + + pci_set_drvdata(pdev, NULL); +} + +static const struct pci_device_id thunderx_gpio_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xA00A) }, + { 0, } /* end of table */ +}; + +MODULE_DEVICE_TABLE(pci, thunderx_gpio_id_table); + +static struct pci_driver thunderx_gpio_driver = { + .name = KBUILD_MODNAME, + .id_table = thunderx_gpio_id_table, + .probe = thunderx_gpio_probe, + .remove = thunderx_gpio_remove, +}; + +module_pci_driver(thunderx_gpio_driver); + +MODULE_DESCRIPTION("Cavium Inc. ThunderX/OCTEON-TX GPIO Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c new file mode 100644 index 000000000000..fa2662f8b026 --- /dev/null +++ b/drivers/gpio/gpio-tps68470.c @@ -0,0 +1,176 @@ +/* + * GPIO driver for TPS68470 PMIC + * + * Copyright (C) 2017 Intel Corporation + * + * Authors: + * Antti Laakso <antti.laakso@intel.com> + * Tianshu Qiu <tian.shu.qiu@intel.com> + * Jian Xu Zheng <jian.xu.zheng@intel.com> + * Yuning Pu <yuning.pu@intel.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/gpio/driver.h> +#include <linux/mfd/tps68470.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define TPS68470_N_LOGIC_OUTPUT 3 +#define TPS68470_N_REGULAR_GPIO 7 +#define TPS68470_N_GPIO (TPS68470_N_LOGIC_OUTPUT + TPS68470_N_REGULAR_GPIO) + +struct tps68470_gpio_data { + struct regmap *tps68470_regmap; + struct gpio_chip gc; +}; + +static int tps68470_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + unsigned int reg = TPS68470_REG_GPDO; + int val, ret; + + if (offset >= TPS68470_N_REGULAR_GPIO) { + offset -= TPS68470_N_REGULAR_GPIO; + reg = TPS68470_REG_SGPO; + } + + ret = regmap_read(regmap, reg, &val); + if (ret) { + dev_err(tps68470_gpio->gc.parent, "reg 0x%x read failed\n", + TPS68470_REG_SGPO); + return ret; + } + return !!(val & BIT(offset)); +} + +/* Return 0 if output, 1 if input */ +static int tps68470_gpio_get_direction(struct gpio_chip *gc, + unsigned int offset) +{ + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + int val, ret; + + /* rest are always outputs */ + if (offset >= TPS68470_N_REGULAR_GPIO) + return 0; + + ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val); + if (ret) { + dev_err(tps68470_gpio->gc.parent, "reg 0x%x read failed\n", + TPS68470_GPIO_CTL_REG_A(offset)); + return ret; + } + + val &= TPS68470_GPIO_MODE_MASK; + return val >= TPS68470_GPIO_MODE_OUT_CMOS ? 0 : 1; +} + +static void tps68470_gpio_set(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + unsigned int reg = TPS68470_REG_GPDO; + + if (offset >= TPS68470_N_REGULAR_GPIO) { + reg = TPS68470_REG_SGPO; + offset -= TPS68470_N_REGULAR_GPIO; + } + + regmap_update_bits(regmap, reg, BIT(offset), value ? BIT(offset) : 0); +} + +static int tps68470_gpio_output(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + + /* rest are always outputs */ + if (offset >= TPS68470_N_REGULAR_GPIO) + return 0; + + /* Set the initial value */ + tps68470_gpio_set(gc, offset, value); + + return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset), + TPS68470_GPIO_MODE_MASK, + TPS68470_GPIO_MODE_OUT_CMOS); +} + +static int tps68470_gpio_input(struct gpio_chip *gc, unsigned int offset) +{ + struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + + /* rest are always outputs */ + if (offset >= TPS68470_N_REGULAR_GPIO) + return -EINVAL; + + return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset), + TPS68470_GPIO_MODE_MASK, 0x00); +} + +static const char *tps68470_names[TPS68470_N_GPIO] = { + "gpio.0", "gpio.1", "gpio.2", "gpio.3", + "gpio.4", "gpio.5", "gpio.6", + "s_enable", "s_idle", "s_resetn", +}; + +static int tps68470_gpio_probe(struct platform_device *pdev) +{ + struct tps68470_gpio_data *tps68470_gpio; + int ret; + + tps68470_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps68470_gpio), + GFP_KERNEL); + if (!tps68470_gpio) + return -ENOMEM; + + tps68470_gpio->tps68470_regmap = dev_get_drvdata(pdev->dev.parent); + tps68470_gpio->gc.label = "tps68470-gpio"; + tps68470_gpio->gc.owner = THIS_MODULE; + tps68470_gpio->gc.direction_input = tps68470_gpio_input; + tps68470_gpio->gc.direction_output = tps68470_gpio_output; + tps68470_gpio->gc.get = tps68470_gpio_get; + tps68470_gpio->gc.get_direction = tps68470_gpio_get_direction; + tps68470_gpio->gc.set = tps68470_gpio_set; + tps68470_gpio->gc.can_sleep = true; + tps68470_gpio->gc.names = tps68470_names; + tps68470_gpio->gc.ngpio = TPS68470_N_GPIO; + tps68470_gpio->gc.base = -1; + tps68470_gpio->gc.parent = &pdev->dev; + + ret = devm_gpiochip_add_data(&pdev->dev, &tps68470_gpio->gc, + tps68470_gpio); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register gpio_chip: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, tps68470_gpio); + + return ret; +} + +static struct platform_driver tps68470_gpio_driver = { + .driver = { + .name = "tps68470-gpio", + }, + .probe = tps68470_gpio_probe, +}; + +builtin_platform_driver(tps68470_gpio_driver) diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index b780314cdfc9..dadeacf43e0c 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -32,8 +32,6 @@ #include <linux/mfd/twl6040.h> -static struct gpio_chip twl6040gpo_chip; - static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset) { struct twl6040 *twl6040 = dev_get_drvdata(chip->parent->parent); diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index ca958e0f6909..22c5be65051f 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -527,13 +527,12 @@ static void tz1090_gpio_register_banks(struct tz1090_gpio *priv) ret = of_property_read_u32(node, "reg", &addr); if (ret) { - dev_err(priv->dev, "invalid reg on %s\n", - node->full_name); + dev_err(priv->dev, "invalid reg on %pOF\n", node); continue; } if (addr >= 3) { - dev_err(priv->dev, "index %u in %s out of range\n", - addr, node->full_name); + dev_err(priv->dev, "index %u in %pOF out of range\n", + addr, node); continue; } @@ -543,8 +542,7 @@ static void tz1090_gpio_register_banks(struct tz1090_gpio *priv) ret = tz1090_gpio_bank_probe(&info); if (ret) { - dev_err(priv->dev, "failure registering %s\n", - node->full_name); + dev_err(priv->dev, "failure registering %pOF\n", node); of_node_put(node); continue; } diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 521fbe338589..cbe9e06861de 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -30,10 +30,16 @@ #define VF610_GPIO_PER_PORT 32 +struct fsl_gpio_soc_data { + /* SoCs has a Port Data Direction Register (PDDR) */ + bool have_paddr; +}; + struct vf610_gpio_port { struct gpio_chip gc; void __iomem *base; void __iomem *gpio_base; + const struct fsl_gpio_soc_data *sdata; u8 irqc[VF610_GPIO_PER_PORT]; int irq; }; @@ -43,6 +49,7 @@ struct vf610_gpio_port { #define GPIO_PCOR 0x08 #define GPIO_PTOR 0x0c #define GPIO_PDIR 0x10 +#define GPIO_PDDR 0x14 #define PORT_PCR(n) ((n) * 0x4) #define PORT_PCR_IRQC_OFFSET 16 @@ -61,8 +68,13 @@ struct vf610_gpio_port { static struct irq_chip vf610_gpio_irq_chip; +static const struct fsl_gpio_soc_data imx_data = { + .have_paddr = true, +}; + static const struct of_device_id vf610_gpio_dt_ids[] = { - { .compatible = "fsl,vf610-gpio" }, + { .compatible = "fsl,vf610-gpio", .data = NULL, }, + { .compatible = "fsl,imx7ulp-gpio", .data = &imx_data, }, { /* sentinel */ } }; @@ -79,8 +91,18 @@ static inline u32 vf610_gpio_readl(void __iomem *reg) static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio) { struct vf610_gpio_port *port = gpiochip_get_data(gc); - - return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) & BIT(gpio)); + unsigned long mask = BIT(gpio); + void __iomem *addr; + + if (port->sdata && port->sdata->have_paddr) { + mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR); + addr = mask ? port->gpio_base + GPIO_PDOR : + port->gpio_base + GPIO_PDIR; + return !!(vf610_gpio_readl(addr) & BIT(gpio)); + } else { + return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) + & BIT(gpio)); + } } static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) @@ -96,12 +118,28 @@ static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { + struct vf610_gpio_port *port = gpiochip_get_data(chip); + unsigned long mask = BIT(gpio); + u32 val; + + if (port->sdata && port->sdata->have_paddr) { + val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR); + val &= ~mask; + vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR); + } + return pinctrl_gpio_direction_input(chip->base + gpio); } static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) { + struct vf610_gpio_port *port = gpiochip_get_data(chip); + unsigned long mask = BIT(gpio); + + if (port->sdata && port->sdata->have_paddr) + vf610_gpio_writel(mask, port->gpio_base + GPIO_PDDR); + vf610_gpio_set(chip, gpio, value); return pinctrl_gpio_direction_output(chip->base + gpio); @@ -216,6 +254,8 @@ static struct irq_chip vf610_gpio_irq_chip = { static int vf610_gpio_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = of_match_device(vf610_gpio_dt_ids, + &pdev->dev); struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct vf610_gpio_port *port; @@ -227,6 +267,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) if (!port) return -ENOMEM; + port->sdata = of_id->data; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); port->base = devm_ioremap_resource(dev, iores); if (IS_ERR(port->base)) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 14b2a62338ea..e8ec0e33a0a9 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -360,8 +360,8 @@ static int xgpio_probe(struct platform_device *pdev) /* Call the OF gpio helper to setup and register the GPIO device */ status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip); if (status) { - pr_err("%s: error in probe function with status %d\n", - np->full_name, status); + pr_err("%pOF: error in probe function with status %d\n", + np, status); return status; } diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index e23ef7b9451d..3926ce9c2840 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -156,7 +156,7 @@ static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin) return -ENXIO; } -static struct gpio_chip zevio_gpio_chip = { +static const struct gpio_chip zevio_gpio_chip = { .direction_input = zevio_gpio_direction_input, .direction_output = zevio_gpio_direction_output, .set = zevio_gpio_set, diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index df0851464006..b3cc948a2d8b 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -60,13 +60,13 @@ #define ZYNQ_GPIO_BANK5_PIN_MAX(str) (ZYNQ_GPIO_BANK5_PIN_MIN(str) + \ ZYNQ##str##_GPIO_BANK5_NGPIO - 1) - /* Register offsets for the GPIO device */ /* LSW Mask & Data -WO */ #define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK)) /* MSW Mask & Data -WO */ #define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK)) /* Data Register-RW */ +#define ZYNQ_GPIO_DATA_OFFSET(BANK) (0x040 + (4 * BANK)) #define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK)) /* Direction mode reg-RW */ #define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK)) @@ -98,6 +98,19 @@ /* set to differentiate zynq from zynqmp, 0=zynqmp, 1=zynq */ #define ZYNQ_GPIO_QUIRK_IS_ZYNQ BIT(0) +#define GPIO_QUIRK_DATA_RO_BUG BIT(1) + +struct gpio_regs { + u32 datamsw[ZYNQMP_GPIO_MAX_BANK]; + u32 datalsw[ZYNQMP_GPIO_MAX_BANK]; + u32 dirm[ZYNQMP_GPIO_MAX_BANK]; + u32 outen[ZYNQMP_GPIO_MAX_BANK]; + u32 int_en[ZYNQMP_GPIO_MAX_BANK]; + u32 int_dis[ZYNQMP_GPIO_MAX_BANK]; + u32 int_type[ZYNQMP_GPIO_MAX_BANK]; + u32 int_polarity[ZYNQMP_GPIO_MAX_BANK]; + u32 int_any[ZYNQMP_GPIO_MAX_BANK]; +}; /** * struct zynq_gpio - gpio device private data structure @@ -106,6 +119,7 @@ * @clk: clock resource for this controller * @irq: interrupt for the GPIO device * @p_data: pointer to platform data + * @context: context registers */ struct zynq_gpio { struct gpio_chip chip; @@ -113,16 +127,18 @@ struct zynq_gpio { struct clk *clk; int irq; const struct zynq_platform_data *p_data; + struct gpio_regs context; }; /** * struct zynq_platform_data - zynq gpio platform data structure * @label: string to store in gpio->label + * @quirks: Flags is used to identify the platform * @ngpio: max number of gpio pins * @max_bank: maximum number of gpio banks * @bank_min: this array represents bank's min pin * @bank_max: this array represents bank's max pin -*/ + */ struct zynq_platform_data { const char *label; u32 quirks; @@ -147,6 +163,17 @@ static int zynq_gpio_is_zynq(struct zynq_gpio *gpio) } /** + * gpio_data_ro_bug - test if HW bug exists or not + * @gpio: Pointer to driver data struct + * + * Return: 0 if bug doesnot exist, 1 if bug exists. + */ +static int gpio_data_ro_bug(struct zynq_gpio *gpio) +{ + return !!(gpio->p_data->quirks & GPIO_QUIRK_DATA_RO_BUG); +} + +/** * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank * for a given pin in the GPIO device * @pin_num: gpio pin number within the device @@ -154,6 +181,7 @@ static int zynq_gpio_is_zynq(struct zynq_gpio *gpio) * pin * @bank_pin_num: an output parameter used to return pin number within a bank * for the given gpio pin + * @gpio: gpio device data structure * * Returns the bank number and pin offset within the bank. */ @@ -166,11 +194,11 @@ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num, for (bank = 0; bank < gpio->p_data->max_bank; bank++) { if ((pin_num >= gpio->p_data->bank_min[bank]) && - (pin_num <= gpio->p_data->bank_max[bank])) { - *bank_num = bank; - *bank_pin_num = pin_num - - gpio->p_data->bank_min[bank]; - return; + (pin_num <= gpio->p_data->bank_max[bank])) { + *bank_num = bank; + *bank_pin_num = pin_num - + gpio->p_data->bank_min[bank]; + return; } } @@ -197,9 +225,28 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin) zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); - data = readl_relaxed(gpio->base_addr + - ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); - + if (gpio_data_ro_bug(gpio)) { + if (zynq_gpio_is_zynq(gpio)) { + if (bank_num <= 1) { + data = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); + } else { + data = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DATA_OFFSET(bank_num)); + } + } else { + if (bank_num <= 2) { + data = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); + } else { + data = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DATA_OFFSET(bank_num)); + } + } + } else { + data = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); + } return (data >> bank_pin_num) & 1; } @@ -263,7 +310,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) * as inputs. */ if (zynq_gpio_is_zynq(gpio) && bank_num == 0 && - (bank_pin_num == 7 || bank_pin_num == 8)) + (bank_pin_num == 7 || bank_pin_num == 8)) return -EINVAL; /* clear the bit in direction mode reg to set the pin as input */ @@ -464,13 +511,14 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) writel_relaxed(int_any, gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); - if (type & IRQ_TYPE_LEVEL_MASK) { + if (type & IRQ_TYPE_LEVEL_MASK) irq_set_chip_handler_name_locked(irq_data, - &zynq_gpio_level_irqchip, handle_fasteoi_irq, NULL); - } else { + &zynq_gpio_level_irqchip, + handle_fasteoi_irq, NULL); + else irq_set_chip_handler_name_locked(irq_data, - &zynq_gpio_edge_irqchip, handle_level_irq, NULL); - } + &zynq_gpio_edge_irqchip, + handle_level_irq, NULL); return 0; } @@ -530,7 +578,6 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio, /** * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device - * @irq: irq number of the gpio bank where interrupt has occurred * @desc: irq descriptor instance of the 'irq' * * This function reads the Interrupt Status Register of each bank to get the @@ -560,14 +607,73 @@ static void zynq_gpio_irqhandler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } +static void zynq_gpio_save_context(struct zynq_gpio *gpio) +{ + unsigned int bank_num; + + for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { + gpio->context.datalsw[bank_num] = + readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num)); + gpio->context.datamsw[bank_num] = + readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num)); + gpio->context.dirm[bank_num] = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + gpio->context.int_en[bank_num] = readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTMASK_OFFSET(bank_num)); + gpio->context.int_type[bank_num] = + readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); + gpio->context.int_polarity[bank_num] = + readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); + gpio->context.int_any[bank_num] = + readl_relaxed(gpio->base_addr + + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + } +} + +static void zynq_gpio_restore_context(struct zynq_gpio *gpio) +{ + unsigned int bank_num; + + for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { + writel_relaxed(gpio->context.datalsw[bank_num], + gpio->base_addr + + ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num)); + writel_relaxed(gpio->context.datamsw[bank_num], + gpio->base_addr + + ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num)); + writel_relaxed(gpio->context.dirm[bank_num], + gpio->base_addr + + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); + writel_relaxed(gpio->context.int_en[bank_num], + gpio->base_addr + + ZYNQ_GPIO_INTEN_OFFSET(bank_num)); + writel_relaxed(gpio->context.int_type[bank_num], + gpio->base_addr + + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); + writel_relaxed(gpio->context.int_polarity[bank_num], + gpio->base_addr + + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); + writel_relaxed(gpio->context.int_any[bank_num], + gpio->base_addr + + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + } +} + static int __maybe_unused zynq_gpio_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); int irq = platform_get_irq(pdev, 0); struct irq_data *data = irq_get_irq_data(irq); + struct zynq_gpio *gpio = platform_get_drvdata(pdev); - if (!irqd_is_wakeup_set(data)) + if (!irqd_is_wakeup_set(data)) { + zynq_gpio_save_context(gpio); return pm_runtime_force_suspend(dev); + } return 0; } @@ -577,9 +683,14 @@ static int __maybe_unused zynq_gpio_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); int irq = platform_get_irq(pdev, 0); struct irq_data *data = irq_get_irq_data(irq); + struct zynq_gpio *gpio = platform_get_drvdata(pdev); + int ret; - if (!irqd_is_wakeup_set(data)) - return pm_runtime_force_resume(dev); + if (!irqd_is_wakeup_set(data)) { + ret = pm_runtime_force_resume(dev); + zynq_gpio_restore_context(gpio); + return ret; + } return 0; } @@ -602,7 +713,7 @@ static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev) return clk_prepare_enable(gpio->clk); } -static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset) +static int zynq_gpio_request(struct gpio_chip *chip, unsigned int offset) { int ret; @@ -615,7 +726,7 @@ static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset) return ret < 0 ? ret : 0; } -static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset) +static void zynq_gpio_free(struct gpio_chip *chip, unsigned int offset) { pm_runtime_put(chip->parent); } @@ -623,11 +734,12 @@ static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset) static const struct dev_pm_ops zynq_gpio_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume) SET_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, - zynq_gpio_runtime_resume, NULL) + zynq_gpio_runtime_resume, NULL) }; static const struct zynq_platform_data zynqmp_gpio_def = { .label = "zynqmp_gpio", + .quirks = GPIO_QUIRK_DATA_RO_BUG, .ngpio = ZYNQMP_GPIO_NR_GPIOS, .max_bank = ZYNQMP_GPIO_MAX_BANK, .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP), @@ -646,7 +758,7 @@ static const struct zynq_platform_data zynqmp_gpio_def = { static const struct zynq_platform_data zynq_gpio_def = { .label = "zynq_gpio", - .quirks = ZYNQ_GPIO_QUIRK_IS_ZYNQ, + .quirks = ZYNQ_GPIO_QUIRK_IS_ZYNQ | GPIO_QUIRK_DATA_RO_BUG, .ngpio = ZYNQ_GPIO_NR_GPIOS, .max_bank = ZYNQ_GPIO_MAX_BANK, .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(), diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c9b42dd12dfa..4d2113530735 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -61,7 +61,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) #ifdef CONFIG_PINCTRL /** * acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO - * @chip: GPIO chip + * @gdev: GPIO device * @pin: ACPI GPIO pin number from GpioIo/GpioInt resource * * Function takes ACPI GpioIo/GpioInt pin number as a parameter and @@ -763,7 +763,7 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, * The function is idempotent, though each time it runs it will configure GPIO * pin direction according to the flags in GpioInt resource. * - * Return: Linux IRQ number (>%0) on success, negative errno on failure. + * Return: Linux IRQ number (> %0) on success, negative errno on failure. */ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) { diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 54ce8dc58ad0..bfcd20699ec8 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -78,8 +78,8 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, &gpiospec); if (ret) { - pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n", - __func__, propname, np->full_name, index); + pr_debug("%s: can't parse '%s' property of node '%pOF[%d]'\n", + __func__, propname, np, index); return ERR_PTR(ret); } @@ -93,8 +93,8 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, if (IS_ERR(desc)) goto out; - pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n", - __func__, propname, np->full_name, index, + pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n", + __func__, propname, np, index, PTR_ERR_OR_ZERO(desc)); out: @@ -273,14 +273,13 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) } /** - * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags + * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags * @gc: pointer to the gpio_chip structure - * @np: device node of the GPIO chip - * @gpio_spec: gpio specifier as found in the device tree + * @gpiospec: GPIO specifier as found in the device tree * @flags: a flags pointer to fill in * * This is simple translation function, suitable for the most 1:1 mapped - * gpio chips. This function performs only one sanity check: whether gpio + * GPIO chips. This function performs only one sanity check: whether GPIO * is less than ngpios (that is specified in the gpio_chip). */ int of_gpio_simple_xlate(struct gpio_chip *gc, @@ -337,7 +336,7 @@ int of_mm_gpiochip_add_data(struct device_node *np, int ret = -ENOMEM; struct gpio_chip *gc = &mm_gc->gc; - gc->label = kstrdup(np->full_name, GFP_KERNEL); + gc->label = kasprintf(GFP_KERNEL, "%pOF", np); if (!gc->label) goto err0; @@ -362,8 +361,7 @@ err2: err1: kfree(gc->label); err0: - pr_err("%s: GPIO chip registration failed with status %d\n", - np->full_name, ret); + pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret); return ret; } EXPORT_SYMBOL(of_mm_gpiochip_add_data); @@ -418,8 +416,8 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) group_names_propname, index, &name); if (strlen(name)) { - pr_err("%s: Group name of numeric GPIO ranges must be the empty string.\n", - np->full_name); + pr_err("%pOF: Group name of numeric GPIO ranges must be the empty string.\n", + np); break; } } @@ -434,14 +432,14 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) } else { /* npins == 0: special range */ if (pinspec.args[1]) { - pr_err("%s: Illegal gpio-range format.\n", - np->full_name); + pr_err("%pOF: Illegal gpio-range format.\n", + np); break; } if (!group_names) { - pr_err("%s: GPIO group range requested but no %s property.\n", - np->full_name, group_names_propname); + pr_err("%pOF: GPIO group range requested but no %s property.\n", + np, group_names_propname); break; } @@ -452,8 +450,8 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) break; if (!strlen(name)) { - pr_err("%s: Group name of GPIO group range cannot be the empty string.\n", - np->full_name); + pr_err("%pOF: Group name of GPIO group range cannot be the empty string.\n", + np); break; } diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index fc80add5fedb..3f454eaf2101 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -540,8 +540,8 @@ static struct class gpio_class = { /** * gpiod_export - export a GPIO through sysfs - * @gpio: gpio to make available, already requested - * @direction_may_change: true if userspace may change gpio direction + * @desc: GPIO to make available, already requested + * @direction_may_change: true if userspace may change GPIO direction * Context: arch_initcall or later * * When drivers want to make a GPIO accessible to userspace after they @@ -649,7 +649,7 @@ static int match_export(struct device *dev, const void *desc) * gpiod_export_link - create a sysfs link to an exported GPIO node * @dev: device under which to create symlink * @name: name of the symlink - * @gpio: gpio to create symlink to, already exported + * @desc: GPIO to create symlink to, already exported * * Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN * node. Caller is responsible for unlinking. @@ -680,7 +680,7 @@ EXPORT_SYMBOL_GPL(gpiod_export_link); /** * gpiod_unexport - reverse effect of gpiod_export() - * @gpio: gpio to make unavailable + * @desc: GPIO to make unavailable * * This is implicit on gpiod_free(). */ diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index cd003b74512f..eb80dac4e26a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -84,7 +84,12 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) } /** - * Convert a GPIO number to its descriptor + * gpio_to_desc - Convert a GPIO number to its descriptor + * @gpio: global GPIO number + * + * Returns: + * The GPIO descriptor associated with the given GPIO, or %NULL if no GPIO + * with the given number exists in the system. */ struct gpio_desc *gpio_to_desc(unsigned gpio) { @@ -111,7 +116,14 @@ struct gpio_desc *gpio_to_desc(unsigned gpio) EXPORT_SYMBOL_GPL(gpio_to_desc); /** - * Get the GPIO descriptor corresponding to the given hw number for this chip. + * gpiochip_get_desc - get the GPIO descriptor corresponding to the given + * hardware number for this chip + * @chip: GPIO chip + * @hwnum: hardware number of the GPIO for this chip + * + * Returns: + * A pointer to the GPIO descriptor or %ERR_PTR(-EINVAL) if no GPIO exists + * in the given chip for the specified hardware number. */ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum) @@ -125,9 +137,14 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, } /** - * Convert a GPIO descriptor to the integer namespace. + * desc_to_gpio - convert a GPIO descriptor to the integer namespace + * @desc: GPIO descriptor + * * This should disappear in the future but is needed since we still - * use GPIO numbers for error messages and sysfs nodes + * use GPIO numbers for error messages and sysfs nodes. + * + * Returns: + * The global GPIO number for the GPIO specified by its descriptor. */ int desc_to_gpio(const struct gpio_desc *desc) { @@ -254,7 +271,7 @@ static int gpiodev_add_to_list(struct gpio_device *gdev) return -EBUSY; } -/** +/* * Convert a GPIO name to its descriptor */ static struct gpio_desc *gpio_name_to_desc(const char * const name) @@ -878,7 +895,7 @@ out_free_le: return ret; } -/** +/* * gpio_ioctl() - ioctl handler for the GPIO chardev */ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) @@ -1077,11 +1094,9 @@ static void gpiochip_setup_devs(void) /** * gpiochip_add_data() - register a gpio_chip * @chip: the chip to register, with chip->base initialized - * Context: potentially before irqs will work + * @data: driver-private data associated with this chip * - * Returns a negative errno if the chip can't be registered, such as - * because the chip->base is invalid or already associated with a - * different chip. Otherwise it returns zero as a success code. + * Context: potentially before irqs will work * * When gpiochip_add_data() is called very early during boot, so that GPIOs * can be freely used, the chip->parent device must be registered before @@ -1093,6 +1108,11 @@ static void gpiochip_setup_devs(void) * * If chip->base is negative, this requests dynamic assignment of * a range of valid GPIOs. + * + * Returns: + * A negative errno if the chip can't be registered, such as because the + * chip->base is invalid or already associated with a different chip. + * Otherwise it returns zero as a success code. */ int gpiochip_add_data(struct gpio_chip *chip, void *data) { @@ -1287,6 +1307,10 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data); /** * gpiochip_get_data() - get per-subdriver data for the chip + * @chip: GPIO chip + * + * Returns: + * The per-subdriver data for the chip. */ void *gpiochip_get_data(struct gpio_chip *chip) { @@ -1370,13 +1394,16 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data) * devm_gpiochip_add_data() - Resource manager piochip_add_data() * @dev: the device pointer on which irq_chip belongs to. * @chip: the chip to register, with chip->base initialized - * Context: potentially before irqs will work + * @data: driver-private data associated with this chip * - * Returns a negative errno if the chip can't be registered, such as - * because the chip->base is invalid or already associated with a - * different chip. Otherwise it returns zero as a success code. + * Context: potentially before irqs will work * * The gpio chip automatically be released when the device is unbound. + * + * Returns: + * A negative errno if the chip can't be registered, such as because the + * chip->base is invalid or already associated with a different chip. + * Otherwise it returns zero as a success code. */ int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip, void *data) @@ -1422,7 +1449,7 @@ EXPORT_SYMBOL_GPL(devm_gpiochip_remove); /** * gpiochip_find() - iterator for locating a specific gpio_chip * @data: data to pass to match function - * @callback: Callback function to check gpio_chip + * @match: Callback function to check gpio_chip * * Similar to bus_find_device. It returns a reference to a gpio_chip as * determined by a user supplied @match callback. The callback should return @@ -1604,6 +1631,9 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, { struct gpio_chip *chip = d->host_data; + if (!gpiochip_irqchip_irq_valid(chip, hwirq)) + return -ENXIO; + irq_set_chip_data(irq, chip); /* * This lock class tells lockdep that GPIO irqs are in a different @@ -1670,7 +1700,9 @@ static void gpiochip_irq_relres(struct irq_data *d) static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) { - return irq_find_mapping(chip->irqdomain, offset); + if (!gpiochip_irqchip_irq_valid(chip, offset)) + return -ENXIO; + return irq_create_mapping(chip->irqdomain, offset); } /** @@ -1746,9 +1778,6 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, struct lock_class_key *lock_key) { struct device_node *of_node; - bool irq_base_set = false; - unsigned int offset; - unsigned irq_base = 0; if (!gpiochip || !irqchip) return -EINVAL; @@ -1774,7 +1803,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, * conflicting triggers. Tell the user, and reset to NONE. */ if (WARN(of_node && type != IRQ_TYPE_NONE, - "%s: Ignoring %d default trigger\n", of_node->full_name, type)) + "%pOF: Ignoring %d default trigger\n", of_node, type)) type = IRQ_TYPE_NONE; if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) { acpi_handle_warn(ACPI_HANDLE(gpiochip->parent), @@ -1805,25 +1834,6 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, irqchip->irq_release_resources = gpiochip_irq_relres; } - /* - * Prepare the mapping since the irqchip shall be orthogonal to - * any gpiochip calls. If the first_irq was zero, this is - * necessary to allocate descriptors for all IRQs. - */ - for (offset = 0; offset < gpiochip->ngpio; offset++) { - if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) - continue; - irq_base = irq_create_mapping(gpiochip->irqdomain, offset); - if (!irq_base_set) { - /* - * Store the base into the gpiochip to be used when - * unmapping the irqs. - */ - gpiochip->irq_base = irq_base; - irq_base_set = true; - } - } - acpi_gpiochip_request_interrupts(gpiochip); return 0; @@ -1930,11 +1940,14 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range); /** * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping * @chip: the gpiochip to add the range for - * @pinctrl_name: the dev_name() of the pin controller to map to + * @pinctl_name: the dev_name() of the pin controller to map to * @gpio_offset: the start offset in the current gpio_chip number space * @pin_offset: the start offset in the pin controller number space * @npins: the number of pins from the offset of each pin space (GPIO and * pin controller) to accumulate in this range + * + * Returns: + * 0 on success, or a negative error-code on failure. */ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, unsigned int gpio_offset, unsigned int pin_offset, @@ -2179,7 +2192,8 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); /** * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor - * @desc: GPIO descriptor to request + * @chip: GPIO chip + * @hwnum: hardware number of the GPIO for which to request the descriptor * @label: label for the GPIO * * Function allows GPIO chip drivers to request and use their own GPIO @@ -2187,6 +2201,10 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * function will not increase reference count of the GPIO chip module. This * allows the GPIO chip module to be unloaded as needed (we assume that the * GPIO chip driver handles freeing the GPIOs it has requested). + * + * Returns: + * A pointer to the GPIO descriptor, or an ERR_PTR()-encoded negative error + * code on failure. */ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, const char *label) @@ -2368,12 +2386,13 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) EXPORT_SYMBOL_GPL(gpiod_direction_output); /** - * gpiod_set_debounce - sets @debounce time for a @gpio - * @gpio: the gpio to set debounce time - * @debounce: debounce time is microseconds + * gpiod_set_debounce - sets @debounce time for a GPIO + * @desc: descriptor of the GPIO for which to set debounce time + * @debounce: debounce time in microseconds * - * returns -ENOTSUPP if the controller does not support setting - * debounce. + * Returns: + * 0 on success, %-ENOTSUPP if the controller doesn't support setting the + * debounce time. */ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { @@ -2981,6 +3000,23 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size, EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep); /** + * gpiod_add_lookup_tables() - register GPIO device consumers + * @tables: list of tables of consumers to register + * @n: number of tables in the list + */ +void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) +{ + unsigned int i; + + mutex_lock(&gpio_lookup_lock); + + for (i = 0; i < n; i++) + list_add_tail(&tables[i]->list, &gpio_lookup_list); + + mutex_unlock(&gpio_lookup_lock); +} + +/** * gpiod_set_array_value_cansleep() - assign values to an array of GPIOs * @array_size: number of elements in the descriptor / value arrays * @desc_array: array of GPIO descriptors whose values will be assigned @@ -3322,6 +3358,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * @propname: name of the firmware property representing the GPIO * @index: index of the GPIO to obtain in the consumer * @dflags: GPIO initialization flags + * @label: label to attach to the requested GPIO * * This function can be used for drivers that get their configuration * from firmware. @@ -3330,6 +3367,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * underlying firmware interface and then makes sure that the GPIO * descriptor is requested before it is returned to the caller. * + * Returns: * On successful request the GPIO pin is configured in accordance with * provided @dflags. * diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index a8be286eff86..d003ccb12781 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -219,7 +219,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, /* * Return the GPIO number of the passed descriptor relative to its chip */ -static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc) +static inline int gpio_chip_hwgpio(const struct gpio_desc *desc) { return desc - &desc->gdev->descs[0]; } |