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.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAl3hIDcACgkQQRCzN7AZ
 XXOOyw/8DcaBV6j3EZPDS+b+N74/flNf9JitdJRCtUPn8mjdm+uKNPxbtL/znZc8
 zd3rlpiZOqHy8klB3gOPJsJhgXY9QX/b+F5j8fHZvu0DACugRndCqMJ7wrgwUiPn
 2ni6KJmz6z5urhcfaAIgyinTWOMegvSVfqjISaUCRCAg3F9dIeQoulRvTPk2ybvv
 f31jAGemGbvvQPpd81SYCxuTbMg+jxBIgnOCaX+VmUaBLzh8J2W4It3Myp6M4Sbg
 Td6QU4b2J2Q0quk/Dc7c4saT+qRODkg2syPKV2YqmWwdLRDxZyKESMdkCXLWlWJU
 fP+KZ4lDxhCaOAYUrY2sEAYMw4E8MzrfeWikdIe0nk0DWqNQhWvDyzsNsB90XGFb
 aGgeCPH2W1MdE6usPhLidBaHbLeowzndw5BiEl0UCJUqz7tzTCd5iMIAhoSU/Sr5
 ymO8J45G9rdx5pscA3cXhpR/PmqaETYQ/uNrLuxTdI4F4xY12+M0vPrV8z3oDPxB
 U/uL0v6HndDcFAavQQiMd9eL6Hocirnn+Z2xFut3nOznHY96ozXSnZb3lzvH/kqI
 Du2C8geboVcZsiZJTKVN1zxnfIA8oDauzTOEpGFbIGFhmy0zt4RRRptL4W8NxeFm
 KCOk/HqlGeuqJ49epta3mqhUC0MSASA9fdicCdiDqvw+puEznwU=
 =o13I
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2019-12-01 17:56:50 -08:00
commit 99a0d9f5e8
88 changed files with 1851 additions and 600 deletions

View File

@ -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>;
};
...

View File

@ -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
...

View File

@ -8,6 +8,7 @@ Required Properties:
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller. - "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
- "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) 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-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-r8a774c0": for R8A774C0 (RZ/G2E) compatible GPIO controller.
- "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) 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. - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.

View File

@ -2,7 +2,7 @@
A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio) 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 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 Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The

View File

@ -5,7 +5,7 @@ GPIO Driver Interface
This document serves as a guide for writers of GPIO chip drivers. This document serves as a guide for writers of GPIO chip drivers.
Each GPIO controller driver needs to include the following header, which defines 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> #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 under the assumption that your interrupts are 1-to-1-mapped to the
GPIO line index: GPIO line index:
GPIO line offset Hardware IRQ .. csv-table::
0 0 :header: GPIO line offset, Hardware IRQ
1 1
2 2 0,0
... ... 1,1
ngpio-1 ngpio-1 2,2
...,...
ngpio-1, ngpio-1
If some GPIO lines do not have corresponding IRQs, the bitmask valid_mask 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 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. 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 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 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 */ /* Typical state container with dynamic irqchip */
struct my_gpio { 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); return devm_gpiochip_add_data(dev, &g->gc, g);
The helper support using hierarchical interrupt controllers as well. 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 */ /* Typical state container with dynamic irqchip */
struct my_gpio { struct my_gpio {

View File

@ -13,6 +13,7 @@ Contents:
board board
drivers-on-gpio drivers-on-gpio
legacy legacy
bt8xxgpio
Core Core
==== ====

View File

@ -70,7 +70,6 @@ available subsections can be seen below.
fpga/index fpga/index
acpi/index acpi/index
backlight/lp855x-driver.rst backlight/lp855x-driver.rst
bt8xxgpio
connector connector
console console
dcdbas dcdbas

View File

@ -2183,9 +2183,11 @@ L: linux-unisoc@lists.infradead.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: arch/arm/boot/dts/rda8810pl-* F: arch/arm/boot/dts/rda8810pl-*
F: drivers/clocksource/timer-rda.c F: drivers/clocksource/timer-rda.c
F: drivers/gpio/gpio-rda.c
F: drivers/irqchip/irq-rda-intc.c F: drivers/irqchip/irq-rda-intc.c
F: drivers/tty/serial/rda-uart.c F: drivers/tty/serial/rda-uart.c
F: Documentation/devicetree/bindings/arm/rda.yaml 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/interrupt-controller/rda,8810pl-intc.txt
F: Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt F: Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
F: Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt F: Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
@ -8329,7 +8331,7 @@ F: Documentation/fb/intelfb.rst
F: drivers/video/fbdev/intelfb/ F: drivers/video/fbdev/intelfb/
INTEL GPIO DRIVERS INTEL GPIO DRIVERS
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com> M: Andy Shevchenko <andy@kernel.org>
L: linux-gpio@vger.kernel.org L: linux-gpio@vger.kernel.org
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git 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 F: arch/x86/include/asm/intel_punit_ipc.h
INTEL PMIC GPIO DRIVERS INTEL PMIC GPIO DRIVERS
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com> M: Andy Shevchenko <andy@kernel.org>
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
F: drivers/gpio/gpio-*cove.c F: drivers/gpio/gpio-*cove.c

View File

@ -11,8 +11,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/ahci_platform.h> #include <linux/ahci_platform.h>
#include <linux/gpio/consumer.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/libata.h> #include <linux/libata.h>
@ -100,7 +100,7 @@ struct imx_ahci_priv {
struct clk *phy_pclk0; struct clk *phy_pclk0;
struct clk *phy_pclk1; struct clk *phy_pclk1;
void __iomem *phy_base; void __iomem *phy_base;
int clkreq_gpio; struct gpio_desc *clkreq_gpiod;
struct regmap *gpr; struct regmap *gpr;
bool no_device; bool no_device;
bool first_time; 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) static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
{ {
int ret;
struct resource *phy_res; struct resource *phy_res;
struct platform_device *pdev = imxpriv->ahci_pdev; struct platform_device *pdev = imxpriv->ahci_pdev;
struct device_node *np = dev->of_node; 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 */ /* Fetch GPIO, then enable the external OSC */
imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0); imxpriv->clkreq_gpiod = devm_gpiod_get_optional(dev, "clkreq",
if (gpio_is_valid(imxpriv->clkreq_gpio)) { GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio, if (IS_ERR(imxpriv->clkreq_gpiod))
GPIOF_OUT_INIT_LOW, return PTR_ERR(imxpriv->clkreq_gpiod);
"SATA CLKREQ"); if (imxpriv->clkreq_gpiod)
if (ret == -EBUSY) { gpiod_set_consumer_name(imxpriv->clkreq_gpiod, "SATA CLKREQ");
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;
}
return 0; return 0;
} }

View File

@ -120,6 +120,14 @@ config GPIO_ASPEED
help help
Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers. 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 config GPIO_ATH79
tristate "Atheros AR71XX/AR724X/AR913X GPIO support" tristate "Atheros AR71XX/AR724X/AR913X GPIO support"
default y if ATH79 default y if ATH79
@ -147,6 +155,15 @@ config GPIO_BCM_KONA
help help
Turn on GPIO support for Broadcom "Kona" chips. 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 config GPIO_BRCMSTB
tristate "BRCMSTB GPIO support" tristate "BRCMSTB GPIO support"
default y if (ARCH_BRCMSTB || BMIPS_GENERIC) default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
@ -435,6 +452,15 @@ config GPIO_RCAR
help help
Say yes here to support GPIO on Renesas R-Car SoCs. 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 config GPIO_REG
bool bool
help help
@ -531,6 +557,7 @@ config GPIO_TEGRA186
depends on ARCH_TEGRA_186_SOC || COMPILE_TEST depends on ARCH_TEGRA_186_SOC || COMPILE_TEST
depends on OF_GPIO depends on OF_GPIO
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
select IRQ_DOMAIN_HIERARCHY
help help
Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs. 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 The card needs to be physically altered for using it as a
GPIO card. For more information on how to build a GPIO card GPIO card. For more information on how to build a GPIO card
from a BT8xx TV card, see the documentation file at 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. If unsure, say N.

View File

@ -32,8 +32,10 @@ obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.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_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.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_BD70528) += gpio-bd70528.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.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_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.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_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_REG) += gpio-reg.o obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o

View File

@ -80,6 +80,10 @@ Work items:
- Look over and identify any remaining easily converted drivers and - Look over and identify any remaining easily converted drivers and
dry-code conversions to MMIO GPIO for maintainers to test 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 - 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 helpers (x86 inb()/outb()) and convert port-mapped I/O drivers to use
this with dry-coding and sending to maintainers to test this with dry-coding and sending to maintainers to test

View File

@ -59,7 +59,10 @@ static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
const unsigned port = offset / 8; const unsigned port = offset / 8;
const unsigned mask = BIT(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) static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset)

View File

@ -53,7 +53,7 @@ struct idi_48_gpio {
static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{ {
return 1; return GPIO_LINE_DIRECTION_IN;
} }
static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned 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); struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
unsigned i; 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 base_offset;
unsigned mask; unsigned mask;

View File

@ -51,9 +51,9 @@ struct idio_16_gpio {
static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset) static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{ {
if (offset > 15) 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) static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)

View File

