diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-12-01 17:56:50 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-12-01 17:56:50 -0800 |
commit | 99a0d9f5e87352c4bd8d01bc9b39f7091c12e4d4 (patch) | |
tree | db8608677da8ec882f495bfb3885727f2a5b5d40 | |
parent | 37323918cac24c89facdc009b0566b25cce94ea5 (diff) | |
parent | 41c4616bb81ff9b2efd981453f2c5d8f57d0c0b8 (diff) |
Merge tag 'gpio-v5.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij:
"This is the bulk of GPIO changes for the v5.5 kernel cycle
Core changes:
- Expose pull up/down flags for the GPIO character device to
userspace.
After clear input from the RaspberryPi and Beagle communities, it
has been established that prototyping, industrial automation and
make communities strongly need this feature, and as we want people
to use the character device, we have implemented the simple pull
up/down interface for GPIO lines.
This means we can specify that a (chip-specific) pull up/down
resistor can be enabled, but does not offer fine-grained control
such as cases where the resistance of the same pull resistor can be
controlled (yet).
- Introduce devm_fwnode_gpiod_get_index() and start to phase out the
old symbol devm_fwnode_get_index_gpiod_from_child().
- A bit of documentation clean-up work.
- Introduce a define for GPIO line directions and deploy it in all
GPIO drivers in the drivers/gpio directory.
- Add a special callback to populate pin ranges when cooperating with
the pin control subsystem and registering ranges as part of adding
a gpiolib driver and a gpio_irq_chip driver at the same time. This
is also deployed in the Intel Merrifield driver.
New drivers:
- RDA Micro GPIO controller.
- XGS-iproc GPIO driver.
Driver improvements:
- Wake event and debounce support on the Tegra 186 driver.
- Finalize the Aspeed SGPIO driver.
- MPC8xxx uses a normal IRQ handler rather than a chained handler"
* tag 'gpio-v5.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (64 commits)
gpio: Add TODO item for regmap helper
Documentation: gpio: driver.rst: Fix warnings
gpio: of: Fix bogus reference to gpiod_get_count()
gpiolib: Grammar s/manager/managed/
gpio: lynxpoint: Setup correct IRQ handlers
MAINTAINERS: Replace my email by one @kernel.org
gpiolib: acpi: Make acpi_gpiochip_alloc_event always return AE_OK
gpio/mpc8xxx: fix qoriq GPIO reading
gpio: mpc8xxx: Don't overwrite default irq_set_type callback
gpiolib: acpi: Print pin number on acpi_gpiochip_alloc_event errors
gpiolib: fix coding style in gpiod_hog()
drm/bridge: ti-tfp410: switch to using fwnode_gpiod_get_index()
gpio: merrifield: Pass irqchip when adding gpiochip
gpio: merrifield: Add GPIO <-> pin mapping ranges via callback
gpiolib: Introduce ->add_pin_ranges() callback
gpio: mmio: remove untrue leftover comment
gpio: em: Use platform_get_irq() to obtain interrupts
gpio: tegra186: Add debounce support
gpio: tegra186: Program interrupt route mapping
gpio: tegra186: Derive register offsets from bank/port
...
88 files changed, 1849 insertions, 598 deletions
diff --git a/Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml b/Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml new file mode 100644 index 000000000000..64e279a4bc10 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/brcm,xgs-iproc-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom XGS iProc GPIO controller + +maintainers: + - Chris Packham <chris.packham@alliedtelesis.co.nz> + +description: | + This controller is the Chip Common A GPIO present on a number of Broadcom + switch ASICs with integrated SoCs. + +properties: + compatible: + const: brcm,iproc-gpio-cca + + reg: + items: + - description: the I/O address containing the GPIO controller + registers. + - description: the I/O address containing the Chip Common A interrupt + registers. + + gpio-controller: true + + '#gpio-cells': + const: 2 + + ngpios: + minimum: 0 + maximum: 32 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - "#gpio-cells" + - gpio-controller + +dependencies: + interrupt-controller: [ interrupts ] + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + gpio@18000060 { + compatible = "brcm,iproc-gpio-cca"; + #gpio-cells = <2>; + reg = <0x18000060 0x50>, + <0x18000000 0x50>; + ngpios = <12>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; + }; + + +... diff --git a/Documentation/devicetree/bindings/gpio/gpio-rda.yaml b/Documentation/devicetree/bindings/gpio/gpio-rda.yaml new file mode 100644 index 000000000000..6ece555f074f --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-rda.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/gpio-rda.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RDA Micro GPIO controller + +maintainers: + - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + +properties: + compatible: + const: rda,8810pl-gpio + + reg: + maxItems: 1 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + ngpios: + description: + Number of available gpios in a bank. + minimum: 1 + maximum: 32 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - gpio-controller + - "#gpio-cells" + - ngpios + - interrupt-controller + - "#interrupt-cells" + - interrupts + +additionalProperties: false + +... diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index f3f2c468c1b6..41e5fed0f842 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -8,6 +8,7 @@ Required Properties: - "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller. - "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller. - "renesas,gpio-r8a774a1": for R8A774A1 (RZ/G2M) compatible GPIO controller. + - "renesas,gpio-r8a774b1": for R8A774B1 (RZ/G2N) compatible GPIO controller. - "renesas,gpio-r8a774c0": for R8A774C0 (RZ/G2E) compatible GPIO controller. - "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller. - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller. diff --git a/Documentation/driver-api/bt8xxgpio.rst b/Documentation/driver-api/gpio/bt8xxgpio.rst index a845feb074de..d7e75f1234e7 100644 --- a/Documentation/driver-api/bt8xxgpio.rst +++ b/Documentation/driver-api/gpio/bt8xxgpio.rst @@ -2,7 +2,7 @@ A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio) =================================================================== -For advanced documentation, see http://www.bu3sch.de/btgpio.php +For advanced documentation, see https://bues.ch/cms/unmaintained/btgpio.html A generic digital 24-port PCI GPIO card can be built out of an ordinary Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The diff --git a/Documentation/driver-api/gpio/driver.rst b/Documentation/driver-api/gpio/driver.rst index 3fdb32422f8a..10ef357ef658 100644 --- a/Documentation/driver-api/gpio/driver.rst +++ b/Documentation/driver-api/gpio/driver.rst @@ -5,7 +5,7 @@ GPIO Driver Interface This document serves as a guide for writers of GPIO chip drivers. Each GPIO controller driver needs to include the following header, which defines -the structures used to define a GPIO driver: +the structures used to define a GPIO driver:: #include <linux/gpio/driver.h> @@ -398,12 +398,15 @@ provided. A big portion of overhead code will be managed by gpiolib, under the assumption that your interrupts are 1-to-1-mapped to the GPIO line index: - GPIO line offset Hardware IRQ - 0 0 - 1 1 - 2 2 - ... ... - ngpio-1 ngpio-1 +.. csv-table:: + :header: GPIO line offset, Hardware IRQ + + 0,0 + 1,1 + 2,2 + ...,... + ngpio-1, ngpio-1 + If some GPIO lines do not have corresponding IRQs, the bitmask valid_mask and the flag need_valid_mask in gpio_irq_chip can be used to mask off some @@ -413,7 +416,9 @@ The preferred way to set up the helpers is to fill in the struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip. If you do this, the additional irq_chip will be set up by gpiolib at the same time as setting up the rest of the GPIO functionality. The following -is a typical example of a cascaded interrupt handler using gpio_irq_chip: +is a typical example of a cascaded interrupt handler using gpio_irq_chip:: + +.. code-block:: c /* Typical state container with dynamic irqchip */ struct my_gpio { @@ -448,7 +453,9 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip: return devm_gpiochip_add_data(dev, &g->gc, g); The helper support using hierarchical interrupt controllers as well. -In this case the typical set-up will look like this: +In this case the typical set-up will look like this:: + +.. code-block:: c /* Typical state container with dynamic irqchip */ struct my_gpio { diff --git a/Documentation/driver-api/gpio/index.rst b/Documentation/driver-api/gpio/index.rst index c5b8467f9104..5b61032aa4ea 100644 --- a/Documentation/driver-api/gpio/index.rst +++ b/Documentation/driver-api/gpio/index.rst @@ -13,6 +13,7 @@ Contents: board drivers-on-gpio legacy + bt8xxgpio Core ==== diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index d0efa35052e3..3bcd9a13fbb3 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -70,7 +70,6 @@ available subsections can be seen below. fpga/index acpi/index backlight/lp855x-driver.rst - bt8xxgpio connector console dcdbas diff --git a/MAINTAINERS b/MAINTAINERS index be5ed39b41fa..b469f0a289b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2183,9 +2183,11 @@ L: linux-unisoc@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/boot/dts/rda8810pl-* F: drivers/clocksource/timer-rda.c +F: drivers/gpio/gpio-rda.c F: drivers/irqchip/irq-rda-intc.c F: drivers/tty/serial/rda-uart.c F: Documentation/devicetree/bindings/arm/rda.yaml +F: Documentation/devicetree/bindings/gpio/gpio-rda.yaml F: Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt F: Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt F: Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt @@ -8329,7 +8331,7 @@ F: Documentation/fb/intelfb.rst F: drivers/video/fbdev/intelfb/ INTEL GPIO DRIVERS -M: Andy Shevchenko <andriy.shevchenko@linux.intel.com> +M: Andy Shevchenko <andy@kernel.org> L: linux-gpio@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git @@ -8483,7 +8485,7 @@ F: arch/x86/include/asm/intel_pmc_ipc.h F: arch/x86/include/asm/intel_punit_ipc.h INTEL PMIC GPIO DRIVERS -M: Andy Shevchenko <andriy.shevchenko@linux.intel.com> +M: Andy Shevchenko <andy@kernel.org> S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git F: drivers/gpio/gpio-*cove.c diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index bfc617cc8ac5..948d2c6557f3 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -11,8 +11,8 @@ #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/ahci_platform.h> +#include <linux/gpio/consumer.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/libata.h> @@ -100,7 +100,7 @@ struct imx_ahci_priv { struct clk *phy_pclk0; struct clk *phy_pclk1; void __iomem *phy_base; - int clkreq_gpio; + struct gpio_desc *clkreq_gpiod; struct regmap *gpr; bool no_device; bool first_time; @@ -980,7 +980,6 @@ static struct scsi_host_template ahci_platform_sht = { static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv) { - int ret; struct resource *phy_res; struct platform_device *pdev = imxpriv->ahci_pdev; struct device_node *np = dev->of_node; @@ -1033,20 +1032,12 @@ static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv) } /* Fetch GPIO, then enable the external OSC */ - imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0); - if (gpio_is_valid(imxpriv->clkreq_gpio)) { - ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio, - GPIOF_OUT_INIT_LOW, - "SATA CLKREQ"); - if (ret == -EBUSY) { - dev_info(dev, "clkreq had been initialized.\n"); - } else if (ret) { - dev_err(dev, "%d unable to get clkreq.\n", ret); - return ret; - } - } else if (imxpriv->clkreq_gpio == -EPROBE_DEFER) { - return imxpriv->clkreq_gpio; - } + imxpriv->clkreq_gpiod = devm_gpiod_get_optional(dev, "clkreq", + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); + if (IS_ERR(imxpriv->clkreq_gpiod)) + return PTR_ERR(imxpriv->clkreq_gpiod); + if (imxpriv->clkreq_gpiod) + gpiod_set_consumer_name(imxpriv->clkreq_gpiod, "SATA CLKREQ"); return 0; } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 92d0ff63b3ea..8adffd42f8cb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -120,6 +120,14 @@ config GPIO_ASPEED help Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers. +config GPIO_ASPEED_SGPIO + bool "Aspeed SGPIO support" + depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say Y here to support Aspeed AST2500 SGPIO functionality. + config GPIO_ATH79 tristate "Atheros AR71XX/AR724X/AR913X GPIO support" default y if ATH79 @@ -147,6 +155,15 @@ config GPIO_BCM_KONA help Turn on GPIO support for Broadcom "Kona" chips. +config GPIO_BCM_XGS_IPROC + tristate "BRCM XGS iProc GPIO support" + depends on OF_GPIO && (ARCH_BCM_IPROC || COMPILE_TEST) + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + default ARCH_BCM_IPROC + help + Say yes here to enable GPIO support for Broadcom XGS iProc SoCs. + config GPIO_BRCMSTB tristate "BRCMSTB GPIO support" default y if (ARCH_BRCMSTB || BMIPS_GENERIC) @@ -435,6 +452,15 @@ config GPIO_RCAR help Say yes here to support GPIO on Renesas R-Car SoCs. +config GPIO_RDA + bool "RDA Micro GPIO controller support" + depends on ARCH_RDA || COMPILE_TEST + depends on OF_GPIO + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say Y here to support RDA Micro GPIO controller. + config GPIO_REG bool help @@ -531,6 +557,7 @@ config GPIO_TEGRA186 depends on ARCH_TEGRA_186_SOC || COMPILE_TEST depends on OF_GPIO select GPIOLIB_IRQCHIP + select IRQ_DOMAIN_HIERARCHY help Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs. @@ -1320,7 +1347,7 @@ config GPIO_BT8XX The card needs to be physically altered for using it as a GPIO card. For more information on how to build a GPIO card from a BT8xx TV card, see the documentation file at - Documentation/driver-api/bt8xxgpio.rst + Documentation/driver-api/gpio/bt8xxgpio.rst If unsure, say N. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index d2fd19c15bae..34eb8b2b12dd 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -32,8 +32,10 @@ obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o +obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o +obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o @@ -115,6 +117,7 @@ obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o +obj-$(CONFIG_GPIO_RDA) += gpio-rda.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_REG) += gpio-reg.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 9c048f10c9ad..76f8c7ff18ff 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -80,6 +80,10 @@ Work items: - Look over and identify any remaining easily converted drivers and dry-code conversions to MMIO GPIO for maintainers to test +- Expand the MMIO GPIO or write a new library for regmap-based I/O + helpers for GPIO drivers on regmap that simply use offsets + 0..n in some register to drive GPIO lines + - Expand the MMIO GPIO or write a new library for port-mapped I/O helpers (x86 inb()/outb()) and convert port-mapped I/O drivers to use this with dry-coding and sending to maintainers to test diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index a44fa8af5b0d..400c09b905f8 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -59,7 +59,10 @@ static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned offset) const unsigned port = offset / 8; const unsigned mask = BIT(offset % 8); - return !!(dio48egpio->io_state[port] & mask); + if (dio48egpio->io_state[port] & mask) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index ff53887bdaa8..c50329ab493a 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -53,7 +53,7 @@ struct idi_48_gpio { static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { - return 1; + return GPIO_LINE_DIRECTION_IN; } static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -65,7 +65,7 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset) { struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); unsigned i; - const unsigned register_offset[6] = { 0, 1, 2, 4, 5, 6 }; + static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 }; unsigned base_offset; unsigned mask; diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index 8d2f51cd9d91..5752d9dab148 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -51,9 +51,9 @@ struct idio_16_gpio { static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { if (offset > 15) - return 1; + return GPIO_LINE_DIRECTION_IN; - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index 83a2286d93f6..173e06758e6c 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -77,7 +77,10 @@ static int mmio_74xx_get_direction(struct gpio_chip *gc, unsigned offset) { struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc); - return !(priv->flags & MMIO_74XX_DIR_OUT); + if (priv->flags & MMIO_74XX_DIR_OUT) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio) diff --git a/drivers/gpio/gpio-amd-fch.c b/drivers/gpio/gpio-amd-fch.c index 181df1581df5..4e44ba4d7423 100644 --- a/drivers/gpio/gpio-amd-fch.c +++ b/drivers/gpio/gpio-amd-fch.c @@ -92,7 +92,7 @@ static int amd_fch_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) ret = (readl_relaxed(ptr) & AMD_FCH_GPIO_FLAG_DIRECTION); spin_unlock_irqrestore(&priv->lock, flags); - return ret; + return ret ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } static void amd_fch_gpio_set(struct gpio_chip *gc, diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/gpio-aspeed-sgpio.c index 7e99860ca447..7e99860ca447 100644 --- a/drivers/gpio/sgpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed-sgpio.c diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 09e53c5f3b0a..f1037b61f763 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -487,10 +487,10 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) u32 val; if (!have_input(gpio, offset)) - return 0; + return GPIO_LINE_DIRECTION_OUT; if (!have_output(gpio, offset)) - return 1; + return GPIO_LINE_DIRECTION_IN; spin_lock_irqsave(&gpio->lock, flags); @@ -498,8 +498,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) spin_unlock_irqrestore(&gpio->lock, flags); - return !val; - + return val ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; } static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index f1a5ea9b3de2..53fae02c40ad 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -226,7 +226,6 @@ static int ath79_gpio_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct ath79_gpio_ctrl *ctrl; struct gpio_irq_chip *girq; - struct resource *res; u32 ath79_gpio_count; bool oe_inverted; int err; @@ -256,12 +255,9 @@ static int ath79_gpio_probe(struct platform_device *pdev) return -EINVAL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - ctrl->base = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!ctrl->base) - return -ENOMEM; + ctrl->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ctrl->base)) + return PTR_ERR(ctrl->base); raw_spin_lock_init(&ctrl->lock); err = bgpio_init(&ctrl->gc, dev, 4, diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 9fa6d3a967d2..4122683eb1f9 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -127,7 +127,7 @@ static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio) u32 val; val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK; - return !!val; + return val ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) @@ -144,7 +144,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) raw_spin_lock_irqsave(&kona_gpio->lock, flags); /* this function only applies to output pin */ - if (bcm_kona_gpio_get_dir(chip, gpio) == 1) + if (bcm_kona_gpio_get_dir(chip, gpio) == GPIO_LINE_DIRECTION_IN) goto out; reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); @@ -170,7 +170,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) reg_base = kona_gpio->reg_base; raw_spin_lock_irqsave(&kona_gpio->lock, flags); - if (bcm_kona_gpio_get_dir(chip, gpio) == 1) + if (bcm_kona_gpio_get_dir(chip, gpio) == GPIO_LINE_DIRECTION_IN) reg_offset = GPIO_IN_STATUS(bank_id); else reg_offset = GPIO_OUT_STATUS(bank_id); diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c index 4ba4d4a67881..45b3da8da336 100644 --- a/drivers/gpio/gpio-bd70528.c +++ b/drivers/gpio/gpio-bd70528.c @@ -54,8 +54,10 @@ static int bd70528_get_direction(struct gpio_chip *chip, unsigned int offset) dev_err(bdgpio->chip.dev, "Could not read gpio direction\n"); return ret; } + if (val & BD70528_GPIO_OUT_EN_MASK) + return GPIO_LINE_DIRECTION_OUT; - return !(val & BD70528_GPIO_OUT_EN_MASK); + return GPIO_LINE_DIRECTION_IN; } static int bd70528_gpio_set_config(struct gpio_chip *chip, unsigned int offset, @@ -166,9 +168,9 @@ static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset) * locking would make no sense. */ ret = bd70528_get_direction(chip, offset); - if (ret == 0) + if (ret == GPIO_LINE_DIRECTION_OUT) ret = bd70528_gpio_get_o(bdgpio, offset); - else if (ret == 1) + 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"); @@ -230,3 +232,4 @@ module_platform_driver(bd70528_gpio); MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); MODULE_DESCRIPTION("BD70528 voltage regulator driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bd70528-gpio"); diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c index 5224a946e8ab..c0abc9c6851b 100644 --- a/drivers/gpio/gpio-bd9571mwv.c +++ b/drivers/gpio/gpio-bd9571mwv.c @@ -37,8 +37,10 @@ static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip, ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val); if (ret < 0) return ret; + if (val & BIT(offset)) + return GPIO_LINE_DIRECTION_IN; - return val & BIT(offset); + return GPIO_LINE_DIRECTION_OUT; } static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index 8a33c2fc174d..26b40c8b8a12 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -200,9 +200,9 @@ static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset) struct dln2_gpio *dln2 = gpiochip_get_data(chip); if (test_bit(offset, dln2->output_enabled)) - return 0; + return GPIO_LINE_DIRECTION_OUT; - return 1; + return GPIO_LINE_DIRECTION_IN; } static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset) @@ -214,7 +214,7 @@ static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset) if (dir < 0) return dir; - if (dir == 1) + if (dir == GPIO_LINE_DIRECTION_IN) return dln2_gpio_pin_get_in_val(dln2, offset); return dln2_gpio_pin_get_out_val(dln2, offset); diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 620f25b7efb4..17a243c528ad 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -269,13 +269,12 @@ static void em_gio_irq_domain_remove(void *data) static int em_gio_probe(struct platform_device *pdev) { struct em_gio_priv *p; - struct resource *io[2], *irq[2]; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; struct device *dev = &pdev->dev; const char *name = dev_name(dev); unsigned int ngpios; - int ret; + int irq[2], ret; p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); if (!p) @@ -285,25 +284,21 @@ static int em_gio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); spin_lock_init(&p->sense_lock); - io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1); - irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + irq[0] = platform_get_irq(pdev, 0); + if (irq[0] < 0) + return irq[0]; - if (!io[0] || !io[1] || !irq[0] || !irq[1]) { - dev_err(dev, "missing IRQ or IOMEM\n"); - return -EINVAL; - } + irq[1] = platform_get_irq(pdev, 1); + if (irq[1] < 0) + return irq[1]; - p->base0 = devm_ioremap_nocache(dev, io[0]->start, - resource_size(io[0])); - if (!p->base0) - return -ENOMEM; + p->base0 = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(p->base0)) + return PTR_ERR(p->base0); - p->base1 = devm_ioremap_nocache(dev, io[1]->start, - resource_size(io[1])); - if (!p->base1) - return -ENOMEM; + p->base1 = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(p->base1)) + return PTR_ERR(p->base1); if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) { dev_err(dev, "Missing ngpios OF property\n"); @@ -326,7 +321,7 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->ngpio = ngpios; irq_chip = &p->irq_chip; - irq_chip->name = name; + irq_chip->name = "gpio-em"; irq_chip->irq_mask = em_gio_irq_disable; irq_chip->irq_unmask = em_gio_irq_enable; irq_chip->irq_set_type = em_gio_irq_set_type; @@ -346,14 +341,12 @@ static int em_gio_probe(struct platform_device *pdev) if (ret) return ret; - if (devm_request_irq(dev, irq[0]->start, - em_gio_irq_handler, 0, name, p)) { + if (devm_request_irq(dev, irq[0], em_gio_irq_handler, 0, name, p)) { dev_err(dev, "failed to request low IRQ\n"); return -ENOENT; } - if (devm_request_irq(dev, irq[1]->start, - em_gio_irq_handler, 0, name, p)) { + if (devm_request_irq(dev, irq[1], em_gio_irq_handler, 0, name, p)) { dev_err(dev, "failed to request high IRQ\n"); return -ENOENT; } diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c index fae327d5b06e..da1ef0b1c291 100644 --- a/drivers/gpio/gpio-exar.c +++ b/drivers/gpio/gpio-exar.c @@ -77,7 +77,10 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; unsigned int bit = (offset + exar_gpio->first_pin) % 8; - return !!(exar_get(chip, addr) & BIT(bit)); + if (exar_get(chip, addr) & BIT(bit)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int exar_get_value(struct gpio_chip *chip, unsigned int offset) diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index fdc639f856f1..cadd02993539 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -250,7 +250,10 @@ static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) superio_exit(sio->addr); - return !(dir & 1 << offset); + if (dir & 1 << offset) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 78a1db24e931..c22d6f94129c 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -52,7 +52,10 @@ static int gpiomm_gpio_get_direction(struct gpio_chip *chip, const unsigned int port = offset / 8; const unsigned int mask = BIT(offset % 8); - return !!(gpiommgpio->io_state[port] & mask); + if (gpiommgpio->io_state[port] & mask) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int gpiomm_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 6eb56f7ab9c9..a40bd56673fe 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -220,7 +220,10 @@ static int egpio_get_direction(struct gpio_chip *chip, unsigned offset) egpio = gpiochip_get_data(chip); - return !test_bit(offset, &egpio->is_out); + if (test_bit(offset, &egpio->is_out)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static void egpio_write_cache(struct egpio_info *ei) @@ -265,7 +268,6 @@ static int __init egpio_probe(struct platform_device *pdev) struct gpio_chip *chip; unsigned int irq, irq_end; int i; - int ret; /* Initialize ei data structure. */ ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL); @@ -275,28 +277,24 @@ static int __init egpio_probe(struct platform_device *pdev) spin_lock_init(&ei->lock); /* Find chained irq */ - ret = -EINVAL; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res) ei->chained_irq = res->start; /* Map egpio chip into virtual address space. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - goto fail; - ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!ei->base_addr) - goto fail; - pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr); + ei->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ei->base_addr)) + return PTR_ERR(ei->base_addr); if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) - goto fail; + return -EINVAL; + ei->bus_shift = fls(pdata->bus_width - 1) - 3; pr_debug("bus_shift = %d\n", ei->bus_shift); if ((pdata->reg_width != 8) && (pdata->reg_width != 16)) - goto fail; + return -EINVAL; + ei->reg_shift = fls(pdata->reg_width - 1); pr_debug("reg_shift = %d\n", ei->reg_shift); @@ -308,10 +306,9 @@ static int __init egpio_probe(struct platform_device *pdev) ei->chip = devm_kcalloc(&pdev->dev, ei->nchips, sizeof(struct egpio_chip), GFP_KERNEL); - if (!ei->chip) { - ret = -ENOMEM; - goto fail; - } + if (!ei->chip) + return -ENOMEM; + for (i = 0; i < ei->nchips; i++) { ei->chip[i].reg_start = pdata->chip[i].reg_start; ei->chip[i].cached_values = pdata->chip[i].initial_values; @@ -321,10 +318,9 @@ static int __init egpio_probe(struct platform_device *pdev) chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "htc-egpio-%d", i); - if (!chip->label) { - ret = -ENOMEM; - goto fail; - } + if (!chip->label) + return -ENOMEM; + chip->parent = &pdev->dev; chip->owner = THIS_MODULE; chip->get = egpio_get; @@ -366,10 +362,6 @@ static int __init egpio_probe(struct platform_device *pdev) } return 0; - -fail: - printk(KERN_ERR "EGPIO failed to setup\n"); - return ret; } #ifdef CONFIG_PM diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 90bf7742f9b0..2f086d0aa1f4 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -159,7 +159,10 @@ static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr) { - return ichx_read_bit(GPIO_IO_SEL, nr); + if (ichx_read_bit(GPIO_IO_SEL, nr)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index ef51638f3f75..4ea15f08e0f4 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -104,7 +104,10 @@ static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset) struct kempld_gpio_data *gpio = gpiochip_get_data(chip); struct kempld_device_data *pld = gpio->pld; - return !kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset); + if (kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int kempld_gpio_pincount(struct kempld_device_data *pld) diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c index 801995dd9b26..70fad87ff2db 100644 --- a/drivers/gpio/gpio-lp873x.c +++ b/drivers/gpio/gpio-lp873x.c @@ -33,7 +33,7 @@ static int lp873x_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { /* This device is output only */ - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int lp873x_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c index a121c8f10610..e1244520cf7d 100644 --- a/drivers/gpio/gpio-lp87565.c +++ b/drivers/gpio/gpio-lp87565.c @@ -57,7 +57,10 @@ static int lp87565_gpio_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return !(val & BIT(offset)); + if (val & BIT(offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int lp87565_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index e9e47c0d5be7..490ce7bae25e 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -164,6 +164,12 @@ static int lp_irq_type(struct irq_data *d, unsigned type) value |= TRIG_SEL_BIT | INT_INV_BIT; outl(value, reg); + + if (type & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(d, handle_edge_irq); + else if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(d, handle_level_irq); + spin_unlock_irqrestore(&lg->lock, flags); return 0; diff --git a/drivers/gpio/gpio-madera.c b/drivers/gpio/gpio-madera.c index 7086f8b5388f..8f38303fcbc4 100644 --- a/drivers/gpio/gpio-madera.c +++ b/drivers/gpio/gpio-madera.c @@ -34,7 +34,10 @@ static int madera_gpio_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return !!(val & MADERA_GP1_DIR_MASK); + if (val & MADERA_GP1_DIR_MASK) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int madera_gpio_direction_in(struct gpio_chip *chip, unsigned int offset) diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index 4b4b2ceb82fc..0696d5a21431 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -94,7 +94,7 @@ DECLARE_CRC8_TABLE(max3191x_crc8); static int max3191x_get_direction(struct gpio_chip *gpio, unsigned int offset) { - return 1; /* always in */ + return GPIO_LINE_DIRECTION_IN; /* always in */ } static int max3191x_direction_input(struct gpio_chip *gpio, unsigned int offset) diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index 642c6321c22a..313bd02dd893 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -18,109 +18,115 @@ struct max77620_gpio { struct gpio_chip gpio_chip; struct regmap *rmap; struct device *dev; + struct mutex buslock; /* irq_bus_lock */ + unsigned int irq_type[8]; + bool irq_enabled[8]; }; -static const struct regmap_irq max77620_gpio_irqs[] = { - [0] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE0, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 0, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [1] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE1, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 1, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [2] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE2, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 2, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [3] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE3, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 3, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [4] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE4, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 4, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [5] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE5, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 5, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [6] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE6, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 6, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, - [7] = { - .reg_offset = 0, - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE7, - .type = { - .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, - .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING, - .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK, - .type_reg_offset = 7, - .types_supported = IRQ_TYPE_EDGE_BOTH, - }, - }, -}; +static irqreturn_t max77620_gpio_irqhandler(int irq, void *data) +{ + struct max77620_gpio *gpio = data; + unsigned int value, offset; + unsigned long pending; + int err; + + err = regmap_read(gpio->rmap, MAX77620_REG_IRQ_LVL2_GPIO, &value); + if (err < 0) { + dev_err(gpio->dev, "REG_IRQ_LVL2_GPIO read failed: %d\n", err); + return IRQ_NONE; + } + + pending = value; + + for_each_set_bit(offset, &pending, 8) { + unsigned int virq; + + virq = irq_find_mapping(gpio->gpio_chip.irq.domain, offset); + handle_nested_irq(virq); + } + + return IRQ_HANDLED; +} + +static void max77620_gpio_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + + gpio->irq_enabled[data->hwirq] = false; +} -static const struct regmap_irq_chip max77620_gpio_irq_chip = { - .name = "max77620-gpio", - .irqs = max77620_gpio_irqs, - .num_irqs = ARRAY_SIZE(max77620_gpio_irqs), - .num_regs = 1, - .num_type_reg = 8, - .irq_reg_stride = 1, - .type_reg_stride = 1, - .status_base = MAX77620_REG_IRQ_LVL2_GPIO, - .type_base = MAX77620_REG_GPIO0, +static void max77620_gpio_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + + gpio->irq_enabled[data->hwirq] = true; +} + +static int max77620_gpio_set_irq_type(struct irq_data *data, unsigned int type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + unsigned int irq_type; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + irq_type = MAX77620_CNFG_GPIO_INT_RISING; + break; + + case IRQ_TYPE_EDGE_FALLING: + irq_type = MAX77620_CNFG_GPIO_INT_FALLING; + break; + + case IRQ_TYPE_EDGE_BOTH: + irq_type = MAX77620_CNFG_GPIO_INT_RISING | + MAX77620_CNFG_GPIO_INT_FALLING; + break; + + default: + return -EINVAL; + } + + gpio->irq_type[data->hwirq] = irq_type; + + return 0; +} + +static void max77620_gpio_bus_lock(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + + mutex_lock(&gpio->buslock); +} + +static void max77620_gpio_bus_sync_unlock(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct max77620_gpio *gpio = gpiochip_get_data(chip); + unsigned int value, offset = data->hwirq; + int err; + + value = gpio->irq_enabled[offset] ? gpio->irq_type[offset] : 0; + + err = regmap_update_bits(gpio->rmap, GPIO_REG_ADDR(offset), + MAX77620_CNFG_GPIO_INT_MASK, value); + if (err < 0) + dev_err(chip->parent, "failed to update interrupt mask: %d\n", + err); + + mutex_unlock(&gpio->buslock); +} + +static struct irq_chip max77620_gpio_irqchip = { + .name = "max77620-gpio", + .irq_mask = max77620_gpio_irq_mask, + .irq_unmask = max77620_gpio_irq_unmask, + .irq_set_type = max77620_gpio_set_irq_type, + .irq_bus_lock = max77620_gpio_bus_lock, + .irq_bus_sync_unlock = max77620_gpio_bus_sync_unlock, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset) @@ -254,14 +260,6 @@ static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset, return -ENOTSUPP; } -static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) -{ - struct max77620_gpio *mgpio = gpiochip_get_data(gc); - struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent); - - return regmap_irq_get_virq(chip->gpio_irq_data, offset); -} - static int max77620_gpio_probe(struct platform_device *pdev) { struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -287,7 +285,6 @@ static int max77620_gpio_probe(struct platform_device *pdev) mgpio->gpio_chip.direction_output = max77620_gpio_dir_output; mgpio->gpio_chip.set = max77620_gpio_set; mgpio->gpio_chip.set_config = max77620_gpio_set_config; - mgpio->gpio_chip.to_irq = max77620_gpio_to_irq; mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR; mgpio->gpio_chip.can_sleep = 1; mgpio->gpio_chip.base = -1; @@ -303,15 +300,21 @@ static int max77620_gpio_probe(struct platform_device *pdev) return ret; } - ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq, - IRQF_ONESHOT, -1, - &max77620_gpio_irq_chip, - &chip->gpio_irq_data); + mutex_init(&mgpio->buslock); + + gpiochip_irqchip_add_nested(&mgpio->gpio_chip, &max77620_gpio_irqchip, + 0, handle_edge_irq, IRQ_TYPE_NONE); + + ret = request_threaded_irq(gpio_irq, NULL, max77620_gpio_irqhandler, + IRQF_ONESHOT, "max77620-gpio", mgpio); if (ret < 0) { - dev_err(&pdev->dev, "Failed to add gpio irq_chip %d\n", ret); + dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret); return ret; } + gpiochip_set_nested_irqchip(&mgpio->gpio_chip, &max77620_gpio_irqchip, + gpio_irq); + return 0; } diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 3302125e5265..48918a016cd8 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -162,7 +162,10 @@ static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - return !(readl(gpdr) & BIT(offset % 32)); + if (readl(gpdr) & BIT(offset % 32)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, @@ -362,8 +365,9 @@ static void mrfld_irq_handler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } -static void mrfld_irq_init_hw(struct mrfld_gpio *priv) +static int mrfld_irq_init_hw(struct gpio_chip *chip) { + struct mrfld_gpio *priv = gpiochip_get_data(chip); void __iomem *reg; unsigned int base; @@ -375,6 +379,8 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv) reg = gpio_reg(&priv->chip, base, GFER); writel(0, reg); } + + return 0; } static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) @@ -393,14 +399,36 @@ static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) return name; } -static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip) { + struct mrfld_gpio *priv = gpiochip_get_data(chip); const struct mrfld_gpio_pinrange *range; const char *pinctrl_dev_name; + unsigned int i; + int retval; + + pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); + for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { + range = &mrfld_gpio_ranges[i]; + retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name, + range->gpio_base, + range->pin_base, + range->npins); + if (retval) { + dev_err(priv->dev, "failed to add GPIO pin range\n"); + return retval; + } + } + + return 0; +} + +static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct gpio_irq_chip *girq; struct mrfld_gpio *priv; u32 gpio_base, irq_base; void __iomem *base; - unsigned int i; int retval; retval = pcim_enable_device(pdev); @@ -441,42 +469,31 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id priv->chip.base = gpio_base; priv->chip.ngpio = MRFLD_NGPIO; priv->chip.can_sleep = false; + priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges; raw_spin_lock_init(&priv->lock); - pci_set_drvdata(pdev, priv); + girq = &priv->chip.irq; + girq->chip = &mrfld_irqchip; + girq->init_hw = mrfld_irq_init_hw; + girq->parent_handler = mrfld_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, + sizeof(*girq->parents), GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = pdev->irq; + girq->first = irq_base; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); return retval; } - pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); - for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { - range = &mrfld_gpio_ranges[i]; - retval = gpiochip_add_pin_range(&priv->chip, - pinctrl_dev_name, - range->gpio_base, - range->pin_base, - range->npins); - if (retval) { - dev_err(&pdev->dev, "failed to add GPIO pin range\n"); - return retval; - } - } - - retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, - handle_bad_irq, IRQ_TYPE_NONE); - if (retval) { - dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); - return retval; - } - - mrfld_irq_init_hw(priv); - - gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq, - mrfld_irq_handler); - + pci_set_drvdata(pdev, priv); return 0; } diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 6f904c874678..f729e3e9e983 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -370,15 +370,23 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) { /* Return 0 if output, 1 if input */ - if (gc->bgpio_dir_unreadable) - return !(gc->bgpio_dir & bgpio_line2mask(gc, gpio)); - if (gc->reg_dir_out) - return !(gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio)); + if (gc->bgpio_dir_unreadable) { + if (gc->bgpio_dir & bgpio_line2mask(gc, gpio)) + return GPIO_LINE_DIRECTION_OUT; + return GPIO_LINE_DIRECTION_IN; + } + + if (gc->reg_dir_out) { + if (gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio)) + return GPIO_LINE_DIRECTION_OUT; + return GPIO_LINE_DIRECTION_IN; + } + if (gc->reg_dir_in) - return !!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio)); + if (!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio))) + return GPIO_LINE_DIRECTION_OUT; - /* This should not happen */ - return 1; + return GPIO_LINE_DIRECTION_IN; } static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 213aedc97dc2..56d647a30e3e 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -34,14 +34,9 @@ #define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__) -enum { - GPIO_MOCKUP_DIR_IN = 0, - GPIO_MOCKUP_DIR_OUT = 1, -}; - /* * struct gpio_pin_status - structure describing a GPIO status - * @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out + * @dir: Configures direction of gpio as "in" or "out" * @value: Configures status of the gpio as 0(low) or 1(high) */ struct gpio_mockup_line_status { @@ -146,13 +141,68 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc, mutex_unlock(&chip->lock); } +static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip, + unsigned int offset, int value) +{ + struct gpio_desc *desc; + struct gpio_chip *gc; + struct irq_sim *sim; + int curr, irq, irq_type; + + gc = &chip->gc; + desc = &gc->gpiodev->descs[offset]; + sim = &chip->irqsim; + + mutex_lock(&chip->lock); + + if (test_bit(FLAG_REQUESTED, &desc->flags) && + !test_bit(FLAG_IS_OUT, &desc->flags)) { + curr = __gpio_mockup_get(chip, offset); + if (curr == value) + goto out; + + irq = irq_sim_irqnum(sim, offset); + irq_type = irq_get_trigger_type(irq); + + if ((value == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) || + (value == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING))) + irq_sim_fire(sim, offset); + } + + /* Change the value unless we're actively driving the line. */ + if (!test_bit(FLAG_REQUESTED, &desc->flags) || + !test_bit(FLAG_IS_OUT, &desc->flags)) + __gpio_mockup_set(chip, offset, value); + +out: + chip->lines[offset].pull = value; + mutex_unlock(&chip->lock); + return 0; +} + +static int gpio_mockup_set_config(struct gpio_chip *gc, + unsigned int offset, unsigned long config) +{ + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_PULL_UP: + return gpio_mockup_apply_pull(chip, offset, 1); + case PIN_CONFIG_BIAS_PULL_DOWN: + return gpio_mockup_apply_pull(chip, offset, 0); + default: + break; + } + return -ENOTSUPP; +} + static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset, int value) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); mutex_lock(&chip->lock); - chip->lines[offset].dir = GPIO_MOCKUP_DIR_OUT; + chip->lines[offset].dir = GPIO_LINE_DIRECTION_OUT; __gpio_mockup_set(chip, offset, value); mutex_unlock(&chip->lock); @@ -164,7 +214,7 @@ static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset) struct gpio_mockup_chip *chip = gpiochip_get_data(gc); mutex_lock(&chip->lock); - chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN; + chip->lines[offset].dir = GPIO_LINE_DIRECTION_IN; mutex_unlock(&chip->lock); return 0; @@ -226,12 +276,8 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file, size_t size, loff_t *ppos) { struct gpio_mockup_dbgfs_private *priv; - int rv, val, curr, irq, irq_type; - struct gpio_mockup_chip *chip; + int rv, val; struct seq_file *sfile; - struct gpio_desc *desc; - struct gpio_chip *gc; - struct irq_sim *sim; if (*ppos != 0) return -EINVAL; @@ -244,35 +290,9 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file, sfile = file->private_data; priv = sfile->private; - chip = priv->chip; - gc = &chip->gc; - desc = &gc->gpiodev->descs[priv->offset]; - sim = &chip->irqsim; - - mutex_lock(&chip->lock); - - if (test_bit(FLAG_REQUESTED, &desc->flags) && - !test_bit(FLAG_IS_OUT, &desc->flags)) { - curr = __gpio_mockup_get(chip, priv->offset); - if (curr == val) - goto out; - - irq = irq_sim_irqnum(sim, priv->offset); - irq_type = irq_get_trigger_type(irq); - - if ((val == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) || - (val == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING))) - irq_sim_fire(sim, priv->offset); - } - - /* Change the value unless we're actively driving the line. */ - if (!test_bit(FLAG_REQUESTED, &desc->flags) || - !test_bit(FLAG_IS_OUT, &desc->flags)) - __gpio_mockup_set(chip, priv->offset, val); - -out: - chip->lines[priv->offset].pull = val; - mutex_unlock(&chip->lock); + rv = gpio_mockup_apply_pull(priv->chip, priv->offset, val); + if (rv) + return rv; return size; } @@ -418,6 +438,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) gc->direction_output = gpio_mockup_dirout; gc->direction_input = gpio_mockup_dirin; gc->get_direction = gpio_mockup_get_direction; + gc->set_config = gpio_mockup_set_config; gc->to_irq = gpio_mockup_to_irq; gc->free = gpio_mockup_free; diff --git a/drivers/gpio/gpio-moxtet.c b/drivers/gpio/gpio-moxtet.c index 3fd729994a38..8299909318f4 100644 --- a/drivers/gpio/gpio-moxtet.c +++ b/drivers/gpio/gpio-moxtet.c @@ -78,9 +78,9 @@ static int moxtet_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) /* All lines are hard wired to be either input or output, not both. */ if (chip->desc->in_mask & BIT(offset)) - return 1; + return GPIO_LINE_DIRECTION_IN; else if (chip->desc->out_mask & BIT(offset)) - return 0; + return GPIO_LINE_DIRECTION_OUT; else return -EINVAL; } diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 16a47de29c94..f1e164cecff8 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -22,6 +22,7 @@ #include <linux/irq.h> #include <linux/gpio/driver.h> #include <linux/bitops.h> +#include <linux/interrupt.h> #define MPC8XXX_GPIO_PINS 32 @@ -127,20 +128,19 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return -ENXIO; } -static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc) +static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data) { - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_desc_get_chip(desc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = data; struct gpio_chip *gc = &mpc8xxx_gc->gc; - unsigned int mask; + unsigned long mask; + int i; mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER) & gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR); - if (mask) - generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, - 32 - ffs(mask))); - if (chip->irq_eoi) - chip->irq_eoi(&desc->irq_data); + for_each_set_bit(i, &mask, 32) + generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 31 - i)); + + return IRQ_HANDLED; } static void mpc8xxx_irq_unmask(struct irq_data *d) @@ -377,7 +377,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) * It's assumed that only a single type of gpio controller is available * on the current machine, so overwriting global data is fine. */ - mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; + if (devtype->irq_set_type) + mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; if (devtype->gpio_dir_out) gc->direction_output = devtype->gpio_dir_out; @@ -386,6 +387,9 @@ static int mpc8xxx_probe(struct platform_device *pdev) gc->to_irq = mpc8xxx_gpio_to_irq; + if (of_device_is_compatible(np, "fsl,qoriq-gpio")) + gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff); + ret = gpiochip_add_data(gc, mpc8xxx_gc); if (ret) { pr_err("%pOF: GPIO chip registration failed with status %d\n", @@ -409,8 +413,16 @@ static int mpc8xxx_probe(struct platform_device *pdev) if (devtype->gpio_dir_in_init) devtype->gpio_dir_in_init(gc); - irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, - mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); + ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn, + mpc8xxx_gpio_irq_cascade, + IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade", + mpc8xxx_gc); + if (ret) { + dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n", + np->full_name, mpc8xxx_gc->irqn, ret); + goto err; + } + return 0; err: iounmap(mpc8xxx_gc->regs); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 2f0f50336b9a..993bbeb3c006 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -384,7 +384,10 @@ static int mvebu_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u); - return !!(u & BIT(pin)); + if (u & BIT(pin)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin) diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 7907a8755866..c77d474185f3 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -411,6 +411,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct mxc_gpio_port *port; + int irq_count; int irq_base; int err; @@ -426,9 +427,15 @@ static int mxc_gpio_probe(struct platform_device *pdev) if (IS_ERR(port->base)) return PTR_ERR(port->base); - port->irq_high = platform_get_irq(pdev, 1); - if (port->irq_high < 0) - port->irq_high = 0; + irq_count = platform_irq_count(pdev); + if (irq_count < 0) + return irq_count; + + if (irq_count > 1) { + port->irq_high = platform_get_irq(pdev, 1); + if (port->irq_high < 0) + port->irq_high = 0; + } port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 5e5437a2c607..c4a314c68555 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -248,7 +248,10 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset) u32 dir; dir = readl(port->base + PINCTRL_DOE(port)); - return !(dir & mask); + if (dir & mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static const struct platform_device_id mxs_gpio_ids[] = { diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index d0f27084a942..3bd8adaeed9e 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -805,8 +805,10 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank = gpiochip_get_data(chip); - return !!(readl_relaxed(bank->base + bank->regs->direction) & - BIT(offset)); + if (readl_relaxed(bank->base + bank->regs->direction) & BIT(offset)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index de5d1383f28d..82122c3c688a 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -449,7 +449,10 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) if (ret < 0) return ret; - return !!(reg_val & bit); + if (reg_val & bit) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static void pca953x_gpio_set_multiple(struct gpio_chip *gc, diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c index 5aa136a6a3e0..df51dd08bdfe 100644 --- a/drivers/gpio/gpio-pci-idio-16.c +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -61,9 +61,9 @@ static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { if (offset > 15) - return 1; + return GPIO_LINE_DIRECTION_IN; - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int idio_16_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c index 52f1647a46fd..44c1e4fc489f 100644 --- a/drivers/gpio/gpio-pcie-idio-24.c +++ b/drivers/gpio/gpio-pcie-idio-24.c @@ -104,15 +104,18 @@ static int idio_24_gpio_get_direction(struct gpio_chip *chip, /* FET Outputs */ if (offset < 24) - return 0; + return GPIO_LINE_DIRECTION_OUT; /* Isolated Inputs */ if (offset < 48) - return 1; + return GPIO_LINE_DIRECTION_IN; /* TTL/CMOS I/O */ /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ - return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask); + if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int idio_24_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c index f809a5a8e9eb..1331b2a94679 100644 --- a/drivers/gpio/gpio-pisosr.c +++ b/drivers/gpio/gpio-pisosr.c @@ -65,7 +65,7 @@ static int pisosr_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { /* This device always input */ - return 1; + return GPIO_LINE_DIRECTION_IN; } static int pisosr_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 722ce5cf861e..5df7782e348f 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -63,7 +63,10 @@ static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) { struct pl061 *pl061 = gpiochip_get_data(gc); - return !(readb(pl061->base + GPIODIR) & BIT(offset)); + if (readb(pl061->base + GPIODIR) & BIT(offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c index b77ea16ffa03..bb100e0124e6 100644 --- a/drivers/gpio/gpio-raspberrypi-exp.c +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -147,7 +147,10 @@ static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off) get.gpio); return ret ? ret : -EIO; } - return !get.direction; + if (get.direction) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 187984d26f47..f800b250971c 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -279,7 +279,10 @@ static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset) { struct gpio_rcar_priv *p = gpiochip_get_data(chip); - return !(gpio_rcar_read(p, INOUTSEL) & BIT(offset)); + if (gpio_rcar_read(p, INOUTSEL) & BIT(offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) @@ -483,7 +486,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->ngpio = npins; irq_chip = &p->irq_chip; - irq_chip->name = name; + irq_chip->name = "gpio-rcar"; irq_chip->parent_device = dev; irq_chip->irq_mask = gpio_rcar_irq_disable; irq_chip->irq_unmask = gpio_rcar_irq_enable; diff --git a/drivers/gpio/gpio-rda.c b/drivers/gpio/gpio-rda.c new file mode 100644 index 000000000000..28dcbb58b76b --- /dev/null +++ b/drivers/gpio/gpio-rda.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RDA Micro GPIO driver + * + * Copyright (C) 2012 RDA Micro Inc. + * Copyright (C) 2019 Manivannan Sadhasivam + */ + +#include <linux/bitops.h> +#include <linux/gpio/driver.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#define RDA_GPIO_OEN_VAL 0x00 +#define RDA_GPIO_OEN_SET_OUT 0x04 +#define RDA_GPIO_OEN_SET_IN 0x08 +#define RDA_GPIO_VAL 0x0c +#define RDA_GPIO_SET 0x10 +#define RDA_GPIO_CLR 0x14 +#define RDA_GPIO_INT_CTRL_SET 0x18 +#define RDA_GPIO_INT_CTRL_CLR 0x1c +#define RDA_GPIO_INT_CLR 0x20 +#define RDA_GPIO_INT_STATUS 0x24 + +#define RDA_GPIO_IRQ_RISE_SHIFT 0 +#define RDA_GPIO_IRQ_FALL_SHIFT 8 +#define RDA_GPIO_DEBOUCE_SHIFT 16 +#define RDA_GPIO_LEVEL_SHIFT 24 + +#define RDA_GPIO_IRQ_MASK 0xff + +/* Each bank consists of 32 GPIOs */ +#define RDA_GPIO_BANK_NR 32 + +struct rda_gpio { + struct gpio_chip chip; + void __iomem *base; + spinlock_t lock; + struct irq_chip irq_chip; + int irq; +}; + +static inline void rda_gpio_update(struct gpio_chip *chip, unsigned int offset, + u16 reg, int val) +{ + struct rda_gpio *rda_gpio = gpiochip_get_data(chip); + void __iomem *base = rda_gpio->base; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&rda_gpio->lock, flags); + tmp = readl_relaxed(base + reg); + + if (val) + tmp |= BIT(offset); + else + tmp &= ~BIT(offset); + + writel_relaxed(tmp, base + reg); + spin_unlock_irqrestore(&rda_gpio->lock, flags); +} + +static void rda_gpio_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct rda_gpio *rda_gpio = gpiochip_get_data(chip); + void __iomem *base = rda_gpio->base; + u32 offset = irqd_to_hwirq(data); + u32 value; + + value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; + value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; + + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); +} + +static void rda_gpio_irq_ack(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + + rda_gpio_update(chip, offset, RDA_GPIO_INT_CLR, 1); +} + +static int rda_gpio_set_irq(struct gpio_chip *chip, u32 offset, + unsigned int flow_type) +{ + struct rda_gpio *rda_gpio = gpiochip_get_data(chip); + void __iomem *base = rda_gpio->base; + u32 value; + + switch (flow_type) { + case IRQ_TYPE_EDGE_RISING: + /* Set rising edge trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + + /* Switch to edge trigger interrupt */ + value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); + break; + + case IRQ_TYPE_EDGE_FALLING: + /* Set falling edge trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + + /* Switch to edge trigger interrupt */ + value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); + break; + + case IRQ_TYPE_EDGE_BOTH: + /* Set both edge trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; + value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + + /* Switch to edge trigger interrupt */ + value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR); + break; + + case IRQ_TYPE_LEVEL_HIGH: + /* Set high level trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT; + + /* Switch to level trigger interrupt */ + value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + break; + + case IRQ_TYPE_LEVEL_LOW: + /* Set low level trigger */ + value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT; + + /* Switch to level trigger interrupt */ + value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT; + writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static void rda_gpio_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + u32 trigger = irqd_get_trigger_type(data); + + rda_gpio_set_irq(chip, offset, trigger); +} + +static int rda_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + int ret; + + ret = rda_gpio_set_irq(chip, offset, flow_type); + if (ret) + return ret; + + if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + irq_set_handler_locked(data, handle_level_irq); + else if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + irq_set_handler_locked(data, handle_edge_irq); + + return 0; +} + +static void rda_gpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); + struct rda_gpio *rda_gpio = gpiochip_get_data(chip); + unsigned long status; + u32 n, girq; + + chained_irq_enter(ic, desc); + + status = readl_relaxed(rda_gpio->base + RDA_GPIO_INT_STATUS); + /* Only lower 8 bits are capable of generating interrupts */ + status &= RDA_GPIO_IRQ_MASK; + + for_each_set_bit(n, &status, RDA_GPIO_BANK_NR) { + girq = irq_find_mapping(chip->irq.domain, n); + generic_handle_irq(girq); + } + + chained_irq_exit(ic, desc); +} + +static int rda_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct gpio_irq_chip *girq; + struct rda_gpio *rda_gpio; + u32 ngpios; + int ret; + + rda_gpio = devm_kzalloc(dev, sizeof(*rda_gpio), GFP_KERNEL); + if (!rda_gpio) + return -ENOMEM; + + ret = device_property_read_u32(dev, "ngpios", &ngpios); + if (ret < 0) + return ret; + + /* + * Not all ports have interrupt capability. For instance, on + * RDA8810PL, GPIOC doesn't support interrupt. So we must handle + * those also. + */ + rda_gpio->irq = platform_get_irq(pdev, 0); + + rda_gpio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rda_gpio->base)) + return PTR_ERR(rda_gpio->base); + + spin_lock_init(&rda_gpio->lock); + + ret = bgpio_init(&rda_gpio->chip, dev, 4, + rda_gpio->base + RDA_GPIO_VAL, + rda_gpio->base + RDA_GPIO_SET, + rda_gpio->base + RDA_GPIO_CLR, + rda_gpio->base + RDA_GPIO_OEN_SET_OUT, + rda_gpio->base + RDA_GPIO_OEN_SET_IN, + BGPIOF_READ_OUTPUT_REG_SET); + if (ret) { + dev_err(dev, "bgpio_init failed\n"); + return ret; + } + + rda_gpio->chip.label = dev_name(dev); + rda_gpio->chip.ngpio = ngpios; + rda_gpio->chip.base = -1; + rda_gpio->chip.parent = dev; + rda_gpio->chip.of_node = np; + + if (rda_gpio->irq >= 0) { + rda_gpio->irq_chip.name = "rda-gpio", + rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack, + rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask, + rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask, + rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type, + rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE, + + girq = &rda_gpio->chip.irq; + girq->chip = &rda_gpio->irq_chip; + girq->handler = handle_bad_irq; + girq->default_type = IRQ_TYPE_NONE; + girq->parent_handler = rda_gpio_irq_handler; + girq->parent_handler_data = rda_gpio; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = rda_gpio->irq; + } + + platform_set_drvdata(pdev, rda_gpio); + + return devm_gpiochip_add_data(dev, &rda_gpio->chip, rda_gpio); +} + +static const struct of_device_id rda_gpio_of_match[] = { + { .compatible = "rda,8810pl-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rda_gpio_of_match); + +static struct platform_driver rda_gpio_driver = { + .probe = rda_gpio_probe, + .driver = { + .name = "rda-gpio", + .of_match_table = rda_gpio_of_match, + }, +}; + +module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe); + +MODULE_DESCRIPTION("RDA Micro GPIO driver"); +MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-reg.c b/drivers/gpio/gpio-reg.c index fdc7a9d5b382..d35169bde25a 100644 --- a/drivers/gpio/gpio-reg.c +++ b/drivers/gpio/gpio-reg.c @@ -26,7 +26,8 @@ static int gpio_reg_get_direction(struct gpio_chip *gc, unsigned offset) { struct gpio_reg *r = to_gpio_reg(gc); - return r->direction & BIT(offset) ? 1 : 0; + return r->direction & BIT(offset) ? GPIO_LINE_DIRECTION_IN : + GPIO_LINE_DIRECTION_OUT; } static int gpio_reg_direction_output(struct gpio_chip *gc, unsigned offset, diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 46b7cf23fb0f..edff5e81489f 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -53,7 +53,10 @@ static int sa1100_get_direction(struct gpio_chip *chip, unsigned offset) { void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR; - return !(readl_relaxed(gpdr) & BIT(offset)); + if (readl_relaxed(gpdr) & BIT(offset)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-sama5d2-piobu.c b/drivers/gpio/gpio-sama5d2-piobu.c index 7d718557092e..b04c561f3280 100644 --- a/drivers/gpio/gpio-sama5d2-piobu.c +++ b/drivers/gpio/gpio-sama5d2-piobu.c @@ -119,7 +119,8 @@ static int sama5d2_piobu_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return (ret == PIOBU_IN) ? 1 : 0; + return (ret == PIOBU_IN) ? GPIO_LINE_DIRECTION_IN : + GPIO_LINE_DIRECTION_OUT; } /** @@ -154,9 +155,9 @@ static int sama5d2_piobu_get(struct gpio_chip *chip, unsigned int pin) /* if pin is input, read value from PDS else read from SOD */ int ret = sama5d2_piobu_get_direction(chip, pin); - if (ret == 1) + if (ret == GPIO_LINE_DIRECTION_IN) ret = sama5d2_piobu_read_value(chip, pin, PIOBU_PDS); - else if (!ret) + else if (ret == GPIO_LINE_DIRECTION_OUT) ret = sama5d2_piobu_read_value(chip, pin, PIOBU_SOD); if (ret < 0) diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index fb143f28c386..c65f35b68202 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -127,7 +127,10 @@ static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned gpio_num) { struct sch_gpio *sch = gpiochip_get_data(gc); - return sch_gpio_reg_get(sch, gpio_num, GIO); + if (sch_gpio_reg_get(sch, gpio_num, GIO)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static const struct gpio_chip sch_gpio_chip = { diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index 8ecf336c9af4..da01e1cad7cb 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -228,7 +228,10 @@ static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) data = inb(block->runtime_reg + block->config_regs[offset]); spin_unlock(&block->lock); - return !!(data & SCH311X_GPIO_CONF_DIR); + if (data & SCH311X_GPIO_CONF_DIR) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset, diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c index 006a7e6a75f2..311f66757b92 100644 --- a/drivers/gpio/gpio-siox.c +++ b/drivers/gpio/gpio-siox.c @@ -203,9 +203,9 @@ static int gpio_siox_direction_output(struct gpio_chip *chip, static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset) { if (offset < 12) - return 1; /* input */ + return GPIO_LINE_DIRECTION_IN; else - return 0; /* output */ + return GPIO_LINE_DIRECTION_OUT; } static int gpio_siox_probe(struct siox_device *sdevice) diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 994d542daf53..542706a852e6 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -84,7 +84,10 @@ static int stmpe_gpio_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return !(ret & mask); + if (ret & mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int stmpe_gpio_direction_output(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 75b1135b383a..6be0684cfa49 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -97,7 +97,10 @@ static int tc3589x_gpio_get_direction(struct gpio_chip *chip, if (ret < 0) return ret; - return !(ret & BIT(pos)); + if (ret & BIT(pos)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int tc3589x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 8a01d3694b28..6fdfe4c5303e 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -215,7 +215,10 @@ static int tegra_gpio_get_direction(struct gpio_chip *chip, oe = tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)); - return !(oe & pin_mask); + if (oe & pin_mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index ef40fbe923cf..55b43b7ce88d 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -15,6 +15,14 @@ #include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/gpio/tegra194-gpio.h> +/* security registers */ +#define TEGRA186_GPIO_CTL_SCR 0x0c +#define TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28) +#define TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27) + +#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4) + +/* control registers */ #define TEGRA186_GPIO_ENABLE_CONFIG 0x00 #define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0) #define TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1) @@ -24,6 +32,7 @@ #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE (0x3 << 2) #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (0x3 << 2) #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4) +#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5) #define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6) #define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04 @@ -44,15 +53,16 @@ struct tegra_gpio_port { const char *name; - unsigned int offset; + unsigned int bank; + unsigned int port; unsigned int pins; - unsigned int irq; }; struct tegra_gpio_soc { const struct tegra_gpio_port *ports; unsigned int num_ports; const char *name; + unsigned int instance; }; struct tegra_gpio { @@ -63,6 +73,7 @@ struct tegra_gpio { const struct tegra_gpio_soc *soc; + void __iomem *secure; void __iomem *base; }; @@ -89,12 +100,15 @@ static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio, unsigned int pin) { const struct tegra_gpio_port *port; + unsigned int offset; port = tegra186_gpio_get_port(gpio, &pin); if (!port) return NULL; - return gpio->base + port->offset + pin * 0x20; + offset = port->bank * 0x1000 + port->port * 0x200; + + return gpio->base + offset + pin * 0x20; } static int tegra186_gpio_get_direction(struct gpio_chip *chip, @@ -110,9 +124,9 @@ static int tegra186_gpio_get_direction(struct gpio_chip *chip, value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT) - return 0; + return GPIO_LINE_DIRECTION_OUT; - return 1; + return GPIO_LINE_DIRECTION_IN; } static int tegra186_gpio_direction_input(struct gpio_chip *chip, @@ -204,6 +218,42 @@ static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset, writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE); } +static int tegra186_gpio_set_config(struct gpio_chip *chip, + unsigned int offset, + unsigned long config) +{ + struct tegra_gpio *gpio = gpiochip_get_data(chip); + u32 debounce, value; + void __iomem *base; + + base = tegra186_gpio_get_base(gpio, offset); + if (base == NULL) + return -ENXIO; + + if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) + return -ENOTSUPP; + + debounce = pinconf_to_config_argument(config); + + /* + * The Tegra186 GPIO controller supports a maximum of 255 ms debounce + * time. + */ + if (debounce > 255000) + return -EINVAL; + + debounce = DIV_ROUND_UP(debounce, USEC_PER_MSEC); + + value = TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(debounce); + writel(value, base + TEGRA186_GPIO_DEBOUNCE_CONTROL); + + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); + value |= TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE; + writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); + + return 0; +} + static int tegra186_gpio_of_xlate(struct gpio_chip *chip, const struct of_phandle_args *spec, u32 *flags) @@ -327,7 +377,7 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int type) else irq_set_handler_locked(data, handle_edge_irq); - return 0; + return irq_chip_set_type_parent(data, type); } static void tegra186_gpio_irq(struct irq_desc *desc) @@ -342,12 +392,14 @@ static void tegra186_gpio_irq(struct irq_desc *desc) for (i = 0; i < gpio->soc->num_ports; i++) { const struct tegra_gpio_port *port = &gpio->soc->ports[i]; - void __iomem *base = gpio->base + port->offset; unsigned int pin, irq; unsigned long value; + void __iomem *base; - /* skip ports that are not associated with this controller */ - if (parent != gpio->irq[port->irq]) + base = gpio->base + port->bank * 0x1000 + port->port * 0x200; + + /* skip ports that are not associated with this bank */ + if (parent != gpio->irq[port->bank]) goto skip; value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); @@ -367,46 +419,119 @@ skip: chained_irq_exit(chip, desc); } -static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain, - struct device_node *np, - const u32 *spec, unsigned int size, - unsigned long *hwirq, - unsigned int *type) +static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data); unsigned int port, pin, i, offset = 0; - if (size < 2) + if (WARN_ON(gpio->gpio.of_gpio_n_cells < 2)) + return -EINVAL; + + if (WARN_ON(fwspec->param_count < gpio->gpio.of_gpio_n_cells)) return -EINVAL; - port = spec[0] / 8; - pin = spec[0] % 8; + port = fwspec->param[0] / 8; + pin = fwspec->param[0] % 8; - if (port >= gpio->soc->num_ports) { - dev_err(gpio->gpio.parent, "invalid port number: %u\n", port); + if (port >= gpio->soc->num_ports) return -EINVAL; - } for (i = 0; i < port; i++) offset += gpio->soc->ports[i].pins; - *type = spec[1] & IRQ_TYPE_SENSE_MASK; + *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; *hwirq = offset + pin; return 0; } -static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = { - .map = gpiochip_irq_map, - .unmap = gpiochip_irq_unmap, - .xlate = tegra186_gpio_irq_domain_xlate, +static void tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip, + struct irq_fwspec *fwspec, + unsigned int parent_hwirq, + unsigned int parent_type) +{ + struct tegra_gpio *gpio = gpiochip_get_data(chip); + + fwspec->param_count = 3; + fwspec->param[0] = gpio->soc->instance; + fwspec->param[1] = parent_hwirq; + fwspec->param[2] = parent_type; +} + +static int tegra186_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 unsigned int tegra186_gpio_child_offset_to_irq(struct gpio_chip *chip, + unsigned int offset) +{ + struct tegra_gpio *gpio = gpiochip_get_data(chip); + unsigned int i; + + for (i = 0; i < gpio->soc->num_ports; i++) { + if (offset < gpio->soc->ports[i].pins) + break; + + offset -= gpio->soc->ports[i].pins; + } + + return offset + i * 8; +} + +static const struct of_device_id tegra186_pmc_of_match[] = { + { .compatible = "nvidia,tegra186-pmc" }, + { .compatible = "nvidia,tegra194-pmc" }, + { /* sentinel */ } }; +static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) +{ + unsigned int i, j; + u32 value; + + for (i = 0; i < gpio->soc->num_ports; i++) { + const struct tegra_gpio_port *port = &gpio->soc->ports[i]; + unsigned int offset, p = port->port; + void __iomem *base; + + base = gpio->secure + port->bank * 0x1000 + 0x800; + + value = readl(base + TEGRA186_GPIO_CTL_SCR); + + /* + * For controllers that haven't been locked down yet, make + * sure to program the default interrupt route mapping. + */ + if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 && + (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) { + for (j = 0; j < 8; j++) { + offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j); + + value = readl(base + offset); + value = BIT(port->pins) - 1; + writel(value, base + offset); + } + } + } +} + static int tegra186_gpio_probe(struct platform_device *pdev) { unsigned int i, j, offset; struct gpio_irq_chip *irq; struct tegra_gpio *gpio; + struct device_node *np; char **names; int err; @@ -416,6 +541,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->soc = of_device_get_match_data(&pdev->dev); + gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security"); + if (IS_ERR(gpio->secure)) + return PTR_ERR(gpio->secure); + gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio"); if (IS_ERR(gpio->base)) return PTR_ERR(gpio->base); @@ -447,6 +576,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.direction_output = tegra186_gpio_direction_output; gpio->gpio.get = tegra186_gpio_get, gpio->gpio.set = tegra186_gpio_set; + gpio->gpio.set_config = tegra186_gpio_set_config; gpio->gpio.base = -1; @@ -485,10 +615,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->intc.irq_mask = tegra186_irq_mask; gpio->intc.irq_unmask = tegra186_irq_unmask; gpio->intc.irq_set_type = tegra186_irq_set_type; + gpio->intc.irq_set_wake = irq_chip_set_wake_parent; irq = &gpio->gpio.irq; irq->chip = &gpio->intc; - irq->domain_ops = &tegra186_gpio_irq_domain_ops; + irq->fwnode = of_node_to_fwnode(pdev->dev.of_node); + irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq; + irq->populate_parent_fwspec = tegra186_gpio_populate_parent_fwspec; + irq->child_offset_to_irq = tegra186_gpio_child_offset_to_irq; + irq->child_irq_domain_ops.translate = tegra186_gpio_irq_domain_translate; irq->handler = handle_simple_irq; irq->default_type = IRQ_TYPE_NONE; irq->parent_handler = tegra186_gpio_irq; @@ -496,6 +631,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev) irq->num_parents = gpio->num_irq; irq->parents = gpio->irq; + np = of_find_matching_node(NULL, tegra186_pmc_of_match); + if (np) { + irq->parent_domain = irq_find_host(np); + of_node_put(np); + + if (!irq->parent_domain) + return -EPROBE_DEFER; + } + + tegra186_gpio_init_route_mapping(gpio); + irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio, sizeof(*irq->map), GFP_KERNEL); if (!irq->map) @@ -505,7 +651,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) const struct tegra_gpio_port *port = &gpio->soc->ports[i]; for (j = 0; j < port->pins; j++) - irq->map[offset + j] = irq->parents[port->irq]; + irq->map[offset + j] = irq->parents[port->bank]; offset += port->pins; } @@ -524,136 +670,140 @@ static int tegra186_gpio_remove(struct platform_device *pdev) return 0; } -#define TEGRA186_MAIN_GPIO_PORT(port, base, count, controller) \ - [TEGRA186_MAIN_GPIO_PORT_##port] = { \ - .name = #port, \ - .offset = base, \ - .pins = count, \ - .irq = controller, \ +#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA186_MAIN_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } static const struct tegra_gpio_port tegra186_main_ports[] = { - TEGRA186_MAIN_GPIO_PORT( A, 0x2000, 7, 2), - TEGRA186_MAIN_GPIO_PORT( B, 0x3000, 7, 3), - TEGRA186_MAIN_GPIO_PORT( C, 0x3200, 7, 3), - TEGRA186_MAIN_GPIO_PORT( D, 0x3400, 6, 3), - TEGRA186_MAIN_GPIO_PORT( E, 0x2200, 8, 2), - TEGRA186_MAIN_GPIO_PORT( F, 0x2400, 6, 2), - TEGRA186_MAIN_GPIO_PORT( G, 0x4200, 6, 4), - TEGRA186_MAIN_GPIO_PORT( H, 0x1000, 7, 1), - TEGRA186_MAIN_GPIO_PORT( I, 0x0800, 8, 0), - TEGRA186_MAIN_GPIO_PORT( J, 0x5000, 8, 5), - TEGRA186_MAIN_GPIO_PORT( K, 0x5200, 1, 5), - TEGRA186_MAIN_GPIO_PORT( L, 0x1200, 8, 1), - TEGRA186_MAIN_GPIO_PORT( M, 0x5600, 6, 5), - TEGRA186_MAIN_GPIO_PORT( N, 0x0000, 7, 0), - TEGRA186_MAIN_GPIO_PORT( O, 0x0200, 4, 0), - TEGRA186_MAIN_GPIO_PORT( P, 0x4000, 7, 4), - TEGRA186_MAIN_GPIO_PORT( Q, 0x0400, 6, 0), - TEGRA186_MAIN_GPIO_PORT( R, 0x0a00, 6, 0), - TEGRA186_MAIN_GPIO_PORT( T, 0x0600, 4, 0), - TEGRA186_MAIN_GPIO_PORT( X, 0x1400, 8, 1), - TEGRA186_MAIN_GPIO_PORT( Y, 0x1600, 7, 1), - TEGRA186_MAIN_GPIO_PORT(BB, 0x2600, 2, 2), - TEGRA186_MAIN_GPIO_PORT(CC, 0x5400, 4, 5), + TEGRA186_MAIN_GPIO_PORT( A, 2, 0, 7), + TEGRA186_MAIN_GPIO_PORT( B, 3, 0, 7), + TEGRA186_MAIN_GPIO_PORT( C, 3, 1, 7), + TEGRA186_MAIN_GPIO_PORT( D, 3, 2, 6), + TEGRA186_MAIN_GPIO_PORT( E, 2, 1, 8), + TEGRA186_MAIN_GPIO_PORT( F, 2, 2, 6), + TEGRA186_MAIN_GPIO_PORT( G, 4, 1, 6), + TEGRA186_MAIN_GPIO_PORT( H, 1, 0, 7), + TEGRA186_MAIN_GPIO_PORT( I, 0, 4, 8), + TEGRA186_MAIN_GPIO_PORT( J, 5, 0, 8), + TEGRA186_MAIN_GPIO_PORT( K, 5, 1, 1), + TEGRA186_MAIN_GPIO_PORT( L, 1, 1, 8), + TEGRA186_MAIN_GPIO_PORT( M, 5, 3, 6), + TEGRA186_MAIN_GPIO_PORT( N, 0, 0, 7), + TEGRA186_MAIN_GPIO_PORT( O, 0, 1, 4), + TEGRA186_MAIN_GPIO_PORT( P, 4, 0, 7), + TEGRA186_MAIN_GPIO_PORT( Q, 0, 2, 6), + TEGRA186_MAIN_GPIO_PORT( R, 0, 5, 6), + TEGRA186_MAIN_GPIO_PORT( T, 0, 3, 4), + TEGRA186_MAIN_GPIO_PORT( X, 1, 2, 8), + TEGRA186_MAIN_GPIO_PORT( Y, 1, 3, 7), + TEGRA186_MAIN_GPIO_PORT(BB, 2, 3, 2), + TEGRA186_MAIN_GPIO_PORT(CC, 5, 2, 4), }; static const struct tegra_gpio_soc tegra186_main_soc = { .num_ports = ARRAY_SIZE(tegra186_main_ports), .ports = tegra186_main_ports, .name = "tegra186-gpio", + .instance = 0, }; -#define TEGRA186_AON_GPIO_PORT(port, base, count, controller) \ - [TEGRA186_AON_GPIO_PORT_##port] = { \ - .name = #port, \ - .offset = base, \ - .pins = count, \ - .irq = controller, \ +#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA186_AON_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } static const struct tegra_gpio_port tegra186_aon_ports[] = { - TEGRA186_AON_GPIO_PORT( S, 0x0200, 5, 0), - TEGRA186_AON_GPIO_PORT( U, 0x0400, 6, 0), - TEGRA186_AON_GPIO_PORT( V, 0x0800, 8, 0), - TEGRA186_AON_GPIO_PORT( W, 0x0a00, 8, 0), - TEGRA186_AON_GPIO_PORT( Z, 0x0e00, 4, 0), - TEGRA186_AON_GPIO_PORT(AA, 0x0c00, 8, 0), - TEGRA186_AON_GPIO_PORT(EE, 0x0600, 3, 0), - TEGRA186_AON_GPIO_PORT(FF, 0x0000, 5, 0), + TEGRA186_AON_GPIO_PORT( S, 0, 1, 5), + TEGRA186_AON_GPIO_PORT( U, 0, 2, 6), + TEGRA186_AON_GPIO_PORT( V, 0, 4, 8), + TEGRA186_AON_GPIO_PORT( W, 0, 5, 8), + TEGRA186_AON_GPIO_PORT( Z, 0, 7, 4), + TEGRA186_AON_GPIO_PORT(AA, 0, 6, 8), + TEGRA186_AON_GPIO_PORT(EE, 0, 3, 3), + TEGRA186_AON_GPIO_PORT(FF, 0, 0, 5), }; static const struct tegra_gpio_soc tegra186_aon_soc = { .num_ports = ARRAY_SIZE(tegra186_aon_ports), .ports = tegra186_aon_ports, .name = "tegra186-gpio-aon", + .instance = 1, }; -#define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \ - [TEGRA194_MAIN_GPIO_PORT_##port] = { \ - .name = #port, \ - .offset = base, \ - .pins = count, \ - .irq = controller, \ +#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA194_MAIN_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } static const struct tegra_gpio_port tegra194_main_ports[] = { - TEGRA194_MAIN_GPIO_PORT( A, 0x1400, 8, 1), - TEGRA194_MAIN_GPIO_PORT( B, 0x4e00, 2, 4), - TEGRA194_MAIN_GPIO_PORT( C, 0x4600, 8, 4), - TEGRA194_MAIN_GPIO_PORT( D, 0x4800, 4, 4), - TEGRA194_MAIN_GPIO_PORT( E, 0x4a00, 8, 4), - TEGRA194_MAIN_GPIO_PORT( F, 0x4c00, 6, 4), - TEGRA194_MAIN_GPIO_PORT( G, 0x4000, 8, 4), - TEGRA194_MAIN_GPIO_PORT( H, 0x4200, 8, 4), - TEGRA194_MAIN_GPIO_PORT( I, 0x4400, 5, 4), - TEGRA194_MAIN_GPIO_PORT( J, 0x5200, 6, 5), - TEGRA194_MAIN_GPIO_PORT( K, 0x3000, 8, 3), - TEGRA194_MAIN_GPIO_PORT( L, 0x3200, 4, 3), - TEGRA194_MAIN_GPIO_PORT( M, 0x2600, 8, 2), - TEGRA194_MAIN_GPIO_PORT( N, 0x2800, 3, 2), - TEGRA194_MAIN_GPIO_PORT( O, 0x5000, 6, 5), - TEGRA194_MAIN_GPIO_PORT( P, 0x2a00, 8, 2), - TEGRA194_MAIN_GPIO_PORT( Q, 0x2c00, 8, 2), - TEGRA194_MAIN_GPIO_PORT( R, 0x2e00, 6, 2), - TEGRA194_MAIN_GPIO_PORT( S, 0x3600, 8, 3), - TEGRA194_MAIN_GPIO_PORT( T, 0x3800, 8, 3), - TEGRA194_MAIN_GPIO_PORT( U, 0x3a00, 1, 3), - TEGRA194_MAIN_GPIO_PORT( V, 0x1000, 8, 1), - TEGRA194_MAIN_GPIO_PORT( W, 0x1200, 2, 1), - TEGRA194_MAIN_GPIO_PORT( X, 0x2000, 8, 2), - TEGRA194_MAIN_GPIO_PORT( Y, 0x2200, 8, 2), - TEGRA194_MAIN_GPIO_PORT( Z, 0x2400, 8, 2), - TEGRA194_MAIN_GPIO_PORT(FF, 0x3400, 2, 3), - TEGRA194_MAIN_GPIO_PORT(GG, 0x0000, 2, 0) + TEGRA194_MAIN_GPIO_PORT( A, 1, 2, 8), + TEGRA194_MAIN_GPIO_PORT( B, 4, 7, 2), + TEGRA194_MAIN_GPIO_PORT( C, 4, 3, 8), + TEGRA194_MAIN_GPIO_PORT( D, 4, 4, 4), + TEGRA194_MAIN_GPIO_PORT( E, 4, 5, 8), + TEGRA194_MAIN_GPIO_PORT( F, 4, 6, 6), + TEGRA194_MAIN_GPIO_PORT( G, 4, 0, 8), + TEGRA194_MAIN_GPIO_PORT( H, 4, 1, 8), + TEGRA194_MAIN_GPIO_PORT( I, 4, 2, 5), + TEGRA194_MAIN_GPIO_PORT( J, 5, 1, 6), + TEGRA194_MAIN_GPIO_PORT( K, 3, 0, 8), + TEGRA194_MAIN_GPIO_PORT( L, 3, 1, 4), + TEGRA194_MAIN_GPIO_PORT( M, 2, 3, 8), + TEGRA194_MAIN_GPIO_PORT( N, 2, 4, 3), + TEGRA194_MAIN_GPIO_PORT( O, 5, 0, 6), + TEGRA194_MAIN_GPIO_PORT( P, 2, 5, 8), + TEGRA194_MAIN_GPIO_PORT( Q, 2, 6, 8), + TEGRA194_MAIN_GPIO_PORT( R, 2, 7, 6), + TEGRA194_MAIN_GPIO_PORT( S, 3, 3, 8), + TEGRA194_MAIN_GPIO_PORT( T, 3, 4, 8), + TEGRA194_MAIN_GPIO_PORT( U, 3, 5, 1), + TEGRA194_MAIN_GPIO_PORT( V, 1, 0, 8), + TEGRA194_MAIN_GPIO_PORT( W, 1, 1, 2), + TEGRA194_MAIN_GPIO_PORT( X, 2, 0, 8), + TEGRA194_MAIN_GPIO_PORT( Y, 2, 1, 8), + TEGRA194_MAIN_GPIO_PORT( Z, 2, 2, 8), + TEGRA194_MAIN_GPIO_PORT(FF, 3, 2, 2), + TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2) }; static const struct tegra_gpio_soc tegra194_main_soc = { .num_ports = ARRAY_SIZE(tegra194_main_ports), .ports = tegra194_main_ports, .name = "tegra194-gpio", + .instance = 0, }; -#define TEGRA194_AON_GPIO_PORT(port, base, count, controller) \ - [TEGRA194_AON_GPIO_PORT_##port] = { \ - .name = #port, \ - .offset = base, \ - .pins = count, \ - .irq = controller, \ +#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA194_AON_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } static const struct tegra_gpio_port tegra194_aon_ports[] = { - TEGRA194_AON_GPIO_PORT(AA, 0x0600, 8, 0), - TEGRA194_AON_GPIO_PORT(BB, 0x0800, 4, 0), - TEGRA194_AON_GPIO_PORT(CC, 0x0200, 8, 0), - TEGRA194_AON_GPIO_PORT(DD, 0x0400, 3, 0), - TEGRA194_AON_GPIO_PORT(EE, 0x0000, 7, 0) + TEGRA194_AON_GPIO_PORT(AA, 0, 3, 8), + TEGRA194_AON_GPIO_PORT(BB, 0, 4, 4), + TEGRA194_AON_GPIO_PORT(CC, 0, 1, 8), + TEGRA194_AON_GPIO_PORT(DD, 0, 2, 3), + TEGRA194_AON_GPIO_PORT(EE, 0, 0, 7) }; static const struct tegra_gpio_soc tegra194_aon_soc = { .num_ports = ARRAY_SIZE(tegra194_aon_ports), .ports = tegra194_aon_ports, .name = "tegra194-gpio-aon", + .instance = 1, }; static const struct of_device_id tegra186_gpio_of_match[] = { diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index ddad5c7ea617..d08d86a22b1f 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -169,7 +169,10 @@ static int thunderx_gpio_get_direction(struct gpio_chip *chip, unsigned int line bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line)); - return !(bit_cfg & GPIO_BIT_CFG_TX_OE); + if (bit_cfg & GPIO_BIT_CFG_TX_OE) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int thunderx_gpio_set_config(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c index c8b34d787eed..99d5a84a9129 100644 --- a/drivers/gpio/gpio-tpic2810.c +++ b/drivers/gpio/gpio-tpic2810.c @@ -39,7 +39,7 @@ static int tpic2810_get_direction(struct gpio_chip *chip, unsigned offset) { /* This device always output */ - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int tpic2810_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c index 2eea98ff4ea3..1e9d8262d0ff 100644 --- a/drivers/gpio/gpio-tps65086.c +++ b/drivers/gpio/gpio-tps65086.c @@ -21,7 +21,7 @@ static int tps65086_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { /* This device is output only */ - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int tps65086_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 3ad68bd78282..510d9ed9fd2a 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -32,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc, return ret; if (val & GPIO_CFG_MASK) - return 0; + return GPIO_LINE_DIRECTION_OUT; else - return 1; + return GPIO_LINE_DIRECTION_IN; } static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c index aff6e504c666..f7f5f770e0fb 100644 --- a/drivers/gpio/gpio-tps68470.c +++ b/drivers/gpio/gpio-tps68470.c @@ -47,7 +47,6 @@ static int tps68470_gpio_get(struct gpio_chip *gc, unsigned int offset) return !!(val & BIT(offset)); } -/* Return 0 if output, 1 if input */ static int tps68470_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) { @@ -57,7 +56,7 @@ static int tps68470_gpio_get_direction(struct gpio_chip *gc, /* rest are always outputs */ if (offset >= TPS68470_N_REGULAR_GPIO) - return 0; + return GPIO_LINE_DIRECTION_OUT; ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val); if (ret) { @@ -67,7 +66,8 @@ static int tps68470_gpio_get_direction(struct gpio_chip *gc, } val &= TPS68470_GPIO_MODE_MASK; - return val >= TPS68470_GPIO_MODE_OUT_CMOS ? 0 : 1; + return val >= TPS68470_GPIO_MODE_OUT_CMOS ? GPIO_LINE_DIRECTION_OUT : + GPIO_LINE_DIRECTION_IN; } static void tps68470_gpio_set(struct gpio_chip *gc, unsigned int offset, diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c index a3109bcaa0ac..5022e0ad0fae 100644 --- a/drivers/gpio/gpio-tqmx86.c +++ b/drivers/gpio/gpio-tqmx86.c @@ -101,7 +101,10 @@ static int tqmx86_gpio_direction_output(struct gpio_chip *chip, static int tqmx86_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { - return !!(TQMX86_DIR_INPUT_MASK & BIT(offset)); + if (TQMX86_DIR_INPUT_MASK & BIT(offset)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static void tqmx86_gpio_irq_mask(struct irq_data *data) diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c index 1da8d0586329..d885032cf814 100644 --- a/drivers/gpio/gpio-ts4900.c +++ b/drivers/gpio/gpio-ts4900.c @@ -44,7 +44,10 @@ static int ts4900_gpio_get_direction(struct gpio_chip *chip, regmap_read(priv->regmap, offset, ®); - return !(reg & TS4900_GPIO_OE); + if (reg & TS4900_GPIO_OE) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int ts4900_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index fbfb648d3502..de249726230e 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -165,10 +165,10 @@ static int twl4030_get_gpio_direction(int gpio) if (ret < 0) return ret; - /* 1 = output, but gpiolib semantics are inverse so invert */ - ret = !(ret & d_msk); + if (ret & d_msk) + return GPIO_LINE_DIRECTION_OUT; - return ret; + return GPIO_LINE_DIRECTION_IN; } static int twl4030_set_gpio_dataout(int gpio, int enable) @@ -380,10 +380,10 @@ static int twl_get_direction(struct gpio_chip *chip, unsigned offset) { struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); /* - * Default 0 = output + * Default GPIO_LINE_DIRECTION_OUT * LED GPIOs >= TWL4030_GPIO_MAX are always output */ - int ret = 0; + int ret = GPIO_LINE_DIRECTION_OUT; mutex_lock(&priv->mutex); if (offset < TWL4030_GPIO_MAX) { diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index c845b2ff1f43..648fb418d775 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -34,8 +34,7 @@ static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset) static int twl6040gpo_get_direction(struct gpio_chip *chip, unsigned offset) { - /* This means "out" */ - return 0; + return GPIO_LINE_DIRECTION_OUT; } static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset, diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 93cdcc41e9fb..bd203e8fa58e 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -113,7 +113,10 @@ static int uniphier_gpio_offset_read(struct gpio_chip *chip, static int uniphier_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { - return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR); + if (uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int uniphier_gpio_direction_input(struct gpio_chip *chip, diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 444fe9e7f04a..8b481b3c1ebe 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -170,13 +170,16 @@ static int wcove_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) int ret, reg = to_reg(gpio, CTRL_OUT); if (reg < 0) - return 0; + return GPIO_LINE_DIRECTION_OUT; ret = regmap_read(wg->regmap, reg, &val); if (ret) return ret; - return !(val & CTLO_DIR_OUT); + if (val & CTLO_DIR_OUT) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } static int wcove_gpio_get(struct gpio_chip *chip, unsigned int gpio) diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index e0ef66b6a237..fe456bea81f6 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -56,7 +56,10 @@ static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) const unsigned port = offset / 8; const unsigned mask = BIT(offset % 8); - return !!(ws16c48gpio->io_state[port] & mask); + if (ws16c48gpio->io_state[port] & mask) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c index 2918363884de..532b0df8a1f2 100644 --- a/drivers/gpio/gpio-xgene.c +++ b/drivers/gpio/gpio-xgene.c @@ -80,7 +80,10 @@ static int xgene_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); bit_offset = GPIO_BIT_OFFSET(offset); - return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset)); + if (ioread32(chip->base + bank_offset) & BIT(bit_offset)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) @@ -155,28 +158,16 @@ static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume); static int xgene_gpio_probe(struct platform_device *pdev) { - struct resource *res; struct xgene_gpio *gpio; int err = 0; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) { - err = -ENOMEM; - goto err; - } + if (!gpio) + return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - err = -EINVAL; - goto err; - } - - gpio->base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!gpio->base) { - err = -ENOMEM; - goto err; - } + gpio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(gpio->base)) + return PTR_ERR(gpio->base); gpio->chip.ngpio = XGENE_MAX_GPIOS; @@ -196,14 +187,11 @@ static int xgene_gpio_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "failed to register gpiochip.\n"); - goto err; + return err; } dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n"); return 0; -err: - dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n"); - return err; } static const struct of_device_id xgene_gpio_of_match[] = { diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c new file mode 100644 index 000000000000..773e5c24309e --- /dev/null +++ b/drivers/gpio/gpio-xgs-iproc.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Broadcom + */ + +#include <linux/gpio/driver.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#define IPROC_CCA_INT_F_GPIOINT BIT(0) +#define IPROC_CCA_INT_STS 0x20 +#define IPROC_CCA_INT_MASK 0x24 + +#define IPROC_GPIO_CCA_DIN 0x0 +#define IPROC_GPIO_CCA_DOUT 0x4 +#define IPROC_GPIO_CCA_OUT_EN 0x8 +#define IPROC_GPIO_CCA_INT_LEVEL 0x10 +#define IPROC_GPIO_CCA_INT_LEVEL_MASK 0x14 +#define IPROC_GPIO_CCA_INT_EVENT 0x18 +#define IPROC_GPIO_CCA_INT_EVENT_MASK 0x1C +#define IPROC_GPIO_CCA_INT_EDGE 0x24 + +struct iproc_gpio_chip { + struct irq_chip irqchip; + struct gpio_chip gc; + spinlock_t lock; + struct device *dev; + void __iomem *base; + void __iomem *intr; +}; + +static inline struct iproc_gpio_chip * +to_iproc_gpio(struct gpio_chip *gc) +{ + return container_of(gc, struct iproc_gpio_chip, gc); +} + +static void iproc_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 irq = d->irq; + u32 irq_type, event_status = 0; + + spin_lock_irqsave(&chip->lock, flags); + irq_type = irq_get_trigger_type(irq); + if (irq_type & IRQ_TYPE_EDGE_BOTH) { + event_status |= BIT(pin); + writel_relaxed(event_status, + chip->base + IPROC_GPIO_CCA_INT_EVENT); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + +static void iproc_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 irq = d->irq; + u32 int_mask, irq_type, event_mask; + + spin_lock_irqsave(&chip->lock, flags); + irq_type = irq_get_trigger_type(irq); + event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + + if (irq_type & IRQ_TYPE_EDGE_BOTH) { + event_mask |= 1 << pin; + writel_relaxed(event_mask, + chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + } else { + int_mask |= 1 << pin; + writel_relaxed(int_mask, + chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + +static void iproc_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 irq = d->irq; + u32 irq_type, int_mask, event_mask; + + spin_lock_irqsave(&chip->lock, flags); + irq_type = irq_get_trigger_type(irq); + event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + + if (irq_type & IRQ_TYPE_EDGE_BOTH) { + event_mask &= ~BIT(pin); + writel_relaxed(event_mask, + chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + } else { + int_mask &= ~BIT(pin); + writel_relaxed(int_mask, + chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + +static int iproc_gpio_irq_set_type(struct irq_data *d, u32 type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 irq = d->irq; + u32 event_pol, int_pol; + int ret = 0; + + spin_lock_irqsave(&chip->lock, flags); + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE); + event_pol &= ~BIT(pin); + writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE); + break; + case IRQ_TYPE_EDGE_FALLING: + event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE); + event_pol |= BIT(pin); + writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE); + break; + case IRQ_TYPE_LEVEL_HIGH: + int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL); + int_pol &= ~BIT(pin); + writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL); + break; + case IRQ_TYPE_LEVEL_LOW: + int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL); + int_pol |= BIT(pin); + writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL); + break; + default: + /* should not come here */ + ret = -EINVAL; + goto out_unlock; + } + + if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(irq_get_irq_data(irq), handle_level_irq); + else if (type & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(irq_get_irq_data(irq), handle_edge_irq); + +out_unlock: + spin_unlock_irqrestore(&chip->lock, flags); + + return ret; +} + +static irqreturn_t iproc_gpio_irq_handler(int irq, void *data) +{ + struct gpio_chip *gc = (struct gpio_chip *)data; + struct iproc_gpio_chip *chip = to_iproc_gpio(gc); + int bit; + unsigned long int_bits = 0; + u32 int_status; + + /* go through the entire GPIOs and handle all interrupts */ + int_status = readl_relaxed(chip->intr + IPROC_CCA_INT_STS); + if (int_status & IPROC_CCA_INT_F_GPIOINT) { + u32 event, level; + + /* Get level and edge interrupts */ + event = + readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK); + event &= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT); + level = readl_relaxed(chip->base + IPROC_GPIO_CCA_DIN); + level ^= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL); + level &= + readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK); + int_bits = level | event; + + for_each_set_bit(bit, &int_bits, gc->ngpio) + generic_handle_irq(irq_linear_revmap(gc->irq.domain, bit)); + } + + return int_bits ? IRQ_HANDLED : IRQ_NONE; +} + +static int iproc_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *dn = pdev->dev.of_node; + struct iproc_gpio_chip *chip; + u32 num_gpios; + int irq, ret; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = dev; + platform_set_drvdata(pdev, chip); + spin_lock_init(&chip->lock); + + chip->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); + + ret = bgpio_init(&chip->gc, dev, 4, + chip->base + IPROC_GPIO_CCA_DIN, + chip->base + IPROC_GPIO_CCA_DOUT, + NULL, + chip->base + IPROC_GPIO_CCA_OUT_EN, + NULL, + 0); + if (ret) { + dev_err(dev, "unable to init GPIO chip\n"); + return ret; + } + + chip->gc.label = dev_name(dev); + if (of_property_read_u32(dn, "ngpios", &num_gpios)) + chip->gc.ngpio = num_gpios; + + irq = platform_get_irq(pdev, 0); + if (irq > 0) { + struct gpio_irq_chip *girq; + struct irq_chip *irqc; + u32 val; + + irqc = &chip->irqchip; + irqc->name = dev_name(dev); + irqc->irq_ack = iproc_gpio_irq_ack; + irqc->irq_mask = iproc_gpio_irq_mask; + irqc->irq_unmask = iproc_gpio_irq_unmask; + irqc->irq_set_type = iproc_gpio_irq_set_type; + + chip->intr = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(chip->intr)) + return PTR_ERR(chip->intr); + + /* Enable GPIO interrupts for CCA GPIO */ + val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK); + val |= IPROC_CCA_INT_F_GPIOINT; + writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK); + + /* + * Directly request the irq here instead of passing + * a flow-handler to gpiochip_set_chained_irqchip, + * because the irq is shared. + */ + ret = devm_request_irq(dev, irq, iproc_gpio_irq_handler, + IRQF_SHARED, chip->gc.label, &chip->gc); + if (ret) { + dev_err(dev, "Fail to request IRQ%d: %d\n", irq, ret); + return ret; + } + + girq = &chip->gc.irq; + girq->chip = irqc; + /* This will let us handle the parent IRQ in the driver */ + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + } + + ret = devm_gpiochip_add_data(dev, &chip->gc, chip); + if (ret) { + dev_err(dev, "unable to add GPIO chip\n"); + return ret; + } + + return 0; +} + +static int __exit iproc_gpio_remove(struct platform_device *pdev) +{ + struct iproc_gpio_chip *chip; + + chip = platform_get_drvdata(pdev); + if (!chip) + return -ENODEV; + + if (chip->intr) { + u32 val; + + val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK); + val &= ~IPROC_CCA_INT_F_GPIOINT; + writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK); + } + + return 0; +} + +static const struct of_device_id bcm_iproc_gpio_of_match[] = { + { .compatible = "brcm,iproc-gpio-cca" }, + {} +}; +MODULE_DEVICE_TABLE(of, bcm_iproc_gpio_of_match); + +static struct platform_driver bcm_iproc_gpio_driver = { + .driver = { + .name = "iproc-xgs-gpio", + .of_match_table = bcm_iproc_gpio_of_match, + }, + .probe = iproc_gpio_probe, + .remove = iproc_gpio_remove, +}; + +module_platform_driver(bcm_iproc_gpio_driver); + +MODULE_DESCRIPTION("XGS IPROC GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c index 05f1998c11a4..31b5072b2df0 100644 --- a/drivers/gpio/gpio-xra1403.c +++ b/drivers/gpio/gpio-xra1403.c @@ -83,7 +83,10 @@ static int xra1403_get_direction(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - return !!(val & BIT(offset % 8)); + if (val & BIT(offset % 8)) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; } static int xra1403_get(struct gpio_chip *chip, unsigned int offset) diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c index 43d3fa5f511a..08d7c3b32038 100644 --- a/drivers/gpio/gpio-xtensa.c +++ b/drivers/gpio/gpio-xtensa.c @@ -72,7 +72,7 @@ static inline void disable_cp(unsigned long flags, unsigned long cpenable) static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset) { - return 1; /* input only */ + return GPIO_LINE_DIRECTION_IN; /* input only */ } static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset) @@ -95,7 +95,7 @@ static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset, static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset) { - return 0; /* output only */ + return GPIO_LINE_DIRECTION_OUT; /* output only */ } static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index cd475ff4bcad..4c3f6370eab4 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -360,7 +360,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, * * This function returns the direction of the specified GPIO. * - * Return: 0 for output, 1 for input + * Return: GPIO_LINE_DIRECTION_OUT or GPIO_LINE_DIRECTION_IN */ static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) { @@ -372,7 +372,10 @@ static int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); - return !(reg & BIT(bank_pin_num)); + if (reg & BIT(bank_pin_num)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; } /** diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 59ccfd24627d..d30e57dc755c 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -194,6 +194,7 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio) acpi_gpiochip_request_irq(acpi_gpio, event); } +/* Always returns AE_OK so that we keep looping over the resources */ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, void *context) { @@ -230,19 +231,25 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event", GPIO_ACTIVE_HIGH, GPIOD_IN); if (IS_ERR(desc)) { - dev_err(chip->parent, "Failed to request GPIO\n"); - return AE_ERROR; + dev_err(chip->parent, + "Failed to request GPIO for pin 0x%04X, err %ld\n", + pin, PTR_ERR(desc)); + return AE_OK; } ret = gpiochip_lock_as_irq(chip, pin); if (ret) { - dev_err(chip->parent, "Failed to lock GPIO as interrupt\n"); + dev_err(chip->parent, + "Failed to lock GPIO pin 0x%04X as interrupt, err %d\n", + pin, ret); goto fail_free_desc; } irq = gpiod_to_irq(desc); if (irq < 0) { - dev_err(chip->parent, "Failed to translate GPIO to IRQ\n"); + dev_err(chip->parent, + "Failed to translate GPIO pin 0x%04X to IRQ, err %d\n", + pin, irq); goto fail_unlock_irq; } @@ -287,7 +294,7 @@ fail_unlock_irq: fail_free_desc: gpiochip_free_own_desc(desc); - return AE_ERROR; + return AE_OK; } /** diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 80ea49f570f4..dc27b1a88e93 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -27,7 +27,7 @@ * This is used by external users of of_gpio_count() from <linux/of_gpio.h> * * FIXME: get rid of those external users by converting them to GPIO - * descriptors and let them all use gpiod_get_count() + * descriptors and let them all use gpiod_count() */ int of_gpio_get_count(struct device *dev, const char *con_id) { @@ -84,8 +84,9 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, /** * of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs * to set the .valid_mask - * @dev: the device for the GPIO provider - * @return: true if the valid mask needs to be set + * @gc: the target gpio_chip + * + * Return: true if the valid mask needs to be set */ bool of_gpio_need_valid_mask(const struct gpio_chip *gc) { @@ -134,18 +135,20 @@ static void of_gpio_flags_quirks(struct device_node *np, (!(strcmp(propname, "enable-gpio") && strcmp(propname, "enable-gpios")) && of_device_is_compatible(np, "regulator-gpio")))) { + bool active_low = !of_property_read_bool(np, + "enable-active-high"); /* * The regulator GPIO handles are specified such that the * presence or absence of "enable-active-high" solely controls * the polarity of the GPIO line. Any phandle flags must * be actively ignored. */ - if (*flags & OF_GPIO_ACTIVE_LOW) { + if ((*flags & OF_GPIO_ACTIVE_LOW) && !active_low) { pr_warn("%s GPIO handle specifies active low - ignored\n", of_node_full_name(np)); *flags &= ~OF_GPIO_ACTIVE_LOW; } - if (!of_property_read_bool(np, "enable-active-high")) + if (active_low) *flags |= OF_GPIO_ACTIVE_LOW; } /* @@ -882,16 +885,13 @@ int of_gpiochip_add(struct gpio_chip *chip) of_node_get(chip->of_node); ret = of_gpiochip_scan_gpios(chip); - if (ret) { + if (ret) of_node_put(chip->of_node); - gpiochip_remove_pin_ranges(chip); - } return ret; } void of_gpiochip_remove(struct gpio_chip *chip) { - gpiochip_remove_pin_ranges(chip); of_node_put(chip->of_node); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index fb33ff6fc1a9..9913886ede90 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -390,6 +390,14 @@ static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip) gpiochip->valid_mask = NULL; } +static int gpiochip_add_pin_ranges(struct gpio_chip *gc) +{ + if (gc->add_pin_ranges) + return gc->add_pin_ranges(gc); + + return 0; +} + bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip, unsigned int offset) { @@ -422,9 +430,127 @@ struct linehandle_state { (GPIOHANDLE_REQUEST_INPUT | \ GPIOHANDLE_REQUEST_OUTPUT | \ GPIOHANDLE_REQUEST_ACTIVE_LOW | \ + GPIOHANDLE_REQUEST_BIAS_PULL_UP | \ + GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \ + GPIOHANDLE_REQUEST_BIAS_DISABLE | \ GPIOHANDLE_REQUEST_OPEN_DRAIN | \ GPIOHANDLE_REQUEST_OPEN_SOURCE) +static int linehandle_validate_flags(u32 flags) +{ + /* Return an error if an unknown flag is set */ + if (flags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) + return -EINVAL; + + /* + * Do not allow both INPUT & OUTPUT flags to be set as they are + * contradictory. + */ + if ((flags & GPIOHANDLE_REQUEST_INPUT) && + (flags & GPIOHANDLE_REQUEST_OUTPUT)) + return -EINVAL; + + /* + * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If + * the hardware actually supports enabling both at the same time the + * electrical result would be disastrous. + */ + if ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) && + (flags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) + return -EINVAL; + + /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */ + if (!(flags & GPIOHANDLE_REQUEST_OUTPUT) && + ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || + (flags & GPIOHANDLE_REQUEST_OPEN_SOURCE))) + return -EINVAL; + + /* Bias flags only allowed for input or output mode. */ + if (!((flags & GPIOHANDLE_REQUEST_INPUT) || + (flags & GPIOHANDLE_REQUEST_OUTPUT)) && + ((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) || + (flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || + (flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN))) + return -EINVAL; + + /* Only one bias flag can be set. */ + if (((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) && + (flags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | + GPIOHANDLE_REQUEST_BIAS_PULL_UP))) || + ((flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) && + (flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP))) + return -EINVAL; + + return 0; +} + +static void linehandle_configure_flag(unsigned long *flagsp, + u32 bit, bool active) +{ + if (active) + set_bit(bit, flagsp); + else + clear_bit(bit, flagsp); +} + +static long linehandle_set_config(struct linehandle_state *lh, + void __user *ip) +{ + struct gpiohandle_config gcnf; + struct gpio_desc *desc; + int i, ret; + u32 lflags; + unsigned long *flagsp; + + if (copy_from_user(&gcnf, ip, sizeof(gcnf))) + return -EFAULT; + + lflags = gcnf.flags; + ret = linehandle_validate_flags(lflags); + if (ret) + return ret; + + for (i = 0; i < lh->numdescs; i++) { + desc = lh->descs[i]; + flagsp = &desc->flags; + + linehandle_configure_flag(flagsp, FLAG_ACTIVE_LOW, + lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW); + + linehandle_configure_flag(flagsp, FLAG_OPEN_DRAIN, + lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN); + + linehandle_configure_flag(flagsp, FLAG_OPEN_SOURCE, + lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE); + + linehandle_configure_flag(flagsp, FLAG_PULL_UP, + lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP); + + linehandle_configure_flag(flagsp, FLAG_PULL_DOWN, + lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN); + + linehandle_configure_flag(flagsp, FLAG_BIAS_DISABLE, + lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE); + + /* + * Lines have to be requested explicitly for input + * or output, else the line will be treated "as is". + */ + if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { + int val = !!gcnf.default_values[i]; + + ret = gpiod_direction_output(desc, val); + if (ret) + return ret; + } else if (lflags & GPIOHANDLE_REQUEST_INPUT) { + ret = gpiod_direction_input(desc); + if (ret) + return ret; + } + } + return 0; +} + static long linehandle_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { @@ -475,6 +601,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, lh->descs, NULL, vals); + } else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) { + return linehandle_set_config(lh, ip); } return -EINVAL; } @@ -526,32 +654,9 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) lflags = handlereq.flags; - /* Return an error if an unknown flag is set */ - if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) - return -EINVAL; - - /* - * Do not allow both INPUT & OUTPUT flags to be set as they are - * contradictory. - */ - if ((lflags & GPIOHANDLE_REQUEST_INPUT) && - (lflags & GPIOHANDLE_REQUEST_OUTPUT)) - return -EINVAL; - - /* - * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If - * the hardware actually supports enabling both at the same time the - * electrical result would be disastrous. - */ - if ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) && - (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) - return -EINVAL; - - /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */ - if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) && - ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || - (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))) - return -EINVAL; + ret = linehandle_validate_flags(lflags); + if (ret) + return ret; lh = kzalloc(sizeof(*lh), GFP_KERNEL); if (!lh) @@ -593,6 +698,12 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) set_bit(FLAG_OPEN_DRAIN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) + set_bit(FLAG_BIAS_DISABLE, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) + set_bit(FLAG_PULL_DOWN, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) + set_bit(FLAG_PULL_UP, &desc->flags); ret = gpiod_set_transitory(desc, false); if (ret < 0) @@ -895,6 +1006,32 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) if (copy_from_user(&eventreq, ip, sizeof(eventreq))) return -EFAULT; + offset = eventreq.lineoffset; + lflags = eventreq.handleflags; + eflags = eventreq.eventflags; + + if (offset >= gdev->ngpio) + return -EINVAL; + + /* Return an error if a unknown flag is set */ + if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) || + (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) + return -EINVAL; + + /* This is just wrong: we don't look for events on output lines */ + if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) || + (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || + (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) + return -EINVAL; + + /* Only one bias flag can be set. */ + if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) && + (lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | + GPIOHANDLE_REQUEST_BIAS_PULL_UP))) || + ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) && + (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP))) + return -EINVAL; + le = kzalloc(sizeof(*le), GFP_KERNEL); if (!le) return -ENOMEM; @@ -912,30 +1049,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) } } - offset = eventreq.lineoffset; - lflags = eventreq.handleflags; - eflags = eventreq.eventflags; - - if (offset >= gdev->ngpio) { - ret = -EINVAL; - goto out_free_label; - } - - /* Return an error if a unknown flag is set */ - if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) || - (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) { - ret = -EINVAL; - goto out_free_label; - } - - /* This is just wrong: we don't look for events on output lines */ - if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) || - (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || - (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) { - ret = -EINVAL; - goto out_free_label; - } - desc = &gdev->descs[offset]; ret = gpiod_request(desc, le->label); if (ret) @@ -945,6 +1058,12 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) + set_bit(FLAG_BIAS_DISABLE, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) + set_bit(FLAG_PULL_DOWN, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) + set_bit(FLAG_PULL_UP, &desc->flags); ret = gpiod_direction_input(desc); if (ret) @@ -1098,6 +1217,12 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE | GPIOLINE_FLAG_IS_OUT); + if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_BIAS_DISABLE; + if (test_bit(FLAG_PULL_DOWN, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN; + if (test_bit(FLAG_PULL_UP, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_UP; if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; @@ -1403,15 +1528,19 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, } } + ret = gpiochip_add_pin_ranges(chip); + if (ret) + goto err_remove_of_chip; + acpi_gpiochip_add(chip); machine_gpiochip_add(chip); - ret = gpiochip_irqchip_init_hw(chip); + ret = gpiochip_irqchip_init_valid_mask(chip); if (ret) goto err_remove_acpi_chip; - ret = gpiochip_irqchip_init_valid_mask(chip); + ret = gpiochip_irqchip_init_hw(chip); if (ret) goto err_remove_acpi_chip; @@ -1444,6 +1573,7 @@ err_remove_of_chip: gpiochip_free_hogs(chip); of_gpiochip_remove(chip); err_free_gpiochip_mask: + gpiochip_remove_pin_ranges(chip); gpiochip_free_valid_mask(chip); err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); @@ -1499,8 +1629,8 @@ void gpiochip_remove(struct gpio_chip *chip) gdev->chip = NULL; gpiochip_irqchip_remove(chip); acpi_gpiochip_remove(chip); - gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); + gpiochip_remove_pin_ranges(chip); gpiochip_free_valid_mask(chip); /* * We accept no more calls into the driver from this point, so @@ -1539,7 +1669,7 @@ static void devm_gpio_chip_release(struct device *dev, void *res) } /** - * devm_gpiochip_add_data() - Resource manager gpiochip_add_data() + * devm_gpiochip_add_data() - Resource managed gpiochip_add_data() * @dev: pointer to the device that gpio_chip belongs to. * @chip: the chip to register, with chip->base initialized * @data: driver-private data associated with this chip @@ -2790,6 +2920,9 @@ static bool gpiod_free_commit(struct gpio_desc *desc) clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); + clear_bit(FLAG_PULL_UP, &desc->flags); + clear_bit(FLAG_PULL_DOWN, &desc->flags); + clear_bit(FLAG_BIAS_DISABLE, &desc->flags); clear_bit(FLAG_IS_HOGGED, &desc->flags); ret = true; } @@ -2916,6 +3049,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset, unsigned arg; switch (mode) { + case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_UP: arg = 1; @@ -2929,6 +3063,26 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset, return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP; } +static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc) +{ + int bias = 0; + int ret = 0; + + if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) + bias = PIN_CONFIG_BIAS_DISABLE; + else if (test_bit(FLAG_PULL_UP, &desc->flags)) + bias = PIN_CONFIG_BIAS_PULL_UP; + else if (test_bit(FLAG_PULL_DOWN, &desc->flags)) + bias = PIN_CONFIG_BIAS_PULL_DOWN; + + if (bias) { + ret = gpio_set_config(chip, gpio_chip_hwgpio(desc), bias); + if (ret != -ENOTSUPP) + return ret; + } + return 0; +} + /** * gpiod_direction_input - set the GPIO direction to input * @desc: GPIO to set to input @@ -2973,15 +3127,10 @@ int gpiod_direction_input(struct gpio_desc *desc) __func__); return -EIO; } - if (ret == 0) + if (ret == 0) { clear_bit(FLAG_IS_OUT, &desc->flags); - - if (test_bit(FLAG_PULL_UP, &desc->flags)) - gpio_set_config(chip, gpio_chip_hwgpio(desc), - PIN_CONFIG_BIAS_PULL_UP); - else if (test_bit(FLAG_PULL_DOWN, &desc->flags)) - gpio_set_config(chip, gpio_chip_hwgpio(desc), - PIN_CONFIG_BIAS_PULL_DOWN); + ret = gpio_set_bias(chip, desc); + } trace_gpio_direction(desc_to_gpio(desc), 1, ret); @@ -3111,6 +3260,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) } set_output_value: + ret = gpio_set_bias(gc, desc); + if (ret) + return ret; return gpiod_direction_output_raw_commit(desc, value); set_output_flag: @@ -4742,9 +4894,9 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, pr_info("GPIO line %d (%s) hogged as %s%s\n", desc_to_gpio(desc), name, - (dflags&GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input", - (dflags&GPIOD_FLAGS_BIT_DIR_OUT) ? - (dflags&GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low":""); + (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input", + (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? + (dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : ""); return 0; } diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index b8b10a409c7b..ca9bc1e4803c 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -110,6 +110,7 @@ struct gpio_desc { #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ #define FLAG_PULL_UP 13 /* GPIO has pull up enabled */ #define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */ +#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */ /* Connection label */ const char *label; diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index aa3198dc9903..6f6d6d1e60ae 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -285,8 +285,8 @@ static int tfp410_get_connector_properties(struct tfp410 *dvi) else dvi->connector_type = DRM_MODE_CONNECTOR_DVID; - dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode, - "hpd-gpios", 0, GPIOD_IN, "hpd"); + dvi->hpd = fwnode_gpiod_get_index(&connector_node->fwnode, + "hpd", 0, GPIOD_IN, "hpd"); if (IS_ERR(dvi->hpd)) { ret = PTR_ERR(dvi->hpd); dvi->hpd = NULL; diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 5dd9c982e2cb..e2480ef94c55 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -22,6 +22,9 @@ enum gpio_lookup_flags; struct gpio_chip; +#define GPIO_LINE_DIRECTION_IN 1 +#define GPIO_LINE_DIRECTION_OUT 0 + /** * struct gpio_irq_chip - GPIO interrupt controller */ @@ -286,6 +289,9 @@ struct gpio_irq_chip { * state (such as pullup/pulldown configuration). * @init_valid_mask: optional routine to initialize @valid_mask, to be used if * not all GPIOs are valid. + * @add_pin_ranges: optional routine to initialize pin ranges, to be used when + * requires special mapping of the pins that provides GPIO functionality. + * It is called after adding GPIO chip and before adding IRQ chip. * @base: identifies the first GPIO number handled by this chip; * or, if negative during registration, requests dynamic ID allocation. * DEPRECATION: providing anything non-negative and nailing the base @@ -376,6 +382,8 @@ struct gpio_chip { unsigned long *valid_mask, unsigned int ngpios); + int (*add_pin_ranges)(struct gpio_chip *chip); + int base; u16 ngpio; const char *const *names; diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 4ebfe0ac6c5b..799cf823d493 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -33,6 +33,9 @@ struct gpiochip_info { #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) +#define GPIOLINE_FLAG_BIAS_PULL_UP (1UL << 5) +#define GPIOLINE_FLAG_BIAS_PULL_DOWN (1UL << 6) +#define GPIOLINE_FLAG_BIAS_DISABLE (1UL << 7) /** * struct gpioline_info - Information about a certain GPIO line @@ -62,6 +65,9 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) +#define GPIOHANDLE_REQUEST_BIAS_PULL_UP (1UL << 5) +#define GPIOHANDLE_REQUEST_BIAS_PULL_DOWN (1UL << 6) +#define GPIOHANDLE_REQUEST_BIAS_DISABLE (1UL << 7) /** * struct gpiohandle_request - Information about a GPIO handle request @@ -95,6 +101,24 @@ struct gpiohandle_request { }; /** + * struct gpiohandle_config - Configuration for a GPIO handle request + * @flags: updated flags for the requested GPIO lines, such as + * GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed + * together + * @default_values: if the GPIOHANDLE_REQUEST_OUTPUT is set in flags, + * this specifies the default output value, should be 0 (low) or + * 1 (high), anything else than 0 or 1 will be interpreted as 1 (high) + * @padding: reserved for future use and should be zero filled + */ +struct gpiohandle_config { + __u32 flags; + __u8 default_values[GPIOHANDLES_MAX]; + __u32 padding[4]; /* padding for future use */ +}; + +#define GPIOHANDLE_SET_CONFIG_IOCTL _IOWR(0xB4, 0x0a, struct gpiohandle_config) + +/** * struct gpiohandle_data - Information of values on a GPIO handle * @values: when getting the state of lines this contains the current * state of a line, when setting the state of lines these should contain |