aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig29
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/TODO19
-rw-r--r--drivers/gpio/gpio-104-dio-48e.c250
-rw-r--r--drivers/gpio/gpio-104-idi-48.c158
-rw-r--r--drivers/gpio/gpio-104-idio-16.c61
-rw-r--r--drivers/gpio/gpio-74xx-mmio.c15
-rw-r--r--drivers/gpio/gpio-adnp.c19
-rw-r--r--drivers/gpio/gpio-adp5588.c45
-rw-r--r--drivers/gpio/gpio-amdpt.c10
-rw-r--r--drivers/gpio/gpio-bcm-kona.c10
-rw-r--r--drivers/gpio/gpio-brcmstb.c35
-rw-r--r--drivers/gpio/gpio-cadence.c12
-rw-r--r--drivers/gpio/gpio-crystalcove.c70
-rw-r--r--drivers/gpio/gpio-davinci.c83
-rw-r--r--drivers/gpio/gpio-dln2.c23
-rw-r--r--drivers/gpio/gpio-dwapb.c81
-rw-r--r--drivers/gpio/gpio-ftgpio010.c8
-rw-r--r--drivers/gpio/gpio-gpio-mm.c205
-rw-r--r--drivers/gpio/gpio-grgpio.c44
-rw-r--r--drivers/gpio/gpio-hlwd.c18
-rw-r--r--drivers/gpio/gpio-i8255.c287
-rw-r--r--drivers/gpio/gpio-i8255.h46
-rw-r--r--drivers/gpio/gpio-idt3243x.c12
-rw-r--r--drivers/gpio/gpio-ixp4xx.c49
-rw-r--r--drivers/gpio/gpio-loongson1.c8
-rw-r--r--drivers/gpio/gpio-lp3943.c16
-rw-r--r--drivers/gpio/gpio-lp873x.c10
-rw-r--r--drivers/gpio/gpio-lp87565.c10
-rw-r--r--drivers/gpio/gpio-max732x.c37
-rw-r--r--drivers/gpio/gpio-max77620.c9
-rw-r--r--drivers/gpio/gpio-menz127.c8
-rw-r--r--drivers/gpio/gpio-merrifield.c22
-rw-r--r--drivers/gpio/gpio-ml-ioh.c76
-rw-r--r--drivers/gpio/gpio-mlxbf2.c18
-rw-r--r--drivers/gpio/gpio-mmio.c22
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c5
-rw-r--r--drivers/gpio/gpio-msc313.c15
-rw-r--r--drivers/gpio/gpio-mvebu.c5
-rw-r--r--drivers/gpio/gpio-mxs.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c70
-rw-r--r--drivers/gpio/gpio-pca9570.c2
-rw-r--r--drivers/gpio/gpio-pcf857x.c49
-rw-r--r--drivers/gpio/gpio-pch.c43
-rw-r--r--drivers/gpio/gpio-pisosr.c10
-rw-r--r--drivers/gpio/gpio-pl061.c32
-rw-r--r--drivers/gpio/gpio-rcar.c38
-rw-r--r--drivers/gpio/gpio-realtek-otto.c147
-rw-r--r--drivers/gpio/gpio-rockchip.c32
-rw-r--r--drivers/gpio/gpio-sch.c35
-rw-r--r--drivers/gpio/gpio-sifive.c26
-rw-r--r--drivers/gpio/gpio-sim.c20
-rw-r--r--drivers/gpio/gpio-spear-spics.c5
-rw-r--r--drivers/gpio/gpio-syscon.c49
-rw-r--r--drivers/gpio/gpio-tb10x.c4
-rw-r--r--drivers/gpio/gpio-tegra.c15
-rw-r--r--drivers/gpio/gpio-tegra186.c128
-rw-r--r--drivers/gpio/gpio-thunderx.c17
-rw-r--r--drivers/gpio/gpio-tpic2810.c10
-rw-r--r--drivers/gpio/gpio-ts4800.c5
-rw-r--r--drivers/gpio/gpio-twl4030.c18
-rw-r--r--drivers/gpio/gpio-ucb1400.c20
-rw-r--r--drivers/gpio/gpio-vf610.c1
-rw-r--r--drivers/gpio/gpio-visconti.c15
-rw-r--r--drivers/gpio/gpio-vr41xx.c543
-rw-r--r--drivers/gpio/gpio-wcove.c10
-rw-r--r--drivers/gpio/gpio-winbond.c7
-rw-r--r--drivers/gpio/gpio-ws16c48.c125
-rw-r--r--drivers/gpio/gpio-xgs-iproc.c6
-rw-r--r--drivers/gpio/gpio-xilinx.c4
-rw-r--r--drivers/gpio/gpio-zevio.c25
-rw-r--r--drivers/gpio/gpiolib-acpi.c3
-rw-r--r--drivers/gpio/gpiolib-cdev.c412
-rw-r--r--drivers/gpio/gpiolib-devres.c32
-rw-r--r--drivers/gpio/gpiolib-of.c21
-rw-r--r--drivers/gpio/gpiolib-sysfs.c3
-rw-r--r--drivers/gpio/gpiolib.c205
-rw-r--r--drivers/gpio/gpiolib.h12
78 files changed, 2055 insertions, 1998 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ad99b96f6d79..0499c2facbb0 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -353,8 +353,8 @@ config GPIO_IOP
config GPIO_IXP4XX
bool "Intel IXP4xx GPIO"
- depends on ARM # For <asm/mach-types.h>
depends on ARCH_IXP4XX
+ depends on OF
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
select IRQ_DOMAIN_HIERARCHY
@@ -363,6 +363,7 @@ config GPIO_IXP4XX
IXP4xx series of chips.
If unsure, say N.
+
config GPIO_LOGICVC
tristate "Xylon LogiCVC GPIO support"
depends on MFD_SYSCON && OF
@@ -551,6 +552,7 @@ config GPIO_SAMA5D2_PIOBU
tristate "SAMA5D2 PIOBU GPIO support"
depends on MFD_SYSCON
depends on OF_GPIO
+ depends on ARCH_AT91 || COMPILE_TEST
select GPIO_SYSCON
help
Say yes here to use the PIOBU pins as GPIOs.
@@ -682,10 +684,10 @@ config GPIO_UNIPHIER
config GPIO_VF610
def_bool y
- depends on ARCH_MXC && SOC_VF610
+ depends on ARCH_MXC
select GPIOLIB_IRQCHIP
help
- Say yes here to support Vybrid vf610 GPIOs.
+ Say yes here to support i.MX or Vybrid vf610 GPIOs.
config GPIO_VISCONTI
tristate "Toshiba Visconti GPIO support"
@@ -697,12 +699,6 @@ config GPIO_VISCONTI
help
Say yes here to support GPIO on Tohisba Visconti.
-config GPIO_VR41XX
- tristate "NEC VR4100 series General-purpose I/O Unit support"
- depends on CPU_VR41XX
- help
- Say yes here to support the NEC VR4100 series General-purpose I/O Unit.
-
config GPIO_VX855
tristate "VIA VX855/VX875 GPIO"
depends on (X86 || COMPILE_TEST) && PCI
@@ -836,11 +832,24 @@ endmenu
menu "Port-mapped I/O GPIO drivers"
depends on X86 # Unconditional I/O space access
+config GPIO_I8255
+ tristate
+ help
+ Enables support for the i8255 interface library functions. The i8255
+ interface library provides functions to facilitate communication with
+ interfaces compatible with the venerable Intel 8255 Programmable
+ Peripheral Interface (PPI). The Intel 8255 PPI chip was first released
+ in the early 1970s but compatible interfaces are nowadays typically
+ found embedded in larger VLSI processing chips and FPGA components.
+
+ If built as a module its name will be gpio-i8255.
+
config GPIO_104_DIO_48E
tristate "ACCES 104-DIO-48E GPIO support"
depends on PC104
select ISA_BUS_API
select GPIOLIB_IRQCHIP
+ select GPIO_I8255
help
Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E,
104-DIO-24E). The base port addresses for the devices may be
@@ -864,6 +873,7 @@ config GPIO_104_IDI_48
depends on PC104
select ISA_BUS_API
select GPIOLIB_IRQCHIP
+ select GPIO_I8255
help
Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A,
104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for
@@ -884,6 +894,7 @@ config GPIO_GPIO_MM
tristate "Diamond Systems GPIO-MM GPIO support"
depends on PC104
select ISA_BUS_API
+ select GPIO_I8255
help
Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 30141fec12be..3fa4f3f93d85 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o
obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o
obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
+obj-$(CONFIG_GPIO_I8255) += gpio-i8255.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
@@ -170,7 +171,6 @@ obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o
obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o
-obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o
diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO
index b8b1473a5b1e..f87ff3fa8a53 100644
--- a/drivers/gpio/TODO
+++ b/drivers/gpio/TODO
@@ -178,3 +178,22 @@ discussed but the idea is to provide a low-level access point
for debugging and hacking and to expose all lines without the
need of any exporting. Also provide ample ammunition to shoot
oneself in the foot, because this is debugfs after all.
+
+
+Moving over to immutable irq_chip structures
+
+Most of the gpio chips implementing interrupt support rely on gpiolib
+intercepting some of the irq_chip callbacks, preventing the structures
+from being made read-only and forcing duplication of structures that
+should otherwise be unique.
+
+The solution is to call into the gpiolib code when needed (resource
+management, enable/disable or unmask/mask callbacks), and to let the
+core code know about that by exposing a flag (IRQCHIP_IMMUTABLE) in
+the irq_chip structure. The irq_chip structure can then be made unique
+and const.
+
+A small number of drivers have been converted (pl061, tegra186, msm,
+amd, apple), and can be used as examples of how to proceed with this
+conversion. Note that drivers using the generic irqchip framework
+cannot be converted yet, but watch this space!
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 6bf41040c41f..a41551870759 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -6,8 +6,7 @@
* This driver supports the following ACCES devices: 104-DIO-48E and
* 104-DIO-24E.
*/
-#include <linux/bitmap.h>
-#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -20,6 +19,11 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "gpio-i8255.h"
+
+MODULE_IMPORT_NS(I8255);
#define DIO48E_EXTENT 16
#define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT)
@@ -33,34 +37,54 @@ static unsigned int irq[MAX_NUM_DIO48E];
module_param_hw_array(irq, uint, irq, NULL, 0);
MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
+#define DIO48E_NUM_PPI 2
+
+/**
+ * struct dio48e_reg - device register structure
+ * @ppi: Programmable Peripheral Interface groups
+ * @enable_buffer: Enable/Disable Buffer groups
+ * @unused1: Unused
+ * @enable_interrupt: Write: Enable Interrupt
+ * Read: Disable Interrupt
+ * @unused2: Unused
+ * @enable_counter: Write: Enable Counter/Timer Addressing
+ * Read: Disable Counter/Timer Addressing
+ * @unused3: Unused
+ * @clear_interrupt: Clear Interrupt
+ */
+struct dio48e_reg {
+ struct i8255 ppi[DIO48E_NUM_PPI];
+ u8 enable_buffer[DIO48E_NUM_PPI];
+ u8 unused1;
+ u8 enable_interrupt;
+ u8 unused2;
+ u8 enable_counter;
+ u8 unused3;
+ u8 clear_interrupt;
+};
+
/**
* struct dio48e_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
- * @io_state: bit I/O state (whether bit is set to input or output)
- * @out_state: output bits state
- * @control: Control registers state
- * @lock: synchronization lock to prevent I/O race conditions
- * @base: base port address of the GPIO device
- * @irq_mask: I/O bits affected by interrupts
+ * @chip: instance of the gpio_chip
+ * @ppi_state: PPI device states
+ * @lock: synchronization lock to prevent I/O race conditions
+ * @reg: I/O address offset for the device registers
+ * @irq_mask: I/O bits affected by interrupts
*/
struct dio48e_gpio {
struct gpio_chip chip;
- unsigned char io_state[6];
- unsigned char out_state[6];
- unsigned char control[2];
+ struct i8255_state ppi_state[DIO48E_NUM_PPI];
raw_spinlock_t lock;
- unsigned int base;
+ struct dio48e_reg __iomem *reg;
unsigned char irq_mask;
};
static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
- const unsigned int port = offset / 8;
- const unsigned int mask = BIT(offset % 8);
- if (dio48egpio->io_state[port] & mask)
- return GPIO_LINE_DIRECTION_IN;
+ if (i8255_get_direction(dio48egpio->ppi_state, offset))
+ return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
}
@@ -68,38 +92,9 @@ static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset
static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
- const unsigned int io_port = offset / 8;
- const unsigned int control_port = io_port / 3;
- const unsigned int control_addr = dio48egpio->base + 3 + control_port * 4;
- unsigned long flags;
- unsigned int control;
- raw_spin_lock_irqsave(&dio48egpio->lock, flags);
-
- /* Check if configuring Port C */
- if (io_port == 2 || io_port == 5) {
- /* Port C can be configured by nibble */
- if (offset % 8 > 3) {
- dio48egpio->io_state[io_port] |= 0xF0;
- dio48egpio->control[control_port] |= BIT(3);
- } else {
- dio48egpio->io_state[io_port] |= 0x0F;
- dio48egpio->control[control_port] |= BIT(0);
- }
- } else {
- dio48egpio->io_state[io_port] |= 0xFF;
- if (io_port == 0 || io_port == 3)
- dio48egpio->control[control_port] |= BIT(4);
- else
- dio48egpio->control[control_port] |= BIT(1);
- }
-
- control = BIT(7) | dio48egpio->control[control_port];
- outb(control, control_addr);
- control &= ~BIT(7);
- outb(control, control_addr);
-
- raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
+ i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state,
+ offset);
return 0;
}
@@ -108,48 +103,9 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off
int value)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
- const unsigned int io_port = offset / 8;
- const unsigned int control_port = io_port / 3;
- const unsigned int mask = BIT(offset % 8);
- const unsigned int control_addr = dio48egpio->base + 3 + control_port * 4;
- const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
- unsigned long flags;
- unsigned int control;
- raw_spin_lock_irqsave(&dio48egpio->lock, flags);
-
- /* Check if configuring Port C */
- if (io_port == 2 || io_port == 5) {
- /* Port C can be configured by nibble */
- if (offset % 8 > 3) {
- dio48egpio->io_state[io_port] &= 0x0F;
- dio48egpio->control[control_port] &= ~BIT(3);
- } else {
- dio48egpio->io_state[io_port] &= 0xF0;
- dio48egpio->control[control_port] &= ~BIT(0);
- }
- } else {
- dio48egpio->io_state[io_port] &= 0x00;
- if (io_port == 0 || io_port == 3)
- dio48egpio->control[control_port] &= ~BIT(4);
- else
- dio48egpio->control[control_port] &= ~BIT(1);
- }
-
- if (value)
- dio48egpio->out_state[io_port] |= mask;
- else
- dio48egpio->out_state[io_port] &= ~mask;
-
- control = BIT(7) | dio48egpio->control[control_port];
- outb(control, control_addr);
-
- outb(dio48egpio->out_state[io_port], dio48egpio->base + out_port);
-
- control &= ~BIT(7);
- outb(control, control_addr);
-
- raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
+ i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state,
+ offset, value);
return 0;
}
@@ -157,47 +113,16 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off
static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
- const unsigned int port = offset / 8;
- const unsigned int mask = BIT(offset % 8);
- const unsigned int in_port = (port > 2) ? port + 1 : port;
- unsigned long flags;
- unsigned int port_state;
- raw_spin_lock_irqsave(&dio48egpio->lock, flags);
-
- /* ensure that GPIO is set for input */
- if (!(dio48egpio->io_state[port] & mask)) {
- raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
- return -EINVAL;
- }
-
- port_state = inb(dio48egpio->base + in_port);
-
- raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
-
- return !!(port_state & mask);
+ return i8255_get(dio48egpio->reg->ppi, offset);
}
-static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
-
static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- unsigned int port_addr;
- unsigned long port_state;
-
- /* clear bits array to a clean slate */
- bitmap_zero(bits, chip->ngpio);
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- port_addr = dio48egpio->base + ports[offset / 8];
- port_state = inb(port_addr) & gpio_mask;
-
- bitmap_set_value8(bits, port_state, offset);
- }
+ i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio);
return 0;
}
@@ -205,49 +130,17 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
- const unsigned int port = offset / 8;
- const unsigned int mask = BIT(offset % 8);
- const unsigned int out_port = (port > 2) ? port + 1 : port;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&dio48egpio->lock, flags);
-
- if (value)
- dio48egpio->out_state[port] |= mask;
- else
- dio48egpio->out_state[port] &= ~mask;
- outb(dio48egpio->out_state[port], dio48egpio->base + out_port);
-
- raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
+ i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value);
}
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 long offset;
- unsigned long gpio_mask;
- size_t index;
- unsigned int port_addr;
- unsigned long bitmask;
- unsigned long flags;
-
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- index = offset / 8;
- port_addr = dio48egpio->base + ports[index];
-
- bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
-
- raw_spin_lock_irqsave(&dio48egpio->lock, flags);
-
- /* update output state data and set device gpio register */
- dio48egpio->out_state[index] &= ~gpio_mask;
- dio48egpio->out_state[index] |= bitmask;
- outb(dio48egpio->out_state[index], port_addr);
- raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
- }
+ i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask,
+ bits, chip->ngpio);
}
static void dio48e_irq_ack(struct irq_data *data)
@@ -274,7 +167,7 @@ static void dio48e_irq_mask(struct irq_data *data)
if (!dio48egpio->irq_mask)
/* disable interrupts */
- inb(dio48egpio->base + 0xB);
+ ioread8(&dio48egpio->reg->enable_interrupt);
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
}
@@ -294,8 +187,8 @@ static void dio48e_irq_unmask(struct irq_data *data)
if (!dio48egpio->irq_mask) {
/* enable interrupts */
- outb(0x00, dio48egpio->base + 0xF);
- outb(0x00, dio48egpio->base + 0xB);
+ iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
+ iowrite8(0x00, &dio48egpio->reg->enable_interrupt);
}
if (offset == 19)
@@ -341,7 +234,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
raw_spin_lock(&dio48egpio->lock);
- outb(0x00, dio48egpio->base + 0xF);
+ iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
raw_spin_unlock(&dio48egpio->lock);
@@ -373,11 +266,26 @@ static int dio48e_irq_init_hw(struct gpio_chip *gc)
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc);
/* Disable IRQ by default */
- inb(dio48egpio->base + 0xB);
+ ioread8(&dio48egpio->reg->enable_interrupt);
return 0;
}
+static void dio48e_init_ppi(struct i8255 __iomem *const ppi,
+ struct i8255_state *const ppi_state)
+{
+ const unsigned long ngpio = 24;
+ const unsigned long mask = GENMASK(ngpio - 1, 0);
+ const unsigned long bits = 0;
+ unsigned long i;
+
+ /* Initialize all GPIO to output 0 */
+ for (i = 0; i < DIO48E_NUM_PPI; i++) {
+ i8255_mode0_output(&ppi[i]);
+ i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
+ }
+}
+
static int dio48e_probe(struct device *dev, unsigned int id)
{
struct dio48e_gpio *dio48egpio;
@@ -395,6 +303,10 @@ static int dio48e_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
+ dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
+ if (!dio48egpio->reg)
+ return -ENOMEM;
+
dio48egpio->chip.label = name;
dio48egpio->chip.parent = dev;
dio48egpio->chip.owner = THIS_MODULE;
@@ -408,7 +320,6 @@ static int dio48e_probe(struct device *dev, unsigned int id)
dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple;
dio48egpio->chip.set = dio48e_gpio_set;
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
- dio48egpio->base = base[id];
girq = &dio48egpio->chip.irq;
girq->chip = &dio48e_irqchip;
@@ -422,17 +333,8 @@ static int dio48e_probe(struct device *dev, unsigned int id)
raw_spin_lock_init(&dio48egpio->lock);
- /* initialize all GPIO as output */
- outb(0x80, base[id] + 3);
- outb(0x00, base[id]);
- outb(0x00, base[id] + 1);
- outb(0x00, base[id] + 2);
- outb(0x00, base[id] + 3);
- outb(0x80, base[id] + 7);
- outb(0x00, base[id] + 4);
- outb(0x00, base[id] + 5);
- outb(0x00, base[id] + 6);
- outb(0x00, base[id] + 7);
+ i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI);
+ dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state);
err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
if (err) {
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index 34be7dd9f5b9..40be76efeed7 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -6,8 +6,7 @@
* This driver supports the following ACCES devices: 104-IDI-48A,
* 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
*/
-#include <linux/bitmap.h>
-#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -20,6 +19,11 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "gpio-i8255.h"
+
+MODULE_IMPORT_NS(I8255);
#define IDI_48_EXTENT 8
#define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
@@ -34,72 +38,61 @@ module_param_hw_array(irq, uint, irq, NULL, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
/**
+ * struct idi_48_reg - device register structure
+ * @port0: Port 0 Inputs
+ * @unused: Unused
+ * @port1: Port 1 Inputs
+ * @irq: Read: IRQ Status Register/IRQ Clear
+ * Write: IRQ Enable/Disable
+ */
+struct idi_48_reg {
+ u8 port0[3];
+ u8 unused;
+ u8 port1[3];
+ u8 irq;
+};
+
+/**
* struct idi_48_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
- * @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
+ * @reg: I/O address offset for the device registers
* @cos_enb: Change-Of-State IRQ enable boundaries mask
*/
struct idi_48_gpio {
struct gpio_chip chip;
- raw_spinlock_t lock;
- spinlock_t ack_lock;
+ spinlock_t lock;
unsigned char irq_mask[6];
- unsigned base;
+ struct idi_48_reg __iomem *reg;
unsigned char cos_enb;
};
-static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
return GPIO_LINE_DIRECTION_IN;
}
-static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
return 0;
}
-static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
- unsigned i;
- static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 };
- unsigned base_offset;
- unsigned mask;
-
- for (i = 0; i < 48; i += 8)
- if (offset < i + 8) {
- base_offset = register_offset[i / 8];
- mask = BIT(offset - i);
+ void __iomem *const ppi = idi48gpio->reg;
- return !!(inb(idi48gpio->base + base_offset) & mask);
- }
-
- /* The following line should never execute since offset < 48 */
- return 0;
+ return i8255_get(ppi, offset);
}
static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
- unsigned int port_addr;
- unsigned long port_state;
+ void __iomem *const ppi = idi48gpio->reg;
- /* clear bits array to a clean slate */
- bitmap_zero(bits, chip->ngpio);
-
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- port_addr = idi48gpio->base + ports[offset / 8];
- port_state = inb(port_addr) & gpio_mask;
-
- bitmap_set_value8(bits, port_state, offset);
- }
+ i8255_get_multiple(ppi, mask, bits, chip->ngpio);
return 0;
}
@@ -112,67 +105,56 @@ static void idi_48_irq_mask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
- const unsigned offset = irqd_to_hwirq(data);
- unsigned i;
- unsigned mask;
- unsigned boundary;
+ const unsigned int offset = irqd_to_hwirq(data);
+ const unsigned long boundary = offset / 8;
+ const unsigned long mask = BIT(offset % 8);
unsigned long flags;
- for (i = 0; i < 48; i += 8)
- if (offset < i + 8) {
- mask = BIT(offset - i);
- boundary = i / 8;
+ spin_lock_irqsave(&idi48gpio->lock, flags);
- idi48gpio->irq_mask[boundary] &= ~mask;
+ idi48gpio->irq_mask[boundary] &= ~mask;
- if (!idi48gpio->irq_mask[boundary]) {
- idi48gpio->cos_enb &= ~BIT(boundary);
+ /* Exit early if there are still input lines with IRQ unmasked */
+ if (idi48gpio->irq_mask[boundary])
+ goto exit;
- raw_spin_lock_irqsave(&idi48gpio->lock, flags);
+ idi48gpio->cos_enb &= ~BIT(boundary);
- outb(idi48gpio->cos_enb, idi48gpio->base + 7);
+ iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
- raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
- }
-
- return;
- }
+exit:
+ spin_unlock_irqrestore(&idi48gpio->lock, flags);
}
static void idi_48_irq_unmask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
- const unsigned offset = irqd_to_hwirq(data);
- unsigned i;
- unsigned mask;
- unsigned boundary;
- unsigned prev_irq_mask;
+ const unsigned int offset = irqd_to_hwirq(data);
+ const unsigned long boundary = offset / 8;
+ const unsigned long mask = BIT(offset % 8);
+ unsigned int prev_irq_mask;
unsigned long flags;
- for (i = 0; i < 48; i += 8)
- if (offset < i + 8) {
- mask = BIT(offset - i);
- boundary = i / 8;
- prev_irq_mask = idi48gpio->irq_mask[boundary];
+ spin_lock_irqsave(&idi48gpio->lock, flags);
- idi48gpio->irq_mask[boundary] |= mask;
+ prev_irq_mask = idi48gpio->irq_mask[boundary];
- if (!prev_irq_mask) {
- idi48gpio->cos_enb |= BIT(boundary);
+ idi48gpio->irq_mask[boundary] |= mask;
- raw_spin_lock_irqsave(&idi48gpio->lock, flags);
+ /* Exit early if IRQ was already unmasked for this boundary */
+ if (prev_irq_mask)
+ goto exit;
- outb(idi48gpio->cos_enb, idi48gpio->base + 7);
+ idi48gpio->cos_enb |= BIT(boundary);
- raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
- }
+ iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
- return;
- }
+exit:
+ spin_unlock_irqrestore(&idi48gpio->lock, flags);
}
-static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type)
+static int idi_48_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 &&
@@ -200,17 +182,13 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
unsigned long gpio;
struct gpio_chip *const chip = &idi48gpio->chip;
- spin_lock(&idi48gpio->ack_lock);
-
- raw_spin_lock(&idi48gpio->lock);
-
- cos_status = inb(idi48gpio->base + 7);
+ spin_lock(&idi48gpio->lock);
- raw_spin_unlock(&idi48gpio->lock);
+ cos_status = ioread8(&idi48gpio->reg->irq);
/* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
if (cos_status & BIT(6)) {
- spin_unlock(&idi48gpio->ack_lock);
+ spin_unlock(&idi48gpio->lock);
return IRQ_NONE;
}
@@ -228,7 +206,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
}
}
- spin_unlock(&idi48gpio->ack_lock);
+ spin_unlock(&idi48gpio->lock);
return IRQ_HANDLED;
}
@@ -250,8 +228,8 @@ static int idi_48_irq_init_hw(struct gpio_chip *gc)
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
/* Disable IRQ by default */
- outb(0, idi48gpio->base + 7);
- inb(idi48gpio->base + 7);
+ iowrite8(0, &idi48gpio->reg->irq);
+ ioread8(&idi48gpio->reg->irq);
return 0;
}
@@ -273,6 +251,10 @@ static int idi_48_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
+ idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
+ if (!idi48gpio->reg)
+ return -ENOMEM;
+
idi48gpio->chip.label = name;
idi48gpio->chip.parent = dev;
idi48gpio->chip.owner = THIS_MODULE;
@@ -283,7 +265,6 @@ static int idi_48_probe(struct device *dev, unsigned int id)
idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
idi48gpio->chip.get = idi_48_gpio_get;
idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
- idi48gpio->base = base[id];
girq = &idi48gpio->chip.irq;
girq->chip = &idi_48_irqchip;
@@ -295,8 +276,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
girq->handler = handle_edge_irq;
girq->init_hw = idi_48_irq_init_hw;
- raw_spin_lock_init(&idi48gpio->lock);
- spin_lock_init(&idi48gpio->ack_lock);
+ spin_lock_init(&idi48gpio->lock);
err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
if (err) {
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index c68ed1a135fa..65a5f581d981 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -6,7 +6,7 @@
* This driver supports the following ACCES devices: 104-IDIO-16,
* 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
*/
-#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
+#include <linux/types.h>
#define IDIO_16_EXTENT 8
#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
@@ -33,18 +34,41 @@ module_param_hw_array(irq, uint, irq, NULL, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
/**
+ * struct idio_16_reg - device registers structure
+ * @out0_7: Read: N/A
+ * Write: FET Drive Outputs 0-7
+ * @in0_7: Read: Isolated Inputs 0-7
+ * Write: Clear Interrupt
+ * @irq_ctl: Read: Enable IRQ
+ * Write: Disable IRQ
+ * @unused: N/A
+ * @out8_15: Read: N/A
+ * Write: FET Drive Outputs 8-15
+ * @in8_15: Read: Isolated Inputs 8-15
+ * Write: N/A
+ */
+struct idio_16_reg {
+ u8 out0_7;
+ u8 in0_7;
+ u8 irq_ctl;
+ u8 unused;
+ u8 out8_15;
+ u8 in8_15;
+};
+
+/**
* struct idio_16_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @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
+ * @reg: I/O address offset for the device registers
* @out_state: output bits state
*/
struct idio_16_gpio {
struct gpio_chip chip;
raw_spinlock_t lock;
unsigned long irq_mask;
- unsigned int base;
+ struct idio_16_reg __iomem *reg;
unsigned int out_state;
};
@@ -79,9 +103,9 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
return -EINVAL;
if (offset < 24)
- return !!(inb(idio16gpio->base + 1) & mask);
+ return !!(ioread8(&idio16gpio->reg->in0_7) & mask);
- return !!(inb(idio16gpio->base + 5) & (mask>>8));
+ return !!(ioread8(&idio16gpio->reg->in8_15) & (mask>>8));
}
static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
@@ -91,9 +115,9 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
*bits = 0;
if (*mask & GENMASK(23, 16))
- *bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
+ *bits |= (unsigned long)ioread8(&idio16gpio->reg->in0_7) << 16;
if (*mask & GENMASK(31, 24))
- *bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
+ *bits |= (unsigned long)ioread8(&idio16gpio->reg->in8_15) << 24;
return 0;
}
@@ -116,9 +140,9 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
idio16gpio->out_state &= ~mask;
if (offset > 7)
- outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
+ iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15);
else
- outb(idio16gpio->out_state, idio16gpio->base);
+ iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
@@ -135,9 +159,9 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
idio16gpio->out_state |= *mask & *bits;
if (*mask & 0xFF)
- outb(idio16gpio->out_state, idio16gpio->base);
+ iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7);
if ((*mask >> 8) & 0xFF)
- outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
+ iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
@@ -158,7 +182,7 @@ static void idio_16_irq_mask(struct irq_data *data)
if (!idio16gpio->irq_mask) {
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
- outb(0, idio16gpio->base + 2);
+ iowrite8(0, &idio16gpio->reg->irq_ctl);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
@@ -177,7 +201,7 @@ static void idio_16_irq_unmask(struct irq_data *data)
if (!prev_irq_mask) {
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
- inb(idio16gpio->base + 2);
+ ioread8(&idio16gpio->reg->irq_ctl);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
@@ -212,7 +236,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
raw_spin_lock(&idio16gpio->lock);
- outb(0, idio16gpio->base + 1);
+ iowrite8(0, &idio16gpio->reg->in0_7);
raw_spin_unlock(&idio16gpio->lock);
@@ -232,8 +256,8 @@ static int idio_16_irq_init_hw(struct gpio_chip *gc)
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
/* Disable IRQ by default */
- outb(0, idio16gpio->base + 2);
- outb(0, idio16gpio->base + 1);
+ iowrite8(0, &idio16gpio->reg->irq_ctl);
+ iowrite8(0, &idio16gpio->reg->in0_7);
return 0;
}
@@ -255,6 +279,10 @@ static int idio_16_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
+ idio16gpio->reg = devm_ioport_map(dev, base[id], IDIO_16_EXTENT);
+ if (!idio16gpio->reg)
+ return -ENOMEM;
+
idio16gpio->chip.label = name;
idio16gpio->chip.parent = dev;
idio16gpio->chip.owner = THIS_MODULE;
@@ -268,7 +296,6 @@ static int idio_16_probe(struct device *dev, unsigned int id)
idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
idio16gpio->chip.set = idio_16_gpio_set;
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
- idio16gpio->base = base[id];
idio16gpio->out_state = 0xFFFF;
girq = &idio16gpio->chip.irq;
diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c
index 173e06758e6c..cd399898ed12 100644
--- a/drivers/gpio/gpio-74xx-mmio.c
+++ b/drivers/gpio/gpio-74xx-mmio.c
@@ -5,15 +5,17 @@
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
*/
+#include <linux/bits.h>
#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/gpio/driver.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#define MMIO_74XX_DIR_IN (0 << 8)
#define MMIO_74XX_DIR_OUT (1 << 8)
-#define MMIO_74XX_BIT_CNT(x) ((x) & 0xff)
+#define MMIO_74XX_BIT_CNT(x) ((x) & GENMASK(7, 0))
struct mmio_74xx_gpio_priv {
struct gpio_chip gc;
@@ -87,7 +89,10 @@ static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
- return (priv->flags & MMIO_74XX_DIR_OUT) ? -ENOTSUPP : 0;
+ if (priv->flags & MMIO_74XX_DIR_IN)
+ return 0;
+
+ return -ENOTSUPP;
}
static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -112,7 +117,7 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- priv->flags = (uintptr_t)of_device_get_match_data(&pdev->dev);
+ priv->flags = (uintptr_t)device_get_match_data(&pdev->dev);
dat = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dat))
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index cc349d4e4973..a6439e3daff0 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -6,8 +6,9 @@
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_irq.h>
+#include <linux/property.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -485,22 +486,17 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios,
return 0;
}
-static int adnp_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adnp_i2c_probe(struct i2c_client *client)
{
- struct device_node *np = client->dev.of_node;
+ struct device *dev = &client->dev;
struct adnp *adnp;
u32 num_gpios;
int err;
- err = of_property_read_u32(np, "nr-gpios", &num_gpios);
+ err = device_property_read_u32(dev, "nr-gpios", &num_gpios);
if (err < 0)
return err;
- client->irq = irq_of_parse_and_map(np, 0);
- if (!client->irq)
- return -EPROBE_DEFER;
-
adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL);
if (!adnp)
return -ENOMEM;
@@ -508,8 +504,7 @@ static int adnp_i2c_probe(struct i2c_client *client,
mutex_init(&adnp->i2c_lock);
adnp->client = client;
- err = adnp_gpio_setup(adnp, num_gpios,
- of_property_read_bool(np, "interrupt-controller"));
+ err = adnp_gpio_setup(adnp, num_gpios, device_property_read_bool(dev, "interrupt-controller"));
if (err)
return err;
@@ -535,7 +530,7 @@ static struct i2c_driver adnp_i2c_driver = {
.name = "gpio-adnp",
.of_match_table = adnp_of_match,
},
- .probe = adnp_i2c_probe,
+ .probe_new = adnp_i2c_probe,
.id_table = adnp_i2c_id,
};
module_i2c_driver(adnp_i2c_driver);
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index f1e4ac90e7d3..d49f12560cde 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -6,20 +6,18 @@
* Copyright 2009-2010 Analog Devices Inc.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/of_device.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/platform_data/adp5588.h>
-#define DRV_NAME "adp5588-gpio"
-
/*
* Early pre 4.0 Silicon required to delay readout by at least 25ms,
* since the Event Counter Register updated 25ms after the interrupt
@@ -406,12 +404,6 @@ static int adp5588_gpio_probe(struct i2c_client *client)
if (ret)
return ret;
- if (pdata && pdata->setup) {
- ret = pdata->setup(client, gc->base, gc->ngpio, pdata->context);
- if (ret < 0)
- dev_warn(&client->dev, "setup failed, %d\n", ret);
- }
-
i2c_set_clientdata(client, dev);
return 0;
@@ -419,20 +411,7 @@ static int adp5588_gpio_probe(struct i2c_client *client)
static int adp5588_gpio_remove(struct i2c_client *client)
{
- struct adp5588_gpio_platform_data *pdata =
- dev_get_platdata(&client->dev);
struct adp5588_gpio *dev = i2c_get_clientdata(client);
- int ret;
-
- if (pdata && pdata->teardown) {
- ret = pdata->teardown(client,
- dev->gpio_chip.base, dev->gpio_chip.ngpio,
- pdata->context);
- if (ret < 0) {
- dev_err(&client->dev, "teardown failed %d\n", ret);
- return ret;
- }
- }
if (dev->client->irq)
free_irq(dev->client->irq, dev);
@@ -441,23 +420,21 @@ static int adp5588_gpio_remove(struct i2c_client *client)
}
static const struct i2c_device_id adp5588_gpio_id[] = {
- {DRV_NAME, 0},
+ { "adp5588-gpio" },
{}
};
MODULE_DEVICE_TABLE(i2c, adp5588_gpio_id);
-#ifdef CONFIG_OF
static const struct of_device_id adp5588_gpio_of_id[] = {
- { .compatible = "adi," DRV_NAME, },
- {},
+ { .compatible = "adi,adp5588-gpio" },
+ {}
};
MODULE_DEVICE_TABLE(of, adp5588_gpio_of_id);
-#endif
static struct i2c_driver adp5588_gpio_driver = {
.driver = {
- .name = DRV_NAME,
- .of_match_table = of_match_ptr(adp5588_gpio_of_id),
+ .name = "adp5588-gpio",
+ .of_match_table = adp5588_gpio_of_id,
},
.probe_new = adp5588_gpio_probe,
.remove = adp5588_gpio_remove,
diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c
index 8cfb353c3abb..07c6d090058d 100644
--- a/drivers/gpio/gpio-amdpt.c
+++ b/drivers/gpio/gpio-amdpt.c
@@ -36,19 +36,19 @@ static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset);
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
if (using_pins & BIT(offset)) {
dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n",
offset);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return -EINVAL;
}
writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -59,13 +59,13 @@ static void pt_gpio_free(struct gpio_chip *gc, unsigned offset)
unsigned long flags;
u32 using_pins;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
using_pins &= ~BIT(offset);
writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset);
}
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index e84474494429..70770429ba48 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom Kona GPIO Driver
*
* Author: Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>
* Copyright (C) 2012-2014 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/bitops.h>
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 74ef89248867..c55b35da61a0 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -1,15 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Broadcom
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2015-2017 Broadcom
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
@@ -92,9 +82,9 @@ brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
unsigned long status;
unsigned long flags;
- spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
status = __brcmstb_gpio_get_active_irqs(bank);
- spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
return status;
}
@@ -114,14 +104,14 @@ static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
u32 imask;
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
imask = gc->read_reg(priv->reg_base + GIO_MASK(bank->id));
if (enable)
imask |= mask;
else
imask &= ~mask;
gc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
@@ -204,7 +194,7 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
- spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
iedge_config = bank->gc.read_reg(priv->reg_base +
GIO_EC(bank->id)) & ~mask;
@@ -220,7 +210,7 @@ static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
bank->gc.write_reg(priv->reg_base + GIO_LEVEL(bank->id),
ilevel | level);
- spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
return 0;
}
@@ -385,12 +375,7 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
{
struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
struct brcmstb_gpio_bank *bank;
- int offset, ret = 0, virq;
-
- if (!priv) {
- dev_err(&pdev->dev, "called %s without drvdata!\n", __func__);
- return -EFAULT;
- }
+ int offset, virq;
if (priv->parent_irq > 0)
irq_set_chained_handler_and_data(priv->parent_irq, NULL, NULL);
@@ -411,7 +396,7 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
list_for_each_entry(bank, &priv->bank_list, node)
gpiochip_remove(&bank->gc);
- return ret;
+ return 0;
}
static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c
index 562f8f7e7d1f..137aea49ba02 100644
--- a/drivers/gpio/gpio-cadence.c
+++ b/drivers/gpio/gpio-cadence.c
@@ -41,12 +41,12 @@ static int cdns_gpio_request(struct gpio_chip *chip, unsigned int offset)
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
unsigned long flags;
- spin_lock_irqsave(&chip->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&chip->bgpio_lock, flags);
iowrite32(ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE) & ~BIT(offset),
cgpio->regs + CDNS_GPIO_BYPASS_MODE);
- spin_unlock_irqrestore(&chip->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags);
return 0;
}
@@ -55,13 +55,13 @@ static void cdns_gpio_free(struct gpio_chip *chip, unsigned int offset)
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
unsigned long flags;
- spin_lock_irqsave(&chip->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&chip->bgpio_lock, flags);
iowrite32(ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE) |
(BIT(offset) & cgpio->bypass_orig),
cgpio->regs + CDNS_GPIO_BYPASS_MODE);
- spin_unlock_irqrestore(&chip->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags);
}
static void cdns_gpio_irq_mask(struct irq_data *d)
@@ -90,7 +90,7 @@ static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type)
u32 mask = BIT(d->hwirq);
int ret = 0;
- spin_lock_irqsave(&chip->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&chip->bgpio_lock, flags);
int_value = ioread32(cgpio->regs + CDNS_GPIO_IRQ_VALUE) & ~mask;
int_type = ioread32(cgpio->regs + CDNS_GPIO_IRQ_TYPE) & ~mask;
@@ -115,7 +115,7 @@ static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type)
iowrite32(int_type, cgpio->regs + CDNS_GPIO_IRQ_TYPE);
err_irq_type:
- spin_unlock_irqrestore(&chip->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags);
return ret;
}
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index b55c74a5e064..1ee62cd58582 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/seq_file.h>
+#include <linux/types.h>
#define CRYSTALCOVE_GPIO_NUM 16
#define CRYSTALCOVE_VGPIO_NUM 95
@@ -110,8 +111,7 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type)
return reg + gpio % 8;
}
-static void crystalcove_update_irq_mask(struct crystalcove_gpio *cg,
- int gpio)
+static void crystalcove_update_irq_mask(struct crystalcove_gpio *cg, int gpio)
{
u8 mirqs0 = gpio < 8 ? MGPIO0IRQS0 : MGPIO1IRQS0;
int mask = BIT(gpio % 8);
@@ -140,8 +140,7 @@ static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned int gpio)
return regmap_write(cg->regmap, reg, CTLO_INPUT_SET);
}
-static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned int gpio,
- int value)
+static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned int gpio, int value)
{
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
int reg = to_reg(gpio, CTRL_OUT);
@@ -168,8 +167,7 @@ static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned int gpio)
return val & 0x1;
}
-static void crystalcove_gpio_set(struct gpio_chip *chip,
- unsigned int gpio, int value)
+static void crystalcove_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
{
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
int reg = to_reg(gpio, CTRL_OUT);
@@ -185,10 +183,10 @@ static void crystalcove_gpio_set(struct gpio_chip *chip,
static int crystalcove_irq_type(struct irq_data *data, unsigned int type)
{
- struct crystalcove_gpio *cg =
- gpiochip_get_data(irq_data_get_irq_chip_data(data));
+ struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data));
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
- if (data->hwirq >= CRYSTALCOVE_GPIO_NUM)
+ if (hwirq >= CRYSTALCOVE_GPIO_NUM)
return 0;
switch (type) {
@@ -215,22 +213,20 @@ static int crystalcove_irq_type(struct irq_data *data, unsigned int type)
static void crystalcove_bus_lock(struct irq_data *data)
{
- struct crystalcove_gpio *cg =
- gpiochip_get_data(irq_data_get_irq_chip_data(data));
+ struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data));
mutex_lock(&cg->buslock);
}
static void crystalcove_bus_sync_unlock(struct irq_data *data)
{
- struct crystalcove_gpio *cg =
- gpiochip_get_data(irq_data_get_irq_chip_data(data));
- int gpio = data->hwirq;
+ struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data));
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
if (cg->update & UPDATE_IRQ_TYPE)
- crystalcove_update_irq_ctrl(cg, gpio);
+ crystalcove_update_irq_ctrl(cg, hwirq);
if (cg->update & UPDATE_IRQ_MASK)
- crystalcove_update_irq_mask(cg, gpio);
+ crystalcove_update_irq_mask(cg, hwirq);
cg->update = 0;
mutex_unlock(&cg->buslock);
@@ -238,34 +234,43 @@ static void crystalcove_bus_sync_unlock(struct irq_data *data)
static void crystalcove_irq_unmask(struct irq_data *data)
{
- struct crystalcove_gpio *cg =
- gpiochip_get_data(irq_data_get_irq_chip_data(data));
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct crystalcove_gpio *cg = gpiochip_get_data(gc);
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
- if (data->hwirq < CRYSTALCOVE_GPIO_NUM) {
- cg->set_irq_mask = false;
- cg->update |= UPDATE_IRQ_MASK;
- }
+ if (hwirq >= CRYSTALCOVE_GPIO_NUM)
+ return;
+
+ gpiochip_enable_irq(gc, hwirq);
+
+ cg->set_irq_mask = false;
+ cg->update |= UPDATE_IRQ_MASK;
}
static void crystalcove_irq_mask(struct irq_data *data)
{
- struct crystalcove_gpio *cg =
- gpiochip_get_data(irq_data_get_irq_chip_data(data));
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct crystalcove_gpio *cg = gpiochip_get_data(gc);
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
- if (data->hwirq < CRYSTALCOVE_GPIO_NUM) {
- cg->set_irq_mask = true;
- cg->update |= UPDATE_IRQ_MASK;
- }
+ if (hwirq >= CRYSTALCOVE_GPIO_NUM)
+ return;
+
+ cg->set_irq_mask = true;
+ cg->update |= UPDATE_IRQ_MASK;
+
+ gpiochip_disable_irq(gc, hwirq);
}
-static struct irq_chip crystalcove_irqchip = {
+static const struct irq_chip crystalcove_irqchip = {
.name = "Crystal Cove",
.irq_mask = crystalcove_irq_mask,
.irq_unmask = crystalcove_irq_unmask,
.irq_set_type = crystalcove_irq_type,
.irq_bus_lock = crystalcove_bus_lock,
.irq_bus_sync_unlock = crystalcove_bus_sync_unlock,
- .flags = IRQCHIP_SKIP_SET_WAKE,
+ .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
@@ -293,8 +298,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static void crystalcove_gpio_dbg_show(struct seq_file *s,
- struct gpio_chip *chip)
+static void crystalcove_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
int gpio, offset;
@@ -353,7 +357,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
cg->regmap = pmic->regmap;
girq = &cg->chip.irq;
- girq->chip = &crystalcove_irqchip;
+ gpio_irq_chip_set_chip(girq, &crystalcove_irqchip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index f960587f86a3..59c4c48d8296 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -22,6 +22,7 @@
#include <linux/platform_data/gpio-davinci.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
#include <asm-generic/gpio.h>
@@ -62,6 +63,8 @@ struct davinci_gpio_controller {
void __iomem *regs[MAX_REGS_BANKS];
int gpio_unbanked;
int irqs[MAX_INT_PER_BANK];
+ struct davinci_gpio_regs context[MAX_REGS_BANKS];
+ u32 binten_context;
};
static inline u32 __gpio_mask(unsigned gpio)
@@ -622,6 +625,85 @@ done:
return 0;
}
+static void davinci_gpio_save_context(struct davinci_gpio_controller *chips,
+ u32 nbank)
+{
+ struct davinci_gpio_regs __iomem *g;
+ struct davinci_gpio_regs *context;
+ u32 bank;
+ void __iomem *base;
+
+ base = chips->regs[0] - offset_array[0];
+ chips->binten_context = readl_relaxed(base + BINTEN);
+
+ for (bank = 0; bank < nbank; bank++) {
+ g = chips->regs[bank];
+ context = &chips->context[bank];
+ context->dir = readl_relaxed(&g->dir);
+ context->set_data = readl_relaxed(&g->set_data);
+ context->set_rising = readl_relaxed(&g->set_rising);
+ context->set_falling = readl_relaxed(&g->set_falling);
+ }
+
+ /* Clear Bank interrupt enable bit */
+ writel_relaxed(0, base + BINTEN);
+
+ /* Clear all interrupt status registers */
+ writel_relaxed(GENMASK(31, 0), &g->intstat);
+}
+
+static void davinci_gpio_restore_context(struct davinci_gpio_controller *chips,
+ u32 nbank)
+{
+ struct davinci_gpio_regs __iomem *g;
+ struct davinci_gpio_regs *context;
+ u32 bank;
+ void __iomem *base;
+
+ base = chips->regs[0] - offset_array[0];
+
+ if (readl_relaxed(base + BINTEN) != chips->binten_context)
+ writel_relaxed(chips->binten_context, base + BINTEN);
+
+ for (bank = 0; bank < nbank; bank++) {
+ g = chips->regs[bank];
+ context = &chips->context[bank];
+ if (readl_relaxed(&g->dir) != context->dir)
+ writel_relaxed(context->dir, &g->dir);
+ if (readl_relaxed(&g->set_data) != context->set_data)
+ writel_relaxed(context->set_data, &g->set_data);
+ if (readl_relaxed(&g->set_rising) != context->set_rising)
+ writel_relaxed(context->set_rising, &g->set_rising);
+ if (readl_relaxed(&g->set_falling) != context->set_falling)
+ writel_relaxed(context->set_falling, &g->set_falling);
+ }
+}
+
+static int davinci_gpio_suspend(struct device *dev)
+{
+ struct davinci_gpio_controller *chips = dev_get_drvdata(dev);
+ struct davinci_gpio_platform_data *pdata = dev_get_platdata(dev);
+ u32 nbank = DIV_ROUND_UP(pdata->ngpio, 32);
+
+ davinci_gpio_save_context(chips, nbank);
+
+ return 0;
+}
+
+static int davinci_gpio_resume(struct device *dev)
+{
+ struct davinci_gpio_controller *chips = dev_get_drvdata(dev);
+ struct davinci_gpio_platform_data *pdata = dev_get_platdata(dev);
+ u32 nbank = DIV_ROUND_UP(pdata->ngpio, 32);
+
+ davinci_gpio_restore_context(chips, nbank);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_DEV_PM_OPS(davinci_gpio_dev_pm_ops, davinci_gpio_suspend,
+ davinci_gpio_resume);
+
static const struct of_device_id davinci_gpio_ids[] = {
{ .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
{ .compatible = "ti,am654-gpio", keystone_gpio_get_irq_chip},
@@ -634,6 +716,7 @@ static struct platform_driver davinci_gpio_driver = {
.probe = davinci_gpio_probe,
.driver = {
.name = "davinci_gpio",
+ .pm = pm_sleep_ptr(&davinci_gpio_dev_pm_ops),
.of_match_table = of_match_ptr(davinci_gpio_ids),
},
};
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
index 08b9e2cf4f2d..71fa437b491f 100644
--- a/drivers/gpio/gpio-dln2.c
+++ b/drivers/gpio/gpio-dln2.c
@@ -46,7 +46,6 @@
struct dln2_gpio {
struct platform_device *pdev;
struct gpio_chip gpio;
- struct irq_chip irqchip;
/*
* Cache pin direction to save us one transfer, since the hardware has
@@ -306,6 +305,7 @@ static void dln2_irq_unmask(struct irq_data *irqd)
struct dln2_gpio *dln2 = gpiochip_get_data(gc);
int pin = irqd_to_hwirq(irqd);
+ gpiochip_enable_irq(gc, pin);
set_bit(pin, dln2->unmasked_irqs);
}
@@ -316,6 +316,7 @@ static void dln2_irq_mask(struct irq_data *irqd)
int pin = irqd_to_hwirq(irqd);
clear_bit(pin, dln2->unmasked_irqs);
+ gpiochip_disable_irq(gc, pin);
}
static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
@@ -384,6 +385,17 @@ static void dln2_irq_bus_unlock(struct irq_data *irqd)
mutex_unlock(&dln2->irq_lock);
}
+static const struct irq_chip dln2_irqchip = {
+ .name = "dln2-irq",
+ .irq_mask = dln2_irq_mask,
+ .irq_unmask = dln2_irq_unmask,
+ .irq_set_type = dln2_irq_set_type,
+ .irq_bus_lock = dln2_irq_bus_lock,
+ .irq_bus_sync_unlock = dln2_irq_bus_unlock,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
const void *data, int len)
{
@@ -465,15 +477,8 @@ static int dln2_gpio_probe(struct platform_device *pdev)
dln2->gpio.direction_output = dln2_gpio_direction_output;
dln2->gpio.set_config = dln2_gpio_set_config;
- dln2->irqchip.name = "dln2-irq",
- dln2->irqchip.irq_mask = dln2_irq_mask,
- dln2->irqchip.irq_unmask = dln2_irq_unmask,
- dln2->irqchip.irq_set_type = dln2_irq_set_type,
- dln2->irqchip.irq_bus_lock = dln2_irq_bus_lock,
- dln2->irqchip.irq_bus_sync_unlock = dln2_irq_bus_unlock,
-
girq = &dln2->gpio.irq;
- girq->chip = &dln2->irqchip;
+ gpio_irq_chip_set_chip(girq, &dln2_irqchip);
/* The event comes from the outside so no parent handler */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index b0f3aca61974..c22fcaa44a61 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -95,7 +95,6 @@ struct dwapb_context {
#endif
struct dwapb_gpio_port_irqchip {
- struct irq_chip irqchip;
unsigned int nr_irqs;
unsigned int irq[DWAPB_MAX_GPIOS];
};
@@ -243,35 +242,41 @@ static void dwapb_irq_ack(struct irq_data *d)
u32 val = BIT(irqd_to_hwirq(d));
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
dwapb_write(gpio, GPIO_PORTA_EOI, val);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void dwapb_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
unsigned long flags;
u32 val;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
- val = dwapb_read(gpio, GPIO_INTMASK) | BIT(irqd_to_hwirq(d));
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
+ val = dwapb_read(gpio, GPIO_INTMASK) | BIT(hwirq);
dwapb_write(gpio, GPIO_INTMASK, val);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+
+ gpiochip_disable_irq(gc, hwirq);
}
static void dwapb_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
unsigned long flags;
u32 val;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
- val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(irqd_to_hwirq(d));
+ gpiochip_enable_irq(gc, hwirq);
+
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
+ val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(hwirq);
dwapb_write(gpio, GPIO_INTMASK, val);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void dwapb_irq_enable(struct irq_data *d)
@@ -281,11 +286,11 @@ static void dwapb_irq_enable(struct irq_data *d)
unsigned long flags;
u32 val;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
val = dwapb_read(gpio, GPIO_INTEN);
val |= BIT(irqd_to_hwirq(d));
dwapb_write(gpio, GPIO_INTEN, val);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void dwapb_irq_disable(struct irq_data *d)
@@ -295,11 +300,11 @@ static void dwapb_irq_disable(struct irq_data *d)
unsigned long flags;
u32 val;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
val = dwapb_read(gpio, GPIO_INTEN);
val &= ~BIT(irqd_to_hwirq(d));
dwapb_write(gpio, GPIO_INTEN, val);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static int dwapb_irq_set_type(struct irq_data *d, u32 type)
@@ -309,7 +314,7 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
irq_hw_number_t bit = irqd_to_hwirq(d);
unsigned long level, polarity, flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
polarity = dwapb_read(gpio, GPIO_INT_POLARITY);
@@ -344,7 +349,7 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
if (type != IRQ_TYPE_EDGE_BOTH)
dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -364,8 +369,23 @@ static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable)
return 0;
}
+#else
+#define dwapb_irq_set_wake NULL
#endif
+static const struct irq_chip dwapb_irq_chip = {
+ .name = DWAPB_DRIVER_NAME,
+ .irq_ack = dwapb_irq_ack,
+ .irq_mask = dwapb_irq_mask,
+ .irq_unmask = dwapb_irq_unmask,
+ .irq_set_type = dwapb_irq_set_type,
+ .irq_enable = dwapb_irq_enable,
+ .irq_disable = dwapb_irq_disable,
+ .irq_set_wake = dwapb_irq_set_wake,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
unsigned offset, unsigned debounce)
{
@@ -374,7 +394,7 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
unsigned long flags, val_deb;
unsigned long mask = BIT(offset);
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
if (debounce)
@@ -383,7 +403,7 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
val_deb &= ~mask;
dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -439,16 +459,6 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
girq->default_type = IRQ_TYPE_NONE;
port->pirq = pirq;
- pirq->irqchip.name = DWAPB_DRIVER_NAME;
- pirq->irqchip.irq_ack = dwapb_irq_ack;
- pirq->irqchip.irq_mask = dwapb_irq_mask;
- pirq->irqchip.irq_unmask = dwapb_irq_unmask;
- pirq->irqchip.irq_set_type = dwapb_irq_set_type;
- pirq->irqchip.irq_enable = dwapb_irq_enable;
- pirq->irqchip.irq_disable = dwapb_irq_disable;
-#ifdef CONFIG_PM_SLEEP
- pirq->irqchip.irq_set_wake = dwapb_irq_set_wake;
-#endif
/*
* Intel ACPI-based platforms mostly have the DesignWare APB GPIO
@@ -475,7 +485,7 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
girq->parent_handler = dwapb_irq_handler;
}
- girq->chip = &pirq->irqchip;
+ gpio_irq_chip_set_chip(girq, &dwapb_irq_chip);
return;
@@ -652,10 +662,9 @@ static int dwapb_get_clks(struct dwapb_gpio *gpio)
gpio->clks[1].id = "db";
err = devm_clk_bulk_get_optional(gpio->dev, DWAPB_NR_CLOCKS,
gpio->clks);
- if (err) {
- dev_err(gpio->dev, "Cannot get APB/Debounce clocks\n");
- return err;
- }
+ if (err)
+ return dev_err_probe(gpio->dev, err,
+ "Cannot get APB/Debounce clocks\n");
err = clk_bulk_prepare_enable(DWAPB_NR_CLOCKS, gpio->clks);
if (err) {
@@ -738,7 +747,7 @@ static int dwapb_gpio_suspend(struct device *dev)
unsigned long flags;
int i;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
for (i = 0; i < gpio->nr_ports; i++) {
unsigned int offset;
unsigned int idx = gpio->ports[i].idx;
@@ -765,7 +774,7 @@ static int dwapb_gpio_suspend(struct device *dev)
dwapb_write(gpio, GPIO_INTMASK, ~ctx->wake_en);
}
}
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks);
@@ -785,7 +794,7 @@ static int dwapb_gpio_resume(struct device *dev)
return err;
}
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
for (i = 0; i < gpio->nr_ports; i++) {
unsigned int offset;
unsigned int idx = gpio->ports[i].idx;
@@ -812,7 +821,7 @@ static int dwapb_gpio_resume(struct device *dev)
dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
}
}
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
index b90a45c939a4..f422c3e129a0 100644
--- a/drivers/gpio/gpio-ftgpio010.c
+++ b/drivers/gpio/gpio-ftgpio010.c
@@ -315,8 +315,8 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
return 0;
dis_clk:
- if (!IS_ERR(g->clk))
- clk_disable_unprepare(g->clk);
+ clk_disable_unprepare(g->clk);
+
return ret;
}
@@ -324,8 +324,8 @@ static int ftgpio_gpio_remove(struct platform_device *pdev)
{
struct ftgpio_gpio *g = platform_get_drvdata(pdev);
- if (!IS_ERR(g->clk))
- clk_disable_unprepare(g->clk);
+ clk_disable_unprepare(g->clk);
+
return 0;
}
diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c
index b89b8c5ff1f5..2689671b6b01 100644
--- a/drivers/gpio/gpio-gpio-mm.c
+++ b/drivers/gpio/gpio-gpio-mm.c
@@ -6,8 +6,6 @@
* This driver supports the following Diamond Systems devices: GPIO-MM and
* GPIO-MM-12.
*/
-#include <linux/bitmap.h>
-#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -17,7 +15,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/spinlock.h>
+
+#include "gpio-i8255.h"
+
+MODULE_IMPORT_NS(I8255);
#define GPIOMM_EXTENT 8
#define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
@@ -27,32 +28,26 @@ static unsigned int num_gpiomm;
module_param_hw_array(base, uint, ioport, &num_gpiomm, 0);
MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
+#define GPIOMM_NUM_PPI 2
+
/**
* struct gpiomm_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
- * @io_state: bit I/O state (whether bit is set to input or output)
- * @out_state: output bits state
- * @control: Control registers state
- * @lock: synchronization lock to prevent I/O race conditions
- * @base: base port address of the GPIO device
+ * @chip: instance of the gpio_chip
+ * @ppi_state: Programmable Peripheral Interface group states
+ * @ppi: Programmable Peripheral Interface groups
*/
struct gpiomm_gpio {
struct gpio_chip chip;
- unsigned char io_state[6];
- unsigned char out_state[6];
- unsigned char control[2];
- spinlock_t lock;
- unsigned int base;
+ struct i8255_state ppi_state[GPIOMM_NUM_PPI];
+ struct i8255 __iomem *ppi;
};
static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
- const unsigned int port = offset / 8;
- const unsigned int mask = BIT(offset % 8);
- if (gpiommgpio->io_state[port] & mask)
+ if (i8255_get_direction(gpiommgpio->ppi_state, offset))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
@@ -62,36 +57,8 @@ static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
- const unsigned int io_port = offset / 8;
- const unsigned int control_port = io_port / 3;
- const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
- unsigned long flags;
- unsigned int control;
-
- spin_lock_irqsave(&gpiommgpio->lock, flags);
-
- /* Check if configuring Port C */
- if (io_port == 2 || io_port == 5) {
- /* Port C can be configured by nibble */
- if (offset % 8 > 3) {
- gpiommgpio->io_state[io_port] |= 0xF0;
- gpiommgpio->control[control_port] |= BIT(3);
- } else {
- gpiommgpio->io_state[io_port] |= 0x0F;
- gpiommgpio->control[control_port] |= BIT(0);
- }
- } else {
- gpiommgpio->io_state[io_port] |= 0xFF;
- if (io_port == 0 || io_port == 3)
- gpiommgpio->control[control_port] |= BIT(4);
- else
- gpiommgpio->control[control_port] |= BIT(1);
- }
- control = BIT(7) | gpiommgpio->control[control_port];
- outb(control, control_addr);
-
- spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+ i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset);
return 0;
}
@@ -100,45 +67,9 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
- const unsigned int io_port = offset / 8;
- const unsigned int control_port = io_port / 3;
- const unsigned int mask = BIT(offset % 8);
- const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
- const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
- unsigned long flags;
- unsigned int control;
-
- spin_lock_irqsave(&gpiommgpio->lock, flags);
-
- /* Check if configuring Port C */
- if (io_port == 2 || io_port == 5) {
- /* Port C can be configured by nibble */
- if (offset % 8 > 3) {
- gpiommgpio->io_state[io_port] &= 0x0F;
- gpiommgpio->control[control_port] &= ~BIT(3);
- } else {
- gpiommgpio->io_state[io_port] &= 0xF0;
- gpiommgpio->control[control_port] &= ~BIT(0);
- }
- } else {
- gpiommgpio->io_state[io_port] &= 0x00;
- if (io_port == 0 || io_port == 3)
- gpiommgpio->control[control_port] &= ~BIT(4);
- else
- gpiommgpio->control[control_port] &= ~BIT(1);
- }
-
- if (value)
- gpiommgpio->out_state[io_port] |= mask;
- else
- gpiommgpio->out_state[io_port] &= ~mask;
-
- control = BIT(7) | gpiommgpio->control[control_port];
- outb(control, control_addr);
- outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port);
-
- spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+ i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset,
+ value);
return 0;
}
@@ -146,47 +77,16 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
- const unsigned int port = offset / 8;
- const unsigned int mask = BIT(offset % 8);
- const unsigned int in_port = (port > 2) ? port + 1 : port;
- unsigned long flags;
- unsigned int port_state;
-
- spin_lock_irqsave(&gpiommgpio->lock, flags);
-
- /* ensure that GPIO is set for input */
- if (!(gpiommgpio->io_state[port] & mask)) {
- spin_unlock_irqrestore(&gpiommgpio->lock, flags);
- return -EINVAL;
- }
-
- port_state = inb(gpiommgpio->base + in_port);
-
- spin_unlock_irqrestore(&gpiommgpio->lock, flags);
- return !!(port_state & mask);
+ return i8255_get(gpiommgpio->ppi, offset);
}
-static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
-
static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- unsigned int port_addr;
- unsigned long port_state;
-
- /* clear bits array to a clean slate */
- bitmap_zero(bits, chip->ngpio);
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- port_addr = gpiommgpio->base + ports[offset / 8];
- port_state = inb(port_addr) & gpio_mask;
-
- bitmap_set_value8(bits, port_state, offset);
- }
+ i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
return 0;
}
@@ -195,49 +95,17 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
- const unsigned int port = offset / 8;
- const unsigned int mask = BIT(offset % 8);
- const unsigned int out_port = (port > 2) ? port + 1 : port;
- unsigned long flags;
- spin_lock_irqsave(&gpiommgpio->lock, flags);
-
- if (value)
- gpiommgpio->out_state[port] |= mask;
- else
- gpiommgpio->out_state[port] &= ~mask;
-
- outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
-
- spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+ i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value);
}
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 long offset;
- unsigned long gpio_mask;
- size_t index;
- unsigned int port_addr;
- unsigned long bitmask;
- unsigned long flags;
-
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- index = offset / 8;
- port_addr = gpiommgpio->base + ports[index];
- bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
-
- spin_lock_irqsave(&gpiommgpio->lock, flags);
-
- /* update output state data and set device gpio register */
- gpiommgpio->out_state[index] &= ~gpio_mask;
- gpiommgpio->out_state[index] |= bitmask;
- outb(gpiommgpio->out_state[index], port_addr);
-
- spin_unlock_irqrestore(&gpiommgpio->lock, flags);
- }
+ i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits,
+ chip->ngpio);
}
#define GPIOMM_NGPIO 48
@@ -252,6 +120,21 @@ static const char *gpiomm_names[GPIOMM_NGPIO] = {
"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
};
+static void gpiomm_init_dio(struct i8255 __iomem *const ppi,
+ struct i8255_state *const ppi_state)
+{
+ const unsigned long ngpio = 24;
+ const unsigned long mask = GENMASK(ngpio - 1, 0);
+ const unsigned long bits = 0;
+ unsigned long i;
+
+ /* Initialize all GPIO to output 0 */
+ for (i = 0; i < GPIOMM_NUM_PPI; i++) {
+ i8255_mode0_output(&ppi[i]);
+ i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
+ }
+}
+
static int gpiomm_probe(struct device *dev, unsigned int id)
{
struct gpiomm_gpio *gpiommgpio;
@@ -268,6 +151,10 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
+ gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
+ if (!gpiommgpio->ppi)
+ return -ENOMEM;
+
gpiommgpio->chip.label = name;
gpiommgpio->chip.parent = dev;
gpiommgpio->chip.owner = THIS_MODULE;
@@ -281,9 +168,9 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
gpiommgpio->chip.set = gpiomm_gpio_set;
gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
- gpiommgpio->base = base[id];
- spin_lock_init(&gpiommgpio->lock);
+ i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI);
+ gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state);
err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
if (err) {
@@ -291,16 +178,6 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
return err;
}
- /* initialize all GPIO as output */
- outb(0x80, base[id] + 3);
- outb(0x00, base[id]);
- outb(0x00, base[id] + 1);
- outb(0x00, base[id] + 2);
- outb(0x80, base[id] + 7);
- outb(0x00, base[id] + 4);
- outb(0x00, base[id] + 5);
- outb(0x00, base[id] + 6);
-
return 0;
}
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 23d447e17a67..bea0e32c195d 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -145,7 +145,7 @@ static int grgpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
- spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
ipol = priv->gc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask;
iedge = priv->gc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask;
@@ -153,7 +153,7 @@ static int grgpio_irq_set_type(struct irq_data *d, unsigned int type)
priv->gc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol);
priv->gc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge);
- spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
return 0;
}
@@ -164,11 +164,11 @@ static void grgpio_irq_mask(struct irq_data *d)
int offset = d->hwirq;
unsigned long flags;
- spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
grgpio_set_imask(priv, offset, 0);
- spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
}
static void grgpio_irq_unmask(struct irq_data *d)
@@ -177,11 +177,11 @@ static void grgpio_irq_unmask(struct irq_data *d)
int offset = d->hwirq;
unsigned long flags;
- spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
grgpio_set_imask(priv, offset, 1);
- spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
}
static struct irq_chip grgpio_irq_chip = {
@@ -199,7 +199,7 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev)
int i;
int match = 0;
- spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
/*
* For each gpio line, call its interrupt handler if it its underlying
@@ -215,7 +215,7 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev)
}
}
- spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
if (!match)
dev_warn(priv->dev, "No gpio line matched irq %d\n", irq);
@@ -247,13 +247,13 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
dev_dbg(priv->dev, "Mapping irq %d for gpio line %d\n",
irq, offset);
- spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
/* Request underlying irq if not already requested */
lirq->irq = irq;
uirq = &priv->uirqs[lirq->index];
if (uirq->refcnt == 0) {
- spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
ret = request_irq(uirq->uirq, grgpio_irq_handler, 0,
dev_name(priv->dev), priv);
if (ret) {
@@ -262,11 +262,11 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
uirq->uirq);
return ret;
}
- spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
}
uirq->refcnt++;
- spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
/* Setup irq */
irq_set_chip_data(irq, priv);
@@ -290,7 +290,7 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL);
- spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
/* Free underlying irq if last user unmapped */
index = -1;
@@ -309,13 +309,13 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
uirq = &priv->uirqs[lirq->index];
uirq->refcnt--;
if (uirq->refcnt == 0) {
- spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
free_irq(uirq->uirq, priv);
return;
}
}
- spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
}
static const struct irq_domain_ops grgpio_irq_domain_ops = {
@@ -434,25 +434,13 @@ static int grgpio_probe(struct platform_device *ofdev)
static int grgpio_remove(struct platform_device *ofdev)
{
struct grgpio_priv *priv = platform_get_drvdata(ofdev);
- int i;
- int ret = 0;
-
- if (priv->domain) {
- for (i = 0; i < GRGPIO_MAX_NGPIO; i++) {
- if (priv->uirqs[i].refcnt != 0) {
- ret = -EBUSY;
- goto out;
- }
- }
- }
gpiochip_remove(&priv->gc);
if (priv->domain)
irq_domain_remove(priv->domain);
-out:
- return ret;
+ return 0;
}
static const struct of_device_id grgpio_match[] = {
diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c
index 641719a96a1a..4e13e937f832 100644
--- a/drivers/gpio/gpio-hlwd.c
+++ b/drivers/gpio/gpio-hlwd.c
@@ -65,7 +65,7 @@ static void hlwd_gpio_irqhandler(struct irq_desc *desc)
int hwirq;
u32 emulated_pending;
- spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
pending = ioread32be(hlwd->regs + HW_GPIOB_INTFLAG);
pending &= ioread32be(hlwd->regs + HW_GPIOB_INTMASK);
@@ -93,7 +93,7 @@ static void hlwd_gpio_irqhandler(struct irq_desc *desc)
/* Mark emulated interrupts as pending */
pending |= rising | falling;
}
- spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
chained_irq_enter(chip, desc);
@@ -118,11 +118,11 @@ static void hlwd_gpio_irq_mask(struct irq_data *data)
unsigned long flags;
u32 mask;
- spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK);
mask &= ~BIT(data->hwirq);
iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK);
- spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
}
static void hlwd_gpio_irq_unmask(struct irq_data *data)
@@ -132,11 +132,11 @@ static void hlwd_gpio_irq_unmask(struct irq_data *data)
unsigned long flags;
u32 mask;
- spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK);
mask |= BIT(data->hwirq);
iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK);
- spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
}
static void hlwd_gpio_irq_enable(struct irq_data *data)
@@ -173,7 +173,7 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
unsigned long flags;
u32 level;
- spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags);
hlwd->edge_emulation &= ~BIT(data->hwirq);
@@ -194,11 +194,11 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
hlwd_gpio_irq_setup_emulation(hlwd, data->hwirq, flow_type);
break;
default:
- spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
return -EINVAL;
}
- spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags);
return 0;
}
diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c
new file mode 100644
index 000000000000..9b97db418df1
--- /dev/null
+++ b/drivers/gpio/gpio-i8255.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel 8255 Programmable Peripheral Interface
+ * Copyright (C) 2022 William Breathitt Gray
+ */
+#include <linux/bitmap.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "gpio-i8255.h"
+
+#define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0)
+#define I8255_CONTROL_PORTB_DIRECTION BIT(1)
+#define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3)
+#define I8255_CONTROL_PORTA_DIRECTION BIT(4)
+#define I8255_CONTROL_MODE_SET BIT(7)
+#define I8255_PORTA 0
+#define I8255_PORTB 1
+#define I8255_PORTC 2
+
+static int i8255_get_port(struct i8255 __iomem *const ppi,
+ const unsigned long io_port, const unsigned long mask)
+{
+ const unsigned long bank = io_port / 3;
+ const unsigned long ppi_port = io_port % 3;
+
+ return ioread8(&ppi[bank].port[ppi_port]) & mask;
+}
+
+static u8 i8255_direction_mask(const unsigned long offset)
+{
+ const unsigned long port_offset = offset % 8;
+ const unsigned long io_port = offset / 8;
+ const unsigned long ppi_port = io_port % 3;
+
+ switch (ppi_port) {
+ case I8255_PORTA:
+ return I8255_CONTROL_PORTA_DIRECTION;
+ case I8255_PORTB:
+ return I8255_CONTROL_PORTB_DIRECTION;
+ case I8255_PORTC:
+ /* Port C can be configured by nibble */
+ if (port_offset >= 4)
+ return I8255_CONTROL_PORTC_UPPER_DIRECTION;
+ return I8255_CONTROL_PORTC_LOWER_DIRECTION;
+ default:
+ /* Should never reach this path */
+ return 0;
+ }
+}
+
+static void i8255_set_port(struct i8255 __iomem *const ppi,
+ struct i8255_state *const state,
+ const unsigned long io_port,
+ const unsigned long mask, const unsigned long bits)
+{
+ const unsigned long bank = io_port / 3;
+ const unsigned long ppi_port = io_port % 3;
+ unsigned long flags;
+ unsigned long out_state;
+
+ spin_lock_irqsave(&state[bank].lock, flags);
+
+ out_state = ioread8(&ppi[bank].port[ppi_port]);
+ out_state = (out_state & ~mask) | (bits & mask);
+ iowrite8(out_state, &ppi[bank].port[ppi_port]);
+
+ spin_unlock_irqrestore(&state[bank].lock, flags);
+}
+
+/**
+ * i8255_direction_input - configure signal offset as input
+ * @ppi: Intel 8255 Programmable Peripheral Interface banks
+ * @state: devices states of the respective PPI banks
+ * @offset: signal offset to configure as input
+ *
+ * Configures a signal @offset as input for the respective Intel 8255
+ * Programmable Peripheral Interface (@ppi) banks. The @state control_state
+ * values are updated to reflect the new configuration.
+ */
+void i8255_direction_input(struct i8255 __iomem *const ppi,
+ struct i8255_state *const state,
+ const unsigned long offset)
+{
+ const unsigned long io_port = offset / 8;
+ const unsigned long bank = io_port / 3;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state[bank].lock, flags);
+
+ state[bank].control_state |= I8255_CONTROL_MODE_SET;
+ state[bank].control_state |= i8255_direction_mask(offset);
+
+ iowrite8(state[bank].control_state, &ppi[bank].control);
+
+ spin_unlock_irqrestore(&state[bank].lock, flags);
+}
+EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255);
+
+/**
+ * i8255_direction_output - configure signal offset as output
+ * @ppi: Intel 8255 Programmable Peripheral Interface banks
+ * @state: devices states of the respective PPI banks
+ * @offset: signal offset to configure as output
+ * @value: signal value to output
+ *
+ * Configures a signal @offset as output for the respective Intel 8255
+ * Programmable Peripheral Interface (@ppi) banks and sets the respective signal
+ * output to the desired @value. The @state control_state values are updated to
+ * reflect the new configuration.
+ */
+void i8255_direction_output(struct i8255 __iomem *const ppi,
+ struct i8255_state *const state,
+ const unsigned long offset,
+ const unsigned long value)
+{
+ const unsigned long io_port = offset / 8;
+ const unsigned long bank = io_port / 3;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state[bank].lock, flags);
+
+ state[bank].control_state |= I8255_CONTROL_MODE_SET;
+ state[bank].control_state &= ~i8255_direction_mask(offset);
+
+ iowrite8(state[bank].control_state, &ppi[bank].control);
+
+ spin_unlock_irqrestore(&state[bank].lock, flags);
+
+ i8255_set(ppi, state, offset, value);
+}
+EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255);
+
+/**
+ * i8255_get - get signal value at signal offset
+ * @ppi: Intel 8255 Programmable Peripheral Interface banks
+ * @offset: offset of signal to get
+ *
+ * Returns the signal value (0=low, 1=high) for the signal at @offset for the
+ * respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
+ */
+int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset)
+{
+ const unsigned long io_port = offset / 8;
+ const unsigned long offset_mask = BIT(offset % 8);
+
+ return !!i8255_get_port(ppi, io_port, offset_mask);
+}
+EXPORT_SYMBOL_NS_GPL(i8255_get, I8255);
+
+/**
+ * i8255_get_direction - get the I/O direction for a signal offset
+ * @state: devices states of the respective PPI banks
+ * @offset: offset of signal to get direction
+ *
+ * Returns the signal direction (0=output, 1=input) for the signal at @offset.
+ */
+int i8255_get_direction(const struct i8255_state *const state,
+ const unsigned long offset)
+{
+ const unsigned long io_port = offset / 8;
+ const unsigned long bank = io_port / 3;
+
+ return !!(state[bank].control_state & i8255_direction_mask(offset));
+}
+EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255);
+
+/**
+ * i8255_get_multiple - get multiple signal values at multiple signal offsets
+ * @ppi: Intel 8255 Programmable Peripheral Interface banks
+ * @mask: mask of signals to get
+ * @bits: bitmap to store signal values
+ * @ngpio: number of GPIO signals of the respective PPI banks
+ *
+ * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask
+ * for the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
+ */
+void i8255_get_multiple(struct i8255 __iomem *const ppi,
+ const unsigned long *const mask,
+ unsigned long *const bits, const unsigned long ngpio)
+{
+ unsigned long offset;
+ unsigned long port_mask;
+ unsigned long io_port;
+ unsigned long port_state;
+
+ bitmap_zero(bits, ngpio);
+
+ for_each_set_clump8(offset, port_mask, mask, ngpio) {
+ io_port = offset / 8;
+ port_state = i8255_get_port(ppi, io_port, port_mask);
+
+ bitmap_set_value8(bits, port_state, offset);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255);
+
+/**
+ * i8255_mode0_output - configure all PPI ports to MODE 0 output mode
+ * @ppi: Intel 8255 Programmable Peripheral Interface bank
+ *
+ * Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to
+ * MODE 0 (Basic Input/Output) output mode.
+ */
+void i8255_mode0_output(struct i8255 __iomem *const ppi)
+{
+ iowrite8(I8255_CONTROL_MODE_SET, &ppi->control);
+}
+EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255);
+
+/**
+ * i8255_set - set signal value at signal offset
+ * @ppi: Intel 8255 Programmable Peripheral Interface banks
+ * @state: devices states of the respective PPI banks
+ * @offset: offset of signal to set
+ * @value: value of signal to set
+ *
+ * Assigns output @value for the signal at @offset for the respective Intel 8255
+ * Programmable Peripheral Interface (@ppi) banks.
+ */
+void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state,
+ const unsigned long offset, const unsigned long value)
+{
+ const unsigned long io_port = offset / 8;
+ const unsigned long port_offset = offset % 8;
+ const unsigned long mask = BIT(port_offset);
+ const unsigned long bits = value << port_offset;
+
+ i8255_set_port(ppi, state, io_port, mask, bits);
+}
+EXPORT_SYMBOL_NS_GPL(i8255_set, I8255);
+
+/**
+ * i8255_set_multiple - set signal values at multiple signal offsets
+ * @ppi: Intel 8255 Programmable Peripheral Interface banks
+ * @state: devices states of the respective PPI banks
+ * @mask: mask of signals to set
+ * @bits: bitmap of signal output values
+ * @ngpio: number of GPIO signals of the respective PPI banks
+ *
+ * Assigns output values defined by @bits for the signals defined by @mask for
+ * the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
+ */
+void i8255_set_multiple(struct i8255 __iomem *const ppi,
+ struct i8255_state *const state,
+ const unsigned long *const mask,
+ const unsigned long *const bits,
+ const unsigned long ngpio)
+{
+ unsigned long offset;
+ unsigned long port_mask;
+ unsigned long io_port;
+ unsigned long value;
+
+ for_each_set_clump8(offset, port_mask, mask, ngpio) {
+ io_port = offset / 8;
+ value = bitmap_get_value8(bits, offset);
+ i8255_set_port(ppi, state, io_port, port_mask, value);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255);
+
+/**
+ * i8255_state_init - initialize i8255_state structure
+ * @state: devices states of the respective PPI banks
+ * @nbanks: number of Intel 8255 Programmable Peripheral Interface banks
+ *
+ * Initializes the @state of each Intel 8255 Programmable Peripheral Interface
+ * bank for use in i8255 library functions.
+ */
+void i8255_state_init(struct i8255_state *const state,
+ const unsigned long nbanks)
+{
+ unsigned long bank;
+
+ for (bank = 0; bank < nbanks; bank++)
+ spin_lock_init(&state[bank].lock);
+}
+EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255);
+
+MODULE_AUTHOR("William Breathitt Gray");
+MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-i8255.h b/drivers/gpio/gpio-i8255.h
new file mode 100644
index 000000000000..d9084aae9446
--- /dev/null
+++ b/drivers/gpio/gpio-i8255.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2022 William Breathitt Gray */
+#ifndef _I8255_H_
+#define _I8255_H_
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/**
+ * struct i8255 - Intel 8255 register structure
+ * @port: Port A, B, and C
+ * @control: Control register
+ */
+struct i8255 {
+ u8 port[3];
+ u8 control;
+};
+
+/**
+ * struct i8255_state - Intel 8255 state structure
+ * @lock: synchronization lock for accessing device state
+ * @control_state: Control register state
+ */
+struct i8255_state {
+ spinlock_t lock;
+ u8 control_state;
+};
+
+void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *state,
+ unsigned long offset);
+void i8255_direction_output(struct i8255 __iomem *ppi,
+ struct i8255_state *state, unsigned long offset,
+ unsigned long value);
+int i8255_get(struct i8255 __iomem *ppi, unsigned long offset);
+int i8255_get_direction(const struct i8255_state *state, unsigned long offset);
+void i8255_get_multiple(struct i8255 __iomem *ppi, const unsigned long *mask,
+ unsigned long *bits, unsigned long ngpio);
+void i8255_mode0_output(struct i8255 __iomem *const ppi);
+void i8255_set(struct i8255 __iomem *ppi, struct i8255_state *state,
+ unsigned long offset, unsigned long value);
+void i8255_set_multiple(struct i8255 __iomem *ppi, struct i8255_state *state,
+ const unsigned long *mask, const unsigned long *bits,
+ unsigned long ngpio);
+void i8255_state_init(struct i8255_state *const state, unsigned long nbanks);
+
+#endif /* _I8255_H_ */
diff --git a/drivers/gpio/gpio-idt3243x.c b/drivers/gpio/gpio-idt3243x.c
index 52b8b72ded77..1cafdf46f875 100644
--- a/drivers/gpio/gpio-idt3243x.c
+++ b/drivers/gpio/gpio-idt3243x.c
@@ -57,7 +57,7 @@ static int idt_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
if (sense == IRQ_TYPE_NONE || (sense & IRQ_TYPE_EDGE_BOTH))
return -EINVAL;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
ilevel = readl(ctrl->gpio + IDT_GPIO_ILEVEL);
if (sense & IRQ_TYPE_LEVEL_HIGH)
@@ -68,7 +68,7 @@ static int idt_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
writel(ilevel, ctrl->gpio + IDT_GPIO_ILEVEL);
irq_set_handler_locked(d, handle_level_irq);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -86,12 +86,12 @@ static void idt_gpio_mask(struct irq_data *d)
struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
ctrl->mask_cache |= BIT(d->hwirq);
writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void idt_gpio_unmask(struct irq_data *d)
@@ -100,12 +100,12 @@ static void idt_gpio_unmask(struct irq_data *d)
struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
ctrl->mask_cache &= ~BIT(d->hwirq);
writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static int idt_gpio_irq_init_hw(struct gpio_chip *gc)
diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c
index b3b050604e0b..312309be0287 100644
--- a/drivers/gpio/gpio-ixp4xx.c
+++ b/drivers/gpio/gpio-ixp4xx.c
@@ -14,10 +14,6 @@
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/bitops.h>
-/* Include that go away with DT transition */
-#include <linux/irqchip/irq-ixp4xx.h>
-
-#include <asm/mach-types.h>
#define IXP4XX_REG_GPOUT 0x00
#define IXP4XX_REG_GPOE 0x04
@@ -128,7 +124,7 @@ static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type)
int_reg = IXP4XX_REG_GPIT1;
}
- spin_lock_irqsave(&g->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&g->gc.bgpio_lock, flags);
/* Clear the style for the appropriate pin */
val = __raw_readl(g->base + int_reg);
@@ -147,7 +143,7 @@ static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type)
val |= BIT(d->hwirq);
__raw_writel(val, g->base + IXP4XX_REG_GPOE);
- spin_unlock_irqrestore(&g->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&g->gc.bgpio_lock, flags);
/* This parent only accept level high (asserted) */
return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
@@ -195,6 +191,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
struct resource *res;
struct ixp4xx_gpio *g;
struct gpio_irq_chip *girq;
+ struct device_node *irq_parent;
int ret;
g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
@@ -207,40 +204,24 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
if (IS_ERR(g->base))
return PTR_ERR(g->base);
- /*
- * When we convert to device tree we will simply look up the
- * parent irqdomain using irq_find_host(parent) as parent comes
- * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get
- * the fwnode. For now we need this boardfile style code.
- */
- if (np) {
- struct device_node *irq_parent;
-
- irq_parent = of_irq_find_parent(np);
- if (!irq_parent) {
- dev_err(dev, "no IRQ parent node\n");
- return -ENODEV;
- }
- parent = irq_find_host(irq_parent);
- if (!parent) {
- dev_err(dev, "no IRQ parent domain\n");
- return -ENODEV;
- }
- g->fwnode = of_node_to_fwnode(np);
- } else {
- parent = ixp4xx_get_irq_domain();
- g->fwnode = irq_domain_alloc_fwnode(&res->start);
- if (!g->fwnode) {
- dev_err(dev, "no domain base\n");
- return -ENODEV;
- }
+ irq_parent = of_irq_find_parent(np);
+ if (!irq_parent) {
+ dev_err(dev, "no IRQ parent node\n");
+ return -ENODEV;
+ }
+ parent = irq_find_host(irq_parent);
+ if (!parent) {
+ dev_err(dev, "no IRQ parent domain\n");
+ return -ENODEV;
}
+ g->fwnode = of_node_to_fwnode(np);
/*
* Make sure GPIO 14 and 15 are NOT used as clocks but GPIO on
* specific machines.
*/
- if (machine_is_dsmg600() || machine_is_nas100d())
+ if (of_machine_is_compatible("dlink,dsm-g600-a") ||
+ of_machine_is_compatible("iom,nas-100d"))
__raw_writel(0x0, g->base + IXP4XX_REG_GPCLK);
/*
diff --git a/drivers/gpio/gpio-loongson1.c b/drivers/gpio/gpio-loongson1.c
index 1b1ee94eeab4..5d90b3bc5a25 100644
--- a/drivers/gpio/gpio-loongson1.c
+++ b/drivers/gpio/gpio-loongson1.c
@@ -25,10 +25,10 @@ static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
{
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
__raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | BIT(offset),
gpio_reg_base + GPIO_CFG);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -37,10 +37,10 @@ static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset)
{
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
__raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~BIT(offset),
gpio_reg_base + GPIO_CFG);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static int ls1x_gpio_probe(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c
index 8a30fb185aab..79edd5db49d2 100644
--- a/drivers/gpio/gpio-lp3943.c
+++ b/drivers/gpio/gpio-lp3943.c
@@ -42,7 +42,7 @@ struct lp3943_gpio {
u16 input_mask; /* 1 = GPIO is input direction, 0 = output */
};
-static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
+static int lp3943_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
struct lp3943 *lp3943 = lp3943_gpio->lp3943;
@@ -54,7 +54,7 @@ static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
return 0;
}
-static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset)
+static void lp3943_gpio_free(struct gpio_chip *chip, unsigned int offset)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
struct lp3943 *lp3943 = lp3943_gpio->lp3943;
@@ -72,7 +72,7 @@ static int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset,
val << mux[offset].shift);
}
-static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
@@ -82,7 +82,7 @@ static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
}
static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio,
- struct gpio_chip *chip, unsigned offset)
+ struct gpio_chip *chip, unsigned int offset)
{
u8 addr, read;
int err;
@@ -107,7 +107,7 @@ static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio,
}
static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio,
- struct gpio_chip *chip, unsigned offset)
+ struct gpio_chip *chip, unsigned int offset)
{
struct lp3943 *lp3943 = lp3943_gpio->lp3943;
const struct lp3943_reg_cfg *mux = lp3943->mux_cfg;
@@ -128,7 +128,7 @@ static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio,
return -EINVAL;
}
-static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int lp3943_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
@@ -147,7 +147,7 @@ static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
return lp3943_get_gpio_out_status(lp3943_gpio, chip, offset);
}
-static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void lp3943_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
u8 data;
@@ -160,7 +160,7 @@ static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
lp3943_gpio_set_mode(lp3943_gpio, offset, data);
}
-static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c
index 70fad87ff2db..5c79ba1f229c 100644
--- a/drivers/gpio/gpio-lp873x.c
+++ b/drivers/gpio/gpio-lp873x.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
* Keerthy <j-keerthy@ti.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License version 2 for more details.
- *
* Based on the TPS65218 driver
*/
diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c
index fcde6708b5df..d3ce027de081 100644
--- a/drivers/gpio/gpio-lp87565.c
+++ b/drivers/gpio/gpio-lp87565.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
* Keerthy <j-keerthy@ti.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License version 2 for more details.
- *
* Based on the LP873X driver
*/
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 238cbe926b9f..da6972117030 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -496,17 +496,13 @@ static int max732x_irq_setup(struct max732x_chip *chip,
const struct i2c_device_id *id)
{
struct i2c_client *client = chip->client;
- struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
int has_irq = max732x_features[id->driver_data] >> 32;
int irq_base = 0;
int ret;
- if (((pdata && pdata->irq_base) || client->irq)
- && has_irq != INT_NONE) {
+ if (client->irq && has_irq != INT_NONE) {
struct gpio_irq_chip *girq;
- if (pdata)
- irq_base = pdata->irq_base;
chip->irq_features = has_irq;
mutex_init(&chip->irq_lock);
@@ -540,10 +536,9 @@ static int max732x_irq_setup(struct max732x_chip *chip,
const struct i2c_device_id *id)
{
struct i2c_client *client = chip->client;
- struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
int has_irq = max732x_features[id->driver_data] >> 32;
- if (((pdata && pdata->irq_base) || client->irq) && has_irq != INT_NONE)
+ if (client->irq && has_irq != INT_NONE)
dev_warn(&client->dev, "interrupt support not compiled in\n");
return 0;
@@ -703,44 +698,16 @@ static int max732x_probe(struct i2c_client *client,
if (ret)
return ret;
- if (pdata->setup) {
- ret = pdata->setup(client, chip->gpio_chip.base,
- chip->gpio_chip.ngpio, pdata->context);
- if (ret < 0)
- dev_warn(&client->dev, "setup failed, %d\n", ret);
- }
-
i2c_set_clientdata(client, chip);
return 0;
}
-static int max732x_remove(struct i2c_client *client)
-{
- struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
- struct max732x_chip *chip = i2c_get_clientdata(client);
-
- if (pdata && pdata->teardown) {
- int ret;
-
- ret = pdata->teardown(client, chip->gpio_chip.base,
- chip->gpio_chip.ngpio, pdata->context);
- if (ret < 0) {
- dev_err(&client->dev, "%s failed, %d\n",
- "teardown", ret);
- return ret;
- }
- }
-
- return 0;
-}
-
static struct i2c_driver max732x_driver = {
.driver = {
.name = "max732x",
.of_match_table = of_match_ptr(max732x_of_table),
},
.probe = max732x_probe,
- .remove = max732x_remove,
.id_table = max732x_id,
};
diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c
index ebf9dea6546b..c18b60e39a94 100644
--- a/drivers/gpio/gpio-max77620.c
+++ b/drivers/gpio/gpio-max77620.c
@@ -54,6 +54,7 @@ static void max77620_gpio_irq_mask(struct irq_data *data)
struct max77620_gpio *gpio = gpiochip_get_data(chip);
gpio->irq_enabled[data->hwirq] = false;
+ gpiochip_disable_irq(chip, data->hwirq);
}
static void max77620_gpio_irq_unmask(struct irq_data *data)
@@ -61,6 +62,7 @@ static void max77620_gpio_irq_unmask(struct irq_data *data)
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct max77620_gpio *gpio = gpiochip_get_data(chip);
+ gpiochip_enable_irq(chip, data->hwirq);
gpio->irq_enabled[data->hwirq] = true;
}
@@ -119,14 +121,15 @@ static void max77620_gpio_bus_sync_unlock(struct irq_data *data)
mutex_unlock(&gpio->buslock);
}
-static struct irq_chip max77620_gpio_irqchip = {
+static const struct irq_chip max77620_gpio_irqchip = {
.name = "max77620-gpio",
.irq_mask = max77620_gpio_irq_mask,
.irq_unmask = max77620_gpio_irq_unmask,
.irq_set_type = max77620_gpio_set_irq_type,
.irq_bus_lock = max77620_gpio_bus_lock,
.irq_bus_sync_unlock = max77620_gpio_bus_sync_unlock,
- .flags = IRQCHIP_MASK_ON_SUSPEND,
+ .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
@@ -318,7 +321,7 @@ static int max77620_gpio_probe(struct platform_device *pdev)
mgpio->gpio_chip.base = -1;
girq = &mgpio->gpio_chip.irq;
- girq->chip = &max77620_gpio_irqchip;
+ gpio_irq_chip_set_chip(girq, &max77620_gpio_irqchip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c
index 1e21c661d79d..a035a9bcb57c 100644
--- a/drivers/gpio/gpio-menz127.c
+++ b/drivers/gpio/gpio-menz127.c
@@ -64,7 +64,7 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
debounce /= 50;
}
- spin_lock(&gc->bgpio_lock);
+ raw_spin_lock(&gc->bgpio_lock);
db_en = readl(priv->reg_base + MEN_Z127_DBER);
@@ -79,7 +79,7 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
writel(db_en, priv->reg_base + MEN_Z127_DBER);
writel(db_cnt, priv->reg_base + GPIO_TO_DBCNT_REG(gpio));
- spin_unlock(&gc->bgpio_lock);
+ raw_spin_unlock(&gc->bgpio_lock);
return 0;
}
@@ -91,7 +91,7 @@ static int men_z127_set_single_ended(struct gpio_chip *gc,
struct men_z127_gpio *priv = gpiochip_get_data(gc);
u32 od_en;
- spin_lock(&gc->bgpio_lock);
+ raw_spin_lock(&gc->bgpio_lock);
od_en = readl(priv->reg_base + MEN_Z127_ODER);
if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
@@ -101,7 +101,7 @@ static int men_z127_set_single_ended(struct gpio_chip *gc,
od_en &= ~BIT(offset);
writel(od_en, priv->reg_base + MEN_Z127_ODER);
- spin_unlock(&gc->bgpio_lock);
+ raw_spin_unlock(&gc->bgpio_lock);
return 0;
}
diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c
index f3d1baeacbe9..72ac09a59702 100644
--- a/drivers/gpio/gpio-merrifield.c
+++ b/drivers/gpio/gpio-merrifield.c
@@ -220,10 +220,8 @@ static void mrfld_irq_ack(struct irq_data *d)
raw_spin_unlock_irqrestore(&priv->lock, flags);
}
-static void mrfld_irq_unmask_mask(struct irq_data *d, bool unmask)
+static void mrfld_irq_unmask_mask(struct mrfld_gpio *priv, u32 gpio, bool unmask)
{
- struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
- u32 gpio = irqd_to_hwirq(d);
void __iomem *gimr = gpio_reg(&priv->chip, gpio, GIMR);
unsigned long flags;
u32 value;
@@ -241,12 +239,20 @@ static void mrfld_irq_unmask_mask(struct irq_data *d, bool unmask)
static void mrfld_irq_mask(struct irq_data *d)
{
- mrfld_irq_unmask_mask(d, false);
+ struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
+ u32 gpio = irqd_to_hwirq(d);
+
+ mrfld_irq_unmask_mask(priv, gpio, false);
+ gpiochip_disable_irq(&priv->chip, gpio);
}
static void mrfld_irq_unmask(struct irq_data *d)
{
- mrfld_irq_unmask_mask(d, true);
+ struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
+ u32 gpio = irqd_to_hwirq(d);
+
+ gpiochip_enable_irq(&priv->chip, gpio);
+ mrfld_irq_unmask_mask(priv, gpio, true);
}
static int mrfld_irq_set_type(struct irq_data *d, unsigned int type)
@@ -329,13 +335,15 @@ static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
-static struct irq_chip mrfld_irqchip = {
+static const struct irq_chip mrfld_irqchip = {
.name = "gpio-merrifield",
.irq_ack = mrfld_irq_ack,
.irq_mask = mrfld_irq_mask,
.irq_unmask = mrfld_irq_unmask,
.irq_set_type = mrfld_irq_set_type,
.irq_set_wake = mrfld_irq_set_wake,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static void mrfld_irq_handler(struct irq_desc *desc)
@@ -482,7 +490,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
return retval;
girq = &priv->chip.irq;
- girq->chip = &mrfld_irqchip;
+ gpio_irq_chip_set_chip(girq, &mrfld_irqchip);
girq->init_hw = mrfld_irq_init_hw;
girq->parent_handler = mrfld_irq_handler;
girq->num_parents = 1;
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index b060c4773698..48e3768a830e 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -409,29 +409,27 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
void *chip_save;
int irq_base;
- ret = pci_enable_device(pdev);
+ ret = pcim_enable_device(pdev);
if (ret) {
- dev_err(dev, "%s : pci_enable_device failed", __func__);
- goto err_pci_enable;
+ dev_err(dev, "%s : pcim_enable_device failed", __func__);
+ return ret;
}
- ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME);
if (ret) {
- dev_err(dev, "pci_request_regions failed-%d", ret);
- goto err_request_regions;
+ dev_err(dev, "pcim_iomap_regions failed-%d", ret);
+ return ret;
}
- base = pci_iomap(pdev, 1, 0);
+ base = pcim_iomap_table(pdev)[1];
if (!base) {
- dev_err(dev, "%s : pci_iomap failed", __func__);
- ret = -ENOMEM;
- goto err_iomap;
+ dev_err(dev, "%s : pcim_iomap_table failed", __func__);
+ return -ENOMEM;
}
- chip_save = kcalloc(8, sizeof(*chip), GFP_KERNEL);
+ chip_save = devm_kcalloc(dev, 8, sizeof(*chip), GFP_KERNEL);
if (chip_save == NULL) {
- ret = -ENOMEM;
- goto err_kzalloc;
+ return -ENOMEM;
}
chip = chip_save;
@@ -442,10 +440,10 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
chip->ch = i;
spin_lock_init(&chip->spinlock);
ioh_gpio_setup(chip, num_ports[i]);
- ret = gpiochip_add_data(&chip->gpio, chip);
+ ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
if (ret) {
dev_err(dev, "IOH gpio: Failed to register GPIO\n");
- goto err_gpiochip_add;
+ return ret;
}
}
@@ -456,15 +454,14 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
if (irq_base < 0) {
dev_warn(dev,
"ml_ioh_gpio: Failed to get IRQ base num\n");
- ret = irq_base;
- goto err_gpiochip_add;
+ return irq_base;
}
chip->irq_base = irq_base;
ret = ioh_gpio_alloc_generic_chip(chip,
irq_base, num_ports[j]);
if (ret)
- goto err_gpiochip_add;
+ return ret;
}
chip = chip_save;
@@ -472,52 +469,12 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
IRQF_SHARED, KBUILD_MODNAME, chip);
if (ret != 0) {
dev_err(dev, "%s request_irq failed\n", __func__);
- goto err_gpiochip_add;
+ return ret;
}
pci_set_drvdata(pdev, chip);
return 0;
-
-err_gpiochip_add:
- chip = chip_save;
- while (--i >= 0) {
- gpiochip_remove(&chip->gpio);
- chip++;
- }
- kfree(chip_save);
-
-err_kzalloc:
- pci_iounmap(pdev, base);
-
-err_iomap:
- pci_release_regions(pdev);
-
-err_request_regions:
- pci_disable_device(pdev);
-
-err_pci_enable:
-
- dev_err(dev, "%s Failed returns %d\n", __func__, ret);
- return ret;
-}
-
-static void ioh_gpio_remove(struct pci_dev *pdev)
-{
- int i;
- struct ioh_gpio *chip = pci_get_drvdata(pdev);
- void *chip_save;
-
- chip_save = chip;
-
- for (i = 0; i < 8; i++, chip++)
- gpiochip_remove(&chip->gpio);
-
- chip = chip_save;
- pci_iounmap(pdev, chip->base);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- kfree(chip);
}
static int __maybe_unused ioh_gpio_suspend(struct device *dev)
@@ -558,7 +515,6 @@ static struct pci_driver ioh_gpio_driver = {
.name = "ml_ioh_gpio",
.id_table = ioh_gpio_pcidev_id,
.probe = ioh_gpio_probe,
- .remove = ioh_gpio_remove,
.driver = {
.pm = &ioh_gpio_pm_ops,
},
diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c
index 3d89912a05b8..64cb060d9d75 100644
--- a/drivers/gpio/gpio-mlxbf2.c
+++ b/drivers/gpio/gpio-mlxbf2.c
@@ -131,7 +131,7 @@ static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs)
u32 arm_gpio_lock_val;
mutex_lock(yu_arm_gpio_lock_param.lock);
- spin_lock(&gs->gc.bgpio_lock);
+ raw_spin_lock(&gs->gc.bgpio_lock);
arm_gpio_lock_val = readl(yu_arm_gpio_lock_param.io);
@@ -139,7 +139,7 @@ static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs)
* When lock active bit[31] is set, ModeX is write enabled
*/
if (YU_LOCK_ACTIVE_BIT(arm_gpio_lock_val)) {
- spin_unlock(&gs->gc.bgpio_lock);
+ raw_spin_unlock(&gs->gc.bgpio_lock);
mutex_unlock(yu_arm_gpio_lock_param.lock);
return -EINVAL;
}
@@ -157,7 +157,7 @@ static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs)
__releases(yu_arm_gpio_lock_param.lock)
{
writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io);
- spin_unlock(&gs->gc.bgpio_lock);
+ raw_spin_unlock(&gs->gc.bgpio_lock);
mutex_unlock(yu_arm_gpio_lock_param.lock);
}
@@ -237,7 +237,7 @@ static void mlxbf2_gpio_irq_enable(struct irq_data *irqd)
unsigned long flags;
u32 val;
- spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
val |= BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE);
@@ -245,7 +245,7 @@ static void mlxbf2_gpio_irq_enable(struct irq_data *irqd)
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
val |= BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
- spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
}
static void mlxbf2_gpio_irq_disable(struct irq_data *irqd)
@@ -256,11 +256,11 @@ static void mlxbf2_gpio_irq_disable(struct irq_data *irqd)
unsigned long flags;
u32 val;
- spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
val &= ~BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0);
- spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
}
static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr)
@@ -307,7 +307,7 @@ mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
return -EINVAL;
}
- spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gs->gc.bgpio_lock, flags);
if (fall) {
val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN);
val |= BIT(offset);
@@ -319,7 +319,7 @@ mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
val |= BIT(offset);
writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN);
}
- spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
return 0;
}
diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c
index c335a0309ba3..d9dff3dc92ae 100644
--- a/drivers/gpio/gpio-mmio.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -220,7 +220,7 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
unsigned long mask = bgpio_line2mask(gc, gpio);
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
if (val)
gc->bgpio_data |= mask;
@@ -229,7 +229,7 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
gc->write_reg(gc->reg_dat, gc->bgpio_data);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
@@ -248,7 +248,7 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
unsigned long mask = bgpio_line2mask(gc, gpio);
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
if (val)
gc->bgpio_data |= mask;
@@ -257,7 +257,7 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
gc->write_reg(gc->reg_set, gc->bgpio_data);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void bgpio_multiple_get_masks(struct gpio_chip *gc,
@@ -286,7 +286,7 @@ static void bgpio_set_multiple_single_reg(struct gpio_chip *gc,
unsigned long flags;
unsigned long set_mask, clear_mask;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
@@ -295,7 +295,7 @@ static void bgpio_set_multiple_single_reg(struct gpio_chip *gc,
gc->write_reg(reg, gc->bgpio_data);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
@@ -347,7 +347,7 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
@@ -356,7 +356,7 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
if (gc->reg_dir_out)
gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -387,7 +387,7 @@ static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
@@ -396,7 +396,7 @@ static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
if (gc->reg_dir_out)
gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
@@ -610,7 +610,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
if (gc->bgpio_bits > BITS_PER_LONG)
return -EINVAL;
- spin_lock_init(&gc->bgpio_lock);
+ raw_spin_lock_init(&gc->bgpio_lock);
gc->parent = dev;
gc->label = dev_name(dev);
gc->base = -1;
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index a964e25ea620..15049822937a 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIOs on MPC512x/8349/8572/8610/QorIQ and compatible
*
* Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
* Copyright (C) 2016 Freescale Semiconductor Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
*/
#include <linux/acpi.h>
diff --git a/drivers/gpio/gpio-msc313.c b/drivers/gpio/gpio-msc313.c
index b2c90bdd39d0..52d7b8d99170 100644
--- a/drivers/gpio/gpio-msc313.c
+++ b/drivers/gpio/gpio-msc313.c
@@ -550,15 +550,12 @@ static struct irq_chip msc313_gpio_irqchip = {
* so we need to provide the fwspec. Essentially gpiochip_populate_parent_fwspec_twocell
* that puts GIC_SPI into the first cell.
*/
-static void *msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
- unsigned int parent_hwirq,
- unsigned int parent_type)
+static int msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
+ union gpio_irq_fwspec *gfwspec,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
{
- struct irq_fwspec *fwspec;
-
- fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
- if (!fwspec)
- return NULL;
+ struct irq_fwspec *fwspec = &gfwspec->fwspec;
fwspec->fwnode = gc->irq.parent_domain->fwnode;
fwspec->param_count = 3;
@@ -566,7 +563,7 @@ static void *msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
fwspec->param[1] = parent_hwirq;
fwspec->param[2] = parent_type;
- return fwspec;
+ return 0;
}
static int msc313e_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 2db19cd640a4..aa126ab80f0c 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO driver for Marvell SoCs
*
@@ -7,10 +8,6 @@
* Andrew Lunn <andrew@lunn.ch>
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
*
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- *
* This driver is a fairly straightforward GPIO driver for the
* complete family of Marvell EBU SoC platforms (Orion, Dove,
* Kirkwood, Discovery, Armada 370/XP). The only complexity of this
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index c5166cd47c9c..7f59e5d936c2 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
//
-// MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
+// MXS GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
// Copyright 2008 Juergen Beisert, kernel@pengutronix.de
//
// Based on code from Freescale,
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 8726921a1129..ecd7d169470b 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -71,6 +71,7 @@
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
static const struct i2c_device_id pca953x_id[] = {
+ { "pca6408", 8 | PCA953X_TYPE | PCA_INT, },
{ "pca6416", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
{ "pca9506", 40 | PCA953X_TYPE | PCA_INT, },
@@ -200,7 +201,6 @@ struct pca953x_chip {
DECLARE_BITMAP(irq_stat, MAX_LINE);
DECLARE_BITMAP(irq_trig_raise, MAX_LINE);
DECLARE_BITMAP(irq_trig_fall, MAX_LINE);
- struct irq_chip irq_chip;
#endif
atomic_t wakeup_path;
@@ -351,6 +351,9 @@ static const struct regmap_config pca953x_i2c_regmap = {
.reg_bits = 8,
.val_bits = 8,
+ .use_single_read = true,
+ .use_single_write = true,
+
.readable_reg = pca953x_readable_register,
.writeable_reg = pca953x_writeable_register,
.volatile_reg = pca953x_volatile_register,
@@ -628,6 +631,7 @@ static void pca953x_irq_mask(struct irq_data *d)
irq_hw_number_t hwirq = irqd_to_hwirq(d);
clear_bit(hwirq, chip->irq_mask);
+ gpiochip_disable_irq(gc, hwirq);
}
static void pca953x_irq_unmask(struct irq_data *d)
@@ -636,6 +640,7 @@ static void pca953x_irq_unmask(struct irq_data *d)
struct pca953x_chip *chip = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
+ gpiochip_enable_irq(gc, hwirq);
set_bit(hwirq, chip->irq_mask);
}
@@ -720,6 +725,26 @@ static void pca953x_irq_shutdown(struct irq_data *d)
clear_bit(hwirq, chip->irq_trig_fall);
}
+static void pca953x_irq_print_chip(struct irq_data *data, struct seq_file *p)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+
+ seq_printf(p, dev_name(gc->parent));
+}
+
+static const struct irq_chip pca953x_irq_chip = {
+ .irq_mask = pca953x_irq_mask,
+ .irq_unmask = pca953x_irq_unmask,
+ .irq_set_wake = pca953x_irq_set_wake,
+ .irq_bus_lock = pca953x_irq_bus_lock,
+ .irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock,
+ .irq_set_type = pca953x_irq_set_type,
+ .irq_shutdown = pca953x_irq_shutdown,
+ .irq_print_chip = pca953x_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pending)
{
struct gpio_chip *gc = &chip->gpio_chip;
@@ -811,7 +836,6 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
{
struct i2c_client *client = chip->client;
- struct irq_chip *irq_chip = &chip->irq_chip;
DECLARE_BITMAP(reg_direction, MAX_LINE);
DECLARE_BITMAP(irq_stat, MAX_LINE);
struct gpio_irq_chip *girq;
@@ -845,17 +869,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
bitmap_and(chip->irq_stat, irq_stat, reg_direction, chip->gpio_chip.ngpio);
mutex_init(&chip->irq_lock);
- irq_chip->name = dev_name(&client->dev);
- irq_chip->irq_mask = pca953x_irq_mask;
- irq_chip->irq_unmask = pca953x_irq_unmask;
- irq_chip->irq_set_wake = pca953x_irq_set_wake;
- irq_chip->irq_bus_lock = pca953x_irq_bus_lock;
- irq_chip->irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock;
- irq_chip->irq_set_type = pca953x_irq_set_type;
- irq_chip->irq_shutdown = pca953x_irq_shutdown;
-
girq = &chip->gpio_chip.irq;
- girq->chip = irq_chip;
+ gpio_irq_chip_set_chip(girq, &pca953x_irq_chip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
@@ -894,15 +909,18 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
{
DECLARE_BITMAP(val, MAX_LINE);
+ u8 regaddr;
int ret;
- ret = regcache_sync_region(chip->regmap, chip->regs->output,
- chip->regs->output + NBANK(chip));
+ regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
+ ret = regcache_sync_region(chip->regmap, regaddr,
+ regaddr + NBANK(chip) - 1);
if (ret)
goto out;
- ret = regcache_sync_region(chip->regmap, chip->regs->direction,
- chip->regs->direction + NBANK(chip));
+ regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
+ ret = regcache_sync_region(chip->regmap, regaddr,
+ regaddr + NBANK(chip) - 1);
if (ret)
goto out;
@@ -1108,20 +1126,21 @@ static int pca953x_regcache_sync(struct device *dev)
{
struct pca953x_chip *chip = dev_get_drvdata(dev);
int ret;
+ u8 regaddr;
/*
* The ordering between direction and output is important,
* sync these registers first and only then sync the rest.
*/
- ret = regcache_sync_region(chip->regmap, chip->regs->direction,
- chip->regs->direction + NBANK(chip));
+ regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
+ ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
if (ret) {
dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
return ret;
}
- ret = regcache_sync_region(chip->regmap, chip->regs->output,
- chip->regs->output + NBANK(chip));
+ regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
+ ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
if (ret) {
dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
return ret;
@@ -1129,16 +1148,18 @@ static int pca953x_regcache_sync(struct device *dev)
#ifdef CONFIG_GPIO_PCA953X_IRQ
if (chip->driver_data & PCA_PCAL) {
- ret = regcache_sync_region(chip->regmap, PCAL953X_IN_LATCH,
- PCAL953X_IN_LATCH + NBANK(chip));
+ regaddr = pca953x_recalc_addr(chip, PCAL953X_IN_LATCH, 0);
+ ret = regcache_sync_region(chip->regmap, regaddr,
+ regaddr + NBANK(chip) - 1);
if (ret) {
dev_err(dev, "Failed to sync INT latch registers: %d\n",
ret);
return ret;
}
- ret = regcache_sync_region(chip->regmap, PCAL953X_INT_MASK,
- PCAL953X_INT_MASK + NBANK(chip));
+ regaddr = pca953x_recalc_addr(chip, PCAL953X_INT_MASK, 0);
+ ret = regcache_sync_region(chip->regmap, regaddr,
+ regaddr + NBANK(chip) - 1);
if (ret) {
dev_err(dev, "Failed to sync INT mask registers: %d\n",
ret);
@@ -1198,6 +1219,7 @@ static int pca953x_resume(struct device *dev)
#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
static const struct of_device_id pca953x_dt_ids[] = {
+ { .compatible = "nxp,pca6408", .data = OF_953X(8, PCA_INT), },
{ .compatible = "nxp,pca6416", .data = OF_953X(16, PCA_INT), },
{ .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
{ .compatible = "nxp,pca9506", .data = OF_953X(40, PCA_INT), },
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c
index cb2b2f735c15..ab2a652964ec 100644
--- a/drivers/gpio/gpio-pca9570.c
+++ b/drivers/gpio/gpio-pca9570.c
@@ -121,12 +121,14 @@ static int pca9570_probe(struct i2c_client *client)
static const struct i2c_device_id pca9570_id_table[] = {
{ "pca9570", 4 },
+ { "pca9571", 8 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
static const struct of_device_id pca9570_of_match_table[] = {
{ .compatible = "nxp,pca9570", .data = (void *)4 },
+ { .compatible = "nxp,pca9571", .data = (void *)8 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pca9570_of_match_table);
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index b7568ee33696..59cc27e4de51 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -71,7 +71,6 @@ MODULE_DEVICE_TABLE(of, pcf857x_of_table);
*/
struct pcf857x {
struct gpio_chip chip;
- struct irq_chip irqchip;
struct i2c_client *client;
struct mutex lock; /* protect 'out' */
unsigned out; /* software latch */
@@ -203,15 +202,19 @@ static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
static void pcf857x_irq_enable(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
- gpio->irq_enabled |= (1 << data->hwirq);
+ gpiochip_enable_irq(&gpio->chip, hwirq);
+ gpio->irq_enabled |= (1 << hwirq);
}
static void pcf857x_irq_disable(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+ irq_hw_number_t hwirq = irqd_to_hwirq(data);
- gpio->irq_enabled &= ~(1 << data->hwirq);
+ gpio->irq_enabled &= ~(1 << hwirq);
+ gpiochip_disable_irq(&gpio->chip, hwirq);
}
static void pcf857x_irq_bus_lock(struct irq_data *data)
@@ -228,6 +231,20 @@ static void pcf857x_irq_bus_sync_unlock(struct irq_data *data)
mutex_unlock(&gpio->lock);
}
+static const struct irq_chip pcf857x_irq_chip = {
+ .name = "pcf857x",
+ .irq_enable = pcf857x_irq_enable,
+ .irq_disable = pcf857x_irq_disable,
+ .irq_ack = noop,
+ .irq_mask = noop,
+ .irq_unmask = noop,
+ .irq_set_wake = pcf857x_irq_set_wake,
+ .irq_bus_lock = pcf857x_irq_bus_lock,
+ .irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
/*-------------------------------------------------------------------------*/
static int pcf857x_probe(struct i2c_client *client,
@@ -338,16 +355,6 @@ static int pcf857x_probe(struct i2c_client *client,
if (client->irq) {
struct gpio_irq_chip *girq;
- gpio->irqchip.name = "pcf857x";
- gpio->irqchip.irq_enable = pcf857x_irq_enable;
- gpio->irqchip.irq_disable = pcf857x_irq_disable;
- gpio->irqchip.irq_ack = noop;
- gpio->irqchip.irq_mask = noop;
- gpio->irqchip.irq_unmask = noop;
- gpio->irqchip.irq_set_wake = pcf857x_irq_set_wake;
- gpio->irqchip.irq_bus_lock = pcf857x_irq_bus_lock;
- gpio->irqchip.irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock;
-
status = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf857x_irq, IRQF_ONESHOT |
IRQF_TRIGGER_FALLING | IRQF_SHARED,
@@ -356,7 +363,7 @@ static int pcf857x_probe(struct i2c_client *client,
goto fail;
girq = &gpio->chip.irq;
- girq->chip = &gpio->irqchip;
+ gpio_irq_chip_set_chip(girq, &pcf857x_irq_chip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
@@ -396,20 +403,12 @@ static int pcf857x_remove(struct i2c_client *client)
{
struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
struct pcf857x *gpio = i2c_get_clientdata(client);
- int status = 0;
- if (pdata && pdata->teardown) {
- status = pdata->teardown(client,
- gpio->chip.base, gpio->chip.ngpio,
+ if (pdata && pdata->teardown)
+ pdata->teardown(client, gpio->chip.base, gpio->chip.ngpio,
pdata->context);
- if (status < 0) {
- dev_err(&client->dev, "%s --> %d\n",
- "teardown", status);
- return status;
- }
- }
- return status;
+ return 0;
}
static void pcf857x_shutdown(struct i2c_client *client)
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 3a0bd8795741..ee37ecb615cb 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -37,6 +37,11 @@ struct pch_regs {
u32 reset;
};
+#define PCI_DEVICE_ID_INTEL_EG20T_PCH 0x8803
+#define PCI_DEVICE_ID_ROHM_ML7223m_IOH 0x8014
+#define PCI_DEVICE_ID_ROHM_ML7223n_IOH 0x8043
+#define PCI_DEVICE_ID_ROHM_EG20T_PCH 0x8803
+
enum pch_type_t {
INTEL_EG20T_PCH,
OKISEMI_ML7223m_IOH, /* LAPIS Semiconductor ML7223 IOH PCIe Bus-m */
@@ -357,16 +362,12 @@ static int pch_gpio_probe(struct pci_dev *pdev,
chip->dev = dev;
ret = pcim_enable_device(pdev);
- if (ret) {
- dev_err(dev, "pci_enable_device FAILED");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable PCI device\n");
ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME);
- if (ret) {
- dev_err(dev, "pci_request_regions FAILED-%d", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request and map PCI regions\n");
chip->base = pcim_iomap_table(pdev)[1];
chip->ioh = id->driver_data;
@@ -376,10 +377,8 @@ static int pch_gpio_probe(struct pci_dev *pdev,
pch_gpio_setup(chip);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
- if (ret) {
- dev_err(dev, "PCH gpio: Failed to register GPIO\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register GPIO\n");
irq_base = devm_irq_alloc_descs(dev, -1, 0,
gpio_pins[chip->ioh], NUMA_NO_NODE);
@@ -396,10 +395,8 @@ static int pch_gpio_probe(struct pci_dev *pdev,
ret = devm_request_irq(dev, pdev->irq, pch_gpio_handler,
IRQF_SHARED, KBUILD_MODNAME, chip);
- if (ret) {
- dev_err(dev, "request_irq failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request IRQ\n");
return pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
}
@@ -433,15 +430,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume);
static const struct pci_device_id pch_gpio_pcidev_id[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803),
- .driver_data = INTEL_EG20T_PCH },
- { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014),
- .driver_data = OKISEMI_ML7223m_IOH },
- { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043),
- .driver_data = OKISEMI_ML7223n_IOH },
- { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803),
- .driver_data = INTEL_EG20T_PCH },
- { 0, }
+ { PCI_DEVICE_DATA(INTEL, EG20T_PCH, INTEL_EG20T_PCH) },
+ { PCI_DEVICE_DATA(ROHM, ML7223m_IOH, OKISEMI_ML7223m_IOH) },
+ { PCI_DEVICE_DATA(ROHM, ML7223n_IOH, OKISEMI_ML7223n_IOH) },
+ { PCI_DEVICE_DATA(ROHM, EG20T_PCH, INTEL_EG20T_PCH) },
+ { }
};
MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id);
diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c
index 81a47ae09ff8..67071bea08c2 100644
--- a/drivers/gpio/gpio-pisosr.c
+++ b/drivers/gpio/gpio-pisosr.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License version 2 for more details.
*/
#include <linux/bitmap.h>
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 4ecab700f23f..6464056cb6ae 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -52,7 +52,6 @@ struct pl061 {
void __iomem *base;
struct gpio_chip gc;
- struct irq_chip irq_chip;
int parent_irq;
#ifdef CONFIG_PM
@@ -241,6 +240,8 @@ static void pl061_irq_mask(struct irq_data *d)
gpioie = readb(pl061->base + GPIOIE) & ~mask;
writeb(gpioie, pl061->base + GPIOIE);
raw_spin_unlock(&pl061->lock);
+
+ gpiochip_disable_irq(gc, d->hwirq);
}
static void pl061_irq_unmask(struct irq_data *d)
@@ -250,6 +251,8 @@ static void pl061_irq_unmask(struct irq_data *d)
u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
u8 gpioie;
+ gpiochip_enable_irq(gc, d->hwirq);
+
raw_spin_lock(&pl061->lock);
gpioie = readb(pl061->base + GPIOIE) | mask;
writeb(gpioie, pl061->base + GPIOIE);
@@ -283,6 +286,24 @@ static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
return irq_set_irq_wake(pl061->parent_irq, state);
}
+static void pl061_irq_print_chip(struct irq_data *data, struct seq_file *p)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+
+ seq_printf(p, dev_name(gc->parent));
+}
+
+static const struct irq_chip pl061_irq_chip = {
+ .irq_ack = pl061_irq_ack,
+ .irq_mask = pl061_irq_mask,
+ .irq_unmask = pl061_irq_unmask,
+ .irq_set_type = pl061_irq_type,
+ .irq_set_wake = pl061_irq_set_wake,
+ .irq_print_chip = pl061_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
@@ -315,13 +336,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
/*
* irq_chip support
*/
- pl061->irq_chip.name = dev_name(dev);
- pl061->irq_chip.irq_ack = pl061_irq_ack;
- pl061->irq_chip.irq_mask = pl061_irq_mask;
- pl061->irq_chip.irq_unmask = pl061_irq_unmask;
- pl061->irq_chip.irq_set_type = pl061_irq_type;
- pl061->irq_chip.irq_set_wake = pl061_irq_set_wake;
-
writeb(0, pl061->base + GPIOIE); /* disable irqs */
irq = adev->irq[0];
if (!irq)
@@ -329,7 +343,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
pl061->parent_irq = irq;
girq = &pl061->gc.irq;
- girq->chip = &pl061->irq_chip;
+ gpio_irq_chip_set_chip(girq, &pl061_irq_chip);
girq->parent_handler = pl061_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 3a76538f27fa..5b117f3bd322 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -44,7 +44,6 @@ struct gpio_rcar_priv {
spinlock_t lock;
struct device *dev;
struct gpio_chip gpio_chip;
- struct irq_chip irq_chip;
unsigned int irq_parent;
atomic_t wakeup_path;
struct gpio_rcar_info info;
@@ -96,16 +95,20 @@ static void gpio_rcar_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
- gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
+ gpio_rcar_write(p, INTMSK, ~BIT(hwirq));
+ gpiochip_disable_irq(gc, hwirq);
}
static void gpio_rcar_irq_enable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
- gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
+ gpiochip_enable_irq(gc, hwirq);
+ gpio_rcar_write(p, MSKCLR, BIT(hwirq));
}
static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
@@ -203,6 +206,17 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
+static const struct irq_chip gpio_rcar_irq_chip = {
+ .name = "gpio-rcar",
+ .irq_mask = gpio_rcar_irq_disable,
+ .irq_unmask = gpio_rcar_irq_enable,
+ .irq_set_type = gpio_rcar_irq_set_type,
+ .irq_set_wake = gpio_rcar_irq_set_wake,
+ .flags = IRQCHIP_IMMUTABLE | IRQCHIP_SET_TYPE_MASKED |
+ IRQCHIP_MASK_ON_SUSPEND,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
{
struct gpio_rcar_priv *p = dev_id;
@@ -411,7 +425,7 @@ static const struct gpio_rcar_info gpio_rcar_info_gen3 = {
.has_inen = false,
};
-static const struct gpio_rcar_info gpio_rcar_info_v3u = {
+static const struct gpio_rcar_info gpio_rcar_info_gen4 = {
.has_outdtsel = true,
.has_both_edge_trigger = true,
.has_always_in = true,
@@ -421,7 +435,7 @@ static const struct gpio_rcar_info gpio_rcar_info_v3u = {
static const struct of_device_id gpio_rcar_of_table[] = {
{
.compatible = "renesas,gpio-r8a779a0",
- .data = &gpio_rcar_info_v3u,
+ .data = &gpio_rcar_info_gen4,
}, {
.compatible = "renesas,rcar-gen1-gpio",
.data = &gpio_rcar_info_gen1,
@@ -432,6 +446,9 @@ static const struct of_device_id gpio_rcar_of_table[] = {
.compatible = "renesas,rcar-gen3-gpio",
.data = &gpio_rcar_info_gen3,
}, {
+ .compatible = "renesas,rcar-gen4-gpio",
+ .data = &gpio_rcar_info_gen4,
+ }, {
.compatible = "renesas,gpio-rcar",
.data = &gpio_rcar_info_gen1,
}, {
@@ -478,7 +495,6 @@ static int gpio_rcar_probe(struct platform_device *pdev)
{
struct gpio_rcar_priv *p;
struct gpio_chip *gpio_chip;
- struct irq_chip *irq_chip;
struct gpio_irq_chip *girq;
struct device *dev = &pdev->dev;
const char *name = dev_name(dev);
@@ -528,16 +544,8 @@ static int gpio_rcar_probe(struct platform_device *pdev)
gpio_chip->base = -1;
gpio_chip->ngpio = npins;
- irq_chip = &p->irq_chip;
- irq_chip->name = "gpio-rcar";
- 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;
- irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
- irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
-
girq = &gpio_chip->irq;
- girq->chip = irq_chip;
+ gpio_irq_chip_set_chip(girq, &gpio_rcar_irq_chip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-realtek-otto.c b/drivers/gpio/gpio-realtek-otto.c
index bd75401b549d..63dcf42f7c20 100644
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/gpio/driver.h>
+#include <linux/cpumask.h>
#include <linux/irq.h>
#include <linux/minmax.h>
#include <linux/mod_devicetable.h>
@@ -55,9 +56,13 @@
struct realtek_gpio_ctrl {
struct gpio_chip gc;
void __iomem *base;
+ void __iomem *cpumask_base;
+ struct cpumask cpu_irq_maskable;
raw_spinlock_t lock;
u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
+ unsigned int (*port_offset_u8)(unsigned int port);
+ unsigned int (*port_offset_u16)(unsigned int port);
};
/* Expand with more flags as devices with other quirks are added */
@@ -69,6 +74,16 @@ enum realtek_gpio_flags {
* line the IRQ handler was assigned to, causing uncaught interrupts.
*/
GPIO_INTERRUPTS_DISABLED = BIT(0),
+ /*
+ * Port order is reversed, meaning DCBA register layout for 1-bit
+ * fields, and [BA, DC] for 2-bit fields.
+ */
+ GPIO_PORTS_REVERSED = BIT(1),
+ /*
+ * Interrupts can be enabled per cpu. This requires a secondary IO
+ * range, where the per-cpu enable masks are located.
+ */
+ GPIO_INTERRUPTS_PER_CPU = BIT(2),
};
static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
@@ -86,21 +101,50 @@ static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
* port. The two interrupt mask registers store two bits per GPIO, so use u16
* values.
*/
+static unsigned int realtek_gpio_port_offset_u8(unsigned int port)
+{
+ return port;
+}
+
+static unsigned int realtek_gpio_port_offset_u16(unsigned int port)
+{
+ return 2 * port;
+}
+
+/*
+ * Reversed port order register access
+ *
+ * For registers with one bit per GPIO, all ports are stored as u8-s in one
+ * register in reversed order. The two interrupt mask registers store two bits
+ * per GPIO, so use u16 values. The first register contains ports 1 and 0, the
+ * second ports 3 and 2.
+ */
+static unsigned int realtek_gpio_port_offset_u8_rev(unsigned int port)
+{
+ return 3 - port;
+}
+
+static unsigned int realtek_gpio_port_offset_u16_rev(unsigned int port)
+{
+ return 2 * (port ^ 1);
+}
+
static void realtek_gpio_write_imr(struct realtek_gpio_ctrl *ctrl,
unsigned int port, u16 irq_type, u16 irq_mask)
{
- iowrite16(irq_type & irq_mask, ctrl->base + REALTEK_GPIO_REG_IMR + 2 * port);
+ iowrite16(irq_type & irq_mask,
+ ctrl->base + REALTEK_GPIO_REG_IMR + ctrl->port_offset_u16(port));
}
static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl,
unsigned int port, u8 mask)
{
- iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + port);
+ iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
}
static u8 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port)
{
- return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + port);
+ return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
}
/* Set the rising and falling edge mask bits for a GPIO port pin */
@@ -128,6 +172,8 @@ static void realtek_gpio_irq_unmask(struct irq_data *data)
unsigned long flags;
u16 m;
+ gpiochip_enable_irq(&ctrl->gc, line);
+
raw_spin_lock_irqsave(&ctrl->lock, flags);
m = ctrl->intr_mask[port];
m |= realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
@@ -151,6 +197,8 @@ static void realtek_gpio_irq_mask(struct irq_data *data)
ctrl->intr_mask[port] = m;
realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ gpiochip_disable_irq(&ctrl->gc, line);
}
static int realtek_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
@@ -211,25 +259,75 @@ static void realtek_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(irq_chip, desc);
}
+static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl,
+ unsigned int port, int cpu)
+{
+ return ctrl->cpumask_base + ctrl->port_offset_u8(port) +
+ REALTEK_GPIO_PORTS_PER_BANK * cpu;
+}
+
+static int realtek_gpio_irq_set_affinity(struct irq_data *data,
+ const struct cpumask *dest, bool force)
+{
+ struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
+ unsigned int line = irqd_to_hwirq(data);
+ unsigned int port = line / 8;
+ unsigned int port_pin = line % 8;
+ void __iomem *irq_cpu_mask;
+ unsigned long flags;
+ int cpu;
+ u8 v;
+
+ if (!ctrl->cpumask_base)
+ return -ENXIO;
+
+ raw_spin_lock_irqsave(&ctrl->lock, flags);
+
+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
+ v = ioread8(irq_cpu_mask);
+
+ if (cpumask_test_cpu(cpu, dest))
+ v |= BIT(port_pin);
+ else
+ v &= ~BIT(port_pin);
+
+ iowrite8(v, irq_cpu_mask);
+ }
+
+ raw_spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ irq_data_update_effective_affinity(data, dest);
+
+ return 0;
+}
+
static int realtek_gpio_irq_init(struct gpio_chip *gc)
{
struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
unsigned int port;
+ int cpu;
for (port = 0; (port * 8) < gc->ngpio; port++) {
realtek_gpio_write_imr(ctrl, port, 0, 0);
realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
+
+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable)
+ iowrite8(GENMASK(7, 0), realtek_gpio_irq_cpu_mask(ctrl, port, cpu));
}
return 0;
}
-static struct irq_chip realtek_gpio_irq_chip = {
+static const struct irq_chip realtek_gpio_irq_chip = {
.name = "realtek-otto-gpio",
.irq_ack = realtek_gpio_irq_ack,
.irq_mask = realtek_gpio_irq_mask,
.irq_unmask = realtek_gpio_irq_unmask,
.irq_set_type = realtek_gpio_irq_set_type,
+ .irq_set_affinity = realtek_gpio_irq_set_affinity,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static const struct of_device_id realtek_gpio_of_match[] = {
@@ -243,6 +341,13 @@ static const struct of_device_id realtek_gpio_of_match[] = {
{
.compatible = "realtek,rtl8390-gpio",
},
+ {
+ .compatible = "realtek,rtl9300-gpio",
+ .data = (void *)(GPIO_PORTS_REVERSED | GPIO_INTERRUPTS_PER_CPU)
+ },
+ {
+ .compatible = "realtek,rtl9310-gpio",
+ },
{}
};
MODULE_DEVICE_TABLE(of, realtek_gpio_of_match);
@@ -250,11 +355,14 @@ MODULE_DEVICE_TABLE(of, realtek_gpio_of_match);
static int realtek_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ unsigned long bgpio_flags;
unsigned int dev_flags;
struct gpio_irq_chip *girq;
struct realtek_gpio_ctrl *ctrl;
+ struct resource *res;
u32 ngpios;
- int err, irq;
+ unsigned int nr_cpus;
+ int cpu, err, irq;
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
@@ -277,10 +385,20 @@ static int realtek_gpio_probe(struct platform_device *pdev)
raw_spin_lock_init(&ctrl->lock);
+ if (dev_flags & GPIO_PORTS_REVERSED) {
+ bgpio_flags = 0;
+ ctrl->port_offset_u8 = realtek_gpio_port_offset_u8_rev;
+ ctrl->port_offset_u16 = realtek_gpio_port_offset_u16_rev;
+ } else {
+ bgpio_flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+ ctrl->port_offset_u8 = realtek_gpio_port_offset_u8;
+ ctrl->port_offset_u16 = realtek_gpio_port_offset_u16;
+ }
+
err = bgpio_init(&ctrl->gc, dev, 4,
ctrl->base + REALTEK_GPIO_REG_DATA, NULL, NULL,
ctrl->base + REALTEK_GPIO_REG_DIR, NULL,
- BGPIOF_BIG_ENDIAN_BYTE_ORDER);
+ bgpio_flags);
if (err) {
dev_err(dev, "unable to init generic GPIO");
return err;
@@ -292,7 +410,7 @@ static int realtek_gpio_probe(struct platform_device *pdev)
irq = platform_get_irq_optional(pdev, 0);
if (!(dev_flags & GPIO_INTERRUPTS_DISABLED) && irq > 0) {
girq = &ctrl->gc.irq;
- girq->chip = &realtek_gpio_irq_chip;
+ gpio_irq_chip_set_chip(girq, &realtek_gpio_irq_chip);
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
girq->parent_handler = realtek_gpio_irq_handler;
@@ -305,6 +423,21 @@ static int realtek_gpio_probe(struct platform_device *pdev)
girq->init_hw = realtek_gpio_irq_init;
}
+ cpumask_clear(&ctrl->cpu_irq_maskable);
+
+ if ((dev_flags & GPIO_INTERRUPTS_PER_CPU) && irq > 0) {
+ ctrl->cpumask_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
+ if (IS_ERR(ctrl->cpumask_base))
+ return dev_err_probe(dev, PTR_ERR(ctrl->cpumask_base),
+ "missing CPU IRQ mask registers");
+
+ nr_cpus = resource_size(res) / REALTEK_GPIO_PORTS_PER_BANK;
+ nr_cpus = min(nr_cpus, num_present_cpus());
+
+ for (cpu = 0; cpu < nr_cpus; cpu++)
+ cpumask_set_cpu(cpu, &ctrl->cpu_irq_maskable);
+ }
+
return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
}
diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 099e358d2491..f91e876fd969 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -19,6 +19,7 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/pinctrl/pinconf-generic.h>
#include <linux/regmap.h>
#include "../pinctrl/core.h"
@@ -26,6 +27,7 @@
#define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */
#define GPIO_TYPE_V2 (0x01000C2B) /* GPIO Version ID 0x01000C2B */
+#define GPIO_TYPE_V2_1 (0x0101157C) /* GPIO Version ID 0x0101157C */
static const struct rockchip_gpio_regs gpio_regs_v1 = {
.port_dr = 0x00,
@@ -663,7 +665,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
id = readl(bank->reg_base + gpio_regs_v2.version_id);
/* If not gpio v2, that is default to v1. */
- if (id == GPIO_TYPE_V2) {
+ if (id == GPIO_TYPE_V2 || id == GPIO_TYPE_V2_1) {
bank->gpio_regs = &gpio_regs_v2;
bank->gpio_type = GPIO_TYPE_V2;
bank->db_clk = of_clk_get(bank->of_node, 1);
@@ -706,7 +708,7 @@ static int rockchip_gpio_probe(struct platform_device *pdev)
struct device_node *pctlnp = of_get_parent(np);
struct pinctrl_dev *pctldev = NULL;
struct rockchip_pin_bank *bank = NULL;
- struct rockchip_pin_output_deferred *cfg;
+ struct rockchip_pin_deferred *cfg;
static int gpio;
int id, ret;
@@ -747,15 +749,27 @@ static int rockchip_gpio_probe(struct platform_device *pdev)
return ret;
}
- while (!list_empty(&bank->deferred_output)) {
- cfg = list_first_entry(&bank->deferred_output,
- struct rockchip_pin_output_deferred, head);
+ while (!list_empty(&bank->deferred_pins)) {
+ cfg = list_first_entry(&bank->deferred_pins,
+ struct rockchip_pin_deferred, head);
list_del(&cfg->head);
- ret = rockchip_gpio_direction_output(&bank->gpio_chip, cfg->pin, cfg->arg);
- if (ret)
- dev_warn(dev, "setting output pin %u to %u failed\n", cfg->pin, cfg->arg);
-
+ switch (cfg->param) {
+ case PIN_CONFIG_OUTPUT:
+ ret = rockchip_gpio_direction_output(&bank->gpio_chip, cfg->pin, cfg->arg);
+ if (ret)
+ dev_warn(dev, "setting output pin %u to %u failed\n", cfg->pin,
+ cfg->arg);
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ ret = rockchip_gpio_direction_input(&bank->gpio_chip, cfg->pin);
+ if (ret)
+ dev_warn(dev, "setting input pin %u failed\n", cfg->pin);
+ break;
+ default:
+ dev_warn(dev, "unknown deferred config param %d\n", cfg->param);
+ break;
+ }
kfree(cfg);
}
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index acda4c5052d3..8a83f7bf4382 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -38,7 +38,6 @@
struct sch_gpio {
struct gpio_chip chip;
- struct irq_chip irqchip;
spinlock_t lock;
unsigned short iobase;
unsigned short resume_base;
@@ -218,11 +217,9 @@ static void sch_irq_ack(struct irq_data *d)
spin_unlock_irqrestore(&sch->lock, flags);
}
-static void sch_irq_mask_unmask(struct irq_data *d, int val)
+static void sch_irq_mask_unmask(struct gpio_chip *gc, irq_hw_number_t gpio_num, int val)
{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct sch_gpio *sch = gpiochip_get_data(gc);
- irq_hw_number_t gpio_num = irqd_to_hwirq(d);
unsigned long flags;
spin_lock_irqsave(&sch->lock, flags);
@@ -232,14 +229,32 @@ static void sch_irq_mask_unmask(struct irq_data *d, int val)
static void sch_irq_mask(struct irq_data *d)
{
- sch_irq_mask_unmask(d, 0);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t gpio_num = irqd_to_hwirq(d);
+
+ sch_irq_mask_unmask(gc, gpio_num, 0);
+ gpiochip_disable_irq(gc, gpio_num);
}
static void sch_irq_unmask(struct irq_data *d)
{
- sch_irq_mask_unmask(d, 1);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ irq_hw_number_t gpio_num = irqd_to_hwirq(d);
+
+ gpiochip_enable_irq(gc, gpio_num);
+ sch_irq_mask_unmask(gc, gpio_num, 1);
}
+static const struct irq_chip sch_irqchip = {
+ .name = "sch_gpio",
+ .irq_ack = sch_irq_ack,
+ .irq_mask = sch_irq_mask,
+ .irq_unmask = sch_irq_unmask,
+ .irq_set_type = sch_irq_type,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context)
{
struct sch_gpio *sch = context;
@@ -367,14 +382,8 @@ static int sch_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sch);
- sch->irqchip.name = "sch_gpio";
- sch->irqchip.irq_ack = sch_irq_ack;
- sch->irqchip.irq_mask = sch_irq_mask;
- sch->irqchip.irq_unmask = sch_irq_unmask;
- sch->irqchip.irq_set_type = sch_irq_type;
-
girq = &sch->chip.irq;
- girq->chip = &sch->irqchip;
+ gpio_irq_chip_set_chip(girq, &sch_irqchip);
girq->num_parents = 0;
girq->parents = NULL;
girq->parent_handler = NULL;
diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
index 7d82388b4ab7..238f3210970c 100644
--- a/drivers/gpio/gpio-sifive.c
+++ b/drivers/gpio/gpio-sifive.c
@@ -44,7 +44,7 @@ static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset)
unsigned long flags;
unsigned int trigger;
- spin_lock_irqsave(&chip->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&chip->gc.bgpio_lock, flags);
trigger = (chip->irq_state & BIT(offset)) ? chip->trigger[offset] : 0;
regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset),
(trigger & IRQ_TYPE_EDGE_RISING) ? BIT(offset) : 0);
@@ -54,7 +54,7 @@ static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset)
(trigger & IRQ_TYPE_LEVEL_HIGH) ? BIT(offset) : 0);
regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset),
(trigger & IRQ_TYPE_LEVEL_LOW) ? BIT(offset) : 0);
- spin_unlock_irqrestore(&chip->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&chip->gc.bgpio_lock, flags);
}
static int sifive_gpio_irq_set_type(struct irq_data *d, unsigned int trigger)
@@ -75,22 +75,24 @@ static void sifive_gpio_irq_enable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct sifive_gpio *chip = gpiochip_get_data(gc);
- int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
+ int offset = hwirq % SIFIVE_GPIO_MAX;
u32 bit = BIT(offset);
unsigned long flags;
+ gpiochip_enable_irq(gc, hwirq);
irq_chip_enable_parent(d);
/* Switch to input */
gc->direction_input(gc, offset);
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
/* Clear any sticky pending interrupts */
regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit);
regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit);
regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit);
regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
/* Enable interrupts */
assign_bit(offset, &chip->irq_state, 1);
@@ -101,11 +103,13 @@ static void sifive_gpio_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct sifive_gpio *chip = gpiochip_get_data(gc);
- int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
+ int offset = hwirq % SIFIVE_GPIO_MAX;
assign_bit(offset, &chip->irq_state, 0);
sifive_gpio_set_ie(chip, offset);
irq_chip_disable_parent(d);
+ gpiochip_disable_irq(gc, hwirq);
}
static void sifive_gpio_irq_eoi(struct irq_data *d)
@@ -116,13 +120,13 @@ static void sifive_gpio_irq_eoi(struct irq_data *d)
u32 bit = BIT(offset);
unsigned long flags;
- spin_lock_irqsave(&gc->bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
/* Clear all pending interrupts */
regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit);
regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit);
regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit);
regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
- spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
irq_chip_eoi_parent(d);
}
@@ -137,7 +141,7 @@ static int sifive_gpio_irq_set_affinity(struct irq_data *data,
return -EINVAL;
}
-static struct irq_chip sifive_gpio_irqchip = {
+static const struct irq_chip sifive_gpio_irqchip = {
.name = "sifive-gpio",
.irq_set_type = sifive_gpio_irq_set_type,
.irq_mask = irq_chip_mask_parent,
@@ -146,6 +150,8 @@ static struct irq_chip sifive_gpio_irqchip = {
.irq_disable = sifive_gpio_irq_disable,
.irq_eoi = sifive_gpio_irq_eoi,
.irq_set_affinity = sifive_gpio_irq_set_affinity,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
@@ -242,7 +248,7 @@ static int sifive_gpio_probe(struct platform_device *pdev)
chip->gc.parent = dev;
chip->gc.owner = THIS_MODULE;
girq = &chip->gc.irq;
- girq->chip = &sifive_gpio_irqchip;
+ gpio_irq_chip_set_chip(girq, &sifive_gpio_irqchip);
girq->fwnode = of_node_to_fwnode(node);
girq->parent_domain = parent;
girq->child_to_parent_hwirq = sifive_gpio_child_to_parent_hwirq;
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index 41c31b10ae84..1020c2feb249 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -314,8 +314,8 @@ static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip)
for (i = 0; i < num_lines; i++) {
attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
- attrs = devm_kcalloc(dev, sizeof(*attrs),
- GPIO_SIM_NUM_ATTRS, GFP_KERNEL);
+ attrs = devm_kcalloc(dev, GPIO_SIM_NUM_ATTRS, sizeof(*attrs),
+ GFP_KERNEL);
val_attr = devm_kzalloc(dev, sizeof(*val_attr), GFP_KERNEL);
pull_attr = devm_kzalloc(dev, sizeof(*pull_attr), GFP_KERNEL);
if (!attr_group || !attrs || !val_attr || !pull_attr)
@@ -991,28 +991,22 @@ static struct configfs_attribute *gpio_sim_device_config_attrs[] = {
};
struct gpio_sim_chip_name_ctx {
- struct gpio_sim_device *dev;
+ struct fwnode_handle *swnode;
char *page;
};
static int gpio_sim_emit_chip_name(struct device *dev, void *data)
{
struct gpio_sim_chip_name_ctx *ctx = data;
- struct fwnode_handle *swnode;
- struct gpio_sim_bank *bank;
/* This would be the sysfs device exported in /sys/class/gpio. */
if (dev->class)
return 0;
- swnode = dev_fwnode(dev);
+ if (device_match_fwnode(dev, ctx->swnode))
+ return sprintf(ctx->page, "%s\n", dev_name(dev));
- list_for_each_entry(bank, &ctx->dev->bank_list, siblings) {
- if (bank->swnode == swnode)
- return sprintf(ctx->page, "%s\n", dev_name(dev));
- }
-
- return -ENODATA;
+ return 0;
}
static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
@@ -1020,7 +1014,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
{
struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
- struct gpio_sim_chip_name_ctx ctx = { dev, page };
+ struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page };
int ret;
mutex_lock(&dev->lock);
diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c
index 49aac2bb8d2c..51539185400d 100644
--- a/drivers/gpio/gpio-spear-spics.c
+++ b/drivers/gpio/gpio-spear-spics.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SPEAr platform SPI chipselect abstraction over gpiolib
*
* Copyright (C) 2012 ST Microelectronics
* Shiraz Hashim <shiraz.linux.kernel@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <linux/err.h>
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index fdd3d497b535..6076937b18e7 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -38,7 +38,6 @@
*/
struct syscon_gpio_data {
- const char *compatible;
unsigned int flags;
unsigned int bit_count;
unsigned int dat_bit_offset;
@@ -125,7 +124,6 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
static const struct syscon_gpio_data clps711x_mctrl_gpio = {
/* ARM CLPS711X SYSFLG1 Bits 8-10 */
- .compatible = "cirrus,ep7209-syscon1",
.flags = GPIO_SYSCON_FEAT_IN,
.bit_count = 3,
.dat_bit_offset = 0x40 * 8 + 8,
@@ -182,7 +180,6 @@ static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static const struct syscon_gpio_data keystone_dsp_gpio = {
/* ARM Keystone 2 */
- .compatible = NULL,
.flags = GPIO_SYSCON_FEAT_OUT,
.bit_count = 28,
.dat_bit_offset = 4,
@@ -219,33 +216,25 @@ static int syscon_gpio_probe(struct platform_device *pdev)
priv->data = of_device_get_match_data(dev);
- if (priv->data->compatible) {
- priv->syscon = syscon_regmap_lookup_by_compatible(
- priv->data->compatible);
- if (IS_ERR(priv->syscon))
- return PTR_ERR(priv->syscon);
- } else {
- priv->syscon =
- syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
- if (IS_ERR(priv->syscon) && np->parent)
- priv->syscon = syscon_node_to_regmap(np->parent);
- if (IS_ERR(priv->syscon))
- return PTR_ERR(priv->syscon);
-
- ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1,
- &priv->dreg_offset);
- if (ret)
- dev_err(dev, "can't read the data register offset!\n");
-
- priv->dreg_offset <<= 3;
-
- ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
- &priv->dir_reg_offset);
- if (ret)
- dev_dbg(dev, "can't read the dir register offset!\n");
-
- priv->dir_reg_offset <<= 3;
- }
+ priv->syscon = syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
+ if (IS_ERR(priv->syscon) && np->parent)
+ priv->syscon = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(priv->syscon))
+ return PTR_ERR(priv->syscon);
+
+ ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1,
+ &priv->dreg_offset);
+ if (ret)
+ dev_err(dev, "can't read the data register offset!\n");
+
+ priv->dreg_offset <<= 3;
+
+ ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
+ &priv->dir_reg_offset);
+ if (ret)
+ dev_dbg(dev, "can't read the dir register offset!\n");
+
+ priv->dir_reg_offset <<= 3;
priv->chip.parent = dev;
priv->chip.owner = THIS_MODULE;
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index 718a508d3b2f..de6afa3f9716 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -62,14 +62,14 @@ static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs,
u32 r;
unsigned long flags;
- spin_lock_irqsave(&gpio->gc.bgpio_lock, flags);
+ raw_spin_lock_irqsave(&gpio->gc.bgpio_lock, flags);
r = tb10x_reg_read(gpio, offs);
r = (r & ~mask) | (val & mask);
tb10x_reg_write(gpio, offs, r);
- spin_unlock_irqrestore(&gpio->gc.bgpio_lock, flags);
+ raw_spin_unlock_irqrestore(&gpio->gc.bgpio_lock, flags);
}
static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index ff2d2a1f9c73..e4fb4cb38a0f 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -443,15 +443,12 @@ static int tegra_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
return 0;
}
-static void *tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
- unsigned int parent_hwirq,
- unsigned int parent_type)
+static int tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+ union gpio_irq_fwspec *gfwspec,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
{
- struct irq_fwspec *fwspec;
-
- fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
- if (!fwspec)
- return NULL;
+ struct irq_fwspec *fwspec = &gfwspec->fwspec;
fwspec->fwnode = chip->irq.parent_domain->fwnode;
fwspec->param_count = 3;
@@ -459,7 +456,7 @@ static void *tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
fwspec->param[1] = parent_hwirq;
fwspec->param[2] = parent_type;
- return fwspec;
+ return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 031fe105b58e..54d9fa7da9c1 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2017 NVIDIA Corporation
+ * Copyright (c) 2016-2022 NVIDIA Corporation
*
* Author: Thierry Reding <treding@nvidia.com>
+ * Dipen Patel <dpatel@nvidia.com>
*/
#include <linux/gpio/driver.h>
@@ -11,6 +12,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/hte.h>
#include <dt-bindings/gpio/tegra186-gpio.h>
#include <dt-bindings/gpio/tegra194-gpio.h>
@@ -36,6 +38,7 @@
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4)
#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5)
#define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6)
+#define TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC BIT(7)
#define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04
#define TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff)
@@ -76,11 +79,11 @@ struct tegra_gpio_soc {
const struct tegra186_pin_range *pin_ranges;
unsigned int num_pin_ranges;
const char *pinmux;
+ bool has_gte;
};
struct tegra_gpio {
struct gpio_chip gpio;
- struct irq_chip intc;
unsigned int num_irq;
unsigned int *irq;
@@ -194,6 +197,76 @@ static int tegra186_gpio_direction_output(struct gpio_chip *chip,
return 0;
}
+#define HTE_BOTH_EDGES (HTE_RISING_EDGE_TS | HTE_FALLING_EDGE_TS)
+
+static int tegra186_gpio_en_hw_ts(struct gpio_chip *gc, u32 offset,
+ unsigned long flags)
+{
+ struct tegra_gpio *gpio;
+ void __iomem *base;
+ int value;
+
+ if (!gc)
+ return -EINVAL;
+
+ gpio = gpiochip_get_data(gc);
+ if (!gpio)
+ return -ENODEV;
+
+ base = tegra186_gpio_get_base(gpio, offset);
+ if (WARN_ON(base == NULL))
+ return -EINVAL;
+
+ value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+ value |= TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC;
+
+ if (flags == HTE_BOTH_EDGES) {
+ value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE;
+ } else if (flags == HTE_RISING_EDGE_TS) {
+ value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
+ value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
+ } else if (flags == HTE_FALLING_EDGE_TS) {
+ value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
+ }
+
+ writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+ return 0;
+}
+
+static int tegra186_gpio_dis_hw_ts(struct gpio_chip *gc, u32 offset,
+ unsigned long flags)
+{
+ struct tegra_gpio *gpio;
+ void __iomem *base;
+ int value;
+
+ if (!gc)
+ return -EINVAL;
+
+ gpio = gpiochip_get_data(gc);
+ if (!gpio)
+ return -ENODEV;
+
+ base = tegra186_gpio_get_base(gpio, offset);
+ if (WARN_ON(base == NULL))
+ return -EINVAL;
+
+ value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+ value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TIMESTAMP_FUNC;
+ if (flags == HTE_BOTH_EDGES) {
+ value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE;
+ } else if (flags == HTE_RISING_EDGE_TS) {
+ value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
+ value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
+ } else if (flags == HTE_FALLING_EDGE_TS) {
+ value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
+ }
+ writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+ return 0;
+}
+
static int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct tegra_gpio *gpio = gpiochip_get_data(chip);
@@ -372,6 +445,8 @@ static void tegra186_irq_mask(struct irq_data *data)
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
value &= ~TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+ gpiochip_disable_irq(&gpio->gpio, data->hwirq);
}
static void tegra186_irq_unmask(struct irq_data *data)
@@ -385,6 +460,8 @@ static void tegra186_irq_unmask(struct irq_data *data)
if (WARN_ON(base == NULL))
return;
+ gpiochip_enable_irq(&gpio->gpio, data->hwirq);
+
value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
value |= TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
@@ -456,6 +533,24 @@ static int tegra186_irq_set_wake(struct irq_data *data, unsigned int on)
return 0;
}
+static void tegra186_irq_print_chip(struct irq_data *data, struct seq_file *p)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+
+ seq_printf(p, dev_name(gc->parent));
+}
+
+static const struct irq_chip tegra186_gpio_irq_chip = {
+ .irq_ack = tegra186_irq_ack,
+ .irq_mask = tegra186_irq_mask,
+ .irq_unmask = tegra186_irq_unmask,
+ .irq_set_type = tegra186_irq_set_type,
+ .irq_set_wake = tegra186_irq_set_wake,
+ .irq_print_chip = tegra186_irq_print_chip,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
static void tegra186_gpio_irq(struct irq_desc *desc)
{
struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
@@ -526,16 +621,13 @@ static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain,
return 0;
}
-static void *tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
- unsigned int parent_hwirq,
- unsigned int parent_type)
+static int tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+ union gpio_irq_fwspec *gfwspec,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
{
struct tegra_gpio *gpio = gpiochip_get_data(chip);
- struct irq_fwspec *fwspec;
-
- fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
- if (!fwspec)
- return NULL;
+ struct irq_fwspec *fwspec = &gfwspec->fwspec;
fwspec->fwnode = chip->irq.parent_domain->fwnode;
fwspec->param_count = 3;
@@ -543,7 +635,7 @@ static void *tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
fwspec->param[1] = parent_hwirq;
fwspec->param[2] = parent_type;
- return fwspec;
+ return 0;
}
static int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
@@ -726,6 +818,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->gpio.set = tegra186_gpio_set;
gpio->gpio.set_config = tegra186_gpio_set_config;
gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges;
+ if (gpio->soc->has_gte) {
+ gpio->gpio.en_hw_timestamp = tegra186_gpio_en_hw_ts;
+ gpio->gpio.dis_hw_timestamp = tegra186_gpio_dis_hw_ts;
+ }
gpio->gpio.base = -1;
@@ -760,15 +856,8 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
#endif /* CONFIG_OF_GPIO */
- gpio->intc.name = dev_name(&pdev->dev);
- gpio->intc.irq_ack = tegra186_irq_ack;
- gpio->intc.irq_mask = tegra186_irq_mask;
- gpio->intc.irq_unmask = tegra186_irq_unmask;
- gpio->intc.irq_set_type = tegra186_irq_set_type;
- gpio->intc.irq_set_wake = tegra186_irq_set_wake;
-
irq = &gpio->gpio.irq;
- irq->chip = &gpio->intc;
+ gpio_irq_chip_set_chip(irq, &tegra186_gpio_irq_chip);
irq->fwnode = of_node_to_fwnode(pdev->dev.of_node);
irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq;
irq->populate_parent_alloc_arg = tegra186_gpio_populate_parent_fwspec;
@@ -977,6 +1066,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = {
.name = "tegra194-gpio-aon",
.instance = 1,
.num_irqs_per_bank = 8,
+ .has_gte = true,
};
#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c
index 9f66deab46ea..cc62c6e64103 100644
--- a/drivers/gpio/gpio-thunderx.c
+++ b/drivers/gpio/gpio-thunderx.c
@@ -15,8 +15,6 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
-#include <asm-generic/msi.h>
-
#define GPIO_RX_DAT 0x0
#define GPIO_TX_SET 0x8
@@ -408,18 +406,15 @@ static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
return 0;
}
-static void *thunderx_gpio_populate_parent_alloc_info(struct gpio_chip *chip,
- unsigned int parent_hwirq,
- unsigned int parent_type)
+static int thunderx_gpio_populate_parent_alloc_info(struct gpio_chip *chip,
+ union gpio_irq_fwspec *gfwspec,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
{
- msi_alloc_info_t *info;
-
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return NULL;
+ msi_alloc_info_t *info = &gfwspec->msiinfo;
info->hwirq = parent_hwirq;
- return info;
+ return 0;
}
static int thunderx_gpio_probe(struct pci_dev *pdev,
diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c
index 99d5a84a9129..a09b1e69b072 100644
--- a/drivers/gpio/gpio-tpic2810.c
+++ b/drivers/gpio/gpio-tpic2810.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License version 2 for more details.
*/
#include <linux/gpio/driver.h>
diff --git a/drivers/gpio/gpio-ts4800.c b/drivers/gpio/gpio-ts4800.c
index 8c0d82d926dd..95d80ba14bee 100644
--- a/drivers/gpio/gpio-ts4800.c
+++ b/drivers/gpio/gpio-ts4800.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO driver for the TS-4800 board
*
* Copyright (c) 2016 - Savoir-faire Linux
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#include <linux/gpio/driver.h>
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index de249726230e..5046e51af8df 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -593,27 +593,13 @@ out:
/* Cannot use as gpio_twl4030_probe() calls us */
static int gpio_twl4030_remove(struct platform_device *pdev)
{
- struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
- int status;
-
- if (pdata && pdata->teardown) {
- status = pdata->teardown(&pdev->dev, priv->gpio_chip.base,
- TWL4030_GPIO_MAX);
- if (status) {
- dev_dbg(&pdev->dev, "teardown --> %d\n", status);
- return status;
- }
- }
gpiochip_remove(&priv->gpio_chip);
- if (is_module())
- return 0;
-
/* REVISIT no support yet for deregistering all the IRQs */
- WARN_ON(1);
- return -EIO;
+ WARN_ON(!is_module());
+ return 0;
}
static const struct of_device_id twl_gpio_match[] = {
diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c
index d2a8644864c3..386e69300332 100644
--- a/drivers/gpio/gpio-ucb1400.c
+++ b/drivers/gpio/gpio-ucb1400.c
@@ -64,34 +64,14 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
ucb->gc.can_sleep = true;
err = devm_gpiochip_add_data(&dev->dev, &ucb->gc, ucb);
- if (err)
- goto err;
-
- if (ucb->gpio_setup)
- err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio);
err:
return err;
}
-static int ucb1400_gpio_remove(struct platform_device *dev)
-{
- int err = 0;
- struct ucb1400_gpio *ucb = platform_get_drvdata(dev);
-
- if (ucb && ucb->gpio_teardown) {
- err = ucb->gpio_teardown(&dev->dev, ucb->gc.ngpio);
- if (err)
- return err;
- }
-
- return err;
-}
-
static struct platform_driver ucb1400_gpio_driver = {
.probe = ucb1400_gpio_probe,
- .remove = ucb1400_gpio_remove,
.driver = {
.name = "ucb1400_gpio"
},
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 23cddb265a0d..9db42f6a2043 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -19,6 +19,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
#define VF610_GPIO_PER_PORT 32
diff --git a/drivers/gpio/gpio-visconti.c b/drivers/gpio/gpio-visconti.c
index e6534ea1eaa7..5e108ba9956a 100644
--- a/drivers/gpio/gpio-visconti.c
+++ b/drivers/gpio/gpio-visconti.c
@@ -103,15 +103,12 @@ static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
return -EINVAL;
}
-static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
- unsigned int parent_hwirq,
- unsigned int parent_type)
+static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+ union gpio_irq_fwspec *gfwspec,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
{
- struct irq_fwspec *fwspec;
-
- fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
- if (!fwspec)
- return NULL;
+ struct irq_fwspec *fwspec = &gfwspec->fwspec;
fwspec->fwnode = chip->irq.parent_domain->fwnode;
fwspec->param_count = 3;
@@ -119,7 +116,7 @@ static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
fwspec->param[1] = parent_hwirq;
fwspec->param[2] = parent_type;
- return fwspec;
+ return 0;
}
static int visconti_gpio_probe(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
deleted file mode 100644
index 98cd715ccc33..000000000000
--- a/drivers/gpio/gpio-vr41xx.c
+++ /dev/null
@@ -1,543 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Driver for NEC VR4100 series General-purpose I/O Unit.
- *
- * Copyright (C) 2002 MontaVista Software Inc.
- * Author: Yoichi Yuasa <source@mvista.com>
- * Copyright (C) 2003-2009 Yoichi Yuasa <yuasa@linux-mips.org>
- */
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/gpio/driver.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <asm/vr41xx/giu.h>
-#include <asm/vr41xx/irq.h>
-#include <asm/vr41xx/vr41xx.h>
-
-MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
-MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
-MODULE_LICENSE("GPL");
-
-#define GIUIOSELL 0x00
-#define GIUIOSELH 0x02
-#define GIUPIODL 0x04
-#define GIUPIODH 0x06
-#define GIUINTSTATL 0x08
-#define GIUINTSTATH 0x0a
-#define GIUINTENL 0x0c
-#define GIUINTENH 0x0e
-#define GIUINTTYPL 0x10
-#define GIUINTTYPH 0x12
-#define GIUINTALSELL 0x14
-#define GIUINTALSELH 0x16
-#define GIUINTHTSELL 0x18
-#define GIUINTHTSELH 0x1a
-#define GIUPODATL 0x1c
-#define GIUPODATEN 0x1c
-#define GIUPODATH 0x1e
- #define PIOEN0 0x0100
- #define PIOEN1 0x0200
-#define GIUPODAT 0x1e
-#define GIUFEDGEINHL 0x20
-#define GIUFEDGEINHH 0x22
-#define GIUREDGEINHL 0x24
-#define GIUREDGEINHH 0x26
-
-#define GIUUSEUPDN 0x1e0
-#define GIUTERMUPDN 0x1e2
-
-#define GPIO_HAS_PULLUPDOWN_IO 0x0001
-#define GPIO_HAS_OUTPUT_ENABLE 0x0002
-#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
-
-enum {
- GPIO_INPUT,
- GPIO_OUTPUT,
-};
-
-static DEFINE_SPINLOCK(giu_lock);
-static unsigned long giu_flags;
-
-static void __iomem *giu_base;
-static struct gpio_chip vr41xx_gpio_chip;
-
-#define giu_read(offset) readw(giu_base + (offset))
-#define giu_write(offset, value) writew((value), giu_base + (offset))
-
-#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE)
-#define GIUINT_HIGH_OFFSET 16
-#define GIUINT_HIGH_MAX 32
-
-static inline u16 giu_set(u16 offset, u16 set)
-{
- u16 data;
-
- data = giu_read(offset);
- data |= set;
- giu_write(offset, data);
-
- return data;
-}
-
-static inline u16 giu_clear(u16 offset, u16 clear)
-{
- u16 data;
-
- data = giu_read(offset);
- data &= ~clear;
- giu_write(offset, data);
-
- return data;
-}
-
-static void ack_giuint_low(struct irq_data *d)
-{
- giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq));
-}
-
-static void mask_giuint_low(struct irq_data *d)
-{
- giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
-}
-
-static void mask_ack_giuint_low(struct irq_data *d)
-{
- unsigned int pin;
-
- pin = GPIO_PIN_OF_IRQ(d->irq);
- giu_clear(GIUINTENL, 1 << pin);
- giu_write(GIUINTSTATL, 1 << pin);
-}
-
-static void unmask_giuint_low(struct irq_data *d)
-{
- giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
-}
-
-static unsigned int startup_giuint(struct irq_data *data)
-{
- int ret;
-
- ret = gpiochip_lock_as_irq(&vr41xx_gpio_chip, irqd_to_hwirq(data));
- if (ret) {
- dev_err(vr41xx_gpio_chip.parent,
- "unable to lock HW IRQ %lu for IRQ\n",
- data->hwirq);
- return ret;
- }
-
- /* Satisfy the .enable semantics by unmasking the line */
- unmask_giuint_low(data);
- return 0;
-}
-
-static void shutdown_giuint(struct irq_data *data)
-{
- mask_giuint_low(data);
- gpiochip_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq);
-}
-
-static struct irq_chip giuint_low_irq_chip = {
- .name = "GIUINTL",
- .irq_ack = ack_giuint_low,
- .irq_mask = mask_giuint_low,
- .irq_mask_ack = mask_ack_giuint_low,
- .irq_unmask = unmask_giuint_low,
- .irq_startup = startup_giuint,
- .irq_shutdown = shutdown_giuint,
-};
-
-static void ack_giuint_high(struct irq_data *d)
-{
- giu_write(GIUINTSTATH,
- 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_giuint_high(struct irq_data *d)
-{
- giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_ack_giuint_high(struct irq_data *d)
-{
- unsigned int pin;
-
- pin = GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET;
- giu_clear(GIUINTENH, 1 << pin);
- giu_write(GIUINTSTATH, 1 << pin);
-}
-
-static void unmask_giuint_high(struct irq_data *d)
-{
- giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
-}
-
-static struct irq_chip giuint_high_irq_chip = {
- .name = "GIUINTH",
- .irq_ack = ack_giuint_high,
- .irq_mask = mask_giuint_high,
- .irq_mask_ack = mask_ack_giuint_high,
- .irq_unmask = unmask_giuint_high,
-};
-
-static int giu_get_irq(unsigned int irq)
-{
- u16 pendl, pendh, maskl, maskh;
- int i;
-
- pendl = giu_read(GIUINTSTATL);
- pendh = giu_read(GIUINTSTATH);
- maskl = giu_read(GIUINTENL);
- maskh = giu_read(GIUINTENH);
-
- maskl &= pendl;
- maskh &= pendh;
-
- if (maskl) {
- for (i = 0; i < 16; i++) {
- if (maskl & (1 << i))
- return GIU_IRQ(i);
- }
- } else if (maskh) {
- for (i = 0; i < 16; i++) {
- if (maskh & (1 << i))
- return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
- }
- }
-
- printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
- maskl, pendl, maskh, pendh);
-
- atomic_inc(&irq_err_count);
-
- return -EINVAL;
-}
-
-void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
- irq_signal_t signal)
-{
- u16 mask;
-
- if (pin < GIUINT_HIGH_OFFSET) {
- mask = 1 << pin;
- if (trigger != IRQ_TRIGGER_LEVEL) {
- giu_set(GIUINTTYPL, mask);
- if (signal == IRQ_SIGNAL_HOLD)
- giu_set(GIUINTHTSELL, mask);
- else
- giu_clear(GIUINTHTSELL, mask);
- if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
- switch (trigger) {
- case IRQ_TRIGGER_EDGE_FALLING:
- giu_set(GIUFEDGEINHL, mask);
- giu_clear(GIUREDGEINHL, mask);
- break;
- case IRQ_TRIGGER_EDGE_RISING:
- giu_clear(GIUFEDGEINHL, mask);
- giu_set(GIUREDGEINHL, mask);
- break;
- default:
- giu_set(GIUFEDGEINHL, mask);
- giu_set(GIUREDGEINHL, mask);
- break;
- }
- }
- irq_set_chip_and_handler(GIU_IRQ(pin),
- &giuint_low_irq_chip,
- handle_edge_irq);
- } else {
- giu_clear(GIUINTTYPL, mask);
- giu_clear(GIUINTHTSELL, mask);
- irq_set_chip_and_handler(GIU_IRQ(pin),
- &giuint_low_irq_chip,
- handle_level_irq);
- }
- giu_write(GIUINTSTATL, mask);
- } else if (pin < GIUINT_HIGH_MAX) {
- mask = 1 << (pin - GIUINT_HIGH_OFFSET);
- if (trigger != IRQ_TRIGGER_LEVEL) {
- giu_set(GIUINTTYPH, mask);
- if (signal == IRQ_SIGNAL_HOLD)
- giu_set(GIUINTHTSELH, mask);
- else
- giu_clear(GIUINTHTSELH, mask);
- if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
- switch (trigger) {
- case IRQ_TRIGGER_EDGE_FALLING:
- giu_set(GIUFEDGEINHH, mask);
- giu_clear(GIUREDGEINHH, mask);
- break;
- case IRQ_TRIGGER_EDGE_RISING:
- giu_clear(GIUFEDGEINHH, mask);
- giu_set(GIUREDGEINHH, mask);
- break;
- default:
- giu_set(GIUFEDGEINHH, mask);
- giu_set(GIUREDGEINHH, mask);
- break;
- }
- }
- irq_set_chip_and_handler(GIU_IRQ(pin),
- &giuint_high_irq_chip,
- handle_edge_irq);
- } else {
- giu_clear(GIUINTTYPH, mask);
- giu_clear(GIUINTHTSELH, mask);
- irq_set_chip_and_handler(GIU_IRQ(pin),
- &giuint_high_irq_chip,
- handle_level_irq);
- }
- giu_write(GIUINTSTATH, mask);
- }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
-
-void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
-{
- u16 mask;
-
- if (pin < GIUINT_HIGH_OFFSET) {
- mask = 1 << pin;
- if (level == IRQ_LEVEL_HIGH)
- giu_set(GIUINTALSELL, mask);
- else
- giu_clear(GIUINTALSELL, mask);
- giu_write(GIUINTSTATL, mask);
- } else if (pin < GIUINT_HIGH_MAX) {
- mask = 1 << (pin - GIUINT_HIGH_OFFSET);
- if (level == IRQ_LEVEL_HIGH)
- giu_set(GIUINTALSELH, mask);
- else
- giu_clear(GIUINTALSELH, mask);
- giu_write(GIUINTSTATH, mask);
- }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
-
-static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
-{
- u16 offset, mask, reg;
- unsigned long flags;
-
- if (pin >= chip->ngpio)
- return -EINVAL;
-
- if (pin < 16) {
- offset = GIUIOSELL;
- mask = 1 << pin;
- } else if (pin < 32) {
- offset = GIUIOSELH;
- mask = 1 << (pin - 16);
- } else {
- if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
- offset = GIUPODATEN;
- mask = 1 << (pin - 32);
- } else {
- switch (pin) {
- case 48:
- offset = GIUPODATH;
- mask = PIOEN0;
- break;
- case 49:
- offset = GIUPODATH;
- mask = PIOEN1;
- break;
- default:
- return -EINVAL;
- }
- }
- }
-
- spin_lock_irqsave(&giu_lock, flags);
-
- reg = giu_read(offset);
- if (dir == GPIO_OUTPUT)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(offset, reg);
-
- spin_unlock_irqrestore(&giu_lock, flags);
-
- return 0;
-}
-
-static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
-{
- u16 reg, mask;
-
- if (pin >= chip->ngpio)
- return -EINVAL;
-
- if (pin < 16) {
- reg = giu_read(GIUPIODL);
- mask = 1 << pin;
- } else if (pin < 32) {
- reg = giu_read(GIUPIODH);
- mask = 1 << (pin - 16);
- } else if (pin < 48) {
- reg = giu_read(GIUPODATL);
- mask = 1 << (pin - 32);
- } else {
- reg = giu_read(GIUPODATH);
- mask = 1 << (pin - 48);
- }
-
- if (reg & mask)
- return 1;
-
- return 0;
-}
-
-static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin,
- int value)
-{
- u16 offset, mask, reg;
- unsigned long flags;
-
- if (pin >= chip->ngpio)
- return;
-
- if (pin < 16) {
- offset = GIUPIODL;
- mask = 1 << pin;
- } else if (pin < 32) {
- offset = GIUPIODH;
- mask = 1 << (pin - 16);
- } else if (pin < 48) {
- offset = GIUPODATL;
- mask = 1 << (pin - 32);
- } else {
- offset = GIUPODATH;
- mask = 1 << (pin - 48);
- }
-
- spin_lock_irqsave(&giu_lock, flags);
-
- reg = giu_read(offset);
- if (value)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(offset, reg);
-
- spin_unlock_irqrestore(&giu_lock, flags);
-}
-
-
-static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- return giu_set_direction(chip, offset, GPIO_INPUT);
-}
-
-static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- vr41xx_gpio_set(chip, offset, value);
-
- return giu_set_direction(chip, offset, GPIO_OUTPUT);
-}
-
-static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- if (offset >= chip->ngpio)
- return -EINVAL;
-
- return GIU_IRQ_BASE + offset;
-}
-
-static struct gpio_chip vr41xx_gpio_chip = {
- .label = "vr41xx",
- .owner = THIS_MODULE,
- .direction_input = vr41xx_gpio_direction_input,
- .get = vr41xx_gpio_get,
- .direction_output = vr41xx_gpio_direction_output,
- .set = vr41xx_gpio_set,
- .to_irq = vr41xx_gpio_to_irq,
-};
-
-static int giu_probe(struct platform_device *pdev)
-{
- unsigned int trigger, i, pin;
- struct irq_chip *chip;
- int irq;
-
- switch (pdev->id) {
- case GPIO_50PINS_PULLUPDOWN:
- giu_flags = GPIO_HAS_PULLUPDOWN_IO;
- vr41xx_gpio_chip.ngpio = 50;
- break;
- case GPIO_36PINS:
- vr41xx_gpio_chip.ngpio = 36;
- break;
- case GPIO_48PINS_EDGE_SELECT:
- giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
- vr41xx_gpio_chip.ngpio = 48;
- break;
- default:
- dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id);
- return -ENODEV;
- }
-
- giu_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(giu_base))
- return PTR_ERR(giu_base);
-
- vr41xx_gpio_chip.parent = &pdev->dev;
-
- if (gpiochip_add_data(&vr41xx_gpio_chip, NULL))
- return -ENODEV;
-
- giu_write(GIUINTENL, 0);
- giu_write(GIUINTENH, 0);
-
- trigger = giu_read(GIUINTTYPH) << 16;
- trigger |= giu_read(GIUINTTYPL);
- for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
- pin = GPIO_PIN_OF_IRQ(i);
- if (pin < GIUINT_HIGH_OFFSET)
- chip = &giuint_low_irq_chip;
- else
- chip = &giuint_high_irq_chip;
-
- if (trigger & (1 << pin))
- irq_set_chip_and_handler(i, chip, handle_edge_irq);
- else
- irq_set_chip_and_handler(i, chip, handle_level_irq);
-
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0 || irq >= nr_irqs)
- return -EBUSY;
-
- return cascade_irq(irq, giu_get_irq);
-}
-
-static int giu_remove(struct platform_device *pdev)
-{
- if (giu_base) {
- giu_base = NULL;
- }
-
- return 0;
-}
-
-static struct platform_driver giu_device_driver = {
- .probe = giu_probe,
- .remove = giu_remove,
- .driver = {
- .name = "GIU",
- },
-};
-
-module_platform_driver(giu_device_driver);
diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c
index 16a0fae1e32e..c18b6b47384f 100644
--- a/drivers/gpio/gpio-wcove.c
+++ b/drivers/gpio/gpio-wcove.c
@@ -299,6 +299,8 @@ static void wcove_irq_unmask(struct irq_data *data)
if (gpio >= WCOVE_GPIO_NUM)
return;
+ gpiochip_enable_irq(chip, gpio);
+
wg->set_irq_mask = false;
wg->update |= UPDATE_IRQ_MASK;
}
@@ -314,15 +316,19 @@ static void wcove_irq_mask(struct irq_data *data)
wg->set_irq_mask = true;
wg->update |= UPDATE_IRQ_MASK;
+
+ gpiochip_disable_irq(chip, gpio);
}
-static struct irq_chip wcove_irqchip = {
+static const struct irq_chip wcove_irqchip = {
.name = "Whiskey Cove",
.irq_mask = wcove_irq_mask,
.irq_unmask = wcove_irq_unmask,
.irq_set_type = wcove_irq_type,
.irq_bus_lock = wcove_bus_lock,
.irq_bus_sync_unlock = wcove_bus_sync_unlock,
+ .flags = IRQCHIP_IMMUTABLE,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
@@ -452,7 +458,7 @@ static int wcove_gpio_probe(struct platform_device *pdev)
}
girq = &wg->chip.irq;
- girq->chip = &wcove_irqchip;
+ gpio_irq_chip_set_chip(girq, &wcove_irqchip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-winbond.c b/drivers/gpio/gpio-winbond.c
index 7f8f5b02e31d..4b61d975cc0e 100644
--- a/drivers/gpio/gpio-winbond.c
+++ b/drivers/gpio/gpio-winbond.c
@@ -385,12 +385,13 @@ static int winbond_gpio_get(struct gpio_chip *gc, unsigned int offset)
unsigned long *base = gpiochip_get_data(gc);
const struct winbond_gpio_info *info;
bool val;
+ int ret;
winbond_gpio_get_info(&offset, &info);
- val = winbond_sio_enter(*base);
- if (val)
- return val;
+ ret = winbond_sio_enter(*base);
+ if (ret)
+ return ret;
winbond_sio_select_logical(*base, info->dev);
diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
index bb02a82e22f4..b098f2dc196b 100644
--- a/drivers/gpio/gpio-ws16c48.c
+++ b/drivers/gpio/gpio-ws16c48.c
@@ -4,7 +4,6 @@
* Copyright (C) 2016 William Breathitt Gray
*/
#include <linux/bitmap.h>
-#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -17,8 +16,9 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
+#include <linux/types.h>
-#define WS16C48_EXTENT 16
+#define WS16C48_EXTENT 10
#define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT)
static unsigned int base[MAX_NUM_WS16C48];
@@ -31,6 +31,20 @@ module_param_hw_array(irq, uint, irq, NULL, 0);
MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
/**
+ * struct ws16c48_reg - device register structure
+ * @port: Port 0 through 5 I/O
+ * @int_pending: Interrupt Pending
+ * @page_lock: Register page (Bits 7-6) and I/O port lock (Bits 5-0)
+ * @pol_enab_int_id: Interrupt polarity, enable, and ID
+ */
+struct ws16c48_reg {
+ u8 port[6];
+ u8 int_pending;
+ u8 page_lock;
+ u8 pol_enab_int_id[3];
+};
+
+/**
* struct ws16c48_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @io_state: bit I/O state (whether bit is set to input or output)
@@ -38,7 +52,7 @@ MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
* @lock: synchronization lock to prevent I/O race conditions
* @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
+ * @reg: I/O address offset for the device registers
*/
struct ws16c48_gpio {
struct gpio_chip chip;
@@ -47,7 +61,7 @@ struct ws16c48_gpio {
raw_spinlock_t lock;
unsigned long irq_mask;
unsigned long flow_mask;
- unsigned base;
+ struct ws16c48_reg __iomem *reg;
};
static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -73,7 +87,7 @@ static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
ws16c48gpio->io_state[port] |= mask;
ws16c48gpio->out_state[port] &= ~mask;
- outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
+ iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
@@ -95,7 +109,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
ws16c48gpio->out_state[port] |= mask;
else
ws16c48gpio->out_state[port] &= ~mask;
- outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
+ iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
@@ -118,7 +132,7 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
- port_state = inb(ws16c48gpio->base + port);
+ port_state = ioread8(ws16c48gpio->reg->port + port);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
@@ -131,15 +145,17 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
- unsigned int port_addr;
+ size_t index;
+ u8 __iomem *port_addr;
unsigned long port_state;
/* clear bits array to a clean slate */
bitmap_zero(bits, chip->ngpio);
for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
- port_addr = ws16c48gpio->base + offset / 8;
- port_state = inb(port_addr) & gpio_mask;
+ index = offset / 8;
+ port_addr = ws16c48gpio->reg->port + index;
+ port_state = ioread8(port_addr) & gpio_mask;
bitmap_set_value8(bits, port_state, offset);
}
@@ -166,7 +182,7 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
ws16c48gpio->out_state[port] |= mask;
else
ws16c48gpio->out_state[port] &= ~mask;
- outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
+ iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@@ -178,13 +194,13 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
unsigned long offset;
unsigned long gpio_mask;
size_t index;
- unsigned int port_addr;
+ u8 __iomem *port_addr;
unsigned long bitmask;
unsigned long flags;
for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
index = offset / 8;
- port_addr = ws16c48gpio->base + index;
+ port_addr = ws16c48gpio->reg->port + index;
/* mask out GPIO configured for input */
gpio_mask &= ~ws16c48gpio->io_state[index];
@@ -195,7 +211,7 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
/* update output state data and set device gpio register */
ws16c48gpio->out_state[index] &= ~gpio_mask;
ws16c48gpio->out_state[index] |= bitmask;
- outb(ws16c48gpio->out_state[index], port_addr);
+ iowrite8(ws16c48gpio->out_state[index], port_addr);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@@ -219,10 +235,15 @@ static void ws16c48_irq_ack(struct irq_data *data)
port_state = ws16c48gpio->irq_mask >> (8*port);
- outb(0x80, ws16c48gpio->base + 7);
- outb(port_state & ~mask, ws16c48gpio->base + 8 + port);
- outb(port_state | mask, ws16c48gpio->base + 8 + port);
- outb(0xC0, ws16c48gpio->base + 7);
+ /* Select Register Page 2; Unlock all I/O ports */
+ iowrite8(0x80, &ws16c48gpio->reg->page_lock);
+
+ /* Clear pending interrupt */
+ iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port);
+ iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port);
+
+ /* Select Register Page 3; Unlock all I/O ports */
+ iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@@ -235,6 +256,7 @@ static void ws16c48_irq_mask(struct irq_data *data)
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
+ unsigned long port_state;
/* only the first 3 ports support interrupts */
if (port > 2)
@@ -243,10 +265,16 @@ static void ws16c48_irq_mask(struct irq_data *data)
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
ws16c48gpio->irq_mask &= ~mask;
+ port_state = ws16c48gpio->irq_mask >> (8 * port);
+
+ /* Select Register Page 2; Unlock all I/O ports */
+ iowrite8(0x80, &ws16c48gpio->reg->page_lock);
+
+ /* Disable interrupt */
+ iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
- outb(0x80, ws16c48gpio->base + 7);
- outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
- outb(0xC0, ws16c48gpio->base + 7);
+ /* Select Register Page 3; Unlock all I/O ports */
+ iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@@ -259,6 +287,7 @@ static void ws16c48_irq_unmask(struct irq_data *data)
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
+ unsigned long port_state;
/* only the first 3 ports support interrupts */
if (port > 2)
@@ -267,10 +296,16 @@ static void ws16c48_irq_unmask(struct irq_data *data)
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
ws16c48gpio->irq_mask |= mask;
+ port_state = ws16c48gpio->irq_mask >> (8 * port);
+
+ /* Select Register Page 2; Unlock all I/O ports */
+ iowrite8(0x80, &ws16c48gpio->reg->page_lock);
+
+ /* Enable interrupt */
+ iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
- outb(0x80, ws16c48gpio->base + 7);
- outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
- outb(0xC0, ws16c48gpio->base + 7);
+ /* Select Register Page 3; Unlock all I/O ports */
+ iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@@ -283,6 +318,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
+ unsigned long port_state;
/* only the first 3 ports support interrupts */
if (port > 2)
@@ -304,9 +340,16 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
return -EINVAL;
}
- outb(0x40, ws16c48gpio->base + 7);
- outb(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port);
- outb(0xC0, ws16c48gpio->base + 7);
+ port_state = ws16c48gpio->flow_mask >> (8 * port);
+
+ /* Select Register Page 1; Unlock all I/O ports */
+ iowrite8(0x40, &ws16c48gpio->reg->page_lock);
+
+ /* Set interrupt polarity */
+ iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
+
+ /* Select Register Page 3; Unlock all I/O ports */
+ iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
@@ -325,25 +368,26 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
{
struct ws16c48_gpio *const ws16c48gpio = dev_id;
struct gpio_chip *const chip = &ws16c48gpio->chip;
+ struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg;
unsigned long int_pending;
unsigned long port;
unsigned long int_id;
unsigned long gpio;
- int_pending = inb(ws16c48gpio->base + 6) & 0x7;
+ int_pending = ioread8(&reg->int_pending) & 0x7;
if (!int_pending)
return IRQ_NONE;
/* loop until all pending interrupts are handled */
do {
for_each_set_bit(port, &int_pending, 3) {
- int_id = inb(ws16c48gpio->base + 8 + port);
+ int_id = ioread8(reg->pol_enab_int_id + port);
for_each_set_bit(gpio, &int_id, 8)
generic_handle_domain_irq(chip->irq.domain,
gpio + 8*port);
}
- int_pending = inb(ws16c48gpio->base + 6) & 0x7;
+ int_pending = ioread8(&reg->int_pending) & 0x7;
} while (int_pending);
return IRQ_HANDLED;
@@ -369,12 +413,16 @@ static int ws16c48_irq_init_hw(struct gpio_chip *gc)
{
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc);
- /* Disable IRQ by default */
- outb(0x80, ws16c48gpio->base + 7);
- outb(0, ws16c48gpio->base + 8);
- outb(0, ws16c48gpio->base + 9);
- outb(0, ws16c48gpio->base + 10);
- outb(0xC0, ws16c48gpio->base + 7);
+ /* Select Register Page 2; Unlock all I/O ports */
+ iowrite8(0x80, &ws16c48gpio->reg->page_lock);
+
+ /* Disable interrupts for all lines */
+ iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]);
+ iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]);
+ iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]);
+
+ /* Select Register Page 3; Unlock all I/O ports */
+ iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
return 0;
}
@@ -396,6 +444,10 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
+ ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
+ if (!ws16c48gpio->reg)
+ return -ENOMEM;
+
ws16c48gpio->chip.label = name;
ws16c48gpio->chip.parent = dev;
ws16c48gpio->chip.owner = THIS_MODULE;
@@ -409,7 +461,6 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple;
ws16c48gpio->chip.set = ws16c48_gpio_set;
ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
- ws16c48gpio->base = base[id];
girq = &ws16c48gpio->chip.irq;
girq->chip = &ws16c48_irqchip;
diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c
index 43ca52fa6f9a..fd88500399c6 100644
--- a/drivers/gpio/gpio-xgs-iproc.c
+++ b/drivers/gpio/gpio-xgs-iproc.c
@@ -281,11 +281,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
static int iproc_gpio_remove(struct platform_device *pdev)
{
- struct iproc_gpio_chip *chip;
-
- chip = platform_get_drvdata(pdev);
- if (!chip)
- return -ENODEV;
+ struct iproc_gpio_chip *chip = platform_get_drvdata(pdev);
if (chip->intr) {
u32 val;
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index b6d3a57e27ed..2fc6b6ff7f16 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -99,7 +99,7 @@ static inline void xgpio_set_value32(unsigned long *map, int bit, u32 v)
const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5);
map[index] &= ~(0xFFFFFFFFul << offset);
- map[index] |= v << offset;
+ map[index] |= (unsigned long)v << offset;
}
static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch)
@@ -117,12 +117,14 @@ static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch)
static void xgpio_read_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a)
{
void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32);
+
xgpio_set_value32(a, bit, xgpio_readreg(addr));
}
static void xgpio_write_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a)
{
void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32);
+
xgpio_writereg(addr, xgpio_get_value32(a, bit));
}
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index f6f8a541348f..ce9d1282165c 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -11,7 +11,6 @@
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/gpio/driver.h>
@@ -53,22 +52,23 @@
#define ZEVIO_GPIO_BIT(gpio) (gpio&7)
struct zevio_gpio {
+ struct gpio_chip chip;
spinlock_t lock;
- struct of_mm_gpio_chip chip;
+ void __iomem *regs;
};
static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
unsigned port_offset)
{
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
- return readl(IOMEM(c->chip.regs + section_offset + port_offset));
+ return readl(IOMEM(c->regs + section_offset + port_offset));
}
static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
unsigned port_offset, u32 val)
{
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
- writel(val, IOMEM(c->chip.regs + section_offset + port_offset));
+ writel(val, IOMEM(c->regs + section_offset + port_offset));
}
/* Functions for struct gpio_chip */
@@ -178,12 +178,15 @@ static int zevio_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, controller);
/* Copy our reference */
- controller->chip.gc = zevio_gpio_chip;
- controller->chip.gc.parent = &pdev->dev;
+ controller->chip = zevio_gpio_chip;
+ controller->chip.parent = &pdev->dev;
- status = of_mm_gpiochip_add_data(pdev->dev.of_node,
- &(controller->chip),
- controller);
+ controller->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(controller->regs))
+ return dev_err_probe(&pdev->dev, PTR_ERR(controller->regs),
+ "failed to ioremap memory resource\n");
+
+ status = devm_gpiochip_add_data(&pdev->dev, &controller->chip, controller);
if (status) {
dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status);
return status;
@@ -192,10 +195,10 @@ static int zevio_gpio_probe(struct platform_device *pdev)
spin_lock_init(&controller->lock);
/* Disable interrupts, they only cause errors */
- for (i = 0; i < controller->chip.gc.ngpio; i += 8)
+ for (i = 0; i < controller->chip.ngpio; i += 8)
zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF);
- dev_dbg(controller->chip.gc.parent, "ZEVIO GPIO controller set up!\n");
+ dev_dbg(controller->chip.parent, "ZEVIO GPIO controller set up!\n");
return 0;
}
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index c2523ac26fac..9be1376f9a62 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -687,6 +687,9 @@ int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
case ACPI_PIN_CONFIG_PULLDOWN:
*lookupflags |= GPIO_PULL_DOWN;
break;
+ case ACPI_PIN_CONFIG_NOPULL:
+ *lookupflags |= GPIO_PULL_DISABLE;
+ break;
default:
break;
}
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index ffa0256cad5a..f8041d4898d1 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -24,6 +24,7 @@
#include <linux/timekeeping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
+#include <linux/hte.h>
#include <uapi/linux/gpio.h>
#include "gpiolib.h"
@@ -197,16 +198,15 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd,
void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd;
DECLARE_BITMAP(vals, GPIOHANDLES_MAX);
- int i;
+ unsigned int i;
+ int ret;
- if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
- /* NOTE: It's ok to read values of output lines. */
- int ret = gpiod_get_array_value_complex(false,
- true,
- lh->num_descs,
- lh->descs,
- NULL,
- vals);
+ switch (cmd) {
+ case GPIOHANDLE_GET_LINE_VALUES_IOCTL:
+ /* NOTE: It's okay to read values of output lines */
+ ret = gpiod_get_array_value_complex(false, true,
+ lh->num_descs, lh->descs,
+ NULL, vals);
if (ret)
return ret;
@@ -218,7 +218,7 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
return 0;
- } else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) {
+ case GPIOHANDLE_SET_LINE_VALUES_IOCTL:
/*
* All line descriptors were created at once with the same
* flags so just check if the first one is really output.
@@ -240,10 +240,11 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd,
lh->descs,
NULL,
vals);
- } else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) {
+ case GPIOHANDLE_SET_CONFIG_IOCTL:
return linehandle_set_config(lh, ip);
+ default:
+ return -EINVAL;
}
- return -EINVAL;
}
#ifdef CONFIG_COMPAT
@@ -420,6 +421,10 @@ out_free_lh:
* @work: the worker that implements software debouncing
* @sw_debounced: flag indicating if the software debouncer is active
* @level: the current debounced physical level of the line
+ * @hdesc: the Hardware Timestamp Engine (HTE) descriptor
+ * @raw_level: the line level at the time of event
+ * @total_discard_seq: the running counter of the discarded events
+ * @last_seqno: the last sequence number before debounce period expires
*/
struct line {
struct gpio_desc *desc;
@@ -429,12 +434,15 @@ struct line {
struct linereq *req;
unsigned int irq;
/*
- * eflags is set by edge_detector_setup(), edge_detector_stop() and
- * edge_detector_update(), which are themselves mutually exclusive,
- * and is accessed by edge_irq_thread() and debounce_work_func(),
- * which can both live with a slightly stale value.
+ * The flags for the active edge detector configuration.
+ *
+ * edflags is set by linereq_create(), linereq_free(), and
+ * linereq_set_config_unlocked(), which are themselves mutually
+ * exclusive, and is accessed by edge_irq_thread(),
+ * process_hw_ts_thread() and debounce_work_func(),
+ * which can all live with a slightly stale value.
*/
- u64 eflags;
+ u64 edflags;
/*
* timestamp_ns and req_seqno are accessed only by
* edge_irq_handler() and edge_irq_thread(), which are themselves
@@ -464,6 +472,24 @@ struct line {
* stale value.
*/
unsigned int level;
+#ifdef CONFIG_HTE
+ struct hte_ts_desc hdesc;
+ /*
+ * HTE provider sets line level at the time of event. The valid
+ * value is 0 or 1 and negative value for an error.
+ */
+ int raw_level;
+ /*
+ * when sw_debounce is set on HTE enabled line, this is running
+ * counter of the discarded events.
+ */
+ u32 total_discard_seq;
+ /*
+ * when sw_debounce is set on HTE enabled line, this variable records
+ * last sequence number before debounce period expires.
+ */
+ u32 last_seqno;
+#endif /* CONFIG_HTE */
};
/**
@@ -518,8 +544,15 @@ struct linereq {
GPIO_V2_LINE_DRIVE_FLAGS | \
GPIO_V2_LINE_EDGE_FLAGS | \
GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME | \
+ GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \
GPIO_V2_LINE_BIAS_FLAGS)
+/* subset of flags relevant for edge detector configuration */
+#define GPIO_V2_LINE_EDGE_DETECTOR_FLAGS \
+ (GPIO_V2_LINE_FLAG_ACTIVE_LOW | \
+ GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \
+ GPIO_V2_LINE_EDGE_FLAGS)
+
static void linereq_put_event(struct linereq *lr,
struct gpio_v2_line_event *le)
{
@@ -542,16 +575,145 @@ static u64 line_event_timestamp(struct line *line)
{
if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &line->desc->flags))
return ktime_get_real_ns();
+ else if (IS_ENABLED(CONFIG_HTE) &&
+ test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags))
+ return line->timestamp_ns;
return ktime_get_ns();
}
+static u32 line_event_id(int level)
+{
+ return level ? GPIO_V2_LINE_EVENT_RISING_EDGE :
+ GPIO_V2_LINE_EVENT_FALLING_EDGE;
+}
+
+#ifdef CONFIG_HTE
+
+static enum hte_return process_hw_ts_thread(void *p)
+{
+ struct line *line;
+ struct linereq *lr;
+ struct gpio_v2_line_event le;
+ u64 edflags;
+ int level;
+
+ if (!p)
+ return HTE_CB_HANDLED;
+
+ line = p;
+ lr = line->req;
+
+ memset(&le, 0, sizeof(le));
+
+ le.timestamp_ns = line->timestamp_ns;
+ edflags = READ_ONCE(line->edflags);
+
+ switch (edflags & GPIO_V2_LINE_EDGE_FLAGS) {
+ case GPIO_V2_LINE_FLAG_EDGE_BOTH:
+ level = (line->raw_level >= 0) ?
+ line->raw_level :
+ gpiod_get_raw_value_cansleep(line->desc);
+
+ if (edflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW)
+ level = !level;
+
+ le.id = line_event_id(level);
+ break;
+ case GPIO_V2_LINE_FLAG_EDGE_RISING:
+ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
+ break;
+ case GPIO_V2_LINE_FLAG_EDGE_FALLING:
+ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
+ break;
+ default:
+ return HTE_CB_HANDLED;
+ }
+ le.line_seqno = line->line_seqno;
+ le.seqno = (lr->num_lines == 1) ? le.line_seqno : line->req_seqno;
+ le.offset = gpio_chip_hwgpio(line->desc);
+
+ linereq_put_event(lr, &le);
+
+ return HTE_CB_HANDLED;
+}
+
+static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p)
+{
+ struct line *line;
+ struct linereq *lr;
+ int diff_seqno = 0;
+
+ if (!ts || !p)
+ return HTE_CB_HANDLED;
+
+ line = p;
+ line->timestamp_ns = ts->tsc;
+ line->raw_level = ts->raw_level;
+ lr = line->req;
+
+ if (READ_ONCE(line->sw_debounced)) {
+ line->total_discard_seq++;
+ line->last_seqno = ts->seq;
+ mod_delayed_work(system_wq, &line->work,
+ usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us)));
+ } else {
+ if (unlikely(ts->seq < line->line_seqno))
+ return HTE_CB_HANDLED;
+
+ diff_seqno = ts->seq - line->line_seqno;
+ line->line_seqno = ts->seq;
+ if (lr->num_lines != 1)
+ line->req_seqno = atomic_add_return(diff_seqno,
+ &lr->seqno);
+
+ return HTE_RUN_SECOND_CB;
+ }
+
+ return HTE_CB_HANDLED;
+}
+
+static int hte_edge_setup(struct line *line, u64 eflags)
+{
+ int ret;
+ unsigned long flags = 0;
+ struct hte_ts_desc *hdesc = &line->hdesc;
+
+ if (eflags & GPIO_V2_LINE_FLAG_EDGE_RISING)
+ flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ?
+ HTE_FALLING_EDGE_TS :
+ HTE_RISING_EDGE_TS;
+ if (eflags & GPIO_V2_LINE_FLAG_EDGE_FALLING)
+ flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ?
+ HTE_RISING_EDGE_TS :
+ HTE_FALLING_EDGE_TS;
+
+ line->total_discard_seq = 0;
+
+ hte_init_line_attr(hdesc, desc_to_gpio(line->desc), flags, NULL,
+ line->desc);
+
+ ret = hte_ts_get(NULL, hdesc, 0);
+ if (ret)
+ return ret;
+
+ return hte_request_ts_ns(hdesc, process_hw_ts, process_hw_ts_thread,
+ line);
+}
+
+#else
+
+static int hte_edge_setup(struct line *line, u64 eflags)
+{
+ return 0;
+}
+#endif /* CONFIG_HTE */
+
static irqreturn_t edge_irq_thread(int irq, void *p)
{
struct line *line = p;
struct linereq *lr = line->req;
struct gpio_v2_line_event le;
- u64 eflags;
/* Do not leak kernel stack to userspace */
memset(&le, 0, sizeof(le));
@@ -570,23 +732,17 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
}
line->timestamp_ns = 0;
- eflags = READ_ONCE(line->eflags);
- if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) {
- int level = gpiod_get_value_cansleep(line->desc);
-
- if (level)
- /* Emit low-to-high event */
- le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
- else
- /* Emit high-to-low event */
- le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
- } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
- /* Emit low-to-high event */
+ switch (READ_ONCE(line->edflags) & GPIO_V2_LINE_EDGE_FLAGS) {
+ case GPIO_V2_LINE_FLAG_EDGE_BOTH:
+ le.id = line_event_id(gpiod_get_value_cansleep(line->desc));
+ break;
+ case GPIO_V2_LINE_FLAG_EDGE_RISING:
le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
- } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
- /* Emit high-to-low event */
+ break;
+ case GPIO_V2_LINE_FLAG_EDGE_FALLING:
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
- } else {
+ break;
+ default:
return IRQ_NONE;
}
line->line_seqno++;
@@ -651,10 +807,16 @@ static void debounce_work_func(struct work_struct *work)
struct gpio_v2_line_event le;
struct line *line = container_of(work, struct line, work.work);
struct linereq *lr;
- int level;
- u64 eflags;
+ u64 eflags, edflags = READ_ONCE(line->edflags);
+ int level = -1;
+#ifdef CONFIG_HTE
+ int diff_seqno;
- level = gpiod_get_raw_value_cansleep(line->desc);
+ if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE)
+ level = line->raw_level;
+#endif
+ if (level < 0)
+ level = gpiod_get_raw_value_cansleep(line->desc);
if (level < 0) {
pr_debug_ratelimited("debouncer failed to read line value\n");
return;
@@ -666,12 +828,12 @@ static void debounce_work_func(struct work_struct *work)
WRITE_ONCE(line->level, level);
/* -- edge detection -- */
- eflags = READ_ONCE(line->eflags);
+ eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS;
if (!eflags)
return;
/* switch from physical level to logical - if they differ */
- if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags))
+ if (edflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW)
level = !level;
/* ignore edges that are not being monitored */
@@ -685,23 +847,31 @@ static void debounce_work_func(struct work_struct *work)
lr = line->req;
le.timestamp_ns = line_event_timestamp(line);
le.offset = gpio_chip_hwgpio(line->desc);
- line->line_seqno++;
- le.line_seqno = line->line_seqno;
- le.seqno = (lr->num_lines == 1) ?
- le.line_seqno : atomic_inc_return(&lr->seqno);
+#ifdef CONFIG_HTE
+ if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) {
+ /* discard events except the last one */
+ line->total_discard_seq -= 1;
+ diff_seqno = line->last_seqno - line->total_discard_seq -
+ line->line_seqno;
+ line->line_seqno = line->last_seqno - line->total_discard_seq;
+ le.line_seqno = line->line_seqno;
+ le.seqno = (lr->num_lines == 1) ?
+ le.line_seqno : atomic_add_return(diff_seqno, &lr->seqno);
+ } else
+#endif /* CONFIG_HTE */
+ {
+ line->line_seqno++;
+ le.line_seqno = line->line_seqno;
+ le.seqno = (lr->num_lines == 1) ?
+ le.line_seqno : atomic_inc_return(&lr->seqno);
+ }
- if (level)
- /* Emit low-to-high event */
- le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
- else
- /* Emit high-to-low event */
- le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
+ le.id = line_event_id(level);
linereq_put_event(lr, &le);
}
-static int debounce_setup(struct line *line,
- unsigned int debounce_period_us)
+static int debounce_setup(struct line *line, unsigned int debounce_period_us)
{
unsigned long irqflags;
int ret, level, irq;
@@ -721,19 +891,26 @@ static int debounce_setup(struct line *line,
if (level < 0)
return level;
- irq = gpiod_to_irq(line->desc);
- if (irq < 0)
- return -ENXIO;
+ if (!(IS_ENABLED(CONFIG_HTE) &&
+ test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags))) {
+ irq = gpiod_to_irq(line->desc);
+ if (irq < 0)
+ return -ENXIO;
- WRITE_ONCE(line->level, level);
- irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
- ret = request_irq(irq, debounce_irq_handler, irqflags,
- line->req->label, line);
- if (ret)
- return ret;
+ irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+ ret = request_irq(irq, debounce_irq_handler, irqflags,
+ line->req->label, line);
+ if (ret)
+ return ret;
+ line->irq = irq;
+ } else {
+ ret = hte_edge_setup(line, GPIO_V2_LINE_FLAG_EDGE_BOTH);
+ if (ret)
+ return ret;
+ }
+ WRITE_ONCE(line->level, level);
WRITE_ONCE(line->sw_debounced, 1);
- line->irq = irq;
}
return 0;
}
@@ -773,9 +950,14 @@ static void edge_detector_stop(struct line *line)
line->irq = 0;
}
+#ifdef CONFIG_HTE
+ if (READ_ONCE(line->edflags) & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE)
+ hte_ts_put(&line->hdesc);
+#endif
+
cancel_delayed_work_sync(&line->work);
WRITE_ONCE(line->sw_debounced, 0);
- WRITE_ONCE(line->eflags, 0);
+ WRITE_ONCE(line->edflags, 0);
if (line->desc)
WRITE_ONCE(line->desc->debounce_period_us, 0);
/* do not change line->level - see comment in debounced_value() */
@@ -783,20 +965,20 @@ static void edge_detector_stop(struct line *line)
static int edge_detector_setup(struct line *line,
struct gpio_v2_line_config *lc,
- unsigned int line_idx,
- u64 eflags)
+ unsigned int line_idx, u64 edflags)
{
u32 debounce_period_us;
unsigned long irqflags = 0;
+ u64 eflags;
int irq, ret;
+ eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS;
if (eflags && !kfifo_initialized(&line->req->events)) {
ret = kfifo_alloc(&line->req->events,
line->req->event_buffer_size, GFP_KERNEL);
if (ret)
return ret;
}
- WRITE_ONCE(line->eflags, eflags);
if (gpio_v2_line_config_debounced(lc, line_idx)) {
debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx);
ret = debounce_setup(line, debounce_period_us);
@@ -809,6 +991,10 @@ static int edge_detector_setup(struct line *line,
if (!eflags || READ_ONCE(line->sw_debounced))
return 0;
+ if (IS_ENABLED(CONFIG_HTE) &&
+ (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE))
+ return hte_edge_setup(line, edflags);
+
irq = gpiod_to_irq(line->desc);
if (irq < 0)
return -ENXIO;
@@ -833,29 +1019,29 @@ static int edge_detector_setup(struct line *line,
static int edge_detector_update(struct line *line,
struct gpio_v2_line_config *lc,
- unsigned int line_idx,
- u64 eflags, bool polarity_change)
+ unsigned int line_idx, u64 edflags)
{
+ u64 active_edflags = READ_ONCE(line->edflags);
unsigned int debounce_period_us =
- gpio_v2_line_config_debounce_period(lc, line_idx);
+ gpio_v2_line_config_debounce_period(lc, line_idx);
- if ((READ_ONCE(line->eflags) == eflags) && !polarity_change &&
+ if ((active_edflags == edflags) &&
(READ_ONCE(line->desc->debounce_period_us) == debounce_period_us))
return 0;
/* sw debounced and still will be...*/
if (debounce_period_us && READ_ONCE(line->sw_debounced)) {
- WRITE_ONCE(line->eflags, eflags);
WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us);
return 0;
}
/* reconfiguring edge detection or sw debounce being disabled */
if ((line->irq && !READ_ONCE(line->sw_debounced)) ||
+ (active_edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) ||
(!debounce_period_us && READ_ONCE(line->sw_debounced)))
edge_detector_stop(line);
- return edge_detector_setup(line, lc, line_idx, eflags);
+ return edge_detector_setup(line, lc, line_idx, edflags);
}
static u64 gpio_v2_line_config_flags(struct gpio_v2_line_config *lc,
@@ -892,6 +1078,10 @@ static int gpio_v2_line_flags_validate(u64 flags)
if (flags & ~GPIO_V2_LINE_VALID_FLAGS)
return -EINVAL;
+ if (!IS_ENABLED(CONFIG_HTE) &&
+ (flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE))
+ return -EOPNOTSUPP;
+
/*
* Do not allow both INPUT and OUTPUT flags to be set as they are
* contradictory.
@@ -900,6 +1090,12 @@ static int gpio_v2_line_flags_validate(u64 flags)
(flags & GPIO_V2_LINE_FLAG_OUTPUT))
return -EINVAL;
+ /* Only allow one event clock source */
+ if (IS_ENABLED(CONFIG_HTE) &&
+ (flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME) &&
+ (flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE))
+ return -EINVAL;
+
/* Edge detection requires explicit input. */
if ((flags & GPIO_V2_LINE_EDGE_FLAGS) &&
!(flags & GPIO_V2_LINE_FLAG_INPUT))
@@ -992,6 +1188,8 @@ static void gpio_v2_line_config_flags_to_desc_flags(u64 flags,
assign_bit(FLAG_EVENT_CLOCK_REALTIME, flagsp,
flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME);
+ assign_bit(FLAG_EVENT_CLOCK_HTE, flagsp,
+ flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE);
}
static long linereq_get_values(struct linereq *lr, void __user *ip)
@@ -1118,19 +1316,17 @@ static long linereq_set_config_unlocked(struct linereq *lr,
struct gpio_v2_line_config *lc)
{
struct gpio_desc *desc;
+ struct line *line;
unsigned int i;
- u64 flags;
- bool polarity_change;
+ u64 flags, edflags;
int ret;
for (i = 0; i < lr->num_lines; i++) {
+ line = &lr->lines[i];
desc = lr->lines[i].desc;
flags = gpio_v2_line_config_flags(lc, i);
- polarity_change =
- (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) !=
- ((flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) != 0));
-
gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags);
+ edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS;
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
@@ -1138,7 +1334,7 @@ static long linereq_set_config_unlocked(struct linereq *lr,
if (flags & GPIO_V2_LINE_FLAG_OUTPUT) {
int val = gpio_v2_line_config_output_value(lc, i);
- edge_detector_stop(&lr->lines[i]);
+ edge_detector_stop(line);
ret = gpiod_direction_output(desc, val);
if (ret)
return ret;
@@ -1147,13 +1343,13 @@ static long linereq_set_config_unlocked(struct linereq *lr,
if (ret)
return ret;
- ret = edge_detector_update(&lr->lines[i], lc, i,
- flags & GPIO_V2_LINE_EDGE_FLAGS,
- polarity_change);
+ ret = edge_detector_update(line, lc, i, edflags);
if (ret)
return ret;
}
+ WRITE_ONCE(line->edflags, edflags);
+
blocking_notifier_call_chain(&desc->gdev->notifier,
GPIO_V2_LINE_CHANGED_CONFIG,
desc);
@@ -1188,14 +1384,16 @@ static long linereq_ioctl(struct file *file, unsigned int cmd,
struct linereq *lr = file->private_data;
void __user *ip = (void __user *)arg;
- if (cmd == GPIO_V2_LINE_GET_VALUES_IOCTL)
+ switch (cmd) {
+ case GPIO_V2_LINE_GET_VALUES_IOCTL:
return linereq_get_values(lr, ip);
- else if (cmd == GPIO_V2_LINE_SET_VALUES_IOCTL)
+ case GPIO_V2_LINE_SET_VALUES_IOCTL:
return linereq_set_values(lr, ip);
- else if (cmd == GPIO_V2_LINE_SET_CONFIG_IOCTL)
+ case GPIO_V2_LINE_SET_CONFIG_IOCTL:
return linereq_set_config(lr, ip);
-
- return -EINVAL;
+ default:
+ return -EINVAL;
+ }
}
#ifdef CONFIG_COMPAT
@@ -1280,9 +1478,10 @@ static void linereq_free(struct linereq *lr)
unsigned int i;
for (i = 0; i < lr->num_lines; i++) {
- edge_detector_stop(&lr->lines[i]);
- if (lr->lines[i].desc)
+ if (lr->lines[i].desc) {
+ edge_detector_stop(&lr->lines[i]);
gpiod_free(lr->lines[i].desc);
+ }
}
kfifo_free(&lr->events);
kfree(lr->label);
@@ -1316,7 +1515,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
struct gpio_v2_line_config *lc;
struct linereq *lr;
struct file *file;
- u64 flags;
+ u64 flags, edflags;
unsigned int i;
int fd, ret;
@@ -1390,6 +1589,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
if (ret < 0)
goto out_free_linereq;
+ edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS;
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
@@ -1406,11 +1606,13 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
goto out_free_linereq;
ret = edge_detector_setup(&lr->lines[i], lc, i,
- flags & GPIO_V2_LINE_EDGE_FLAGS);
+ edflags);
if (ret)
goto out_free_linereq;
}
+ lr->lines[i].edflags = edflags;
+
blocking_notifier_call_chain(&desc->gdev->notifier,
GPIO_V2_LINE_CHANGED_REQUESTED, desc);
@@ -1959,6 +2161,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &desc->flags))
info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;
+ else if (test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags))
+ info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE;
debounce_period_us = READ_ONCE(desc->debounce_period_us);
if (debounce_period_us) {
@@ -2113,28 +2317,30 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return -ENODEV;
/* Fill in the struct and pass to userspace */
- if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
+ switch (cmd) {
+ case GPIO_GET_CHIPINFO_IOCTL:
return chipinfo_get(cdev, ip);
#ifdef CONFIG_GPIO_CDEV_V1
- } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
+ case GPIO_GET_LINEHANDLE_IOCTL:
return linehandle_create(gdev, ip);
- } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
+ case GPIO_GET_LINEEVENT_IOCTL:
return lineevent_create(gdev, ip);
- } else if (cmd == GPIO_GET_LINEINFO_IOCTL ||
- cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
- return lineinfo_get_v1(cdev, ip,
- cmd == GPIO_GET_LINEINFO_WATCH_IOCTL);
+ case GPIO_GET_LINEINFO_IOCTL:
+ return lineinfo_get_v1(cdev, ip, false);
+ case GPIO_GET_LINEINFO_WATCH_IOCTL:
+ return lineinfo_get_v1(cdev, ip, true);
#endif /* CONFIG_GPIO_CDEV_V1 */
- } else if (cmd == GPIO_V2_GET_LINEINFO_IOCTL ||
- cmd == GPIO_V2_GET_LINEINFO_WATCH_IOCTL) {
- return lineinfo_get(cdev, ip,
- cmd == GPIO_V2_GET_LINEINFO_WATCH_IOCTL);
- } else if (cmd == GPIO_V2_GET_LINE_IOCTL) {
+ case GPIO_V2_GET_LINEINFO_IOCTL:
+ return lineinfo_get(cdev, ip, false);
+ case GPIO_V2_GET_LINEINFO_WATCH_IOCTL:
+ return lineinfo_get(cdev, ip, true);
+ case GPIO_V2_GET_LINE_IOCTL:
return linereq_create(gdev, ip);
- } else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
+ case GPIO_GET_LINEINFO_UNWATCH_IOCTL:
return lineinfo_unwatch(cdev, ip);
+ default:
+ return -EINVAL;
}
- return -EINVAL;
}
#ifdef CONFIG_COMPAT
diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c
index 79da85d17b71..16a696249229 100644
--- a/drivers/gpio/gpiolib-devres.c
+++ b/drivers/gpio/gpiolib-devres.c
@@ -375,9 +375,6 @@ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
}
EXPORT_SYMBOL_GPL(devm_gpiod_put_array);
-
-
-
static void devm_gpio_release(struct device *dev, void *res)
{
unsigned *gpio = res;
@@ -385,13 +382,6 @@ static void devm_gpio_release(struct device *dev, void *res)
gpio_free(*gpio);
}
-static int devm_gpio_match(struct device *dev, void *res, void *data)
-{
- unsigned *this = res, *gpio = data;
-
- return *this == *gpio;
-}
-
/**
* devm_gpio_request - request a GPIO for a managed device
* @dev: device to request the GPIO for
@@ -402,11 +392,7 @@ static int devm_gpio_match(struct device *dev, void *res, void *data)
* same arguments and performs the same function as
* gpio_request(). GPIOs requested with this function will be
* automatically freed on driver detach.
- *
- * If an GPIO allocated with this function needs to be freed
- * separately, devm_gpio_free() must be used.
*/
-
int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
{
unsigned *dr;
@@ -459,24 +445,6 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
}
EXPORT_SYMBOL_GPL(devm_gpio_request_one);
-/**
- * devm_gpio_free - free a GPIO
- * @dev: device to free GPIO for
- * @gpio: GPIO to free
- *
- * Except for the extra @dev argument, this function takes the
- * same arguments and performs the same function as gpio_free().
- * This function instead of gpio_free() should be used to manually
- * free GPIOs allocated with devm_gpio_request().
- */
-void devm_gpio_free(struct device *dev, unsigned int gpio)
-{
-
- WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
- &gpio));
-}
-EXPORT_SYMBOL_GPL(devm_gpio_free);
-
static void devm_gpio_chip_release(void *data)
{
struct gpio_chip *gc = data;
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 7e5e51d49d09..a037b50bef33 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -354,6 +354,9 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
if (flags & OF_GPIO_PULL_DOWN)
lflags |= GPIO_PULL_DOWN;
+ if (flags & OF_GPIO_PULL_DISABLE)
+ lflags |= GPIO_PULL_DISABLE;
+
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
if (ret < 0) {
gpiod_put(desc);
@@ -556,6 +559,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
*flags |= GPIO_PULL_UP;
if (of_flags & OF_GPIO_PULL_DOWN)
*flags |= GPIO_PULL_DOWN;
+ if (of_flags & OF_GPIO_PULL_DISABLE)
+ *flags |= GPIO_PULL_DISABLE;
return desc;
}
@@ -621,6 +626,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
*lflags |= GPIO_PULL_UP;
if (xlate_flags & OF_GPIO_PULL_DOWN)
*lflags |= GPIO_PULL_DOWN;
+ if (xlate_flags & OF_GPIO_PULL_DISABLE)
+ *lflags |= GPIO_PULL_DISABLE;
if (of_property_read_bool(np, "input"))
*dflags |= GPIOD_IN;
@@ -712,16 +719,15 @@ static void of_gpiochip_remove_hog(struct gpio_chip *chip,
struct device_node *hog)
{
struct gpio_desc *desc;
- unsigned int i;
- for_each_gpio_desc_with_flag(i, chip, desc, FLAG_IS_HOGGED)
+ for_each_gpio_desc_with_flag(chip, desc, FLAG_IS_HOGGED)
if (desc->hog == hog)
gpiochip_free_own_desc(desc);
}
static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
{
- return chip->gpiodev->dev.of_node == data;
+ return device_match_of_node(&chip->gpiodev->dev, data);
}
static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
@@ -861,7 +867,8 @@ int of_mm_gpiochip_add_data(struct device_node *np,
if (mm_gc->save_regs)
mm_gc->save_regs(mm_gc);
- mm_gc->gc.of_node = np;
+ of_node_put(mm_gc->gc.of_node);
+ mm_gc->gc.of_node = of_node_get(np);
ret = gpiochip_add_data(gc, data);
if (ret)
@@ -869,6 +876,7 @@ int of_mm_gpiochip_add_data(struct device_node *np,
return 0;
err2:
+ of_node_put(np);
iounmap(mm_gc->regs);
err1:
kfree(gc->label);
@@ -931,6 +939,11 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
if (!np)
return 0;
+ if (!of_property_read_bool(np, "gpio-ranges") &&
+ chip->of_gpio_ranges_fallback) {
+ return chip->of_gpio_ranges_fallback(chip, np);
+ }
+
group_names = of_find_property(np, group_names_propname, NULL);
for (;; index++) {
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index d44ffea038f5..cd27bf173dec 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -760,7 +760,6 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
{
struct gpio_desc *desc;
struct gpio_chip *chip = gdev->chip;
- unsigned int i;
if (!gdev->mockdev)
return;
@@ -773,7 +772,7 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
mutex_unlock(&sysfs_lock);
/* unregister gpiod class devices owned by sysfs */
- for_each_gpio_desc_with_flag(i, chip, desc, FLAG_SYSFS)
+ for_each_gpio_desc_with_flag(chip, desc, FLAG_SYSFS)
gpiod_free(desc);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b7694171655c..cc9c0a12259e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -189,9 +189,8 @@ static int gpiochip_find_base(int ngpio)
/* found a free space? */
if (gdev->base + gdev->ngpio <= base)
break;
- else
- /* nope, check the space right before the chip */
- base = gdev->base - ngpio;
+ /* nope, check the space right before the chip */
+ base = gdev->base - ngpio;
}
if (gpio_is_valid(base)) {
@@ -289,7 +288,6 @@ static int gpiodev_add_to_list(struct gpio_device *gdev)
}
}
- dev_err(&gdev->dev, "GPIO integer space overlap, cannot add chip\n");
return -EBUSY;
}
@@ -310,15 +308,10 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(gdev, &gpio_devices, list) {
- int i;
-
- for (i = 0; i != gdev->ngpio; ++i) {
- struct gpio_desc *desc = &gdev->descs[i];
-
- if (!desc->name)
- continue;
+ struct gpio_desc *desc;
- if (!strcmp(desc->name, name)) {
+ for_each_gpio_desc(gdev->chip, desc) {
+ if (desc->name && !strcmp(desc->name, name)) {
spin_unlock_irqrestore(&gpio_lock, flags);
return desc;
}
@@ -728,6 +721,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
ret = gpiodev_add_to_list(gdev);
if (ret) {
spin_unlock_irqrestore(&gpio_lock, flags);
+ chip_err(gc, "GPIO integer space overlap, cannot add chip\n");
goto err_free_label;
}
@@ -1113,7 +1107,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
irq_hw_number_t hwirq;
unsigned int type = IRQ_TYPE_NONE;
struct irq_fwspec *fwspec = data;
- void *parent_arg;
+ union gpio_irq_fwspec gpio_parent_fwspec = {};
unsigned int parent_hwirq;
unsigned int parent_type;
struct gpio_irq_chip *girq = &gc->irq;
@@ -1153,14 +1147,15 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
irq_set_probe(irq);
/* This parent only handles asserted level IRQs */
- parent_arg = girq->populate_parent_alloc_arg(gc, parent_hwirq, parent_type);
- if (!parent_arg)
- return -ENOMEM;
+ ret = girq->populate_parent_alloc_arg(gc, &gpio_parent_fwspec,
+ parent_hwirq, parent_type);
+ if (ret)
+ return ret;
chip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
irq, parent_hwirq);
irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key);
- ret = irq_domain_alloc_irqs_parent(d, irq, 1, parent_arg);
+ ret = irq_domain_alloc_irqs_parent(d, irq, 1, &gpio_parent_fwspec);
/*
* If the parent irqdomain is msi, the interrupts have already
* been allocated, so the EEXIST is good.
@@ -1172,7 +1167,6 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
"failed to allocate parent hwirq %d for hwirq %lu\n",
parent_hwirq, hwirq);
- kfree(parent_arg);
return ret;
}
@@ -1187,15 +1181,18 @@ static void gpiochip_hierarchy_setup_domain_ops(struct irq_domain_ops *ops)
ops->activate = gpiochip_irq_domain_activate;
ops->deactivate = gpiochip_irq_domain_deactivate;
ops->alloc = gpiochip_hierarchy_irq_domain_alloc;
- ops->free = irq_domain_free_irqs_common;
/*
- * We only allow overriding the translate() function for
+ * We only allow overriding the translate() and free() functions for
* hierarchical chips, and this should only be done if the user
- * really need something other than 1:1 translation.
+ * really need something other than 1:1 translation for translate()
+ * callback and free if user wants to free up any resources which
+ * were allocated during callbacks, for example populate_parent_alloc_arg.
*/
if (!ops->translate)
ops->translate = gpiochip_hierarchy_irq_domain_translate;
+ if (!ops->free)
+ ops->free = irq_domain_free_irqs_common;
}
static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
@@ -1236,34 +1233,28 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
return !!gc->irq.parent_domain;
}
-void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
- unsigned int parent_hwirq,
- unsigned int parent_type)
+int gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
+ union gpio_irq_fwspec *gfwspec,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
{
- struct irq_fwspec *fwspec;
-
- fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
- if (!fwspec)
- return NULL;
+ struct irq_fwspec *fwspec = &gfwspec->fwspec;
fwspec->fwnode = gc->irq.parent_domain->fwnode;
fwspec->param_count = 2;
fwspec->param[0] = parent_hwirq;
fwspec->param[1] = parent_type;
- return fwspec;
+ return 0;
}
EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell);
-void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
- unsigned int parent_hwirq,
- unsigned int parent_type)
+int gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
+ union gpio_irq_fwspec *gfwspec,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
{
- struct irq_fwspec *fwspec;
-
- fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
- if (!fwspec)
- return NULL;
+ struct irq_fwspec *fwspec = &gfwspec->fwspec;
fwspec->fwnode = gc->irq.parent_domain->fwnode;
fwspec->param_count = 4;
@@ -1272,7 +1263,7 @@ void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
fwspec->param[2] = 0;
fwspec->param[3] = parent_type;
- return fwspec;
+ return 0;
}
EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_fourcell);
@@ -1433,19 +1424,21 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)
return irq_create_mapping(domain, offset);
}
-static int gpiochip_irq_reqres(struct irq_data *d)
+int gpiochip_irq_reqres(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
return gpiochip_reqres_irq(gc, d->hwirq);
}
+EXPORT_SYMBOL(gpiochip_irq_reqres);
-static void gpiochip_irq_relres(struct irq_data *d)
+void gpiochip_irq_relres(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
gpiochip_relres_irq(gc, d->hwirq);
}
+EXPORT_SYMBOL(gpiochip_irq_relres);
static void gpiochip_irq_mask(struct irq_data *d)
{
@@ -1485,6 +1478,11 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
{
struct irq_chip *irqchip = gc->irq.chip;
+ if (irqchip->flags & IRQCHIP_IMMUTABLE)
+ return;
+
+ chip_warn(gc, "not an immutable chip, please consider fixing it!\n");
+
if (!irqchip->irq_request_resources &&
!irqchip->irq_release_resources) {
irqchip->irq_request_resources = gpiochip_irq_reqres;
@@ -1652,7 +1650,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)
irq_domain_remove(gc->irq.domain);
}
- if (irqchip) {
+ if (irqchip && !(irqchip->flags & IRQCHIP_IMMUTABLE)) {
if (irqchip->irq_request_resources == gpiochip_irq_reqres) {
irqchip->irq_request_resources = NULL;
irqchip->irq_release_resources = NULL;
@@ -2420,8 +2418,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
ret = gpiod_direction_input(desc);
goto set_output_flag;
}
- }
- else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
+ } else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
ret = gpio_set_config(desc, PIN_CONFIG_DRIVE_OPEN_SOURCE);
if (!ret)
goto set_output_value;
@@ -2454,6 +2451,64 @@ set_output_flag:
EXPORT_SYMBOL_GPL(gpiod_direction_output);
/**
+ * gpiod_enable_hw_timestamp_ns - Enable hardware timestamp in nanoseconds.
+ *
+ * @desc: GPIO to enable.
+ * @flags: Flags related to GPIO edge.
+ *
+ * Return 0 in case of success, else negative error code.
+ */
+int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags)
+{
+ int ret = 0;
+ struct gpio_chip *gc;
+
+ VALIDATE_DESC(desc);
+
+ gc = desc->gdev->chip;
+ if (!gc->en_hw_timestamp) {
+ gpiod_warn(desc, "%s: hw ts not supported\n", __func__);
+ return -ENOTSUPP;
+ }
+
+ ret = gc->en_hw_timestamp(gc, gpio_chip_hwgpio(desc), flags);
+ if (ret)
+ gpiod_warn(desc, "%s: hw ts request failed\n", __func__);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gpiod_enable_hw_timestamp_ns);
+
+/**
+ * gpiod_disable_hw_timestamp_ns - Disable hardware timestamp.
+ *
+ * @desc: GPIO to disable.
+ * @flags: Flags related to GPIO edge, same value as used during enable call.
+ *
+ * Return 0 in case of success, else negative error code.
+ */
+int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags)
+{
+ int ret = 0;
+ struct gpio_chip *gc;
+
+ VALIDATE_DESC(desc);
+
+ gc = desc->gdev->chip;
+ if (!gc->dis_hw_timestamp) {
+ gpiod_warn(desc, "%s: hw ts not supported\n", __func__);
+ return -ENOTSUPP;
+ }
+
+ ret = gc->dis_hw_timestamp(gc, gpio_chip_hwgpio(desc), flags);
+ if (ret)
+ gpiod_warn(desc, "%s: hw ts release failed\n", __func__);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gpiod_disable_hw_timestamp_ns);
+
+/**
* gpiod_set_config - sets @config for a GPIO
* @desc: descriptor of the GPIO for which to set the configuration
* @config: Same packed config format as generic pinconf
@@ -2539,6 +2594,11 @@ void gpiod_toggle_active_low(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_toggle_active_low);
+static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *desc)
+{
+ return gc->get ? gc->get(gc, gpio_chip_hwgpio(desc)) : -EIO;
+}
+
/* I/O calls are only valid after configuration completed; the relevant
* "is this a valid GPIO" error checks should already have been done.
*
@@ -2564,12 +2624,10 @@ EXPORT_SYMBOL_GPL(gpiod_toggle_active_low);
static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
{
struct gpio_chip *gc;
- int offset;
int value;
gc = desc->gdev->chip;
- offset = gpio_chip_hwgpio(desc);
- value = gc->get ? gc->get(gc, offset) : -EIO;
+ value = gpio_chip_get_value(gc, desc);
value = value < 0 ? value : !!value;
trace_gpio_value(desc_to_gpio(desc), 1, value);
return value;
@@ -2578,9 +2636,9 @@ static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
static int gpio_chip_get_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits)
{
- if (gc->get_multiple) {
+ if (gc->get_multiple)
return gc->get_multiple(gc, mask, bits);
- } else if (gc->get) {
+ if (gc->get) {
int i, value;
for_each_set_bit(i, mask, gc->ngpio) {
@@ -3884,9 +3942,11 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
if (lflags & GPIO_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
- if ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) {
+ if (((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) ||
+ ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DISABLE)) ||
+ ((lflags & GPIO_PULL_DOWN) && (lflags & GPIO_PULL_DISABLE))) {
gpiod_err(desc,
- "both pull-up and pull-down enabled, invalid configuration\n");
+ "multiple pull-up, pull-down or pull-disable enabled, invalid configuration\n");
return -EINVAL;
}
@@ -3894,6 +3954,8 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
set_bit(FLAG_PULL_UP, &desc->flags);
else if (lflags & GPIO_PULL_DOWN)
set_bit(FLAG_PULL_DOWN, &desc->flags);
+ else if (lflags & GPIO_PULL_DISABLE)
+ set_bit(FLAG_BIAS_DISABLE, &desc->flags);
ret = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
if (ret < 0)
@@ -4140,9 +4202,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
static void gpiochip_free_hogs(struct gpio_chip *gc)
{
struct gpio_desc *desc;
- int id;
- for_each_gpio_desc_with_flag(id, gc, desc, FLAG_IS_HOGGED)
+ for_each_gpio_desc_with_flag(gc, desc, FLAG_IS_HOGGED)
gpiochip_free_own_desc(desc);
}
@@ -4402,34 +4463,32 @@ core_initcall(gpiolib_dev_init);
static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
{
- unsigned i;
struct gpio_chip *gc = gdev->chip;
+ struct gpio_desc *desc;
unsigned gpio = gdev->base;
- struct gpio_desc *gdesc = &gdev->descs[0];
+ int value;
bool is_out;
bool is_irq;
bool active_low;
- for (i = 0; i < gdev->ngpio; i++, gpio++, gdesc++) {
- if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) {
- if (gdesc->name) {
- seq_printf(s, " gpio-%-3d (%-20.20s)\n",
- gpio, gdesc->name);
- }
- continue;
+ for_each_gpio_desc(gc, desc) {
+ if (test_bit(FLAG_REQUESTED, &desc->flags)) {
+ gpiod_get_direction(desc);
+ is_out = test_bit(FLAG_IS_OUT, &desc->flags);
+ value = gpio_chip_get_value(gc, desc);
+ is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags);
+ active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags);
+ seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s\n",
+ gpio, desc->name ?: "", desc->label,
+ is_out ? "out" : "in ",
+ value >= 0 ? (value ? "hi" : "lo") : "? ",
+ is_irq ? "IRQ " : "",
+ active_low ? "ACTIVE LOW" : "");
+ } else if (desc->name) {
+ seq_printf(s, " gpio-%-3d (%-20.20s)\n", gpio, desc->name);
}
- gpiod_get_direction(gdesc);
- is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
- is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags);
- active_low = test_bit(FLAG_ACTIVE_LOW, &gdesc->flags);
- seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s",
- gpio, gdesc->name ? gdesc->name : "", gdesc->label,
- is_out ? "out" : "in ",
- gc->get ? (gc->get(gc, i) ? "hi" : "lo") : "? ",
- is_irq ? "IRQ " : "",
- active_low ? "ACTIVE LOW" : "");
- seq_printf(s, "\n");
+ gpio++;
}
}
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 06f3faa9fbef..d900ecdbac46 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -100,10 +100,13 @@ struct gpio_array {
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum);
-#define for_each_gpio_desc_with_flag(i, gc, desc, flag) \
- for (i = 0, desc = gpiochip_get_desc(gc, i); \
- i < gc->ngpio; \
- i++, desc = gpiochip_get_desc(gc, i)) \
+#define for_each_gpio_desc(gc, desc) \
+ for (unsigned int __i = 0; \
+ __i < gc->ngpio && (desc = gpiochip_get_desc(gc, __i)); \
+ __i++) \
+
+#define for_each_gpio_desc_with_flag(gc, desc, flag) \
+ for_each_gpio_desc(gc, desc) \
if (!test_bit(flag, &desc->flags)) {} else
int gpiod_get_array_value_complex(bool raw, bool can_sleep,
@@ -158,6 +161,7 @@ struct gpio_desc {
#define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */
#define FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */
#define FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */
+#define FLAG_EVENT_CLOCK_HTE 19 /* GPIO CDEV reports hardware timestamps in events */
/* Connection label */
const char *label;