@ -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); 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) static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio)

View File

@ -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); ret = (readl_relaxed(ptr) & AMD_FCH_GPIO_FLAG_DIRECTION);
spin_unlock_irqrestore(&priv->lock, flags); 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, static void amd_fch_gpio_set(struct gpio_chip *gc,

View File

@ -487,10 +487,10 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
u32 val; u32 val;
if (!have_input(gpio, offset)) if (!have_input(gpio, offset))
return 0; return GPIO_LINE_DIRECTION_OUT;
if (!have_output(gpio, offset)) if (!have_output(gpio, offset))
return 1; return GPIO_LINE_DIRECTION_IN;
spin_lock_irqsave(&gpio->lock, flags); 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); 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, static inline int irqd_to_aspeed_gpio_data(struct irq_data *d,

View File

@ -226,7 +226,6 @@ static int ath79_gpio_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct ath79_gpio_ctrl *ctrl; struct ath79_gpio_ctrl *ctrl;
struct gpio_irq_chip *girq; struct gpio_irq_chip *girq;
struct resource *res;
u32 ath79_gpio_count; u32 ath79_gpio_count;
bool oe_inverted; bool oe_inverted;
int err; int err;
@ -256,12 +255,9 @@ static int ath79_gpio_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ctrl->base = devm_platform_ioremap_resource(pdev, 0);
if (!res) if (IS_ERR(ctrl->base))
return -EINVAL; return PTR_ERR(ctrl->base);
ctrl->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!ctrl->base)
return -ENOMEM;
raw_spin_lock_init(&ctrl->lock); raw_spin_lock_init(&ctrl->lock);
err = bgpio_init(&ctrl->gc, dev, 4, err = bgpio_init(&ctrl->gc, dev, 4,

View File

@ -127,7 +127,7 @@ static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
u32 val; u32 val;
val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK; 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) 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); raw_spin_lock_irqsave(&kona_gpio->lock, flags);
/* this function only applies to output pin */ /* 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; goto out;
reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); 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; reg_base = kona_gpio->reg_base;
raw_spin_lock_irqsave(&kona_gpio->lock, flags); 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); reg_offset = GPIO_IN_STATUS(bank_id);
else else
reg_offset = GPIO_OUT_STATUS(bank_id); reg_offset = GPIO_OUT_STATUS(bank_id);

View File

@ -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"); dev_err(bdgpio->chip.dev, "Could not read gpio direction\n");
return ret; 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, 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. * locking would make no sense.
*/ */
ret = bd70528_get_direction(chip, offset); ret = bd70528_get_direction(chip, offset);
if (ret == 0) if (ret == GPIO_LINE_DIRECTION_OUT)
ret = bd70528_gpio_get_o(bdgpio, offset); 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); ret = bd70528_gpio_get_i(bdgpio, offset);
else else
dev_err(bdgpio->chip.dev, "failed to read GPIO direction\n"); 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_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD70528 voltage regulator driver"); MODULE_DESCRIPTION("BD70528 voltage regulator driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd70528-gpio");

View File

@ -37,8 +37,10 @@ static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip,
ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val); ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val);
if (ret < 0) if (ret < 0)
return ret; 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, static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip,

View File

@ -200,9 +200,9 @@ static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
struct dln2_gpio *dln2 = gpiochip_get_data(chip); struct dln2_gpio *dln2 = gpiochip_get_data(chip);
if (test_bit(offset, dln2->output_enabled)) 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) 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) if (dir < 0)
return dir; 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_in_val(dln2, offset);
return dln2_gpio_pin_get_out_val(dln2, offset); return dln2_gpio_pin_get_out_val(dln2, offset);

View File

@ -269,13 +269,12 @@ static void em_gio_irq_domain_remove(void *data)
static int em_gio_probe(struct platform_device *pdev) static int em_gio_probe(struct platform_device *pdev)
{ {
struct em_gio_priv *p; struct em_gio_priv *p;
struct resource *io[2], *irq[2];
struct gpio_chip *gpio_chip; struct gpio_chip *gpio_chip;
struct irq_chip *irq_chip; struct irq_chip *irq_chip;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const char *name = dev_name(dev); const char *name = dev_name(dev);
unsigned int ngpios; unsigned int ngpios;
int ret; int irq[2], ret;
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
if (!p) if (!p)
@ -285,25 +284,21 @@ static int em_gio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, p); platform_set_drvdata(pdev, p);
spin_lock_init(&p->sense_lock); spin_lock_init(&p->sense_lock);
io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq[0] = platform_get_irq(pdev, 0);
io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (irq[0] < 0)
irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0); return irq[0];
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (!io[0] || !io[1] || !irq[0] || !irq[1]) { irq[1] = platform_get_irq(pdev, 1);
dev_err(dev, "missing IRQ or IOMEM\n"); if (irq[1] < 0)
return -EINVAL; return irq[1];
}
p->base0 = devm_ioremap_nocache(dev, io[0]->start, p->base0 = devm_platform_ioremap_resource(pdev, 0);
resource_size(io[0])); if (IS_ERR(p->base0))
if (!p->base0) return PTR_ERR(p->base0);
return -ENOMEM;
p->base1 = devm_ioremap_nocache(dev, io[1]->start, p->base1 = devm_platform_ioremap_resource(pdev, 1);
resource_size(io[1])); if (IS_ERR(p->base1))
if (!p->base1) return PTR_ERR(p->base1);
return -ENOMEM;
if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) { if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
dev_err(dev, "Missing ngpios OF property\n"); 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; gpio_chip->ngpio = ngpios;
irq_chip = &p->irq_chip; 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_mask = em_gio_irq_disable;
irq_chip->irq_unmask = em_gio_irq_enable; irq_chip->irq_unmask = em_gio_irq_enable;
irq_chip->irq_set_type = em_gio_irq_set_type; 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) if (ret)
return ret; return ret;
if (devm_request_irq(dev, irq[0]->start, if (devm_request_irq(dev, irq[0], em_gio_irq_handler, 0, name, p)) {
em_gio_irq_handler, 0, name, p)) {
dev_err(dev, "failed to request low IRQ\n"); dev_err(dev, "failed to request low IRQ\n");
return -ENOENT; return -ENOENT;
} }
if (devm_request_irq(dev, irq[1]->start, if (devm_request_irq(dev, irq[1], em_gio_irq_handler, 0, name, p)) {
em_gio_irq_handler, 0, name, p)) {
dev_err(dev, "failed to request high IRQ\n"); dev_err(dev, "failed to request high IRQ\n");
return -ENOENT; return -ENOENT;
} }

View File

@ -77,7 +77,10 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
unsigned int bit = (offset + exar_gpio->first_pin) % 8; 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) static int exar_get_value(struct gpio_chip *chip, unsigned int offset)

View File

@ -250,7 +250,10 @@ static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
superio_exit(sio->addr); 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) static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)

View File

@ -52,7 +52,10 @@ static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
const unsigned int port = offset / 8; const unsigned int port = offset / 8;
const unsigned int mask = BIT(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, static int gpiomm_gpio_direction_input(struct gpio_chip *chip,

View File

@ -220,7 +220,10 @@ static int egpio_get_direction(struct gpio_chip *chip, unsigned offset)
egpio = gpiochip_get_data(chip); 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) 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; struct gpio_chip *chip;
unsigned int irq, irq_end; unsigned int irq, irq_end;
int i; int i;
int ret;
/* Initialize ei data structure. */ /* Initialize ei data structure. */
ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL); 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); spin_lock_init(&ei->lock);
/* Find chained irq */ /* Find chained irq */
ret = -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) if (res)
ei->chained_irq = res->start; ei->chained_irq = res->start;
/* Map egpio chip into virtual address space. */ /* Map egpio chip into virtual address space. */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ei->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (!res) if (IS_ERR(ei->base_addr))
goto fail; return PTR_ERR(ei->base_addr);
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);
if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
goto fail; return -EINVAL;
ei->bus_shift = fls(pdata->bus_width - 1) - 3; ei->bus_shift = fls(pdata->bus_width - 1) - 3;
pr_debug("bus_shift = %d\n", ei->bus_shift); pr_debug("bus_shift = %d\n", ei->bus_shift);
if ((pdata->reg_width != 8) && (pdata->reg_width != 16)) if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
goto fail; return -EINVAL;
ei->reg_shift = fls(pdata->reg_width - 1); ei->reg_shift = fls(pdata->reg_width - 1);
pr_debug("reg_shift = %d\n", ei->reg_shift); 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->chip = devm_kcalloc(&pdev->dev,
ei->nchips, sizeof(struct egpio_chip), ei->nchips, sizeof(struct egpio_chip),
GFP_KERNEL); GFP_KERNEL);
if (!ei->chip) { if (!ei->chip)
ret = -ENOMEM; return -ENOMEM;
goto fail;
}
for (i = 0; i < ei->nchips; i++) { for (i = 0; i < ei->nchips; i++) {
ei->chip[i].reg_start = pdata->chip[i].reg_start; ei->chip[i].reg_start = pdata->chip[i].reg_start;
ei->chip[i].cached_values = pdata->chip[i].initial_values; 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, chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"htc-egpio-%d", "htc-egpio-%d",
i); i);
if (!chip->label) { if (!chip->label)
ret = -ENOMEM; return -ENOMEM;
goto fail;
}
chip->parent = &pdev->dev; chip->parent = &pdev->dev;
chip->owner = THIS_MODULE; chip->owner = THIS_MODULE;
chip->get = egpio_get; chip->get = egpio_get;
@ -366,10 +362,6 @@ static int __init egpio_probe(struct platform_device *pdev)
} }
return 0; return 0;
fail:
printk(KERN_ERR "EGPIO failed to setup\n");
return ret;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM

