diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-22 21:00:46 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-22 21:00:46 +0300 |
commit | 882d6edfc45cd2b6e33cf973eab9a1ae1dbad5d1 (patch) | |
tree | 034ebc487adeb29cef2c546b5e0b61d70a3bc339 /drivers/gpio | |
parent | 0328b5f2ef4af8ba060e64baa928c94037e7308f (diff) | |
parent | a8002a35935aaefcd6a42ad3289f62bab947f2ca (diff) | |
download | linux-882d6edfc45cd2b6e33cf973eab9a1ae1dbad5d1.tar.xz |
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/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 30 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpio/gpio-aggregator.c | 40 | ||||
-rw-r--r-- | drivers/gpio/gpio-bd70528.c | 59 | ||||
-rw-r--r-- | drivers/gpio/gpio-bd71828.c | 39 | ||||
-rw-r--r-- | drivers/gpio/gpio-ep93xx.c | 28 | ||||
-rw-r--r-- | drivers/gpio/gpio-max77620.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-merrifield.c | 5 | ||||
-rw-r--r-- | drivers/gpio/gpio-mvebu.c | 148 | ||||
-rw-r--r-- | drivers/gpio/gpio-pca953x.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-pcf857x.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-rcar.c | 85 | ||||
-rw-r--r-- | drivers/gpio/gpio-sl28cpld.c | 4 | ||||
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 263 | ||||
-rw-r--r-- | drivers/gpio/gpio-tegra186.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-visconti.c | 218 | ||||
-rw-r--r-- | drivers/gpio/gpio-vx855.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-wcove.c | 65 | ||||
-rw-r--r-- | drivers/gpio/gpio-xilinx.c | 369 | ||||
-rw-r--r-- | drivers/gpio/gpio-zx.c | 289 |
20 files changed, 1015 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) |