summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-02-22 10:00:46 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2021-02-22 10:00:46 -0800
commit882d6edfc45cd2b6e33cf973eab9a1ae1dbad5d1 (patch)
tree034ebc487adeb29cef2c546b5e0b61d70a3bc339 /drivers
parent0328b5f2ef4af8ba060e64baa928c94037e7308f (diff)
parenta8002a35935aaefcd6a42ad3289f62bab947f2ca (diff)
Merge tag 'gpio-updates-for-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski: "It's been a relatively calm release cycle and we're actually removing more code than we're adding. Summary: - new driver for the Toshiba Visconti platform - rework of interrupt handling in gpio-tegra - updates for GPIO selftests: we're now using the character device to perform the subsystem checks - support for a new rcar variant + some code refactoring - refactoring of gpio-ep93xx - SPDX License identifier has been updated in the uapi header so that userspace programs bundling it can become fully REUSE-compliant - improvements to pwm handling in gpio-mvebu - support for interrupt handling and power management for gpio-xilinx as well as some code refactoring - support for a new chip variant in gpio-pca953x - removal of drivers: zte xs & intel-mid and removal of leftovers from intel-msic - impovements to intel drivers pulled from Andy Shevchenko - improvements to the gpio-aggregator virtual GPIO driver - and several minor tweaks and fixes to code and documentation all over the place" * tag 'gpio-updates-for-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (71 commits) gpio: pcf857x: Fix missing first interrupt gpio: ep93xx: refactor base IRQ number gpio: ep93xx: refactor ep93xx_gpio_add_bank gpio: ep93xx: Fix typo s/hierarchial/hierarchical gpio: ep93xx: drop to_irq binding gpio: ep93xx: Fix wrong irq numbers in port F gpio: uapi: use the preferred SPDX license identifier gpio: gpio-xilinx: Add check if width exceeds 32 gpio: gpio-xilinx: Add support for suspend and resume gpio: gpio-xilinx: Add interrupt support gpio: gpio-xilinx: Reduce spinlock array to array gpio: gpio-xilinx: Simplify with dev_err_probe() gpio: msic: Drop driver from Makefile gpio: wcove: Split out to_ireg() helper and deduplicate the code gpio: wcove: Switch to use regmap_set_bits(), regmap_clear_bits() gpio: wcove: Get rid of error prone casting in IRQ handler gpio: intel-mid: Remove driver for deprecated platform gpio: msic: Remove driver for deprecated platform gpio: aggregator: Remove trailing comma in terminator entries gpio: aggregator: Use compound literal from the header ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig30
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/gpio-aggregator.c40
-rw-r--r--drivers/gpio/gpio-bd70528.c59
-rw-r--r--drivers/gpio/gpio-bd71828.c39
-rw-r--r--drivers/gpio/gpio-ep93xx.c28
-rw-r--r--drivers/gpio/gpio-max77620.c2
-rw-r--r--drivers/gpio/gpio-merrifield.c5
-rw-r--r--drivers/gpio/gpio-mvebu.c148
-rw-r--r--drivers/gpio/gpio-pca953x.c2
-rw-r--r--drivers/gpio/gpio-pcf857x.c2
-rw-r--r--drivers/gpio/gpio-rcar.c85
-rw-r--r--drivers/gpio/gpio-sl28cpld.c4
-rw-r--r--drivers/gpio/gpio-tegra.c263
-rw-r--r--drivers/gpio/gpio-tegra186.c2
-rw-r--r--drivers/gpio/gpio-visconti.c218
-rw-r--r--drivers/gpio/gpio-vx855.c2
-rw-r--r--drivers/gpio/gpio-wcove.c65
-rw-r--r--drivers/gpio/gpio-xilinx.c369
-rw-r--r--drivers/gpio/gpio-zx.c289
-rw-r--r--drivers/pinctrl/visconti/pinctrl-common.c23
21 files changed, 1038 insertions, 640 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f62f0b6b0bc0..e3607ec4c2e8 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -487,11 +487,11 @@ config GPIO_PXA
Say yes here to support the PXA GPIO device
config GPIO_RCAR
- tristate "Renesas R-Car GPIO"
+ tristate "Renesas R-Car and RZ/G GPIO support"
depends on ARCH_RENESAS || COMPILE_TEST
select GPIOLIB_IRQCHIP
help
- Say yes here to support GPIO on Renesas R-Car SoCs.
+ Say yes here to support GPIO on Renesas R-Car or RZ/G SoCs.
config GPIO_RDA
bool "RDA Micro GPIO controller support"
@@ -595,7 +595,7 @@ config GPIO_TB10X
select OF_GPIO
config GPIO_TEGRA
- bool "NVIDIA Tegra GPIO support"
+ tristate "NVIDIA Tegra GPIO support"
default ARCH_TEGRA
depends on ARCH_TEGRA || COMPILE_TEST
depends on OF_GPIO
@@ -648,6 +648,16 @@ config GPIO_VF610
help
Say yes here to support Vybrid vf610 GPIOs.
+config GPIO_VISCONTI
+ tristate "Toshiba Visconti GPIO support"
+ depends on ARCH_VISCONTI || COMPILE_TEST
+ depends on OF_GPIO
+ select GPIOLIB_IRQCHIP
+ select GPIO_GENERIC
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ Say yes here to support GPIO on Tohisba Visconti.
+
config GPIO_VR41XX
tristate "NEC VR4100 series General-purpose I/O Uint support"
depends on CPU_VR41XX
@@ -670,7 +680,7 @@ config GPIO_WCD934X
tristate "Qualcomm Technologies Inc WCD9340/WCD9341 gpio controller driver"
depends on MFD_WCD934X && OF_GPIO
help
- This driver is to supprot GPIO block found on the Qualcomm Technologies
+ This driver is to support GPIO block found on the Qualcomm Technologies
Inc WCD9340/WCD9341 Audio Codec.
config GPIO_XGENE
@@ -694,6 +704,8 @@ config GPIO_XGENE_SB
config GPIO_XILINX
tristate "Xilinx GPIO support"
+ select GPIOLIB_IRQCHIP
+ depends on OF_GPIO
help
Say yes here to support the Xilinx FPGA GPIO device
@@ -731,13 +743,6 @@ config GPIO_ZYNQ
help
Say yes here to support Xilinx Zynq GPIO controller.
-config GPIO_ZX
- bool "ZTE ZX GPIO support"
- depends on ARCH_ZX || COMPILE_TEST
- select GPIOLIB_IRQCHIP
- help
- Say yes here to support the GPIO device on ZTE ZX SoCs.
-
config GPIO_LOONGSON1
tristate "Loongson1 GPIO support"
depends on MACH_LOONGSON32
@@ -1623,8 +1628,7 @@ config GPIO_MOCKUP
select IRQ_SIM
help
This enables GPIO Testing driver, which provides a way to test GPIO
- subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
- must be selected for this test.
+ subsystem through sysfs (or char device) and debugfs.
User could use it through the script in
tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
it.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a2106d667fb3..c58a90a3c3b1 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -102,7 +102,6 @@ obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
obj-$(CONFIG_GPIO_MSC313) += gpio-msc313.o
-obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
@@ -163,6 +162,7 @@ obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.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
@@ -179,5 +179,4 @@ obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o
obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
-obj-$(CONFIG_GPIO_ZX) += gpio-zx.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index dfd8a4876a27..08171431bb8f 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -62,34 +62,6 @@ static char *get_arg(char **args)
return start;
}
-static bool isrange(const char *s)
-{
- size_t n;
-
- if (IS_ERR_OR_NULL(s))
- return false;
-
- while (1) {
- n = strspn(s, "0123456789");
- if (!n)
- return false;
-
- s += n;
-
- switch (*s++) {
- case '\0':
- return true;
-
- case '-':
- case ',':
- break;
-
- default:
- return false;
- }
- }
-}
-
static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
int hwnum, unsigned int *n)
{
@@ -100,8 +72,7 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
if (!lookups)
return -ENOMEM;
- lookups->table[*n] =
- (struct gpiod_lookup)GPIO_LOOKUP_IDX(key, hwnum, NULL, *n, 0);
+ lookups->table[*n] = GPIO_LOOKUP_IDX(key, hwnum, NULL, *n, 0);
(*n)++;
memset(&lookups->table[*n], 0, sizeof(lookups->table[*n]));
@@ -112,10 +83,10 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
static int aggr_parse(struct gpio_aggregator *aggr)
{
+ char *name, *offsets, *p;
char *args = aggr->args;
unsigned long *bitmap;
unsigned int i, n = 0;
- char *name, *offsets;
int error = 0;
bitmap = bitmap_alloc(ARCH_NR_GPIOS, GFP_KERNEL);
@@ -130,7 +101,8 @@ static int aggr_parse(struct gpio_aggregator *aggr)
goto free_bitmap;
}
- if (!isrange(offsets)) {
+ p = get_options(offsets, 0, &error);
+ if (error == 0 || *p) {
/* Named GPIO line */
error = aggr_add_gpio(aggr, name, U16_MAX, &n);
if (error)
@@ -271,7 +243,7 @@ static DRIVER_ATTR_WO(delete_device);
static struct attribute *gpio_aggregator_attrs[] = {
&driver_attr_new_device.attr,
&driver_attr_delete_device.attr,
- NULL,
+ NULL
};
ATTRIBUTE_GROUPS(gpio_aggregator);
@@ -545,7 +517,7 @@ static const struct of_device_id gpio_aggregator_dt_ids[] = {
* Add GPIO-operated devices controlled from userspace below,
* or use "driver_override" in sysfs
*/
- {},
+ {}
};
MODULE_DEVICE_TABLE(of, gpio_aggregator_dt_ids);
#endif
diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c
index 45b3da8da336..397a50d6bc65 100644
--- a/drivers/gpio/gpio-bd70528.c
+++ b/drivers/gpio/gpio-bd70528.c
@@ -12,7 +12,8 @@
#define GPIO_OUT_REG(offset) (BD70528_REG_GPIO1_OUT + (offset) * 2)
struct bd70528_gpio {
- struct rohm_regmap_dev chip;
+ struct regmap *regmap;
+ struct device *dev;
struct gpio_chip gpio;
};
@@ -35,11 +36,11 @@ static int bd70528_set_debounce(struct bd70528_gpio *bdgpio,
val = BD70528_DEBOUNCE_50MS;
break;
default:
- dev_err(bdgpio->chip.dev,
+ dev_err(bdgpio->dev,
"Invalid debounce value %u\n", debounce);
return -EINVAL;
}
- return regmap_update_bits(bdgpio->chip.regmap, GPIO_IN_REG(offset),
+ return regmap_update_bits(bdgpio->regmap, GPIO_IN_REG(offset),
BD70528_DEBOUNCE_MASK, val);
}
@@ -49,9 +50,9 @@ static int bd70528_get_direction(struct gpio_chip *chip, unsigned int offset)
int val, ret;
/* Do we need to do something to IRQs here? */
- ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), &val);
+ ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), &val);
if (ret) {
- dev_err(bdgpio->chip.dev, "Could not read gpio direction\n");
+ dev_err(bdgpio->dev, "Could not read gpio direction\n");
return ret;
}
if (val & BD70528_GPIO_OUT_EN_MASK)
@@ -67,13 +68,13 @@ static int bd70528_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
switch (pinconf_to_config_param(config)) {
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- return regmap_update_bits(bdgpio->chip.regmap,
+ return regmap_update_bits(bdgpio->regmap,
GPIO_OUT_REG(offset),
BD70528_GPIO_DRIVE_MASK,
BD70528_GPIO_OPEN_DRAIN);
break;
case PIN_CONFIG_DRIVE_PUSH_PULL:
- return regmap_update_bits(bdgpio->chip.regmap,
+ return regmap_update_bits(bdgpio->regmap,
GPIO_OUT_REG(offset),
BD70528_GPIO_DRIVE_MASK,
BD70528_GPIO_PUSH_PULL);
@@ -93,7 +94,7 @@ static int bd70528_direction_input(struct gpio_chip *chip, unsigned int offset)
struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
/* Do we need to do something to IRQs here? */
- return regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
+ return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset),
BD70528_GPIO_OUT_EN_MASK,
BD70528_GPIO_OUT_DISABLE);
}
@@ -105,10 +106,10 @@ static void bd70528_gpio_set(struct gpio_chip *chip, unsigned int offset,
struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
u8 val = (value) ? BD70528_GPIO_OUT_HI : BD70528_GPIO_OUT_LO;
- ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
+ ret = regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset),
BD70528_GPIO_OUT_MASK, val);
if (ret)
- dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value);
+ dev_err(bdgpio->dev, "Could not set gpio to %d\n", value);
}
static int bd70528_direction_output(struct gpio_chip *chip, unsigned int offset,
@@ -117,7 +118,7 @@ static int bd70528_direction_output(struct gpio_chip *chip, unsigned int offset,
struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
bd70528_gpio_set(chip, offset, value);
- return regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
+ return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset),
BD70528_GPIO_OUT_EN_MASK,
BD70528_GPIO_OUT_ENABLE);
}
@@ -129,11 +130,11 @@ static int bd70528_gpio_get_o(struct bd70528_gpio *bdgpio, unsigned int offset)
int ret;
unsigned int val;
- ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), &val);
+ ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), &val);
if (!ret)
ret = !!(val & BD70528_GPIO_OUT_MASK);
else
- dev_err(bdgpio->chip.dev, "GPIO (out) state read failed\n");
+ dev_err(bdgpio->dev, "GPIO (out) state read failed\n");
return ret;
}
@@ -143,12 +144,12 @@ static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset)
unsigned int val;
int ret;
- ret = regmap_read(bdgpio->chip.regmap, BD70528_REG_GPIO_STATE, &val);
+ ret = regmap_read(bdgpio->regmap, BD70528_REG_GPIO_STATE, &val);
if (!ret)
ret = !(val & GPIO_IN_STATE_MASK(offset));
else
- dev_err(bdgpio->chip.dev, "GPIO (in) state read failed\n");
+ dev_err(bdgpio->dev, "GPIO (in) state read failed\n");
return ret;
}
@@ -173,29 +174,22 @@ static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset)
else if (ret == GPIO_LINE_DIRECTION_IN)
ret = bd70528_gpio_get_i(bdgpio, offset);
else
- dev_err(bdgpio->chip.dev, "failed to read GPIO direction\n");
+ dev_err(bdgpio->dev, "failed to read GPIO direction\n");
return ret;
}
static int bd70528_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct bd70528_gpio *bdgpio;
- struct rohm_regmap_dev *bd70528;
int ret;
- bd70528 = dev_get_drvdata(pdev->dev.parent);
- if (!bd70528) {
- dev_err(&pdev->dev, "No MFD driver data\n");
- return -EINVAL;
- }
-
- bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio),
- GFP_KERNEL);
+ bdgpio = devm_kzalloc(dev, sizeof(*bdgpio), GFP_KERNEL);
if (!bdgpio)
return -ENOMEM;
- bdgpio->chip.dev = &pdev->dev;
- bdgpio->gpio.parent = pdev->dev.parent;
+ bdgpio->dev = dev;
+ bdgpio->gpio.parent = dev->parent;
bdgpio->gpio.label = "bd70528-gpio";
bdgpio->gpio.owner = THIS_MODULE;
bdgpio->gpio.get_direction = bd70528_get_direction;
@@ -208,14 +202,15 @@ static int bd70528_probe(struct platform_device *pdev)
bdgpio->gpio.ngpio = 4;
bdgpio->gpio.base = -1;
#ifdef CONFIG_OF_GPIO
- bdgpio->gpio.of_node = pdev->dev.parent->of_node;
+ bdgpio->gpio.of_node = dev->parent->of_node;
#endif
- bdgpio->chip.regmap = bd70528->regmap;
+ bdgpio->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!bdgpio->regmap)
+ return -ENODEV;
- ret = devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio,
- bdgpio);
+ ret = devm_gpiochip_add_data(dev, &bdgpio->gpio, bdgpio);
if (ret)
- dev_err(&pdev->dev, "gpio_init: Failed to add bd70528-gpio\n");
+ dev_err(dev, "gpio_init: Failed to add bd70528-gpio\n");
return ret;
}
diff --git a/drivers/gpio/gpio-bd71828.c b/drivers/gpio/gpio-bd71828.c
index 3dbbc638e9a9..c8e382b53f2f 100644
--- a/drivers/gpio/gpio-bd71828.c
+++ b/drivers/gpio/gpio-bd71828.c
@@ -11,7 +11,8 @@
#define HALL_GPIO_OFFSET 3
struct bd71828_gpio {
- struct rohm_regmap_dev chip;
+ struct regmap *regmap;
+ struct device *dev;
struct gpio_chip gpio;
};
@@ -29,10 +30,10 @@ static void bd71828_gpio_set(struct gpio_chip *chip, unsigned int offset,
if (offset == HALL_GPIO_OFFSET)
return;
- ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
+ ret = regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset),
BD71828_GPIO_OUT_MASK, val);
if (ret)
- dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value);
+ dev_err(bdgpio->dev, "Could not set gpio to %d\n", value);
}
static int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset)
@@ -42,10 +43,10 @@ static int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset)
struct bd71828_gpio *bdgpio = gpiochip_get_data(chip);
if (offset == HALL_GPIO_OFFSET)
- ret = regmap_read(bdgpio->chip.regmap, BD71828_REG_IO_STAT,
+ ret = regmap_read(bdgpio->regmap, BD71828_REG_IO_STAT,
&val);
else
- ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
+ ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset),
&val);
if (!ret)
ret = (val & BD71828_GPIO_OUT_MASK);
@@ -63,12 +64,12 @@ static int bd71828_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
switch (pinconf_to_config_param(config)) {
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- return regmap_update_bits(bdgpio->chip.regmap,
+ return regmap_update_bits(bdgpio->regmap,
GPIO_OUT_REG(offset),
BD71828_GPIO_DRIVE_MASK,
BD71828_GPIO_OPEN_DRAIN);
case PIN_CONFIG_DRIVE_PUSH_PULL:
- return regmap_update_bits(bdgpio->chip.regmap,
+ return regmap_update_bits(bdgpio->regmap,
GPIO_OUT_REG(offset),
BD71828_GPIO_DRIVE_MASK,
BD71828_GPIO_PUSH_PULL);
@@ -96,22 +97,15 @@ static int bd71828_get_direction(struct gpio_chip *chip, unsigned int offset)
static int bd71828_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct bd71828_gpio *bdgpio;
- struct rohm_regmap_dev *bd71828;
- bd71828 = dev_get_drvdata(pdev->dev.parent);
- if (!bd71828) {
- dev_err(&pdev->dev, "No MFD driver data\n");
- return -EINVAL;
- }
-
- bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio),
- GFP_KERNEL);
+ bdgpio = devm_kzalloc(dev, sizeof(*bdgpio), GFP_KERNEL);
if (!bdgpio)
return -ENOMEM;
- bdgpio->chip.dev = &pdev->dev;
- bdgpio->gpio.parent = pdev->dev.parent;
+ bdgpio->dev = dev;
+ bdgpio->gpio.parent = dev->parent;
bdgpio->gpio.label = "bd71828-gpio";
bdgpio->gpio.owner = THIS_MODULE;
bdgpio->gpio.get_direction = bd71828_get_direction;
@@ -127,11 +121,12 @@ static int bd71828_probe(struct platform_device *pdev)
* "gpio-reserved-ranges" and exclude them from control
*/
bdgpio->gpio.ngpio = 4;
- bdgpio->gpio.of_node = pdev->dev.parent->of_node;
- bdgpio->chip.regmap = bd71828->regmap;
+ bdgpio->gpio.of_node = dev->parent->of_node;
+ bdgpio->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!bdgpio->regmap)
+ return -ENODEV;
- return devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio,
- bdgpio);
+ return devm_gpiochip_add_data(dev, &bdgpio->gpio, bdgpio);
}
static struct platform_driver bd71828_gpio = {
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 94d9fa0d6aa7..ef148b26b587 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -31,6 +31,8 @@
/* Maximum value for irq capable line identifiers */
#define EP93XX_GPIO_LINE_MAX_IRQ 23
+#define EP93XX_GPIO_A_IRQ_BASE 64
+#define EP93XX_GPIO_B_IRQ_BASE 72
/*
* Static mapping of GPIO bank F IRQS:
* F0..F7 (16..24) to irq 80..87.
@@ -292,14 +294,14 @@ struct ep93xx_gpio_bank {
static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
/* Bank A has 8 IRQs */
- EP93XX_GPIO_BANK("A", 0x00, 0x10, 0x90, 0, true, false, 64),
+ EP93XX_GPIO_BANK("A", 0x00, 0x10, 0x90, 0, true, false, EP93XX_GPIO_A_IRQ_BASE),
/* Bank B has 8 IRQs */
- EP93XX_GPIO_BANK("B", 0x04, 0x14, 0xac, 8, true, false, 72),
+ EP93XX_GPIO_BANK("B", 0x04, 0x14, 0xac, 8, true, false, EP93XX_GPIO_B_IRQ_BASE),
EP93XX_GPIO_BANK("C", 0x08, 0x18, 0x00, 40, false, false, 0),
EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 0x00, 24, false, false, 0),
EP93XX_GPIO_BANK("E", 0x20, 0x24, 0x00, 32, false, false, 0),
/* Bank F has 8 IRQs */
- EP93XX_GPIO_BANK("F", 0x30, 0x34, 0x4c, 16, false, true, 0),
+ EP93XX_GPIO_BANK("F", 0x30, 0x34, 0x4c, 16, false, true, EP93XX_GPIO_F_IRQ_BASE),
EP93XX_GPIO_BANK("G", 0x38, 0x3c, 0x00, 48, false, false, 0),
EP93XX_GPIO_BANK("H", 0x40, 0x44, 0x00, 56, false, false, 0),
};
@@ -318,11 +320,6 @@ static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
return 0;
}
-static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset)
-{
- return EP93XX_GPIO_F_IRQ_BASE + offset;
-}
-
static void ep93xx_init_irq_chip(struct device *dev, struct irq_chip *ic)
{
ic->irq_ack = ep93xx_gpio_irq_ack;
@@ -375,7 +372,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
girq->parent_handler = ep93xx_gpio_ab_irq_handler;
girq->num_parents = 1;
- girq->parents = devm_kcalloc(dev, 1,
+ girq->parents = devm_kcalloc(dev, girq->num_parents,
sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
@@ -393,20 +390,19 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
/*
* FIXME: convert this to use hierarchical IRQ support!
- * this requires fixing the root irqchip to be hierarchial.
+ * this requires fixing the root irqchip to be hierarchical.
*/
girq->parent_handler = ep93xx_gpio_f_irq_handler;
girq->num_parents = 8;
- girq->parents = devm_kcalloc(dev, 8,
+ girq->parents = devm_kcalloc(dev, girq->num_parents,
sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
/* Pick resources 1..8 for these IRQs */
- for (i = 1; i <= 8; i++)
- girq->parents[i - 1] = platform_get_irq(pdev, i);
- for (i = 0; i < 8; i++) {
- gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
+ for (i = 0; i < girq->num_parents; i++) {
+ girq->parents[i] = platform_get_irq(pdev, i + 1);
+ gpio_irq = bank->irq_base + i;
irq_set_chip_data(gpio_irq, &epg->gc[5]);
irq_set_chip_and_handler(gpio_irq,
girq->chip,
@@ -415,7 +411,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
}
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
- gc->to_irq = ep93xx_gpio_f_to_irq;
+ girq->first = bank->irq_base;
}
return devm_gpiochip_add_data(dev, gc, epg);
diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c
index 7c0a9ef0b500..82b3a913005d 100644
--- a/drivers/gpio/gpio-max77620.c
+++ b/drivers/gpio/gpio-max77620.c
@@ -325,7 +325,7 @@ static int max77620_gpio_probe(struct platform_device *pdev)
girq->parents = NULL;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_edge_irq;
- girq->init_hw = max77620_gpio_irq_init_hw,
+ girq->init_hw = max77620_gpio_irq_init_hw;
girq->threaded = true;
platform_set_drvdata(pdev, mgpio);
diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c
index 706687fab634..22f3ce218f5d 100644
--- a/drivers/gpio/gpio-merrifield.c
+++ b/drivers/gpio/gpio-merrifield.c
@@ -194,6 +194,11 @@ static int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
{
u32 debounce;
+ if ((pinconf_to_config_param(config) == PIN_CONFIG_BIAS_DISABLE) ||
+ (pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_UP) ||
+ (pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_DOWN))
+ return gpiochip_generic_config(chip, offset, config);
+
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
return -ENOTSUPP;
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index a912a8fed197..8f429d9f3661 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -70,7 +70,12 @@
*/
#define PWM_BLINK_ON_DURATION_OFF 0x0
#define PWM_BLINK_OFF_DURATION_OFF 0x4
+#define PWM_BLINK_COUNTER_B_OFF 0x8
+/* Armada 8k variant gpios register offsets */
+#define AP80X_GPIO0_OFF_A8K 0x1040
+#define CP11X_GPIO0_OFF_A8K 0x100
+#define CP11X_GPIO1_OFF_A8K 0x140
/* The MV78200 has per-CPU registers for edge mask and level mask */
#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18)
@@ -93,6 +98,7 @@
struct mvebu_pwm {
struct regmap *regs;
+ u32 offset;
unsigned long clk_rate;
struct gpio_desc *gpiod;
struct pwm_chip chip;
@@ -283,12 +289,12 @@ mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val)
*/
static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
{
- return PWM_BLINK_ON_DURATION_OFF;
+ return mvpwm->offset + PWM_BLINK_ON_DURATION_OFF;
}
static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
{
- return PWM_BLINK_OFF_DURATION_OFF;
+ return mvpwm->offset + PWM_BLINK_OFF_DURATION_OFF;
}
/*
@@ -667,26 +673,21 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
spin_lock_irqsave(&mvpwm->lock, flags);
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u);
- val = (unsigned long long) u * NSEC_PER_SEC;
- do_div(val, mvpwm->clk_rate);
- if (val > UINT_MAX)
- state->duty_cycle = UINT_MAX;
- else if (val)
- state->duty_cycle = val;
+ /* Hardware treats zero as 2^32. See mvebu_pwm_apply(). */
+ if (u > 0)
+ val = u;
else
- state->duty_cycle = 1;
+ val = UINT_MAX + 1ULL;
+ state->duty_cycle = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC,
+ mvpwm->clk_rate);
- val = (unsigned long long) u; /* on duration */
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
- val += (unsigned long long) u; /* period = on + off duration */
- val *= NSEC_PER_SEC;
- do_div(val, mvpwm->clk_rate);
- if (val > UINT_MAX)
- state->period = UINT_MAX;
- else if (val)
- state->period = val;
+ /* period = on + off duration */
+ if (u > 0)
+ val += u;
else
- state->period = 1;
+ val += UINT_MAX + 1ULL;
+ state->period = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, mvpwm->clk_rate);
regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
if (u)
@@ -708,19 +709,27 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle;
do_div(val, NSEC_PER_SEC);
- if (val > UINT_MAX)
+ if (val > UINT_MAX + 1ULL)
return -EINVAL;
- if (val)
+ /*
+ * Zero on/off values don't work as expected. Experimentation shows
+ * that zero value is treated as 2^32. This behavior is not documented.
+ */
+ if (val == UINT_MAX + 1ULL)
+ on = 0;
+ else if (val)
on = val;
else
on = 1;
- val = (unsigned long long) mvpwm->clk_rate *
- (state->period - state->duty_cycle);
+ val = (unsigned long long) mvpwm->clk_rate * state->period;
do_div(val, NSEC_PER_SEC);
- if (val > UINT_MAX)
+ val -= on;
+ if (val > UINT_MAX + 1ULL)
return -EINVAL;
- if (val)
+ if (val == UINT_MAX + 1ULL)
+ off = 0;
+ else if (val)
off = val;
else
off = 1;
@@ -778,51 +787,80 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
struct device *dev = &pdev->dev;
struct mvebu_pwm *mvpwm;
void __iomem *base;
+ u32 offset;
u32 set;
- if (!of_device_is_compatible(mvchip->chip.of_node,
- "marvell,armada-370-gpio"))
- return 0;
-
- /*
- * There are only two sets of PWM configuration registers for
- * all the GPIO lines on those SoCs which this driver reserves
- * for the first two GPIO chips. So if the resource is missing
- * we can't treat it as an error.
- */
- if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"))
+ if (of_device_is_compatible(mvchip->chip.of_node,
+ "marvell,armada-370-gpio")) {
+ /*
+ * There are only two sets of PWM configuration registers for
+ * all the GPIO lines on those SoCs which this driver reserves
+ * for the first two GPIO chips. So if the resource is missing
+ * we can't treat it as an error.
+ */
+ if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"))
+ return 0;
+ offset = 0;
+ } else if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
+ int ret = of_property_read_u32(dev->of_node,
+ "marvell,pwm-offset", &offset);
+ if (ret < 0)
+ return 0;
+ } else {
return 0;
+ }
if (IS_ERR(mvchip->clk))
return PTR_ERR(mvchip->clk);
- /*
- * Use set A for lines of GPIO chip with id 0, B for GPIO chip
- * with id 1. Don't allow further GPIO chips to be used for PWM.
- */
- if (id == 0)
- set = 0;
- else if (id == 1)
- set = U32_MAX;
- else
- return -EINVAL;
- regmap_write(mvchip->regs,
- GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
-
mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
if (!mvpwm)
return -ENOMEM;
mvchip->mvpwm = mvpwm;
mvpwm->mvchip = mvchip;
+ mvpwm->offset = offset;
+
+ if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
+ mvpwm->regs = mvchip->regs;
+
+ switch (mvchip->offset) {
+ case AP80X_GPIO0_OFF_A8K:
+ case CP11X_GPIO0_OFF_A8K:
+ /* Blink counter A */
+ set = 0;
+ break;
+ case CP11X_GPIO1_OFF_A8K:
+ /* Blink counter B */
+ set = U32_MAX;
+ mvpwm->offset += PWM_BLINK_COUNTER_B_OFF;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ base = devm_platform_ioremap_resource_byname(pdev, "pwm");
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- base = devm_platform_ioremap_resource_byname(pdev, "pwm");
- if (IS_ERR(base))
- return PTR_ERR(base);
+ mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
+ &mvebu_gpio_regmap_config);
+ if (IS_ERR(mvpwm->regs))
+ return PTR_ERR(mvpwm->regs);
- mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
- &mvebu_gpio_regmap_config);
- if (IS_ERR(mvpwm->regs))
- return PTR_ERR(mvpwm->regs);
+ /*
+ * Use set A for lines of GPIO chip with id 0, B for GPIO chip
+ * with id 1. Don't allow further GPIO chips to be used for PWM.
+ */
+ if (id == 0)
+ set = 0;
+ else if (id == 1)
+ set = U32_MAX;
+ else
+ return -EINVAL;
+ }
+
+ regmap_write(mvchip->regs,
+ GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
mvpwm->clk_rate = clk_get_rate(mvchip->clk);
if (!mvpwm->clk_rate) {
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 825b362eb4b7..5ea09fd01544 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -73,6 +73,7 @@
static const struct i2c_device_id pca953x_id[] = {
{ "pca6416", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
+ { "pca9506", 40 | PCA953X_TYPE | PCA_INT, },
{ "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9536", 4 | PCA953X_TYPE, },
@@ -1236,6 +1237,7 @@ static int pca953x_resume(struct device *dev)
static const struct of_device_id pca953x_dt_ids[] = {
{ .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), },
{ .compatible = "nxp,pca9534", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
{ .compatible = "nxp,pca9536", .data = OF_953X( 4, 0), },
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index a2a8d155c75e..b7568ee33696 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -332,7 +332,7 @@ static int pcf857x_probe(struct i2c_client *client,
* reset state. Otherwise it flags pins to be driven low.
*/
gpio->out = ~n_latch;
- gpio->status = gpio->out;
+ gpio->status = gpio->read(gpio->client);
/* Enable irqchip if we have an interrupt */
if (client->irq) {
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 0b572dbc4a36..e7092d5fe700 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -35,6 +35,8 @@ struct gpio_rcar_bank_info {
struct gpio_rcar_info {
bool has_outdtsel;
bool has_both_edge_trigger;
+ bool has_always_in;
+ bool has_inen;
};
struct gpio_rcar_priv {
@@ -62,6 +64,7 @@ struct gpio_rcar_priv {
#define FILONOFF 0x28 /* Chattering Prevention On/Off Register */
#define OUTDTSEL 0x40 /* Output Data Select Register */
#define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */
+#define INEN 0x50 /* General Input Enable Register */
#define RCAR_MAX_GPIO_PER_BANK 32
@@ -302,9 +305,11 @@ static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
u32 bit = BIT(offset);
- /* testing on r8a7790 shows that INDT does not show correct pin state
- * when configured as output, so use OUTDT in case of output pins */
- if (gpio_rcar_read(p, INOUTSEL) & bit)
+ /*
+ * Before R-Car Gen3, INDT does not show correct pin state when
+ * configured as output, so use OUTDT in case of output pins
+ */
+ if (!p->info.has_always_in && (gpio_rcar_read(p, INOUTSEL) & bit))
return !!(gpio_rcar_read(p, OUTDT) & bit);
else
return !!(gpio_rcar_read(p, INDT) & bit);
@@ -324,6 +329,11 @@ static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
if (!bankmask)
return 0;
+ if (p->info.has_always_in) {
+ bits[0] = gpio_rcar_read(p, INDT) & bankmask;
+ return 0;
+ }
+
spin_lock_irqsave(&p->lock, flags);
outputs = gpio_rcar_read(p, INOUTSEL);
m = outputs & bankmask;
@@ -383,41 +393,35 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
.has_outdtsel = false,
.has_both_edge_trigger = false,
+ .has_always_in = false,
+ .has_inen = false,
};
static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
.has_outdtsel = true,
.has_both_edge_trigger = true,
+ .has_always_in = false,
+ .has_inen = false,
+};
+
+static const struct gpio_rcar_info gpio_rcar_info_gen3 = {
+ .has_outdtsel = true,
+ .has_both_edge_trigger = true,
+ .has_always_in = true,
+ .has_inen = false,
+};
+
+static const struct gpio_rcar_info gpio_rcar_info_v3u = {
+ .has_outdtsel = true,
+ .has_both_edge_trigger = true,
+ .has_always_in = true,
+ .has_inen = true,
};
static const struct of_device_id gpio_rcar_of_table[] = {
{
- .compatible = "renesas,gpio-r8a7743",
- /* RZ/G1 GPIO is identical to R-Car Gen2. */
- .data = &gpio_rcar_info_gen2,
- }, {
- .compatible = "renesas,gpio-r8a7790",
- .data = &gpio_rcar_info_gen2,
- }, {
- .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,
- }, {
- .compatible = "renesas,gpio-r8a7794",
- .data = &gpio_rcar_info_gen2,
- }, {
- .compatible = "renesas,gpio-r8a7795",
- /* Gen3 GPIO is identical to Gen2. */
- .data = &gpio_rcar_info_gen2,
- }, {
- .compatible = "renesas,gpio-r8a7796",
- /* Gen3 GPIO is identical to Gen2. */
- .data = &gpio_rcar_info_gen2,
+ .compatible = "renesas,gpio-r8a779a0",
+ .data = &gpio_rcar_info_v3u,
}, {
.compatible = "renesas,rcar-gen1-gpio",
.data = &gpio_rcar_info_gen1,
@@ -426,8 +430,7 @@ static const struct of_device_id gpio_rcar_of_table[] = {
.data = &gpio_rcar_info_gen2,
}, {
.compatible = "renesas,rcar-gen3-gpio",
- /* Gen3 GPIO is identical to Gen2. */
- .data = &gpio_rcar_info_gen2,
+ .data = &gpio_rcar_info_gen3,
}, {
.compatible = "renesas,gpio-rcar",
.data = &gpio_rcar_info_gen1,
@@ -460,6 +463,17 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
return 0;
}
+static void gpio_rcar_enable_inputs(struct gpio_rcar_priv *p)
+{
+ u32 mask = GENMASK(p->gpio_chip.ngpio - 1, 0);
+
+ /* Select "Input Enable" in INEN */
+ if (p->gpio_chip.valid_mask)
+ mask &= p->gpio_chip.valid_mask[0];
+ if (mask)
+ gpio_rcar_write(p, INEN, gpio_rcar_read(p, INEN) | mask);
+}
+
static int gpio_rcar_probe(struct platform_device *pdev)
{
struct gpio_rcar_priv *p;
@@ -549,6 +563,12 @@ static int gpio_rcar_probe(struct platform_device *pdev)
goto err1;
}
+ if (p->info.has_inen) {
+ pm_runtime_get_sync(p->dev);
+ gpio_rcar_enable_inputs(p);
+ pm_runtime_put(p->dev);
+ }
+
dev_info(dev, "driving %d GPIOs\n", npins);
return 0;
@@ -624,6 +644,9 @@ static int gpio_rcar_resume(struct device *dev)
}
}
+ if (p->info.has_inen)
+ gpio_rcar_enable_inputs(p);
+
return 0;
}
#endif /* CONFIG_PM_SLEEP*/
diff --git a/drivers/gpio/gpio-sl28cpld.c b/drivers/gpio/gpio-sl28cpld.c
index 889b8f5622c2..52404736ac86 100644
--- a/drivers/gpio/gpio-sl28cpld.c
+++ b/drivers/gpio/gpio-sl28cpld.c
@@ -65,13 +65,13 @@ static int sl28cpld_gpio_irq_init(struct platform_device *pdev,
if (!irq_chip)
return -ENOMEM;
- irq_chip->name = "sl28cpld-gpio-irq",
+ irq_chip->name = "sl28cpld-gpio-irq";
irq_chip->irqs = sl28cpld_gpio_irqs;
irq_chip->num_irqs = ARRAY_SIZE(sl28cpld_gpio_irqs);
irq_chip->num_regs = 1;
irq_chip->status_base = base + GPIO_REG_IP;
irq_chip->mask_base = base + GPIO_REG_IE;
- irq_chip->mask_invert = true,
+ irq_chip->mask_invert = true;
irq_chip->ack_base = base + GPIO_REG_IP;
ret = devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index e19ebff6018c..0025f613d9b3 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -60,7 +60,6 @@ struct tegra_gpio_info;
struct tegra_gpio_bank {
unsigned int bank;
- unsigned int irq;
/*
* IRQ-core code uses raw locking, and thus, nested locking also
@@ -81,7 +80,6 @@ struct tegra_gpio_bank {
u32 dbc_enb[4];
#endif
u32 dbc_cnt[4];
- struct tegra_gpio_info *tgi;
};
struct tegra_gpio_soc_config {
@@ -93,12 +91,12 @@ struct tegra_gpio_soc_config {
struct tegra_gpio_info {
struct device *dev;
void __iomem *regs;
- struct irq_domain *irq_domain;
struct tegra_gpio_bank *bank_info;
const struct tegra_gpio_soc_config *soc;
struct gpio_chip gc;
struct irq_chip ic;
u32 bank_count;
+ unsigned int *irqs;
};
static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi,
@@ -274,17 +272,10 @@ static int tegra_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
return tegra_gpio_set_debounce(chip, offset, debounce);
}
-static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
-{
- struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
-
- return irq_find_mapping(tgi->irq_domain, offset);
-}
-
static void tegra_gpio_irq_ack(struct irq_data *d)
{
- struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- struct tegra_gpio_info *tgi = bank->tgi;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
unsigned int gpio = d->hwirq;
tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio));
@@ -292,8 +283,8 @@ static void tegra_gpio_irq_ack(struct irq_data *d)
static void tegra_gpio_irq_mask(struct irq_data *d)
{
- struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- struct tegra_gpio_info *tgi = bank->tgi;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
unsigned int gpio = d->hwirq;
tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0);
@@ -301,8 +292,8 @@ static void tegra_gpio_irq_mask(struct irq_data *d)
static void tegra_gpio_irq_unmask(struct irq_data *d)
{
- struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- struct tegra_gpio_info *tgi = bank->tgi;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
unsigned int gpio = d->hwirq;
tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1);
@@ -311,11 +302,14 @@ static void tegra_gpio_irq_unmask(struct irq_data *d)
static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
unsigned int gpio = d->hwirq, port = GPIO_PORT(gpio), lvl_type;
- struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- struct tegra_gpio_info *tgi = bank->tgi;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+ struct tegra_gpio_bank *bank;
unsigned long flags;
- u32 val;
int ret;
+ u32 val;
+
+ bank = &tgi->bank_info[GPIO_BANK(d->hwirq)];
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_RISING:
@@ -367,13 +361,16 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
irq_set_handler_locked(d, handle_edge_irq);
- return 0;
+ if (d->parent_data)
+ ret = irq_chip_set_type_parent(d, type);
+
+ return ret;
}
static void tegra_gpio_irq_shutdown(struct irq_data *d)
{
- struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- struct tegra_gpio_info *tgi = bank->tgi;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
unsigned int gpio = d->hwirq;
tegra_gpio_irq_mask(d);
@@ -382,13 +379,25 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d)
static void tegra_gpio_irq_handler(struct irq_desc *desc)
{
- unsigned int port, pin, gpio;
+ struct tegra_gpio_info *tgi = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_domain *domain = tgi->gc.irq.domain;
+ unsigned int irq = irq_desc_get_irq(desc);
+ struct tegra_gpio_bank *bank = NULL;
+ unsigned int port, pin, gpio, i;
bool unmasked = false;
- u32 lvl;
unsigned long sta;
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc);
- struct tegra_gpio_info *tgi = bank->tgi;
+ u32 lvl;
+
+ for (i = 0; i < tgi->bank_count; i++) {
+ if (tgi->irqs[i] == irq) {
+ bank = &tgi->bank_info[i];
+ break;
+ }
+ }
+
+ if (WARN_ON(bank == NULL))
+ return;
chained_irq_enter(chip, desc);
@@ -411,14 +420,47 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
- generic_handle_irq(irq_find_mapping(tgi->irq_domain,
- gpio + pin));
+ irq = irq_find_mapping(domain, gpio + pin);
+ if (WARN_ON(irq == 0))
+ continue;
+
+ generic_handle_irq(irq);
}
}
if (!unmasked)
chained_irq_exit(chip, desc);
+}
+
+static int tegra_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
+ unsigned int hwirq,
+ unsigned int type,
+ unsigned int *parent_hwirq,
+ unsigned int *parent_type)
+{
+ *parent_hwirq = chip->irq.child_offset_to_irq(chip, hwirq);
+ *parent_type = type;
+
+ return 0;
+}
+
+static void *tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
+{
+ struct irq_fwspec *fwspec;
+
+ fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
+ if (!fwspec)
+ return NULL;
+ fwspec->fwnode = chip->irq.parent_domain->fwnode;
+ fwspec->param_count = 3;
+ fwspec->param[0] = 0;
+ fwspec->param[1] = parent_hwirq;
+ fwspec->param[2] = parent_type;
+
+ return fwspec;
}
#ifdef CONFIG_PM_SLEEP
@@ -497,19 +539,31 @@ static int tegra_gpio_suspend(struct device *dev)
static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
{
- struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+ struct tegra_gpio_bank *bank;
unsigned int gpio = d->hwirq;
u32 port, bit, mask;
int err;
- err = irq_set_irq_wake(bank->irq, enable);
- if (err)
- return err;
+ bank = &tgi->bank_info[GPIO_BANK(d->hwirq)];
port = GPIO_PORT(gpio);
bit = GPIO_BIT(gpio);
mask = BIT(bit);
+ err = irq_set_irq_wake(tgi->irqs[bank->bank], enable);
+ if (err)
+ return err;
+
+ if (d->parent_data) {
+ err = irq_chip_set_wake_parent(d, enable);
+ if (err) {
+ irq_set_irq_wake(tgi->irqs[bank->bank], !enable);
+ return err;
+ }
+ }
+
if (enable)
bank->wake_enb[port] |= mask;
else
@@ -519,6 +573,35 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
}
#endif
+static int tegra_gpio_irq_set_affinity(struct irq_data *data,
+ const struct cpumask *dest,
+ bool force)
+{
+ if (data->parent_data)
+ return irq_chip_set_affinity_parent(data, dest, force);
+
+ return -EINVAL;
+}
+
+static int tegra_gpio_irq_request_resources(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
+ tegra_gpio_enable(tgi, d->hwirq);
+
+ return gpiochip_reqres_irq(chip, d->hwirq);
+}
+
+static void tegra_gpio_irq_release_resources(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
+ gpiochip_relres_irq(chip, d->hwirq);
+ tegra_gpio_enable(tgi, d->hwirq);
+}
+
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
@@ -526,7 +609,7 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
static int tegra_dbg_gpio_show(struct seq_file *s, void *unused)
{
- struct tegra_gpio_info *tgi = s->private;
+ struct tegra_gpio_info *tgi = dev_get_drvdata(s->private);
unsigned int i, j;
for (i = 0; i < tgi->bank_count; i++) {
@@ -548,12 +631,10 @@ static int tegra_dbg_gpio_show(struct seq_file *s, void *unused)
return 0;
}
-DEFINE_SHOW_ATTRIBUTE(tegra_dbg_gpio);
-
static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
{
- debugfs_create_file("tegra_gpio", 0444, NULL, tgi,
- &tegra_dbg_gpio_fops);
+ debugfs_create_devm_seqfile(tgi->dev, "tegra_gpio", NULL,
+ tegra_dbg_gpio_show);
}
#else
@@ -568,14 +649,18 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
};
-static struct lock_class_key gpio_lock_class;
-static struct lock_class_key gpio_request_class;
+static const struct of_device_id tegra_pmc_of_match[] = {
+ { .compatible = "nvidia,tegra210-pmc", },
+ { /* sentinel */ },
+};
static int tegra_gpio_probe(struct platform_device *pdev)
{
- struct tegra_gpio_info *tgi;
struct tegra_gpio_bank *bank;
- unsigned int gpio, i, j;
+ struct tegra_gpio_info *tgi;
+ struct gpio_irq_chip *irq;
+ struct device_node *np;
+ unsigned int i, j;
int ret;
tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL);
@@ -604,7 +689,6 @@ static int tegra_gpio_probe(struct platform_device *pdev)
tgi->gc.direction_output = tegra_gpio_direction_output;
tgi->gc.set = tegra_gpio_set;
tgi->gc.get_direction = tegra_gpio_get_direction;
- tgi->gc.to_irq = tegra_gpio_to_irq;
tgi->gc.base = 0;
tgi->gc.ngpio = tgi->bank_count * 32;
tgi->gc.parent = &pdev->dev;
@@ -619,6 +703,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
tgi->ic.irq_set_wake = tegra_gpio_irq_set_wake;
#endif
+ tgi->ic.irq_request_resources = tegra_gpio_irq_request_resources;
+ tgi->ic.irq_release_resources = tegra_gpio_irq_release_resources;
platform_set_drvdata(pdev, tgi);
@@ -630,11 +716,10 @@ static int tegra_gpio_probe(struct platform_device *pdev)
if (!tgi->bank_info)
return -ENOMEM;
- tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
- tgi->gc.ngpio,
- &irq_domain_simple_ops, NULL);
- if (!tgi->irq_domain)
- return -ENODEV;
+ tgi->irqs = devm_kcalloc(&pdev->dev, tgi->bank_count,
+ sizeof(*tgi->irqs), GFP_KERNEL);
+ if (!tgi->irqs)
+ return -ENOMEM;
for (i = 0; i < tgi->bank_count; i++) {
ret = platform_get_irq(pdev, i);
@@ -643,8 +728,36 @@ static int tegra_gpio_probe(struct platform_device *pdev)
bank = &tgi->bank_info[i];
bank->bank = i;
- bank->irq = ret;
- bank->tgi = tgi;
+
+ tgi->irqs[i] = ret;
+
+ for (j = 0; j < 4; j++) {
+ raw_spin_lock_init(&bank->lvl_lock[j]);
+ spin_lock_init(&bank->dbc_lock[j]);
+ }
+ }
+
+ irq = &tgi->gc.irq;
+ irq->chip = &tgi->ic;
+ irq->fwnode = of_node_to_fwnode(pdev->dev.of_node);
+ irq->child_to_parent_hwirq = tegra_gpio_child_to_parent_hwirq;
+ irq->populate_parent_alloc_arg = tegra_gpio_populate_parent_fwspec;
+ irq->handler = handle_simple_irq;
+ irq->default_type = IRQ_TYPE_NONE;
+ irq->parent_handler = tegra_gpio_irq_handler;
+ irq->parent_handler_data = tgi;
+ irq->num_parents = tgi->bank_count;
+ irq->parents = tgi->irqs;
+
+ np = of_find_matching_node(NULL, tegra_pmc_of_match);
+ if (np) {
+ irq->parent_domain = irq_find_host(np);
+ of_node_put(np);
+
+ if (!irq->parent_domain)
+ return -EPROBE_DEFER;
+
+ tgi->ic.irq_set_affinity = tegra_gpio_irq_set_affinity;
}
tgi->regs = devm_platform_ioremap_resource(pdev, 0);
@@ -660,33 +773,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
}
ret = devm_gpiochip_add_data(&pdev->dev, &tgi->gc, tgi);
- if (ret < 0) {
- irq_domain_remove(tgi->irq_domain);
+ if (ret < 0)
return ret;
- }
-
- for (gpio = 0; gpio < tgi->gc.ngpio; gpio++) {
- int irq = irq_create_mapping(tgi->irq_domain, gpio);
- /* No validity check; all Tegra GPIOs are valid IRQs */
-
- bank = &tgi->bank_info[GPIO_BANK(gpio)];
-
- irq_set_chip_data(irq, bank);
- irq_set_lockdep_class(irq, &gpio_lock_class, &gpio_request_class);
- irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
- }
-
- for (i = 0; i < tgi->bank_count; i++) {
- bank = &tgi->bank_info[i];
-
- irq_set_chained_handler_and_data(bank->irq,
- tegra_gpio_irq_handler, bank);
-
- for (j = 0; j < 4; j++) {
- raw_spin_lock_init(&bank->lvl_lock[j]);
- spin_lock_init(&bank->dbc_lock[j]);
- }
- }
tegra_gpio_debuginit(tgi);
@@ -715,18 +803,21 @@ static const struct of_device_id tegra_gpio_of_match[] = {
{ .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
{ },
};
+MODULE_DEVICE_TABLE(of, tegra_gpio_of_match);
static struct platform_driver tegra_gpio_driver = {
- .driver = {
- .name = "tegra-gpio",
- .pm = &tegra_gpio_pm_ops,
+ .driver = {
+ .name = "tegra-gpio",
+ .pm = &tegra_gpio_pm_ops,
.of_match_table = tegra_gpio_of_match,
},
- .probe = tegra_gpio_probe,
+ .probe = tegra_gpio_probe,
};
-
-static int __init tegra_gpio_init(void)
-{
- return platform_driver_register(&tegra_gpio_driver);
-}
-subsys_initcall(tegra_gpio_init);
+module_platform_driver(tegra_gpio_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra GPIO controller driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_AUTHOR("Erik Gilling <konkers@google.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 286e0b1f46e4..1bd9e44df718 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -657,7 +657,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->gpio.get_direction = tegra186_gpio_get_direction;
gpio->gpio.direction_input = tegra186_gpio_direction_input;
gpio->gpio.direction_output = tegra186_gpio_direction_output;
- gpio->gpio.get = tegra186_gpio_get,
+ gpio->gpio.get = tegra186_gpio_get;
gpio->gpio.set = tegra186_gpio_set;
gpio->gpio.set_config = tegra186_gpio_set_config;
gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges;
diff --git a/drivers/gpio/gpio-visconti.c b/drivers/gpio/gpio-visconti.c
new file mode 100644
index 000000000000..0e3d19828eb1
--- /dev/null
+++ b/drivers/gpio/gpio-visconti.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Toshiba Visconti GPIO Support
+ *
+ * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
+ * (C) Copyright 2020 TOSHIBA CORPORATION
+ *
+ * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+
+/* register offset */
+#define GPIO_DIR 0x00
+#define GPIO_IDATA 0x08
+#define GPIO_ODATA 0x10
+#define GPIO_OSET 0x18
+#define GPIO_OCLR 0x20
+#define GPIO_INTMODE 0x30
+
+#define BASE_HW_IRQ 24
+
+struct visconti_gpio {
+ void __iomem *base;
+ spinlock_t lock; /* protect gpio register */
+ struct gpio_chip gpio_chip;
+ struct irq_chip irq_chip;
+};
+
+static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct visconti_gpio *priv = gpiochip_get_data(gc);
+ u32 offset = irqd_to_hwirq(d);
+ u32 bit = BIT(offset);
+ u32 intc_type = IRQ_TYPE_EDGE_RISING;
+ u32 intmode, odata;
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ odata = readl(priv->base + GPIO_ODATA);
+ intmode = readl(priv->base + GPIO_INTMODE);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ odata &= ~bit;
+ intmode &= ~bit;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ odata |= bit;
+ intmode &= ~bit;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ intmode |= bit;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ intc_type = IRQ_TYPE_LEVEL_HIGH;
+ odata &= ~bit;
+ intmode &= ~bit;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ intc_type = IRQ_TYPE_LEVEL_HIGH;
+ odata |= bit;
+ intmode &= ~bit;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ writel(odata, priv->base + GPIO_ODATA);
+ writel(intmode, priv->base + GPIO_INTMODE);
+ irq_set_irq_type(offset, intc_type);
+
+ ret = irq_chip_set_type_parent(d, type);
+err:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+
+static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
+ unsigned int child,
+ unsigned int child_type,
+ unsigned int *parent,
+ unsigned int *parent_type)
+{
+ /* Interrupts 0..15 mapped to interrupts 24..39 on the GIC */
+ if (child < 16) {
+ /* All these interrupts are level high in the CPU */
+ *parent_type = IRQ_TYPE_LEVEL_HIGH;
+ *parent = child + BASE_HW_IRQ;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+ unsigned int parent_hwirq,
+ unsigned int parent_type)
+{
+ struct irq_fwspec *fwspec;
+
+ fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
+ if (!fwspec)
+ return NULL;
+
+ fwspec->fwnode = chip->irq.parent_domain->fwnode;
+ fwspec->param_count = 3;
+ fwspec->param[0] = 0;
+ fwspec->param[1] = parent_hwirq;
+ fwspec->param[2] = parent_type;
+
+ return fwspec;
+}
+
+static int visconti_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct visconti_gpio *priv;
+ struct irq_chip *irq_chip;
+ struct gpio_irq_chip *girq;
+ struct irq_domain *parent;
+ struct device_node *irq_parent;
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->lock);
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ irq_parent = of_irq_find_parent(dev->of_node);
+ 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;
+ }
+
+ fwnode = of_node_to_fwnode(irq_parent);
+ of_node_put(irq_parent);
+
+ ret = bgpio_init(&priv->gpio_chip, dev, 4,
+ priv->base + GPIO_IDATA,
+ priv->base + GPIO_OSET,
+ priv->base + GPIO_OCLR,
+ priv->base + GPIO_DIR,
+ NULL,
+ 0);
+ if (ret) {
+ dev_err(dev, "unable to init generic GPIO\n");
+ return ret;
+ }
+
+ irq_chip = &priv->irq_chip;
+ irq_chip->name = dev_name(dev);
+ irq_chip->irq_mask = irq_chip_mask_parent;
+ irq_chip->irq_unmask = irq_chip_unmask_parent;
+ irq_chip->irq_eoi = irq_chip_eoi_parent;
+ irq_chip->irq_set_type = visconti_gpio_irq_set_type;
+ irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
+
+ girq = &priv->gpio_chip.irq;
+ girq->chip = irq_chip;
+ girq->fwnode = fwnode;
+ girq->parent_domain = parent;
+ girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq;
+ girq->populate_parent_alloc_arg = visconti_gpio_populate_parent_fwspec;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_level_irq;
+
+ ret = devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
+ if (ret) {
+ dev_err(dev, "failed to add GPIO chip\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return ret;
+}
+
+static const struct of_device_id visconti_gpio_of_match[] = {
+ { .compatible = "toshiba,gpio-tmpv7708", },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, visconti_gpio_of_match);
+
+static struct platform_driver visconti_gpio_driver = {
+ .probe = visconti_gpio_probe,
+ .driver = {
+ .name = "visconti_gpio",
+ .of_match_table = of_match_ptr(visconti_gpio_of_match),
+ }
+};
+module_platform_driver(visconti_gpio_driver);
+
+MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>");
+MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 3bf397b8dfbc..69713fd5485b 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -216,7 +216,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
c->direction_output = vx855gpio_direction_output;
c->get = vx855gpio_get;
c->set = vx855gpio_set;
- c->set_config = vx855gpio_set_config,
+ c->set_config = vx855gpio_set_config;
c->dbg_show = NULL;
c->base = 0;
c->ngpio = NR_VX855_GP;
diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c
index b5fbba5a783a..a19eeef6cf1e 100644
--- a/drivers/gpio/gpio-wcove.c
+++ b/drivers/gpio/gpio-wcove.c
@@ -73,6 +73,8 @@
enum ctrl_register {
CTRL_IN,
CTRL_OUT,
+ IRQ_STATUS,
+ IRQ_MASK,
};
/*
@@ -112,22 +114,29 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type)
return reg;
}
-static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio)
+static inline int to_ireg(int gpio, enum ctrl_register type, unsigned int *mask)
{
- unsigned int reg, mask;
+ unsigned int reg = type == IRQ_STATUS ? IRQ_STATUS_BASE : IRQ_MASK_BASE;
if (gpio < GROUP0_NR_IRQS) {
- reg = IRQ_MASK_BASE;
- mask = BIT(gpio % GROUP0_NR_IRQS);
+ reg += 0;
+ *mask = BIT(gpio);
} else {
- reg = IRQ_MASK_BASE + 1;
- mask = BIT((gpio - GROUP0_NR_IRQS) % GROUP1_NR_IRQS);
+ reg += 1;
+ *mask = BIT(gpio - GROUP0_NR_IRQS);
}
+ return reg;
+}
+
+static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio)
+{
+ unsigned int mask, reg = to_ireg(gpio, IRQ_MASK, &mask);
+
if (wg->set_irq_mask)
- regmap_update_bits(wg->regmap, reg, mask, mask);
+ regmap_set_bits(wg->regmap, reg, mask);
else
- regmap_update_bits(wg->regmap, reg, mask, 0);
+ regmap_clear_bits(wg->regmap, reg, mask);
}
static void wcove_update_irq_ctrl(struct wcove_gpio *wg, int gpio)
@@ -207,9 +216,9 @@ static void wcove_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
return;
if (value)
- regmap_update_bits(wg->regmap, reg, 1, 1);
+ regmap_set_bits(wg->regmap, reg, 1);
else
- regmap_update_bits(wg->regmap, reg, 1, 0);
+ regmap_clear_bits(wg->regmap, reg, 1);
}
static int wcove_gpio_set_config(struct gpio_chip *chip, unsigned int gpio,
@@ -324,7 +333,8 @@ static struct irq_chip wcove_irqchip = {
static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
{
struct wcove_gpio *wg = (struct wcove_gpio *)data;
- unsigned int pending, virq, gpio, mask, offset;
+ unsigned int virq, gpio;
+ unsigned long pending;
u8 p[2];
if (regmap_bulk_read(wg->regmap, IRQ_STATUS_BASE, p, 2)) {
@@ -339,15 +349,12 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
/* Iterate until no interrupt is pending */
while (pending) {
/* One iteration is for all pending bits */
- for_each_set_bit(gpio, (const unsigned long *)&pending,
- WCOVE_GPIO_NUM) {
- offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0;
- mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) :
- BIT(gpio);
+ for_each_set_bit(gpio, &pending, WCOVE_GPIO_NUM) {
+ unsigned int mask, reg = to_ireg(gpio, IRQ_STATUS, &mask);
+
virq = irq_find_mapping(wg->chip.irq.domain, gpio);
handle_nested_irq(virq);
- regmap_update_bits(wg->regmap, IRQ_STATUS_BASE + offset,
- mask, mask);
+ regmap_set_bits(wg->regmap, reg, mask);
}
/* Next iteration */
@@ -367,30 +374,26 @@ static void wcove_gpio_dbg_show(struct seq_file *s,
{
unsigned int ctlo, ctli, irq_mask, irq_status;
struct wcove_gpio *wg = gpiochip_get_data(chip);
- int gpio, offset, group, ret = 0;
+ int gpio, mask, ret = 0;
for (gpio = 0; gpio < WCOVE_GPIO_NUM; gpio++) {
- group = gpio < GROUP0_NR_IRQS ? 0 : 1;
ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_OUT), &ctlo);
ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_IN), &ctli);
- ret += regmap_read(wg->regmap, IRQ_MASK_BASE + group,
- &irq_mask);
- ret += regmap_read(wg->regmap, IRQ_STATUS_BASE + group,
- &irq_status);
+ ret += regmap_read(wg->regmap, to_ireg(gpio, IRQ_MASK, &mask), &irq_mask);
+ ret += regmap_read(wg->regmap, to_ireg(gpio, IRQ_STATUS, &mask), &irq_status);
if (ret) {
pr_err("Failed to read registers: ctrl out/in or irq status/mask\n");
break;
}
- offset = gpio % 8;
seq_printf(s, " gpio-%-2d %s %s %s %s ctlo=%2x,%s %s\n",
gpio, ctlo & CTLO_DIR_OUT ? "out" : "in ",
ctli & 0x1 ? "hi" : "lo",
ctli & CTLI_INTCNT_NE ? "fall" : " ",
ctli & CTLI_INTCNT_PE ? "rise" : " ",
ctlo,
- irq_mask & BIT(offset) ? "mask " : "unmask",
- irq_status & BIT(offset) ? "pending" : " ");
+ irq_mask & mask ? "mask " : "unmask",
+ irq_status & mask ? "pending" : " ");
}
}
@@ -434,7 +437,7 @@ static int wcove_gpio_probe(struct platform_device *pdev)
wg->chip.get_direction = wcove_gpio_get_direction;
wg->chip.get = wcove_gpio_get;
wg->chip.set = wcove_gpio_set;
- wg->chip.set_config = wcove_gpio_set_config,
+ wg->chip.set_config = wcove_gpio_set_config;
wg->chip.base = -1;
wg->chip.ngpio = WCOVE_VGPIO_NUM;
wg->chip.can_sleep = true;
@@ -473,14 +476,12 @@ static int wcove_gpio_probe(struct platform_device *pdev)
}
/* Enable GPIO0 interrupts */
- ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE, GPIO_IRQ0_MASK,
- 0x00);
+ ret = regmap_clear_bits(wg->regmap, IRQ_MASK_BASE + 0, GPIO_IRQ0_MASK);
if (ret)
return ret;
/* Enable GPIO1 interrupts */
- ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE + 1, GPIO_IRQ1_MASK,
- 0x00);
+ ret = regmap_clear_bits(wg->regmap, IRQ_MASK_BASE + 1, GPIO_IRQ1_MASK);
if (ret)
return ret;
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index be539381fd82..b411d3156e0b 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -10,10 +10,13 @@
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
/* Register Offset Definitions */
@@ -22,6 +25,11 @@
#define XGPIO_CHANNEL_OFFSET 0x8
+#define XGPIO_GIER_OFFSET 0x11c /* Global Interrupt Enable */
+#define XGPIO_GIER_IE BIT(31)
+#define XGPIO_IPISR_OFFSET 0x120 /* IP Interrupt Status */
+#define XGPIO_IPIER_OFFSET 0x128 /* IP Interrupt Enable */
+
/* Read/Write access to the GPIO registers */
#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86)
# define xgpio_readreg(offset) readl(offset)
@@ -36,9 +44,15 @@
* @gc: GPIO chip
* @regs: register block
* @gpio_width: GPIO width for every channel
- * @gpio_state: GPIO state shadow register
+ * @gpio_state: GPIO write state shadow register
+ * @gpio_last_irq_read: GPIO read state register from last interrupt
* @gpio_dir: GPIO direction shadow register
* @gpio_lock: Lock used for synchronization
+ * @irq: IRQ used by GPIO device
+ * @irqchip: IRQ chip
+ * @irq_enable: GPIO IRQ enable/disable bitfield
+ * @irq_rising_edge: GPIO IRQ rising edge enable/disable bitfield
+ * @irq_falling_edge: GPIO IRQ falling edge enable/disable bitfield
* @clk: clock resource for this driver
*/
struct xgpio_instance {
@@ -46,8 +60,14 @@ struct xgpio_instance {
void __iomem *regs;
unsigned int gpio_width[2];
u32 gpio_state[2];
+ u32 gpio_last_irq_read[2];
u32 gpio_dir[2];
- spinlock_t gpio_lock[2];
+ spinlock_t gpio_lock; /* For serializing operations */
+ int irq;
+ struct irq_chip irqchip;
+ u32 irq_enable[2];
+ u32 irq_rising_edge[2];
+ u32 irq_falling_edge[2];
struct clk *clk;
};
@@ -113,7 +133,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
- spin_lock_irqsave(&chip->gpio_lock[index], flags);
+ spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write to GPIO signal and set its direction to output */
if (val)
@@ -124,7 +144,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
- spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
}
/**
@@ -144,7 +164,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
int index = xgpio_index(chip, 0);
int offset, i;
- spin_lock_irqsave(&chip->gpio_lock[index], flags);
+ spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write to GPIO signals */
for (i = 0; i < gc->ngpio; i++) {
@@ -155,9 +175,9 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
index * XGPIO_CHANNEL_OFFSET,
chip->gpio_state[index]);
- spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
index = xgpio_index(chip, i);
- spin_lock_irqsave(&chip->gpio_lock[index], flags);
+ spin_lock_irqsave(&chip->gpio_lock, flags);
}
if (__test_and_clear_bit(i, mask)) {
offset = xgpio_offset(chip, i);
@@ -171,7 +191,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
index * XGPIO_CHANNEL_OFFSET, chip->gpio_state[index]);
- spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
}
/**
@@ -190,14 +210,14 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
- spin_lock_irqsave(&chip->gpio_lock[index], flags);
+ spin_lock_irqsave(&chip->gpio_lock, flags);
/* Set the GPIO bit in shadow register and set direction as input */
chip->gpio_dir[index] |= BIT(offset);
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
- spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
return 0;
}
@@ -221,7 +241,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
int index = xgpio_index(chip, gpio);
int offset = xgpio_offset(chip, gpio);
- spin_lock_irqsave(&chip->gpio_lock[index], flags);
+ spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write state of GPIO signal */
if (val)
@@ -236,7 +256,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
- spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
return 0;
}
@@ -259,6 +279,39 @@ static void xgpio_save_regs(struct xgpio_instance *chip)
chip->gpio_dir[1]);
}
+static int xgpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ int ret;
+
+ ret = pm_runtime_get_sync(chip->parent);
+ /*
+ * If the device is already active pm_runtime_get() will return 1 on
+ * success, but gpio_request still needs to return 0.
+ */
+ return ret < 0 ? ret : 0;
+}
+
+static void xgpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ pm_runtime_put(chip->parent);
+}
+
+static int __maybe_unused xgpio_suspend(struct device *dev)
+{
+ struct xgpio_instance *gpio = dev_get_drvdata(dev);
+ struct irq_data *data = irq_get_irq_data(gpio->irq);
+
+ if (!data) {
+ dev_err(dev, "irq_get_irq_data() failed\n");
+ return -EINVAL;
+ }
+
+ if (!irqd_is_wakeup_set(data))
+ return pm_runtime_force_suspend(dev);
+
+ return 0;
+}
+
/**
* xgpio_remove - Remove method for the GPIO device.
* @pdev: pointer to the platform device
@@ -271,12 +324,224 @@ static int xgpio_remove(struct platform_device *pdev)
{
struct xgpio_instance *gpio = platform_get_drvdata(pdev);
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(gpio->clk);
return 0;
}
/**
+ * xgpio_irq_ack - Acknowledge a child GPIO interrupt.
+ * @irq_data: per IRQ and chip data passed down to chip functions
+ * This currently does nothing, but irq_ack is unconditionally called by
+ * handle_edge_irq and therefore must be defined.
+ */
+static void xgpio_irq_ack(struct irq_data *irq_data)
+{
+}
+
+static int __maybe_unused xgpio_resume(struct device *dev)
+{
+ struct xgpio_instance *gpio = dev_get_drvdata(dev);
+ struct irq_data *data = irq_get_irq_data(gpio->irq);
+
+ if (!data) {
+ dev_err(dev, "irq_get_irq_data() failed\n");
+ return -EINVAL;
+ }
+
+ if (!irqd_is_wakeup_set(data))
+ return pm_runtime_force_resume(dev);
+
+ return 0;
+}
+
+static int __maybe_unused xgpio_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct xgpio_instance *gpio = platform_get_drvdata(pdev);
+
+ clk_disable(gpio->clk);
+
+ return 0;
+}
+
+static int __maybe_unused xgpio_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct xgpio_instance *gpio = platform_get_drvdata(pdev);
+
+ return clk_enable(gpio->clk);
+}
+
+static const struct dev_pm_ops xgpio_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(xgpio_suspend, xgpio_resume)
+ SET_RUNTIME_PM_OPS(xgpio_runtime_suspend,
+ xgpio_runtime_resume, NULL)
+};
+
+/**
+ * xgpio_irq_mask - Write the specified signal of the GPIO device.
+ * @irq_data: per IRQ and chip data passed down to chip functions
+ */
+static void xgpio_irq_mask(struct irq_data *irq_data)
+{
+ unsigned long flags;
+ struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
+ int irq_offset = irqd_to_hwirq(irq_data);
+ int index = xgpio_index(chip, irq_offset);
+ int offset = xgpio_offset(chip, irq_offset);
+
+ spin_lock_irqsave(&chip->gpio_lock, flags);
+
+ chip->irq_enable[index] &= ~BIT(offset);
+
+ if (!chip->irq_enable[index]) {
+ /* Disable per channel interrupt */
+ u32 temp = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET);
+
+ temp &= ~BIT(index);
+ xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp);
+ }
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
+}
+
+/**
+ * xgpio_irq_unmask - Write the specified signal of the GPIO device.
+ * @irq_data: per IRQ and chip data passed down to chip functions
+ */
+static void xgpio_irq_unmask(struct irq_data *irq_data)
+{
+ unsigned long flags;
+ struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
+ int irq_offset = irqd_to_hwirq(irq_data);
+ int index = xgpio_index(chip, irq_offset);
+ int offset = xgpio_offset(chip, irq_offset);
+ u32 old_enable = chip->irq_enable[index];
+
+ spin_lock_irqsave(&chip->gpio_lock, flags);
+
+ chip->irq_enable[index] |= BIT(offset);
+
+ if (!old_enable) {
+ /* Clear any existing per-channel interrupts */
+ u32 val = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET) &
+ BIT(index);
+
+ if (val)
+ xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, val);
+
+ /* Update GPIO IRQ read data before enabling interrupt*/
+ val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
+ index * XGPIO_CHANNEL_OFFSET);
+ chip->gpio_last_irq_read[index] = val;
+
+ /* Enable per channel interrupt */
+ val = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET);
+ val |= BIT(index);
+ xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, val);
+ }
+
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
+}
+
+/**
+ * xgpio_set_irq_type - Write the specified signal of the GPIO device.
+ * @irq_data: Per IRQ and chip data passed down to chip functions
+ * @type: Interrupt type that is to be set for the gpio pin
+ *
+ * Return:
+ * 0 if interrupt type is supported otherwise -EINVAL
+ */
+static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
+{
+ struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
+ int irq_offset = irqd_to_hwirq(irq_data);
+ int index = xgpio_index(chip, irq_offset);
+ int offset = xgpio_offset(chip, irq_offset);
+
+ /*
+ * The Xilinx GPIO hardware provides a single interrupt status
+ * indication for any state change in a given GPIO channel (bank).
+ * Therefore, only rising edge or falling edge triggers are
+ * supported.
+ */
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_BOTH:
+ chip->irq_rising_edge[index] |= BIT(offset);
+ chip->irq_falling_edge[index] |= BIT(offset);
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ chip->irq_rising_edge[index] |= BIT(offset);
+ chip->irq_falling_edge[index] &= ~BIT(offset);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ chip->irq_rising_edge[index] &= ~BIT(offset);
+ chip->irq_falling_edge[index] |= BIT(offset);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ irq_set_handler_locked(irq_data, handle_edge_irq);
+ return 0;
+}
+
+/**
+ * xgpio_irqhandler - Gpio interrupt service routine
+ * @desc: Pointer to interrupt description
+ */
+static void xgpio_irqhandler(struct irq_desc *desc)
+{
+ struct xgpio_instance *chip = irq_desc_get_handler_data(desc);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ u32 num_channels = chip->gpio_width[1] ? 2 : 1;
+ u32 offset = 0, index;
+ u32 status = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET);
+
+ xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, status);
+
+ chained_irq_enter(irqchip, desc);
+ for (index = 0; index < num_channels; index++) {
+ if ((status & BIT(index))) {
+ unsigned long rising_events, falling_events, all_events;
+ unsigned long flags;
+ u32 data, bit;
+ unsigned int irq;
+
+ spin_lock_irqsave(&chip->gpio_lock, flags);
+ data = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
+ index * XGPIO_CHANNEL_OFFSET);
+ rising_events = data &
+ ~chip->gpio_last_irq_read[index] &
+ chip->irq_enable[index] &
+ chip->irq_rising_edge[index];
+ falling_events = ~data &
+ chip->gpio_last_irq_read[index] &
+ chip->irq_enable[index] &
+ chip->irq_falling_edge[index];
+ dev_dbg(chip->gc.parent,
+ "IRQ chan %u rising 0x%lx falling 0x%lx\n",
+ index, rising_events, falling_events);
+ all_events = rising_events | falling_events;
+ chip->gpio_last_irq_read[index] = data;
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
+
+ for_each_set_bit(bit, &all_events, 32) {
+ irq = irq_find_mapping(chip->gc.irq.domain,
+ offset + bit);
+ generic_handle_irq(irq);
+ }
+ }
+ offset += chip->gpio_width[index];
+ }
+
+ chained_irq_exit(irqchip, desc);
+}
+
+/**
* xgpio_of_probe - Probe method for the GPIO device.
* @pdev: pointer to the platform device
*
@@ -289,7 +554,10 @@ static int xgpio_probe(struct platform_device *pdev)
struct xgpio_instance *chip;
int status = 0;
struct device_node *np = pdev->dev.of_node;
- u32 is_dual;
+ u32 is_dual = 0;
+ u32 cells = 2;
+ struct gpio_irq_chip *girq;
+ u32 temp;
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -305,6 +573,15 @@ static int xgpio_probe(struct platform_device *pdev)
if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0]))
chip->gpio_dir[0] = 0xFFFFFFFF;
+ /* Update cells with gpio-cells value */
+ if (of_property_read_u32(np, "#gpio-cells", &cells))
+ dev_dbg(&pdev->dev, "Missing gpio-cells property\n");
+
+ if (cells != 2) {
+ dev_err(&pdev->dev, "#gpio-cells mismatch\n");
+ return -EINVAL;
+ }
+
/*
* Check device node and parent device node for device width
* and assume default width of 32
@@ -312,7 +589,10 @@ static int xgpio_probe(struct platform_device *pdev)
if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0]))
chip->gpio_width[0] = 32;
- spin_lock_init(&chip->gpio_lock[0]);
+ if (chip->gpio_width[0] > 32)
+ return -EINVAL;
+
+ spin_lock_init(&chip->gpio_lock);
if (of_property_read_u32(np, "xlnx,is-dual", &is_dual))
is_dual = 0;
@@ -336,7 +616,8 @@ static int xgpio_probe(struct platform_device *pdev)
&chip->gpio_width[1]))
chip->gpio_width[1] = 32;
- spin_lock_init(&chip->gpio_lock[1]);
+ if (chip->gpio_width[1] > 32)
+ return -EINVAL;
}
chip->gc.base = -1;
@@ -344,8 +625,11 @@ static int xgpio_probe(struct platform_device *pdev)
chip->gc.parent = &pdev->dev;
chip->gc.direction_input = xgpio_dir_in;
chip->gc.direction_output = xgpio_dir_out;
+ chip->gc.of_gpio_n_cells = cells;
chip->gc.get = xgpio_get;
chip->gc.set = xgpio_set;
+ chip->gc.request = xgpio_request;
+ chip->gc.free = xgpio_free;
chip->gc.set_multiple = xgpio_set_multiple;
chip->gc.label = dev_name(&pdev->dev);
@@ -357,28 +641,68 @@ static int xgpio_probe(struct platform_device *pdev)
}
chip->clk = devm_clk_get_optional(&pdev->dev, NULL);
- if (IS_ERR(chip->clk)) {
- if (PTR_ERR(chip->clk) != -EPROBE_DEFER)
- dev_dbg(&pdev->dev, "Input clock not found\n");
- return PTR_ERR(chip->clk);
- }
+ if (IS_ERR(chip->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(chip->clk), "input clock not found.\n");
status = clk_prepare_enable(chip->clk);
if (status < 0) {
dev_err(&pdev->dev, "Failed to prepare clk\n");
return status;
}
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
xgpio_save_regs(chip);
+ chip->irq = platform_get_irq_optional(pdev, 0);
+ if (chip->irq <= 0)
+ goto skip_irq;
+
+ chip->irqchip.name = "gpio-xilinx";
+ chip->irqchip.irq_ack = xgpio_irq_ack;
+ chip->irqchip.irq_mask = xgpio_irq_mask;
+ chip->irqchip.irq_unmask = xgpio_irq_unmask;
+ chip->irqchip.irq_set_type = xgpio_set_irq_type;
+
+ /* Disable per-channel interrupts */
+ xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, 0);
+ /* Clear any existing per-channel interrupts */
+ temp = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET);
+ xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, temp);
+ /* Enable global interrupts */
+ xgpio_writereg(chip->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE);
+
+ girq = &chip->gc.irq;
+ girq->chip = &chip->irqchip;
+ girq->parent_handler = xgpio_irqhandler;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(&pdev->dev, 1,
+ sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents) {
+ status = -ENOMEM;
+ goto err_pm_put;
+ }
+ girq->parents[0] = chip->irq;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+
+skip_irq:
status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
if (status) {
dev_err(&pdev->dev, "failed to add GPIO chip\n");
- clk_disable_unprepare(chip->clk);
- return status;
+ goto err_pm_put;
}
+ pm_runtime_put(&pdev->dev);
return 0;
+
+err_pm_put:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ clk_disable_unprepare(chip->clk);
+ return status;
}
static const struct of_device_id xgpio_of_match[] = {
@@ -394,6 +718,7 @@ static struct platform_driver xgpio_plat_driver = {
.driver = {
.name = "gpio-xilinx",
.of_match_table = xgpio_of_match,
+ .pm = &xgpio_dev_pm_ops,
},
};
diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c
deleted file mode 100644
index 64bfb722756a..000000000000
--- a/drivers/gpio/gpio-zx.c
+++ /dev/null
@@ -1,289 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ZTE ZX296702 GPIO driver
- *
- * Author: Jun Nie <jun.nie@linaro.org>
- *
- * Copyright (C) 2015 Linaro Ltd.
- */
-#include <linux/bitops.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/irqchip/chained_irq.h>
-#include <linux/init.h>
-#include <linux/of.h>
-#include <linux/pinctrl/consumer.h>
-#include <linux/platform_device.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-
-#define ZX_GPIO_DIR 0x00
-#define ZX_GPIO_IVE 0x04
-#define ZX_GPIO_IV 0x08
-#define ZX_GPIO_IEP 0x0C
-#define ZX_GPIO_IEN 0x10
-#define ZX_GPIO_DI 0x14
-#define ZX_GPIO_DO1 0x18
-#define ZX_GPIO_DO0 0x1C
-#define ZX_GPIO_DO 0x20
-
-#define ZX_GPIO_IM 0x28
-#define ZX_GPIO_IE 0x2C
-
-#define ZX_GPIO_MIS 0x30
-#define ZX_GPIO_IC 0x34
-
-#define ZX_GPIO_NR 16
-
-struct zx_gpio {
- raw_spinlock_t lock;
-
- void __iomem *base;
- struct gpio_chip gc;
-};
-
-static int zx_direction_input(struct gpio_chip *gc, unsigned offset)
-{
- struct zx_gpio *chip = gpiochip_get_data(gc);
- unsigned long flags;
- u16 gpiodir;
-
- if (offset >= gc->ngpio)
- return -EINVAL;
-
- raw_spin_lock_irqsave(&chip->lock, flags);
- gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR);
- gpiodir &= ~BIT(offset);
- writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR);
- raw_spin_unlock_irqrestore(&chip->lock, flags);
-
- return 0;
-}
-
-static int zx_direction_output(struct gpio_chip *gc, unsigned offset,
- int value)
-{
- struct zx_gpio *chip = gpiochip_get_data(gc);
- unsigned long flags;
- u16 gpiodir;
-
- if (offset >= gc->ngpio)
- return -EINVAL;
-
- raw_spin_lock_irqsave(&chip->lock, flags);
- gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR);
- gpiodir |= BIT(offset);
- writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR);
-
- if (value)
- writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1);
- else
- writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0);
- raw_spin_unlock_irqrestore(&chip->lock, flags);
-
- return 0;
-}
-
-static int zx_get_value(struct gpio_chip *gc, unsigned offset)
-{
- struct zx_gpio *chip = gpiochip_get_data(gc);
-
- return !!(readw_relaxed(chip->base + ZX_GPIO_DI) & BIT(offset));
-}
-
-static void zx_set_value(struct gpio_chip *gc, unsigned offset, int value)
-{
- struct zx_gpio *chip = gpiochip_get_data(gc);
-
- if (value)
- writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1);
- else
- writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0);
-}
-
-static int zx_irq_type(struct irq_data *d, unsigned trigger)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct zx_gpio *chip = gpiochip_get_data(gc);
- int offset = irqd_to_hwirq(d);
- unsigned long flags;
- u16 gpiois, gpioi_epos, gpioi_eneg, gpioiev;
- u16 bit = BIT(offset);
-
- if (offset < 0 || offset >= ZX_GPIO_NR)
- return -EINVAL;
-
- raw_spin_lock_irqsave(&chip->lock, flags);
-
- gpioiev = readw_relaxed(chip->base + ZX_GPIO_IV);
- gpiois = readw_relaxed(chip->base + ZX_GPIO_IVE);
- gpioi_epos = readw_relaxed(chip->base + ZX_GPIO_IEP);
- gpioi_eneg = readw_relaxed(chip->base + ZX_GPIO_IEN);
-
- if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- gpiois |= bit;
- if (trigger & IRQ_TYPE_LEVEL_HIGH)
- gpioiev |= bit;
- else
- gpioiev &= ~bit;
- } else
- gpiois &= ~bit;
-
- if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
- gpioi_epos |= bit;
- gpioi_eneg |= bit;
- } else {
- if (trigger & IRQ_TYPE_EDGE_RISING) {
- gpioi_epos |= bit;
- gpioi_eneg &= ~bit;
- } else if (trigger & IRQ_TYPE_EDGE_FALLING) {
- gpioi_eneg |= bit;
- gpioi_epos &= ~bit;
- }
- }
-
- writew_relaxed(gpiois, chip->base + ZX_GPIO_IVE);
- writew_relaxed(gpioi_epos, chip->base + ZX_GPIO_IEP);
- writew_relaxed(gpioi_eneg, chip->base + ZX_GPIO_IEN);
- writew_relaxed(gpioiev, chip->base + ZX_GPIO_IV);
- raw_spin_unlock_irqrestore(&chip->lock, flags);
-
- return 0;
-}
-
-static void zx_irq_handler(struct irq_desc *desc)
-{
- unsigned long pending;
- int offset;
- struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct zx_gpio *chip = gpiochip_get_data(gc);
- struct irq_chip *irqchip = irq_desc_get_chip(desc);
-
- chained_irq_enter(irqchip, desc);
-
- pending = readw_relaxed(chip->base + ZX_GPIO_MIS);
- writew_relaxed(pending, chip->base + ZX_GPIO_IC);
- if (pending) {
- for_each_set_bit(offset, &pending, ZX_GPIO_NR)
- generic_handle_irq(irq_find_mapping(gc->irq.domain,
- offset));
- }
-
- chained_irq_exit(irqchip, desc);
-}
-
-static void zx_irq_mask(struct irq_data *d)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct zx_gpio *chip = gpiochip_get_data(gc);
- u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR);
- u16 gpioie;
-
- raw_spin_lock(&chip->lock);
- gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) | mask;
- writew_relaxed(gpioie, chip->base + ZX_GPIO_IM);
- gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) & ~mask;
- writew_relaxed(gpioie, chip->base + ZX_GPIO_IE);
- raw_spin_unlock(&chip->lock);
-}
-
-static void zx_irq_unmask(struct irq_data *d)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct zx_gpio *chip = gpiochip_get_data(gc);
- u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR);
- u16 gpioie;
-
- raw_spin_lock(&chip->lock);
- gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) & ~mask;
- writew_relaxed(gpioie, chip->base + ZX_GPIO_IM);
- gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) | mask;
- writew_relaxed(gpioie, chip->base + ZX_GPIO_IE);
- raw_spin_unlock(&chip->lock);
-}
-
-static struct irq_chip zx_irqchip = {
- .name = "zx-gpio",
- .irq_mask = zx_irq_mask,
- .irq_unmask = zx_irq_unmask,
- .irq_set_type = zx_irq_type,
-};
-
-static int zx_gpio_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct zx_gpio *chip;
- struct gpio_irq_chip *girq;
- int irq, id, ret;
-
- chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
-
- chip->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(chip->base))
- return PTR_ERR(chip->base);
-
- id = of_alias_get_id(dev->of_node, "gpio");
-
- raw_spin_lock_init(&chip->lock);
- chip->gc.request = gpiochip_generic_request;
- chip->gc.free = gpiochip_generic_free;
- chip->gc.direction_input = zx_direction_input;
- chip->gc.direction_output = zx_direction_output;
- chip->gc.get = zx_get_value;
- chip->gc.set = zx_set_value;
- chip->gc.base = ZX_GPIO_NR * id;
- chip->gc.ngpio = ZX_GPIO_NR;
- chip->gc.label = dev_name(dev);
- chip->gc.parent = dev;
- chip->gc.owner = THIS_MODULE;
-
- /*
- * irq_chip support
- */
- writew_relaxed(0xffff, chip->base + ZX_GPIO_IM);
- writew_relaxed(0, chip->base + ZX_GPIO_IE);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
- girq = &chip->gc.irq;
- girq->chip = &zx_irqchip;
- girq->parent_handler = zx_irq_handler;
- girq->num_parents = 1;
- girq->parents = devm_kcalloc(&pdev->dev, 1,
- sizeof(*girq->parents),
- GFP_KERNEL);
- if (!girq->parents)
- return -ENOMEM;
- girq->parents[0] = irq;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_simple_irq;
-
- ret = gpiochip_add_data(&chip->gc, chip);
- if (ret)
- return ret;
-
- platform_set_drvdata(pdev, chip);
- dev_info(dev, "ZX GPIO chip registered\n");
-
- return 0;
-}
-
-static const struct of_device_id zx_gpio_match[] = {
- {
- .compatible = "zte,zx296702-gpio",
- },
- { },
-};
-
-static struct platform_driver zx_gpio_driver = {
- .probe = zx_gpio_probe,
- .driver = {
- .name = "zx_gpio",
- .of_match_table = of_match_ptr(zx_gpio_match),
- },
-};
-builtin_platform_driver(zx_gpio_driver)
diff --git a/drivers/pinctrl/visconti/pinctrl-common.c b/drivers/pinctrl/visconti/pinctrl-common.c
index 0cb10b7b4430..21c7e0d18fea 100644
--- a/drivers/pinctrl/visconti/pinctrl-common.c
+++ b/drivers/pinctrl/visconti/pinctrl-common.c
@@ -245,11 +245,34 @@ static int visconti_set_mux(struct pinctrl_dev *pctldev,
return 0;
}
+static int visconti_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int pin)
+{
+ struct visconti_pinctrl *priv = pinctrl_dev_get_drvdata(pctldev);
+ const struct visconti_mux *gpio_mux = &priv->devdata->gpio_mux[pin];
+ unsigned long flags;
+ unsigned int val;
+
+ dev_dbg(priv->dev, "%s: pin = %d\n", __func__, pin);
+
+ /* update mux */
+ spin_lock_irqsave(&priv->lock, flags);
+ val = readl(priv->base + gpio_mux->offset);
+ val &= ~gpio_mux->mask;
+ val |= gpio_mux->val;
+ writel(val, priv->base + gpio_mux->offset);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
static const struct pinmux_ops visconti_pinmux_ops = {
.get_functions_count = visconti_get_functions_count,
.get_function_name = visconti_get_function_name,
.get_function_groups = visconti_get_function_groups,
.set_mux = visconti_set_mux,
+ .gpio_request_enable = visconti_gpio_request_enable,
.strict = true,
};