View File

@ -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) 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) static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)

View File

@ -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_gpio_data *gpio = gpiochip_get_data(chip);
struct kempld_device_data *pld = gpio->pld; 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) static int kempld_gpio_pincount(struct kempld_device_data *pld)

View File

@ -33,7 +33,7 @@ static int lp873x_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset) unsigned int offset)
{ {
/* This device is output only */ /* This device is output only */
return 0; return GPIO_LINE_DIRECTION_OUT;
} }
static int lp873x_gpio_direction_input(struct gpio_chip *chip, static int lp873x_gpio_direction_input(struct gpio_chip *chip,

View File

@ -57,7 +57,10 @@ static int lp87565_gpio_get_direction(struct gpio_chip *chip,
if (ret < 0) if (ret < 0)
return ret; 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, static int lp87565_gpio_direction_input(struct gpio_chip *chip,

View File

@ -164,6 +164,12 @@ static int lp_irq_type(struct irq_data *d, unsigned type)
value |= TRIG_SEL_BIT | INT_INV_BIT; value |= TRIG_SEL_BIT | INT_INV_BIT;
outl(value, reg); 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); spin_unlock_irqrestore(&lg->lock, flags);
return 0; return 0;

View File

@ -34,7 +34,10 @@ static int madera_gpio_get_direction(struct gpio_chip *chip,
if (ret < 0) if (ret < 0)
return ret; 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) static int madera_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)

View File

@ -94,7 +94,7 @@ DECLARE_CRC8_TABLE(max3191x_crc8);
static int max3191x_get_direction(struct gpio_chip *gpio, unsigned int offset) 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) static int max3191x_direction_input(struct gpio_chip *gpio, unsigned int offset)

View File

@ -18,109 +18,115 @@ struct max77620_gpio {
struct gpio_chip gpio_chip; struct gpio_chip gpio_chip;
struct regmap *rmap; struct regmap *rmap;
struct device *dev; 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[] = { static irqreturn_t max77620_gpio_irqhandler(int irq, void *data)
[0] = { {
.reg_offset = 0, struct max77620_gpio *gpio = data;
.mask = MAX77620_IRQ_LVL2_GPIO_EDGE0, unsigned int value, offset;
.type = { unsigned long pending;
.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING, int err;
.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 const struct regmap_irq_chip max77620_gpio_irq_chip = { 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 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", .name = "max77620-gpio",
.irqs = max77620_gpio_irqs, .irq_mask = max77620_gpio_irq_mask,
.num_irqs = ARRAY_SIZE(max77620_gpio_irqs), .irq_unmask = max77620_gpio_irq_unmask,
.num_regs = 1, .irq_set_type = max77620_gpio_set_irq_type,
.num_type_reg = 8, .irq_bus_lock = max77620_gpio_bus_lock,
.irq_reg_stride = 1, .irq_bus_sync_unlock = max77620_gpio_bus_sync_unlock,
.type_reg_stride = 1, .flags = IRQCHIP_MASK_ON_SUSPEND,
.status_base = MAX77620_REG_IRQ_LVL2_GPIO,
.type_base = MAX77620_REG_GPIO0,
}; };
static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset) 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; 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) static int max77620_gpio_probe(struct platform_device *pdev)
{ {
struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent); 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.direction_output = max77620_gpio_dir_output;
mgpio->gpio_chip.set = max77620_gpio_set; mgpio->gpio_chip.set = max77620_gpio_set;
mgpio->gpio_chip.set_config = max77620_gpio_set_config; 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.ngpio = MAX77620_GPIO_NR;
mgpio->gpio_chip.can_sleep = 1; mgpio->gpio_chip.can_sleep = 1;
mgpio->gpio_chip.base = -1; mgpio->gpio_chip.base = -1;
@ -303,15 +300,21 @@ static int max77620_gpio_probe(struct platform_device *pdev)
return ret; return ret;
} }
ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq, mutex_init(&mgpio->buslock);
IRQF_ONESHOT, -1,
&max77620_gpio_irq_chip, gpiochip_irqchip_add_nested(&mgpio->gpio_chip, &max77620_gpio_irqchip,
&chip->gpio_irq_data); 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) { 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; return ret;
} }
gpiochip_set_nested_irqchip(&mgpio->gpio_chip, &max77620_gpio_irqchip,
gpio_irq);
return 0; return 0;
} }

View File

@ -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); 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, 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); 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; void __iomem *reg;
unsigned int base; unsigned int base;
@ -375,6 +379,8 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv)
reg = gpio_reg(&priv->chip, base, GFER); reg = gpio_reg(&priv->chip, base, GFER);
writel(0, reg); writel(0, reg);
} }
return 0;
} }
static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) 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; 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 struct mrfld_gpio_pinrange *range;
const char *pinctrl_dev_name; 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; struct mrfld_gpio *priv;
u32 gpio_base, irq_base; u32 gpio_base, irq_base;
void __iomem *base; void __iomem *base;
unsigned int i;
int retval; int retval;
retval = pcim_enable_device(pdev); 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.base = gpio_base;
priv->chip.ngpio = MRFLD_NGPIO; priv->chip.ngpio = MRFLD_NGPIO;
priv->chip.can_sleep = false; priv->chip.can_sleep = false;
priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges;
raw_spin_lock_init(&priv->lock); 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); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
if (retval) { if (retval) {
dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
return retval; return retval;
} }
pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); pci_set_drvdata(pdev, 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);
return 0; return 0;
} }

View File

@ -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) static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
{ {
/* Return 0 if output, 1 if input */ /* Return 0 if output, 1 if input */
if (gc->bgpio_dir_unreadable) if (gc->bgpio_dir_unreadable) {
return !(gc->bgpio_dir & bgpio_line2mask(gc, gpio)); if (gc->bgpio_dir & bgpio_line2mask(gc, gpio))
if (gc->reg_dir_out) return GPIO_LINE_DIRECTION_OUT;
return !(gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio)); return GPIO_LINE_DIRECTION_IN;
if (gc->reg_dir_in) }
return !!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio));
/* This should not happen */ if (gc->reg_dir_out) {
return 1; 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)
if (!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio)))
return GPIO_LINE_DIRECTION_OUT;
return GPIO_LINE_DIRECTION_IN;
} }
static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)

View File

@ -34,14 +34,9 @@
#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__) #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 * 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) * @value: Configures status of the gpio as 0(low) or 1(high)
*/ */
struct gpio_mockup_line_status { struct gpio_mockup_line_status {
@ -146,13 +141,68 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc,
mutex_unlock(&chip->lock); 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, static int gpio_mockup_dirout(struct gpio_chip *gc,
unsigned int offset, int value) unsigned int offset, int value)
{ {
struct gpio_mockup_chip *chip = gpiochip_get_data(gc); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->lock); 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); __gpio_mockup_set(chip, offset, value);
mutex_unlock(&chip->lock); 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); struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->lock); mutex_lock(&chip->lock);
chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN; chip->lines[offset].dir = GPIO_LINE_DIRECTION_IN;
mutex_unlock(&chip->lock); mutex_unlock(&chip->lock);
return 0; return 0;
@ -226,12 +276,8 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file,
size_t size, loff_t *ppos) size_t size, loff_t *ppos)
{ {
struct gpio_mockup_dbgfs_private *priv; struct gpio_mockup_dbgfs_private *priv;
int rv, val, curr, irq, irq_type; int rv, val;
struct gpio_mockup_chip *chip;
struct seq_file *sfile; struct seq_file *sfile;
struct gpio_desc *desc;
struct gpio_chip *gc;
struct irq_sim *sim;
if (*ppos != 0) if (*ppos != 0)
return -EINVAL; return -EINVAL;
@ -244,35 +290,9 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file,
sfile = file->private_data; sfile = file->private_data;
priv = sfile->private; priv = sfile->private;
chip = priv->chip; rv = gpio_mockup_apply_pull(priv->chip, priv->offset, val);
gc = &chip->gc; if (rv)
desc = &gc->gpiodev->descs[priv->offset]; return rv;
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);
return size; return size;
} }
@ -418,6 +438,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
gc->direction_output = gpio_mockup_dirout; gc->direction_output = gpio_mockup_dirout;
gc->direction_input = gpio_mockup_dirin; gc->direction_input = gpio_mockup_dirin;
gc->get_direction = gpio_mockup_get_direction; gc->get_direction = gpio_mockup_get_direction;
gc->set_config = gpio_mockup_set_config;
gc->to_irq = gpio_mockup_to_irq; gc->to_irq = gpio_mockup_to_irq;
gc->free = gpio_mockup_free; gc->free = gpio_mockup_free;

View File

