summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2017-02-17 14:24:32 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2017-02-17 14:24:35 +1100
commitd5f1dc97dbf3a671ca8d19a4a2ade2bc4f4616ac (patch)
tree66290bce77a989650250df5f495130bc50ebaa53
parentffd28acc029b3bbb7f2ff6478fea6a90178ec5d9 (diff)
parent9202ba2397d1ded79078606c6921787b27a85e1a (diff)
Merge remote-tracking branch 'gpio/for-next'
-rw-r--r--Documentation/devicetree/bindings/gpio/cortina,gemini-gpio.txt24
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-pca953x.txt4
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio.txt8
-rw-r--r--Documentation/gpio/driver.txt64
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/gpio/Kconfig29
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/devres.c32
-rw-r--r--drivers/gpio/gpio-104-dio-48e.c91
-rw-r--r--drivers/gpio/gpio-104-idi-48.c45
-rw-r--r--drivers/gpio/gpio-104-idio-16.c60
-rw-r--r--drivers/gpio/gpio-bcm-kona.c14
-rw-r--r--drivers/gpio/gpio-davinci.c177
-rw-r--r--drivers/gpio/gpio-dln2.c12
-rw-r--r--drivers/gpio/gpio-dwapb.c14
-rw-r--r--drivers/gpio/gpio-ep93xx.c11
-rw-r--r--drivers/gpio/gpio-exar.c200
-rw-r--r--drivers/gpio/gpio-f7188x.c19
-rw-r--r--drivers/gpio/gpio-gemini.c236
-rw-r--r--drivers/gpio/gpio-gpio-mm.c68
-rw-r--r--drivers/gpio/gpio-intel-mid.c2
-rw-r--r--drivers/gpio/gpio-lp873x.c14
-rw-r--r--drivers/gpio/gpio-max77620.c20
-rw-r--r--drivers/gpio/gpio-mcp23s08.c320
-rw-r--r--drivers/gpio/gpio-menz127.c34
-rw-r--r--drivers/gpio/gpio-merrifield.c14
-rw-r--r--drivers/gpio/gpio-mm-lantiq.c2
-rw-r--r--drivers/gpio/gpio-mockup.c377
-rw-r--r--drivers/gpio/gpio-mvebu.c2
-rw-r--r--drivers/gpio/gpio-omap.c14
-rw-r--r--drivers/gpio/gpio-pca953x.c9
-rw-r--r--drivers/gpio/gpio-pci-idio-16.c348
-rw-r--r--drivers/gpio/gpio-rcar.c21
-rw-r--r--drivers/gpio/gpio-stp-xway.c2
-rw-r--r--drivers/gpio/gpio-tc3589x.c15
-rw-r--r--drivers/gpio/gpio-tegra.c14
-rw-r--r--drivers/gpio/gpio-tps65218.c14
-rw-r--r--drivers/gpio/gpio-vx855.c13
-rw-r--r--drivers/gpio/gpio-wcove.c13
-rw-r--r--drivers/gpio/gpio-wm831x.c21
-rw-r--r--drivers/gpio/gpio-wm8994.c13
-rw-r--r--drivers/gpio/gpio-ws16c48.c90
-rw-r--r--drivers/gpio/gpiolib-acpi.c5
-rw-r--r--drivers/gpio/gpiolib-of.c31
-rw-r--r--drivers/gpio/gpiolib.c111
-rw-r--r--drivers/gpio/gpiolib.h3
-rw-r--r--drivers/input/keyboard/gpio_keys.c12
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c14
-rw-r--r--drivers/leds/leds-gpio.c14
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm281xx.c6
-rw-r--r--drivers/pinctrl/bcm/pinctrl-iproc-gpio.c2
-rw-r--r--drivers/pinctrl/bcm/pinctrl-ns2-mux.c6
-rw-r--r--drivers/pinctrl/bcm/pinctrl-nsp-gpio.c6
-rw-r--r--drivers/pinctrl/core.c29
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c4
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c14
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c2
-rw-r--r--drivers/pinctrl/pinconf.c12
-rw-r--r--drivers/pinctrl/pinconf.h9
-rw-r--r--drivers/pinctrl/pinctrl-amd.c14
-rw-r--r--drivers/pinctrl/pinctrl-da850-pupd.c2
-rw-r--r--drivers/pinctrl/pinctrl-lpc18xx.c10
-rw-r--r--drivers/pinctrl/pinctrl-max77620.c2
-rw-r--r--drivers/pinctrl/pinctrl-palmas.c2
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c2
-rw-r--r--drivers/pinctrl/pinctrl-single.c2
-rw-r--r--drivers/pinctrl/pinctrl-sx150x.c55
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas7.c3
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c2
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-core.c4
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c2
-rw-r--r--drivers/rtc/rtc-omap.c2
-rw-r--r--drivers/staging/greybus/gpio.c15
-rw-r--r--drivers/tty/serial/st-asc.c11
-rw-r--r--drivers/usb/serial/cp210x.c13
-rw-r--r--drivers/video/fbdev/amba-clcd-nomadik.c19
-rw-r--r--include/linux/gpio/consumer.h38
-rw-r--r--include/linux/gpio/driver.h37
-rw-r--r--include/linux/pinctrl/consumer.h6
-rw-r--r--include/linux/pinctrl/pinconf-generic.h52
-rw-r--r--include/linux/platform_data/gpio-davinci.h15
-rw-r--r--tools/gpio/.gitignore4
-rw-r--r--tools/gpio/gpio-hammer.c2
83 files changed, 2222 insertions, 861 deletions
diff --git a/Documentation/devicetree/bindings/gpio/cortina,gemini-gpio.txt b/Documentation/devicetree/bindings/gpio/cortina,gemini-gpio.txt
new file mode 100644
index 000000000000..5c9246c054e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/cortina,gemini-gpio.txt
@@ -0,0 +1,24 @@
+Cortina Systems Gemini GPIO Controller
+
+Required properties:
+
+- compatible : Must be "cortina,gemini-gpio"
+- reg : Should contain registers location and length
+- interrupts : Should contain the interrupt line for the GPIO block
+- gpio-controller : marks this as a GPIO controller
+- #gpio-cells : Should be 2, see gpio/gpio.txt
+- interrupt-controller : marks this as an interrupt controller
+- #interrupt-cells : a standard two-cell interrupt flag, see
+ interrupt-controller/interrupts.txt
+
+Example:
+
+gpio@4d000000 {
+ compatible = "cortina,gemini-gpio";
+ reg = <0x4d000000 0x100>;
+ interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
index 08dd15f89ba9..e63935710011 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
@@ -29,6 +29,10 @@ Required properties:
onsemi,pca9654
exar,xra1202
+Optional properties:
+ - reset-gpios: GPIO specification for the RESET input. This is an
+ active low signal to the PCA953x.
+
Example:
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index 68d28f62a6f4..84ede036f73d 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -187,10 +187,10 @@ gpio-controller's driver probe function.
Each GPIO hog definition is represented as a child node of the GPIO controller.
Required properties:
-- gpio-hog: A property specifying that this child node represent a GPIO hog.
-- gpios: Store the GPIO information (id, flags, ...). Shall contain the
- number of cells specified in its parent node (GPIO controller
- node).
+- gpio-hog: A property specifying that this child node represents a GPIO hog.
+- gpios: Store the GPIO information (id, flags, ...) for each GPIO to
+ affect. Shall contain an integer multiple of the number of cells
+ specified in its parent node (GPIO controller node).
Only one of the following properties scanned in the order shown below.
This means that when multiple properties are present they will be searched
in the order presented below and the first match is taken as the intended
diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index 747c721776ed..fc1d2f83564d 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -41,34 +41,71 @@ In the gpiolib framework each GPIO controller is packaged as a "struct
gpio_chip" (see linux/gpio/driver.h for its complete definition) with members
common to each controller of that type:
- - methods to establish GPIO direction
- - methods used to access GPIO values
- - method to return the IRQ number associated to a given GPIO
+ - methods to establish GPIO line direction
+ - methods used to access GPIO line values
+ - method to set electrical configuration to a a given GPIO line
+ - method to return the IRQ number associated to a given GPIO line
- flag saying whether calls to its methods may sleep
+ - optional line names array to identify lines
- optional debugfs dump method (showing extra state like pullup config)
- optional base number (will be automatically assigned if omitted)
- - label for diagnostics and GPIOs mapping using platform data
+ - optional label for diagnostics and GPIO chip mapping using platform data
The code implementing a gpio_chip should support multiple instances of the
controller, possibly using the driver model. That code will configure each
-gpio_chip and issue gpiochip_add(). Removing a GPIO controller should be rare;
-use gpiochip_remove() when it is unavoidable.
+gpio_chip and issue gpiochip_add[_data]() or devm_gpiochip_add_data().
+Removing a GPIO controller should be rare; use [devm_]gpiochip_remove() when
+it is unavoidable.
-Most often a gpio_chip is part of an instance-specific structure with state not
+Often a gpio_chip is part of an instance-specific structure with states not
exposed by the GPIO interfaces, such as addressing, power management, and more.
-Chips such as codecs will have complex non-GPIO state.
+Chips such as audio codecs will have complex non-GPIO states.
Any debugfs dump method should normally ignore signals which haven't been
requested as GPIOs. They can use gpiochip_is_requested(), which returns either
NULL or the label associated with that GPIO when it was requested.
-RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs
+RT_FULL: the GPIO driver should not use spinlock_t or any sleepable APIs
(like PM runtime) in its gpio_chip implementation (.get/.set and direction
control callbacks) if it is expected to call GPIO APIs from atomic context
on -RT (inside hard IRQ handlers and similar contexts). Normally this should
not be required.
+GPIO electrical configuration
+-----------------------------
+
+GPIOs can be configured for several electrical modes of operation by using the
+.set_config() callback. Currently this API supports setting debouncing and
+single-ended modes (open drain/open source). These settings are described
+below.
+
+The .set_config() callback uses the same enumerators and configuration
+semantics as the generic pin control drivers. This is not a coincidence: it is
+possible to assign the .set_config() to the function gpiochip_generic_config()
+which will result in pinctrl_gpio_set_config() being called and eventually
+ending up in the pin control back-end "behind" the GPIO controller, usually
+closer to the actual pins. This way the pin controller can manage the below
+listed GPIO configurations.
+
+
+GPIOs with debounce support
+---------------------------
+
+Debouncing is a configuration set to a pin indicating that it is connected to
+a mechanical switch or button, or similar that may bounce. Bouncing means the
+line is pulled high/low quickly at very short intervals for mechanical
+reasons. This can result in the value being unstable or irqs fireing repeatedly
+unless the line is debounced.
+
+Debouncing in practice involves setting up a timer when something happens on
+the line, wait a little while and then sample the line again, so see if it
+still has the same value (low or high). This could also be repeated by a clever
+state machine, waiting for a line to become stable. In either case, it sets
+a certain number of milliseconds for debouncing, or just "on/off" if that time
+is not configurable.
+
+
GPIOs with open drain/source support
------------------------------------
@@ -146,10 +183,11 @@ a pull-up resistor is needed on the outgoing rail to complete the circuit, and
in the second case, a pull-down resistor is needed on the rail.
Hardware that supports open drain or open source or both, can implement a
-special callback in the gpio_chip: .set_single_ended() that takes an enum flag
-telling whether to configure the line as open drain, open source or push-pull.
-This will happen in response to the GPIO_OPEN_DRAIN or GPIO_OPEN_SOURCE flag
-set in the machine file, or coming from other hardware descriptions.
+special callback in the gpio_chip: .set_config() that takes a generic
+pinconf packed value telling whether to configure the line as open drain,
+open source or push-pull. This will happen in response to the
+GPIO_OPEN_DRAIN or GPIO_OPEN_SOURCE flag set in the machine file, or coming
+from other hardware descriptions.
If this state can not be configured in hardware, i.e. if the GPIO hardware does
not support open drain/open source in hardware, the GPIO library will instead
diff --git a/MAINTAINERS b/MAINTAINERS
index ca1c40cf770a..985834dfd725 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -265,6 +265,12 @@ L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/counter/104-quad-8.c
+ACCES PCI-IDIO-16 GPIO DRIVER
+M: William Breathitt Gray <vilhelm.gray@gmail.com>
+L: linux-gpio@vger.kernel.org
+S: Maintained
+F: drivers/gpio/gpio-pci-idio-16.c
+
ACENIC DRIVER
M: Jes Sorensen <jes@trained-monkey.org>
L: linux-acenic@sunsite.dk
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d5d36549ecc1..05043071fc98 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -185,6 +185,13 @@ config GPIO_ETRAXFS
help
Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.
+config GPIO_EXAR
+ tristate "Support for GPIO pins on XR17V352/354/358"
+ depends on SERIAL_8250_EXAR
+ help
+ Selecting this option will enable handling of GPIO pins present
+ on Exar XR17V352/354/358 chips.
+
config GPIO_GE_FPGA
bool "GE FPGA based GPIO"
depends on GE_FPGA
@@ -197,6 +204,15 @@ config GPIO_GE_FPGA
and write pin state) for GPIO implemented in a number of GE single
board computers.
+config GPIO_GEMINI
+ bool "Gemini GPIO"
+ depends on ARCH_GEMINI
+ depends on OF_GPIO
+ select GPIO_GENERIC
+ select GPIOLIB_IRQCHIP
+ help
+ Support for common GPIOs found in Cortina systems Gemini platforms.
+
config GPIO_GENERIC_PLATFORM
tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
select GPIO_GENERIC
@@ -282,6 +298,8 @@ config GPIO_MOCKUP
tristate "GPIO Testing Driver"
depends on GPIOLIB && SYSFS
select GPIO_SYSFS
+ select GPIOLIB_IRQCHIP
+ select IRQ_WORK
help
This enables GPIO Testing driver, which provides a way to test GPIO
subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
@@ -1141,6 +1159,15 @@ config GPIO_PCH
ML7223/ML7831 is companion chip for Intel Atom E6xx series.
ML7223/ML7831 is completely compatible for Intel EG20T PCH.
+config GPIO_PCI_IDIO_16
+ tristate "ACCES PCI-IDIO-16 GPIO support"
+ select GPIOLIB_IRQCHIP
+ help
+ Enables GPIO support for the ACCES PCI-IDIO-16. An interrupt is
+ generated when any of the inputs change state (low to high or high to
+ low). Input filter control is not supported by this driver, and the
+ input filters are deactivated by this driver.
+
config GPIO_RDC321X
tristate "RDC R-321x GPIO support"
select MFD_CORE
@@ -1197,6 +1224,8 @@ config GPIO_MCP23S08
tristate "Microchip MCP23xxx I/O expander"
depends on OF_GPIO
select GPIOLIB_IRQCHIP
+ select REGMAP_I2C if I2C
+ select REGMAP if SPI_MASTER
help
SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
I/O expanders.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a7676b82de6f..becb96c724fe 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -46,8 +46,10 @@ obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
+obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
+obj-$(CONFIG_GPIO_GEMINI) += gpio-gemini.o
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
@@ -90,6 +92,7 @@ obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
+obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index b760cbbb41d8..7031eea165c9 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -11,7 +11,7 @@
*
* This file is based on kernel/irq/devres.c
*
- * Copyright (c) 2011 John Crispin <blogic@openwrt.org>
+ * Copyright (c) 2011 John Crispin <john@phrozen.org>
*/
#include <linux/module.h>
@@ -21,6 +21,8 @@
#include <linux/device.h>
#include <linux/gfp.h>
+#include "gpiolib.h"
+
static void devm_gpiod_release(struct device *dev, void *res)
{
struct gpio_desc **desc = res;
@@ -123,19 +125,26 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
EXPORT_SYMBOL(devm_gpiod_get_index);
/**
- * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node
+ * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a
+ * device's child node
* @dev: GPIO consumer
* @con_id: function within the GPIO consumer
+ * @index: index of the GPIO to obtain in the consumer
* @child: firmware node (child of @dev)
+ * @flags: GPIO initialization flags
*
* GPIO descriptors returned from this function are automatically disposed on
* driver detach.
+ *
+ * On successfull request the GPIO pin is configured in accordance with
+ * provided @flags.
*/
-struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
- const char *con_id,
- struct fwnode_handle *child)
+struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
+ const char *con_id, int index,
+ struct fwnode_handle *child,
+ enum gpiod_flags flags,
+ const char *label)
{
- static const char * const suffixes[] = { "gpios", "gpio" };
char prop_name[32]; /* 32 is max size of property name */
struct gpio_desc **dr;
struct gpio_desc *desc;
@@ -146,15 +155,16 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
if (!dr)
return ERR_PTR(-ENOMEM);
- for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id)
snprintf(prop_name, sizeof(prop_name), "%s-%s",
- con_id, suffixes[i]);
+ con_id, gpio_suffixes[i]);
else
snprintf(prop_name, sizeof(prop_name), "%s",
- suffixes[i]);
+ gpio_suffixes[i]);
- desc = fwnode_get_named_gpiod(child, prop_name);
+ desc = fwnode_get_named_gpiod(child, prop_name, index, flags,
+ label);
if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
break;
}
@@ -168,7 +178,7 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
return desc;
}
-EXPORT_SYMBOL(devm_get_gpiod_from_child);
+EXPORT_SYMBOL(devm_fwnode_get_index_gpiod_from_child);
/**
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index fcf776971ca9..17bd2ab4ebe2 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -48,7 +48,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
* @control: Control registers state
* @lock: synchronization lock to prevent I/O race conditions
* @base: base port address of the GPIO device
- * @irq: Interrupt line number
* @irq_mask: I/O bits affected by interrupts
*/
struct dio48e_gpio {
@@ -58,7 +57,6 @@ struct dio48e_gpio {
unsigned char control[2];
spinlock_t lock;
unsigned base;
- unsigned irq;
unsigned char irq_mask;
};
@@ -204,6 +202,44 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&dio48egpio->lock, flags);
}
+static void dio48e_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
+{
+ struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
+ unsigned int i;
+ const unsigned int gpio_reg_size = 8;
+ unsigned int port;
+ unsigned int out_port;
+ unsigned int bitmask;
+ unsigned long flags;
+
+ /* set bits are evaluated a gpio register size at a time */
+ for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
+ /* no more set bits in this mask word; skip to the next word */
+ if (!mask[BIT_WORD(i)]) {
+ i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
+ continue;
+ }
+
+ port = i / gpio_reg_size;
+ out_port = (port > 2) ? port + 1 : port;
+ bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
+
+ spin_lock_irqsave(&dio48egpio->lock, flags);
+
+ /* update output state data and set device gpio register */
+ dio48egpio->out_state[port] &= ~mask[BIT_WORD(i)];
+ dio48egpio->out_state[port] |= bitmask;
+ outb(dio48egpio->out_state[port], dio48egpio->base + out_port);
+
+ spin_unlock_irqrestore(&dio48egpio->lock, flags);
+
+ /* prepare for next gpio register set */
+ mask[BIT_WORD(i)] >>= gpio_reg_size;
+ bits[BIT_WORD(i)] >>= gpio_reg_size;
+ }
+}
+
static void dio48e_irq_ack(struct irq_data *data)
{
}
@@ -302,6 +338,26 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+#define DIO48E_NGPIO 48
+static const char *dio48e_names[DIO48E_NGPIO] = {
+ "PPI Group 0 Port A 0", "PPI Group 0 Port A 1", "PPI Group 0 Port A 2",
+ "PPI Group 0 Port A 3", "PPI Group 0 Port A 4", "PPI Group 0 Port A 5",
+ "PPI Group 0 Port A 6", "PPI Group 0 Port A 7", "PPI Group 0 Port B 0",
+ "PPI Group 0 Port B 1", "PPI Group 0 Port B 2", "PPI Group 0 Port B 3",
+ "PPI Group 0 Port B 4", "PPI Group 0 Port B 5", "PPI Group 0 Port B 6",
+ "PPI Group 0 Port B 7", "PPI Group 0 Port C 0", "PPI Group 0 Port C 1",
+ "PPI Group 0 Port C 2", "PPI Group 0 Port C 3", "PPI Group 0 Port C 4",
+ "PPI Group 0 Port C 5", "PPI Group 0 Port C 6", "PPI Group 0 Port C 7",
+ "PPI Group 1 Port A 0", "PPI Group 1 Port A 1", "PPI Group 1 Port A 2",
+ "PPI Group 1 Port A 3", "PPI Group 1 Port A 4", "PPI Group 1 Port A 5",
+ "PPI Group 1 Port A 6", "PPI Group 1 Port A 7", "PPI Group 1 Port B 0",
+ "PPI Group 1 Port B 1", "PPI Group 1 Port B 2", "PPI Group 1 Port B 3",
+ "PPI Group 1 Port B 4", "PPI Group 1 Port B 5", "PPI Group 1 Port B 6",
+ "PPI Group 1 Port B 7", "PPI Group 1 Port C 0", "PPI Group 1 Port C 1",
+ "PPI Group 1 Port C 2", "PPI Group 1 Port C 3", "PPI Group 1 Port C 4",
+ "PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7"
+};
+
static int dio48e_probe(struct device *dev, unsigned int id)
{
struct dio48e_gpio *dio48egpio;
@@ -322,20 +378,19 @@ static int dio48e_probe(struct device *dev, unsigned int id)
dio48egpio->chip.parent = dev;
dio48egpio->chip.owner = THIS_MODULE;
dio48egpio->chip.base = -1;
- dio48egpio->chip.ngpio = 48;
+ dio48egpio->chip.ngpio = DIO48E_NGPIO;
+ dio48egpio->chip.names = dio48e_names;
dio48egpio->chip.get_direction = dio48e_gpio_get_direction;
dio48egpio->chip.direction_input = dio48e_gpio_direction_input;
dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
dio48egpio->chip.get = dio48e_gpio_get;
dio48egpio->chip.set = dio48e_gpio_set;
+ dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
dio48egpio->base = base[id];
- dio48egpio->irq = irq[id];
spin_lock_init(&dio48egpio->lock);
- dev_set_drvdata(dev, dio48egpio);
-
- err = gpiochip_add_data(&dio48egpio->chip, dio48egpio);
+ err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
@@ -360,30 +415,17 @@ static int dio48e_probe(struct device *dev, unsigned int id)
handle_edge_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err);
- goto err_gpiochip_remove;
+ return err;
}
- err = request_irq(irq[id], dio48e_irq_handler, 0, name, dio48egpio);
+ err = devm_request_irq(dev, irq[id], dio48e_irq_handler, 0, name,
+ dio48egpio);
if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
- goto err_gpiochip_remove;
+ return err;
}
return 0;
-
-err_gpiochip_remove:
- gpiochip_remove(&dio48egpio->chip);
- return err;
-}
-
-static int dio48e_remove(struct device *dev, unsigned int id)
-{
- struct dio48e_gpio *const dio48egpio = dev_get_drvdata(dev);
-
- free_irq(dio48egpio->irq, dio48egpio);
- gpiochip_remove(&dio48egpio->chip);
-
- return 0;
}
static struct isa_driver dio48e_driver = {
@@ -391,7 +433,6 @@ static struct isa_driver dio48e_driver = {
.driver = {
.name = "104-dio-48e"
},
- .remove = dio48e_remove
};
module_isa_driver(dio48e_driver, num_dio48e);
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index 2d2763ea1a68..568375a7ebc2 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -47,7 +47,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
* @ack_lock: synchronization lock to prevent IRQ handler race conditions
* @irq_mask: input bits affected by interrupts
* @base: base port address of the GPIO device
- * @irq: Interrupt line number
* @cos_enb: Change-Of-State IRQ enable boundaries mask
*/
struct idi_48_gpio {
@@ -56,7 +55,6 @@ struct idi_48_gpio {
spinlock_t ack_lock;
unsigned char irq_mask[6];
unsigned base;
- unsigned irq;
unsigned char cos_enb;
};
@@ -219,6 +217,18 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+#define IDI48_NGPIO 48
+static const char *idi48_names[IDI48_NGPIO] = {
+ "Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
+ "Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
+ "Bit 12 A", "Bit 13 A", "Bit 14 A", "Bit 15 A", "Bit 16 A", "Bit 17 A",
+ "Bit 18 A", "Bit 19 A", "Bit 20 A", "Bit 21 A", "Bit 22 A", "Bit 23 A",
+ "Bit 0 B", "Bit 1 B", "Bit 2 B", "Bit 3 B", "Bit 4 B", "Bit 5 B",
+ "Bit 6 B", "Bit 7 B", "Bit 8 B", "Bit 9 B", "Bit 10 B", "Bit 11 B",
+ "Bit 12 B", "Bit 13 B", "Bit 14 B", "Bit 15 B", "Bit 16 B", "Bit 17 B",
+ "Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
+};
+
static int idi_48_probe(struct device *dev, unsigned int id)
{
struct idi_48_gpio *idi48gpio;
@@ -239,19 +249,17 @@ static int idi_48_probe(struct device *dev, unsigned int id)
idi48gpio->chip.parent = dev;
idi48gpio->chip.owner = THIS_MODULE;
idi48gpio->chip.base = -1;
- idi48gpio->chip.ngpio = 48;
+ idi48gpio->chip.ngpio = IDI48_NGPIO;
+ idi48gpio->chip.names = idi48_names;
idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
idi48gpio->chip.get = idi_48_gpio_get;
idi48gpio->base = base[id];
- idi48gpio->irq = irq[id];
spin_lock_init(&idi48gpio->lock);
spin_lock_init(&idi48gpio->ack_lock);
- dev_set_drvdata(dev, idi48gpio);
-
- err = gpiochip_add_data(&idi48gpio->chip, idi48gpio);
+ err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
@@ -265,31 +273,17 @@ static int idi_48_probe(struct device *dev, unsigned int id)
handle_edge_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err);
- goto err_gpiochip_remove;
+ return err;
}
- err = request_irq(irq[id], idi_48_irq_handler, IRQF_SHARED, name,
- idi48gpio);
+ err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
+ name, idi48gpio);
if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
- goto err_gpiochip_remove;
+ return err;
}
return 0;
-
-err_gpiochip_remove:
- gpiochip_remove(&idi48gpio->chip);
- return err;
-}
-
-static int idi_48_remove(struct device *dev, unsigned int id)
-{
- struct idi_48_gpio *const idi48gpio = dev_get_drvdata(dev);
-
- free_irq(idi48gpio->irq, idi48gpio);
- gpiochip_remove(&idi48gpio->chip);
-
- return 0;
}
static struct isa_driver idi_48_driver = {
@@ -297,7 +291,6 @@ static struct isa_driver idi_48_driver = {
.driver = {
.name = "104-idi-48"
},
- .remove = idi_48_remove
};
module_isa_driver(idi_48_driver, num_idi_48);
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 6787b8fcf0d8..7053cf736648 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -46,7 +46,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
* @lock: synchronization lock to prevent I/O race conditions
* @irq_mask: I/O bits affected by interrupts
* @base: base port address of the GPIO device
- * @irq: Interrupt line number
* @out_state: output bits state
*/
struct idio_16_gpio {
@@ -54,7 +53,6 @@ struct idio_16_gpio {
spinlock_t lock;
unsigned long irq_mask;
unsigned base;
- unsigned irq;
unsigned out_state;
};
@@ -116,6 +114,25 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
+static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
+{
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&idio16gpio->lock, flags);
+
+ idio16gpio->out_state &= ~*mask;
+ idio16gpio->out_state |= *mask & *bits;
+
+ if (*mask & 0xFF)
+ outb(idio16gpio->out_state, idio16gpio->base);
+ if ((*mask >> 8) & 0xFF)
+ outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
+
+ spin_unlock_irqrestore(&idio16gpio->lock, flags);
+}
+
static void idio_16_irq_ack(struct irq_data *data)
{
}
@@ -193,6 +210,14 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+#define IDIO_16_NGPIO 32
+static const char *idio_16_names[IDIO_16_NGPIO] = {
+ "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
+ "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
+ "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
+ "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
+};
+
static int idio_16_probe(struct device *dev, unsigned int id)
{
struct idio_16_gpio *idio16gpio;
@@ -213,21 +238,20 @@ static int idio_16_probe(struct device *dev, unsigned int id)
idio16gpio->chip.parent = dev;
idio16gpio->chip.owner = THIS_MODULE;
idio16gpio->chip.base = -1;
- idio16gpio->chip.ngpio = 32;
+ idio16gpio->chip.ngpio = IDIO_16_NGPIO;
+ idio16gpio->chip.names = idio_16_names;
idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
idio16gpio->chip.get = idio_16_gpio_get;
idio16gpio->chip.set = idio_16_gpio_set;
+ idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
idio16gpio->base = base[id];
- idio16gpio->irq = irq[id];
idio16gpio->out_state = 0xFFFF;
spin_lock_init(&idio16gpio->lock);
- dev_set_drvdata(dev, idio16gpio);
-
- err = gpiochip_add_data(&idio16gpio->chip, idio16gpio);
+ err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
@@ -241,30 +265,17 @@ static int idio_16_probe(struct device *dev, unsigned int id)
handle_edge_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err);
- goto err_gpiochip_remove;
+ return err;
}
- err = request_irq(irq[id], idio_16_irq_handler, 0, name, idio16gpio);
+ err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
+ idio16gpio);
if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
- goto err_gpiochip_remove;
+ return err;
}
return 0;
-
-err_gpiochip_remove:
- gpiochip_remove(&idio16gpio->chip);
- return err;
-}
-
-static int idio_16_remove(struct device *dev, unsigned int id)
-{
- struct idio_16_gpio *const idio16gpio = dev_get_drvdata(dev);
-
- free_irq(idio16gpio->irq, idio16gpio);
- gpiochip_remove(&idio16gpio->chip);
-
- return 0;
}
static struct isa_driver idio_16_driver = {
@@ -272,7 +283,6 @@ static struct isa_driver idio_16_driver = {
.driver = {
.name = "104-idio-16"
},
- .remove = idio_16_remove
};
module_isa_driver(idio_16_driver, num_idio_16);
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index 3d1cf018e8e7..41d0ac142580 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -308,6 +308,18 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
return 0;
}
+static int bcm_kona_gpio_set_config(struct gpio_chip *chip, unsigned gpio,
+ unsigned long config)
+{
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+ return bcm_kona_gpio_set_debounce(chip, gpio, debounce);
+}
+
static const struct gpio_chip template_chip = {
.label = "bcm-kona-gpio",
.owner = THIS_MODULE,
@@ -318,7 +330,7 @@ static const struct gpio_chip template_chip = {
.get = bcm_kona_gpio_get,
.direction_output = bcm_kona_gpio_direction_output,
.set = bcm_kona_gpio_set,
- .set_debounce = bcm_kona_gpio_set_debounce,
+ .set_config = bcm_kona_gpio_set_config,
.to_irq = bcm_kona_gpio_to_irq,
.base = 0,
};
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 9191056548fe..72f49d1e110d 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -43,25 +43,7 @@ typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
#define MAX_LABEL_SIZE 20
static void __iomem *gpio_base;
-
-static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio)
-{
- void __iomem *ptr;
-
- if (gpio < 32 * 1)
- ptr = gpio_base + 0x10;
- else if (gpio < 32 * 2)
- ptr = gpio_base + 0x38;
- else if (gpio < 32 * 3)
- ptr = gpio_base + 0x60;
- else if (gpio < 32 * 4)
- ptr = gpio_base + 0x88;
- else if (gpio < 32 * 5)
- ptr = gpio_base + 0xb0;
- else
- ptr = NULL;
- return ptr;
-}
+static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0};
static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d)
{
@@ -81,11 +63,13 @@ static inline int __davinci_direction(struct gpio_chip *chip,
unsigned offset, bool out, int value)
{
struct davinci_gpio_controller *d = gpiochip_get_data(chip);
- struct davinci_gpio_regs __iomem *g = d->regs;
+ struct davinci_gpio_regs __iomem *g;
unsigned long flags;
u32 temp;
- u32 mask = 1 << offset;
+ int bank = offset / 32;
+ u32 mask = __gpio_mask(offset);
+ g = d->regs[bank];
spin_lock_irqsave(&d->lock, flags);
temp = readl_relaxed(&g->dir);
if (out) {
@@ -121,9 +105,12 @@ davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct davinci_gpio_controller *d = gpiochip_get_data(chip);
- struct davinci_gpio_regs __iomem *g = d->regs;
+ struct davinci_gpio_regs __iomem *g;
+ int bank = offset / 32;
- return !!((1 << offset) & readl_relaxed(&g->in_data));
+ g = d->regs[bank];
+
+ return !!(__gpio_mask(offset) & readl_relaxed(&g->in_data));
}
/*
@@ -133,9 +120,13 @@ static void
davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct davinci_gpio_controller *d = gpiochip_get_data(chip);
- struct davinci_gpio_regs __iomem *g = d->regs;
+ struct davinci_gpio_regs __iomem *g;
+ int bank = offset / 32;
- writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data);
+ g = d->regs[bank];
+
+ writel_relaxed(__gpio_mask(offset),
+ value ? &g->set_data : &g->clr_data);
}
static struct davinci_gpio_platform_data *
@@ -172,34 +163,13 @@ of_err:
return NULL;
}
-#ifdef CONFIG_OF_GPIO
-static int davinci_gpio_of_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec,
- u32 *flags)
-{
- struct davinci_gpio_controller *chips = dev_get_drvdata(gc->parent);
- struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->parent);
-
- if (gpiospec->args[0] > pdata->ngpio)
- return -EINVAL;
-
- if (gc != &chips[gpiospec->args[0] / 32].chip)
- return -EINVAL;
-
- if (flags)
- *flags = gpiospec->args[1];
-
- return gpiospec->args[0] % 32;
-}
-#endif
-
static int davinci_gpio_probe(struct platform_device *pdev)
{
- int i, base;
+ static int ctrl_num, bank_base;
+ int gpio, bank;
unsigned ngpio, nbank;
struct davinci_gpio_controller *chips;
struct davinci_gpio_platform_data *pdata;
- struct davinci_gpio_regs __iomem *regs;
struct device *dev = &pdev->dev;
struct resource *res;
char label[MAX_LABEL_SIZE];
@@ -238,41 +208,31 @@ static int davinci_gpio_probe(struct platform_device *pdev)
if (IS_ERR(gpio_base))
return PTR_ERR(gpio_base);
- for (i = 0, base = 0; base < ngpio; i++, base += 32) {
- snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", i);
- chips[i].chip.label = devm_kstrdup(dev, label, GFP_KERNEL);
- if (!chips[i].chip.label)
+ snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++);
+ chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL);
+ if (!chips->chip.label)
return -ENOMEM;
- chips[i].chip.direction_input = davinci_direction_in;
- chips[i].chip.get = davinci_gpio_get;
- chips[i].chip.direction_output = davinci_direction_out;
- chips[i].chip.set = davinci_gpio_set;
+ chips->chip.direction_input = davinci_direction_in;
+ chips->chip.get = davinci_gpio_get;
+ chips->chip.direction_output = davinci_direction_out;
+ chips->chip.set = davinci_gpio_set;
- chips[i].chip.base = base;
- chips[i].chip.ngpio = ngpio - base;
- if (chips[i].chip.ngpio > 32)
- chips[i].chip.ngpio = 32;
+ chips->chip.ngpio = ngpio;
+ chips->chip.base = bank_base;
#ifdef CONFIG_OF_GPIO
- chips[i].chip.of_gpio_n_cells = 2;
- chips[i].chip.of_xlate = davinci_gpio_of_xlate;
- chips[i].chip.parent = dev;
- chips[i].chip.of_node = dev->of_node;
+ chips->chip.of_gpio_n_cells = 2;
+ chips->chip.parent = dev;
+ chips->chip.of_node = dev->of_node;
#endif
- spin_lock_init(&chips[i].lock);
-
- regs = gpio2regs(base);
- if (!regs)
- return -ENXIO;
- chips[i].regs = regs;
- chips[i].set_data = &regs->set_data;
- chips[i].clr_data = &regs->clr_data;
- chips[i].in_data = &regs->in_data;
+ spin_lock_init(&chips->lock);
+ bank_base += ngpio;
- gpiochip_add_data(&chips[i].chip, &chips[i]);
- }
+ for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++)
+ chips->regs[bank] = gpio_base + offset_array[bank];
+ gpiochip_add_data(&chips->chip, chips);
platform_set_drvdata(pdev, chips);
davinci_gpio_irq_setup(pdev);
return 0;
@@ -333,16 +293,19 @@ static struct irq_chip gpio_irqchip = {
static void gpio_irq_handler(struct irq_desc *desc)
{
- unsigned int irq = irq_desc_get_irq(desc);
struct davinci_gpio_regs __iomem *g;
u32 mask = 0xffff;
+ int bank_num;
struct davinci_gpio_controller *d;
+ struct davinci_gpio_irq_data *irqdata;
- d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc);
- g = (struct davinci_gpio_regs __iomem *)d->regs;
+ irqdata = (struct davinci_gpio_irq_data *)irq_desc_get_handler_data(desc);
+ bank_num = irqdata->bank_num;
+ g = irqdata->regs;
+ d = irqdata->chip;
/* we only care about one bank */
- if (irq & 1)
+ if ((bank_num % 2) == 1)
mask <<= 16;
/* temporarily mask (level sensitive) parent IRQ */
@@ -350,6 +313,7 @@ static void gpio_irq_handler(struct irq_desc *desc)
while (1) {
u32 status;
int bit;
+ irq_hw_number_t hw_irq;
/* ack any irqs */
status = readl_relaxed(&g->intstat) & mask;
@@ -362,9 +326,13 @@ static void gpio_irq_handler(struct irq_desc *desc)
while (status) {
bit = __ffs(status);
status &= ~BIT(bit);
+ /* Max number of gpios per controller is 144 so
+ * hw_irq will be in [0..143]
+ */
+ hw_irq = (bank_num / 2) * 32 + bit;
+
generic_handle_irq(
- irq_find_mapping(d->irq_domain,
- d->chip.base + bit));
+ irq_find_mapping(d->irq_domain, hw_irq));
}
}
chained_irq_exit(irq_desc_get_chip(desc), desc);
@@ -376,7 +344,7 @@ static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
struct davinci_gpio_controller *d = gpiochip_get_data(chip);
if (d->irq_domain)
- return irq_create_mapping(d->irq_domain, d->chip.base + offset);
+ return irq_create_mapping(d->irq_domain, offset);
else
return -ENXIO;
}
@@ -390,7 +358,7 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
* can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
*/
if (offset < d->gpio_unbanked)
- return d->gpio_irq + offset;
+ return d->base_irq + offset;
else
return -ENODEV;
}
@@ -403,7 +371,7 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data);
g = (struct davinci_gpio_regs __iomem *)d->regs;
- mask = __gpio_mask(data->irq - d->gpio_irq);
+ mask = __gpio_mask(data->irq - d->base_irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
@@ -420,7 +388,9 @@ static int
davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
- struct davinci_gpio_regs __iomem *g = gpio2regs(hw);
+ struct davinci_gpio_controller *chips =
+ (struct davinci_gpio_controller *)d->host_data;
+ struct davinci_gpio_regs __iomem *g = chips->regs[hw / 32];
irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq,
"davinci_gpio");
@@ -478,6 +448,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
struct irq_domain *irq_domain = NULL;
const struct of_device_id *match;
struct irq_chip *irq_chip;
+ struct davinci_gpio_irq_data *irqdata;
gpio_get_irq_chip_cb_t gpio_get_irq_chip;
/*
@@ -533,10 +504,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
* IRQs, while the others use banked IRQs, would need some setup
* tweaks to recognize hardware which can do that.
*/
- for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) {
- chips[bank].chip.to_irq = gpio_to_irq_banked;
- chips[bank].irq_domain = irq_domain;
- }
+ chips->chip.to_irq = gpio_to_irq_banked;
+ chips->irq_domain = irq_domain;
/*
* AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO
@@ -545,9 +514,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
*/
if (pdata->gpio_unbanked) {
/* pass "bank 0" GPIO IRQs to AINTC */
- chips[0].chip.to_irq = gpio_to_irq_unbanked;
- chips[0].gpio_irq = bank_irq;
- chips[0].gpio_unbanked = pdata->gpio_unbanked;
+ chips->chip.to_irq = gpio_to_irq_unbanked;
+ chips->base_irq = bank_irq;
+ chips->gpio_unbanked = pdata->gpio_unbanked;
binten = GENMASK(pdata->gpio_unbanked / 16, 0);
/* AINTC handles mask/unmask; GPIO handles triggering */
@@ -557,14 +526,14 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
irq_chip->irq_set_type = gpio_irq_type_unbanked;
/* default trigger: both edges */
- g = gpio2regs(0);
+ g = chips->regs[0];
writel_relaxed(~0, &g->set_falling);
writel_relaxed(~0, &g->set_rising);
/* set the direct IRQs up to use that irqchip */
for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) {
irq_set_chip(irq, irq_chip);
- irq_set_handler_data(irq, &chips[gpio / 32]);
+ irq_set_handler_data(irq, chips);
irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
}
@@ -576,8 +545,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
* then chain through our own handler.
*/
for (gpio = 0, bank = 0; gpio < ngpio; bank++, bank_irq++, gpio += 16) {
- /* disabled by default, enabled only as needed */
- g = gpio2regs(gpio);
+ /* disabled by default, enabled only as needed
+ * There are register sets for 32 GPIOs. 2 banks of 16
+ * GPIOs are covered by each set of registers hence divide by 2
+ */
+ g = chips->regs[bank / 2];
writel_relaxed(~0, &g->clr_falling);
writel_relaxed(~0, &g->clr_rising);
@@ -586,8 +558,19 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
* gpio irqs. Pass the irq bank's corresponding controller to
* the chained irq handler.
*/
+ irqdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct
+ davinci_gpio_irq_data),
+ GFP_KERNEL);
+ if (!irqdata)
+ return -ENOMEM;
+
+ irqdata->regs = g;
+ irqdata->bank_num = bank;
+ irqdata->chip = chips;
+
irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler,
- &chips[gpio / 32]);
+ irqdata);
binten |= BIT(bank);
}
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
index 5d38b08d1ee2..aecb847166f5 100644
--- a/drivers/gpio/gpio-dln2.c
+++ b/drivers/gpio/gpio-dln2.c
@@ -272,12 +272,16 @@ static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
return dln2_gpio_set_direction(chip, offset, DLN2_GPIO_DIRECTION_OUT);
}
-static int dln2_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
- unsigned debounce)
+static int dln2_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config)
{
struct dln2_gpio *dln2 = gpiochip_get_data(chip);
- __le32 duration = cpu_to_le32(debounce);
+ __le32 duration;
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ duration = cpu_to_le32(pinconf_to_config_argument(config));
return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_SET_DEBOUNCE,
&duration, sizeof(duration));
}
@@ -474,7 +478,7 @@ static int dln2_gpio_probe(struct platform_device *pdev)
dln2->gpio.get_direction = dln2_gpio_get_direction;
dln2->gpio.direction_input = dln2_gpio_direction_input;
dln2->gpio.direction_output = dln2_gpio_direction_output;
- dln2->gpio.set_debounce = dln2_gpio_set_debounce;
+ dln2->gpio.set_config = dln2_gpio_set_config;
platform_set_drvdata(pdev, dln2);
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 6193f62c0df4..9c15ee4ef4e9 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -279,6 +279,18 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
return 0;
}
+static int dwapb_gpio_set_config(struct gpio_chip *gc, unsigned offset,
+ unsigned long config)
+{
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+ return dwapb_gpio_set_debounce(gc, offset, debounce);
+}
+
static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id)
{
u32 worked;
@@ -426,7 +438,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
/* Only port A support debounce */
if (pp->idx == 0)
- port->gc.set_debounce = dwapb_gpio_set_debounce;
+ port->gc.set_config = dwapb_gpio_set_config;
if (pp->irq)
dwapb_configure_irqs(gpio, port, pp);
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index d054219e18b9..45d384039e9b 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -291,15 +291,20 @@ static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false),
};
-static int ep93xx_gpio_set_debounce(struct gpio_chip *chip,
- unsigned offset, unsigned debounce)
+static int ep93xx_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config)
{
int gpio = chip->base + offset;
int irq = gpio_to_irq(gpio);
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
if (irq < 0)
return -EINVAL;
+ debounce = pinconf_to_config_argument(config);
ep93xx_gpio_int_debounce(irq, debounce ? true : false);
return 0;
@@ -335,7 +340,7 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
gc->base = bank->base;
if (bank->has_debounce) {
- gc->set_debounce = ep93xx_gpio_set_debounce;
+ gc->set_config = ep93xx_gpio_set_config;
gc->to_irq = ep93xx_gpio_to_irq;
}
diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
new file mode 100644
index 000000000000..05c8946d6446
--- /dev/null
+++ b/drivers/gpio/gpio-exar.c
@@ -0,0 +1,200 @@
+/*
+ * GPIO driver for Exar XR17V35X chip
+ *
+ * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
+ *
+ * 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/bitops.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#define EXAR_OFFSET_MPIOLVL_LO 0x90
+#define EXAR_OFFSET_MPIOSEL_LO 0x93
+#define EXAR_OFFSET_MPIOLVL_HI 0x96
+#define EXAR_OFFSET_MPIOSEL_HI 0x99
+
+#define DRIVER_NAME "gpio_exar"
+
+static DEFINE_IDA(ida_index);
+
+struct exar_gpio_chip {
+ struct gpio_chip gpio_chip;
+ struct mutex lock;
+ int index;
+ void __iomem *regs;
+ char name[20];
+};
+
+static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
+ unsigned int offset)
+{
+ struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+ int temp;
+
+ mutex_lock(&exar_gpio->lock);
+ temp = readb(exar_gpio->regs + reg);
+ temp &= ~BIT(offset);
+ if (val)
+ temp |= BIT(offset);
+ writeb(temp, exar_gpio->regs + reg);
+ mutex_unlock(&exar_gpio->lock);
+}
+
+static int exar_set_direction(struct gpio_chip *chip, int direction,
+ unsigned int offset)
+{
+ unsigned int bank = offset / 8;
+ unsigned int addr;
+
+ addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
+ exar_update(chip, addr, direction, offset % 8);
+ return 0;
+}
+
+static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ return exar_set_direction(chip, 0, offset);
+}
+
+static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ return exar_set_direction(chip, 1, offset);
+}
+
+static int exar_get(struct gpio_chip *chip, unsigned int reg)
+{
+ struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+ int value;
+
+ mutex_lock(&exar_gpio->lock);
+ value = readb(exar_gpio->regs + reg);
+ mutex_unlock(&exar_gpio->lock);
+
+ return !!value;
+}
+
+static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ unsigned int bank = offset / 8;
+ unsigned int addr;
+ int val;
+
+ addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
+ val = exar_get(chip, addr) >> (offset % 8);
+
+ return !!val;
+}
+
+static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
+{
+ unsigned int bank = offset / 8;
+ unsigned int addr;
+ int val;
+
+ addr = bank ? EXAR_OFFSET_MPIOLVL_LO : EXAR_OFFSET_MPIOLVL_HI;
+ val = exar_get(chip, addr) >> (offset % 8);
+
+ return !!val;
+}
+
+static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ unsigned int bank = offset / 8;
+ unsigned int addr;
+
+ addr = bank ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
+ exar_update(chip, addr, value, offset % 8);
+}
+
+static int gpio_exar_probe(struct platform_device *pdev)
+{
+ struct pci_dev *pcidev = platform_get_drvdata(pdev);
+ struct exar_gpio_chip *exar_gpio;
+ void __iomem *p;
+ int index, ret;
+
+ if (pcidev->vendor != PCI_VENDOR_ID_EXAR)
+ return -ENODEV;
+
+ /*
+ * Map the pci device to get the register addresses.
+ * We will need to read and write those registers to control
+ * the GPIO pins.
+ * Using managed functions will save us from unmaping on exit.
+ * As the device is enabled using managed functions by the
+ * UART driver we can also use managed functions here.
+ */
+ p = pcim_iomap(pcidev, 0, 0);
+ if (!p)
+ return -ENOMEM;
+
+ exar_gpio = devm_kzalloc(&pcidev->dev, sizeof(*exar_gpio), GFP_KERNEL);
+ if (!exar_gpio)
+ return -ENOMEM;
+
+ mutex_init(&exar_gpio->lock);
+
+ index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
+
+ sprintf(exar_gpio->name, "exar_gpio%d", index);
+ exar_gpio->gpio_chip.label = exar_gpio->name;
+ exar_gpio->gpio_chip.parent = &pcidev->dev;
+ exar_gpio->gpio_chip.direction_output = exar_direction_output;
+ exar_gpio->gpio_chip.direction_input = exar_direction_input;
+ exar_gpio->gpio_chip.get_direction = exar_get_direction;
+ exar_gpio->gpio_chip.get = exar_get_value;
+ exar_gpio->gpio_chip.set = exar_set_value;
+ exar_gpio->gpio_chip.base = -1;
+ exar_gpio->gpio_chip.ngpio = 16;
+ exar_gpio->regs = p;
+ exar_gpio->index = index;
+
+ ret = devm_gpiochip_add_data(&pcidev->dev,
+ &exar_gpio->gpio_chip, exar_gpio);
+ if (ret)
+ goto err_destroy;
+
+ platform_set_drvdata(pdev, exar_gpio);
+
+ return 0;
+
+err_destroy:
+ ida_simple_remove(&ida_index, index);
+ mutex_destroy(&exar_gpio->lock);
+ return ret;
+}
+
+static int gpio_exar_remove(struct platform_device *pdev)
+{
+ struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
+
+ ida_simple_remove(&ida_index, exar_gpio->index);
+ mutex_destroy(&exar_gpio->lock);
+
+ return 0;
+}
+
+static struct platform_driver gpio_exar_driver = {
+ .probe = gpio_exar_probe,
+ .remove = gpio_exar_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+module_platform_driver(gpio_exar_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("Exar GPIO driver");
+MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index e8accde62aa7..56bd76c33767 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -131,9 +131,8 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);
static int f7188x_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value);
static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
-static int f7188x_gpio_set_single_ended(struct gpio_chip *gc,
- unsigned offset,
- enum single_ended_mode mode);
+static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config);
#define F7188X_GPIO_BANK(_base, _ngpio, _regbase) \
{ \
@@ -145,7 +144,7 @@ static int f7188x_gpio_set_single_ended(struct gpio_chip *gc,
.get = f7188x_gpio_get, \
.direction_output = f7188x_gpio_direction_out, \
.set = f7188x_gpio_set, \
- .set_single_ended = f7188x_gpio_set_single_ended, \
+ .set_config = f7188x_gpio_set_config, \
.base = _base, \
.ngpio = _ngpio, \
.can_sleep = true, \
@@ -326,17 +325,17 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
superio_exit(sio->addr);
}
-static int f7188x_gpio_set_single_ended(struct gpio_chip *chip,
- unsigned offset,
- enum single_ended_mode mode)
+static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config)
{
int err;
+ enum pin_config_param param = pinconf_to_config_param(config);
struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
struct f7188x_sio *sio = bank->data->sio;
u8 data;
- if (mode != LINE_MODE_OPEN_DRAIN &&
- mode != LINE_MODE_PUSH_PULL)
+ if (param != PIN_CONFIG_DRIVE_OPEN_DRAIN &&
+ param != PIN_CONFIG_DRIVE_PUSH_PULL)
return -ENOTSUPP;
err = superio_enter(sio->addr);
@@ -345,7 +344,7 @@ static int f7188x_gpio_set_single_ended(struct gpio_chip *chip,
superio_select(sio->addr, SIO_LD_GPIO);
data = superio_inb(sio->addr, gpio_out_mode(bank->regbase));
- if (mode == LINE_MODE_OPEN_DRAIN)
+ if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
data &= ~BIT(offset);
else
data |= BIT(offset);
diff --git a/drivers/gpio/gpio-gemini.c b/drivers/gpio/gpio-gemini.c
new file mode 100644
index 000000000000..962485163b7f
--- /dev/null
+++ b/drivers/gpio/gpio-gemini.c
@@ -0,0 +1,236 @@
+/*
+ * Gemini gpiochip and interrupt routines
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Based on arch/arm/mach-gemini/gpio.c:
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on plat-mxc/gpio.c:
+ * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ */
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+#include <linux/bitops.h>
+
+/* GPIO registers definition */
+#define GPIO_DATA_OUT 0x00
+#define GPIO_DATA_IN 0x04
+#define GPIO_DIR 0x08
+#define GPIO_DATA_SET 0x10
+#define GPIO_DATA_CLR 0x14
+#define GPIO_PULL_EN 0x18
+#define GPIO_PULL_TYPE 0x1C
+#define GPIO_INT_EN 0x20
+#define GPIO_INT_STAT 0x24
+#define GPIO_INT_MASK 0x2C
+#define GPIO_INT_CLR 0x30
+#define GPIO_INT_TYPE 0x34
+#define GPIO_INT_BOTH_EDGE 0x38
+#define GPIO_INT_LEVEL 0x3C
+#define GPIO_DEBOUNCE_EN 0x40
+#define GPIO_DEBOUNCE_PRESCALE 0x44
+
+/**
+ * struct gemini_gpio - Gemini GPIO state container
+ * @dev: containing device for this instance
+ * @gc: gpiochip for this instance
+ */
+struct gemini_gpio {
+ struct device *dev;
+ struct gpio_chip gc;
+ void __iomem *base;
+};
+
+static void gemini_gpio_ack_irq(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gemini_gpio *g = gpiochip_get_data(gc);
+
+ writel(BIT(irqd_to_hwirq(d)), g->base + GPIO_INT_CLR);
+}
+
+static void gemini_gpio_mask_irq(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gemini_gpio *g = gpiochip_get_data(gc);
+ u32 val;
+
+ val = readl(g->base + GPIO_INT_EN);
+ val &= ~BIT(irqd_to_hwirq(d));
+ writel(val, g->base + GPIO_INT_EN);
+}
+
+static void gemini_gpio_unmask_irq(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gemini_gpio *g = gpiochip_get_data(gc);
+ u32 val;
+
+ val = readl(g->base + GPIO_INT_EN);
+ val |= BIT(irqd_to_hwirq(d));
+ writel(val, g->base + GPIO_INT_EN);
+}
+
+static int gemini_gpio_set_irq_type(struct irq_data *d, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gemini_gpio *g = gpiochip_get_data(gc);
+ u32 mask = BIT(irqd_to_hwirq(d));
+ u32 reg_both, reg_level, reg_type;
+
+ reg_type = readl(g->base + GPIO_INT_TYPE);
+ reg_level = readl(g->base + GPIO_INT_LEVEL);
+ reg_both = readl(g->base + GPIO_INT_BOTH_EDGE);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ irq_set_handler_locked(d, handle_edge_irq);
+ reg_type &= ~mask;
+ reg_both |= mask;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ irq_set_handler_locked(d, handle_edge_irq);
+ reg_type &= ~mask;
+ reg_both &= ~mask;
+ reg_level &= ~mask;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ irq_set_handler_locked(d, handle_edge_irq);
+ reg_type &= ~mask;
+ reg_both &= ~mask;
+ reg_level |= mask;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ irq_set_handler_locked(d, handle_level_irq);
+ reg_type |= mask;
+ reg_level &= ~mask;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ irq_set_handler_locked(d, handle_level_irq);
+ reg_type |= mask;
+ reg_level |= mask;
+ break;
+ default:
+ irq_set_handler_locked(d, handle_bad_irq);
+ return -EINVAL;
+ }
+
+ writel(reg_type, g->base + GPIO_INT_TYPE);
+ writel(reg_level, g->base + GPIO_INT_LEVEL);
+ writel(reg_both, g->base + GPIO_INT_BOTH_EDGE);
+
+ gemini_gpio_ack_irq(d);
+
+ return 0;
+}
+
+static struct irq_chip gemini_gpio_irqchip = {
+ .name = "GPIO",
+ .irq_ack = gemini_gpio_ack_irq,
+ .irq_mask = gemini_gpio_mask_irq,
+ .irq_unmask = gemini_gpio_unmask_irq,
+ .irq_set_type = gemini_gpio_set_irq_type,
+};
+
+static void gemini_gpio_irq_handler(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct gemini_gpio *g = gpiochip_get_data(gc);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ int offset;
+ unsigned long stat;
+
+ chained_irq_enter(irqchip, desc);
+
+ stat = readl(g->base + GPIO_INT_STAT);
+ if (stat)
+ for_each_set_bit(offset, &stat, gc->ngpio)
+ generic_handle_irq(irq_find_mapping(gc->irqdomain,
+ offset));
+
+ chained_irq_exit(irqchip, desc);
+}
+
+static int gemini_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct gemini_gpio *g;
+ int irq;
+ int ret;
+
+ g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
+ if (!g)
+ return -ENOMEM;
+
+ g->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ g->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(g->base))
+ return PTR_ERR(g->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (!irq)
+ return -EINVAL;
+
+ ret = bgpio_init(&g->gc, dev, 4,
+ g->base + GPIO_DATA_IN,
+ g->base + GPIO_DATA_SET,
+ g->base + GPIO_DATA_CLR,
+ g->base + GPIO_DIR,
+ NULL,
+ 0);
+ if (ret) {
+ dev_err(dev, "unable to init generic GPIO\n");
+ return ret;
+ }
+ g->gc.label = "Gemini";
+ g->gc.base = -1;
+ g->gc.parent = dev;
+ g->gc.owner = THIS_MODULE;
+ /* ngpio is set by bgpio_init() */
+
+ ret = devm_gpiochip_add_data(dev, &g->gc, g);
+ if (ret)
+ return ret;
+
+ /* Disable, unmask and clear all interrupts */
+ writel(0x0, g->base + GPIO_INT_EN);
+ writel(0x0, g->base + GPIO_INT_MASK);
+ writel(~0x0, g->base + GPIO_INT_CLR);
+
+ ret = gpiochip_irqchip_add(&g->gc, &gemini_gpio_irqchip,
+ 0, handle_bad_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_info(dev, "could not add irqchip\n");
+ return ret;
+ }
+ gpiochip_set_chained_irqchip(&g->gc, &gemini_gpio_irqchip,
+ irq, gemini_gpio_irq_handler);
+
+ dev_info(dev, "Gemini GPIO @%p registered\n", g->base);
+
+ return 0;
+}
+
+static const struct of_device_id gemini_gpio_of_match[] = {
+ {
+ .compatible = "cortina,gemini-gpio",
+ },
+ {},
+};
+
+static struct platform_driver gemini_gpio_driver = {
+ .driver = {
+ .name = "gemini-gpio",
+ .of_match_table = of_match_ptr(gemini_gpio_of_match),
+ },
+ .probe = gemini_gpio_probe,
+};
+builtin_platform_driver(gemini_gpio_driver);
diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c
index 1e7def9449ce..fa4baa2543db 100644
--- a/drivers/gpio/gpio-gpio-mm.c
+++ b/drivers/gpio/gpio-gpio-mm.c
@@ -192,6 +192,56 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
spin_unlock_irqrestore(&gpiommgpio->lock, flags);
}
+static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
+{
+ struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+ unsigned int i;
+ const unsigned int gpio_reg_size = 8;
+ unsigned int port;
+ unsigned int out_port;
+ unsigned int bitmask;
+ unsigned long flags;
+
+ /* set bits are evaluated a gpio register size at a time */
+ for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
+ /* no more set bits in this mask word; skip to the next word */
+ if (!mask[BIT_WORD(i)]) {
+ i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
+ continue;
+ }
+
+ port = i / gpio_reg_size;
+ out_port = (port > 2) ? port + 1 : port;
+ bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
+
+ spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+ /* update output state data and set device gpio register */
+ gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)];
+ gpiommgpio->out_state[port] |= bitmask;
+ outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
+
+ spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+
+ /* prepare for next gpio register set */
+ mask[BIT_WORD(i)] >>= gpio_reg_size;
+ bits[BIT_WORD(i)] >>= gpio_reg_size;
+ }
+}
+
+#define GPIOMM_NGPIO 48
+static const char *gpiomm_names[GPIOMM_NGPIO] = {
+ "Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5",
+ "Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3",
+ "Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1",
+ "Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7",
+ "Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5",
+ "Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3",
+ "Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1",
+ "Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
+};
+
static int gpiomm_probe(struct device *dev, unsigned int id)
{
struct gpiomm_gpio *gpiommgpio;
@@ -212,19 +262,19 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
gpiommgpio->chip.parent = dev;
gpiommgpio->chip.owner = THIS_MODULE;
gpiommgpio->chip.base = -1;
- gpiommgpio->chip.ngpio = 48;
+ gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
+ gpiommgpio->chip.names = gpiomm_names;
gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
gpiommgpio->chip.get = gpiomm_gpio_get;
gpiommgpio->chip.set = gpiomm_gpio_set;
+ gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
gpiommgpio->base = base[id];
spin_lock_init(&gpiommgpio->lock);
- dev_set_drvdata(dev, gpiommgpio);
-
- err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio);
+ err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
@@ -243,21 +293,11 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
return 0;
}
-static int gpiomm_remove(struct device *dev, unsigned int id)
-{
- struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev);
-
- gpiochip_remove(&gpiommgpio->chip);
-
- return 0;
-}
-
static struct isa_driver gpiomm_driver = {
.probe = gpiomm_probe,
.driver = {
.name = "gpio-mm"
},
- .remove = gpiomm_remove
};
module_isa_driver(gpiomm_driver, num_gpiomm);
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index a1e44c221f66..b76ecee82c3f 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -321,7 +321,7 @@ static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv)
}
}
-static int intel_gpio_runtime_idle(struct device *dev)
+static int __maybe_unused intel_gpio_runtime_idle(struct device *dev)
{
int err = pm_schedule_suspend(dev, 500);
return err ?: -EBUSY;
diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c
index 218c706359aa..df0ad2cef0d2 100644
--- a/drivers/gpio/gpio-lp873x.c
+++ b/drivers/gpio/gpio-lp873x.c
@@ -100,21 +100,21 @@ static int lp873x_gpio_request(struct gpio_chip *gc, unsigned int offset)
return 0;
}
-static int lp873x_gpio_set_single_ended(struct gpio_chip *gc,
- unsigned int offset,
- enum single_ended_mode mode)
+static int lp873x_gpio_set_config(struct gpio_chip *gc, unsigned offset,
+ unsigned long config)
{
struct lp873x_gpio *gpio = gpiochip_get_data(gc);
- switch (mode) {
- case LINE_MODE_OPEN_DRAIN:
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
return regmap_update_bits(gpio->lp873->regmap,
LP873X_REG_GPO_CTRL,
BIT(offset * BITS_PER_GPO +
LP873X_GPO_CTRL_OD),
BIT(offset * BITS_PER_GPO +
LP873X_GPO_CTRL_OD));
- case LINE_MODE_PUSH_PULL:
+
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
return regmap_update_bits(gpio->lp873->regmap,
LP873X_REG_GPO_CTRL,
BIT(offset * BITS_PER_GPO +
@@ -133,7 +133,7 @@ static const struct gpio_chip template_chip = {
.direction_output = lp873x_gpio_direction_output,
.get = lp873x_gpio_get,
.set = lp873x_gpio_set,
- .set_single_ended = lp873x_gpio_set_single_ended,
+ .set_config = lp873x_gpio_set_config,
.base = -1,
.ngpio = 2,
.can_sleep = true,
diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c
index ec8de4190db9..743459d9477d 100644
--- a/drivers/gpio/gpio-max77620.c
+++ b/drivers/gpio/gpio-max77620.c
@@ -152,11 +152,10 @@ static int max77620_gpio_dir_output(struct gpio_chip *gc, unsigned int offset,
return ret;
}
-static int max77620_gpio_set_debounce(struct gpio_chip *gc,
+static int max77620_gpio_set_debounce(struct max77620_gpio *mgpio,
unsigned int offset,
unsigned int debounce)
{
- struct max77620_gpio *mgpio = gpiochip_get_data(gc);
u8 val;
int ret;
@@ -202,21 +201,23 @@ static void max77620_gpio_set(struct gpio_chip *gc, unsigned int offset,
dev_err(mgpio->dev, "CNFG_GPIO_OUT update failed: %d\n", ret);
}
-static int max77620_gpio_set_single_ended(struct gpio_chip *gc,
- unsigned int offset,
- enum single_ended_mode mode)
+static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
+ unsigned long config)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
- switch (mode) {
- case LINE_MODE_OPEN_DRAIN:
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_DRV_MASK,
MAX77620_CNFG_GPIO_DRV_OPENDRAIN);
- case LINE_MODE_PUSH_PULL:
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
MAX77620_CNFG_GPIO_DRV_MASK,
MAX77620_CNFG_GPIO_DRV_PUSHPULL);
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ return max77620_gpio_set_debounce(mgpio, offset,
+ pinconf_to_config_argument(config));
default:
break;
}
@@ -257,9 +258,8 @@ static int max77620_gpio_probe(struct platform_device *pdev)
mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
mgpio->gpio_chip.get = max77620_gpio_get;
mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
- mgpio->gpio_chip.set_debounce = max77620_gpio_set_debounce;
mgpio->gpio_chip.set = max77620_gpio_set;
- mgpio->gpio_chip.set_single_ended = max77620_gpio_set_single_ended;
+ mgpio->gpio_chip.set_config = max77620_gpio_set_config;
mgpio->gpio_chip.to_irq = max77620_gpio_to_irq;
mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
mgpio->gpio_chip.can_sleep = 1;
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 504550665091..bdb692345428 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_device.h>
+#include <linux/regmap.h>
/**
* MCP types supported by driver
@@ -58,16 +59,10 @@
struct mcp23s08;
-struct mcp23s08_ops {
- int (*read)(struct mcp23s08 *mcp, unsigned reg);
- int (*write)(struct mcp23s08 *mcp, unsigned reg, unsigned val);
- int (*read_regs)(struct mcp23s08 *mcp, unsigned reg,
- u16 *vals, unsigned n);
-};
-
struct mcp23s08 {
u8 addr;
bool irq_active_high;
+ bool reg_shift;
u16 cache[11];
u16 irq_rise;
@@ -80,188 +75,126 @@ struct mcp23s08 {
struct gpio_chip chip;
- const struct mcp23s08_ops *ops;
- void *data; /* ops specific data */
+ struct regmap *regmap;
+ struct device *dev;
};
-/* A given spi_device can represent up to eight mcp23sxx chips
- * sharing the same chipselect but using different addresses
- * (e.g. chips #0 and #3 might be populated, but not #1 or $2).
- * Driver data holds all the per-chip data.
- */
-struct mcp23s08_driver_data {
- unsigned ngpio;
- struct mcp23s08 *mcp[8];
- struct mcp23s08 chip[];
-};
+static const struct regmap_config mcp23x08_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
-/*----------------------------------------------------------------------*/
-
-#if IS_ENABLED(CONFIG_I2C)
-
-static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg)
-{
- return i2c_smbus_read_byte_data(mcp->data, reg);
-}
-
-static int mcp23008_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
-{
- return i2c_smbus_write_byte_data(mcp->data, reg, val);
-}
-
-static int
-mcp23008_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
-{
- while (n--) {
- int ret = mcp23008_read(mcp, reg++);
- if (ret < 0)
- return ret;
- *vals++ = ret;
- }
-
- return 0;
-}
-
-static int mcp23017_read(struct mcp23s08 *mcp, unsigned reg)
-{
- return i2c_smbus_read_word_data(mcp->data, reg << 1);
-}
-
-static int mcp23017_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
-{
- return i2c_smbus_write_word_data(mcp->data, reg << 1, val);
-}
-
-static int
-mcp23017_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
-{
- while (n--) {
- int ret = mcp23017_read(mcp, reg++);
- if (ret < 0)
- return ret;
- *vals++ = ret;
- }
-
- return 0;
-}
-
-static const struct mcp23s08_ops mcp23008_ops = {
- .read = mcp23008_read,
- .write = mcp23008_write,
- .read_regs = mcp23008_read_regs,
+ .reg_stride = 1,
+ .max_register = MCP_OLAT,
};
-static const struct mcp23s08_ops mcp23017_ops = {
- .read = mcp23017_read,
- .write = mcp23017_write,
- .read_regs = mcp23017_read_regs,
-};
+static const struct regmap_config mcp23x17_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
-#endif /* CONFIG_I2C */
+ .reg_stride = 2,
+ .max_register = MCP_OLAT << 1,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
/*----------------------------------------------------------------------*/
#ifdef CONFIG_SPI_MASTER
-static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
+static int mcp23sxx_spi_write(void *context, const void *data, size_t count)
{
- u8 tx[2], rx[1];
- int status;
+ struct mcp23s08 *mcp = context;
+ struct spi_device *spi = to_spi_device(mcp->dev);
+ struct spi_message m;
+ struct spi_transfer t[2] = { { .tx_buf = &mcp->addr, .len = 1, },
+ { .tx_buf = data, .len = count, }, };
- tx[0] = mcp->addr | 0x01;
- tx[1] = reg;
- status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx));
- return (status < 0) ? status : rx[0];
+ spi_message_init(&m);
+ spi_message_add_tail(&t[0], &m);
+ spi_message_add_tail(&t[1], &m);
+
+ return spi_sync(spi, &m);
}
-static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
+static int mcp23sxx_spi_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
{
- u8 tx[3];
+ struct mcp23s08 *mcp = context;
+ struct spi_device *spi = to_spi_device(mcp->dev);
+ struct spi_message m;
+ struct spi_transfer t[3] = { { .tx_buf = &mcp->addr, .len = 1, },
+ { .tx_buf = reg, .len = reg_size, },
+ { .tx_buf = val, .len = val_size, }, };
- tx[0] = mcp->addr;
- tx[1] = reg;
- tx[2] = val;
- return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0);
+ spi_message_init(&m);
+ spi_message_add_tail(&t[0], &m);
+ spi_message_add_tail(&t[1], &m);
+ spi_message_add_tail(&t[2], &m);
+
+ return spi_sync(spi, &m);
}
-static int
-mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
+static int mcp23sxx_spi_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
{
- u8 tx[2], *tmp;
- int status;
+ struct mcp23s08 *mcp = context;
+ struct spi_device *spi = to_spi_device(mcp->dev);
+ u8 tx[2];
- if ((n + reg) > sizeof(mcp->cache))
+ if (reg_size != 1)
return -EINVAL;
+
tx[0] = mcp->addr | 0x01;
- tx[1] = reg;
+ tx[1] = *((u8 *) reg);
- tmp = (u8 *)vals;
- status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n);
- if (status >= 0) {
- while (n--)
- vals[n] = tmp[n]; /* expand to 16bit */
- }
- return status;
+ return spi_write_then_read(spi, tx, sizeof(tx), val, val_size);
}
-static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg)
-{
- u8 tx[2], rx[2];
- int status;
+static const struct regmap_bus mcp23sxx_spi_regmap = {
+ .write = mcp23sxx_spi_write,
+ .gather_write = mcp23sxx_spi_gather_write,
+ .read = mcp23sxx_spi_read,
+};
- tx[0] = mcp->addr | 0x01;
- tx[1] = reg << 1;
- status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx));
- return (status < 0) ? status : (rx[0] | (rx[1] << 8));
-}
+#endif /* CONFIG_SPI_MASTER */
-static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
+static int mcp_read(struct mcp23s08 *mcp, unsigned int reg, unsigned int *val)
{
- u8 tx[4];
-
- tx[0] = mcp->addr;
- tx[1] = reg << 1;
- tx[2] = val;
- tx[3] = val >> 8;
- return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0);
+ return regmap_read(mcp->regmap, reg << mcp->reg_shift, val);
}
-static int
-mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
+static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val)
{
- u8 tx[2];
- int status;
+ return regmap_write(mcp->regmap, reg << mcp->reg_shift, val);
+}
- if ((n + reg) > sizeof(mcp->cache))
- return -EINVAL;
- tx[0] = mcp->addr | 0x01;
- tx[1] = reg << 1;
+static int mcp_update_cache(struct mcp23s08 *mcp)
+{
+ int ret, reg, i;
- status = spi_write_then_read(mcp->data, tx, sizeof(tx),
- (u8 *)vals, n * 2);
- if (status >= 0) {
- while (n--)
- vals[n] = __le16_to_cpu((__le16)vals[n]);
+ for (i = 0; i < ARRAY_SIZE(mcp->cache); i++) {
+ ret = mcp_read(mcp, i, &reg);
+ if (ret < 0)
+ return ret;
+ mcp->cache[i] = reg;
}
- return status;
+ return 0;
}
-static const struct mcp23s08_ops mcp23s08_ops = {
- .read = mcp23s08_read,
- .write = mcp23s08_write,
- .read_regs = mcp23s08_read_regs,
-};
+/*----------------------------------------------------------------------*/
-static const struct mcp23s08_ops mcp23s17_ops = {
- .read = mcp23s17_read,
- .write = mcp23s17_write,
- .read_regs = mcp23s17_read_regs,
+/* A given spi_device can represent up to eight mcp23sxx chips
+ * sharing the same chipselect but using different addresses
+ * (e.g. chips #0 and #3 might be populated, but not #1 or $2).
+ * Driver data holds all the per-chip data.
+ */
+struct mcp23s08_driver_data {
+ unsigned ngpio;
+ struct mcp23s08 *mcp[8];
+ struct mcp23s08 chip[];
};
-#endif /* CONFIG_SPI_MASTER */
-
-/*----------------------------------------------------------------------*/
static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
{
@@ -270,7 +203,7 @@ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
mutex_lock(&mcp->lock);
mcp->cache[MCP_IODIR] |= (1 << offset);
- status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
+ status = mcp_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
mutex_unlock(&mcp->lock);
return status;
}
@@ -278,13 +211,13 @@ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
static int mcp23s08_get(struct gpio_chip *chip, unsigned offset)
{
struct mcp23s08 *mcp = gpiochip_get_data(chip);
- int status;
+ int status, ret;
mutex_lock(&mcp->lock);
/* REVISIT reading this clears any IRQ ... */
- status = mcp->ops->read(mcp, MCP_GPIO);
- if (status < 0)
+ ret = mcp_read(mcp, MCP_GPIO, &status);
+ if (ret < 0)
status = 0;
else {
mcp->cache[MCP_GPIO] = status;
@@ -303,7 +236,7 @@ static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value)
else
olat &= ~mask;
mcp->cache[MCP_OLAT] = olat;
- return mcp->ops->write(mcp, MCP_OLAT, olat);
+ return mcp_write(mcp, MCP_OLAT, olat);
}
static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -327,7 +260,7 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
status = __mcp23s08_set(mcp, mask, value);
if (status == 0) {
mcp->cache[MCP_IODIR] &= ~mask;
- status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
+ status = mcp_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
}
mutex_unlock(&mcp->lock);
return status;
@@ -341,16 +274,14 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
unsigned int child_irq;
mutex_lock(&mcp->lock);
- intf = mcp->ops->read(mcp, MCP_INTF);
- if (intf < 0) {
+ if (mcp_read(mcp, MCP_INTF, &intf) < 0) {
mutex_unlock(&mcp->lock);
return IRQ_HANDLED;
}
mcp->cache[MCP_INTF] = intf;
- intcap = mcp->ops->read(mcp, MCP_INTCAP);
- if (intcap < 0) {
+ if (mcp_read(mcp, MCP_INTCAP, &intcap) < 0) {
mutex_unlock(&mcp->lock);
return IRQ_HANDLED;
}
@@ -435,9 +366,9 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data)
struct mcp23s08 *mcp = gpiochip_get_data(gc);
mutex_lock(&mcp->lock);
- mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]);
- mcp->ops->write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]);
- mcp->ops->write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]);
+ mcp_write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]);
+ mcp_write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]);
+ mcp_write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]);
mutex_unlock(&mcp->lock);
mutex_unlock(&mcp->irq_lock);
}
@@ -514,7 +445,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
bank = '0' + ((mcp->addr >> 1) & 0x7);
mutex_lock(&mcp->lock);
- t = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache));
+ t = mcp_update_cache(mcp);
if (t < 0) {
seq_printf(s, " I/O ERROR %d\n", t);
goto done;
@@ -549,12 +480,12 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
void *data, unsigned addr, unsigned type,
struct mcp23s08_platform_data *pdata, int cs)
{
- int status;
+ int status, ret;
bool mirror = false;
mutex_init(&mcp->lock);
- mcp->data = data;
+ mcp->dev = dev;
mcp->addr = addr;
mcp->irq_active_high = false;
@@ -571,19 +502,25 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
switch (type) {
#ifdef CONFIG_SPI_MASTER
case MCP_TYPE_S08:
- mcp->ops = &mcp23s08_ops;
+ mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp,
+ &mcp23x08_regmap);
+ mcp->reg_shift = 0;
mcp->chip.ngpio = 8;
mcp->chip.label = "mcp23s08";
break;
case MCP_TYPE_S17:
- mcp->ops = &mcp23s17_ops;
+ mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp,
+ &mcp23x17_regmap);
+ mcp->reg_shift = 1;
mcp->chip.ngpio = 16;
mcp->chip.label = "mcp23s17";
break;
case MCP_TYPE_S18:
- mcp->ops = &mcp23s17_ops;
+ mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp,
+ &mcp23x17_regmap);
+ mcp->reg_shift = 1;
mcp->chip.ngpio = 16;
mcp->chip.label = "mcp23s18";
break;
@@ -591,13 +528,15 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
#if IS_ENABLED(CONFIG_I2C)
case MCP_TYPE_008:
- mcp->ops = &mcp23008_ops;
+ mcp->regmap = devm_regmap_init_i2c(data, &mcp23x08_regmap);
+ mcp->reg_shift = 0;
mcp->chip.ngpio = 8;
mcp->chip.label = "mcp23008";
break;
case MCP_TYPE_017:
- mcp->ops = &mcp23017_ops;
+ mcp->regmap = devm_regmap_init_i2c(data, &mcp23x17_regmap);
+ mcp->reg_shift = 1;
mcp->chip.ngpio = 16;
mcp->chip.label = "mcp23017";
break;
@@ -608,6 +547,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
return -EINVAL;
}
+ if (IS_ERR(mcp->regmap))
+ return PTR_ERR(mcp->regmap);
+
mcp->chip.base = pdata->base;
mcp->chip.can_sleep = true;
mcp->chip.parent = dev;
@@ -617,8 +559,8 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
* and MCP_IOCON.HAEN = 1, so we work with all chips.
*/
- status = mcp->ops->read(mcp, MCP_IOCON);
- if (status < 0)
+ ret = mcp_read(mcp, MCP_IOCON, &status);
+ if (ret < 0)
goto fail;
mcp->irq_controller = pdata->irq_controller;
@@ -646,51 +588,49 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
if (type == MCP_TYPE_S18)
status |= IOCON_INTCC | (IOCON_INTCC << 8);
- status = mcp->ops->write(mcp, MCP_IOCON, status);
- if (status < 0)
+ ret = mcp_write(mcp, MCP_IOCON, status);
+ if (ret < 0)
goto fail;
}
/* configure ~100K pullups */
- status = mcp->ops->write(mcp, MCP_GPPU, pdata->chip[cs].pullups);
- if (status < 0)
+ ret = mcp_write(mcp, MCP_GPPU, pdata->chip[cs].pullups);
+ if (ret < 0)
goto fail;
- status = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache));
- if (status < 0)
+ ret = mcp_update_cache(mcp);
+ if (ret < 0)
goto fail;
/* disable inverter on input */
if (mcp->cache[MCP_IPOL] != 0) {
mcp->cache[MCP_IPOL] = 0;
- status = mcp->ops->write(mcp, MCP_IPOL, 0);
- if (status < 0)
+ ret = mcp_write(mcp, MCP_IPOL, 0);
+ if (ret < 0)
goto fail;
}
/* disable irqs */
if (mcp->cache[MCP_GPINTEN] != 0) {
mcp->cache[MCP_GPINTEN] = 0;
- status = mcp->ops->write(mcp, MCP_GPINTEN, 0);
- if (status < 0)
+ ret = mcp_write(mcp, MCP_GPINTEN, 0);
+ if (ret < 0)
goto fail;
}
- status = gpiochip_add_data(&mcp->chip, mcp);
- if (status < 0)
+ ret = gpiochip_add_data(&mcp->chip, mcp);
+ if (ret < 0)
goto fail;
if (mcp->irq && mcp->irq_controller) {
- status = mcp23s08_irq_setup(mcp);
- if (status) {
+ ret = mcp23s08_irq_setup(mcp);
+ if (ret)
goto fail;
- }
}
fail:
- if (status < 0)
- dev_dbg(dev, "can't setup chip %d, --> %d\n",
- addr, status);
- return status;
+ if (ret < 0)
+ dev_dbg(dev, "can't setup chip %d, --> %d\n", addr, ret);
+ return ret;
}
/*----------------------------------------------------------------------*/
diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c
index a1210e330571..e1037582e34d 100644
--- a/drivers/gpio/gpio-menz127.c
+++ b/drivers/gpio/gpio-menz127.c
@@ -89,22 +89,18 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
static int men_z127_set_single_ended(struct gpio_chip *gc,
unsigned offset,
- enum single_ended_mode mode)
+ enum pin_config_param param)
{
struct men_z127_gpio *priv = gpiochip_get_data(gc);
u32 od_en;
- if (mode != LINE_MODE_OPEN_DRAIN &&
- mode != LINE_MODE_PUSH_PULL)
- return -ENOTSUPP;
-
spin_lock(&gc->bgpio_lock);
od_en = readl(priv->reg_base + MEN_Z127_ODER);
- if (mode == LINE_MODE_OPEN_DRAIN)
+ if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
od_en |= BIT(offset);
else
- /* Implicitly LINE_MODE_PUSH_PULL */
+ /* Implicitly PIN_CONFIG_DRIVE_PUSH_PULL */
od_en &= ~BIT(offset);
writel(od_en, priv->reg_base + MEN_Z127_ODER);
@@ -113,6 +109,27 @@ static int men_z127_set_single_ended(struct gpio_chip *gc,
return 0;
}
+static int men_z127_set_config(struct gpio_chip *gc, unsigned offset,
+ unsigned long config)
+{
+ enum pin_config_param param = pinconf_to_config_param(config);
+
+ switch (param) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ return men_z127_set_single_ended(gc, offset, param);
+
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ return men_z127_debounce(gc, offset,
+ pinconf_to_config_argument(config));
+
+ default:
+ break;
+ }
+
+ return -ENOTSUPP;
+}
+
static int men_z127_probe(struct mcb_device *mdev,
const struct mcb_device_id *id)
{
@@ -149,8 +166,7 @@ static int men_z127_probe(struct mcb_device *mdev,
if (ret)
goto err_unmap;
- men_z127_gpio->gc.set_debounce = men_z127_debounce;
- men_z127_gpio->gc.set_single_ended = men_z127_set_single_ended;
+ men_z127_gpio->gc.set_config = men_z127_set_config;
ret = gpiochip_add_data(&men_z127_gpio->gc, men_z127_gpio);
if (ret) {
diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c
index 69e0f4ace465..f40088d268c1 100644
--- a/drivers/gpio/gpio-merrifield.c
+++ b/drivers/gpio/gpio-merrifield.c
@@ -190,6 +190,18 @@ static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
return 0;
}
+static int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+ return mrfld_gpio_set_debounce(chip, offset, debounce);
+}
+
static void mrfld_irq_ack(struct irq_data *d)
{
struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
@@ -414,7 +426,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
priv->chip.get = mrfld_gpio_get;
priv->chip.set = mrfld_gpio_set;
priv->chip.get_direction = mrfld_gpio_get_direction;
- priv->chip.set_debounce = mrfld_gpio_set_debounce;
+ priv->chip.set_config = mrfld_gpio_set_config;
priv->chip.base = gpio_base;
priv->chip.ngpio = MRFLD_NGPIO;
priv->chip.can_sleep = false;
diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c
index 54e5d8257d34..b1cf76dd84ba 100644
--- a/drivers/gpio/gpio-mm-lantiq.c
+++ b/drivers/gpio/gpio-mm-lantiq.c
@@ -3,7 +3,7 @@
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
- * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2012 John Crispin <john@phrozen.org>
*/
#include <linux/init.h>
diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
index 1ef85b0c2b1f..06dac72cb69c 100644
--- a/drivers/gpio/gpio-mockup.c
+++ b/drivers/gpio/gpio-mockup.c
@@ -14,14 +14,23 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irq_work.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
-#define GPIO_NAME "gpio-mockup"
-#define MAX_GC 10
+#include "gpiolib.h"
-enum direction {
- OUT,
- IN
+#define GPIO_MOCKUP_NAME "gpio-mockup"
+#define GPIO_MOCKUP_MAX_GC 10
+
+enum {
+ DIR_IN = 0,
+ DIR_OUT,
};
/*
@@ -29,150 +38,360 @@ enum direction {
* @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out
* @value: Configures status of the gpio as 0(low) or 1(high)
*/
-struct gpio_pin_status {
- enum direction dir;
+struct gpio_mockup_line_status {
+ int dir;
bool value;
};
-struct mockup_gpio_controller {
+struct gpio_mockup_irq_context {
+ struct irq_work work;
+ int irq;
+};
+
+struct gpio_mockup_chip {
struct gpio_chip gc;
- struct gpio_pin_status *stats;
+ struct gpio_mockup_line_status *lines;
+ struct gpio_mockup_irq_context irq_ctx;
+ struct dentry *dbg_dir;
};
-static int gpio_mockup_ranges[MAX_GC << 1];
+struct gpio_mockup_dbgfs_private {
+ struct gpio_mockup_chip *chip;
+ struct gpio_desc *desc;
+ int offset;
+};
+
+static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_GC << 1];
static int gpio_mockup_params_nr;
module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400);
-const char pins_name_start = 'A';
+static bool gpio_mockup_named_lines;
+module_param_named(gpio_mockup_named_lines,
+ gpio_mockup_named_lines, bool, 0400);
+
+static const char gpio_mockup_name_start = 'A';
+static struct dentry *gpio_mockup_dbg_dir;
-static int mockup_gpio_get(struct gpio_chip *gc, unsigned int offset)
+static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)
{
- struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+ struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
- return cntr->stats[offset].value;
+ return chip->lines[offset].value;
}
-static void mockup_gpio_set(struct gpio_chip *gc, unsigned int offset,
+static void gpio_mockup_set(struct gpio_chip *gc, unsigned int offset,
int value)
{
- struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+ struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
- cntr->stats[offset].value = !!value;
+ chip->lines[offset].value = !!value;
}
-static int mockup_gpio_dirout(struct gpio_chip *gc, unsigned int offset,
+static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset,
int value)
{
- struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+ struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
+
+ gpio_mockup_set(gc, offset, value);
+ chip->lines[offset].dir = DIR_OUT;
+
+ return 0;
+}
+
+static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
+
+ chip->lines[offset].dir = DIR_IN;
+
+ return 0;
+}
+
+static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
+
+ return chip->lines[offset].dir;
+}
+
+static int gpio_mockup_name_lines(struct device *dev,
+ struct gpio_mockup_chip *chip)
+{
+ struct gpio_chip *gc = &chip->gc;
+ char **names;
+ int i;
+
+ names = devm_kzalloc(dev, sizeof(char *) * gc->ngpio, GFP_KERNEL);
+ if (!names)
+ return -ENOMEM;
+
+ for (i = 0; i < gc->ngpio; i++) {
+ names[i] = devm_kasprintf(dev, GFP_KERNEL,
+ "%s-%d", gc->label, i);
+ if (!names[i])
+ return -ENOMEM;
+ }
+
+ gc->names = (const char *const *)names;
- mockup_gpio_set(gc, offset, value);
- cntr->stats[offset].dir = OUT;
return 0;
}
-static int mockup_gpio_dirin(struct gpio_chip *gc, unsigned int offset)
+static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset)
{
- struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+ return chip->irq_base + offset;
+}
+
+/*
+ * While we should generally support irqmask and irqunmask, this driver is
+ * for testing purposes only so we don't care.
+ */
+static void gpio_mockup_irqmask(struct irq_data *d) { }
+static void gpio_mockup_irqunmask(struct irq_data *d) { }
+
+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 = irq_alloc_descs(-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_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);
- cntr->stats[offset].dir = IN;
return 0;
}
-static int mockup_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+static ssize_t gpio_mockup_event_write(struct file *file,
+ const char __user *usr_buf,
+ size_t size, loff_t *ppos)
+{
+ struct gpio_mockup_dbgfs_private *priv;
+ struct gpio_mockup_chip *chip;
+ struct seq_file *sfile;
+ struct gpio_desc *desc;
+ struct gpio_chip *gc;
+ int status, val;
+ char buf;
+
+ sfile = file->private_data;
+ priv = sfile->private;
+ desc = priv->desc;
+ chip = priv->chip;
+ gc = &chip->gc;
+
+ status = copy_from_user(&buf, usr_buf, 1);
+ if (status)
+ return status;
+
+ if (buf == '0')
+ val = 0;
+ else if (buf == '1')
+ val = 1;
+ else
+ return -EINVAL;
+
+ gpiod_set_value_cansleep(desc, val);
+ priv->chip->irq_ctx.irq = gc->irq_base + priv->offset;
+ irq_work_queue(&priv->chip->irq_ctx.work);
+
+ return size;
+}
+
+static int gpio_mockup_event_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, NULL, inode->i_private);
+}
+
+static const struct file_operations gpio_mockup_event_ops = {
+ .owner = THIS_MODULE,
+ .open = gpio_mockup_event_open,
+ .write = gpio_mockup_event_write,
+ .llseek = no_llseek,
+};
+
+static void gpio_mockup_debugfs_setup(struct device *dev,
+ struct gpio_mockup_chip *chip)
{
- struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+ struct gpio_mockup_dbgfs_private *priv;
+ struct dentry *evfile;
+ struct gpio_chip *gc;
+ char *name;
+ int i;
+
+ gc = &chip->gc;
- return cntr->stats[offset].dir;
+ chip->dbg_dir = debugfs_create_dir(gc->label, gpio_mockup_dbg_dir);
+ if (!chip->dbg_dir)
+ goto err;
+
+ for (i = 0; i < gc->ngpio; i++) {
+ name = devm_kasprintf(dev, GFP_KERNEL, "%d", i);
+ if (!name)
+ goto err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ goto err;
+
+ priv->chip = chip;
+ priv->offset = i;
+ priv->desc = &gc->gpiodev->descs[i];
+
+ evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv,
+ &gpio_mockup_event_ops);
+ if (!evfile)
+ goto err;
+ }
+
+ return;
+
+err:
+ dev_err(dev, "error creating debugfs directory\n");
}
-static int mockup_gpio_add(struct device *dev,
- struct mockup_gpio_controller *cntr,
+static int gpio_mockup_add(struct device *dev,
+ struct gpio_mockup_chip *chip,
const char *name, int base, int ngpio)
{
+ struct gpio_chip *gc = &chip->gc;
int ret;
- cntr->gc.base = base;
- cntr->gc.ngpio = ngpio;
- cntr->gc.label = name;
- cntr->gc.owner = THIS_MODULE;
- cntr->gc.parent = dev;
- cntr->gc.get = mockup_gpio_get;
- cntr->gc.set = mockup_gpio_set;
- cntr->gc.direction_output = mockup_gpio_dirout;
- cntr->gc.direction_input = mockup_gpio_dirin;
- cntr->gc.get_direction = mockup_gpio_get_direction;
- cntr->stats = devm_kzalloc(dev, sizeof(*cntr->stats) * cntr->gc.ngpio,
+ gc->base = base;
+ gc->ngpio = ngpio;
+ gc->label = name;
+ gc->owner = THIS_MODULE;
+ gc->parent = dev;
+ gc->get = gpio_mockup_get;
+ gc->set = gpio_mockup_set;
+ gc->direction_output = gpio_mockup_dirout;
+ gc->direction_input = gpio_mockup_dirin;
+ gc->get_direction = gpio_mockup_get_direction;
+ gc->to_irq = gpio_mockup_to_irq;
+
+ chip->lines = devm_kzalloc(dev, sizeof(*chip->lines) * gc->ngpio,
GFP_KERNEL);
- if (!cntr->stats) {
- ret = -ENOMEM;
- goto err;
+ if (!chip->lines)
+ return -ENOMEM;
+
+ if (gpio_mockup_named_lines) {
+ ret = gpio_mockup_name_lines(dev, chip);
+ if (ret)
+ return ret;
}
- ret = devm_gpiochip_add_data(dev, &cntr->gc, cntr);
+
+ ret = gpio_mockup_irqchip_setup(dev, chip);
if (ret)
- goto err;
+ return ret;
+
+ ret = devm_gpiochip_add_data(dev, &chip->gc, chip);
+ if (ret)
+ return ret;
+
+ if (gpio_mockup_dbg_dir)
+ gpio_mockup_debugfs_setup(dev, chip);
- dev_info(dev, "gpio<%d..%d> add successful!", base, base + ngpio);
return 0;
-err:
- dev_err(dev, "gpio<%d..%d> add failed!", base, base + ngpio);
- return ret;
}
-static int mockup_gpio_probe(struct platform_device *pdev)
+static int gpio_mockup_probe(struct platform_device *pdev)
{
+ struct gpio_mockup_chip *chips;
struct device *dev = &pdev->dev;
- struct mockup_gpio_controller *cntr;
- int ret;
- int i;
- int base;
- int ngpio;
- char chip_name[sizeof(GPIO_NAME) + 3];
+ int ret, i, base, ngpio;
+ char *chip_name;
if (gpio_mockup_params_nr < 2)
return -EINVAL;
- cntr = devm_kzalloc(dev, sizeof(*cntr) * (gpio_mockup_params_nr >> 1),
- GFP_KERNEL);
- if (!cntr)
+ chips = devm_kzalloc(dev,
+ sizeof(*chips) * (gpio_mockup_params_nr >> 1),
+ GFP_KERNEL);
+ if (!chips)
return -ENOMEM;
- platform_set_drvdata(pdev, cntr);
+ platform_set_drvdata(pdev, chips);
for (i = 0; i < gpio_mockup_params_nr >> 1; i++) {
base = gpio_mockup_ranges[i * 2];
+
if (base == -1)
ngpio = gpio_mockup_ranges[i * 2 + 1];
else
ngpio = gpio_mockup_ranges[i * 2 + 1] - base;
if (ngpio >= 0) {
- sprintf(chip_name, "%s-%c", GPIO_NAME,
- pins_name_start + i);
- ret = mockup_gpio_add(dev, &cntr[i],
+ chip_name = devm_kasprintf(dev, GFP_KERNEL,
+ "%s-%c", GPIO_MOCKUP_NAME,
+ gpio_mockup_name_start + i);
+ if (!chip_name)
+ return -ENOMEM;
+
+ ret = gpio_mockup_add(dev, &chips[i],
chip_name, base, ngpio);
} else {
ret = -1;
}
+
if (ret) {
- if (base < 0)
- dev_err(dev, "gpio<%d..%d> add failed\n",
- base, ngpio);
- else
- dev_err(dev, "gpio<%d..%d> add failed\n",
- base, base + ngpio);
+ dev_err(dev, "gpio<%d..%d> add failed\n",
+ base, base < 0 ? ngpio : base + ngpio);
return ret;
}
+
+ dev_info(dev, "gpio<%d..%d> add successful!",
+ base, base + ngpio);
}
return 0;
}
-static struct platform_driver mockup_gpio_driver = {
+static int gpio_mockup_remove(struct platform_device *pdev)
+{
+ struct gpio_mockup_chip *chips;
+ int i;
+
+ chips = platform_get_drvdata(pdev);
+
+ for (i = 0; i < gpio_mockup_params_nr >> 1; i++)
+ irq_free_descs(chips[i].gc.irq_base, chips[i].gc.ngpio);
+
+ return 0;
+}
+
+static struct platform_driver gpio_mockup_driver = {
.driver = {
- .name = GPIO_NAME,
- },
- .probe = mockup_gpio_probe,
+ .name = GPIO_MOCKUP_NAME,
+ },
+ .probe = gpio_mockup_probe,
+ .remove = gpio_mockup_remove,
};
static struct platform_device *pdev;
@@ -180,7 +399,12 @@ static int __init mock_device_init(void)
{
int err;
- pdev = platform_device_alloc(GPIO_NAME, -1);
+ gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL);
+ if (!gpio_mockup_dbg_dir)
+ pr_err("%s: error creating debugfs directory\n",
+ GPIO_MOCKUP_NAME);
+
+ pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1);
if (!pdev)
return -ENOMEM;
@@ -190,7 +414,7 @@ static int __init mock_device_init(void)
return err;
}
- err = platform_driver_register(&mockup_gpio_driver);
+ err = platform_driver_register(&gpio_mockup_driver);
if (err) {
platform_device_unregister(pdev);
return err;
@@ -201,7 +425,8 @@ static int __init mock_device_init(void)
static void __exit mock_device_exit(void)
{
- platform_driver_unregister(&mockup_gpio_driver);
+ debugfs_remove_recursive(gpio_mockup_dbg_dir);
+ platform_driver_unregister(&gpio_mockup_driver);
platform_device_unregister(pdev);
}
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 1ed6132b993c..a649556ac3ca 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -659,7 +659,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
if (match)
- soc_variant = (int) match->data;
+ soc_variant = (unsigned long) match->data;
else
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index b98ede78c9d8..efc85a279d54 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -974,6 +974,18 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
return 0;
}
+static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config)
+{
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+ return omap_gpio_debounce(chip, offset, debounce);
+}
+
static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct gpio_bank *bank;
@@ -1045,7 +1057,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
bank->chip.direction_input = omap_gpio_input;
bank->chip.get = omap_gpio_get;
bank->chip.direction_output = omap_gpio_output;
- bank->chip.set_debounce = omap_gpio_debounce;
+ bank->chip.set_config = omap_gpio_set_config;
bank->chip.set = omap_gpio_set;
if (bank->is_mpuio) {
bank->chip.label = "mpuio";
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index d5d72d84b719..d44232aadb6c 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/platform_data/pca953x.h>
@@ -754,8 +755,16 @@ static int pca953x_probe(struct i2c_client *client,
invert = pdata->invert;
chip->names = pdata->names;
} else {
+ struct gpio_desc *reset_gpio;
+
chip->gpio_start = -1;
irq_base = 0;
+
+ /* See if we need to de-assert a reset pin */
+ reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(reset_gpio))
+ return PTR_ERR(reset_gpio);
}
chip->client = client;
diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c
new file mode 100644
index 000000000000..0220787240ce
--- /dev/null
+++ b/drivers/gpio/gpio-pci-idio-16.c
@@ -0,0 +1,348 @@
+/*
+ * GPIO driver for the ACCES PCI-IDIO-16
+ * Copyright (C) 2017 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irqdesc.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/**
+ * struct idio_16_gpio_reg - GPIO device registers structure
+ * @out0_7: Read: FET Drive Outputs 0-7
+ * Write: FET Drive Outputs 0-7
+ * @in0_7: Read: Isolated Inputs 0-7
+ * Write: Clear Interrupt
+ * @irq_ctl: Read: Enable IRQ
+ * Write: Disable IRQ
+ * @filter_ctl: Read: Activate Input Filters 0-15
+ * Write: Deactivate Input Filters 0-15
+ * @out8_15: Read: FET Drive Outputs 8-15
+ * Write: FET Drive Outputs 8-15
+ * @in8_15: Read: Isolated Inputs 8-15
+ * Write: Unused
+ * @irq_status: Read: Interrupt status
+ * Write: Unused
+ */
+struct idio_16_gpio_reg {
+ u8 out0_7;
+ u8 in0_7;
+ u8 irq_ctl;
+ u8 filter_ctl;
+ u8 out8_15;
+ u8 in8_15;
+ u8 irq_status;
+};
+
+/**
+ * struct idio_16_gpio - GPIO device private data structure
+ * @chip: instance of the gpio_chip
+ * @lock: synchronization lock to prevent I/O race conditions
+ * @reg: I/O address offset for the GPIO device registers
+ * @irq_mask: I/O bits affected by interrupts
+ */
+struct idio_16_gpio {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ struct idio_16_gpio_reg __iomem *reg;
+ unsigned long irq_mask;
+};
+
+static int idio_16_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ if (offset > 15)
+ return 1;
+
+ return 0;
+}
+
+static int idio_16_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ return 0;
+}
+
+static int idio_16_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ chip->set(chip, offset, value);
+ return 0;
+}
+
+static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ unsigned long mask = BIT(offset);
+
+ if (offset < 8)
+ return !!(ioread8(&idio16gpio->reg->out0_7) & mask);
+
+ if (offset < 16)
+ return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8));
+
+ if (offset < 24)
+ return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16));
+
+ return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
+}
+
+static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ unsigned int mask = BIT(offset);
+ void __iomem *base;
+ unsigned long flags;
+ unsigned int out_state;
+
+ if (offset > 15)
+ return;
+
+ if (offset > 7) {
+ mask >>= 8;
+ base = &idio16gpio->reg->out8_15;
+ } else
+ base = &idio16gpio->reg->out0_7;
+
+ spin_lock_irqsave(&idio16gpio->lock, flags);
+
+ if (value)
+ out_state = ioread8(base) | mask;
+ else
+ out_state = ioread8(base) & ~mask;
+
+ iowrite8(out_state, base);
+
+ spin_unlock_irqrestore(&idio16gpio->lock, flags);
+}
+
+static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
+{
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ unsigned long flags;
+ unsigned int out_state;
+
+ spin_lock_irqsave(&idio16gpio->lock, flags);
+
+ /* process output lines 0-7 */
+ if (*mask & 0xFF) {
+ out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask;
+ out_state |= *mask & *bits;
+ iowrite8(out_state, &idio16gpio->reg->out0_7);
+ }
+
+ /* shift to next output line word */
+ *mask >>= 8;
+
+ /* process output lines 8-15 */
+ if (*mask & 0xFF) {
+ *bits >>= 8;
+ out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask;
+ out_state |= *mask & *bits;
+ iowrite8(out_state, &idio16gpio->reg->out8_15);
+ }
+
+ spin_unlock_irqrestore(&idio16gpio->lock, flags);
+}
+
+static void idio_16_irq_ack(struct irq_data *data)
+{
+}
+
+static void idio_16_irq_mask(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ const unsigned long mask = BIT(irqd_to_hwirq(data));
+ unsigned long flags;
+
+ idio16gpio->irq_mask &= ~mask;
+
+ if (!idio16gpio->irq_mask) {
+ spin_lock_irqsave(&idio16gpio->lock, flags);
+
+ iowrite8(0, &idio16gpio->reg->irq_ctl);
+
+ spin_unlock_irqrestore(&idio16gpio->lock, flags);
+ }
+}
+
+static void idio_16_irq_unmask(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+ const unsigned long mask = BIT(irqd_to_hwirq(data));
+ const unsigned long prev_irq_mask = idio16gpio->irq_mask;
+ unsigned long flags;
+
+ idio16gpio->irq_mask |= mask;
+
+ if (!prev_irq_mask) {
+ spin_lock_irqsave(&idio16gpio->lock, flags);
+
+ ioread8(&idio16gpio->reg->irq_ctl);
+
+ spin_unlock_irqrestore(&idio16gpio->lock, flags);
+ }
+}
+
+static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ /* The only valid irq types are none and both-edges */
+ if (flow_type != IRQ_TYPE_NONE &&
+ (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct irq_chip idio_16_irqchip = {
+ .name = "pci-idio-16",
+ .irq_ack = idio_16_irq_ack,
+ .irq_mask = idio_16_irq_mask,
+ .irq_unmask = idio_16_irq_unmask,
+ .irq_set_type = idio_16_irq_set_type
+};
+
+static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
+{
+ struct idio_16_gpio *const idio16gpio = dev_id;
+ unsigned int irq_status;
+ struct gpio_chip *const chip = &idio16gpio->chip;
+ int gpio;
+
+ spin_lock(&idio16gpio->lock);
+
+ irq_status = ioread8(&idio16gpio->reg->irq_status);
+
+ spin_unlock(&idio16gpio->lock);
+
+ /* Make sure our device generated IRQ */
+ if (!(irq_status & 0x3) || !(irq_status & 0x4))
+ return IRQ_NONE;
+
+ for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
+ generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
+
+ spin_lock(&idio16gpio->lock);
+
+ /* Clear interrupt */
+ iowrite8(0, &idio16gpio->reg->in0_7);
+
+ spin_unlock(&idio16gpio->lock);
+
+ return IRQ_HANDLED;
+}
+
+#define IDIO_16_NGPIO 32
+static const char *idio_16_names[IDIO_16_NGPIO] = {
+ "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
+ "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
+ "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
+ "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
+};
+
+static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct device *const dev = &pdev->dev;
+ struct idio_16_gpio *idio16gpio;
+ int err;
+ const char *const name = pci_name(pdev);
+
+ idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
+ if (!idio16gpio)
+ return -ENOMEM;
+
+ err = pcim_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "Failed to enable PCI device (%d)\n", err);
+ return err;
+ }
+
+ err = pcim_iomap_regions(pdev, 0x1, name);
+ if (err) {
+ dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
+ return err;
+ }
+
+ idio16gpio->reg = pcim_iomap_table(pdev)[0];
+
+ /* Deactivate input filters */
+ iowrite8(0, &idio16gpio->reg->filter_ctl);
+
+ idio16gpio->chip.label = name;
+ idio16gpio->chip.parent = dev;
+ idio16gpio->chip.owner = THIS_MODULE;
+ idio16gpio->chip.base = -1;
+ idio16gpio->chip.ngpio = IDIO_16_NGPIO;
+ idio16gpio->chip.names = idio_16_names;
+ idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
+ idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
+ idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
+ idio16gpio->chip.get = idio_16_gpio_get;
+ idio16gpio->chip.set = idio_16_gpio_set;
+ idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
+
+ spin_lock_init(&idio16gpio->lock);
+
+ err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
+ if (err) {
+ dev_err(dev, "GPIO registering failed (%d)\n", err);
+ return err;
+ }
+
+ /* Disable IRQ by default and clear any pending interrupt */
+ iowrite8(0, &idio16gpio->reg->irq_ctl);
+ iowrite8(0, &idio16gpio->reg->in0_7);
+
+ err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
+ handle_edge_irq, IRQ_TYPE_NONE);
+ if (err) {
+ dev_err(dev, "Could not add irqchip (%d)\n", err);
+ return err;
+ }
+
+ err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
+ name, idio16gpio);
+ if (err) {
+ dev_err(dev, "IRQ handler registering failed (%d)\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct pci_device_id idio_16_pci_dev_id[] = {
+ { PCI_DEVICE(0x494F, 0x0F00) }, { 0 }
+};
+MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
+
+static struct pci_driver idio_16_driver = {
+ .name = "pci-idio-16",
+ .id_table = idio_16_pci_dev_id,
+ .probe = idio_16_probe
+};
+
+module_pci_driver(idio_16_driver);
+
+MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
+MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 2be48f5eba36..31ad288846af 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -242,11 +242,24 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
{
- return pinctrl_request_gpio(chip->base + offset);
+ struct gpio_rcar_priv *p = gpiochip_get_data(chip);
+ int error;
+
+ error = pm_runtime_get_sync(&p->pdev->dev);
+ if (error < 0)
+ return error;
+
+ error = pinctrl_request_gpio(chip->base + offset);
+ if (error)
+ pm_runtime_put(&p->pdev->dev);
+
+ return error;
}
static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
{
+ struct gpio_rcar_priv *p = gpiochip_get_data(chip);
+
pinctrl_free_gpio(chip->base + offset);
/*
@@ -254,6 +267,8 @@ static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
* drive the GPIO pin as an output.
*/
gpio_rcar_config_general_input_output_mode(chip, offset, false);
+
+ pm_runtime_put(&p->pdev->dev);
}
static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -426,7 +441,6 @@ static int gpio_rcar_probe(struct platform_device *pdev)
}
pm_runtime_enable(dev);
- pm_runtime_get_sync(dev);
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -460,6 +474,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq_chip = &p->irq_chip;
irq_chip->name = name;
+ irq_chip->parent_device = dev;
irq_chip->irq_mask = gpio_rcar_irq_disable;
irq_chip->irq_unmask = gpio_rcar_irq_enable;
irq_chip->irq_set_type = gpio_rcar_irq_set_type;
@@ -494,7 +509,6 @@ static int gpio_rcar_probe(struct platform_device *pdev)
err1:
gpiochip_remove(gpio_chip);
err0:
- pm_runtime_put(dev);
pm_runtime_disable(dev);
return ret;
}
@@ -505,7 +519,6 @@ static int gpio_rcar_remove(struct platform_device *pdev)
gpiochip_remove(&p->gpio_chip);
- pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 19e654f88b3a..c07385b71403 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -3,7 +3,7 @@
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
- * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2012 John Crispin <john@phrozen.org>
*
*/
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index be97101c2c9a..433b45ef332e 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -100,9 +100,8 @@ static int tc3589x_gpio_get_direction(struct gpio_chip *chip,
return !(ret & BIT(pos));
}
-static int tc3589x_gpio_set_single_ended(struct gpio_chip *chip,
- unsigned int offset,
- enum single_ended_mode mode)
+static int tc3589x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
{
struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
@@ -116,22 +115,22 @@ static int tc3589x_gpio_set_single_ended(struct gpio_chip *chip,
unsigned int pos = offset % 8;
int ret;
- switch(mode) {
- case LINE_MODE_OPEN_DRAIN:
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
/* Set open drain mode */
ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), 0);
if (ret)
return ret;
/* Enable open drain/source mode */
return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
- case LINE_MODE_OPEN_SOURCE:
+ case PIN_CONFIG_DRIVE_OPEN_SOURCE:
/* Set open source mode */
ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), BIT(pos));
if (ret)
return ret;
/* Enable open drain/source mode */
return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
- case LINE_MODE_PUSH_PULL:
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
/* Disable open drain/source mode */
return tc3589x_set_bits(tc3589x, odereg, BIT(pos), 0);
default:
@@ -148,7 +147,7 @@ static const struct gpio_chip template_chip = {
.direction_output = tc3589x_gpio_direction_output,
.direction_input = tc3589x_gpio_direction_input,
.get_direction = tc3589x_gpio_get_direction,
- .set_single_ended = tc3589x_gpio_set_single_ended,
+ .set_config = tc3589x_gpio_set_config,
.can_sleep = true,
};
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 661b0e34e067..88529d3c06c9 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -238,6 +238,18 @@ static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
return 0;
}
+static int tegra_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+ return tegra_gpio_set_debounce(chip, offset, debounce);
+}
+
static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
@@ -615,7 +627,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tgi);
if (config->debounce_supported)
- tgi->gc.set_debounce = tegra_gpio_set_debounce;
+ tgi->gc.set_config = tegra_gpio_set_config;
tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count *
sizeof(*tgi->bank_info), GFP_KERNEL);
diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c
index 46e6dcc089cb..a379bba57d31 100644
--- a/drivers/gpio/gpio-tps65218.c
+++ b/drivers/gpio/gpio-tps65218.c
@@ -139,28 +139,28 @@ static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset)
return 0;
}
-static int tps65218_gpio_set_single_ended(struct gpio_chip *gc,
- unsigned offset,
- enum single_ended_mode mode)
+static int tps65218_gpio_set_config(struct gpio_chip *gc, unsigned offset,
+ unsigned long config)
{
struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
struct tps65218 *tps65218 = tps65218_gpio->tps65218;
+ enum pin_config_param param = pinconf_to_config_param(config);
switch (offset) {
case 0:
case 2:
/* GPO1 is hardwired to be open drain */
- if (mode == LINE_MODE_OPEN_DRAIN)
+ if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
return 0;
return -ENOTSUPP;
case 1:
/* GPO2 is push-pull by default, can be set as open drain. */
- if (mode == LINE_MODE_OPEN_DRAIN)
+ if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
return tps65218_clear_bits(tps65218,
TPS65218_REG_CONFIG1,
TPS65218_CONFIG1_GPO2_BUF,
TPS65218_PROTECT_L1);
- if (mode == LINE_MODE_PUSH_PULL)
+ if (param == PIN_CONFIG_DRIVE_PUSH_PULL)
return tps65218_set_bits(tps65218,
TPS65218_REG_CONFIG1,
TPS65218_CONFIG1_GPO2_BUF,
@@ -181,7 +181,7 @@ static const struct gpio_chip template_chip = {
.direction_input = tps65218_gpio_input,
.get = tps65218_gpio_get,
.set = tps65218_gpio_set,
- .set_single_ended = tps65218_gpio_set_single_ended,
+ .set_config = tps65218_gpio_set_config,
.can_sleep = true,
.ngpio = 3,
.base = -1,
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 4e450121129b..98a6f1fcc561 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -186,23 +186,24 @@ static int vx855gpio_direction_output(struct gpio_chip *gpio,
return 0;
}
-static int vx855gpio_set_single_ended(struct gpio_chip *gpio,
- unsigned int nr,
- enum single_ended_mode mode)
+static int vx855gpio_set_config(struct gpio_chip *gpio, unsigned int nr,
+ unsigned long config)
{
+ enum pin_config_param param = pinconf_to_config_param(config);
+
/* The GPI cannot be single-ended */
if (nr < NR_VX855_GPI)
return -EINVAL;
/* The GPO's are push-pull */
if (nr < NR_VX855_GPInO) {
- if (mode != LINE_MODE_PUSH_PULL)
+ if (param != PIN_CONFIG_DRIVE_PUSH_PULL)
return -ENOTSUPP;
return 0;
}
/* The GPIO's are open drain */
- if (mode != LINE_MODE_OPEN_DRAIN)
+ if (param != PIN_CONFIG_DRIVE_OPEN_DRAIN)
return -ENOTSUPP;
return 0;
@@ -231,7 +232,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
c->direction_output = vx855gpio_direction_output;
c->get = vx855gpio_get;
c->set = vx855gpio_set;
- c->set_single_ended = vx855gpio_set_single_ended;
+ c->set_config = vx855gpio_set_config,
c->dbg_show = NULL;
c->base = 0;
c->ngpio = NR_VX855_GP;
diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c
index 34baee5b1dd6..97613de5304e 100644
--- a/drivers/gpio/gpio-wcove.c
+++ b/drivers/gpio/gpio-wcove.c
@@ -202,17 +202,16 @@ static void wcove_gpio_set(struct gpio_chip *chip,
regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), 1, 0);
}
-static int wcove_gpio_set_single_ended(struct gpio_chip *chip,
- unsigned int gpio,
- enum single_ended_mode mode)
+static int wcove_gpio_set_config(struct gpio_chip *chip, unsigned int gpio,
+ unsigned long config)
{
struct wcove_gpio *wg = gpiochip_get_data(chip);
- switch (mode) {
- case LINE_MODE_OPEN_DRAIN:
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT),
CTLO_DRV_MASK, CTLO_DRV_OD);
- case LINE_MODE_PUSH_PULL:
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT),
CTLO_DRV_MASK, CTLO_DRV_CMOS);
default:
@@ -411,7 +410,7 @@ static int wcove_gpio_probe(struct platform_device *pdev)
wg->chip.get_direction = wcove_gpio_get_direction;
wg->chip.get = wcove_gpio_get;
wg->chip.set = wcove_gpio_set;
- wg->chip.set_single_ended = wcove_gpio_set_single_ended,
+ wg->chip.set_config = wcove_gpio_set_config,
wg->chip.base = -1;
wg->chip.ngpio = WCOVE_VGPIO_NUM;
wg->chip.can_sleep = true;
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index 533707f943f4..00e3839b3f96 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -101,11 +101,9 @@ static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
WM831X_IRQ_GPIO_1 + offset);
}
-static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
+static int wm831x_gpio_set_debounce(struct wm831x *wm831x, unsigned offset,
unsigned debounce)
{
- struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
- struct wm831x *wm831x = wm831x_gpio->wm831x;
int reg = WM831X_GPIO1_CONTROL + offset;
int ret, fn;
@@ -132,21 +130,23 @@ static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn);
}
-static int wm831x_set_single_ended(struct gpio_chip *chip,
- unsigned int offset,
- enum single_ended_mode mode)
+static int wm831x_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
{
struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
int reg = WM831X_GPIO1_CONTROL + offset;
- switch (mode) {
- case LINE_MODE_OPEN_DRAIN:
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
return wm831x_set_bits(wm831x, reg,
WM831X_GPN_OD_MASK, WM831X_GPN_OD);
- case LINE_MODE_PUSH_PULL:
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
return wm831x_set_bits(wm831x, reg,
WM831X_GPN_OD_MASK, 0);
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ return wm831x_gpio_set_debounce(wm831x, offset,
+ pinconf_to_config_argument(config));
default:
break;
}
@@ -255,8 +255,7 @@ static const struct gpio_chip template_chip = {
.direction_output = wm831x_gpio_direction_out,
.set = wm831x_gpio_set,
.to_irq = wm831x_gpio_to_irq,
- .set_debounce = wm831x_gpio_set_debounce,
- .set_single_ended = wm831x_set_single_ended,
+ .set_config = wm831x_set_config,
.dbg_show = wm831x_gpio_dbg_show,
.can_sleep = true,
};
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index 68410fda6138..1e35756ac55b 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -103,19 +103,18 @@ static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
}
-static int wm8994_gpio_set_single_ended(struct gpio_chip *chip,
- unsigned int offset,
- enum single_ended_mode mode)
+static int wm8994_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
{
struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
- switch (mode) {
- case LINE_MODE_OPEN_DRAIN:
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
WM8994_GPN_OP_CFG_MASK,
WM8994_GPN_OP_CFG);
- case LINE_MODE_PUSH_PULL:
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
WM8994_GPN_OP_CFG_MASK, 0);
default:
@@ -257,7 +256,7 @@ static const struct gpio_chip template_chip = {
.get = wm8994_gpio_get,
.direction_output = wm8994_gpio_direction_out,
.set = wm8994_gpio_set,
- .set_single_ended = wm8994_gpio_set_single_ended,
+ .set_config = wm8994_gpio_set_config,
.to_irq = wm8994_gpio_to_irq,
.dbg_show = wm8994_gpio_dbg_show,
.can_sleep = true,
diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
index eaa71d440ccf..901b5ccb032d 100644
--- a/drivers/gpio/gpio-ws16c48.c
+++ b/drivers/gpio/gpio-ws16c48.c
@@ -46,7 +46,6 @@ MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
* @irq_mask: I/O bits affected by interrupts
* @flow_mask: IRQ flow type mask for the respective I/O bits
* @base: base port address of the GPIO device
- * @irq: Interrupt line number
*/
struct ws16c48_gpio {
struct gpio_chip chip;
@@ -56,7 +55,6 @@ struct ws16c48_gpio {
unsigned long irq_mask;
unsigned long flow_mask;
unsigned base;
- unsigned irq;
};
static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -155,6 +153,46 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
+static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
+{
+ struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
+ unsigned int i;
+ const unsigned int gpio_reg_size = 8;
+ unsigned int port;
+ unsigned int iomask;
+ unsigned int bitmask;
+ unsigned long flags;
+
+ /* set bits are evaluated a gpio register size at a time */
+ for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
+ /* no more set bits in this mask word; skip to the next word */
+ if (!mask[BIT_WORD(i)]) {
+ i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
+ continue;
+ }
+
+ port = i / gpio_reg_size;
+
+ /* mask out GPIO configured for input */
+ iomask = mask[BIT_WORD(i)] & ~ws16c48gpio->io_state[port];
+ bitmask = iomask & bits[BIT_WORD(i)];
+
+ spin_lock_irqsave(&ws16c48gpio->lock, flags);
+
+ /* update output state data and set device gpio register */
+ ws16c48gpio->out_state[port] &= ~iomask;
+ ws16c48gpio->out_state[port] |= bitmask;
+ outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
+
+ spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
+
+ /* prepare for next gpio register set */
+ mask[BIT_WORD(i)] >>= gpio_reg_size;
+ bits[BIT_WORD(i)] >>= gpio_reg_size;
+ }
+}
+
static void ws16c48_irq_ack(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
@@ -303,6 +341,22 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+#define WS16C48_NGPIO 48
+static const char *ws16c48_names[WS16C48_NGPIO] = {
+ "Port 0 Bit 0", "Port 0 Bit 1", "Port 0 Bit 2", "Port 0 Bit 3",
+ "Port 0 Bit 4", "Port 0 Bit 5", "Port 0 Bit 6", "Port 0 Bit 7",
+ "Port 1 Bit 0", "Port 1 Bit 1", "Port 1 Bit 2", "Port 1 Bit 3",
+ "Port 1 Bit 4", "Port 1 Bit 5", "Port 1 Bit 6", "Port 1 Bit 7",
+ "Port 2 Bit 0", "Port 2 Bit 1", "Port 2 Bit 2", "Port 2 Bit 3",
+ "Port 2 Bit 4", "Port 2 Bit 5", "Port 2 Bit 6", "Port 2 Bit 7",
+ "Port 3 Bit 0", "Port 3 Bit 1", "Port 3 Bit 2", "Port 3 Bit 3",
+ "Port 3 Bit 4", "Port 3 Bit 5", "Port 3 Bit 6", "Port 3 Bit 7",
+ "Port 4 Bit 0", "Port 4 Bit 1", "Port 4 Bit 2", "Port 4 Bit 3",
+ "Port 4 Bit 4", "Port 4 Bit 5", "Port 4 Bit 6", "Port 4 Bit 7",
+ "Port 5 Bit 0", "Port 5 Bit 1", "Port 5 Bit 2", "Port 5 Bit 3",
+ "Port 5 Bit 4", "Port 5 Bit 5", "Port 5 Bit 6", "Port 5 Bit 7"
+};
+
static int ws16c48_probe(struct device *dev, unsigned int id)
{
struct ws16c48_gpio *ws16c48gpio;
@@ -323,20 +377,19 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
ws16c48gpio->chip.parent = dev;
ws16c48gpio->chip.owner = THIS_MODULE;
ws16c48gpio->chip.base = -1;
- ws16c48gpio->chip.ngpio = 48;
+ ws16c48gpio->chip.ngpio = WS16C48_NGPIO;
+ ws16c48gpio->chip.names = ws16c48_names;
ws16c48gpio->chip.get_direction = ws16c48_gpio_get_direction;
ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input;
ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
ws16c48gpio->chip.get = ws16c48_gpio_get;
ws16c48gpio->chip.set = ws16c48_gpio_set;
+ ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
ws16c48gpio->base = base[id];
- ws16c48gpio->irq = irq[id];
spin_lock_init(&ws16c48gpio->lock);
- dev_set_drvdata(dev, ws16c48gpio);
-
- err = gpiochip_add_data(&ws16c48gpio->chip, ws16c48gpio);
+ err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
@@ -353,31 +406,17 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
handle_edge_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(dev, "Could not add irqchip (%d)\n", err);
- goto err_gpiochip_remove;
+ return err;
}
- err = request_irq(irq[id], ws16c48_irq_handler, IRQF_SHARED, name,
- ws16c48gpio);
+ err = devm_request_irq(dev, irq[id], ws16c48_irq_handler, IRQF_SHARED,
+ name, ws16c48gpio);
if (err) {
dev_err(dev, "IRQ handler registering failed (%d)\n", err);
- goto err_gpiochip_remove;
+ return err;
}
return 0;
-
-err_gpiochip_remove:
- gpiochip_remove(&ws16c48gpio->chip);
- return err;
-}
-
-static int ws16c48_remove(struct device *dev, unsigned int id)
-{
- struct ws16c48_gpio *const ws16c48gpio = dev_get_drvdata(dev);
-
- free_irq(ws16c48gpio->irq, ws16c48gpio);
- gpiochip_remove(&ws16c48gpio->chip);
-
- return 0;
}
static struct isa_driver ws16c48_driver = {
@@ -385,7 +424,6 @@ static struct isa_driver ws16c48_driver = {
.driver = {
.name = "ws16c48"
},
- .remove = ws16c48_remove
};
module_isa_driver(ws16c48_driver, num_ws16c48);
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index a3faefa44f68..9b37a3692b3f 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -416,9 +416,8 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
/*
- * ActiveLow is only specified for GpioInt resource. If
- * GpioIo is used then the only way to set the flag is
- * to use _DSD "gpios" property.
+ * Polarity and triggering are only specified for GpioInt
+ * resource.
* Note: we expect here:
* - ACPI_ACTIVE_LOW == GPIO_ACTIVE_LOW
* - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 92b185f19232..975b9f6cf408 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -160,6 +160,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
* of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API
* @np: device node to get GPIO from
* @chip: GPIO chip whose hog is parsed
+ * @idx: Index of the GPIO to parse
* @name: GPIO line name
* @lflags: gpio_lookup_flags - returned from of_find_gpio() or
* of_parse_own_gpio()
@@ -170,7 +171,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
*/
static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
struct gpio_chip *chip,
- const char **name,
+ unsigned int idx, const char **name,
enum gpio_lookup_flags *lflags,
enum gpiod_flags *dflags)
{
@@ -178,6 +179,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
enum of_gpio_flags xlate_flags;
struct of_phandle_args gpiospec;
struct gpio_desc *desc;
+ unsigned int i;
u32 tmp;
int ret;
@@ -196,9 +198,12 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
gpiospec.np = chip_np;
gpiospec.args_count = tmp;
- ret = of_property_read_u32_array(np, "gpios", gpiospec.args, tmp);
- if (ret)
- return ERR_PTR(ret);
+ for (i = 0; i < tmp; i++) {
+ ret = of_property_read_u32_index(np, "gpios", idx * tmp + i,
+ &gpiospec.args[i]);
+ if (ret)
+ return ERR_PTR(ret);
+ }
desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, &xlate_flags);
if (IS_ERR(desc))
@@ -240,20 +245,24 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
const char *name;
enum gpio_lookup_flags lflags;
enum gpiod_flags dflags;
+ unsigned int i;
int ret;
for_each_available_child_of_node(chip->of_node, np) {
if (!of_property_read_bool(np, "gpio-hog"))
continue;
- desc = of_parse_own_gpio(np, chip, &name, &lflags, &dflags);
- if (IS_ERR(desc))
- continue;
+ for (i = 0;; i++) {
+ desc = of_parse_own_gpio(np, chip, i, &name, &lflags,
+ &dflags);
+ if (IS_ERR(desc))
+ break;
- ret = gpiod_hog(desc, name, lflags, dflags);
- if (ret < 0) {
- of_node_put(np);
- return ret;
+ ret = gpiod_hog(desc, name, lflags, dflags);
+ if (ret < 0) {
+ of_node_put(np);
+ return ret;
+ }
}
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index a07ae9e37930..8b4d721d6d63 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1,3 +1,4 @@
+#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -982,7 +983,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp)
struct gpio_device, chrdev);
/* Fail on open if the backing gpiochip is gone */
- if (!gdev || !gdev->chip)
+ if (!gdev->chip)
return -ENODEV;
get_device(&gdev->dev);
filp->private_data = gdev;
@@ -1001,8 +1002,6 @@ static int gpio_chrdev_release(struct inode *inode, struct file *filp)
struct gpio_device *gdev = container_of(inode->i_cdev,
struct gpio_device, chrdev);
- if (!gdev)
- return -ENODEV;
put_device(&gdev->dev);
return 0;
}
@@ -1423,8 +1422,7 @@ void devm_gpiochip_remove(struct device *dev, struct gpio_chip *chip)
ret = devres_release(dev, devm_gpio_chip_release,
devm_gpio_chip_match, chip);
- if (!ret)
- WARN_ON(ret);
+ WARN_ON(ret);
}
EXPORT_SYMBOL_GPL(devm_gpiochip_remove);
@@ -1876,6 +1874,19 @@ void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset)
}
EXPORT_SYMBOL_GPL(gpiochip_generic_free);
+/**
+ * gpiochip_generic_config() - apply configuration for a pin
+ * @chip: the gpiochip owning the GPIO
+ * @offset: the offset of the GPIO to apply the configuration
+ * @config: the configuration to be applied
+ */
+int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config)
+{
+ return pinctrl_gpio_set_config(chip->gpiodev->base + offset, config);
+}
+EXPORT_SYMBOL_GPL(gpiochip_generic_config);
+
#ifdef CONFIG_PINCTRL
/**
@@ -2264,6 +2275,14 @@ int gpiod_direction_input(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_direction_input);
+static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset,
+ enum pin_config_param mode)
+{
+ unsigned long config = { PIN_CONF_PACKED(mode, 0) };
+
+ return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
+}
+
static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{
struct gpio_chip *gc = desc->gdev->chip;
@@ -2280,32 +2299,25 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
/* First see if we can enable open drain in hardware */
- if (gc->set_single_ended) {
- ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
- LINE_MODE_OPEN_DRAIN);
- if (!ret)
- goto set_output_value;
- }
+ ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+ PIN_CONFIG_DRIVE_OPEN_DRAIN);
+ if (!ret)
+ goto set_output_value;
/* Emulate open drain by not actively driving the line high */
if (val)
return gpiod_direction_input(desc);
}
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
- if (gc->set_single_ended) {
- ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
- LINE_MODE_OPEN_SOURCE);
- if (!ret)
- goto set_output_value;
- }
+ ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+ PIN_CONFIG_DRIVE_OPEN_SOURCE);
+ if (!ret)
+ goto set_output_value;
/* Emulate open source by not actively driving the line low */
if (!val)
return gpiod_direction_input(desc);
} else {
- /* Make sure to disable open drain/source hardware, if any */
- if (gc->set_single_ended)
- gc->set_single_ended(gc,
- gpio_chip_hwgpio(desc),
- LINE_MODE_PUSH_PULL);
+ gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+ PIN_CONFIG_DRIVE_PUSH_PULL);
}
set_output_value:
@@ -2376,17 +2388,19 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output);
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{
struct gpio_chip *chip;
+ unsigned long config;
VALIDATE_DESC(desc);
chip = desc->gdev->chip;
- if (!chip->set || !chip->set_debounce) {
+ if (!chip->set || !chip->set_config) {
gpiod_dbg(desc,
- "%s: missing set() or set_debounce() operations\n",
+ "%s: missing set() or set_config() operations\n",
__func__);
return -ENOTSUPP;
}
- return chip->set_debounce(chip, gpio_chip_hwgpio(desc), debounce);
+ config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce);
+ return chip->set_config(chip, gpio_chip_hwgpio(desc), config);
}
EXPORT_SYMBOL_GPL(gpiod_set_debounce);
@@ -2570,18 +2584,11 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
if (chip->set_multiple) {
chip->set_multiple(chip, mask, bits);
} else {
- int i;
- for (i = 0; i < chip->ngpio; i++) {
- if (mask[BIT_WORD(i)] == 0) {
- /* no more set bits in this mask word;
- * skip ahead to the next word */
- i = (BIT_WORD(i) + 1) * BITS_PER_LONG - 1;
- continue;
- }
- /* set outputs if the corresponding mask bit is set */
- if (__test_and_clear_bit(i, mask))
- chip->set(chip, i, test_bit(i, bits));
- }
+ unsigned int i;
+
+ /* set outputs if the corresponding mask bit is set */
+ for_each_set_bit(i, mask, chip->ngpio)
+ chip->set(chip, i, test_bit(i, bits));
}
}
@@ -3309,6 +3316,8 @@ EXPORT_SYMBOL_GPL(gpiod_get_index);
* fwnode_get_named_gpiod - obtain a GPIO from firmware node
* @fwnode: handle of the firmware node
* @propname: name of the firmware property representing the GPIO
+ * @index: index of the GPIO to obtain in the consumer
+ * @dflags: GPIO initialization flags
*
* This function can be used for drivers that get their configuration
* from firmware.
@@ -3317,12 +3326,18 @@ 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.
*
+ * On successfull request the GPIO pin is configured in accordance with
+ * provided @dflags.
+ *
* In case of error an ERR_PTR() is returned.
*/
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
- const char *propname)
+ const char *propname, int index,
+ enum gpiod_flags dflags,
+ const char *label)
{
struct gpio_desc *desc = ERR_PTR(-ENODEV);
+ unsigned long lflags = 0;
bool active_low = false;
bool single_ended = false;
int ret;
@@ -3333,8 +3348,8 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
if (is_of_node(fwnode)) {
enum of_gpio_flags flags;
- desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname, 0,
- &flags);
+ desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname,
+ index, &flags);
if (!IS_ERR(desc)) {
active_low = flags & OF_GPIO_ACTIVE_LOW;
single_ended = flags & OF_GPIO_SINGLE_ENDED;
@@ -3342,7 +3357,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
} else if (is_acpi_node(fwnode)) {
struct acpi_gpio_info info;
- desc = acpi_node_get_gpiod(fwnode, propname, 0, &info);
+ desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
if (!IS_ERR(desc))
active_low = info.polarity == GPIO_ACTIVE_LOW;
}
@@ -3350,18 +3365,24 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
if (IS_ERR(desc))
return desc;
- ret = gpiod_request(desc, NULL);
+ ret = gpiod_request(desc, label);
if (ret)
return ERR_PTR(ret);
if (active_low)
- set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+ lflags |= GPIO_ACTIVE_LOW;
if (single_ended) {
if (active_low)
- set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+ lflags |= GPIO_OPEN_DRAIN;
else
- set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+ lflags |= GPIO_OPEN_SOURCE;
+ }
+
+ ret = gpiod_configure_flags(desc, propname, lflags, dflags);
+ if (ret < 0) {
+ gpiod_put(desc);
+ return ERR_PTR(ret);
}
return desc;
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index d10eaf520860..2495b7ee1b42 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -76,7 +76,8 @@ struct gpio_device {
/**
* struct acpi_gpio_info - ACPI GPIO specific information
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
- * @active_low: in case of @gpioint, the pin is active low
+ * @polarity: interrupt polarity as provided by ACPI
+ * @triggering: triggering type as provided by ACPI
*/
struct acpi_gpio_info {
bool gpioint;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 9c92cdf196e3..da3d362f21b1 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -485,7 +485,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
spin_lock_init(&bdata->lock);
if (child) {
- bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child);
+ bdata->gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL,
+ child,
+ GPIOD_IN,
+ desc);
if (IS_ERR(bdata->gpiod)) {
error = PTR_ERR(bdata->gpiod);
if (error == -ENOENT) {
@@ -500,13 +503,6 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
error);
return error;
}
- } else {
- error = gpiod_direction_input(bdata->gpiod);
- if (error) {
- dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
- desc_to_gpio(bdata->gpiod), error);
- return error;
- }
}
} else if (gpio_is_valid(button->gpio)) {
/*
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 4fce43a6a0e0..edc7262103b9 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -303,8 +303,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
return -EINVAL;
}
- bdata->gpiod = devm_get_gpiod_from_child(dev, NULL,
- child);
+ bdata->gpiod = devm_fwnode_get_gpiod_from_child(dev,
+ NULL, child,
+ GPIOD_IN,
+ button->desc);
if (IS_ERR(bdata->gpiod)) {
error = PTR_ERR(bdata->gpiod);
if (error != -EPROBE_DEFER)
@@ -314,14 +316,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
fwnode_handle_put(child);
return error;
}
-
- error = gpiod_direction_input(bdata->gpiod);
- if (error) {
- dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
- desc_to_gpio(bdata->gpiod), error);
- fwnode_handle_put(child);
- return error;
- }
} else if (gpio_is_valid(button->gpio)) {
/*
* Legacy GPIO number so request the GPIO here and
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index d400dcaf4d29..066fc7590729 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -174,12 +174,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
const char *state = NULL;
struct device_node *np = to_of_node(child);
- led.gpiod = devm_get_gpiod_from_child(dev, NULL, child);
- if (IS_ERR(led.gpiod)) {
- fwnode_handle_put(child);
- return ERR_CAST(led.gpiod);
- }
-
ret = fwnode_property_read_string(child, "label", &led.name);
if (ret && IS_ENABLED(CONFIG_OF) && np)
led.name = np->name;
@@ -188,6 +182,14 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
return ERR_PTR(-EINVAL);
}
+ led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child,
+ GPIOD_ASIS,
+ led.name);
+ if (IS_ERR(led.gpiod)) {
+ fwnode_handle_put(child);
+ return ERR_CAST(led.gpiod);
+ }
+
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
index a5331fdfc795..810a81786f62 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
@@ -1106,7 +1106,7 @@ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev,
struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
int i;
enum pin_config_param param;
- u16 arg;
+ u32 arg;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
@@ -1222,7 +1222,7 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev,
struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
int i, j;
enum pin_config_param param;
- u16 arg;
+ u32 arg;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
@@ -1292,7 +1292,7 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev,
struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
int i;
enum pin_config_param param;
- u16 arg;
+ u32 arg;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
index 5d1e505c3c63..3ca925dfefd1 100644
--- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -619,7 +619,7 @@ static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
{
struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
- u16 arg;
+ u32 arg;
unsigned i, gpio = iproc_pin_to_gpio(pin);
int ret = -ENOTSUPP;
diff --git a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
index 13a4c2774157..4b5cf0e0f16e 100644
--- a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
@@ -703,7 +703,7 @@ static int ns2_pin_get_enable(struct pinctrl_dev *pctrldev, unsigned int pin)
}
static int ns2_pin_set_slew(struct pinctrl_dev *pctrldev, unsigned int pin,
- u16 slew)
+ u32 slew)
{
struct ns2_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrldev);
struct ns2_pin *pin_data = pctrldev->desc->pins[pin].drv_data;
@@ -793,7 +793,7 @@ static void ns2_pin_get_pull(struct pinctrl_dev *pctrldev,
}
static int ns2_pin_set_strength(struct pinctrl_dev *pctrldev, unsigned int pin,
- u16 strength)
+ u32 strength)
{
struct ns2_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrldev);
struct ns2_pin *pin_data = pctrldev->desc->pins[pin].drv_data;
@@ -904,7 +904,7 @@ static int ns2_pin_config_set(struct pinctrl_dev *pctrldev, unsigned int pin,
struct ns2_pin *pin_data = pctrldev->desc->pins[pin].drv_data;
enum pin_config_param param;
unsigned int i;
- u16 arg;
+ u32 arg;
int ret = -ENOTSUPP;
if (pin_data->pin_conf.base == -1)
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
index c8deb8be1da7..91ea32dc1e7f 100644
--- a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
@@ -366,7 +366,7 @@ static const struct pinctrl_ops nsp_pctrl_ops = {
.dt_free_map = pinctrl_utils_free_map,
};
-static int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u16 slew)
+static int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u32 slew)
{
if (slew)
nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, true);
@@ -403,7 +403,7 @@ static void nsp_gpio_get_pull(struct nsp_gpio *chip, unsigned gpio,
}
static int nsp_gpio_set_strength(struct nsp_gpio *chip, unsigned gpio,
- u16 strength)
+ u32 strength)
{
u32 offset, shift, i;
u32 val;
@@ -522,7 +522,7 @@ static int nsp_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
{
struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
- u16 arg;
+ u32 arg;
unsigned int i, gpio;
int ret = -ENOTSUPP;
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index fb38e208f32d..597d4641e348 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -688,6 +688,35 @@ int pinctrl_gpio_direction_output(unsigned gpio)
}
EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
+/**
+ * pinctrl_gpio_set_config() - Apply config to given GPIO pin
+ * @gpio: the GPIO pin number from the GPIO subsystem number space
+ * @config: the configuration to apply to the GPIO
+ *
+ * This function should *ONLY* be used from gpiolib-based GPIO drivers, if
+ * they need to call the underlying pin controller to change GPIO config
+ * (for example set debounce time).
+ */
+int pinctrl_gpio_set_config(unsigned gpio, unsigned long config)
+{
+ unsigned long configs[] = { config };
+ struct pinctrl_gpio_range *range;
+ struct pinctrl_dev *pctldev;
+ int ret, pin;
+
+ ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+ if (ret)
+ return ret;
+
+ mutex_lock(&pctldev->mutex);
+ pin = gpio_to_pin(range, gpio);
+ ret = pinconf_set_config(pctldev, pin, configs, ARRAY_SIZE(configs));
+ mutex_unlock(&pctldev->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_gpio_set_config);
+
static struct pinctrl_state *find_state(struct pinctrl *p,
const char *name)
{
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 5e66860a5e67..f80134e3e0b6 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1059,7 +1059,7 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin,
}
static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
- enum pin_config_param param, u16 arg)
+ enum pin_config_param param, u32 arg)
{
void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
unsigned long flags;
@@ -1151,7 +1151,7 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin,
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
int i, ret;
- u16 arg;
+ u32 arg;
if (chv_pad_locked(pctrl, pin))
return -EBUSY;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index f9aef2ac03a1..3cf384f8b122 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -1054,6 +1054,18 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
return 0;
}
+static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config)
+{
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+ return mtk_gpio_set_debounce(chip, offset, debounce);
+}
+
static const struct gpio_chip mtk_gpio_chip = {
.owner = THIS_MODULE,
.request = gpiochip_generic_request,
@@ -1064,7 +1076,7 @@ static const struct gpio_chip mtk_gpio_chip = {
.get = mtk_gpio_get,
.set = mtk_gpio_set,
.to_irq = mtk_gpio_to_irq,
- .set_debounce = mtk_gpio_set_debounce,
+ .set_config = mtk_gpio_set_config,
.of_gpio_n_cells = 2,
};
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 620c231a2889..cf1686e04378 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -260,7 +260,6 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
enum pin_config_param param;
unsigned int reg, bit;
int i, ret;
- u16 arg;
ret = meson_get_bank(pc, pin, &bank);
if (ret)
@@ -268,7 +267,6 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
- arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index 799048f3c8d4..c1c1ccc58267 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -200,6 +200,18 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
return 0;
}
+int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *configs, size_t nconfigs)
+{
+ const struct pinconf_ops *ops;
+
+ ops = pctldev->desc->confops;
+ if (!ops)
+ return -ENOTSUPP;
+
+ return ops->pin_config_set(pctldev, pin, configs, nconfigs);
+}
+
#ifdef CONFIG_DEBUG_FS
static void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev,
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index 55c75780b3b2..bf8aff9abf32 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -20,6 +20,9 @@ int pinconf_map_to_setting(struct pinctrl_map const *map,
void pinconf_free_setting(struct pinctrl_setting const *setting);
int pinconf_apply_setting(struct pinctrl_setting const *setting);
+int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *configs, size_t nconfigs);
+
/*
* You will only be interested in these if you're using PINCONF
* so don't supply any stubs for these.
@@ -56,6 +59,12 @@ static inline int pinconf_apply_setting(struct pinctrl_setting const *setting)
return 0;
}
+static inline int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *configs, size_t nconfigs)
+{
+ return -ENOTSUPP;
+}
+
#endif
#if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS)
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 537b52055756..5391db7b368d 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -164,6 +164,18 @@ static int amd_gpio_set_debounce(struct gpio_chip *gc, unsigned offset,
return ret;
}
+static int amd_gpio_set_config(struct gpio_chip *gc, unsigned offset,
+ unsigned long config)
+{
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+ return amd_gpio_set_debounce(gc, offset, debounce);
+}
+
#ifdef CONFIG_DEBUG_FS
static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
{
@@ -758,7 +770,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
gpio_dev->gc.direction_output = amd_gpio_direction_output;
gpio_dev->gc.get = amd_gpio_get_value;
gpio_dev->gc.set = amd_gpio_set_value;
- gpio_dev->gc.set_debounce = amd_gpio_set_debounce;
+ gpio_dev->gc.set_config = amd_gpio_set_config;
gpio_dev->gc.dbg_show = amd_gpio_dbg_show;
gpio_dev->gc.base = 0;
diff --git a/drivers/pinctrl/pinctrl-da850-pupd.c b/drivers/pinctrl/pinctrl-da850-pupd.c
index b36a90a3f3e4..44d5f5f5b07f 100644
--- a/drivers/pinctrl/pinctrl-da850-pupd.c
+++ b/drivers/pinctrl/pinctrl-da850-pupd.c
@@ -113,7 +113,6 @@ static int da850_pupd_pin_config_group_set(struct pinctrl_dev *pctldev,
struct da850_pupd_data *data = pinctrl_dev_get_drvdata(pctldev);
u32 ena, sel;
enum pin_config_param param;
- u16 arg;
int i;
ena = readl(data->base + DA850_PUPD_ENA);
@@ -121,7 +120,6 @@ static int da850_pupd_pin_config_group_set(struct pinctrl_dev *pctldev,
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
- arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c
index e053f1fa5512..d090f37ca4a1 100644
--- a/drivers/pinctrl/pinctrl-lpc18xx.c
+++ b/drivers/pinctrl/pinctrl-lpc18xx.c
@@ -904,7 +904,7 @@ static int lpc18xx_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
static int lpc18xx_pconf_set_usb1(struct pinctrl_dev *pctldev,
enum pin_config_param param,
- u16 param_val, u32 *reg)
+ u32 param_val, u32 *reg)
{
switch (param) {
case PIN_CONFIG_LOW_POWER_MODE:
@@ -932,7 +932,7 @@ static int lpc18xx_pconf_set_usb1(struct pinctrl_dev *pctldev,
static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev,
enum pin_config_param param,
- u16 param_val, u32 *reg,
+ u32 param_val, u32 *reg,
unsigned pin)
{
u8 shift;
@@ -982,7 +982,7 @@ static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev,
}
static int lpc18xx_pconf_set_gpio_pin_int(struct pinctrl_dev *pctldev,
- u16 param_val, unsigned pin)
+ u32 param_val, unsigned pin)
{
struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
u32 val, reg_val, reg_offset = LPC18XX_SCU_PINTSEL0;
@@ -1008,7 +1008,7 @@ static int lpc18xx_pconf_set_gpio_pin_int(struct pinctrl_dev *pctldev,
}
static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev, unsigned param,
- u16 param_val, u32 *reg, unsigned pin,
+ u32 param_val, u32 *reg, unsigned pin,
struct lpc18xx_pin_caps *pin_cap)
{
switch (param) {
@@ -1088,7 +1088,7 @@ static int lpc18xx_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
struct lpc18xx_pin_caps *pin_cap;
enum pin_config_param param;
- u16 param_val;
+ u32 param_val;
u32 reg;
int ret;
int i;
diff --git a/drivers/pinctrl/pinctrl-max77620.c b/drivers/pinctrl/pinctrl-max77620.c
index d9ff53e8f715..b8d2180a2bea 100644
--- a/drivers/pinctrl/pinctrl-max77620.c
+++ b/drivers/pinctrl/pinctrl-max77620.c
@@ -402,7 +402,7 @@ static int max77620_pinconf_set(struct pinctrl_dev *pctldev,
struct device *dev = mpci->dev;
struct max77620_fps_config *fps_config;
int param;
- u16 param_val;
+ u32 param_val;
unsigned int val;
unsigned int pu_val;
unsigned int pd_val;
diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c
index a30146da7ffd..4d6a5015b927 100644
--- a/drivers/pinctrl/pinctrl-palmas.c
+++ b/drivers/pinctrl/pinctrl-palmas.c
@@ -860,7 +860,7 @@ static int palmas_pinconf_set(struct pinctrl_dev *pctldev,
{
struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
- u16 param_val;
+ u32 param_val;
const struct palmas_pingroup *g;
const struct palmas_pin_info *opt;
int ret;
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 08765f58253c..7813599e43fa 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -1441,7 +1441,7 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
enum pin_config_param param;
- u16 arg;
+ u32 arg;
int i;
int rc;
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index a5a0392ab817..f71f2e813ea6 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -622,7 +622,7 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
struct pcs_function *func;
unsigned offset = 0, shift = 0, i, data, ret;
- u16 arg;
+ u32 arg;
int j;
ret = pcs_get_function(pctldev, pin, &func);
diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c
index 29fb7403d24e..7450f5118445 100644
--- a/drivers/pinctrl/pinctrl-sx150x.c
+++ b/drivers/pinctrl/pinctrl-sx150x.c
@@ -424,41 +424,6 @@ static int sx150x_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!(value & BIT(offset));
}
-static int sx150x_gpio_set_single_ended(struct gpio_chip *chip,
- unsigned int offset,
- enum single_ended_mode mode)
-{
- struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
- int ret;
-
- switch (mode) {
- case LINE_MODE_PUSH_PULL:
- if (pctl->data->model != SX150X_789 ||
- sx150x_pin_is_oscio(pctl, offset))
- return 0;
-
- ret = regmap_write_bits(pctl->regmap,
- pctl->data->pri.x789.reg_drain,
- BIT(offset), 0);
- break;
-
- case LINE_MODE_OPEN_DRAIN:
- if (pctl->data->model != SX150X_789 ||
- sx150x_pin_is_oscio(pctl, offset))
- return -ENOTSUPP;
-
- ret = regmap_write_bits(pctl->regmap,
- pctl->data->pri.x789.reg_drain,
- BIT(offset), BIT(offset));
- break;
- default:
- ret = -ENOTSUPP;
- break;
- }
-
- return ret;
-}
-
static int __sx150x_gpio_set(struct sx150x_pinctrl *pctl, unsigned int offset,
int value)
{
@@ -811,16 +776,26 @@ static int sx150x_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- ret = sx150x_gpio_set_single_ended(&pctl->gpio,
- pin, LINE_MODE_OPEN_DRAIN);
+ if (pctl->data->model != SX150X_789 ||
+ sx150x_pin_is_oscio(pctl, pin))
+ return -ENOTSUPP;
+
+ ret = regmap_write_bits(pctl->regmap,
+ pctl->data->pri.x789.reg_drain,
+ BIT(pin), BIT(pin));
if (ret < 0)
return ret;
break;
case PIN_CONFIG_DRIVE_PUSH_PULL:
- ret = sx150x_gpio_set_single_ended(&pctl->gpio,
- pin, LINE_MODE_PUSH_PULL);
+ if (pctl->data->model != SX150X_789 ||
+ sx150x_pin_is_oscio(pctl, pin))
+ return 0;
+
+ ret = regmap_write_bits(pctl->regmap,
+ pctl->data->pri.x789.reg_drain,
+ BIT(pin), 0);
if (ret < 0)
return ret;
@@ -1178,7 +1153,7 @@ static int sx150x_probe(struct i2c_client *client,
pctl->gpio.direction_output = sx150x_gpio_direction_output;
pctl->gpio.get = sx150x_gpio_get;
pctl->gpio.set = sx150x_gpio_set;
- pctl->gpio.set_single_ended = sx150x_gpio_set_single_ended;
+ pctl->gpio.set_config = gpiochip_generic_config;
pctl->gpio.parent = dev;
#ifdef CONFIG_OF_GPIO
pctl->gpio.of_node = dev->of_node;
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c
index 7f3041697813..82b8a429743d 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas7.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c
@@ -5322,7 +5322,8 @@ static int atlas7_pin_config_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *configs,
unsigned num_configs)
{
- u16 param, arg;
+ u16 param;
+ u32 arg;
int idx, err;
for (idx = 0; idx < num_configs; idx++) {
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 207a8de4e1ed..b38f7492aba0 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -540,7 +540,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
enum pin_config_param param;
unsigned long flags;
u32 offset, shift, mask, reg;
- u16 arg, val;
+ u32 arg, val;
int ret;
param = pinconf_to_config_param(configs[i]);
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
index 9b2ee717bccc..546f23c9040c 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
@@ -297,7 +297,7 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
const struct pin_desc *desc,
- enum pin_config_param param, u16 arg)
+ enum pin_config_param param, u32 arg)
{
struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
enum uniphier_pin_pull_dir pull_dir =
@@ -468,7 +468,7 @@ static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
for (i = 0; i < num_configs; i++) {
enum pin_config_param param =
pinconf_to_config_param(configs[i]);
- u16 arg = pinconf_to_config_argument(configs[i]);
+ u32 arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index 270ca2a47a8c..c207e60b734f 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -428,7 +428,7 @@ static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
{
struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
- u16 arg;
+ u32 arg;
u32 bank = WMT_BANK_FROM_PIN(pin);
u32 bit = WMT_BIT_FROM_PIN(pin);
u32 reg_pull_en = data->banks[bank].reg_pull_en;
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 51e52446eacb..73594f38c453 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -610,7 +610,7 @@ static int rtc_pinconf_set(struct pinctrl_dev *pctldev,
struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
u32 val;
unsigned int param;
- u16 param_val;
+ u32 param_val;
int i;
rtc->type->unlock(rtc);
diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c
index 0eabfe1135b5..ee5f998b174f 100644
--- a/drivers/staging/greybus/gpio.c
+++ b/drivers/staging/greybus/gpio.c
@@ -474,17 +474,20 @@ static void gb_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
gb_gpio_set_value_operation(ggc, (u8)offset, !!value);
}
-static int gb_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
- unsigned int debounce)
+static int gb_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
- u16 usec;
+ u32 debounce;
+ if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
if (debounce > U16_MAX)
return -EINVAL;
- usec = (u16)debounce;
- return gb_gpio_set_debounce_operation(ggc, (u8)offset, usec);
+ return gb_gpio_set_debounce_operation(ggc, (u8)offset, (u16)debounce);
}
static int gb_gpio_controller_setup(struct gb_gpio_controller *ggc)
@@ -690,7 +693,7 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev,
gpio->direction_output = gb_gpio_direction_output;
gpio->get = gb_gpio_get;
gpio->set = gb_gpio_set;
- gpio->set_debounce = gb_gpio_set_debounce;
+ gpio->set_config = gb_gpio_set_config;
gpio->to_irq = gb_gpio_to_irq;
gpio->base = -1; /* Allocate base dynamically */
gpio->ngpio = ggc->line_max + 1;
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index bcf1d33e6ffe..c334bcc59c64 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -575,12 +575,13 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
pinctrl_select_state(ascport->pinctrl,
ascport->states[NO_HW_FLOWCTRL]);
- gpiod = devm_get_gpiod_from_child(port->dev, "rts",
- &np->fwnode);
- if (!IS_ERR(gpiod)) {
- gpiod_direction_output(gpiod, 0);
+ gpiod = devm_fwnode_get_gpiod_from_child(port->dev,
+ "rts",
+ &np->fwnode,
+ GPIOD_OUT_LOW,
+ np->name);
+ if (!IS_ERR(gpiod))
ascport->rts = gpiod;
- }
}
}
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fbe69465eefa..0c55e7f64269 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -1331,17 +1331,20 @@ static int cp210x_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
return 0;
}
-static int cp210x_gpio_set_single_ended(struct gpio_chip *gc, unsigned int gpio,
- enum single_ended_mode mode)
+static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
+ unsigned long config)
{
struct usb_serial *serial = gpiochip_get_data(gc);
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+ enum pin_config_param param = pinconf_to_config_param(config);
/* Succeed only if in correct mode (this can't be set at runtime) */
- if ((mode == LINE_MODE_PUSH_PULL) && (priv->gpio_mode & BIT(gpio)))
+ if ((param == PIN_CONFIG_DRIVE_PUSH_PULL) &&
+ (priv->gpio_mode & BIT(gpio)))
return 0;
- if ((mode == LINE_MODE_OPEN_DRAIN) && !(priv->gpio_mode & BIT(gpio)))
+ if ((param == PIN_CONFIG_DRIVE_OPEN_DRAIN) &&
+ !(priv->gpio_mode & BIT(gpio)))
return 0;
return -ENOTSUPP;
@@ -1404,7 +1407,7 @@ static int cp2105_shared_gpio_init(struct usb_serial *serial)
priv->gc.direction_output = cp210x_gpio_direction_output;
priv->gc.get = cp210x_gpio_get;
priv->gc.set = cp210x_gpio_set;
- priv->gc.set_single_ended = cp210x_gpio_set_single_ended;
+ priv->gc.set_config = cp210x_gpio_set_config;
priv->gc.owner = THIS_MODULE;
priv->gc.parent = &serial->interface->dev;
priv->gc.base = -1;
diff --git a/drivers/video/fbdev/amba-clcd-nomadik.c b/drivers/video/fbdev/amba-clcd-nomadik.c
index a9a8f7543454..cd2db1113e67 100644
--- a/drivers/video/fbdev/amba-clcd-nomadik.c
+++ b/drivers/video/fbdev/amba-clcd-nomadik.c
@@ -184,32 +184,31 @@ static void tpg110_init(struct device *dev, struct device_node *np,
{
dev_info(dev, "TPG110 display init\n");
- grestb = devm_get_gpiod_from_child(dev, "grestb", &np->fwnode);
+ /* This asserts the GRESTB signal, putting the display into reset */
+ grestb = devm_fwnode_get_gpiod_from_child(dev, "grestb", &np->fwnode,
+ GPIOD_OUT_HIGH, "grestb");
if (IS_ERR(grestb)) {
dev_err(dev, "no GRESTB GPIO\n");
return;
}
- /* This asserts the GRESTB signal, putting the display into reset */
- gpiod_direction_output(grestb, 1);
-
- scen = devm_get_gpiod_from_child(dev, "scen", &np->fwnode);
+ scen = devm_fwnode_get_gpiod_from_child(dev, "scen", &np->fwnode,
+ GPIOD_OUT_LOW, "scen");
if (IS_ERR(scen)) {
dev_err(dev, "no SCEN GPIO\n");
return;
}
- gpiod_direction_output(scen, 0);
- scl = devm_get_gpiod_from_child(dev, "scl", &np->fwnode);
+ scl = devm_fwnode_get_gpiod_from_child(dev, "scl", &np->fwnode,
+ GPIOD_OUT_LOW, "scl");
if (IS_ERR(scl)) {
dev_err(dev, "no SCL GPIO\n");
return;
}
- gpiod_direction_output(scl, 0);
- sda = devm_get_gpiod_from_child(dev, "sda", &np->fwnode);
+ sda = devm_fwnode_get_gpiod_from_child(dev, "sda", &np->fwnode,
+ GPIOD_OUT_LOW, "sda");
if (IS_ERR(sda)) {
dev_err(dev, "no SDA GPIO\n");
return;
}
- gpiod_direction_output(sda, 0);
board->enable = tpg110_enable;
board->disable = tpg110_disable;
}
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index fb0fde686cb1..ea9b01d40017 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -135,10 +135,14 @@ int desc_to_gpio(const struct gpio_desc *desc);
struct fwnode_handle;
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
- const char *propname);
-struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
- const char *con_id,
- struct fwnode_handle *child);
+ const char *propname, int index,
+ enum gpiod_flags dflags,
+ const char *label);
+struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
+ const char *con_id, int index,
+ struct fwnode_handle *child,
+ enum gpiod_flags flags,
+ const char *label);
#else /* CONFIG_GPIOLIB */
static inline int gpiod_count(struct device *dev, const char *con_id)
@@ -411,20 +415,38 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
/* Child properties interface */
struct fwnode_handle;
-static inline struct gpio_desc *fwnode_get_named_gpiod(
- struct fwnode_handle *fwnode, const char *propname)
+static inline
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname, int index,
+ enum gpiod_flags dflags,
+ const char *label)
{
return ERR_PTR(-ENOSYS);
}
-static inline struct gpio_desc *devm_get_gpiod_from_child(
- struct device *dev, const char *con_id, struct fwnode_handle *child)
+static inline
+struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
+ const char *con_id, int index,
+ struct fwnode_handle *child,
+ enum gpiod_flags flags,
+ const char *label)
{
return ERR_PTR(-ENOSYS);
}
#endif /* CONFIG_GPIOLIB */
+static inline
+struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
+ const char *con_id,
+ struct fwnode_handle *child,
+ enum gpiod_flags flags,
+ const char *label)
+{
+ return devm_fwnode_get_index_gpiod_from_child(dev, con_id, 0, child,
+ flags, label);
+}
+
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index e973faba69dc..846f3b989480 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -8,6 +8,7 @@
#include <linux/irqdomain.h>
#include <linux/lockdep.h>
#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
struct gpio_desc;
struct of_phandle_args;
@@ -19,18 +20,6 @@ struct module;
#ifdef CONFIG_GPIOLIB
/**
- * enum single_ended_mode - mode for single ended operation
- * @LINE_MODE_PUSH_PULL: normal mode for a GPIO line, drive actively high/low
- * @LINE_MODE_OPEN_DRAIN: set line to be open drain
- * @LINE_MODE_OPEN_SOURCE: set line to be open source
- */
-enum single_ended_mode {
- LINE_MODE_PUSH_PULL,
- LINE_MODE_OPEN_DRAIN,
- LINE_MODE_OPEN_SOURCE,
-};
-
-/**
* struct gpio_chip - abstract a GPIO controller
* @label: a functional name for the GPIO device, such as a part
* number or the name of the SoC IP-block implementing it.
@@ -48,16 +37,8 @@ enum single_ended_mode {
* @get: returns value for signal "offset", 0=low, 1=high, or negative error
* @set: assigns output value for signal "offset"
* @set_multiple: assigns output values for multiple signals defined by "mask"
- * @set_debounce: optional hook for setting debounce time for specified gpio in
- * interrupt triggered gpio chips
- * @set_single_ended: optional hook for setting a line as open drain, open
- * source, or non-single ended (restore from open drain/source to normal
- * push-pull mode) this should be implemented if the hardware supports
- * open drain or open source settings. The GPIOlib will otherwise try
- * to emulate open drain/source by not actively driving lines high/low
- * if a consumer request this. The driver may return -ENOTSUPP if e.g.
- * it supports just open drain but not open source and is called
- * with LINE_MODE_OPEN_SOURCE as mode argument.
+ * @set_config: optional hook for all kinds of settings. Uses the same
+ * packed config format as generic pinconf.
* @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
* implementation may not sleep
* @dbg_show: optional routine to show contents in debugfs; default code
@@ -150,13 +131,9 @@ struct gpio_chip {
void (*set_multiple)(struct gpio_chip *chip,
unsigned long *mask,
unsigned long *bits);
- int (*set_debounce)(struct gpio_chip *chip,
- unsigned offset,
- unsigned debounce);
- int (*set_single_ended)(struct gpio_chip *chip,
- unsigned offset,
- enum single_ended_mode mode);
-
+ int (*set_config)(struct gpio_chip *chip,
+ unsigned offset,
+ unsigned long config);
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);
@@ -340,6 +317,8 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset);
void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset);
+int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
+ unsigned long config);
#ifdef CONFIG_PINCTRL
diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h
index d7e5d608faa7..a0f2aba72fa9 100644
--- a/include/linux/pinctrl/consumer.h
+++ b/include/linux/pinctrl/consumer.h
@@ -29,6 +29,7 @@ extern int pinctrl_request_gpio(unsigned gpio);
extern void pinctrl_free_gpio(unsigned gpio);
extern int pinctrl_gpio_direction_input(unsigned gpio);
extern int pinctrl_gpio_direction_output(unsigned gpio);
+extern int pinctrl_gpio_set_config(unsigned gpio, unsigned long config);
extern struct pinctrl * __must_check pinctrl_get(struct device *dev);
extern void pinctrl_put(struct pinctrl *p);
@@ -80,6 +81,11 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio)
return 0;
}
+static inline int pinctrl_gpio_set_config(unsigned gpio, unsigned long config)
+{
+ return 0;
+}
+
static inline struct pinctrl * __must_check pinctrl_get(struct device *dev)
{
return NULL;
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index 12343caa114e..7620eb127cff 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -12,12 +12,6 @@
#ifndef __LINUX_PINCTRL_PINCONF_GENERIC_H
#define __LINUX_PINCTRL_PINCONF_GENERIC_H
-/*
- * You shouldn't even be able to compile with these enums etc unless you're
- * using generic pin config. That is why this is defined out.
- */
-#ifdef CONFIG_GENERIC_PINCONF
-
/**
* enum pin_config_param - possible pin configuration parameters
* @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
@@ -92,6 +86,8 @@
* @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
* you need to pass in custom configurations to the pin controller, use
* PIN_CONFIG_END+1 as the base offset.
+ * @PIN_CONFIG_MAX: this is the maximum configuration value that can be
+ * presented using the packed format.
*/
enum pin_config_param {
PIN_CONFIG_BIAS_BUS_HOLD,
@@ -112,49 +108,53 @@ enum pin_config_param {
PIN_CONFIG_OUTPUT,
PIN_CONFIG_POWER_SOURCE,
PIN_CONFIG_SLEW_RATE,
- PIN_CONFIG_END = 0x7FFF,
-};
-
-#ifdef CONFIG_DEBUG_FS
-#define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \
- .has_arg = d }
-
-struct pin_config_item {
- const enum pin_config_param param;
- const char * const display;
- const char * const format;
- bool has_arg;
+ PIN_CONFIG_END = 0x7F,
+ PIN_CONFIG_MAX = 0xFF,
};
-#endif /* CONFIG_DEBUG_FS */
/*
* Helpful configuration macro to be used in tables etc.
*/
-#define PIN_CONF_PACKED(p, a) ((a << 16) | ((unsigned long) p & 0xffffUL))
+#define PIN_CONF_PACKED(p, a) ((a << 8) | ((unsigned long) p & 0xffUL))
/*
* The following inlines stuffs a configuration parameter and data value
* into and out of an unsigned long argument, as used by the generic pin config
- * system. We put the parameter in the lower 16 bits and the argument in the
- * upper 16 bits.
+ * system. We put the parameter in the lower 8 bits and the argument in the
+ * upper 24 bits.
*/
static inline enum pin_config_param pinconf_to_config_param(unsigned long config)
{
- return (enum pin_config_param) (config & 0xffffUL);
+ return (enum pin_config_param) (config & 0xffUL);
}
-static inline u16 pinconf_to_config_argument(unsigned long config)
+static inline u32 pinconf_to_config_argument(unsigned long config)
{
- return (enum pin_config_param) ((config >> 16) & 0xffffUL);
+ return (u32) ((config >> 8) & 0xffffffUL);
}
static inline unsigned long pinconf_to_config_packed(enum pin_config_param param,
- u16 argument)
+ u32 argument)
{
return PIN_CONF_PACKED(param, argument);
}
+#ifdef CONFIG_GENERIC_PINCONF
+
+#ifdef CONFIG_DEBUG_FS
+#define PCONFDUMP(a, b, c, d) { \
+ .param = a, .display = b, .format = c, .has_arg = d \
+ }
+
+struct pin_config_item {
+ const enum pin_config_param param;
+ const char * const display;
+ const char * const format;
+ bool has_arg;
+};
+#endif /* CONFIG_DEBUG_FS */
+
#ifdef CONFIG_OF
#include <linux/device.h>
diff --git a/include/linux/platform_data/gpio-davinci.h b/include/linux/platform_data/gpio-davinci.h
index 6ace3fd32b6a..90ae19ca828f 100644
--- a/include/linux/platform_data/gpio-davinci.h
+++ b/include/linux/platform_data/gpio-davinci.h
@@ -21,23 +21,28 @@
#include <asm-generic/gpio.h>
+#define MAX_REGS_BANKS 5
+
struct davinci_gpio_platform_data {
u32 ngpio;
u32 gpio_unbanked;
};
+struct davinci_gpio_irq_data {
+ void __iomem *regs;
+ struct davinci_gpio_controller *chip;
+ int bank_num;
+};
struct davinci_gpio_controller {
struct gpio_chip chip;
struct irq_domain *irq_domain;
/* Serialize access to GPIO registers */
spinlock_t lock;
- void __iomem *regs;
- void __iomem *set_data;
- void __iomem *clr_data;
- void __iomem *in_data;
+ void __iomem *regs[MAX_REGS_BANKS];
int gpio_unbanked;
- unsigned gpio_irq;
+ unsigned int base_irq;
+ unsigned int base;
};
/*
diff --git a/tools/gpio/.gitignore b/tools/gpio/.gitignore
new file mode 100644
index 000000000000..9e9dd4b681b2
--- /dev/null
+++ b/tools/gpio/.gitignore
@@ -0,0 +1,4 @@
+gpio-event-mon
+gpio-hammer
+lsgpio
+
diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c
index f1eab587dfea..4bcb234c0fca 100644
--- a/tools/gpio/gpio-hammer.c
+++ b/tools/gpio/gpio-hammer.c
@@ -38,7 +38,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines,
memset(&data.values, 0, sizeof(data.values));
ret = gpiotools_request_linehandle(device_name, lines, nlines,
GPIOHANDLE_REQUEST_OUTPUT, &data,
- "gpio-hammler");
+ "gpio-hammer");
if (ret < 0)
goto exit_error;
else