summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig24
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/gpio-74x164.c9
-rw-r--r--drivers/gpio/gpio-clps711x.c10
-rw-r--r--drivers/gpio/gpio-dwapb.c1
-rw-r--r--drivers/gpio/gpio-f7188x.c22
-rw-r--r--drivers/gpio/gpio-intel-mid.c37
-rw-r--r--drivers/gpio/gpio-lynxpoint.c1
-rw-r--r--drivers/gpio/gpio-max77620.c315
-rw-r--r--drivers/gpio/gpio-menz127.c1
-rw-r--r--drivers/gpio/gpio-merrifield.c444
-rw-r--r--drivers/gpio/gpio-mmio.c51
-rw-r--r--drivers/gpio/gpio-palmas.c1
-rw-r--r--drivers/gpio/gpio-pca953x.c23
-rw-r--r--drivers/gpio/gpio-pcf857x.c9
-rw-r--r--drivers/gpio/gpio-rcar.c3
-rw-r--r--drivers/gpio/gpio-rdc321x.c1
-rw-r--r--drivers/gpio/gpio-sch311x.c1
-rw-r--r--drivers/gpio/gpio-stmpe.c18
-rw-r--r--drivers/gpio/gpio-syscon.c4
-rw-r--r--drivers/gpio/gpio-tc3589x.c1
-rw-r--r--drivers/gpio/gpio-tps65218.c7
-rw-r--r--drivers/gpio/gpio-tps6586x.c1
-rw-r--r--drivers/gpio/gpio-tps65910.c1
-rw-r--r--drivers/gpio/gpio-viperboard.c1
-rw-r--r--drivers/gpio/gpio-wm831x.c1
-rw-r--r--drivers/gpio/gpio-wm8350.c1
-rw-r--r--drivers/gpio/gpio-wm8994.c1
-rw-r--r--drivers/gpio/gpio-xilinx.c48
-rw-r--r--drivers/gpio/gpio-xlp.c52
-rw-r--r--drivers/gpio/gpiolib-acpi.c1
-rw-r--r--drivers/gpio/gpiolib-of.c127
-rw-r--r--drivers/gpio/gpiolib.c511
33 files changed, 1573 insertions, 157 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d7860614f87f..98dd47a30fc7 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -250,7 +250,7 @@ config GPIO_LOONGSON
driver for GPIO functionality on Loongson-2F/3A/3B processors.
config GPIO_LPC18XX
- bool "NXP LPC18XX/43XX GPIO support"
+ tristate "NXP LPC18XX/43XX GPIO support"
default y if ARCH_LPC18XX
depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST)
help
@@ -874,6 +874,15 @@ config GPIO_LP3943
LP3943 can be used as a GPIO expander which provides up to 16 GPIOs.
Open drain outputs are required for this usage.
+config GPIO_MAX77620
+ tristate "GPIO support for PMIC MAX77620 and MAX20024"
+ depends on MFD_MAX77620
+ help
+ GPIO driver for MAX77620 and MAX20024 PMIC from Maxim Semiconductor.
+ MAX77620 PMIC has 8 pins that can be configured as GPIOs. The
+ driver also provides interrupt support for each of the gpios.
+ Say yes here to enable the max77620 to be used as gpio controller.
+
config GPIO_MSIC
bool "Intel MSIC mixed signal gpio support"
depends on MFD_INTEL_MSIC
@@ -1029,11 +1038,18 @@ config GPIO_BT8XX
If unsure, say N.
config GPIO_INTEL_MID
- bool "Intel Mid GPIO support"
- depends on X86
+ bool "Intel MID GPIO support"
+ depends on X86_INTEL_MID
+ select GPIOLIB_IRQCHIP
+ help
+ Say Y here to support Intel MID GPIO.
+
+config GPIO_MERRIFIELD
+ tristate "Intel Merrifield GPIO support"
+ depends on X86_INTEL_MID
select GPIOLIB_IRQCHIP
help
- Say Y here to support Intel Mid GPIO.
+ Say Y here to support Intel Merrifield GPIO.
config GPIO_ML_IOH
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 991598ea3fba..2a035ed8f168 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -61,8 +61,10 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
+obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
+obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index 80f9ddf13343..a6607faf2fdf 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -35,13 +35,8 @@ struct gen_74x164_chip {
static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
{
- struct spi_transfer xfer = {
- .tx_buf = chip->buffer,
- .len = chip->registers,
- };
-
- return spi_sync_transfer(to_spi_device(chip->gpio_chip.parent),
- &xfer, 1);
+ return spi_write(to_spi_device(chip->gpio_chip.parent), chip->buffer,
+ chip->registers);
}
static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index 5a690256af9b..52fd63f02134 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -20,8 +20,12 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
void __iomem *dat, *dir;
struct gpio_chip *gc;
struct resource *res;
- int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id;
+ int err, id;
+ if (!np)
+ return -ENODEV;
+
+ id = of_alias_get_id(np, "gpio");
if ((id < 0) || (id > 4))
return -ENODEV;
@@ -63,7 +67,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
break;
}
- gc->base = id * 8;
+ gc->base = -1;
gc->owner = THIS_MODULE;
platform_set_drvdata(pdev, gc);
@@ -71,7 +75,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
}
static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = {
- { .compatible = "cirrus,clps711x-gpio" },
+ { .compatible = "cirrus,ep7209-gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_gpio_ids);
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 34779bb375de..6193f62c0df4 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -486,6 +486,7 @@ dwapb_gpio_get_pdata(struct device *dev)
pp->idx >= DWAPB_MAX_PORTS) {
dev_err(dev,
"missing/invalid port index for port%d\n", i);
+ fwnode_handle_put(fwnode);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index 05aa538c3767..600be8418707 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -125,6 +125,7 @@ static inline void superio_exit(int base)
* GPIO chip.
*/
+static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset);
static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset);
static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);
static int f7188x_gpio_direction_out(struct gpio_chip *chip,
@@ -139,6 +140,7 @@ static int f7188x_gpio_set_single_ended(struct gpio_chip *gc,
.chip = { \
.label = DRVNAME, \
.owner = THIS_MODULE, \
+ .get_direction = f7188x_gpio_get_direction, \
.direction_input = f7188x_gpio_direction_in, \
.get = f7188x_gpio_get, \
.direction_output = f7188x_gpio_direction_out, \
@@ -209,6 +211,26 @@ static struct f7188x_gpio_bank f81866_gpio_bank[] = {
F7188X_GPIO_BANK(80, 8, 0x88),
};
+static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ int err;
+ struct f7188x_gpio_bank *bank =
+ container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_sio *sio = bank->data->sio;
+ u8 dir;
+
+ err = superio_enter(sio->addr);
+ if (err)
+ return err;
+ superio_select(sio->addr, SIO_LD_GPIO);
+
+ dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+
+ superio_exit(sio->addr);
+
+ return !(dir & 1 << offset);
+}
+
static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
int err;
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index cdaba13cb8e8..164de64b11fc 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -1,7 +1,7 @@
/*
* Intel MID GPIO driver
*
- * Copyright (c) 2008-2014 Intel Corporation.
+ * Copyright (c) 2008-2014,2016 Intel Corporation.
*
* 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
@@ -17,21 +17,20 @@
* Moorestown platform Langwell chip.
* Medfield platform Penwell chip.
* Clovertrail platform Cloverview chip.
- * Merrifield platform Tangier chip.
*/
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/stddef.h>
-#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/gpio/driver.h>
-#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0)
#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1)
@@ -64,10 +63,6 @@ enum GPIO_REG {
/* intel_mid gpio driver data */
struct intel_mid_gpio_ddata {
u16 ngpio; /* number of gpio pins */
- u32 gplr_offset; /* offset of first GPLR register from base */
- u32 flis_base; /* base address of FLIS registers */
- u32 flis_len; /* length of FLIS registers */
- u32 (*get_flis_offset)(int gpio);
u32 chip_irq_type; /* chip interrupt type */
};
@@ -252,15 +247,6 @@ static const struct intel_mid_gpio_ddata gpio_cloverview_core = {
.chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
};
-static const struct intel_mid_gpio_ddata gpio_tangier = {
- .ngpio = 192,
- .gplr_offset = 4,
- .flis_base = 0xff0c0000,
- .flis_len = 0x8000,
- .get_flis_offset = NULL,
- .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
-};
-
static const struct pci_device_id intel_gpio_ids[] = {
{
/* Lincroft */
@@ -287,11 +273,6 @@ static const struct pci_device_id intel_gpio_ids[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7),
.driver_data = (kernel_ulong_t)&gpio_cloverview_core,
},
- {
- /* Tangier */
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199),
- .driver_data = (kernel_ulong_t)&gpio_tangier,
- },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
@@ -401,7 +382,7 @@ static int intel_gpio_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock);
pci_set_drvdata(pdev, priv);
- retval = gpiochip_add_data(&priv->chip, priv);
+ retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
if (retval) {
dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
return retval;
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 9df015e85ad9..fbd393b46ce0 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -383,7 +383,6 @@ static int lp_gpio_probe(struct platform_device *pdev)
handle_simple_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(dev, "failed to add irqchip\n");
- gpiochip_remove(gc);
return ret;
}
diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c
new file mode 100644
index 000000000000..b46b436cb97f
--- /dev/null
+++ b/drivers/gpio/gpio-max77620.c
@@ -0,0 +1,315 @@
+/*
+ * MAXIM MAX77620 GPIO driver
+ *
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max77620.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define GPIO_REG_ADDR(offset) (MAX77620_REG_GPIO0 + offset)
+
+struct max77620_gpio {
+ struct gpio_chip gpio_chip;
+ struct regmap *rmap;
+ struct device *dev;
+ int gpio_irq;
+ int irq_base;
+ int gpio_base;
+};
+
+static const struct regmap_irq max77620_gpio_irqs[] = {
+ [0] = {
+ .mask = MAX77620_IRQ_LVL2_GPIO_EDGE0,
+ .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
+ .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
+ .reg_offset = 0,
+ .type_reg_offset = 0,
+ },
+ [1] = {
+ .mask = MAX77620_IRQ_LVL2_GPIO_EDGE1,
+ .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
+ .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
+ .reg_offset = 0,
+ .type_reg_offset = 1,
+ },
+ [2] = {
+ .mask = MAX77620_IRQ_LVL2_GPIO_EDGE2,
+ .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
+ .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
+ .reg_offset = 0,
+ .type_reg_offset = 2,
+ },
+ [3] = {
+ .mask = MAX77620_IRQ_LVL2_GPIO_EDGE3,
+ .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
+ .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
+ .reg_offset = 0,
+ .type_reg_offset = 3,
+ },
+ [4] = {
+ .mask = MAX77620_IRQ_LVL2_GPIO_EDGE4,
+ .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
+ .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
+ .reg_offset = 0,
+ .type_reg_offset = 4,
+ },
+ [5] = {
+ .mask = MAX77620_IRQ_LVL2_GPIO_EDGE5,
+ .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
+ .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
+ .reg_offset = 0,
+ .type_reg_offset = 5,
+ },
+ [6] = {
+ .mask = MAX77620_IRQ_LVL2_GPIO_EDGE6,
+ .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
+ .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
+ .reg_offset = 0,
+ .type_reg_offset = 6,
+ },
+ [7] = {
+ .mask = MAX77620_IRQ_LVL2_GPIO_EDGE7,
+ .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING,
+ .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING,
+ .reg_offset = 0,
+ .type_reg_offset = 7,
+ },
+};
+
+static struct regmap_irq_chip max77620_gpio_irq_chip = {
+ .name = "max77620-gpio",
+ .irqs = max77620_gpio_irqs,
+ .num_irqs = ARRAY_SIZE(max77620_gpio_irqs),
+ .num_regs = 1,
+ .num_type_reg = 8,
+ .irq_reg_stride = 1,
+ .type_reg_stride = 1,
+ .status_base = MAX77620_REG_IRQ_LVL2_GPIO,
+ .type_base = MAX77620_REG_GPIO0,
+};
+
+static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
+{
+ struct max77620_gpio *mgpio = gpiochip_get_data(gc);
+ int ret;
+
+ ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
+ MAX77620_CNFG_GPIO_DIR_MASK,
+ MAX77620_CNFG_GPIO_DIR_INPUT);
+ if (ret < 0)
+ dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret);
+
+ return ret;
+}
+
+static int max77620_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct max77620_gpio *mgpio = gpiochip_get_data(gc);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(mgpio->rmap, GPIO_REG_ADDR(offset), &val);
+ if (ret < 0) {
+ dev_err(mgpio->dev, "CNFG_GPIOx read failed: %d\n", ret);
+ return ret;
+ }
+
+ if (val & MAX77620_CNFG_GPIO_DIR_MASK)
+ return !!(val & MAX77620_CNFG_GPIO_INPUT_VAL_MASK);
+ else
+ return !!(val & MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK);
+}
+
+static int max77620_gpio_dir_output(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ struct max77620_gpio *mgpio = gpiochip_get_data(gc);
+ u8 val;
+ int ret;
+
+ val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH :
+ MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW;
+
+ ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
+ MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val);
+ if (ret < 0) {
+ dev_err(mgpio->dev, "CNFG_GPIOx val update failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
+ MAX77620_CNFG_GPIO_DIR_MASK,
+ MAX77620_CNFG_GPIO_DIR_OUTPUT);
+ if (ret < 0)
+ dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret);
+
+ return ret;
+}
+
+static int max77620_gpio_set_debounce(struct gpio_chip *gc,
+ unsigned int offset,
+ unsigned int debounce)
+{
+ struct max77620_gpio *mgpio = gpiochip_get_data(gc);
+ u8 val;
+ int ret;
+
+ switch (debounce) {
+ case 0:
+ val = MAX77620_CNFG_GPIO_DBNC_None;
+ break;
+ case 1 ... 8:
+ val = MAX77620_CNFG_GPIO_DBNC_8ms;
+ break;
+ case 9 ... 16:
+ val = MAX77620_CNFG_GPIO_DBNC_16ms;
+ break;
+ case 17 ... 32:
+ val = MAX77620_CNFG_GPIO_DBNC_32ms;
+ break;
+ default:
+ dev_err(mgpio->dev, "Illegal value %u\n", debounce);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
+ MAX77620_CNFG_GPIO_DBNC_MASK, val);
+ if (ret < 0)
+ dev_err(mgpio->dev, "CNFG_GPIOx_DBNC update failed: %d\n", ret);
+
+ return ret;
+}
+
+static void max77620_gpio_set(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ struct max77620_gpio *mgpio = gpiochip_get_data(gc);
+ u8 val;
+ int ret;
+
+ val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH :
+ MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW;
+
+ ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
+ MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val);
+ if (ret < 0)
+ dev_err(mgpio->dev, "CNFG_GPIO_OUT update failed: %d\n", ret);
+}
+
+static int max77620_gpio_set_single_ended(struct gpio_chip *gc,
+ unsigned int offset,
+ enum single_ended_mode mode)
+{
+ struct max77620_gpio *mgpio = gpiochip_get_data(gc);
+
+ switch (mode) {
+ case LINE_MODE_OPEN_DRAIN:
+ return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
+ MAX77620_CNFG_GPIO_DRV_MASK,
+ MAX77620_CNFG_GPIO_DRV_OPENDRAIN);
+ case LINE_MODE_PUSH_PULL:
+ return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
+ MAX77620_CNFG_GPIO_DRV_MASK,
+ MAX77620_CNFG_GPIO_DRV_PUSHPULL);
+ default:
+ break;
+ }
+
+ return -ENOTSUPP;
+}
+
+static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+ struct max77620_gpio *mgpio = gpiochip_get_data(gc);
+ struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent);
+
+ return regmap_irq_get_virq(chip->gpio_irq_data, offset);
+}
+
+static int max77620_gpio_probe(struct platform_device *pdev)
+{
+ struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct max77620_gpio *mgpio;
+ int gpio_irq;
+ int ret;
+
+ gpio_irq = platform_get_irq(pdev, 0);
+ if (gpio_irq <= 0) {
+ dev_err(&pdev->dev, "GPIO irq not available %d\n", gpio_irq);
+ return -ENODEV;
+ }
+
+ mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);
+ if (!mgpio)
+ return -ENOMEM;
+
+ mgpio->rmap = chip->rmap;
+ mgpio->dev = &pdev->dev;
+ mgpio->gpio_irq = gpio_irq;
+
+ mgpio->gpio_chip.label = pdev->name;
+ mgpio->gpio_chip.parent = &pdev->dev;
+ mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
+ mgpio->gpio_chip.get = max77620_gpio_get;
+ mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
+ mgpio->gpio_chip.set_debounce = max77620_gpio_set_debounce;
+ mgpio->gpio_chip.set = max77620_gpio_set;
+ mgpio->gpio_chip.set_single_ended = max77620_gpio_set_single_ended;
+ mgpio->gpio_chip.to_irq = max77620_gpio_to_irq;
+ mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
+ mgpio->gpio_chip.can_sleep = 1;
+ mgpio->gpio_chip.base = -1;
+ mgpio->irq_base = -1;
+#ifdef CONFIG_OF_GPIO
+ mgpio->gpio_chip.of_node = pdev->dev.parent->of_node;
+#endif
+
+ platform_set_drvdata(pdev, mgpio);
+
+ ret = devm_gpiochip_add_data(&pdev->dev, &mgpio->gpio_chip, mgpio);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "gpio_init: Failed to add max77620_gpio\n");
+ return ret;
+ }
+
+ mgpio->gpio_base = mgpio->gpio_chip.base;
+ ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, mgpio->gpio_irq,
+ IRQF_ONESHOT, mgpio->irq_base,
+ &max77620_gpio_irq_chip,
+ &chip->gpio_irq_data);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to add gpio irq_chip %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id max77620_gpio_devtype[] = {
+ { .name = "max77620-gpio", },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype);
+
+static struct platform_driver max77620_gpio_driver = {
+ .driver.name = "max77620-gpio",
+ .probe = max77620_gpio_probe,
+ .id_table = max77620_gpio_devtype,
+};
+
+module_platform_driver(max77620_gpio_driver);
+
+MODULE_DESCRIPTION("GPIO interface for MAX77620 and MAX20024 PMIC");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_AUTHOR("Chaitanya Bandi <bandik@nvidia.com>");
+MODULE_ALIAS("platform:max77620-gpio");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c
index cc103aff45e4..a1210e330571 100644
--- a/drivers/gpio/gpio-menz127.c
+++ b/drivers/gpio/gpio-menz127.c
@@ -187,7 +187,6 @@ MODULE_DEVICE_TABLE(mcb, men_z127_ids);
static struct mcb_driver men_z127_driver = {
.driver = {
.name = "z127-gpio",
- .owner = THIS_MODULE,
},
.probe = men_z127_probe,
.remove = men_z127_remove,
diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c
new file mode 100644
index 000000000000..45b51278b8ee
--- /dev/null
+++ b/drivers/gpio/gpio-merrifield.c
@@ -0,0 +1,444 @@
+/*
+ * Intel Merrifield SoC GPIO driver
+ *
+ * Copyright (c) 2016 Intel Corporation.
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pinctrl/consumer.h>
+
+#define GCCR 0x000 /* controller configuration */
+#define GPLR 0x004 /* pin level r/o */
+#define GPDR 0x01c /* pin direction */
+#define GPSR 0x034 /* pin set w/o */
+#define GPCR 0x04c /* pin clear w/o */
+#define GRER 0x064 /* rising edge detect */
+#define GFER 0x07c /* falling edge detect */
+#define GFBR 0x094 /* glitch filter bypass */
+#define GIMR 0x0ac /* interrupt mask */
+#define GISR 0x0c4 /* interrupt source */
+#define GITR 0x300 /* input type */
+#define GLPR 0x318 /* level input polarity */
+#define GWMR 0x400 /* wake mask */
+#define GWSR 0x418 /* wake source */
+#define GSIR 0xc00 /* secure input */
+
+/* Intel Merrifield has 192 GPIO pins */
+#define MRFLD_NGPIO 192
+
+struct mrfld_gpio_pinrange {
+ unsigned int gpio_base;
+ unsigned int pin_base;
+ unsigned int npins;
+};
+
+#define GPIO_PINRANGE(gstart, gend, pstart) \
+ { \
+ .gpio_base = (gstart), \
+ .pin_base = (pstart), \
+ .npins = (gend) - (gstart) + 1, \
+ }
+
+struct mrfld_gpio {
+ struct gpio_chip chip;
+ void __iomem *reg_base;
+ raw_spinlock_t lock;
+ struct device *dev;
+};
+
+static const struct mrfld_gpio_pinrange mrfld_gpio_ranges[] = {
+ GPIO_PINRANGE(0, 11, 146),
+ GPIO_PINRANGE(12, 13, 144),
+ GPIO_PINRANGE(14, 15, 35),
+ GPIO_PINRANGE(16, 16, 164),
+ GPIO_PINRANGE(17, 18, 105),
+ GPIO_PINRANGE(19, 22, 101),
+ GPIO_PINRANGE(23, 30, 107),
+ GPIO_PINRANGE(32, 43, 67),
+ GPIO_PINRANGE(44, 63, 195),
+ GPIO_PINRANGE(64, 67, 140),
+ GPIO_PINRANGE(68, 69, 165),
+ GPIO_PINRANGE(70, 71, 65),
+ GPIO_PINRANGE(72, 76, 228),
+ GPIO_PINRANGE(77, 86, 37),
+ GPIO_PINRANGE(87, 87, 48),
+ GPIO_PINRANGE(88, 88, 47),
+ GPIO_PINRANGE(89, 96, 49),
+ GPIO_PINRANGE(97, 97, 34),
+ GPIO_PINRANGE(102, 119, 83),
+ GPIO_PINRANGE(120, 123, 79),
+ GPIO_PINRANGE(124, 135, 115),
+ GPIO_PINRANGE(137, 142, 158),
+ GPIO_PINRANGE(154, 163, 24),
+ GPIO_PINRANGE(164, 176, 215),
+ GPIO_PINRANGE(177, 189, 127),
+ GPIO_PINRANGE(190, 191, 178),
+};
+
+static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset,
+ unsigned int reg_type_offset)
+{
+ struct mrfld_gpio *priv = gpiochip_get_data(chip);
+ u8 reg = offset / 32;
+
+ return priv->reg_base + reg_type_offset + reg * 4;
+}
+
+static int mrfld_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ void __iomem *gplr = gpio_reg(chip, offset, GPLR);
+
+ return !!(readl(gplr) & BIT(offset % 32));
+}
+
+static void mrfld_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct mrfld_gpio *priv = gpiochip_get_data(chip);
+ void __iomem *gpsr, *gpcr;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ if (value) {
+ gpsr = gpio_reg(chip, offset, GPSR);
+ writel(BIT(offset % 32), gpsr);
+ } else {
+ gpcr = gpio_reg(chip, offset, GPCR);
+ writel(BIT(offset % 32), gpcr);
+ }
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int mrfld_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct mrfld_gpio *priv = gpiochip_get_data(chip);
+ void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ value = readl(gpdr);
+ value &= ~BIT(offset % 32);
+ writel(value, gpdr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int mrfld_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct mrfld_gpio *priv = gpiochip_get_data(chip);
+ void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
+ unsigned long flags;
+
+ mrfld_gpio_set(chip, offset, value);
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ value = readl(gpdr);
+ value |= BIT(offset % 32);
+ writel(value, gpdr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static void mrfld_irq_ack(struct irq_data *d)
+{
+ struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
+ u32 gpio = irqd_to_hwirq(d);
+ void __iomem *gisr = gpio_reg(&priv->chip, gpio, GISR);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ writel(BIT(gpio % 32), gisr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void mrfld_irq_unmask_mask(struct irq_data *d, 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;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ if (unmask)
+ value = readl(gimr) | BIT(gpio % 32);
+ else
+ value = readl(gimr) & ~BIT(gpio % 32);
+ writel(value, gimr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void mrfld_irq_mask(struct irq_data *d)
+{
+ mrfld_irq_unmask_mask(d, false);
+}
+
+static void mrfld_irq_unmask(struct irq_data *d)
+{
+ mrfld_irq_unmask_mask(d, true);
+}
+
+static int mrfld_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mrfld_gpio *priv = gpiochip_get_data(gc);
+ u32 gpio = irqd_to_hwirq(d);
+ void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER);
+ void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER);
+ void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR);
+ void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ value = readl(grer) | BIT(gpio % 32);
+ else
+ value = readl(grer) & ~BIT(gpio % 32);
+ writel(value, grer);
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ value = readl(gfer) | BIT(gpio % 32);
+ else
+ value = readl(gfer) & ~BIT(gpio % 32);
+ writel(value, gfer);
+
+ /*
+ * To prevent glitches from triggering an unintended level interrupt,
+ * configure GLPR register first and then configure GITR.
+ */
+ if (type & IRQ_TYPE_LEVEL_LOW)
+ value = readl(glpr) | BIT(gpio % 32);
+ else
+ value = readl(glpr) & ~BIT(gpio % 32);
+ writel(value, glpr);
+
+ if (type & IRQ_TYPE_LEVEL_MASK) {
+ value = readl(gitr) | BIT(gpio % 32);
+ writel(value, gitr);
+
+ irq_set_handler_locked(d, handle_level_irq);
+ } else if (type & IRQ_TYPE_EDGE_BOTH) {
+ value = readl(gitr) & ~BIT(gpio % 32);
+ writel(value, gitr);
+
+ irq_set_handler_locked(d, handle_edge_irq);
+ }
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mrfld_gpio *priv = gpiochip_get_data(gc);
+ u32 gpio = irqd_to_hwirq(d);
+ void __iomem *gwmr = gpio_reg(&priv->chip, gpio, GWMR);
+ void __iomem *gwsr = gpio_reg(&priv->chip, gpio, GWSR);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&priv->lock, flags);
+
+ /* Clear the existing wake status */
+ writel(BIT(gpio % 32), gwsr);
+
+ if (on)
+ value = readl(gwmr) | BIT(gpio % 32);
+ else
+ value = readl(gwmr) & ~BIT(gpio % 32);
+ writel(value, gwmr);
+
+ raw_spin_unlock_irqrestore(&priv->lock, flags);
+
+ dev_dbg(priv->dev, "%sable wake for gpio %u\n", on ? "en" : "dis", gpio);
+ return 0;
+}
+
+static 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,
+};
+
+static void mrfld_irq_handler(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct mrfld_gpio *priv = gpiochip_get_data(gc);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ unsigned long base, gpio;
+
+ chained_irq_enter(irqchip, desc);
+
+ /* Check GPIO controller to check which pin triggered the interrupt */
+ for (base = 0; base < priv->chip.ngpio; base += 32) {
+ void __iomem *gisr = gpio_reg(&priv->chip, base, GISR);
+ void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR);
+ unsigned long pending, enabled;
+
+ pending = readl(gisr);
+ enabled = readl(gimr);
+
+ /* Only interrupts that are enabled */
+ pending &= enabled;
+
+ for_each_set_bit(gpio, &pending, 32) {
+ unsigned int irq;
+
+ irq = irq_find_mapping(gc->irqdomain, base + gpio);
+ generic_handle_irq(irq);
+ }
+ }
+
+ chained_irq_exit(irqchip, desc);
+}
+
+static void mrfld_irq_init_hw(struct mrfld_gpio *priv)
+{
+ void __iomem *reg;
+ unsigned int base;
+
+ for (base = 0; base < priv->chip.ngpio; base += 32) {
+ /* Clear the rising-edge detect register */
+ reg = gpio_reg(&priv->chip, base, GRER);
+ writel(0, reg);
+ /* Clear the falling-edge detect register */
+ reg = gpio_reg(&priv->chip, base, GFER);
+ writel(0, reg);
+ }
+}
+
+static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ const struct mrfld_gpio_pinrange *range;
+ struct mrfld_gpio *priv;
+ u32 gpio_base, irq_base;
+ void __iomem *base;
+ unsigned int i;
+ int retval;
+
+ retval = pcim_enable_device(pdev);
+ if (retval)
+ return retval;
+
+ retval = pcim_iomap_regions(pdev, BIT(1) | BIT(0), pci_name(pdev));
+ if (retval) {
+ dev_err(&pdev->dev, "I/O memory mapping error\n");
+ return retval;
+ }
+
+ base = pcim_iomap_table(pdev)[1];
+
+ irq_base = readl(base);
+ gpio_base = readl(sizeof(u32) + base);
+
+ /* Release the IO mapping, since we already get the info from BAR1 */
+ pcim_iounmap_regions(pdev, BIT(1));
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "can't allocate chip data\n");
+ return -ENOMEM;
+ }
+
+ priv->dev = &pdev->dev;
+ priv->reg_base = pcim_iomap_table(pdev)[0];
+
+ priv->chip.label = dev_name(&pdev->dev);
+ priv->chip.parent = &pdev->dev;
+ priv->chip.request = gpiochip_generic_request;
+ priv->chip.free = gpiochip_generic_free;
+ priv->chip.direction_input = mrfld_gpio_direction_input;
+ priv->chip.direction_output = mrfld_gpio_direction_output;
+ priv->chip.get = mrfld_gpio_get;
+ priv->chip.set = mrfld_gpio_set;
+ priv->chip.base = gpio_base;
+ priv->chip.ngpio = MRFLD_NGPIO;
+ priv->chip.can_sleep = false;
+
+ raw_spin_lock_init(&priv->lock);
+
+ pci_set_drvdata(pdev, priv);
+ retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
+ if (retval) {
+ dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
+ return retval;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
+ range = &mrfld_gpio_ranges[i];
+ retval = gpiochip_add_pin_range(&priv->chip,
+ "pinctrl-merrifield",
+ range->gpio_base,
+ range->pin_base,
+ range->npins);
+ if (retval) {
+ dev_err(&pdev->dev, "failed to add GPIO pin range\n");
+ return retval;
+ }
+ }
+
+ retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base,
+ handle_simple_irq, IRQ_TYPE_NONE);
+ if (retval) {
+ dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n");
+ return retval;
+ }
+
+ mrfld_irq_init_hw(priv);
+
+ gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq,
+ mrfld_irq_handler);
+
+ return 0;
+}
+
+static const struct pci_device_id mrfld_gpio_ids[] = {
+ { PCI_VDEVICE(INTEL, 0x1199) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, mrfld_gpio_ids);
+
+static struct pci_driver mrfld_gpio_driver = {
+ .name = "gpio-merrifield",
+ .id_table = mrfld_gpio_ids,
+ .probe = mrfld_gpio_probe,
+};
+
+module_pci_driver(mrfld_gpio_driver);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Merrifield SoC GPIO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c
index 6c1cb3b8c02c..6ec144baeb11 100644
--- a/drivers/gpio/gpio-mmio.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -61,6 +61,8 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
static void bgpio_write8(void __iomem *reg, unsigned long data)
{
@@ -569,6 +571,41 @@ static void __iomem *bgpio_map(struct platform_device *pdev,
return devm_ioremap_resource(&pdev->dev, r);
}
+#ifdef CONFIG_OF
+static const struct of_device_id bgpio_of_match[] = {
+ { .compatible = "wd,mbl-gpio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bgpio_of_match);
+
+static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev,
+ unsigned long *flags)
+{
+ struct bgpio_pdata *pdata;
+
+ if (!of_match_device(bgpio_of_match, &pdev->dev))
+ return NULL;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(struct bgpio_pdata),
+ GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->base = -1;
+
+ if (of_property_read_bool(pdev->dev.of_node, "no-output"))
+ *flags |= BGPIOF_NO_OUTPUT;
+
+ return pdata;
+}
+#else
+static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev,
+ unsigned long *flags)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF */
+
static int bgpio_pdev_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -579,10 +616,19 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
void __iomem *dirout;
void __iomem *dirin;
unsigned long sz;
- unsigned long flags = pdev->id_entry->driver_data;
+ unsigned long flags = 0;
int err;
struct gpio_chip *gc;
- struct bgpio_pdata *pdata = dev_get_platdata(dev);
+ struct bgpio_pdata *pdata;
+
+ pdata = bgpio_parse_dt(pdev, &flags);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+
+ if (!pdata) {
+ pdata = dev_get_platdata(dev);
+ flags = pdev->id_entry->driver_data;
+ }
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
if (!r)
@@ -646,6 +692,7 @@ MODULE_DEVICE_TABLE(platform, bgpio_id_table);
static struct platform_driver bgpio_driver = {
.driver = {
.name = "basic-mmio-gpio",
+ .of_match_table = of_match_ptr(bgpio_of_match),
},
.id_table = bgpio_id_table,
.probe = bgpio_pdev_probe,
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
index e248707ca39e..839474430229 100644
--- a/drivers/gpio/gpio-palmas.c
+++ b/drivers/gpio/gpio-palmas.c
@@ -208,7 +208,6 @@ static int palmas_gpio_probe(struct platform_device *pdev)
static struct platform_driver palmas_gpio_driver = {
.driver.name = "palmas-gpio",
- .driver.owner = THIS_MODULE,
.driver.of_match_table = of_palmas_gpio_match,
.probe = palmas_gpio_probe,
};
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 5e3be32ebb8d..02f2a5621bb0 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -44,7 +44,7 @@
#define PCA_GPIO_MASK 0x00FF
#define PCA_INT 0x0100
-#define PCA_PCAL 0x0200
+#define PCA_PCAL 0x0200
#define PCA953X_TYPE 0x1000
#define PCA957X_TYPE 0x2000
#define PCA_TYPE_MASK 0xF000
@@ -67,6 +67,8 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
{ "pca9698", 40 | PCA953X_TYPE, },
+ { "pcal9555a", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
+
{ "max7310", 8 | PCA953X_TYPE, },
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
{ "max7313", 16 | PCA953X_TYPE | PCA_INT, },
@@ -90,7 +92,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
#define MAX_BANK 5
#define BANK_SZ 8
-#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
+#define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
struct pca953x_chip {
unsigned gpio_start;
@@ -135,7 +137,7 @@ static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
int off)
{
- int ret = 0;
+ int ret;
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
int offset = off / BANK_SZ;
@@ -163,10 +165,13 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
NBANK(chip), val);
} else {
switch (chip->chip_type) {
- case PCA953X_TYPE:
- ret = i2c_smbus_write_word_data(chip->client,
- reg << 1, cpu_to_le16(get_unaligned((u16 *)val)));
+ case PCA953X_TYPE: {
+ __le16 word = cpu_to_le16(get_unaligned((u16 *)val));
+
+ ret = i2c_smbus_write_word_data(chip->client, reg << 1,
+ (__force u16)word);
break;
+ }
case PCA957X_TYPE:
ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
val[0]);
@@ -235,7 +240,6 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
goto exit;
chip->reg_direction[off / BANK_SZ] = reg_val;
- ret = 0;
exit:
mutex_unlock(&chip->i2c_lock);
return ret;
@@ -286,7 +290,6 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
goto exit;
chip->reg_direction[off / BANK_SZ] = reg_val;
- ret = 0;
exit:
mutex_unlock(&chip->i2c_lock);
return ret;
@@ -351,7 +354,6 @@ exit:
mutex_unlock(&chip->i2c_lock);
}
-
static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits)
{
@@ -820,7 +822,7 @@ static int pca953x_remove(struct i2c_client *client)
{
struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev);
struct pca953x_chip *chip = i2c_get_clientdata(client);
- int ret = 0;
+ int ret;
if (pdata && pdata->teardown) {
ret = pdata->teardown(client, chip->gpio_chip.base,
@@ -861,6 +863,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "ti,pca9536", .data = OF_953X( 4, 0), },
{ .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 169c09aa33c8..d168410e2338 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -440,6 +440,14 @@ static int pcf857x_remove(struct i2c_client *client)
return status;
}
+static void pcf857x_shutdown(struct i2c_client *client)
+{
+ struct pcf857x *gpio = i2c_get_clientdata(client);
+
+ /* Drive all the I/O lines high */
+ gpio->write(gpio->client, BIT(gpio->chip.ngpio) - 1);
+}
+
static struct i2c_driver pcf857x_driver = {
.driver = {
.name = "pcf857x",
@@ -447,6 +455,7 @@ static struct i2c_driver pcf857x_driver = {
},
.probe = pcf857x_probe,
.remove = pcf857x_remove,
+ .shutdown = pcf857x_shutdown,
.id_table = pcf857x_id,
};
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 681c93fb9e70..b96e0b466f74 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -335,6 +335,9 @@ static const struct of_device_id gpio_rcar_of_table[] = {
.compatible = "renesas,gpio-r8a7791",
.data = &gpio_rcar_info_gen2,
}, {
+ .compatible = "renesas,gpio-r8a7792",
+ .data = &gpio_rcar_info_gen2,
+ }, {
.compatible = "renesas,gpio-r8a7793",
.data = &gpio_rcar_info_gen2,
}, {
diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c
index ec945b90f54d..cbf0f9e6465b 100644
--- a/drivers/gpio/gpio-rdc321x.c
+++ b/drivers/gpio/gpio-rdc321x.c
@@ -200,7 +200,6 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
static struct platform_driver rdc321x_gpio_driver = {
.driver.name = "rdc321x-gpio",
- .driver.owner = THIS_MODULE,
.probe = rdc321x_gpio_probe,
};
diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c
index a03b38ee2e02..b96990c262a1 100644
--- a/drivers/gpio/gpio-sch311x.c
+++ b/drivers/gpio/gpio-sch311x.c
@@ -296,7 +296,6 @@ static int sch311x_gpio_remove(struct platform_device *pdev)
static struct platform_driver sch311x_gpio_driver = {
.driver.name = DRV_NAME,
- .driver.owner = THIS_MODULE,
.probe = sch311x_gpio_probe,
.remove = sch311x_gpio_remove,
};
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 6f7af28b8966..f675132de10e 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -68,6 +68,22 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
stmpe_reg_write(stmpe, reg, mask);
}
+static int stmpe_gpio_get_direction(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
+ u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+ u8 mask = 1 << (offset % 8);
+ int ret;
+
+ ret = stmpe_reg_read(stmpe, reg);
+ if (ret < 0)
+ return ret;
+
+ return !(ret & mask);
+}
+
static int stmpe_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
@@ -106,6 +122,7 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
static struct gpio_chip template_chip = {
.label = "stmpe",
.owner = THIS_MODULE,
+ .get_direction = stmpe_gpio_get_direction,
.direction_input = stmpe_gpio_direction_input,
.get = stmpe_gpio_get,
.direction_output = stmpe_gpio_direction_output,
@@ -416,7 +433,6 @@ static struct platform_driver stmpe_gpio_driver = {
.driver = {
.suppress_bind_attrs = true,
.name = "stmpe-gpio",
- .owner = THIS_MODULE,
},
.probe = stmpe_gpio_probe,
};
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index 24b6d643ecdb..537cec7583fc 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -129,7 +129,7 @@ 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,clps711x-syscon1",
+ .compatible = "cirrus,ep7209-syscon1",
.flags = GPIO_SYSCON_FEAT_IN,
.bit_count = 3,
.dat_bit_offset = 0x40 * 8 + 8,
@@ -168,7 +168,7 @@ static const struct syscon_gpio_data keystone_dsp_gpio = {
static const struct of_device_id syscon_gpio_ids[] = {
{
- .compatible = "cirrus,clps711x-mctrl-gpio",
+ .compatible = "cirrus,ep7209-mctrl-gpio",
.data = &clps711x_mctrl_gpio,
},
{
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 2e35ed3abbcf..8b3659352e49 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -343,7 +343,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
static struct platform_driver tc3589x_gpio_driver = {
.driver.name = "tc3589x-gpio",
- .driver.owner = THIS_MODULE,
.probe = tc3589x_gpio_probe,
};
diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c
index 0eaeac8de9de..1c09a19ae10c 100644
--- a/drivers/gpio/gpio-tps65218.c
+++ b/drivers/gpio/gpio-tps65218.c
@@ -230,6 +230,12 @@ static const struct of_device_id tps65218_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, tps65218_dt_match);
+static const struct platform_device_id tps65218_gpio_id_table[] = {
+ { "tps65218-gpio", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table);
+
static struct platform_driver tps65218_gpio_driver = {
.driver = {
.name = "tps65218-gpio",
@@ -237,6 +243,7 @@ static struct platform_driver tps65218_gpio_driver = {
},
.probe = tps65218_gpio_probe,
.remove = tps65218_gpio_remove,
+ .id_table = tps65218_gpio_id_table,
};
module_platform_driver(tps65218_gpio_driver);
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index 6b15e68a314f..042b9a20781a 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -131,7 +131,6 @@ static int tps6586x_gpio_probe(struct platform_device *pdev)
static struct platform_driver tps6586x_gpio_driver = {
.driver.name = "tps6586x-gpio",
- .driver.owner = THIS_MODULE,
.probe = tps6586x_gpio_probe,
};
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 0ae6a5a54ea8..e63d7dabf78b 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -184,7 +184,6 @@ skip_init:
static struct platform_driver tps65910_gpio_driver = {
.driver.name = "tps65910-gpio",
- .driver.owner = THIS_MODULE,
.probe = tps65910_gpio_probe,
};
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index dec47aafd5cd..e6d1328dddfa 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -440,7 +440,6 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
static struct platform_driver vprbrd_gpio_driver = {
.driver.name = "viperboard-gpio",
- .driver.owner = THIS_MODULE,
.probe = vprbrd_gpio_probe,
};
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index 41ec7834059a..21f97bcd0062 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -296,7 +296,6 @@ static int wm831x_gpio_probe(struct platform_device *pdev)
static struct platform_driver wm831x_gpio_driver = {
.driver.name = "wm831x-gpio",
- .driver.owner = THIS_MODULE,
.probe = wm831x_gpio_probe,
};
diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c
index 07d45a3b205a..e9765707d5c1 100644
--- a/drivers/gpio/gpio-wm8350.c
+++ b/drivers/gpio/gpio-wm8350.c
@@ -139,7 +139,6 @@ static int wm8350_gpio_probe(struct platform_device *pdev)
static struct platform_driver wm8350_gpio_driver = {
.driver.name = "wm8350-gpio",
- .driver.owner = THIS_MODULE,
.probe = wm8350_gpio_probe,
};
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index 744af388c949..2457aac8592e 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -299,7 +299,6 @@ static int wm8994_gpio_probe(struct platform_device *pdev)
static struct platform_driver wm8994_gpio_driver = {
.driver.name = "wm8994-gpio",
- .driver.owner = THIS_MODULE,
.probe = wm8994_gpio_probe,
};
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index d0fbb7f99523..14b2a62338ea 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -133,6 +133,53 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
}
/**
+ * xgpio_set_multiple - Write the specified signals of the GPIO device.
+ * @gc: Pointer to gpio_chip device structure.
+ * @mask: Mask of the GPIOS to modify.
+ * @bits: Value to be wrote on each GPIO
+ *
+ * This function writes the specified values into the specified signals of the
+ * GPIO devices.
+ */
+static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ unsigned long flags;
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct xgpio_instance *chip = gpiochip_get_data(gc);
+ int index = xgpio_index(chip, 0);
+ int offset, i;
+
+ spin_lock_irqsave(&chip->gpio_lock[index], flags);
+
+ /* Write to GPIO signals */
+ for (i = 0; i < gc->ngpio; i++) {
+ if (*mask == 0)
+ break;
+ if (index != xgpio_index(chip, i)) {
+ xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_regoffset(chip, i),
+ chip->gpio_state[index]);
+ spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+ index = xgpio_index(chip, i);
+ spin_lock_irqsave(&chip->gpio_lock[index], flags);
+ }
+ if (__test_and_clear_bit(i, mask)) {
+ offset = xgpio_offset(chip, i);
+ if (test_bit(i, bits))
+ chip->gpio_state[index] |= BIT(offset);
+ else
+ chip->gpio_state[index] &= ~BIT(offset);
+ }
+ }
+
+ xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_regoffset(chip, i), chip->gpio_state[index]);
+
+ spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+}
+
+/**
* xgpio_dir_in - Set the direction of the specified GPIO signal as input.
* @gc: Pointer to gpio_chip device structure.
* @gpio: GPIO signal number.
@@ -306,6 +353,7 @@ static int xgpio_probe(struct platform_device *pdev)
chip->mmchip.gc.direction_output = xgpio_dir_out;
chip->mmchip.gc.get = xgpio_get;
chip->mmchip.gc.set = xgpio_set;
+ chip->mmchip.gc.set_multiple = xgpio_set_multiple;
chip->mmchip.save_regs = xgpio_save_regs;
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index 1a33a19d95b9..4620d050e5a8 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -19,6 +19,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/acpi.h>
/*
* XLP GPIO has multiple 32 bit registers for each feature where each register
@@ -299,7 +300,6 @@ static int xlp_gpio_probe(struct platform_device *pdev)
struct gpio_chip *gc;
struct resource *iores;
struct xlp_gpio_priv *priv;
- const struct of_device_id *of_id;
void __iomem *gpio_base;
int irq_base, irq, err;
int ngpio;
@@ -321,13 +321,26 @@ static int xlp_gpio_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev);
- if (!of_id) {
- dev_err(&pdev->dev, "Failed to get soc type!\n");
- return -ENODEV;
- }
+ if (pdev->dev.of_node) {
+ const struct of_device_id *of_id;
- soc_type = (uintptr_t) of_id->data;
+ of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev);
+ if (!of_id) {
+ dev_err(&pdev->dev, "Unable to match OF ID\n");
+ return -ENODEV;
+ }
+ soc_type = (uintptr_t) of_id->data;
+ } else {
+ const struct acpi_device_id *acpi_id;
+
+ acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
+ &pdev->dev);
+ if (!acpi_id || !acpi_id->driver_data) {
+ dev_err(&pdev->dev, "Unable to match ACPI ID\n");
+ return -ENODEV;
+ }
+ soc_type = (uintptr_t) acpi_id->driver_data;
+ }
switch (soc_type) {
case XLP_GPIO_VARIANT_XLP832:
@@ -388,14 +401,16 @@ static int xlp_gpio_probe(struct platform_device *pdev)
gc->get = xlp_gpio_get;
spin_lock_init(&priv->lock);
- /* XLP has fixed IRQ range for GPIO interrupts */
- if (soc_type == GPIO_VARIANT_VULCAN)
- irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0);
- else
+
+ /* XLP(MIPS) has fixed range for GPIO IRQs, Vulcan(ARM64) does not */
+ if (soc_type != GPIO_VARIANT_VULCAN) {
irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
- if (irq_base < 0) {
- dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
- return irq_base;
+ if (irq_base < 0) {
+ dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
+ return irq_base;
+ }
+ } else {
+ irq_base = 0;
}
err = gpiochip_add_data(gc, priv);
@@ -423,10 +438,19 @@ out_free_desc:
return err;
}
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xlp_gpio_acpi_match[] = {
+ { "BRCM9006", GPIO_VARIANT_VULCAN },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match);
+#endif
+
static struct platform_driver xlp_gpio_driver = {
.driver = {
.name = "xlp-gpio",
.of_match_table = xlp_gpio_of_ids,
+ .acpi_match_table = ACPI_PTR(xlp_gpio_acpi_match),
},
.probe = xlp_gpio_probe,
};
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 2dc52585e3f2..af514618d7fb 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -836,6 +836,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
}
acpi_gpiochip_request_regions(acpi_gpio);
+ acpi_walk_dep_device_list(handle);
}
void acpi_gpiochip_remove(struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 4aabddb38b59..75e7b3919ea7 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -27,38 +27,30 @@
#include "gpiolib.h"
-/* Private data structure for of_gpiochip_find_and_xlate */
-struct gg_data {
- enum of_gpio_flags *flags;
- struct of_phandle_args gpiospec;
+static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
+{
+ return chip->gpiodev->dev.of_node == data;
+}
- struct gpio_desc *out_gpio;
-};
+static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
+{
+ return gpiochip_find(np, of_gpiochip_match_node);
+}
-/* Private function for resolving node pointer to gpio_chip */
-static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
+static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
+ struct of_phandle_args *gpiospec,
+ enum of_gpio_flags *flags)
{
- struct gg_data *gg_data = data;
int ret;
- if ((gc->of_node != gg_data->gpiospec.np) ||
- (gc->of_gpio_n_cells != gg_data->gpiospec.args_count) ||
- (!gc->of_xlate))
- return false;
-
- ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
- if (ret < 0) {
- /* We've found a gpio chip, but the translation failed.
- * Store translation error in out_gpio.
- * Return false to keep looking, as more than one gpio chip
- * could be registered per of-node.
- */
- gg_data->out_gpio = ERR_PTR(ret);
- return false;
- }
-
- gg_data->out_gpio = gpiochip_get_desc(gc, ret);
- return true;
+ if (chip->of_gpio_n_cells != gpiospec->args_count)
+ return ERR_PTR(-EINVAL);
+
+ ret = chip->of_xlate(chip, gpiospec, flags);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ return gpiochip_get_desc(chip, ret);
}
/**
@@ -75,34 +67,37 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
const char *propname, int index, enum of_gpio_flags *flags)
{
- /* Return -EPROBE_DEFER to support probe() functions to be called
- * later when the GPIO actually becomes available
- */
- struct gg_data gg_data = {
- .flags = flags,
- .out_gpio = ERR_PTR(-EPROBE_DEFER)
- };
+ struct of_phandle_args gpiospec;
+ struct gpio_chip *chip;
+ struct gpio_desc *desc;
int ret;
- /* .of_xlate might decide to not fill in the flags, so clear it. */
- if (flags)
- *flags = 0;
-
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
- &gg_data.gpiospec);
+ &gpiospec);
if (ret) {
pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n",
__func__, propname, np->full_name, index);
return ERR_PTR(ret);
}
- gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
+ chip = of_find_gpiochip_by_node(gpiospec.np);
+ if (!chip) {
+ desc = ERR_PTR(-EPROBE_DEFER);
+ goto out;
+ }
+
+ desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags);
+ if (IS_ERR(desc))
+ goto out;
- of_node_put(gg_data.gpiospec.np);
pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n",
__func__, propname, np->full_name, index,
- PTR_ERR_OR_ZERO(gg_data.out_gpio));
- return gg_data.out_gpio;
+ PTR_ERR_OR_ZERO(desc));
+
+out:
+ of_node_put(gpiospec.np);
+
+ return desc;
}
int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
@@ -122,6 +117,7 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);
/**
* of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API
* @np: device node to get GPIO from
+ * @chip: GPIO chip whose hog is parsed
* @name: GPIO line name
* @lflags: gpio_lookup_flags - returned from of_find_gpio() or
* of_parse_own_gpio()
@@ -131,19 +127,19 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);
* value on the error condition.
*/
static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
+ struct gpio_chip *chip,
const char **name,
enum gpio_lookup_flags *lflags,
enum gpiod_flags *dflags)
{
struct device_node *chip_np;
enum of_gpio_flags xlate_flags;
- struct gg_data gg_data = {
- .flags = &xlate_flags,
- };
+ struct of_phandle_args gpiospec;
+ struct gpio_desc *desc;
u32 tmp;
- int i, ret;
+ int ret;
- chip_np = np->parent;
+ chip_np = chip->of_node;
if (!chip_np)
return ERR_PTR(-EINVAL);
@@ -155,25 +151,16 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
if (ret)
return ERR_PTR(ret);
- if (tmp > MAX_PHANDLE_ARGS)
- return ERR_PTR(-EINVAL);
+ gpiospec.np = chip_np;
+ gpiospec.args_count = tmp;
- gg_data.gpiospec.args_count = tmp;
- gg_data.gpiospec.np = chip_np;
- for (i = 0; i < tmp; i++) {
- ret = of_property_read_u32_index(np, "gpios", i,
- &gg_data.gpiospec.args[i]);
- if (ret)
- return ERR_PTR(ret);
- }
+ ret = of_property_read_u32_array(np, "gpios", gpiospec.args, tmp);
+ if (ret)
+ return ERR_PTR(ret);
- gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
- if (!gg_data.out_gpio) {
- if (np->parent == np)
- return ERR_PTR(-ENXIO);
- else
- return ERR_PTR(-EINVAL);
- }
+ desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, &xlate_flags);
+ if (IS_ERR(desc))
+ return desc;
if (xlate_flags & OF_GPIO_ACTIVE_LOW)
*lflags |= GPIO_ACTIVE_LOW;
@@ -186,14 +173,14 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
*dflags |= GPIOD_OUT_HIGH;
else {
pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n",
- desc_to_gpio(gg_data.out_gpio), np->name);
+ desc_to_gpio(desc), np->name);
return ERR_PTR(-EINVAL);
}
if (name && of_property_read_string(np, "line-name", name))
*name = np->name;
- return gg_data.out_gpio;
+ return desc;
}
/**
@@ -262,7 +249,7 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
if (!of_property_read_bool(np, "gpio-hog"))
continue;
- desc = of_parse_own_gpio(np, &name, &lflags, &dflags);
+ desc = of_parse_own_gpio(np, chip, &name, &lflags, &dflags);
if (IS_ERR(desc))
continue;
@@ -410,6 +397,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
break;
pctldev = of_pinctrl_get(pinspec.np);
+ of_node_put(pinspec.np);
if (!pctldev)
return -EPROBE_DEFER;
@@ -487,6 +475,9 @@ int of_gpiochip_add(struct gpio_chip *chip)
chip->of_xlate = of_gpio_simple_xlate;
}
+ if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
+ return -EINVAL;
+
status = of_gpiochip_add_pin_range(chip);
if (status)
return status;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index be74bd370f1f..53ff25ac66d8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -16,11 +16,14 @@
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/idr.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/compat.h>
+#include <linux/anon_inodes.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include <linux/timekeeping.h>
#include <uapi/linux/gpio.h>
#include "gpiolib.h"
@@ -310,6 +313,497 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
return 0;
}
+/*
+ * GPIO line handle management
+ */
+
+/**
+ * struct linehandle_state - contains the state of a userspace handle
+ * @gdev: the GPIO device the handle pertains to
+ * @label: consumer label used to tag descriptors
+ * @descs: the GPIO descriptors held by this handle
+ * @numdescs: the number of descriptors held in the descs array
+ */
+struct linehandle_state {
+ struct gpio_device *gdev;
+ const char *label;
+ struct gpio_desc *descs[GPIOHANDLES_MAX];
+ u32 numdescs;
+};
+
+static long linehandle_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ struct linehandle_state *lh = filep->private_data;
+ void __user *ip = (void __user *)arg;
+ struct gpiohandle_data ghd;
+ int i;
+
+ if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
+ int val;
+
+ /* TODO: check if descriptors are really input */
+ for (i = 0; i < lh->numdescs; i++) {
+ val = gpiod_get_value_cansleep(lh->descs[i]);
+ if (val < 0)
+ return val;
+ ghd.values[i] = val;
+ }
+
+ if (copy_to_user(ip, &ghd, sizeof(ghd)))
+ return -EFAULT;
+
+ return 0;
+ } else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) {
+ int vals[GPIOHANDLES_MAX];
+
+ /* TODO: check if descriptors are really output */
+ if (copy_from_user(&ghd, ip, sizeof(ghd)))
+ return -EFAULT;
+
+ /* Clamp all values to [0,1] */
+ for (i = 0; i < lh->numdescs; i++)
+ vals[i] = !!ghd.values[i];
+
+ /* Reuse the array setting function */
+ gpiod_set_array_value_complex(false,
+ true,
+ lh->numdescs,
+ lh->descs,
+ vals);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+#ifdef CONFIG_COMPAT
+static long linehandle_ioctl_compat(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ return linehandle_ioctl(filep, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static int linehandle_release(struct inode *inode, struct file *filep)
+{
+ struct linehandle_state *lh = filep->private_data;
+ struct gpio_device *gdev = lh->gdev;
+ int i;
+
+ for (i = 0; i < lh->numdescs; i++)
+ gpiod_free(lh->descs[i]);
+ kfree(lh->label);
+ kfree(lh);
+ put_device(&gdev->dev);
+ return 0;
+}
+
+static const struct file_operations linehandle_fileops = {
+ .release = linehandle_release,
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+ .unlocked_ioctl = linehandle_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = linehandle_ioctl_compat,
+#endif
+};
+
+static int linehandle_create(struct gpio_device *gdev, void __user *ip)
+{
+ struct gpiohandle_request handlereq;
+ struct linehandle_state *lh;
+ int fd, i, ret;
+
+ if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
+ return -EFAULT;
+ if ((handlereq.lines == 0) || (handlereq.lines > GPIOHANDLES_MAX))
+ return -EINVAL;
+
+ lh = kzalloc(sizeof(*lh), GFP_KERNEL);
+ if (!lh)
+ return -ENOMEM;
+ lh->gdev = gdev;
+ get_device(&gdev->dev);
+
+ /* Make sure this is terminated */
+ handlereq.consumer_label[sizeof(handlereq.consumer_label)-1] = '\0';
+ if (strlen(handlereq.consumer_label)) {
+ lh->label = kstrdup(handlereq.consumer_label,
+ GFP_KERNEL);
+ if (!lh->label) {
+ ret = -ENOMEM;
+ goto out_free_lh;
+ }
+ }
+
+ /* Request each GPIO */
+ for (i = 0; i < handlereq.lines; i++) {
+ u32 offset = handlereq.lineoffsets[i];
+ u32 lflags = handlereq.flags;
+ struct gpio_desc *desc;
+
+ desc = &gdev->descs[offset];
+ ret = gpiod_request(desc, lh->label);
+ if (ret)
+ goto out_free_descs;
+ lh->descs[i] = desc;
+
+ if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+ if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN)
+ set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+ if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
+ set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+ /*
+ * Lines have to be requested explicitly for input
+ * or output, else the line will be treated "as is".
+ */
+ if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
+ int val = !!handlereq.default_values[i];
+
+ ret = gpiod_direction_output(desc, val);
+ if (ret)
+ goto out_free_descs;
+ } else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
+ ret = gpiod_direction_input(desc);
+ if (ret)
+ goto out_free_descs;
+ }
+ dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
+ offset);
+ }
+ /* Let i point at the last handle */
+ i--;
+ lh->numdescs = handlereq.lines;
+
+ fd = anon_inode_getfd("gpio-linehandle",
+ &linehandle_fileops,
+ lh,
+ O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ ret = fd;
+ goto out_free_descs;
+ }
+
+ handlereq.fd = fd;
+ if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
+ ret = -EFAULT;
+ goto out_free_descs;
+ }
+
+ dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
+ lh->numdescs);
+
+ return 0;
+
+out_free_descs:
+ for (; i >= 0; i--)
+ gpiod_free(lh->descs[i]);
+ kfree(lh->label);
+out_free_lh:
+ kfree(lh);
+ put_device(&gdev->dev);
+ return ret;
+}
+
+/*
+ * GPIO line event management
+ */
+
+/**
+ * struct lineevent_state - contains the state of a userspace event
+ * @gdev: the GPIO device the event pertains to
+ * @label: consumer label used to tag descriptors
+ * @desc: the GPIO descriptor held by this event
+ * @eflags: the event flags this line was requested with
+ * @irq: the interrupt that trigger in response to events on this GPIO
+ * @wait: wait queue that handles blocking reads of events
+ * @events: KFIFO for the GPIO events
+ * @read_lock: mutex lock to protect reads from colliding with adding
+ * new events to the FIFO
+ */
+struct lineevent_state {
+ struct gpio_device *gdev;
+ const char *label;
+ struct gpio_desc *desc;
+ u32 eflags;
+ int irq;
+ wait_queue_head_t wait;
+ DECLARE_KFIFO(events, struct gpioevent_data, 16);
+ struct mutex read_lock;
+};
+
+static unsigned int lineevent_poll(struct file *filep,
+ struct poll_table_struct *wait)
+{
+ struct lineevent_state *le = filep->private_data;
+ unsigned int events = 0;
+
+ poll_wait(filep, &le->wait, wait);
+
+ if (!kfifo_is_empty(&le->events))
+ events = POLLIN | POLLRDNORM;
+
+ return events;
+}
+
+
+static ssize_t lineevent_read(struct file *filep,
+ char __user *buf,
+ size_t count,
+ loff_t *f_ps)
+{
+ struct lineevent_state *le = filep->private_data;
+ unsigned int copied;
+ int ret;
+
+ if (count < sizeof(struct gpioevent_data))
+ return -EINVAL;
+
+ do {
+ if (kfifo_is_empty(&le->events)) {
+ if (filep->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(le->wait,
+ !kfifo_is_empty(&le->events));
+ if (ret)
+ return ret;
+ }
+
+ if (mutex_lock_interruptible(&le->read_lock))
+ return -ERESTARTSYS;
+ ret = kfifo_to_user(&le->events, buf, count, &copied);
+ mutex_unlock(&le->read_lock);
+
+ if (ret)
+ return ret;
+
+ /*
+ * If we couldn't read anything from the fifo (a different
+ * thread might have been faster) we either return -EAGAIN if
+ * the file descriptor is non-blocking, otherwise we go back to
+ * sleep and wait for more data to arrive.
+ */
+ if (copied == 0 && (filep->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ } while (copied == 0);
+
+ return copied;
+}
+
+static int lineevent_release(struct inode *inode, struct file *filep)
+{
+ struct lineevent_state *le = filep->private_data;
+ struct gpio_device *gdev = le->gdev;
+
+ free_irq(le->irq, le);
+ gpiod_free(le->desc);
+ kfree(le->label);
+ kfree(le);
+ put_device(&gdev->dev);
+ return 0;
+}
+
+static long lineevent_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ struct lineevent_state *le = filep->private_data;
+ void __user *ip = (void __user *)arg;
+ struct gpiohandle_data ghd;
+
+ /*
+ * We can get the value for an event line but not set it,
+ * because it is input by definition.
+ */
+ if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
+ int val;
+
+ val = gpiod_get_value_cansleep(le->desc);
+ if (val < 0)
+ return val;
+ ghd.values[0] = val;
+
+ if (copy_to_user(ip, &ghd, sizeof(ghd)))
+ return -EFAULT;
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
+#ifdef CONFIG_COMPAT
+static long lineevent_ioctl_compat(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ return lineevent_ioctl(filep, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static const struct file_operations lineevent_fileops = {
+ .release = lineevent_release,
+ .read = lineevent_read,
+ .poll = lineevent_poll,
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+ .unlocked_ioctl = lineevent_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lineevent_ioctl_compat,
+#endif
+};
+
+static irqreturn_t lineevent_irq_thread(int irq, void *p)
+{
+ struct lineevent_state *le = p;
+ struct gpioevent_data ge;
+ int ret;
+
+ ge.timestamp = ktime_get_real_ns();
+
+ if (le->eflags & GPIOEVENT_REQUEST_BOTH_EDGES) {
+ int level = gpiod_get_value_cansleep(le->desc);
+
+ if (level)
+ /* Emit low-to-high event */
+ ge.id = GPIOEVENT_EVENT_RISING_EDGE;
+ else
+ /* Emit high-to-low event */
+ ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
+ } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
+ /* Emit low-to-high event */
+ ge.id = GPIOEVENT_EVENT_RISING_EDGE;
+ } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
+ /* Emit high-to-low event */
+ ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
+ } else {
+ return IRQ_NONE;
+ }
+
+ ret = kfifo_put(&le->events, ge);
+ if (ret != 0)
+ wake_up_poll(&le->wait, POLLIN);
+
+ return IRQ_HANDLED;
+}
+
+static int lineevent_create(struct gpio_device *gdev, void __user *ip)
+{
+ struct gpioevent_request eventreq;
+ struct lineevent_state *le;
+ struct gpio_desc *desc;
+ u32 offset;
+ u32 lflags;
+ u32 eflags;
+ int fd;
+ int ret;
+ int irqflags = 0;
+
+ if (copy_from_user(&eventreq, ip, sizeof(eventreq)))
+ return -EFAULT;
+
+ le = kzalloc(sizeof(*le), GFP_KERNEL);
+ if (!le)
+ return -ENOMEM;
+ le->gdev = gdev;
+ get_device(&gdev->dev);
+
+ /* Make sure this is terminated */
+ eventreq.consumer_label[sizeof(eventreq.consumer_label)-1] = '\0';
+ if (strlen(eventreq.consumer_label)) {
+ le->label = kstrdup(eventreq.consumer_label,
+ GFP_KERNEL);
+ if (!le->label) {
+ ret = -ENOMEM;
+ goto out_free_le;
+ }
+ }
+
+ offset = eventreq.lineoffset;
+ lflags = eventreq.handleflags;
+ eflags = eventreq.eventflags;
+
+ /* This is just wrong: we don't look for events on output lines */
+ if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
+ ret = -EINVAL;
+ goto out_free_label;
+ }
+
+ desc = &gdev->descs[offset];
+ ret = gpiod_request(desc, le->label);
+ if (ret)
+ goto out_free_desc;
+ le->desc = desc;
+ le->eflags = eflags;
+
+ if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+ if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN)
+ set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+ if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
+ set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+ ret = gpiod_direction_input(desc);
+ if (ret)
+ goto out_free_desc;
+
+ le->irq = gpiod_to_irq(desc);
+ if (le->irq <= 0) {
+ ret = -ENODEV;
+ goto out_free_desc;
+ }
+
+ if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
+ irqflags |= IRQF_TRIGGER_RISING;
+ if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
+ irqflags |= IRQF_TRIGGER_FALLING;
+ irqflags |= IRQF_ONESHOT;
+ irqflags |= IRQF_SHARED;
+
+ INIT_KFIFO(le->events);
+ init_waitqueue_head(&le->wait);
+ mutex_init(&le->read_lock);
+
+ /* Request a thread to read the events */
+ ret = request_threaded_irq(le->irq,
+ NULL,
+ lineevent_irq_thread,
+ irqflags,
+ le->label,
+ le);
+ if (ret)
+ goto out_free_desc;
+
+ fd = anon_inode_getfd("gpio-event",
+ &lineevent_fileops,
+ le,
+ O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ ret = fd;
+ goto out_free_irq;
+ }
+
+ eventreq.fd = fd;
+ if (copy_to_user(ip, &eventreq, sizeof(eventreq))) {
+ ret = -EFAULT;
+ goto out_free_irq;
+ }
+
+ return 0;
+
+out_free_irq:
+ free_irq(le->irq, le);
+out_free_desc:
+ gpiod_free(le->desc);
+out_free_label:
+ kfree(le->label);
+out_free_le:
+ kfree(le);
+ put_device(&gdev->dev);
+ return ret;
+}
+
/**
* gpio_ioctl() - ioctl handler for the GPIO chardev
*/
@@ -385,6 +879,10 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
return 0;
+ } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
+ return linehandle_create(gdev, ip);
+ } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
+ return lineevent_create(gdev, ip);
}
return -EINVAL;
}
@@ -548,13 +1046,14 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
if (chip->parent) {
gdev->dev.parent = chip->parent;
gdev->dev.of_node = chip->parent->of_node;
- } else {
+ }
+
#ifdef CONFIG_OF_GPIO
/* If the gpiochip has an assigned OF node this takes precedence */
- if (chip->of_node)
- gdev->dev.of_node = chip->of_node;
+ if (chip->of_node)
+ gdev->dev.of_node = chip->of_node;
#endif
- }
+
gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);
if (gdev->id < 0) {
status = gdev->id;
@@ -2333,7 +2832,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
&of_flags);
- if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
break;
}