@ -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. */ /* All lines are hard wired to be either input or output, not both. */
if (chip->desc->in_mask & BIT(offset)) if (chip->desc->in_mask & BIT(offset))
return 1; return GPIO_LINE_DIRECTION_IN;
else if (chip->desc->out_mask & BIT(offset)) else if (chip->desc->out_mask & BIT(offset))
return 0; return GPIO_LINE_DIRECTION_OUT;
else else
return -EINVAL; return -EINVAL;
} }

View File

@ -22,6 +22,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/interrupt.h>
#define MPC8XXX_GPIO_PINS 32 #define MPC8XXX_GPIO_PINS 32
@ -127,20 +128,19 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
return -ENXIO; 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 mpc8xxx_gpio_chip *mpc8xxx_gc = data;
struct irq_chip *chip = irq_desc_get_chip(desc);
struct gpio_chip *gc = &mpc8xxx_gc->gc; struct gpio_chip *gc = &mpc8xxx_gc->gc;
unsigned int mask; unsigned long mask;
int i;
mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER) mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER)
& gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR); & gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR);
if (mask) for_each_set_bit(i, &mask, 32)
generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 31 - i));
32 - ffs(mask)));
if (chip->irq_eoi) return IRQ_HANDLED;
chip->irq_eoi(&desc->irq_data);
} }
static void mpc8xxx_irq_unmask(struct irq_data *d) static void mpc8xxx_irq_unmask(struct irq_data *d)
@ -377,6 +377,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
* It's assumed that only a single type of gpio controller is available * It's assumed that only a single type of gpio controller is available
* on the current machine, so overwriting global data is fine. * on the current machine, so overwriting global data is fine.
*/ */
if (devtype->irq_set_type)
mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
if (devtype->gpio_dir_out) if (devtype->gpio_dir_out)
@ -386,6 +387,9 @@ static int mpc8xxx_probe(struct platform_device *pdev)
gc->to_irq = mpc8xxx_gpio_to_irq; 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); ret = gpiochip_add_data(gc, mpc8xxx_gc);
if (ret) { if (ret) {
pr_err("%pOF: GPIO chip registration failed with status %d\n", 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) if (devtype->gpio_dir_in_init)
devtype->gpio_dir_in_init(gc); devtype->gpio_dir_in_init(gc);
irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); 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; return 0;
err: err:
iounmap(mpc8xxx_gc->regs); iounmap(mpc8xxx_gc->regs);

View File

@ -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); 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) static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin)

View File

@ -411,6 +411,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct mxc_gpio_port *port; struct mxc_gpio_port *port;
int irq_count;
int irq_base; int irq_base;
int err; int err;
@ -426,9 +427,15 @@ static int mxc_gpio_probe(struct platform_device *pdev)
if (IS_ERR(port->base)) if (IS_ERR(port->base))
return PTR_ERR(port->base); return PTR_ERR(port->base);
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); port->irq_high = platform_get_irq(pdev, 1);
if (port->irq_high < 0) if (port->irq_high < 0)
port->irq_high = 0; port->irq_high = 0;
}
port->irq = platform_get_irq(pdev, 0); port->irq = platform_get_irq(pdev, 0);
if (port->irq < 0) if (port->irq < 0)

View File

@ -248,7 +248,10 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
u32 dir; u32 dir;
dir = readl(port->base + PINCTRL_DOE(port)); 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[] = { static const struct platform_device_id mxs_gpio_ids[] = {

View File

@ -805,8 +805,10 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{ {
struct gpio_bank *bank = gpiochip_get_data(chip); struct gpio_bank *bank = gpiochip_get_data(chip);
return !!(readl_relaxed(bank->base + bank->regs->direction) & if (readl_relaxed(bank->base + bank->regs->direction) & BIT(offset))
BIT(offset)); return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
} }
static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)

View File

@ -449,7 +449,10 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
if (ret < 0) if (ret < 0)
return ret; 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, static void pca953x_gpio_set_multiple(struct gpio_chip *gc,

View File

@ -61,9 +61,9 @@ static int idio_16_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset) unsigned int offset)
{ {
if (offset > 15) 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, static int idio_16_gpio_direction_input(struct gpio_chip *chip,

View File

@ -104,15 +104,18 @@ static int idio_24_gpio_get_direction(struct gpio_chip *chip,
/* FET Outputs */ /* FET Outputs */
if (offset < 24) if (offset < 24)
return 0; return GPIO_LINE_DIRECTION_OUT;
/* Isolated Inputs */ /* Isolated Inputs */
if (offset < 48) if (offset < 48)
return 1; return GPIO_LINE_DIRECTION_IN;
/* TTL/CMOS I/O */ /* TTL/CMOS I/O */
/* OUT MODE = 1 when TTL/CMOS Output Mode is set */ /* 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, static int idio_24_gpio_direction_input(struct gpio_chip *chip,

View File

@ -65,7 +65,7 @@ static int pisosr_gpio_get_direction(struct gpio_chip *chip,
unsigned offset) unsigned offset)
{ {
/* This device always input */ /* This device always input */
return 1; return GPIO_LINE_DIRECTION_IN;
} }
static int pisosr_gpio_direction_input(struct gpio_chip *chip, static int pisosr_gpio_direction_input(struct gpio_chip *chip,

View File

@ -63,7 +63,10 @@ static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
{ {
struct pl061 *pl061 = gpiochip_get_data(gc); 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) static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)

View File

@ -147,7 +147,10 @@ static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
get.gpio); get.gpio);
return ret ? ret : -EIO; 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) static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)

View File

@ -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); 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) 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; gpio_chip->ngpio = npins;
irq_chip = &p->irq_chip; irq_chip = &p->irq_chip;
irq_chip->name = name; irq_chip->name = "gpio-rcar";
irq_chip->parent_device = dev; irq_chip->parent_device = dev;
irq_chip->irq_mask = gpio_rcar_irq_disable; irq_chip->irq_mask = gpio_rcar_irq_disable;
irq_chip->irq_unmask = gpio_rcar_irq_enable; irq_chip->irq_unmask = gpio_rcar_irq_enable;

294
drivers/gpio/gpio-rda.c Normal file
View File

@ -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");

View File

@ -26,7 +26,8 @@ static int gpio_reg_get_direction(struct gpio_chip *gc, unsigned offset)
{ {
struct gpio_reg *r = to_gpio_reg(gc); 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, static int gpio_reg_direction_output(struct gpio_chip *gc, unsigned offset,

View File

@ -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; 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) static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset)

View File

@ -119,7 +119,8 @@ static int sama5d2_piobu_get_direction(struct gpio_chip *chip,
if (ret < 0) if (ret < 0)
return ret; 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 */ /* if pin is input, read value from PDS else read from SOD */
int ret = sama5d2_piobu_get_direction(chip, pin); 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); 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); ret = sama5d2_piobu_read_value(chip, pin, PIOBU_SOD);
if (ret < 0) if (ret < 0)

View File

@ -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); 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 = { static const struct gpio_chip sch_gpio_chip = {

View File

@ -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]); data = inb(block->runtime_reg + block->config_regs[offset]);
spin_unlock(&block->lock); 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, static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset,

View File

@ -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) static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
{ {
if (offset < 12) if (offset < 12)
return 1; /* input */ return GPIO_LINE_DIRECTION_IN;
else else
return 0; /* output */ return GPIO_LINE_DIRECTION_OUT;
} }
static int gpio_siox_probe(struct siox_device *sdevice) static int gpio_siox_probe(struct siox_device *sdevice)

View File

