aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2018-12-12 15:48:50 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2018-12-12 15:48:50 +1100
commit8912206d891f1da7f072ba3c39e3d35b3b20ae5f (patch)
tree10899bd811c2e3ffca3951c6d4727bdeaea02080
parentbe80ab1969e499e2ace497565eb38a69bc0fb50a (diff)
parent74c79c5c3287a52be1efa217ef07fb1fa31d07ef (diff)
downloadlinux-2.6-8912206d891f1da7f072ba3c39e3d35b3b20ae5f.tar.gz
Merge remote-tracking branch 'gpio/for-next'
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-vf610.txt6
-rw-r--r--Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt38
-rw-r--r--Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt4
-rw-r--r--Documentation/driver-model/devres.txt1
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/gpio/Kconfig1
-rw-r--r--drivers/gpio/TODO109
-rw-r--r--drivers/gpio/gpio-104-dio-48e.c2
-rw-r--r--drivers/gpio/gpio-104-idi-48.c2
-rw-r--r--drivers/gpio/gpio-dwapb.c6
-rw-r--r--drivers/gpio/gpio-gpio-mm.c2
-rw-r--r--drivers/gpio/gpio-grgpio.c1
-rw-r--r--drivers/gpio/gpio-ks8695.c15
-rw-r--r--drivers/gpio/gpio-lpc18xx.c286
-rw-r--r--drivers/gpio/gpio-lynxpoint.c3
-rw-r--r--drivers/gpio/gpio-mt7621.c10
-rw-r--r--drivers/gpio/gpio-mxc.c41
-rw-r--r--drivers/gpio/gpio-omap.c12
-rw-r--r--drivers/gpio/gpio-pci-idio-16.c2
-rw-r--r--drivers/gpio/gpio-pcie-idio-24.c2
-rw-r--r--drivers/gpio/gpio-pl061.c21
-rw-r--r--drivers/gpio/gpio-rcar.c34
-rw-r--r--drivers/gpio/gpio-sch311x.c2
-rw-r--r--drivers/gpio/gpio-tegra.c6
-rw-r--r--drivers/gpio/gpio-uniphier.c17
-rw-r--r--drivers/gpio/gpio-vf610.c44
-rw-r--r--drivers/gpio/gpio-ws16c48.c2
-rw-r--r--drivers/gpio/gpio-zynq.c29
-rw-r--r--drivers/gpio/gpiolib-acpi.c149
-rw-r--r--drivers/gpio/gpiolib-of.c41
-rw-r--r--drivers/gpio/gpiolib.c55
-rw-r--r--include/dt-bindings/gpio/tegra186-gpio.h41
-rw-r--r--include/linux/gpio/consumer.h6
-rw-r--r--include/linux/gpio/driver.h6
34 files changed, 753 insertions, 244 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-vf610.txt b/Documentation/devicetree/bindings/gpio/gpio-vf610.txt
index 0ccbae44019cca..ae254aadee354c 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-vf610.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-vf610.txt
@@ -24,6 +24,12 @@ Required properties for GPIO node:
4 = active high level-sensitive.
8 = active low level-sensitive.
+Optional properties:
+-clocks: Must contain an entry for each entry in clock-names.
+ See common clock-bindings.txt for details.
+-clock-names: A list of clock names. For imx7ulp, it must contain
+ "gpio", "port".
+
Note: Each GPIO port should have an alias correctly numbered in "aliases"
node.
diff --git a/Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt b/Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt
index eb7cdd69e10bf0..627efc78ecf2d8 100644
--- a/Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt
@@ -3,12 +3,24 @@ NXP LPC18xx/43xx GPIO controller Device Tree Bindings
Required properties:
- compatible : Should be "nxp,lpc1850-gpio"
-- reg : Address and length of the register set for the device
-- clocks : Clock specifier (see clock bindings for details)
-- gpio-controller : Marks the device node as a GPIO controller.
-- #gpio-cells : Should be two
- - First cell is the GPIO line number
- - Second cell is used to specify polarity
+- reg : List of addresses and lengths of the GPIO controller
+ register sets
+- reg-names : Should be "gpio", "gpio-pin-ic", "gpio-group0-ic" and
+ "gpio-gpoup1-ic"
+- clocks : Phandle and clock specifier pair for GPIO controller
+- resets : Phandle and reset specifier pair for GPIO controller
+- gpio-controller : Marks the device node as a GPIO controller
+- #gpio-cells : Should be two:
+ - The first cell is the GPIO line number
+ - The second cell is used to specify polarity
+- interrupt-controller : Marks the device node as an interrupt controller
+- #interrupt-cells : Should be two:
+ - The first cell is an interrupt number within
+ 0..9 range, for GPIO pin interrupts it is equal
+ to 'nxp,gpio-pin-interrupt' property value of
+ GPIO pin configuration, 8 is for GPIO GROUP0
+ interrupt, 9 is for GPIO GROUP1 interrupt
+ - The second cell is used to specify interrupt type
Optional properties:
- gpio-ranges : Mapping between GPIO and pinctrl
@@ -19,21 +31,29 @@ Example:
gpio: gpio@400f4000 {
compatible = "nxp,lpc1850-gpio";
- reg = <0x400f4000 0x4000>;
+ reg = <0x400f4000 0x4000>, <0x40087000 0x1000>,
+ <0x40088000 0x1000>, <0x40089000 0x1000>;
+ reg-names = "gpio", "gpio-pin-ic",
+ "gpio-group0-ic", "gpio-gpoup1-ic";
clocks = <&ccu1 CLK_CPU_GPIO>;
+ resets = <&rgu 28>;
gpio-controller;
#gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
gpio-ranges = <&pinctrl LPC_GPIO(0,0) LPC_PIN(0,0) 2>,
...
<&pinctrl LPC_GPIO(7,19) LPC_PIN(f,5) 7>;
};
gpio_joystick {
- compatible = "gpio-keys-polled";
+ compatible = "gpio-keys";
...
- button@0 {
+ button0 {
...
+ interrupt-parent = <&gpio>;
+ interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
gpios = <&gpio LPC_GPIO(4,8) GPIO_ACTIVE_LOW>;
};
};
diff --git a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
index 7276b50c35065b..839dd32ffe11e0 100644
--- a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
@@ -43,7 +43,7 @@ gpio: gpio@20000 {
#address-cells = <1>;
#size-cells = <0>;
- porta: gpio-controller@0 {
+ porta: gpio@0 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
@@ -55,7 +55,7 @@ gpio: gpio@20000 {
interrupts = <0>;
};
- portb: gpio-controller@1 {
+ portb: gpio@1 {
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index ee06ce23152f25..841c99529d2717 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -263,7 +263,6 @@ GPIO
devm_gpiod_put()
devm_gpiod_unhinge()
devm_gpiochip_add_data()
- devm_gpiochip_remove()
devm_gpio_request()
devm_gpio_request_one()
devm_gpio_free()
diff --git a/MAINTAINERS b/MAINTAINERS
index a75257a5ac4b0b..332ba79f17a925 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6417,7 +6417,6 @@ F: drivers/media/rc/gpio-ir-tx.c
GPIO MOCKUP DRIVER
M: Bamvor Jian Zhang <bamv2005@gmail.com>
-R: Bartosz Golaszewski <brgl@bgdev.pl>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-mockup.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 587e5f005b6122..329d2f9523b21c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -287,6 +287,7 @@ config GPIO_LPC18XX
tristate "NXP LPC18XX/43XX GPIO support"
default y if ARCH_LPC18XX
depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST)
+ select IRQ_DOMAIN_HIERARCHY
help
Select this option to enable GPIO driver for
NXP LPC18XX/43XX devices.
diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO
new file mode 100644
index 00000000000000..19d27c90491601
--- /dev/null
+++ b/drivers/gpio/TODO
@@ -0,0 +1,109 @@
+This is a place for planning the ongoing long-term work in the GPIO
+subsystem.
+
+
+GPIO descriptors
+
+Starting with commit 79a9becda894 the GPIO subsystem embarked on a journey
+to move away from the global GPIO numberspace and toward a decriptor-based
+approach. This means that GPIO consumers, drivers and machine descriptions
+ideally have no use or idea of the global GPIO numberspace that has/was
+used in the inception of the GPIO subsystem.
+
+Work items:
+
+- Convert all GPIO device drivers to only #include <linux/gpio/driver.h>
+
+- Convert all consumer drivers to only #include <linux/gpio/consumer.h>
+
+- Convert all machine descriptors in "boardfiles" to only
+ #include <linux/gpio/machine.h>, the other option being to convert it
+ to a machine description such as device tree, ACPI or fwnode that
+ implicitly does not use global GPIO numbers.
+
+- When this work is complete (will require some of the items in the
+ following ongoing work as well) we can delete the old global
+ numberspace accessors from <linux/gpio.h> and eventually delete
+ <linux/gpio.h> altogether.
+
+
+Get rid of <linux/of_gpio.h>
+
+This header and helpers appeared at one point when there was no proper
+driver infrastructure for doing simpler MMIO GPIO devices and there was
+no core support for parsing device tree GPIOs from the core library with
+the [devm_]gpiod_get() calls we have today that will implicitly go into
+the device tree back-end.
+
+Work items:
+
+- Get rid of struct of_mm_gpio_chip altogether: use the generic MMIO
+ GPIO for all current users (see below). Delete struct of_mm_gpio_chip,
+ to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_add()
+ of_mm_gpiochip_remove() from the kernel.
+
+- Change all consumer drivers that #include <linux/of_gpio.h> to
+ #include <linux/gpio/consumer.h> and stop doing custom parsing of the
+ GPIO lines from the device tree. This can be tricky and often ivolves
+ changing boardfiles, etc.
+
+- Pull semantics for legacy device tree (OF) GPIO lookups into
+ gpiolib-of.c: in some cases subsystems are doing custom flags and
+ lookups for polarity inversion, open drain and what not. As we now
+ handle this with generic OF bindings, pull all legacy handling into
+ gpiolib so the library API becomes narrow and deep and handle all
+ legacy bindings internally. (See e.g. commits 6953c57ab172,
+ 6a537d48461d etc)
+
+- Delete <linux/of_gpio.h> when all the above is complete and everything
+ uses <linux/gpio/consumer.h> or <linux/gpio/driver.h> instead.
+
+
+Collect drivers
+
+Collect GPIO drivers from arch/* and other places that should be placed
+in drivers/gpio/gpio-*. Augment platforms to create platform devices or
+similar and probe a proper driver in the gpiolib subsystem.
+
+In some cases it makes sense to create a GPIO chip from the local driver
+for a few GPIOs. Those should stay where they are.
+
+
+Generic MMIO GPIO
+
+The GPIO drivers can utilize the generic MMIO helper library in many
+cases, and the helper library should be as helpful as possible for MMIO
+drivers. (drivers/gpio/gpio-mmio.c)
+
+Work items:
+
+- Look over and identify any remaining easily converted drivers and
+ dry-code conversions to MMIO GPIO for maintainers to test
+
+- Expand the MMIO GPIO or write a new library for port-mapped I/O
+ helpers (x86 inb()/outb()) and convert port-mapped I/O drivers to use
+ this with dry-coding and sending to maintainers to test
+
+
+GPIOLIB irqchip
+
+The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
+try to cover any generic kind of irqchip cascaded from a GPIO.
+
+- Look over and identify any remaining easily converted drivers and
+ dry-code conversions to gpiolib irqchip for maintainers to test
+
+- Support generic hierarchical GPIO interrupts: these are for the
+ non-cascading case where there is one IRQ per GPIO line, there is
+ currently no common infrastructure for this.
+
+
+Increase integration with pin control
+
+There are already ways to use pin control as back-end for GPIO and
+it may make sense to bring these subsystems closer. One reason for
+creating pin control as its own subsystem was that we could avoid any
+use of the global GPIO numbers. Once the above is complete, it may
+make sense to simply join the subsystems into one and make pin
+multiplexing, pin configuration, GPIO, etc selectable options in one
+and the same pin control and GPIO subsystem.
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 9c4e07fcb74b5f..92c8f944bf6412 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -222,7 +222,7 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
port_state = inb(dio48egpio->base + ports[i]);
/* store acquired bits at respective bits array offset */
- bits[word_index] |= port_state << word_offset;
+ bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index 2c9738adb3a684..88dc6f2449f63b 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -128,7 +128,7 @@ static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
port_state = inb(idi48gpio->base + ports[i]);
/* store acquired bits at respective bits array offset */
- bits[word_index] |= port_state << word_offset;
+ bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 044888fd96a1f6..84ae04402f7051 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -748,8 +748,7 @@ static int dwapb_gpio_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int dwapb_gpio_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
+ struct dwapb_gpio *gpio = dev_get_drvdata(dev);
struct gpio_chip *gc = &gpio->ports[0].gc;
unsigned long flags;
int i;
@@ -793,8 +792,7 @@ static int dwapb_gpio_suspend(struct device *dev)
static int dwapb_gpio_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
+ struct dwapb_gpio *gpio = dev_get_drvdata(dev);
struct gpio_chip *gc = &gpio->ports[0].gc;
unsigned long flags;
int i;
diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c
index b56ff2efbf3690..8c150fd68d9d14 100644
--- a/drivers/gpio/gpio-gpio-mm.c
+++ b/drivers/gpio/gpio-gpio-mm.c
@@ -211,7 +211,7 @@ static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
port_state = inb(gpiommgpio->base + ports[i]);
/* store acquired bits at respective bits array offset */
- bits[word_index] |= port_state << word_offset;
+ bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 60a1556c570a45..45b8d6a02b876c 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -30,7 +30,6 @@
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/err.h>
-#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c
index 55d562e1278ec5..d6d6140ffc4012 100644
--- a/drivers/gpio/gpio-ks8695.c
+++ b/drivers/gpio/gpio-ks8695.c
@@ -282,22 +282,13 @@ static int ks8695_gpio_show(struct seq_file *s, void *unused)
return 0;
}
-static int ks8695_gpio_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ks8695_gpio_show, NULL);
-}
-
-static const struct file_operations ks8695_gpio_operations = {
- .open = ks8695_gpio_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(ks8695_gpio);
static int __init ks8695_gpio_debugfs_init(void)
{
/* /sys/kernel/debug/ks8695_gpio */
- (void) debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL, &ks8695_gpio_operations);
+ debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL,
+ &ks8695_gpio_fops);
return 0;
}
postcore_initcall(ks8695_gpio_debugfs_init);
diff --git a/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c
index f12e02e1016d85..d441dbaed7a3d2 100644
--- a/drivers/gpio/gpio-lpc18xx.c
+++ b/drivers/gpio/gpio-lpc18xx.c
@@ -1,20 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* GPIO driver for NXP LPC18xx/43xx.
*
+ * Copyright (C) 2018 Vladimir Zapolskiy <vz@mleia.com>
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/clk.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
+#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -24,13 +25,246 @@
#define LPC18XX_MAX_PORTS 8
#define LPC18XX_PINS_PER_PORT 32
+/* LPC18xx GPIO pin interrupt controller register offsets */
+#define LPC18XX_GPIO_PIN_IC_ISEL 0x00
+#define LPC18XX_GPIO_PIN_IC_IENR 0x04
+#define LPC18XX_GPIO_PIN_IC_SIENR 0x08
+#define LPC18XX_GPIO_PIN_IC_CIENR 0x0c
+#define LPC18XX_GPIO_PIN_IC_IENF 0x10
+#define LPC18XX_GPIO_PIN_IC_SIENF 0x14
+#define LPC18XX_GPIO_PIN_IC_CIENF 0x18
+#define LPC18XX_GPIO_PIN_IC_RISE 0x1c
+#define LPC18XX_GPIO_PIN_IC_FALL 0x20
+#define LPC18XX_GPIO_PIN_IC_IST 0x24
+
+#define NR_LPC18XX_GPIO_PIN_IC_IRQS 8
+
+struct lpc18xx_gpio_pin_ic {
+ void __iomem *base;
+ struct irq_domain *domain;
+ struct raw_spinlock lock;
+};
+
struct lpc18xx_gpio_chip {
struct gpio_chip gpio;
void __iomem *base;
struct clk *clk;
+ struct lpc18xx_gpio_pin_ic *pin_ic;
spinlock_t lock;
};
+static inline void lpc18xx_gpio_pin_ic_isel(struct lpc18xx_gpio_pin_ic *ic,
+ u32 pin, bool set)
+{
+ u32 val = readl_relaxed(ic->base + LPC18XX_GPIO_PIN_IC_ISEL);
+
+ if (set)
+ val &= ~BIT(pin);
+ else
+ val |= BIT(pin);
+
+ writel_relaxed(val, ic->base + LPC18XX_GPIO_PIN_IC_ISEL);
+}
+
+static inline void lpc18xx_gpio_pin_ic_set(struct lpc18xx_gpio_pin_ic *ic,
+ u32 pin, u32 reg)
+{
+ writel_relaxed(BIT(pin), ic->base + reg);
+}
+
+static void lpc18xx_gpio_pin_ic_mask(struct irq_data *d)
+{
+ struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
+ u32 type = irqd_get_trigger_type(d);
+
+ raw_spin_lock(&ic->lock);
+
+ if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING)
+ lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
+ LPC18XX_GPIO_PIN_IC_CIENR);
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
+ LPC18XX_GPIO_PIN_IC_CIENF);
+
+ raw_spin_unlock(&ic->lock);
+
+ irq_chip_mask_parent(d);
+}
+
+static void lpc18xx_gpio_pin_ic_unmask(struct irq_data *d)
+{
+ struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
+ u32 type = irqd_get_trigger_type(d);
+
+ raw_spin_lock(&ic->lock);
+
+ if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING)
+ lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
+ LPC18XX_GPIO_PIN_IC_SIENR);
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
+ LPC18XX_GPIO_PIN_IC_SIENF);
+
+ raw_spin_unlock(&ic->lock);
+
+ irq_chip_unmask_parent(d);
+}
+
+static void lpc18xx_gpio_pin_ic_eoi(struct irq_data *d)
+{
+ struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
+ u32 type = irqd_get_trigger_type(d);
+
+ raw_spin_lock(&ic->lock);
+
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
+ LPC18XX_GPIO_PIN_IC_IST);
+
+ raw_spin_unlock(&ic->lock);
+
+ irq_chip_eoi_parent(d);
+}
+
+static int lpc18xx_gpio_pin_ic_set_type(struct irq_data *d, unsigned int type)
+{
+ struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
+
+ raw_spin_lock(&ic->lock);
+
+ if (type & IRQ_TYPE_LEVEL_HIGH) {
+ lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true);
+ lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
+ LPC18XX_GPIO_PIN_IC_SIENF);
+ } else if (type & IRQ_TYPE_LEVEL_LOW) {
+ lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true);
+ lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
+ LPC18XX_GPIO_PIN_IC_CIENF);
+ } else {
+ lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, false);
+ }
+
+ raw_spin_unlock(&ic->lock);
+
+ return 0;
+}
+
+static struct irq_chip lpc18xx_gpio_pin_ic = {
+ .name = "LPC18xx GPIO pin",
+ .irq_mask = lpc18xx_gpio_pin_ic_mask,
+ .irq_unmask = lpc18xx_gpio_pin_ic_unmask,
+ .irq_eoi = lpc18xx_gpio_pin_ic_eoi,
+ .irq_set_type = lpc18xx_gpio_pin_ic_set_type,
+ .flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static int lpc18xx_gpio_pin_ic_domain_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs, void *data)
+{
+ struct irq_fwspec parent_fwspec, *fwspec = data;
+ struct lpc18xx_gpio_pin_ic *ic = domain->host_data;
+ irq_hw_number_t hwirq;
+ int ret;
+
+ if (nr_irqs != 1)
+ return -EINVAL;
+
+ hwirq = fwspec->param[0];
+ if (hwirq >= NR_LPC18XX_GPIO_PIN_IC_IRQS)
+ return -EINVAL;
+
+ /*
+ * All LPC18xx/LPC43xx GPIO pin hardware interrupts are translated
+ * into edge interrupts 32...39 on parent Cortex-M3/M4 NVIC
+ */
+ parent_fwspec.fwnode = domain->parent->fwnode;
+ parent_fwspec.param_count = 1;
+ parent_fwspec.param[0] = hwirq + 32;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
+ if (ret < 0) {
+ pr_err("failed to allocate parent irq %u: %d\n",
+ parent_fwspec.param[0], ret);
+ return ret;
+ }
+
+ return irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+ &lpc18xx_gpio_pin_ic, ic);
+}
+
+static const struct irq_domain_ops lpc18xx_gpio_pin_ic_domain_ops = {
+ .alloc = lpc18xx_gpio_pin_ic_domain_alloc,
+ .xlate = irq_domain_xlate_twocell,
+ .free = irq_domain_free_irqs_common,
+};
+
+static int lpc18xx_gpio_pin_ic_probe(struct lpc18xx_gpio_chip *gc)
+{
+ struct device *dev = gc->gpio.parent;
+ struct irq_domain *parent_domain;
+ struct device_node *parent_node;
+ struct lpc18xx_gpio_pin_ic *ic;
+ struct resource res;
+ int ret, index;
+
+ parent_node = of_irq_find_parent(dev->of_node);
+ if (!parent_node)
+ return -ENXIO;
+
+ parent_domain = irq_find_host(parent_node);
+ of_node_put(parent_node);
+ if (!parent_domain)
+ return -ENXIO;
+
+ ic = devm_kzalloc(dev, sizeof(*ic), GFP_KERNEL);
+ if (!ic)
+ return -ENOMEM;
+
+ index = of_property_match_string(dev->of_node, "reg-names",
+ "gpio-pin-ic");
+ if (index < 0) {
+ ret = -ENODEV;
+ goto free_ic;
+ }
+
+ ret = of_address_to_resource(dev->of_node, index, &res);
+ if (ret < 0)
+ goto free_ic;
+
+ ic->base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(ic->base)) {
+ ret = PTR_ERR(ic->base);
+ goto free_ic;
+ }
+
+ raw_spin_lock_init(&ic->lock);
+
+ ic->domain = irq_domain_add_hierarchy(parent_domain, 0,
+ NR_LPC18XX_GPIO_PIN_IC_IRQS,
+ dev->of_node,
+ &lpc18xx_gpio_pin_ic_domain_ops,
+ ic);
+ if (!ic->domain) {
+ pr_err("unable to add irq domain\n");
+ ret = -ENODEV;
+ goto free_iomap;
+ }
+
+ gc->pin_ic = ic;
+
+ return 0;
+
+free_iomap:
+ devm_iounmap(dev, ic->base);
+free_ic:
+ devm_kfree(dev, ic);
+
+ return ret;
+}
+
static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
@@ -92,45 +326,62 @@ static const struct gpio_chip lpc18xx_chip = {
static int lpc18xx_gpio_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct lpc18xx_gpio_chip *gc;
- struct resource *res;
- int ret;
+ int index, ret;
- gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
gc->gpio = lpc18xx_chip;
platform_set_drvdata(pdev, gc);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- gc->base = devm_ioremap_resource(&pdev->dev, res);
+ index = of_property_match_string(dev->of_node, "reg-names", "gpio");
+ if (index < 0) {
+ /* To support backward compatibility take the first resource */
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gc->base = devm_ioremap_resource(dev, res);
+ } else {
+ struct resource res;
+
+ ret = of_address_to_resource(dev->of_node, index, &res);
+ if (ret < 0)
+ return ret;
+
+ gc->base = devm_ioremap_resource(dev, &res);
+ }
if (IS_ERR(gc->base))
return PTR_ERR(gc->base);
- gc->clk = devm_clk_get(&pdev->dev, NULL);
+ gc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(gc->clk)) {
- dev_err(&pdev->dev, "input clock not found\n");
+ dev_err(dev, "input clock not found\n");
return PTR_ERR(gc->clk);
}
ret = clk_prepare_enable(gc->clk);
if (ret) {
- dev_err(&pdev->dev, "unable to enable clock\n");
+ dev_err(dev, "unable to enable clock\n");
return ret;
}
spin_lock_init(&gc->lock);
- gc->gpio.parent = &pdev->dev;
+ gc->gpio.parent = dev;
- ret = gpiochip_add_data(&gc->gpio, gc);
+ ret = devm_gpiochip_add_data(dev, &gc->gpio, gc);
if (ret) {
- dev_err(&pdev->dev, "failed to add gpio chip\n");
+ dev_err(dev, "failed to add gpio chip\n");
clk_disable_unprepare(gc->clk);
return ret;
}
+ /* On error GPIO pin interrupt controller just won't be registered */
+ lpc18xx_gpio_pin_ic_probe(gc);
+
return 0;
}
@@ -138,7 +389,9 @@ static int lpc18xx_gpio_remove(struct platform_device *pdev)
{
struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
- gpiochip_remove(&gc->gpio);
+ if (gc->pin_ic)
+ irq_domain_remove(gc->pin_ic->domain);
+
clk_disable_unprepare(gc->clk);
return 0;
@@ -161,5 +414,6 @@ static struct platform_driver lpc18xx_gpio_driver = {
module_platform_driver(lpc18xx_gpio_driver);
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_AUTHOR("Vladimir Zapolskiy <vz@mleia.com>");
MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index b5b5e500e72cfa..ca12d9f9691493 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -408,8 +408,7 @@ static int lp_gpio_runtime_resume(struct device *dev)
static int lp_gpio_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct lp_gpio *lg = platform_get_drvdata(pdev);
+ struct lp_gpio *lg = dev_get_drvdata(dev);
unsigned long reg;
int i;
diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c
index d72af6f6cdbda0..00e954f22bc920 100644
--- a/drivers/gpio/gpio-mt7621.c
+++ b/drivers/gpio/gpio-mt7621.c
@@ -244,6 +244,8 @@ mediatek_gpio_bank_probe(struct device *dev,
rg->chip.of_xlate = mediatek_gpio_xlate;
rg->chip.label = devm_kasprintf(dev, GFP_KERNEL, "%s-bank%d",
dev_name(dev), bank);
+ if (!rg->chip.label)
+ return -ENOMEM;
ret = devm_gpiochip_add_data(dev, &rg->chip, mtk);
if (ret < 0) {
@@ -295,6 +297,7 @@ mediatek_gpio_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct mtk *mtk;
int i;
+ int ret;
mtk = devm_kzalloc(dev, sizeof(*mtk), GFP_KERNEL);
if (!mtk)
@@ -309,8 +312,11 @@ mediatek_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mtk);
mediatek_gpio_irq_chip.name = dev_name(dev);
- for (i = 0; i < MTK_BANK_CNT; i++)
- mediatek_gpio_bank_probe(dev, np, i);
+ for (i = 0; i < MTK_BANK_CNT; i++) {
+ ret = mediatek_gpio_bank_probe(dev, np, i);
+ if (ret)
+ return ret;
+ }
return 0;
}
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 995cf0b9e0b1ba..2d1dfa1e074562 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -17,6 +17,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/syscore_ops.h>
#include <linux/gpio/driver.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -550,33 +551,38 @@ static void mxc_gpio_restore_regs(struct mxc_gpio_port *port)
writel(port->gpio_saved_reg.dr, port->base + GPIO_DR);
}
-static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev)
+static int mxc_gpio_syscore_suspend(void)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct mxc_gpio_port *port = platform_get_drvdata(pdev);
+ struct mxc_gpio_port *port;
- mxc_gpio_save_regs(port);
- clk_disable_unprepare(port->clk);
+ /* walk through all ports */
+ list_for_each_entry(port, &mxc_gpio_ports, node) {
+ mxc_gpio_save_regs(port);
+ clk_disable_unprepare(port->clk);
+ }
return 0;
}
-static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev)
+static void mxc_gpio_syscore_resume(void)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct mxc_gpio_port *port = platform_get_drvdata(pdev);
+ struct mxc_gpio_port *port;
int ret;
- ret = clk_prepare_enable(port->clk);
- if (ret)
- return ret;
- mxc_gpio_restore_regs(port);
-
- return 0;
+ /* walk through all ports */
+ list_for_each_entry(port, &mxc_gpio_ports, node) {
+ ret = clk_prepare_enable(port->clk);
+ if (ret) {
+ pr_err("mxc: failed to enable gpio clock %d\n", ret);
+ return;
+ }
+ mxc_gpio_restore_regs(port);
+ }
}
-static const struct dev_pm_ops mxc_gpio_dev_pm_ops = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume)
+static struct syscore_ops mxc_gpio_syscore_ops = {
+ .suspend = mxc_gpio_syscore_suspend,
+ .resume = mxc_gpio_syscore_resume,
};
static struct platform_driver mxc_gpio_driver = {
@@ -584,7 +590,6 @@ static struct platform_driver mxc_gpio_driver = {
.name = "gpio-mxc",
.of_match_table = mxc_gpio_dt_ids,
.suppress_bind_attrs = true,
- .pm = &mxc_gpio_dev_pm_ops,
},
.probe = mxc_gpio_probe,
.id_table = mxc_gpio_devtype,
@@ -592,6 +597,8 @@ static struct platform_driver mxc_gpio_driver = {
static int __init gpio_mxc_init(void)
{
+ register_syscore_ops(&mxc_gpio_syscore_ops);
+
return platform_driver_register(&mxc_gpio_driver);
}
subsys_initcall(gpio_mxc_init);
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 9887c3db6e16ac..6ed621a0056182 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -984,8 +984,7 @@ omap4_gpio_disable_level_quirk(struct gpio_bank *bank)
static int omap_mpuio_suspend_noirq(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct gpio_bank *bank = platform_get_drvdata(pdev);
+ struct gpio_bank *bank = dev_get_drvdata(dev);
void __iomem *mask_reg = bank->base +
OMAP_MPUIO_GPIO_MASKIT / bank->stride;
unsigned long flags;
@@ -999,8 +998,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev)
static int omap_mpuio_resume_noirq(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct gpio_bank *bank = platform_get_drvdata(pdev);
+ struct gpio_bank *bank = dev_get_drvdata(dev);
void __iomem *mask_reg = bank->base +
OMAP_MPUIO_GPIO_MASKIT / bank->stride;
unsigned long flags;
@@ -1688,8 +1686,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct gpio_bank *bank = platform_get_drvdata(pdev);
+ struct gpio_bank *bank = dev_get_drvdata(dev);
unsigned long flags;
int error = 0;
@@ -1709,8 +1706,7 @@ unlock:
static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct gpio_bank *bank = platform_get_drvdata(pdev);
+ struct gpio_bank *bank = dev_get_drvdata(dev);
unsigned long flags;
int error = 0;
diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c
index 25d16b2af1c39b..6b73497832231e 100644
--- a/drivers/gpio/gpio-pci-idio-16.c
+++ b/drivers/gpio/gpio-pci-idio-16.c
@@ -146,7 +146,7 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
port_state = ioread8(ports[i]);
/* store acquired bits at respective bits array offset */
- bits[word_index] |= port_state << word_offset;
+ bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c
index f953541e78901b..52f1647a46fdff 100644
--- a/drivers/gpio/gpio-pcie-idio-24.c
+++ b/drivers/gpio/gpio-pcie-idio-24.c
@@ -243,7 +243,7 @@ static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
/* store acquired bits at respective bits array offset */
- bits[word_index] |= port_state << word_offset;
+ bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 2afd9de84a0d05..dc42571e6fdc86 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -54,6 +54,7 @@ struct pl061 {
void __iomem *base;
struct gpio_chip gc;
+ struct irq_chip irq_chip;
int parent_irq;
#ifdef CONFIG_PM
@@ -281,15 +282,6 @@ static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
return irq_set_irq_wake(pl061->parent_irq, state);
}
-static struct irq_chip pl061_irqchip = {
- .name = "pl061",
- .irq_ack = pl061_irq_ack,
- .irq_mask = pl061_irq_mask,
- .irq_unmask = pl061_irq_unmask,
- .irq_set_type = pl061_irq_type,
- .irq_set_wake = pl061_irq_set_wake,
-};
-
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
@@ -328,6 +320,13 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
/*
* irq_chip support
*/
+ pl061->irq_chip.name = dev_name(dev);
+ pl061->irq_chip.irq_ack = pl061_irq_ack;
+ pl061->irq_chip.irq_mask = pl061_irq_mask;
+ pl061->irq_chip.irq_unmask = pl061_irq_unmask;
+ pl061->irq_chip.irq_set_type = pl061_irq_type;
+ pl061->irq_chip.irq_set_wake = pl061_irq_set_wake;
+
writeb(0, pl061->base + GPIOIE); /* disable irqs */
irq = adev->irq[0];
if (irq < 0) {
@@ -336,14 +335,14 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
}
pl061->parent_irq = irq;
- ret = gpiochip_irqchip_add(&pl061->gc, &pl061_irqchip,
+ ret = gpiochip_irqchip_add(&pl061->gc, &pl061->irq_chip,
0, handle_bad_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_info(&adev->dev, "could not add irqchip\n");
return ret;
}
- gpiochip_set_chained_irqchip(&pl061->gc, &pl061_irqchip,
+ gpiochip_set_chained_irqchip(&pl061->gc, &pl061->irq_chip,
irq, pl061_irq_handler);
amba_set_drvdata(adev, pl061);
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 3c82bb3c203049..068ce25ffd28f2 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car GPIO Support
*
* Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2013 Magnus Damm
- *
- * 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; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/err.h>
@@ -43,7 +35,7 @@ struct gpio_rcar_bank_info {
struct gpio_rcar_priv {
void __iomem *base;
spinlock_t lock;
- struct platform_device *pdev;
+ struct device *dev;
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
unsigned int irq_parent;
@@ -148,7 +140,7 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
struct gpio_rcar_priv *p = gpiochip_get_data(gc);
unsigned int hwirq = irqd_to_hwirq(d);
- dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type);
+ dev_dbg(p->dev, "sense irq = %d, type = %d\n", hwirq, type);
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_LEVEL_HIGH:
@@ -188,8 +180,7 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
if (p->irq_parent) {
error = irq_set_irq_wake(p->irq_parent, on);
if (error) {
- dev_dbg(&p->pdev->dev,
- "irq %u doesn't support irq_set_wake\n",
+ dev_dbg(p->dev, "irq %u doesn't support irq_set_wake\n",
p->irq_parent);
p->irq_parent = 0;
}
@@ -252,13 +243,13 @@ static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
int error;
- error = pm_runtime_get_sync(&p->pdev->dev);
+ error = pm_runtime_get_sync(p->dev);
if (error < 0)
return error;
error = pinctrl_gpio_request(chip->base + offset);
if (error)
- pm_runtime_put(&p->pdev->dev);
+ pm_runtime_put(p->dev);
return error;
}
@@ -275,7 +266,7 @@ static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
*/
gpio_rcar_config_general_input_output_mode(chip, offset, false);
- pm_runtime_put(&p->pdev->dev);
+ pm_runtime_put(p->dev);
}
static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset)
@@ -406,21 +397,20 @@ MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
{
- struct device_node *np = p->pdev->dev.of_node;
+ struct device_node *np = p->dev->of_node;
const struct gpio_rcar_info *info;
struct of_phandle_args args;
int ret;
- info = of_device_get_match_data(&p->pdev->dev);
+ info = of_device_get_match_data(p->dev);
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
p->has_both_edge_trigger = info->has_both_edge_trigger;
if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
- dev_warn(&p->pdev->dev,
- "Invalid number of gpio lines %u, using %u\n", *npins,
- RCAR_MAX_GPIO_PER_BANK);
+ dev_warn(p->dev, "Invalid number of gpio lines %u, using %u\n",
+ *npins, RCAR_MAX_GPIO_PER_BANK);
*npins = RCAR_MAX_GPIO_PER_BANK;
}
@@ -442,7 +432,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
if (!p)
return -ENOMEM;
- p->pdev = pdev;
+ p->dev = dev;
spin_lock_init(&p->lock);
/* Get device configuration from DT node */
diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c
index 5497f0a88cf0a5..4df5335469fda9 100644
--- a/drivers/gpio/gpio-sch311x.c
+++ b/drivers/gpio/gpio-sch311x.c
@@ -188,7 +188,7 @@ static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
struct sch311x_gpio_block *block = gpiochip_get_data(chip);
spin_lock(&block->lock);
- __sch311x_gpio_set(block, offset, value);
+ __sch311x_gpio_set(block, offset, value);
spin_unlock(&block->lock);
}
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 47dbd19751d0d4..02f6db925fd5eb 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -404,8 +404,7 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
#ifdef CONFIG_PM_SLEEP
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);
+ struct tegra_gpio_info *tgi = dev_get_drvdata(dev);
unsigned long flags;
unsigned int b, p;
@@ -444,8 +443,7 @@ static int tegra_gpio_resume(struct device *dev)
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);
+ struct tegra_gpio_info *tgi = dev_get_drvdata(dev);
unsigned long flags;
unsigned int b, p;
diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c
index 74551cbdb2e81c..0f662b297a95c9 100644
--- a/drivers/gpio/gpio-uniphier.c
+++ b/drivers/gpio/gpio-uniphier.c
@@ -1,16 +1,7 @@
-/*
- * Copyright (C) 2017 Socionext Inc.
- * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2017 Socionext Inc.
+// Author: Masahiro Yamada <yamada.masahiro@socionext.com>
#include <linux/bits.h>
#include <linux/gpio/driver.h>
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 5960396c8d9a26..1b79ebcfce3e5c 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -7,6 +7,7 @@
* Author: Stefan Agner <stefan@agner.ch>.
*/
#include <linux/bitops.h>
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
@@ -32,6 +33,8 @@ struct vf610_gpio_port {
void __iomem *gpio_base;
const struct fsl_gpio_soc_data *sdata;
u8 irqc[VF610_GPIO_PER_PORT];
+ struct clk *clk_port;
+ struct clk *clk_gpio;
int irq;
};
@@ -271,6 +274,33 @@ static int vf610_gpio_probe(struct platform_device *pdev)
if (port->irq < 0)
return port->irq;
+ port->clk_port = devm_clk_get(&pdev->dev, "port");
+ if (!IS_ERR(port->clk_port)) {
+ ret = clk_prepare_enable(port->clk_port);
+ if (ret)
+ return ret;
+ } else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) {
+ /*
+ * Percolate deferrals, for anything else,
+ * just live without the clocking.
+ */
+ return PTR_ERR(port->clk_port);
+ }
+
+ port->clk_gpio = devm_clk_get(&pdev->dev, "gpio");
+ if (!IS_ERR(port->clk_gpio)) {
+ ret = clk_prepare_enable(port->clk_gpio);
+ if (ret) {
+ clk_disable_unprepare(port->clk_port);
+ return ret;
+ }
+ } else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) {
+ clk_disable_unprepare(port->clk_port);
+ return PTR_ERR(port->clk_gpio);
+ }
+
+ platform_set_drvdata(pdev, port);
+
gc = &port->gc;
gc->of_node = np;
gc->parent = dev;
@@ -305,12 +335,26 @@ static int vf610_gpio_probe(struct platform_device *pdev)
return 0;
}
+static int vf610_gpio_remove(struct platform_device *pdev)
+{
+ struct vf610_gpio_port *port = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&port->gc);
+ if (!IS_ERR(port->clk_port))
+ clk_disable_unprepare(port->clk_port);
+ if (!IS_ERR(port->clk_gpio))
+ clk_disable_unprepare(port->clk_gpio);
+
+ return 0;
+}
+
static struct platform_driver vf610_gpio_driver = {
.driver = {
.name = "gpio-vf610",
.of_match_table = vf610_gpio_dt_ids,
},
.probe = vf610_gpio_probe,
+ .remove = vf610_gpio_remove,
};
builtin_platform_driver(vf610_gpio_driver);
diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
index c7028eb0b8e11e..5cf3697bfb152b 100644
--- a/drivers/gpio/gpio-ws16c48.c
+++ b/drivers/gpio/gpio-ws16c48.c
@@ -169,7 +169,7 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
port_state = inb(ws16c48gpio->base + i);
/* store acquired bits at respective bits array offset */
- bits[word_index] |= port_state << word_offset;
+ bits[word_index] |= (port_state << word_offset) & word_mask;
}
return 0;
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 3f5fcdd5a4291d..b3b4edcdffe0b9 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -358,6 +358,28 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
}
/**
+ * zynq_gpio_get_direction - Read the direction of the specified GPIO pin
+ * @chip: gpio_chip instance to be worked on
+ * @pin: gpio pin number within the device
+ *
+ * This function returns the direction of the specified GPIO.
+ *
+ * Return: 0 for output, 1 for input
+ */
+static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin)
+{
+ u32 reg;
+ unsigned int bank_num, bank_pin_num;
+ struct zynq_gpio *gpio = gpiochip_get_data(chip);
+
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
+
+ reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+
+ return !(reg & BIT(bank_pin_num));
+}
+
+/**
* zynq_gpio_irq_mask - Disable the interrupts for a gpio pin
* @irq_data: per irq and chip data passed down to chip functions
*
@@ -693,8 +715,7 @@ static int __maybe_unused zynq_gpio_resume(struct device *dev)
static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct zynq_gpio *gpio = platform_get_drvdata(pdev);
+ struct zynq_gpio *gpio = dev_get_drvdata(dev);
clk_disable_unprepare(gpio->clk);
@@ -703,8 +724,7 @@ static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev)
static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct zynq_gpio *gpio = platform_get_drvdata(pdev);
+ struct zynq_gpio *gpio = dev_get_drvdata(dev);
return clk_prepare_enable(gpio->clk);
}
@@ -827,6 +847,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
chip->free = zynq_gpio_free;
chip->direction_input = zynq_gpio_dir_in;
chip->direction_output = zynq_gpio_dir_out;
+ chip->get_direction = zynq_gpio_get_direction;
chip->base = of_alias_get_id(pdev->dev.of_node, "gpio");
chip->ngpio = gpio->p_data->ngpio;
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 55b72fbe163169..091a3784720d0e 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -19,11 +19,28 @@
#include "gpiolib.h"
+/**
+ * struct acpi_gpio_event - ACPI GPIO event handler data
+ *
+ * @node: list-entry of the events list of the struct acpi_gpio_chip
+ * @handle: handle of ACPI method to execute when the IRQ triggers
+ * @handler: irq_handler to pass to request_irq when requesting the IRQ
+ * @pin: GPIO pin number on the gpio_chip
+ * @irq: Linux IRQ number for the event, for request_ / free_irq
+ * @irqflags: flags to pass to request_irq when requesting the IRQ
+ * @irq_is_wake: If the ACPI flags indicate the IRQ is a wakeup source
+ * @is_requested: True if request_irq has been done
+ * @desc: gpio_desc for the GPIO pin for this event
+ */
struct acpi_gpio_event {
struct list_head node;
acpi_handle handle;
+ irq_handler_t handler;
unsigned int pin;
unsigned int irq;
+ unsigned long irqflags;
+ bool irq_is_wake;
+ bool irq_requested;
struct gpio_desc *desc;
};
@@ -49,10 +66,10 @@ struct acpi_gpio_chip {
/*
* For gpiochips which call acpi_gpiochip_request_interrupts() before late_init
- * (so builtin drivers) we register the ACPI GpioInt event handlers from a
+ * (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
* late_initcall_sync handler, so that other builtin drivers can register their
* OpRegions before the event handlers can run. This list contains gpiochips
- * for which the acpi_gpiochip_request_interrupts() has been deferred.
+ * for which the acpi_gpiochip_request_irqs() call has been deferred.
*/
static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
static LIST_HEAD(acpi_gpio_deferred_req_irqs_list);
@@ -133,8 +150,42 @@ bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
}
EXPORT_SYMBOL_GPL(acpi_gpio_get_irq_resource);
-static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
- void *context)
+static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
+ struct acpi_gpio_event *event)
+{
+ int ret, value;
+
+ ret = request_threaded_irq(event->irq, NULL, event->handler,
+ event->irqflags, "ACPI:Event", event);
+ if (ret) {
+ dev_err(acpi_gpio->chip->parent,
+ "Failed to setup interrupt handler for %d\n",
+ event->irq);
+ return;
+ }
+
+ if (event->irq_is_wake)
+ enable_irq_wake(event->irq);
+
+ event->irq_requested = true;
+
+ /* Make sure we trigger the initial state of edge-triggered IRQs */
+ value = gpiod_get_raw_value_cansleep(event->desc);
+ if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
+ ((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
+ event->handler(event->irq, event);
+}
+
+static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
+{
+ struct acpi_gpio_event *event;
+
+ list_for_each_entry(event, &acpi_gpio->events, node)
+ acpi_gpiochip_request_irq(acpi_gpio, event);
+}
+
+static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
+ void *context)
{
struct acpi_gpio_chip *acpi_gpio = context;
struct gpio_chip *chip = acpi_gpio->chip;
@@ -143,8 +194,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
struct acpi_gpio_event *event;
irq_handler_t handler = NULL;
struct gpio_desc *desc;
- unsigned long irqflags;
- int ret, pin, irq, value;
+ int ret, pin, irq;
if (!acpi_gpio_get_irq_resource(ares, &agpio))
return AE_OK;
@@ -175,8 +225,6 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
gpiod_direction_input(desc);
- value = gpiod_get_value_cansleep(desc);
-
ret = gpiochip_lock_as_irq(chip, pin);
if (ret) {
dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
@@ -189,64 +237,42 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
goto fail_unlock_irq;
}
- irqflags = IRQF_ONESHOT;
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event)
+ goto fail_unlock_irq;
+
+ event->irqflags = IRQF_ONESHOT;
if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
if (agpio->polarity == ACPI_ACTIVE_HIGH)
- irqflags |= IRQF_TRIGGER_HIGH;
+ event->irqflags |= IRQF_TRIGGER_HIGH;
else
- irqflags |= IRQF_TRIGGER_LOW;
+ event->irqflags |= IRQF_TRIGGER_LOW;
} else {
switch (agpio->polarity) {
case ACPI_ACTIVE_HIGH:
- irqflags |= IRQF_TRIGGER_RISING;
+ event->irqflags |= IRQF_TRIGGER_RISING;
break;
case ACPI_ACTIVE_LOW:
- irqflags |= IRQF_TRIGGER_FALLING;
+ event->irqflags |= IRQF_TRIGGER_FALLING;
break;
default:
- irqflags |= IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING;
+ event->irqflags |= IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING;
break;
}
}
- event = kzalloc(sizeof(*event), GFP_KERNEL);
- if (!event)
- goto fail_unlock_irq;
-
event->handle = evt_handle;
+ event->handler = handler;
event->irq = irq;
+ event->irq_is_wake = agpio->wake_capable == ACPI_WAKE_CAPABLE;
event->pin = pin;
event->desc = desc;
- ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
- "ACPI:Event", event);
- if (ret) {
- dev_err(chip->parent,
- "Failed to setup interrupt handler for %d\n",
- event->irq);
- goto fail_free_event;
- }
-
- if (agpio->wake_capable == ACPI_WAKE_CAPABLE)
- enable_irq_wake(irq);
-
list_add_tail(&event->node, &acpi_gpio->events);
- /*
- * Make sure we trigger the initial state of the IRQ when using RISING
- * or FALLING. Note we run the handlers on late_init, the AML code
- * may refer to OperationRegions from other (builtin) drivers which
- * may be probed after us.
- */
- if (((irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
- ((irqflags & IRQF_TRIGGER_FALLING) && value == 0))
- handler(event->irq, event);
-
return AE_OK;
-fail_free_event:
- kfree(event);
fail_unlock_irq:
gpiochip_unlock_as_irq(chip, pin);
fail_free_desc:
@@ -283,6 +309,9 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
if (ACPI_FAILURE(status))
return;
+ acpi_walk_resources(handle, "_AEI",
+ acpi_gpiochip_alloc_event, acpi_gpio);
+
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
defer = !acpi_gpio_deferred_req_irqs_done;
if (defer)
@@ -293,8 +322,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
if (defer)
return;
- acpi_walk_resources(handle, "_AEI",
- acpi_gpiochip_request_interrupt, acpi_gpio);
+ acpi_gpiochip_request_irqs(acpi_gpio);
}
EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
@@ -329,17 +357,15 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
- struct gpio_desc *desc;
+ if (event->irq_requested) {
+ if (event->irq_is_wake)
+ disable_irq_wake(event->irq);
- if (irqd_is_wakeup_set(irq_get_irq_data(event->irq)))
- disable_irq_wake(event->irq);
+ free_irq(event->irq, event);
+ }
- free_irq(event->irq, event);
- desc = event->desc;
- if (WARN_ON(IS_ERR(desc)))
- continue;
gpiochip_unlock_as_irq(chip, event->pin);
- gpiochip_free_own_desc(desc);
+ gpiochip_free_own_desc(event->desc);
list_del(&event->node);
kfree(event);
}
@@ -1200,23 +1226,16 @@ bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
return con_id == NULL;
}
-/* Run deferred acpi_gpiochip_request_interrupts() */
-static int acpi_gpio_handle_deferred_request_interrupts(void)
+/* Run deferred acpi_gpiochip_request_irqs() */
+static int acpi_gpio_handle_deferred_request_irqs(void)
{
struct acpi_gpio_chip *acpi_gpio, *tmp;
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
list_for_each_entry_safe(acpi_gpio, tmp,
&acpi_gpio_deferred_req_irqs_list,
- deferred_req_irqs_list_entry) {
- acpi_handle handle;
-
- handle = ACPI_HANDLE(acpi_gpio->chip->parent);
- acpi_walk_resources(handle, "_AEI",
- acpi_gpiochip_request_interrupt, acpi_gpio);
-
- list_del_init(&acpi_gpio->deferred_req_irqs_list_entry);
- }
+ deferred_req_irqs_list_entry)
+ acpi_gpiochip_request_irqs(acpi_gpio);
acpi_gpio_deferred_req_irqs_done = true;
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
@@ -1224,4 +1243,4 @@ static int acpi_gpio_handle_deferred_request_interrupts(void)
return 0;
}
/* We must use _sync so that this runs after the first deferred_probe run */
-late_initcall_sync(acpi_gpio_handle_deferred_request_interrupts);
+late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 7f1260c78270b5..fa8044228f0e25 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0+
/*
* OF helpers for the GPIO API
*
@@ -58,6 +58,45 @@ static void of_gpio_flags_quirks(struct device_node *np,
int index)
{
/*
+ * Handle MMC "cd-inverted" and "wp-inverted" semantics.
+ */
+ if (IS_ENABLED(CONFIG_MMC)) {
+ if (of_property_read_bool(np, "cd-gpios")) {
+ if (of_property_read_bool(np, "cd-inverted")) {
+ if (*flags & OF_GPIO_ACTIVE_LOW) {
+ /* "cd-inverted" takes precedence */
+ *flags &= ~OF_GPIO_ACTIVE_LOW;
+ pr_warn("%s GPIO handle specifies CD active low - ignored\n",
+ of_node_full_name(np));
+ }
+ } else {
+ /*
+ * Active low is the default according to the
+ * SDHCI specification. If the GPIO handle
+ * specifies the same thing - good.
+ */
+ *flags |= OF_GPIO_ACTIVE_LOW;
+ }
+ }
+ if (of_property_read_bool(np, "wp-gpios")) {
+ if (of_property_read_bool(np, "wp-inverted")) {
+ /* "wp-inverted" takes precedence */
+ if (*flags & OF_GPIO_ACTIVE_LOW) {
+ *flags &= ~OF_GPIO_ACTIVE_LOW;
+ pr_warn("%s GPIO handle specifies WP active low - ignored\n",
+ of_node_full_name(np));
+ }
+ } else {
+ /*
+ * Active low is the default according to the
+ * SDHCI specification. If the GPIO handle
+ * specifies the same thing - good.
+ */
+ *flags |= OF_GPIO_ACTIVE_LOW;
+ }
+ }
+ }
+ /*
* Some GPIO fixed regulator quirks.
* Note that active low is the default.
*/
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 985c09ce80fbc4..fc36dc3587164c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1512,19 +1512,6 @@ static void devm_gpio_chip_release(struct device *dev, void *res)
gpiochip_remove(chip);
}
-static int devm_gpio_chip_match(struct device *dev, void *res, void *data)
-
-{
- struct gpio_chip **r = res;
-
- if (!r || !*r) {
- WARN_ON(!r || !*r);
- return 0;
- }
-
- return *r == data;
-}
-
/**
* devm_gpiochip_add_data() - Resource manager gpiochip_add_data()
* @dev: pointer to the device that gpio_chip belongs to.
@@ -1565,23 +1552,6 @@ int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
/**
- * devm_gpiochip_remove() - Resource manager of gpiochip_remove()
- * @dev: device for which which resource was allocated
- * @chip: the chip to remove
- *
- * A gpio_chip with any GPIOs still requested may not be removed.
- */
-void devm_gpiochip_remove(struct device *dev, struct gpio_chip *chip)
-{
- int ret;
-
- ret = devres_release(dev, devm_gpio_chip_release,
- devm_gpio_chip_match, chip);
- WARN_ON(ret);
-}
-EXPORT_SYMBOL_GPL(devm_gpiochip_remove);
-
-/**
* gpiochip_find() - iterator for locating a specific gpio_chip
* @data: data to pass to match function
* @match: Callback function to check gpio_chip
@@ -2299,6 +2269,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
unsigned long flags;
unsigned offset;
+ if (label) {
+ label = kstrdup_const(label, GFP_KERNEL);
+ if (!label)
+ return -ENOMEM;
+ }
+
spin_lock_irqsave(&gpio_lock, flags);
/* NOTE: gpio_request() can be called in early boot,
@@ -2309,6 +2285,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
desc_set_label(desc, label ? : "?");
status = 0;
} else {
+ kfree_const(label);
status = -EBUSY;
goto done;
}
@@ -2325,6 +2302,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
if (status < 0) {
desc_set_label(desc, NULL);
+ kfree_const(label);
clear_bit(FLAG_REQUESTED, &desc->flags);
goto done;
}
@@ -2420,6 +2398,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
chip->free(chip, gpio_chip_hwgpio(desc));
spin_lock_irqsave(&gpio_lock, flags);
}
+ kfree_const(desc->label);
desc_set_label(desc, NULL);
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
@@ -3375,11 +3354,19 @@ EXPORT_SYMBOL_GPL(gpiod_cansleep);
* @desc: gpio to set the consumer name on
* @name: the new consumer name
*/
-void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
+int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
{
- VALIDATE_DESC_VOID(desc);
- /* Just overwrite whatever the previous name was */
- desc->label = name;
+ VALIDATE_DESC(desc);
+ if (name) {
+ name = kstrdup_const(name, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ }
+
+ kfree_const(desc->label);
+ desc_set_label(desc, name);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(gpiod_set_consumer_name);
diff --git a/include/dt-bindings/gpio/tegra186-gpio.h b/include/dt-bindings/gpio/tegra186-gpio.h
index 463ad398fe3eae..cabc5712e74501 100644
--- a/include/dt-bindings/gpio/tegra186-gpio.h
+++ b/include/dt-bindings/gpio/tegra186-gpio.h
@@ -14,6 +14,34 @@
#include <dt-bindings/gpio/gpio.h>
/* GPIOs implemented by main GPIO controller */
+#define TEGRA186_MAIN_GPIO_PORT_A 0
+#define TEGRA186_MAIN_GPIO_PORT_B 1
+#define TEGRA186_MAIN_GPIO_PORT_C 2
+#define TEGRA186_MAIN_GPIO_PORT_D 3
+#define TEGRA186_MAIN_GPIO_PORT_E 4
+#define TEGRA186_MAIN_GPIO_PORT_F 5
+#define TEGRA186_MAIN_GPIO_PORT_G 6
+#define TEGRA186_MAIN_GPIO_PORT_H 7
+#define TEGRA186_MAIN_GPIO_PORT_I 8
+#define TEGRA186_MAIN_GPIO_PORT_J 9
+#define TEGRA186_MAIN_GPIO_PORT_K 10
+#define TEGRA186_MAIN_GPIO_PORT_L 11
+#define TEGRA186_MAIN_GPIO_PORT_M 12
+#define TEGRA186_MAIN_GPIO_PORT_N 13
+#define TEGRA186_MAIN_GPIO_PORT_O 14
+#define TEGRA186_MAIN_GPIO_PORT_P 15
+#define TEGRA186_MAIN_GPIO_PORT_Q 16
+#define TEGRA186_MAIN_GPIO_PORT_R 17
+#define TEGRA186_MAIN_GPIO_PORT_T 18
+#define TEGRA186_MAIN_GPIO_PORT_X 19
+#define TEGRA186_MAIN_GPIO_PORT_Y 20
+#define TEGRA186_MAIN_GPIO_PORT_BB 21
+#define TEGRA186_MAIN_GPIO_PORT_CC 22
+
+#define TEGRA186_MAIN_GPIO(port, offset) \
+ ((TEGRA186_MAIN_GPIO_PORT_##port * 8) + offset)
+
+/* need to keep these for backwards-compatibility */
#define TEGRA_MAIN_GPIO_PORT_A 0
#define TEGRA_MAIN_GPIO_PORT_B 1
#define TEGRA_MAIN_GPIO_PORT_C 2
@@ -42,6 +70,19 @@
((TEGRA_MAIN_GPIO_PORT_##port * 8) + offset)
/* GPIOs implemented by AON GPIO controller */
+#define TEGRA186_AON_GPIO_PORT_S 0
+#define TEGRA186_AON_GPIO_PORT_U 1
+#define TEGRA186_AON_GPIO_PORT_V 2
+#define TEGRA186_AON_GPIO_PORT_W 3
+#define TEGRA186_AON_GPIO_PORT_Z 4
+#define TEGRA186_AON_GPIO_PORT_AA 5
+#define TEGRA186_AON_GPIO_PORT_EE 6
+#define TEGRA186_AON_GPIO_PORT_FF 7
+
+#define TEGRA186_AON_GPIO(port, offset) \
+ ((TEGRA186_AON_GPIO_PORT_##port * 8) + offset)
+
+/* need to keep these for backwards-compatibility */
#define TEGRA_AON_GPIO_PORT_S 0
#define TEGRA_AON_GPIO_PORT_U 1
#define TEGRA_AON_GPIO_PORT_V 2
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 8aebcf822082ea..7e55a68772d11a 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -163,7 +163,7 @@ int gpiod_is_active_low(const struct gpio_desc *desc);
int gpiod_cansleep(const struct gpio_desc *desc);
int gpiod_to_irq(const struct gpio_desc *desc);
-void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name);
+int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name);
/* Convert between the old gpio_ and new gpiod_ interfaces */
struct gpio_desc *gpio_to_desc(unsigned gpio);
@@ -509,10 +509,12 @@ static inline int gpiod_to_irq(const struct gpio_desc *desc)
return -EINVAL;
}
-static inline void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
+static inline int gpiod_set_consumer_name(struct gpio_desc *desc,
+ const char *name)
{
/* GPIO can never have been requested */
WARN_ON(1);
+ return -EINVAL;
}
static inline struct gpio_desc *gpio_to_desc(unsigned gpio)
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 2db62b550b95a5..9c8d5d491680c9 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -166,11 +166,6 @@ struct gpio_irq_chip {
*/
void (*irq_disable)(struct irq_data *data);
};
-
-static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
-{
- return container_of(chip, struct gpio_irq_chip, chip);
-}
#endif
/**
@@ -422,7 +417,6 @@ static inline int gpiochip_add(struct gpio_chip *chip)
extern void gpiochip_remove(struct gpio_chip *chip);
extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
void *data);
-extern void devm_gpiochip_remove(struct device *dev, struct gpio_chip *chip);
extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, void *data));