@ -84,7 +84,10 @@ static int stmpe_gpio_get_direction(struct gpio_chip *chip,
if (ret < 0) if (ret < 0)
return ret; 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, static int stmpe_gpio_direction_output(struct gpio_chip *chip,

View File

@ -97,7 +97,10 @@ static int tc3589x_gpio_get_direction(struct gpio_chip *chip,
if (ret < 0) if (ret < 0)
return ret; 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, static int tc3589x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,

View File

@ -215,7 +215,10 @@ static int tegra_gpio_get_direction(struct gpio_chip *chip,
oe = tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)); 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, static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,

View File

@ -15,6 +15,14 @@
#include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/gpio/tegra186-gpio.h>
#include <dt-bindings/gpio/tegra194-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 0x00
#define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0) #define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
#define TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1) #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_DOUBLE_EDGE (0x3 << 2)
#define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (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_TRIGGER_LEVEL BIT(4)
#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5)
#define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6) #define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6)
#define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04 #define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04
@ -44,15 +53,16 @@
struct tegra_gpio_port { struct tegra_gpio_port {
const char *name; const char *name;
unsigned int offset; unsigned int bank;
unsigned int port;
unsigned int pins; unsigned int pins;
unsigned int irq;
}; };
struct tegra_gpio_soc { struct tegra_gpio_soc {
const struct tegra_gpio_port *ports; const struct tegra_gpio_port *ports;
unsigned int num_ports; unsigned int num_ports;
const char *name; const char *name;
unsigned int instance;
}; };
struct tegra_gpio { struct tegra_gpio {
@ -63,6 +73,7 @@ struct tegra_gpio {
const struct tegra_gpio_soc *soc; const struct tegra_gpio_soc *soc;
void __iomem *secure;
void __iomem *base; void __iomem *base;
}; };
@ -89,12 +100,15 @@ static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
unsigned int pin) unsigned int pin)
{ {
const struct tegra_gpio_port *port; const struct tegra_gpio_port *port;
unsigned int offset;
port = tegra186_gpio_get_port(gpio, &pin); port = tegra186_gpio_get_port(gpio, &pin);
if (!port) if (!port)
return NULL; 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, 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); value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT) 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, 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); 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, static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
const struct of_phandle_args *spec, const struct of_phandle_args *spec,
u32 *flags) u32 *flags)
@ -327,7 +377,7 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int type)
else else
irq_set_handler_locked(data, handle_edge_irq); 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) 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++) { for (i = 0; i < gpio->soc->num_ports; i++) {
const struct tegra_gpio_port *port = &gpio->soc->ports[i]; const struct tegra_gpio_port *port = &gpio->soc->ports[i];
void __iomem *base = gpio->base + port->offset;
unsigned int pin, irq; unsigned int pin, irq;
unsigned long value; unsigned long value;
void __iomem *base;
/* skip ports that are not associated with this controller */ base = gpio->base + port->bank * 0x1000 + port->port * 0x200;
if (parent != gpio->irq[port->irq])
/* skip ports that are not associated with this bank */
if (parent != gpio->irq[port->bank])
goto skip; goto skip;
value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
@ -367,46 +419,119 @@ skip:
chained_irq_exit(chip, desc); chained_irq_exit(chip, desc);
} }
static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain, static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain,
struct device_node *np, struct irq_fwspec *fwspec,
const u32 *spec, unsigned int size,
unsigned long *hwirq, unsigned long *hwirq,
unsigned int *type) unsigned int *type)
{ {
struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data); struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
unsigned int port, pin, i, offset = 0; unsigned int port, pin, i, offset = 0;
if (size < 2) if (WARN_ON(gpio->gpio.of_gpio_n_cells < 2))
return -EINVAL; return -EINVAL;
port = spec[0] / 8; if (WARN_ON(fwspec->param_count < gpio->gpio.of_gpio_n_cells))
pin = spec[0] % 8; return -EINVAL;
if (port >= gpio->soc->num_ports) { port = fwspec->param[0] / 8;
dev_err(gpio->gpio.parent, "invalid port number: %u\n", port); pin = fwspec->param[0] % 8;
if (port >= gpio->soc->num_ports)
return -EINVAL; return -EINVAL;
}
for (i = 0; i < port; i++) for (i = 0; i < port; i++)
offset += gpio->soc->ports[i].pins; offset += gpio->soc->ports[i].pins;
*type = spec[1] & IRQ_TYPE_SENSE_MASK; *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
*hwirq = offset + pin; *hwirq = offset + pin;
return 0; return 0;
} }
static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = { static void tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
.map = gpiochip_irq_map, struct irq_fwspec *fwspec,
.unmap = gpiochip_irq_unmap, unsigned int parent_hwirq,
.xlate = tegra186_gpio_irq_domain_xlate, 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) static int tegra186_gpio_probe(struct platform_device *pdev)
{ {
unsigned int i, j, offset; unsigned int i, j, offset;
struct gpio_irq_chip *irq; struct gpio_irq_chip *irq;
struct tegra_gpio *gpio; struct tegra_gpio *gpio;
struct device_node *np;
char **names; char **names;
int err; 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->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"); gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
if (IS_ERR(gpio->base)) if (IS_ERR(gpio->base))
return PTR_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.direction_output = tegra186_gpio_direction_output;
gpio->gpio.get = tegra186_gpio_get, gpio->gpio.get = tegra186_gpio_get,
gpio->gpio.set = tegra186_gpio_set; gpio->gpio.set = tegra186_gpio_set;
gpio->gpio.set_config = tegra186_gpio_set_config;
gpio->gpio.base = -1; 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_mask = tegra186_irq_mask;
gpio->intc.irq_unmask = tegra186_irq_unmask; gpio->intc.irq_unmask = tegra186_irq_unmask;
gpio->intc.irq_set_type = tegra186_irq_set_type; gpio->intc.irq_set_type = tegra186_irq_set_type;
gpio->intc.irq_set_wake = irq_chip_set_wake_parent;
irq = &gpio->gpio.irq; irq = &gpio->gpio.irq;
irq->chip = &gpio->intc; 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->handler = handle_simple_irq;
irq->default_type = IRQ_TYPE_NONE; irq->default_type = IRQ_TYPE_NONE;
irq->parent_handler = tegra186_gpio_irq; 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->num_parents = gpio->num_irq;
irq->parents = gpio->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, irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
sizeof(*irq->map), GFP_KERNEL); sizeof(*irq->map), GFP_KERNEL);
if (!irq->map) 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]; const struct tegra_gpio_port *port = &gpio->soc->ports[i];
for (j = 0; j < port->pins; j++) 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; offset += port->pins;
} }
@ -524,136 +670,140 @@ static int tegra186_gpio_remove(struct platform_device *pdev)
return 0; return 0;
} }
#define TEGRA186_MAIN_GPIO_PORT(port, base, count, controller) \ #define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
[TEGRA186_MAIN_GPIO_PORT_##port] = { \ [TEGRA186_MAIN_GPIO_PORT_##_name] = { \
.name = #port, \ .name = #_name, \
.offset = base, \ .bank = _bank, \
.pins = count, \ .port = _port, \
.irq = controller, \ .pins = _pins, \
} }
static const struct tegra_gpio_port tegra186_main_ports[] = { static const struct tegra_gpio_port tegra186_main_ports[] = {
TEGRA186_MAIN_GPIO_PORT( A, 0x2000, 7, 2), TEGRA186_MAIN_GPIO_PORT( A, 2, 0, 7),
TEGRA186_MAIN_GPIO_PORT( B, 0x3000, 7, 3), TEGRA186_MAIN_GPIO_PORT( B, 3, 0, 7),
TEGRA186_MAIN_GPIO_PORT( C, 0x3200, 7, 3), TEGRA186_MAIN_GPIO_PORT( C, 3, 1, 7),
TEGRA186_MAIN_GPIO_PORT( D, 0x3400, 6, 3), TEGRA186_MAIN_GPIO_PORT( D, 3, 2, 6),
TEGRA186_MAIN_GPIO_PORT( E, 0x2200, 8, 2), TEGRA186_MAIN_GPIO_PORT( E, 2, 1, 8),
TEGRA186_MAIN_GPIO_PORT( F, 0x2400, 6, 2), TEGRA186_MAIN_GPIO_PORT( F, 2, 2, 6),
TEGRA186_MAIN_GPIO_PORT( G, 0x4200, 6, 4), TEGRA186_MAIN_GPIO_PORT( G, 4, 1, 6),
TEGRA186_MAIN_GPIO_PORT( H, 0x1000, 7, 1), TEGRA186_MAIN_GPIO_PORT( H, 1, 0, 7),
TEGRA186_MAIN_GPIO_PORT( I, 0x0800, 8, 0), TEGRA186_MAIN_GPIO_PORT( I, 0, 4, 8),
TEGRA186_MAIN_GPIO_PORT( J, 0x5000, 8, 5), TEGRA186_MAIN_GPIO_PORT( J, 5, 0, 8),
TEGRA186_MAIN_GPIO_PORT( K, 0x5200, 1, 5), TEGRA186_MAIN_GPIO_PORT( K, 5, 1, 1),
TEGRA186_MAIN_GPIO_PORT( L, 0x1200, 8, 1), TEGRA186_MAIN_GPIO_PORT( L, 1, 1, 8),
TEGRA186_MAIN_GPIO_PORT( M, 0x5600, 6, 5), TEGRA186_MAIN_GPIO_PORT( M, 5, 3, 6),
TEGRA186_MAIN_GPIO_PORT( N, 0x0000, 7, 0), TEGRA186_MAIN_GPIO_PORT( N, 0, 0, 7),
TEGRA186_MAIN_GPIO_PORT( O, 0x0200, 4, 0), TEGRA186_MAIN_GPIO_PORT( O, 0, 1, 4),
TEGRA186_MAIN_GPIO_PORT( P, 0x4000, 7, 4), TEGRA186_MAIN_GPIO_PORT( P, 4, 0, 7),
TEGRA186_MAIN_GPIO_PORT( Q, 0x0400, 6, 0), TEGRA186_MAIN_GPIO_PORT( Q, 0, 2, 6),
TEGRA186_MAIN_GPIO_PORT( R, 0x0a00, 6, 0), TEGRA186_MAIN_GPIO_PORT( R, 0, 5, 6),
TEGRA186_MAIN_GPIO_PORT( T, 0x0600, 4, 0), TEGRA186_MAIN_GPIO_PORT( T, 0, 3, 4),
TEGRA186_MAIN_GPIO_PORT( X, 0x1400, 8, 1), TEGRA186_MAIN_GPIO_PORT( X, 1, 2, 8),
TEGRA186_MAIN_GPIO_PORT( Y, 0x1600, 7, 1), TEGRA186_MAIN_GPIO_PORT( Y, 1, 3, 7),
TEGRA186_MAIN_GPIO_PORT(BB, 0x2600, 2, 2), TEGRA186_MAIN_GPIO_PORT(BB, 2, 3, 2),
TEGRA186_MAIN_GPIO_PORT(CC, 0x5400, 4, 5), TEGRA186_MAIN_GPIO_PORT(CC, 5, 2, 4),
}; };
static const struct tegra_gpio_soc tegra186_main_soc = { static const struct tegra_gpio_soc tegra186_main_soc = {
.num_ports = ARRAY_SIZE(tegra186_main_ports), .num_ports = ARRAY_SIZE(tegra186_main_ports),
.ports = tegra186_main_ports, .ports = tegra186_main_ports,
.name = "tegra186-gpio", .name = "tegra186-gpio",
.instance = 0,
}; };
#define TEGRA186_AON_GPIO_PORT(port, base, count, controller) \ #define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \
[TEGRA186_AON_GPIO_PORT_##port] = { \ [TEGRA186_AON_GPIO_PORT_##_name] = { \
.name = #port, \ .name = #_name, \
.offset = base, \ .bank = _bank, \
.pins = count, \ .port = _port, \
.irq = controller, \ .pins = _pins, \
} }
static const struct tegra_gpio_port tegra186_aon_ports[] = { static const struct tegra_gpio_port tegra186_aon_ports[] = {
TEGRA186_AON_GPIO_PORT( S, 0x0200, 5, 0), TEGRA186_AON_GPIO_PORT( S, 0, 1, 5),
TEGRA186_AON_GPIO_PORT( U, 0x0400, 6, 0), TEGRA186_AON_GPIO_PORT( U, 0, 2, 6),
TEGRA186_AON_GPIO_PORT( V, 0x0800, 8, 0), TEGRA186_AON_GPIO_PORT( V, 0, 4, 8),
TEGRA186_AON_GPIO_PORT( W, 0x0a00, 8, 0), TEGRA186_AON_GPIO_PORT( W, 0, 5, 8),
TEGRA186_AON_GPIO_PORT( Z, 0x0e00, 4, 0), TEGRA186_AON_GPIO_PORT( Z, 0, 7, 4),
TEGRA186_AON_GPIO_PORT(AA, 0x0c00, 8, 0), TEGRA186_AON_GPIO_PORT(AA, 0, 6, 8),
TEGRA186_AON_GPIO_PORT(EE, 0x0600, 3, 0), TEGRA186_AON_GPIO_PORT(EE, 0, 3, 3),
TEGRA186_AON_GPIO_PORT(FF, 0x0000, 5, 0), TEGRA186_AON_GPIO_PORT(FF, 0, 0, 5),
}; };
static const struct tegra_gpio_soc tegra186_aon_soc = { static const struct tegra_gpio_soc tegra186_aon_soc = {
.num_ports = ARRAY_SIZE(tegra186_aon_ports), .num_ports = ARRAY_SIZE(tegra186_aon_ports),
.ports = tegra186_aon_ports, .ports = tegra186_aon_ports,
.name = "tegra186-gpio-aon", .name = "tegra186-gpio-aon",
.instance = 1,
}; };
#define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \ #define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
[TEGRA194_MAIN_GPIO_PORT_##port] = { \ [TEGRA194_MAIN_GPIO_PORT_##_name] = { \
.name = #port, \ .name = #_name, \
.offset = base, \ .bank = _bank, \
.pins = count, \ .port = _port, \
.irq = controller, \ .pins = _pins, \
} }
static const struct tegra_gpio_port tegra194_main_ports[] = { static const struct tegra_gpio_port tegra194_main_ports[] = {
TEGRA194_MAIN_GPIO_PORT( A, 0x1400, 8, 1), TEGRA194_MAIN_GPIO_PORT( A, 1, 2, 8),
TEGRA194_MAIN_GPIO_PORT( B, 0x4e00, 2, 4), TEGRA194_MAIN_GPIO_PORT( B, 4, 7, 2),
TEGRA194_MAIN_GPIO_PORT( C, 0x4600, 8, 4), TEGRA194_MAIN_GPIO_PORT( C, 4, 3, 8),
TEGRA194_MAIN_GPIO_PORT( D, 0x4800, 4, 4), TEGRA194_MAIN_GPIO_PORT( D, 4, 4, 4),
TEGRA194_MAIN_GPIO_PORT( E, 0x4a00, 8, 4), TEGRA194_MAIN_GPIO_PORT( E, 4, 5, 8),
TEGRA194_MAIN_GPIO_PORT( F, 0x4c00, 6, 4), TEGRA194_MAIN_GPIO_PORT( F, 4, 6, 6),
TEGRA194_MAIN_GPIO_PORT( G, 0x4000, 8, 4), TEGRA194_MAIN_GPIO_PORT( G, 4, 0, 8),
TEGRA194_MAIN_GPIO_PORT( H, 0x4200, 8, 4), TEGRA194_MAIN_GPIO_PORT( H, 4, 1, 8),
TEGRA194_MAIN_GPIO_PORT( I, 0x4400, 5, 4), TEGRA194_MAIN_GPIO_PORT( I, 4, 2, 5),
TEGRA194_MAIN_GPIO_PORT( J, 0x5200, 6, 5), TEGRA194_MAIN_GPIO_PORT( J, 5, 1, 6),
TEGRA194_MAIN_GPIO_PORT( K, 0x3000, 8, 3), TEGRA194_MAIN_GPIO_PORT( K, 3, 0, 8),
TEGRA194_MAIN_GPIO_PORT( L, 0x3200, 4, 3), TEGRA194_MAIN_GPIO_PORT( L, 3, 1, 4),
TEGRA194_MAIN_GPIO_PORT( M, 0x2600, 8, 2), TEGRA194_MAIN_GPIO_PORT( M, 2, 3, 8),
TEGRA194_MAIN_GPIO_PORT( N, 0x2800, 3, 2), TEGRA194_MAIN_GPIO_PORT( N, 2, 4, 3),
TEGRA194_MAIN_GPIO_PORT( O, 0x5000, 6, 5), TEGRA194_MAIN_GPIO_PORT( O, 5, 0, 6),
TEGRA194_MAIN_GPIO_PORT( P, 0x2a00, 8, 2), TEGRA194_MAIN_GPIO_PORT( P, 2, 5, 8),
TEGRA194_MAIN_GPIO_PORT( Q, 0x2c00, 8, 2), TEGRA194_MAIN_GPIO_PORT( Q, 2, 6, 8),
TEGRA194_MAIN_GPIO_PORT( R, 0x2e00, 6, 2), TEGRA194_MAIN_GPIO_PORT( R, 2, 7, 6),
TEGRA194_MAIN_GPIO_PORT( S, 0x3600, 8, 3), TEGRA194_MAIN_GPIO_PORT( S, 3, 3, 8),
TEGRA194_MAIN_GPIO_PORT( T, 0x3800, 8, 3), TEGRA194_MAIN_GPIO_PORT( T, 3, 4, 8),
TEGRA194_MAIN_GPIO_PORT( U, 0x3a00, 1, 3), TEGRA194_MAIN_GPIO_PORT( U, 3, 5, 1),
TEGRA194_MAIN_GPIO_PORT( V, 0x1000, 8, 1), TEGRA194_MAIN_GPIO_PORT( V, 1, 0, 8),
TEGRA194_MAIN_GPIO_PORT( W, 0x1200, 2, 1), TEGRA194_MAIN_GPIO_PORT( W, 1, 1, 2),
TEGRA194_MAIN_GPIO_PORT( X, 0x2000, 8, 2), TEGRA194_MAIN_GPIO_PORT( X, 2, 0, 8),
TEGRA194_MAIN_GPIO_PORT( Y, 0x2200, 8, 2), TEGRA194_MAIN_GPIO_PORT( Y, 2, 1, 8),
TEGRA194_MAIN_GPIO_PORT( Z, 0x2400, 8, 2), TEGRA194_MAIN_GPIO_PORT( Z, 2, 2, 8),
TEGRA194_MAIN_GPIO_PORT(FF, 0x3400, 2, 3), TEGRA194_MAIN_GPIO_PORT(FF, 3, 2, 2),
TEGRA194_MAIN_GPIO_PORT(GG, 0x0000, 2, 0) TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2)
}; };
static const struct tegra_gpio_soc tegra194_main_soc = { static const struct tegra_gpio_soc tegra194_main_soc = {
.num_ports = ARRAY_SIZE(tegra194_main_ports), .num_ports = ARRAY_SIZE(tegra194_main_ports),
.ports = tegra194_main_ports, .ports = tegra194_main_ports,
.name = "tegra194-gpio", .name = "tegra194-gpio",
.instance = 0,
}; };
#define TEGRA194_AON_GPIO_PORT(port, base, count, controller) \ #define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \
[TEGRA194_AON_GPIO_PORT_##port] = { \ [TEGRA194_AON_GPIO_PORT_##_name] = { \
.name = #port, \ .name = #_name, \
.offset = base, \ .bank = _bank, \
.pins = count, \ .port = _port, \
.irq = controller, \ .pins = _pins, \
} }
static const struct tegra_gpio_port tegra194_aon_ports[] = { static const struct tegra_gpio_port tegra194_aon_ports[] = {
TEGRA194_AON_GPIO_PORT(AA, 0x0600, 8, 0), TEGRA194_AON_GPIO_PORT(AA, 0, 3, 8),
TEGRA194_AON_GPIO_PORT(BB, 0x0800, 4, 0), TEGRA194_AON_GPIO_PORT(BB, 0, 4, 4),
TEGRA194_AON_GPIO_PORT(CC, 0x0200, 8, 0), TEGRA194_AON_GPIO_PORT(CC, 0, 1, 8),
TEGRA194_AON_GPIO_PORT(DD, 0x0400, 3, 0), TEGRA194_AON_GPIO_PORT(DD, 0, 2, 3),
TEGRA194_AON_GPIO_PORT(EE, 0x0000, 7, 0) TEGRA194_AON_GPIO_PORT(EE, 0, 0, 7)
}; };
static const struct tegra_gpio_soc tegra194_aon_soc = { static const struct tegra_gpio_soc tegra194_aon_soc = {
.num_ports = ARRAY_SIZE(tegra194_aon_ports), .num_ports = ARRAY_SIZE(tegra194_aon_ports),
.ports = tegra194_aon_ports, .ports = tegra194_aon_ports,
.name = "tegra194-gpio-aon", .name = "tegra194-gpio-aon",
.instance = 1,
}; };
static const struct of_device_id tegra186_gpio_of_match[] = { static const struct of_device_id tegra186_gpio_of_match[] = {

View File

@ -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)); 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, static int thunderx_gpio_set_config(struct gpio_chip *chip,

View File

@ -39,7 +39,7 @@ static int tpic2810_get_direction(struct gpio_chip *chip,
unsigned offset) unsigned offset)
{ {
/* This device always output */ /* This device always output */
return 0; return GPIO_LINE_DIRECTION_OUT;
} }
static int tpic2810_direction_input(struct gpio_chip *chip, static int tpic2810_direction_input(struct gpio_chip *chip,

View File

@ -21,7 +21,7 @@ static int tps65086_gpio_get_direction(struct gpio_chip *chip,
unsigned offset) unsigned offset)
{ {
/* This device is output only */ /* This device is output only */
return 0; return GPIO_LINE_DIRECTION_OUT;
} }
static int tps65086_gpio_direction_input(struct gpio_chip *chip, static int tps65086_gpio_direction_input(struct gpio_chip *chip,

View File

@ -32,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc,
return ret; return ret;
if (val & GPIO_CFG_MASK) if (val & GPIO_CFG_MASK)
return 0; return GPIO_LINE_DIRECTION_OUT;
else else
return 1; return GPIO_LINE_DIRECTION_IN;
} }
static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset) static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset)

View File

@ -47,7 +47,6 @@ static int tps68470_gpio_get(struct gpio_chip *gc, unsigned int offset)
return !!(val & BIT(offset)); return !!(val & BIT(offset));
} }
/* Return 0 if output, 1 if input */
static int tps68470_gpio_get_direction(struct gpio_chip *gc, static int tps68470_gpio_get_direction(struct gpio_chip *gc,
unsigned int offset) unsigned int offset)
{ {
@ -57,7 +56,7 @@ static int tps68470_gpio_get_direction(struct gpio_chip *gc,
/* rest are always outputs */ /* rest are always outputs */
if (offset >= TPS68470_N_REGULAR_GPIO) if (offset >= TPS68470_N_REGULAR_GPIO)
return 0; return GPIO_LINE_DIRECTION_OUT;
ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val); ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val);
if (ret) { if (ret) {
@ -67,7 +66,8 @@ static int tps68470_gpio_get_direction(struct gpio_chip *gc,
} }
val &= TPS68470_GPIO_MODE_MASK; 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, static void tps68470_gpio_set(struct gpio_chip *gc, unsigned int offset,

View File

@ -101,7 +101,10 @@ static int tqmx86_gpio_direction_output(struct gpio_chip *chip,
static int tqmx86_gpio_get_direction(struct gpio_chip *chip, static int tqmx86_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset) 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) static void tqmx86_gpio_irq_mask(struct irq_data *data)

View File

@ -44,7 +44,10 @@ static int ts4900_gpio_get_direction(struct gpio_chip *chip,
regmap_read(priv->regmap, offset, &reg); regmap_read(priv->regmap, offset, &reg);
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, static int ts4900_gpio_direction_input(struct gpio_chip *chip,

View File

@ -165,10 +165,10 @@ static int twl4030_get_gpio_direction(int gpio)
if (ret < 0) if (ret < 0)
return ret; return ret;
/* 1 = output, but gpiolib semantics are inverse so invert */ if (ret & d_msk)
ret = !(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) 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); 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 * LED GPIOs >= TWL4030_GPIO_MAX are always output
*/ */
int ret = 0; int ret = GPIO_LINE_DIRECTION_OUT;
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX) { if (offset < TWL4030_GPIO_MAX) {

View File

@ -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) static int twl6040gpo_get_direction(struct gpio_chip *chip, unsigned offset)
{ {
/* This means "out" */ return GPIO_LINE_DIRECTION_OUT;
return 0;
} }
static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset, static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset,

View File

@ -113,7 +113,10 @@ static int uniphier_gpio_offset_read(struct gpio_chip *chip,
static int uniphier_gpio_get_direction(struct gpio_chip *chip, static int uniphier_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset) 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, static int uniphier_gpio_direction_input(struct gpio_chip *chip,

View File

@ -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); int ret, reg = to_reg(gpio, CTRL_OUT);
if (reg < 0) if (reg < 0)
return 0; return GPIO_LINE_DIRECTION_OUT;
ret = regmap_read(wg->regmap, reg, &val); ret = regmap_read(wg->regmap, reg, &val);
if (ret) if (ret)
return 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) static int wcove_gpio_get(struct gpio_chip *chip, unsigned int gpio)

View File

@ -56,7 +56,10 @@ static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
const unsigned port = offset / 8; const unsigned port = offset / 8;
const unsigned mask = BIT(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) static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)

View File

@ -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); bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
bit_offset = GPIO_BIT_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) 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) static int xgene_gpio_probe(struct platform_device *pdev)
{ {
struct resource *res;
struct xgene_gpio *gpio; struct xgene_gpio *gpio;
int err = 0; int err = 0;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio) { if (!gpio)
err = -ENOMEM; return -ENOMEM;
goto err;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); gpio->base = devm_platform_ioremap_resource(pdev, 0);
if (!res) { if (IS_ERR(gpio->base))
err = -EINVAL; return PTR_ERR(gpio->base);
goto err;
}
gpio->base = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
if (!gpio->base) {
err = -ENOMEM;
goto err;
}
gpio->chip.ngpio = XGENE_MAX_GPIOS; gpio->chip.ngpio = XGENE_MAX_GPIOS;
@ -196,14 +187,11 @@ static int xgene_gpio_probe(struct platform_device *pdev)
if (err) { if (err) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to register gpiochip.\n"); "failed to register gpiochip.\n");
goto err; return err;
} }
dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n"); dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n");
return 0; 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[] = { static const struct of_device_id xgene_gpio_of_match[] = {

View File

@ -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");

View File

@ -83,7 +83,10 @@ static int xra1403_get_direction(struct gpio_chip *chip, unsigned int offset)
if (ret) if (ret)
return 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) static int xra1403_get(struct gpio_chip *chip, unsigned int offset)

View File

@ -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) 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) 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) 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) static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset)

View File

@ -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. * 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) 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)); 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;
} }
/** /**

View File

@ -194,6 +194,7 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
acpi_gpiochip_request_irq(acpi_gpio, event); 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, static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
void *context) 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", desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event",
GPIO_ACTIVE_HIGH, GPIOD_IN); GPIO_ACTIVE_HIGH, GPIOD_IN);
if (IS_ERR(desc)) { if (IS_ERR(desc)) {
dev_err(chip->parent, "Failed to request GPIO\n"); dev_err(chip->parent,
return AE_ERROR; "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); ret = gpiochip_lock_as_irq(chip, pin);
if (ret) { 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; goto fail_free_desc;
} }
irq = gpiod_to_irq(desc); irq = gpiod_to_irq(desc);
if (irq < 0) { 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; goto fail_unlock_irq;
} }
@ -287,7 +294,7 @@ fail_unlock_irq:
fail_free_desc: fail_free_desc:
gpiochip_free_own_desc(desc); gpiochip_free_own_desc(desc);
return AE_ERROR; return AE_OK;
} }
/** /**

View File

@ -27,7 +27,7 @@
* This is used by external users of of_gpio_count() from <linux/of_gpio.h> * 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 * 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) 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 * of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs
* to set the .valid_mask * to set the .valid_mask
* @dev: the device for the GPIO provider * @gc: the target gpio_chip
* @return: true if the valid mask needs to be set *
* Return: true if the valid mask needs to be set
*/ */
bool of_gpio_need_valid_mask(const struct gpio_chip *gc) 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-gpio") &&
strcmp(propname, "enable-gpios")) && strcmp(propname, "enable-gpios")) &&
of_device_is_compatible(np, "regulator-gpio")))) { 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 * The regulator GPIO handles are specified such that the
* presence or absence of "enable-active-high" solely controls * presence or absence of "enable-active-high" solely controls
* the polarity of the GPIO line. Any phandle flags must * the polarity of the GPIO line. Any phandle flags must
* be actively ignored. * 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", pr_warn("%s GPIO handle specifies active low - ignored\n",
of_node_full_name(np)); of_node_full_name(np));
*flags &= ~OF_GPIO_ACTIVE_LOW; *flags &= ~OF_GPIO_ACTIVE_LOW;
} }
if (!of_property_read_bool(np, "enable-active-high")) if (active_low)
*flags |= OF_GPIO_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); of_node_get(chip->of_node);
ret = of_gpiochip_scan_gpios(chip); ret = of_gpiochip_scan_gpios(chip);
if (ret) { if (ret)
of_node_put(chip->of_node); of_node_put(chip->of_node);
gpiochip_remove_pin_ranges(chip);
}
return ret; return ret;
} }
void of_gpiochip_remove(struct gpio_chip *chip) void of_gpiochip_remove(struct gpio_chip *chip)
{ {
gpiochip_remove_pin_ranges(chip);
of_node_put(chip->of_node); of_node_put(chip->of_node);
} }

View File

@ -390,6 +390,14 @@ static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
gpiochip->valid_mask = NULL; 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, bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip,
unsigned int offset) unsigned int offset)
{ {
@ -422,9 +430,127 @@ struct linehandle_state {
(GPIOHANDLE_REQUEST_INPUT | \ (GPIOHANDLE_REQUEST_INPUT | \
GPIOHANDLE_REQUEST_OUTPUT | \ GPIOHANDLE_REQUEST_OUTPUT | \
GPIOHANDLE_REQUEST_ACTIVE_LOW | \ 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_DRAIN | \
GPIOHANDLE_REQUEST_OPEN_SOURCE) 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, static long linehandle_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
@ -475,6 +601,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
lh->descs, lh->descs,
NULL, NULL,
vals); vals);
} else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) {
return linehandle_set_config(lh, ip);
} }
return -EINVAL; return -EINVAL;
} }
@ -526,32 +654,9 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
lflags = handlereq.flags; lflags = handlereq.flags;
/* Return an error if an unknown flag is set */ ret = linehandle_validate_flags(lflags);
if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) if (ret)
return -EINVAL; return ret;
/*
* 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;
lh = kzalloc(sizeof(*lh), GFP_KERNEL); lh = kzalloc(sizeof(*lh), GFP_KERNEL);
if (!lh) if (!lh)
@ -593,6 +698,12 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
set_bit(FLAG_OPEN_DRAIN, &desc->flags); set_bit(FLAG_OPEN_DRAIN, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags); 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); ret = gpiod_set_transitory(desc, false);
if (ret < 0) 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))) if (copy_from_user(&eventreq, ip, sizeof(eventreq)))
return -EFAULT; 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); le = kzalloc(sizeof(*le), GFP_KERNEL);
if (!le) if (!le)
return -ENOMEM; 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]; desc = &gdev->descs[offset];
ret = gpiod_request(desc, le->label); ret = gpiod_request(desc, le->label);
if (ret) if (ret)
@ -945,6 +1058,12 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
set_bit(FLAG_ACTIVE_LOW, &desc->flags); 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); ret = gpiod_direction_input(desc);
if (ret) 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)) if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE | lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
GPIOLINE_FLAG_IS_OUT); 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))) if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT; 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); acpi_gpiochip_add(chip);
machine_gpiochip_add(chip); machine_gpiochip_add(chip);
ret = gpiochip_irqchip_init_hw(chip); ret = gpiochip_irqchip_init_valid_mask(chip);
if (ret) if (ret)
goto err_remove_acpi_chip; goto err_remove_acpi_chip;
ret = gpiochip_irqchip_init_valid_mask(chip); ret = gpiochip_irqchip_init_hw(chip);
if (ret) if (ret)
goto err_remove_acpi_chip; goto err_remove_acpi_chip;
@ -1444,6 +1573,7 @@ err_remove_of_chip:
gpiochip_free_hogs(chip); gpiochip_free_hogs(chip);
of_gpiochip_remove(chip); of_gpiochip_remove(chip);
err_free_gpiochip_mask: err_free_gpiochip_mask:
gpiochip_remove_pin_ranges(chip);
gpiochip_free_valid_mask(chip); gpiochip_free_valid_mask(chip);
err_remove_from_list: err_remove_from_list:
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
@ -1499,8 +1629,8 @@ void gpiochip_remove(struct gpio_chip *chip)
gdev->chip = NULL; gdev->chip = NULL;
gpiochip_irqchip_remove(chip); gpiochip_irqchip_remove(chip);
acpi_gpiochip_remove(chip); acpi_gpiochip_remove(chip);
gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip); of_gpiochip_remove(chip);
gpiochip_remove_pin_ranges(chip);
gpiochip_free_valid_mask(chip); gpiochip_free_valid_mask(chip);
/* /*
* We accept no more calls into the driver from this point, so * 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. * @dev: pointer to the device that gpio_chip belongs to.
* @chip: the chip to register, with chip->base initialized * @chip: the chip to register, with chip->base initialized
* @data: driver-private data associated with this chip * @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_REQUESTED, &desc->flags);
clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
clear_bit(FLAG_OPEN_SOURCE, &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); clear_bit(FLAG_IS_HOGGED, &desc->flags);
ret = true; ret = true;
} }
@ -2916,6 +3049,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
unsigned arg; unsigned arg;
switch (mode) { switch (mode) {
case PIN_CONFIG_BIAS_DISABLE:
case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_UP:
arg = 1; 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; 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 * gpiod_direction_input - set the GPIO direction to input
* @desc: GPIO to set to input * @desc: GPIO to set to input
@ -2973,15 +3127,10 @@ int gpiod_direction_input(struct gpio_desc *desc)
__func__); __func__);
return -EIO; return -EIO;
} }
if (ret == 0) if (ret == 0) {
clear_bit(FLAG_IS_OUT, &desc->flags); clear_bit(FLAG_IS_OUT, &desc->flags);
ret = gpio_set_bias(chip, desc);
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);
trace_gpio_direction(desc_to_gpio(desc), 1, ret); 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: set_output_value:
ret = gpio_set_bias(gc, desc);
if (ret)
return ret;
return gpiod_direction_output_raw_commit(desc, value); return gpiod_direction_output_raw_commit(desc, value);
set_output_flag: set_output_flag:

View File

@ -110,6 +110,7 @@ struct gpio_desc {
#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ #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_UP 13 /* GPIO has pull up enabled */
#define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */ #define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */
#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */
/* Connection label */ /* Connection label */
const char *label; const char *label;

View File

@ -285,8 +285,8 @@ static int tfp410_get_connector_properties(struct tfp410 *dvi)
else else
dvi->connector_type = DRM_MODE_CONNECTOR_DVID; dvi->connector_type = DRM_MODE_CONNECTOR_DVID;
dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode, dvi->hpd = fwnode_gpiod_get_index(&connector_node->fwnode,
"hpd-gpios", 0, GPIOD_IN, "hpd"); "hpd", 0, GPIOD_IN, "hpd");
if (IS_ERR(dvi->hpd)) { if (IS_ERR(dvi->hpd)) {
ret = PTR_ERR(dvi->hpd); ret = PTR_ERR(dvi->hpd);
dvi->hpd = NULL; dvi->hpd = NULL;

View File

@ -22,6 +22,9 @@ enum gpio_lookup_flags;
struct gpio_chip; struct gpio_chip;
#define GPIO_LINE_DIRECTION_IN 1
#define GPIO_LINE_DIRECTION_OUT 0
/** /**
* struct gpio_irq_chip - GPIO interrupt controller * struct gpio_irq_chip - GPIO interrupt controller
*/ */
@ -286,6 +289,9 @@ struct gpio_irq_chip {
* state (such as pullup/pulldown configuration). * state (such as pullup/pulldown configuration).
* @init_valid_mask: optional routine to initialize @valid_mask, to be used if * @init_valid_mask: optional routine to initialize @valid_mask, to be used if
* not all GPIOs are valid. * 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; * @base: identifies the first GPIO number handled by this chip;
* or, if negative during registration, requests dynamic ID allocation. * or, if negative during registration, requests dynamic ID allocation.
* DEPRECATION: providing anything non-negative and nailing the base * DEPRECATION: providing anything non-negative and nailing the base
@ -376,6 +382,8 @@ struct gpio_chip {
unsigned long *valid_mask, unsigned long *valid_mask,
unsigned int ngpios); unsigned int ngpios);
int (*add_pin_ranges)(struct gpio_chip *chip);
int base; int base;
u16 ngpio; u16 ngpio;
const char *const *names; const char *const *names;

View File

@ -33,6 +33,9 @@ struct gpiochip_info {
#define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2)
#define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3)
#define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) #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 * 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_ACTIVE_LOW (1UL << 2)
#define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3)
#define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) #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 * struct gpiohandle_request - Information about a GPIO handle request
@ -94,6 +100,24 @@ struct gpiohandle_request {
int fd; int fd;
}; };
/**
* 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 * struct gpiohandle_data - Information of values on a GPIO handle
* @values: when getting the state of lines this contains the current * @values: when getting the state of lines this contains the current